728x90

※ 제 개인 공부이므로 풀 소스 코드는 작성하지 않습니다.

※ 생략 되어 있는 부분이 많습니다.

struct VtxNUV1
 {
  D3DXVECTOR3 p;
  D3DXVECTOR3 n;
  FLOAT u, v;

  VtxNUV1() : p(0, 0, 0), n(0, 0, 0), u(0), v(0) {}
  VtxNUV1(FLOAT X, FLOAT Y, FLOAT Z
   , FLOAT NX, FLOAT NY, FLOAT NZ
   , FLOAT U, FLOAT V) : p(X, Y, Z), n(NX, NY, NZ), u(U), v(V) {}

  enum { FVF = (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1) };
 };

 

LPD3DXEFFECT  m_pEft;    // Vertex Shader

 

D3DXMATRIX  m_mtWld;   // World Matrix
D3DXMATRIX  m_mtRot;   // Rotation Matrix

 

CMcMesh* m_pMsh;
LPDIRECT3DTEXTURE9  m_pTx0;
LPDIRECT3DTEXTURE9  m_pTx1;

 

정점 구조는 포지션(XYZ), 법선(NORMAL), 텍스처(TEX1)로 구성 되어 있고,

CMcMesh 라고 하는 메쉬 랜더링과 관련된 클래스 객체가 추가 되었다.

 

*create()*

 

hr = D3DXCreateEffectFromFile(m_pdev, "data/shader.fx", NULL, NULL, dwFlags, NULL, &m_pEft, &pErr);

 

D3DXCreateTextureFromFile(m_pdev, "data/earth.bmp", &m_pTx0);
D3DXCreateTextureFromFile(m_pdev, "data/wood.jpg", &m_pTx1);

 

m_pMsh = new CMcMesh;

hr = m_pMsh->Create(m_pdev, "data/teapot.x");

 

Effect를 사용하고 있고, 텍스처는 earth.bmp, wood.jpg 2개가 사용 되고 있다.

CMcMesh 객체를 이용해서 주전자 메쉬를 읽어 들이고 있다.

 

*render()*

 

static INT nPassIndex = 0;

 

 if (::GetAsyncKeyState('1') & 0x8000) nPassIndex = 0;

 if (::GetAsyncKeyState('2') & 0x8000) nPassIndex = 1;

 if (::GetAsyncKeyState('3') & 0x8000) nPassIndex = 2;

 

 m_pdev->SetTransform(D3DTS_WORLD, &m_mtWld);
 m_pdev->SetTexture(1, m_pTx1);

 

 m_pEft->SetTexture("m_TxDif0", m_pTx0);
 m_pEft->SetTexture("m_TxDif1", m_pTx1);

 

 m_pEft->SetTechnique("Tech0");

 

 m_pEft->Begin(NULL, 0);
 m_pEft->BeginPass(nPassIndex);

 

 m_pMsh->Render();

 

 m_pEft->EndPass();
 m_pEft->End();


 m_pdev->SetTexture(0, NULL);

 

 m_pdev->SetPixelShader(NULL);
 m_pdev->SetVertexDeclaration(NULL);

 

 D3DXMATRIX mtI;
 D3DXMatrixIdentity(&mtI);
 m_pdev->SetTransform(D3DTS_WORLD, &mtI);

 

숫자 1번을 누르면 테크닉(Tech0) 안에 있는 패스(0번)의 과정으로 랜더링.

숫자 2번을 누르면 테크닉(Tech0) 안에 있는 패스(1번)의 과정으로 랜더링.

숫자 3번을 누르면 테크닉(Tech0) 안에 있는 패스(2번)의 과정으로 랜더링.

 

방식으로 처리 하고 있다. 패스를 지정해서 사용하고 있기 때문에 패스의 개수를 확인할 필요는 없으므로 Begin() 함수에 NULL 값을 주고 있다.

 

*shader.fx*

 

// Texture
texture m_TxDif0;
sampler SmpDif0 : register(s0) = sampler_state
{
    Texture = (m_TxDif0);
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;

    AddressU = WRAP;
    AddressV = WRAP;
};


texture m_TxDif1;
sampler SmpDif1 : register(s1) = sampler_state
{
    Texture = (m_TxDif1);
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;

    AddressU = WRAP;
    AddressV = WRAP;
};


technique Tech0
{
 pass P0
 {
      // Setup Vertex Processing Constant of Rendering Machine
      FOGENABLE = FALSE;
      LIGHTING = FALSE;
      CULLMODE = CCW;

 

      // Setup Vertex Processing Constant of Rendering Machine
      Sampler[0] = (SmpDif0);

 

      ColorOp[0]  = ADDSIGNED;
      ColorArg1[0] = TEXTURE;
      ColorArg2[0] = DIFFUSE;

 

      AlphaOp[0] = DISABLE;
      ColorOp[1] = DISABLE;
 }

 pass P1
 {
      // Setup Vertex Processing Constant of Rendering Machine
      FOGENABLE = FALSE;
      LIGHTING = FALSE;
      CULLMODE = CCW;

 

      // Setup Vertex Processing Constant of Rendering Machine
      Texture[0] = (m_TxDif1);

 

      ColorOp[0]  = SELECTARG1;
      ColorArg1[0] = TEXTURE;
      ColorArg2[0] = DIFFUSE;

 

      AlphaOp[0] = DISABLE;
      ColorOp[1] = DISABLE;
 }

 pass P2
 {
      FOGENABLE = FALSE;
      LIGHTING = FALSE;
      CULLMODE = CCW;

 

      Sampler[0] = (SmpDif0);
      Sampler[1] = (SmpDif1);

 

      TEXCOORDINDEX[1] = 0;

 

      ColorOp[0]  = MODULATE;
      ColorArg1[0] = TEXTURE;
      ColorArg2[0] = DIFFUSE;
      AlphaOp[0] = DISABLE;

 

      ColorOp[1]  = ADD;
      ColorArg1[1] = CURRENT;
      ColorArg2[1] = TEXTURE;

 

      ColorOp[2]  = DISABLE;

 }
}

 

Pass는 랜더링 처리과정의 가장 기본 단위이며, Pass안에 정점 또는 픽셀 셰이더 객체를 지정한다.

 

그런데 셰이더 객체를 지정하지 않으면 고정 기능 파이프 라인의 정점,픽셀 처리 그리고 기타 렌더링 머신 값을 설정하게 된다.

 

이러한 이점은 다양한 랜더링 환경에 대해서 프로그래머가 특별한 구조를 만들지 않아도 되고 범용성이 있어서 다른 프로그램에도 수정 없이 적용할 수 있다.

 

우선 기본적으로 셰이더 파일에서 설정되고 있는 값들은 실행 프로그램에서도 모두 설정이 가능하다. 이 과정들을 우리는 셰이더 파일에서 설정을 하는 것이다.

(위의 Render() 부분을 보면 SetRenderState, SetSamplerState, SetTextureStageState 등등 평소 사용하던 함수들이 보이지 않을 것이다. 셰이더 파일에서 다 설정하고 있기 때문에!)

 

셰이더 파일의 Pass에서 설정 부분을 알아보기 전에 알아야 할 것이 있다.

지금까지 계속해서 셰이더를 해오면서 StageIndex를 입력하는 함수들이 많이 있었다.

이 Stage에 대해 알아보자.

 

텍스처 처리 과정은 크게 샘플링과 다중 텍스처 처리(Multi-Texturing)으로 구분한다.

 

다중 텍스처 처리는 그림에서 처럼 레스터 처리 색상, 샘플러에 처리된 색상 상태 머신에 Color Factor를 가지고 총 8단계(8 Stage)을 거쳐서 후면 버퍼에 적용할 색상을 만들어 낸다.

 

특별한 경우 3개의 픽셀을 사용하지만 보통은 두 픽셀을 가지고 블랜딩한다.

 

D3D는 최대 8단계 0 ~ 7 Stage까지 다중 텍스처를 진행 한다.

 

이쯤이면 stage가 무엇을 뜻하는지는 알게 되었을거라 생각한다. 

 

다중 텍스처 처리를 하면서 RGB 값만 처리하는것은 아니다. 알파 성분에 대해서도 처리가 가능하며 그림에서와 같이 D3D에선 RGB 값과 알파 값 처리 경로가 독립적으로 동작한다.

 

RGB 처리 과정위치의 x, y, z로 볼 수 있어서 픽셀에 대한 벡터 처리 과정이라 부르기도 하고, 알파는 단일 성분 스칼라와 같아서 픽셀에 대한 스칼라 처리 과정이라 부르기도 한다. 

 

각 Pass 안에 사용되고 있는 공통되는 설정 부분들을 알아 보자.

FOGENABLE → FOG(안개를) 설정한다(TRUE), 설정 안한다(FALSE)

 

LIGHTING →  조명을 설정한다(TRUE), 설정 안한다(FALSE)

 

CULLMODE → 컬링을 하는 방법을 지정, 반시계 방향으로 형성되는 면을 뒷면으로 인식(CCW)

,시계 방향으로 형성되는 면을 뒷면으로 인식(CW), 컬링 하지 않고 모두 그림(NONE)

 

Sampler[index] → 텍스처 샘플링에 대한 작업의 형태를 설정, index는 샘플러 Stage Index이다, D3D는 고정 함수 그래픽 파이프라인에 총 8개의 텍스처를 설정 할 수 있으므로 샘플러 또한 8개가 있다고 할 수 있다. (D3D에서 SetSamplerStage() 함수)

 

Texture[index] → 샘플러에게 텍스처 연결을 설정. index는 텍스처 Stage Index를 말한다.

(D3D에서 SetTexture() 함수)

 

ColorArg1,2...[index] → index 단계(Stage)에서 연산에 적용할 1번째 픽셀(Arg1), 2번째 픽셀(Arg2)이라 하고 샘플러에 지정된 텍스처로부터 픽셀을 가져온다(TEXTURE), 래스터 과정의 색상을 가져온다(DIFFUSE)이다. 전 Stage Index에서 만들어진 픽셀을 가져온다(CURRENT)

 

ColorOp[index] → index 단계(Stage)에서 ColorArg1,2... 에 지정된 픽셀들을 연산(Operation)종류(MODULATE, SELECTARG1, ADDSIGNED....)로 계산하여 index 단계의 픽셀로 만든다.

DISABLE 값을 주게 되면 해당 index 단계(Stage)에서는 연산을 하지 않고 멀티 텍스처 처리를 빠져나온다는 뜻이다.

(ColorArg1,2..., ColorOP는 D3D에서 SetTextureStageState() 함수)

 

AlphaArg1,2...[index], AlphaOp[index] → ColorArg1,2..., ColorOp와 개념은 같고, 알파 값에 대한 인자와, 연산 방법을 설정한다.(D3D에서 SetTextureStageState() 함수)

 

TEXCOORDINDEX[index] → 해당 텍스처를 다른 텍스처 UV좌표로 사용한다, 고정 기능 정점 처리에서만 사용된다.

(TEXCOORDINDEX[1] = 0 , 1번 텍스처 좌표는 0번 텍스처 좌표와 같다.) 

 

위에서 셰이더 객체를 지정하지 않으면 고정 기능 파이프 라인의 정점,픽셀 처리 그리고 기타 렌더링 머신 값을 설정하게 된다고 했다.

 

이번엔 정점 픽셀 셰이더 함수를 작성해서 객체 지정을 하는 방법을 보자.

*shader.fx (예제)*

 

struct SVsOut
{
 float4 Pos : POSITION;
 float4 Dif : COLOR0;
 float2 Tex : TEXCOORD0;
};

 

//정점 처리 함수.

SVsOut VtxPrc0( float3 Pos : POSITION, float3 Nor : NORMAL, float2 Tex : TEXCOORD0 )
{
     SVsOut Out = (SVsOut)0;

     float4 P = 0;
     float3 N = 0;
     float3 L = normalize(m_vcLgt);

     ........

 

     return Out;
}

 

//픽셀 처리 함수.

float4 PxlPrc0(SVsOut In) : COLOR
{
     return In.Dif * tex2D( SampDif, In.Tex );
}

 

technique Tech0
{
 pass P0
 {
      LIGHTING = FALSE;
      CULLMODE = NONE;

 

      ALPHABLENDENABLE= False;
      ZWRITEENABLE = TRUE;

 

      VertexShader = compile vs_3_0 VtxPrc0();
      PixelShader  = compile ps_3_0 PxlPrc0();
 }
}

 

정점과 픽셀 처리 함수를 작성 한 후 Pass안에서  VertexShader, PixelShader 에 각각 지정해 주면 된다.

728x90

'Shader' 카테고리의 다른 글

파도 흉내 내보기...  (0) 2017.08.31
18. Multi-Pass  (0) 2017.03.10
16. D3DEffect  (1) 2017.02.14
15. 다중 텍스처 처리(Multi-Texturing)  (0) 2017.02.13
14. 텍스처 처리(단색화, 흐림효과)  (0) 2017.02.09
Posted by 정망스
,


맨 위로
홈으로 ▲위로 ▼아래로 ♥댓글쓰기 새로고침