16. D3DEffect

Shader 2017. 2. 14. 16:27
728x90

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

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

이전까지 정점 셰이더와, 픽셀 셰이더를 각각 독립적으로 적용하여 사용했다.

독립적으로 사용하는것이 각각 다른 그래픽 카드의 성능에 대처할 수 있는 유연성이 있어 보이지만 통합적으로 작성해서 각 상황에 맞게 처리할 수 있는 방법으로 해결하는 것이 나을 수도 있다.

 

현재 그래픽 카드들은 픽셀 셰이더를 지원하는 경우, 정점 셰이더는 당연히 지원이 되고 프로그램에서도 픽셀 셰이더를 분리해서 사용할 필요가 없기 때문에 이를 한꺼번에 처리하고 코드의 구현에서 좀 더 편리성을 위한 객체가 필요한데 D3D에선 Effect라고 하는 객체를 지원한다.

D3D Effect는 저 수준, 고 수준 셰이더를 기본적으로 지원하고 상수의 공용화, 정점 처리 상태 설정, 픽셀 처리 상태 설정 등의 옵션들이 추가되어 있다.

 

struct VtxDUV1
 {
  D3DXVECTOR3 p;
  DWORD d;
  FLOAT u, v;

  VtxDUV1() {}
  VtxDUV1(FLOAT X, FLOAT Y, FLOAT Z,
   FLOAT U, FLOAT V, DWORD D = 0xFFFFFFFF)
   : p(X, Y, Z), u(U), v(V), d(D) {}

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

 

 struct VtxIdx
 {
  WORD a, b, c;

  VtxIdx() : a(0), b(1), c(2) {}
  VtxIdx(WORD A, WORD B, WORD C) : a(A), b(B), c(C) {}
 };

 

LPD3DXEFFECT  m_pEft;   // ID3DXEffect Instance
LPDIRECT3DVERTEXDECLARATION9  m_pFVF;   // Vertex Declarator

 

D3DXMATRIX  m_mtWld;  // World Matrix

 

VtxDUV1  m_pVtx[24];  // Vertex Buffer
VtxIdx  m_pIdx[12];
LPDIRECT3DTEXTURE9  m_pTex;

 

정점 데이터(VtxDUV1)은 포지션(XYZ), 색상(DIFFUSE), 텍스처 좌표(TEX1)를 가지고 있다.

 

그리고 인덱스 버퍼를 위한 데이터(VtxIdx) 이번에 Effect를 사용하기 위한 새로 추가된 객체 m_pEft(LPD3DXEFFECT)

 

정육면체를 구성하기 위해 정점 버퍼 24개(m_pVtx[24]), 인덱스 버퍼 12개(m_pldx[12]) 로 구성 되어 있다.

 

*shader.fx*

 

float4x4 m_mtWVP; // World * View * Projection Matrix


texture m_TxDif;
sampler smpDif : register(s0) = sampler_state
{
     texture = (m_TxDif);
     MinFilter = LINEAR;
     MagFilter = LINEAR;
     MipFilter = NONE;

     AddressU = WRAP;
     AddressV = WRAP;
};

 

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

 

// Vertex Shader Processing
SVsOut VtxPrc( float3 Pos : POSITION, float4 Dif : COLOR0, float2 Tex : TEXCOORD0)
{
     SVsOut Out = (SVsOut)0;

     Out.Pos = mul( float4(Pos, 1), m_mtWVP);
     Out.Dff = Dif;
     Out.Tex = Tex;

 

     return Out;
}


// Pixel Shader Processing
float4 PxlPrc(SVsOut In) : COLOR
{
     float4 Out= 0;

 

     Out = max(In.Dff, tex2D(smpDif, In.Tex) );
     return Out;
}


technique Tech0
{
     pass P0
     {
          VertexShader = compile vs_3_0 VtxPrc();
          PixelShader  = compile ps_3_0 PxlPrc();
     }

 

기본적인 문법은 정점과 픽셀 처리의 함수 작성은 여태 작성한 방법과 같고, 새롭게 추가 된것은 "technique"와, "pass"가 추가 되었고 이 안에서 컴파일을 지정하고 있음을 볼 수 있다.

 

------ ex ------ 

 

technique
Tech0
{
     pass P0
     {
          VertexShader = compile vs_3_0 VtxPrc();
          PixelShader  = compile ps_3_0 PxlPrc();
     }

 

     pass P1 

     ...

 

technique Tech1
{
...

 

"technique"은 정점과 픽셀 처리에 대한 단위이고, "pass"는 정점 처리와 픽셀 처리의 main 함수와 랜더링 상태 설정을 작성한다.

 

하나의 테크틱은 여러 패스를 가질 수 있고 전체 셰이더 코드는 여러 개의 테크닉을 가질 수 있다.

 

여러 개의 패스와 테크닉의 지원은 패스에서 여러 개의 셰이더 함수를 조합해서 하나의 패스를 만들고 이를 테크닉은 여러 패스를 설정 할 수 있어서 다양한 연출을 실행 프로그램에서가 아니라 셰이더 언어를 작성하는 곳에서 결정을 할 수 있게 된다. 또한 반복적인 내용을 분리해서 모듈의 응집력 또한 높일 수 있다.

 

*create()*

 

HRESULT hr = 0;

 

LPD3DXBUFFER pErr = NULL;

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

 

DWORD dFVF = VtxDUV1::FVF;
D3DVERTEXELEMENT9 vertex_decl[MAX_FVF_DECL_SIZE] = { 0 };
D3DXDeclaratorFromFVF(dFVF, vertex_decl);
if (FAILED(hr = m_pdev->CreateVertexDeclaration(vertex_decl, &m_pFVF)))
  return -1;

 

D3DXCreateTextureFromFile(m_pdev, "texture/dx5_logo.bmp", &m_pTex);


float fSize = 30;

 

m_pVtx[0] = VtxDUV1(-1.f, -1.f, -1.f, 0.f, 1.f, 0XFFFF0000);
m_pVtx[1] = VtxDUV1(-1.f, 1.f, -1.f, 0.f, 0.f, 0XFF00FF00);
m_pVtx[2] = VtxDUV1(1.f, 1.f, -1.f, 1.f, 0.f, 0XFF0000FF);
m_pVtx[3] = VtxDUV1(1.f, -1.f, -1.f, 1.f, 1.f, 0XFFFF00FF);

 

// the back face vertex data
m_pVtx[4] = VtxDUV1(-1.f, -1.f, 1.f, 0.f, 1.f, 0XFFFFFF00);
m_pVtx[5] = VtxDUV1(1.f, -1.f, 1.f, 0.f, 0.f, 0XFF00FFFF);
m_pVtx[6] = VtxDUV1(1.f, 1.f, 1.f, 1.f, 0.f, 0XFFFF00FF);
m_pVtx[7] = VtxDUV1(-1.f, 1.f, 1.f, 1.f, 1.f, 0XFFFFFFFF);

 

// the top face vertex data
m_pVtx[8] = VtxDUV1(-1.f, 1.f, -1.f, 0.f, 1.f, 0XFFF0FFF0);
m_pVtx[9] = VtxDUV1(-1.f, 1.f, 1.f, 0.f, 0.f, 0XFF0F0FFF);
m_pVtx[10] = VtxDUV1(1.f, 1.f, 1.f, 1.f, 0.f, 0XFFFFF00F);
m_pVtx[11] = VtxDUV1(1.f, 1.f, -1.f, 1.f, 1.f, 0XFFFFFFFF);

 

// the bottom face vertex data
m_pVtx[12] = VtxDUV1(-1.f, -1.f, -1.f, 0.f, 1.f, 0XFFFF0FF0);
m_pVtx[13] = VtxDUV1(1.f, -1.f, -1.f, 0.f, 0.f, 0XFFF0F0FF);
m_pVtx[14] = VtxDUV1(1.f, -1.f, 1.f, 1.f, 0.f, 0XFF0FFF0F);
m_pVtx[15] = VtxDUV1(-1.f, -1.f, 1.f, 1.f, 1.f, 0XFFFFFFFF);

 

// the left face vertex data
m_pVtx[16] = VtxDUV1(-1.f, -1.f, 1.f, 0.f, 1.f, 0XFFF0FFF0);
m_pVtx[17] = VtxDUV1(-1.f, 1.f, 1.f, 0.f, 0.f, 0XFF0FF0FF);
m_pVtx[18] = VtxDUV1(-1.f, 1.f, -1.f, 1.f, 0.f, 0XFFFF0F0F);
m_pVtx[19] = VtxDUV1(-1.f, -1.f, -1.f, 1.f, 1.f, 0XFFFFFFFF);

 

// the right face vertex data
m_pVtx[20] = VtxDUV1(1.f, -1.f, -1.f, 0.f, 1.f, 0XFFFFF00F);
m_pVtx[21] = VtxDUV1(1.f, 1.f, -1.f, 0.f, 0.f, 0XFF0FFFF0);
m_pVtx[22] = VtxDUV1(1.f, 1.f, 1.f, 1.f, 0.f, 0XFFF00FFF);
m_pVtx[23] = VtxDUV1(1.f, -1.f, 1.f, 1.f, 1.f, 0XFFFFFFFF);


for (int i = 0; i<24; ++i)
  m_pVtx[i].p *= fSize;


// the front face index data
m_pIdx[0] = VtxIdx(0, 1, 2);
m_pIdx[1] = VtxIdx(0, 2, 3);

 

// the back face index data
m_pIdx[2] = VtxIdx(4, 5, 6);
m_pIdx[3] = VtxIdx(4, 6, 7);

 

// the top face index data
m_pIdx[4] = VtxIdx(8, 9, 10);
m_pIdx[5] = VtxIdx(8, 10, 11);

 

// the bottom face index data
m_pIdx[6] = VtxIdx(12, 13, 14);
m_pIdx[7] = VtxIdx(12, 14, 15);

 

// the left face index data
m_pIdx[8] = VtxIdx(16, 17, 18);
m_pIdx[9] = VtxIdx(16, 18, 19);

 

// the right face index data
m_pIdx[10] = VtxIdx(20, 21, 22);
m_pIdx[11] = VtxIdx(20, 22, 23);

 

D3DXCreateEffect...() 함수로 이렇게 작성된 셰이더를 컴파일 하며 컴파일과 동시에 ID3DXEffect 객체를 생성한다.

 

이전까지 HLSL 셰이더와의 차이점은 컴파일과 동시에 이펙트 객체를 생성하고, 상수 테이블을 만들지 않고 있다. 나머지 에러에 대한 처리는 이전과 동일하다.

 

ID3DXEffect 객체는 내부에 상수를 설정할 수 있도록 구성되어 있고 인터페이스는 상수 테이블에서 사용한 함수들을 그대로 사용할 수 있고 Technique, Pass, 텍스처에 대한 인터페이스가 추가 되어있다.

 

*update()*

 

D3DXMATRIX mtRotX;   // Rotation Matrix X
D3DXMATRIX mtRotY;   // Rotation Matrix Y
D3DXMATRIX mtRotZ;   // Rotation Matrix Z

 

// Setup Rotating World Matrix
FLOAT  fAngle = D3DXToRadian(GetTickCount() * 0.03f);
D3DXMatrixRotationY(&mtRotY, fAngle*3.f);
D3DXMatrixRotationZ(&mtRotZ, fAngle*2.f);
D3DXMatrixRotationX(&mtRotX, fAngle*1.f);

 

m_mtWld = mtRotY * mtRotZ * mtRotX;
m_mtWld._42 = 40.f;
m_mtWld._43 = -30.f;

 

X,Y,Z축 마다 일정값으로 회전을 하도록 월드행렬을 셋팅해주고 있다.

 

*Render()*

 

HRESULT hr = -1;

 

D3DXMATRIX mtWld = m_mtWld;
D3DXMATRIX mtViw;
D3DXMATRIX mtPrj;
D3DXMATRIX mtWVP;

 

m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);
m_pdev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

 

m_pdev->GetTransform(D3DTS_VIEW, &mtViw);
m_pdev->GetTransform(D3DTS_PROJECTION, &mtPrj);


mtWVP = mtWld * mtViw * mtPrj;

 

// Setup Constant
hr = m_pEft->SetMatrix("m_mtWVP", &mtWVP);
hr = m_pEft->SetTexture("m_TxDif", m_pTex);

 

// Rendering
hr = m_pdev->SetVertexDeclaration(m_pFVF);
hr = m_pEft->SetTechnique("Tech0");

 

UINT nPass = 0;
hr = m_pEft->Begin(&nPass, 0);

 

for (UINT n = 0; n < nPass; ++n)
{
  hr = m_pEft->BeginPass(n);
  hr = m_pdev->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST
   , 0
   , 24
   , 12
   , m_pIdx
   , D3DFMT_INDEX16
   , m_pVtx
   , sizeof(VtxDUV1));
  m_pEft->EndPass();
}

m_pEft->End();

 

// 정점, 픽셀 Shader 해제
hr = m_pdev->SetVertexDeclaration(NULL);
hr = m_pdev->SetVertexShader(NULL);
hr = m_pdev->SetPixelShader(NULL);

 

1. ID3DXEffect로 장면을 연출하는 과정은 SetVector(), SetMatrix(), SetInt()등의 함수상수를 설정하고, SetTechnique() 함수Technique을 지정한다.

 

2. 다음으로 Begin() 함수를 이용해서 Pass 개수를 확인한다.

(Pass의 개수가 필요 없다면 &nPass 부분에 NULL 값을 넣어 주면 된다.)

 

3Begin() 함수는 End() 함수와 반드시 짝을 이루어야 하고, Begin() / End() 함수 사이에 for문 또는 직접 인덱스를 사용해서 Pass() 함수 ( 또는 BeginPass() / EndPass() ) 아래에 Draw...() 함수를 호출하여 그린다.

 

Pass(), BeginPass() 함수Pass안에 구성된 정점 셰이더와 픽셀 셰이더 객체 사용을 지정하는 것과 같다.

( Pass() -> 2003버전 || BeginPass() / EndPass() -> 2003 이후 버전.)  

 

4. End() 함수를 호출하면 정점 셰이더, 픽셀 셰이더 사용이 끝나야 되는데 간혹 그래픽 카드에서 처리되지 않을 경우를 대비하여 명시적으로 SetVertexShader(NULL), SetPixelShader(NULL) 처럼 셰이더 사용을 해제 해준다.
728x90

'Shader' 카테고리의 다른 글

18. Multi-Pass  (0) 2017.03.10
17. Effect의 상태 설정.  (0) 2017.03.10
15. 다중 텍스처 처리(Multi-Texturing)  (0) 2017.02.13
14. 텍스처 처리(단색화, 흐림효과)  (0) 2017.02.09
13. 픽셀 처리 사용자 함수  (0) 2017.02.09
Posted by 정망스
,


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