'Shader'에 해당되는 글 20건

  1. 2017.08.31 파도 흉내 내보기...
  2. 2017.03.10 18. Multi-Pass
  3. 2017.03.10 17. Effect의 상태 설정.
  4. 2017.02.14 16. D3DEffect 1
  5. 2017.02.13 15. 다중 텍스처 처리(Multi-Texturing)

파도 흉내 내보기...

Shader 2017. 8. 31. 13:30
728x90

 

물 이미지 따와서 적용하고 파도가 출렁거리는 효과를 내보았다.

이미지 uv값은 일정 시간과 속도를 기준으로 움직이고 정점들의 포지션 y값을 시간,속도,파도의주기율 등의 값으로 계산을하여 포지션을 계속해서 변경하면서 출렁이는 효과가 되게 해보았다.

 

728x90

'Shader' 카테고리의 다른 글

18. Multi-Pass  (0) 2017.03.10
17. Effect의 상태 설정.  (0) 2017.03.10
16. D3DEffect  (1) 2017.02.14
15. 다중 텍스처 처리(Multi-Texturing)  (0) 2017.02.13
14. 텍스처 처리(단색화, 흐림효과)  (0) 2017.02.09
Posted by 정망스
,

18. Multi-Pass

Shader 2017. 3. 10. 11:21
728x90

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

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

Effect는 하나의 Technique에 여러 Pass를 가질 수 있다. 이것을 Multi-Pass라 한다.

 

Multi-Pass를 사용하면 같은 렌더링 물체에 대해서 서로 다른 렌더링 환경을 가지고 연속해서 그리는 상황에 대해 편리하다.

 

struct VtxNDUV1
 {
  D3DXVECTOR3 p;
  D3DXVECTOR3 n;
  DWORD d;
  FLOAT u, v;

  VtxNDUV1() : p(0, 0, 0), n(0, 0, 0), u(0), v(0), d(0xFFFFFFFF) {}
  VtxNDUV1(FLOAT X, FLOAT Y, FLOAT Z
   , FLOAT NX, FLOAT NY, FLOAT NZ
   , FLOAT U, FLOAT V
   , DWORD D = 0XFFFFFFFF) : p(X, Y, Z), n(NX, NY, NZ), u(U), v(V), d(D) {}

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

 };

 

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

 

D3DXMATRIX  m_mtWld;   // World Matrix

 

INT   m_iNvx;    // Vertex Number
VtxNDUV1* m_pVtx;    // Vertex Buffer
LPDIRECT3DTEXTURE9  m_pTx;

 

정점은 포지션(XYZ), 법선(NORMAL), 색상(DIFFUSE), 텍스처(TEX1)로 이루어진 구를 형성한다.

 

*Render()*

 

HRESULT  hr = -1;


D3DXMATRIX  mtViw;        // View Matrix
D3DXMATRIX  mtPrj;        // Projection Matrix
D3DXVECTOR4 vcLight(1, 0.0f, 0.0f, 0.0f);  // 광원방향
D3DXVECTOR4 xcGlow(1, 1.0f, 0.2f, 1.0f);  // Glow 색상
FLOAT  fThick = 40.F;      // Glow 두께
D3DXVECTOR4 vcGlow;        // Glow 축

 

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


D3DXMATRIX mtViwI;
D3DXMatrixInverse(&mtViwI, NULL, &mtViw);
vcGlow = D3DXVECTOR4(m_mtWld._41 - mtViwI._41, m_mtWld._42 - mtViwI._42, m_mtWld._43 - mtViwI._43, 0);
D3DXVec4Normalize(&vcGlow, &vcGlow);

 

m_pdev->SetVertexDeclaration(m_pFVF);   // 정점선언

 

// 상수 연결
hr = m_pEft->SetMatrix("m_mtWld", &m_mtWld);
hr = m_pEft->SetMatrix("m_mtViw", &mtViw);
hr = m_pEft->SetMatrix("m_mtPrj", &mtPrj);

 

hr = m_pEft->SetVector("m_vcLgt", &vcLight);

 

hr = m_pEft->SetVector("m_GlowColor", &xcGlow);
hr = m_pEft->SetVector("m_GlowAxis", &vcGlow);
hr = m_pEft->SetFloat("m_GlowThick", fThick);

 

hr = m_pEft->SetTexture("m_TxDif", m_pTx);


// Techinque 지정
hr = m_pEft->SetTechnique("Tech0");


// Pass 개수 확인
UINT nPass = 0;
hr = m_pEft->Begin(&nPass, 0);

 

// Pass 수 만큼 같은 물체를 Rendering
for (UINT n = 0; n < nPass; ++n)
{
      hr = m_pEft->BeginPass(n);
      hr = m_pdev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, m_iNvx - 2, m_pVtx, sizeof(VtxNDUV1));
      m_pEft->EndPass();
}

 

m_pEft->End();

 

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

 

월드행렬(m_mtWld)에는 Z축은 고정값으로 회전을하고, Y축은 일정 값을 기준으로 계속해서 회전 하는 값이 설정 되어 있다.

 

Glow축(vcGlow) 구하기 위해 뷰행렬의 역행렬을 구해서 .41, .42, .43의 값 (카메라의 위치를 가리키는 x,y,z값( = 카메라의 z방향 축의 벡터 ) 값을 가져와 월드 행렬의 .41, .42, .43에 각각 뺀 값을 정규화 해서 방향을 구하고 있다.)

 

Begin() 함수를 통해 nPass에 입력되는 Tech0(테크닉) 안에 있는 Pass의 갯수만큼 for문을 실행하여 랜더링 하고 있다.

 

여기서 잠깐,, 항상 궁금했던 것이, 뷰행렬의 역행렬에서 우리가 필요로 하는 카메라의 속성들을 구할 수 있는건 어떤 원리일까 라는 것에서 정보를 좀 찾아 보았다.(잠깐 딴 길로 샌다.)

 

뷰 행렬을 얻어오면 이 행렬의 값들은 현재 카메라 행렬의 역처럼 동작을 한다

(오른쪽을 보면 왼쪽으로 회전, 왼쪽을 보면 오른쪽으로 회전 등등)

 

간단하게는 실제로 카메라는 정지해 있고 월드의 상태가 변하기 때문이다.

(카메라를 오른쪽으로 30도 돌아간다는것은 카메라는 정지하고 월드가 왼쪽으로 30도 돌려진다는 개념.)

 

좀 더 자세히 알아 보자면, 파이프 라인에서 모든 객체들의 정점월드 변환을 해준 다음 카메라 변환을 하여 카메라 좌표계를 기준으로 변환 하게 된다.

 

카메라 또한 하나의 객체이므로 월드 변환을 통해서 월드 좌표계에 위치를 하게 되고 이 때 사용한 월드 변환을 카메라의 월드 변환(월드 행렬)이라고 하였을 때, 이 카메라의 월드 변환(월드 행렬)의 역행렬이 뷰 행렬이 된다는 것이고 이것을 객체들의 정점에 곱해주면 카메라 좌표계를 기준으로 하게 된다는 것이다.

(월드 행렬)

 

(뷰 행렬)

 

뷰 행렬이 위와 같은 모습이 되는 이유를 알아 보자면

뷰 행렬은 기본적으로 카메라의 위치(Eye), up벡터, 카메라가 보고 있는 지점(Look)벡터의 속성들로 뷰 행렬을 구성하게 된다.

 

뷰 행렬을 만들기 위해서 먼저 카메라가 바라보는 방향을 설정하는데 이것을 카메라의 z축으로 설정한다.

 

이후 z축과 Up벡터를 이용해서 카메라의 x, y축 벡터를 만들 수 있다.

 

 

Zaxis  = 카메라가 보고 있는 지점 위치(Look) – 카메라의 위치(Eye);

Zaxis = normalize(Zaxis);

 

Xaxis = Cross(Up, Zaxis);

Xaxis = normalize(Xaxis);

 

Yaxis = Cross( Zaxis, Xaxis);

 

OpenGL의 경우 오른손 좌표계 이므로 마지막 y축을 결정할 때 x와 z축의 순서가 바뀌어야 한다.

 

위와 같이 카메라의 x,y,z축을 구했으니 월드 공간에 있는 정점들의 위치를 연산을 통하여 카메라 공간의 x,y,z축에 위치 하도록 한다.

 

연산은 카메라의 각각의 축을 기준으로 카메라와 정점의 상대 위치 값을 내적하면 된다.

위의 계산을 풀면 다음과 같다.

 

X' = Dot(P – Eye, Xaxis); -> X' = Dot(P, Xaxis) - Dot(Eye, Xaxis);

Y' = Dot(P – Eye, Yaxis); -> Y' = Dot(P, Yaxis) - Dot(Eye, Yaxis);

Z' = Dot(P – Eye, Zaxis); -> Z' = Dot(P, Zaxis) - Dot(Eye, Zaxis);

 

정점의 위치를 4차원 동차 좌표로 바꾸고 행렬을 이용하면 다음과 같이 뷰 행렬이 구해 진다.

 

*shader.fx*

 

float4x4 m_mtWld;  // World
float4x4 m_mtViw;  // View
float4x4 m_mtPrj;  // Projection
float4  m_vcLgt;  // Lighting Direction


texture m_TxDif;
sampler SampDif = sampler_state
{
    Texture = <m_TxDif>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;

    AddressU = Wrap;
    AddressV = Wrap;
};

 

// Vertex Shader Output Structure
struct SVsOut
{
     float4 Pos : POSITION;  // Output Position
     float4 Dif : COLOR0;  // Output Diffuse Color
     float2 Tex : TEXCOORD0; // Output Diffuse Map Coordinate
};


SVsOut VtxPrc0( float3 Pos : POSITION,  // vertex position
    float3 Nor : NORMAL,  // Normal Vector
    float2 Tex : TEXCOORD0  // Diffuse Map )
{
     SVsOut Out = (SVsOut)0;

 

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

 

     P = float4(Pos, 1);
     P = mul(P, m_mtWld);
     P = mul(P, m_mtViw);
     P = mul(P, m_mtPrj);

 

     N = mul(Nor, (float3x3)m_mtWld);  // Rotation Normal Vector

 

     float  D=0;

 

     D = 0.5F * dot(N, L) + 0.5F;   // Lambert I = (V*L+1)/2
     D = pow(D, 1.3f);

 

     Out.Pos = P;       // Output Position
     Out.Dif = D;       // Diffuse
     Out.Tex = Tex;       // Diffuse Map Coordinate

 

     return Out;
}


// Pixel Shader Processing
float4 PxlPrc0(SVsOut In) : COLOR
{
     return In.Dif * tex2D( SampDif, In.Tex ); // Output color = Diffuse * Texture Color
}

 

float  m_GlowThick;  // Glow Thick
float4 m_GlowColor;  // Glow Color
float3 m_GlowAxis;  // Glow Axis


SVsOut VtxPrc1( float4 Pos : POSITION, // vertex position
    float4 Nor : NORMAL, // Normal Vector
    float2 Tex : TEXCOORD0 // Diffuse Map )
{
     SVsOut Out = (SVsOut)0;

 

     float4 P = Pos;
     float3 N = normalize(Nor);
     P +=float4(N,0) * m_GlowThick;
     P = mul(P, m_mtViw);
     P = mul(P, m_mtPrj);


     float Power=0.F;
     Power  = (1+ dot(N, m_GlowAxis) ) * 0.6666F;  // Glow Color Intensity
     Power = pow(Power, 4.0);       // Glow = Glow ^ 4

 

     Out.Pos = P;          // Output Position
     Out.Dif  = m_GlowColor * Power;

 

     Out.Tex = Tex;          // Diffuse Map Coordinate

 

     return Out;
}


// Pixel Shader Processing
float4 PxlPrc1(SVsOut In) : COLOR
{
     return In.Dif;
}


technique Tech0
{
 // Model Rendering
 pass P0
 {
      LIGHTING = FALSE;
      CULLMODE = NONE;

 

      ALPHABLENDENABLE= False;
      ZWRITEENABLE = TRUE;

 

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


 }

 // Glow Effect Rendering
 pass P1
 {
      LIGHTING = FALSE;
      CULLMODE = CW;

 

      ALPHABLENDENABLE= TRUE;
      SRCBLEND  = SRCALPHA;
      DESTBLEND  = DESTALPHA;
      ZWRITEENABLE = FALSE;

 

      VertexShader = compile vs_3_0 VtxPrc1();
      PixelShader  = compile ps_3_0 PxlPrc1();
 }
}

이번 셰이더 파일은 고정 파이프라인이 아닌 우리가 직접 작성하는 프로그램 가능한 파이프 라인을 이용 한다.

  

P0 패스는 VtxPrc0의 정점 처리 함수와 PxlPrc0의 픽셀 처리 함수를 사용하여 "earth.bmp" 텍스처를 이용한 지구를 랜더링하고, 램버트 확산 기법을 적용 하고 있다.

 

P1 패스는 VtxPrc1의 정점 처리 함수와 PxlPrc1의 픽셀 처리 함수를 사용하여 Glow를 구하는 연산 과정을 거친 후 적용 하고 있다.

728x90

'Shader' 카테고리의 다른 글

파도 흉내 내보기...  (0) 2017.08.31
17. Effect의 상태 설정.  (0) 2017.03.10
16. D3DEffect  (1) 2017.02.14
15. 다중 텍스처 처리(Multi-Texturing)  (0) 2017.02.13
14. 텍스처 처리(단색화, 흐림효과)  (0) 2017.02.09
Posted by 정망스
,
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 정망스
,

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 정망스
,
728x90

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

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

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

  VtxDUV1() : p(0, 0, 0), d(0xFFFFFFFF) {}
  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), };
 };

 

LPDIRECT3DPIXELSHADER9  m_pPs;    // Pixel Shader
LPD3DXCONSTANTTABLE  m_pTbl;    // Constant Table

 

D3DXMATRIX  m_mtWld;   // World Matrix

 

INT   m_iNvx;    // Vertex Number
VtxDUV1* m_pVtx;    // Vertex Buffer
LPDIRECT3DTEXTURE9  m_pTx0;

 

포지션(xyz), 색상(diffuse), 텍스처(tex1)로 구성된 정점 데이터이다.

 

*shader.fx*

 

sampler smp0 : register(s0);

 

float4 PxlPrc( in float4 Dif : COLOR0, in float4 Tex0 : TEXCOORD0 ) : COLOR0
{

float4 Out;

Out = tex2D(smp0, Tex0);   // Sampling Texture with Sampler
Out *= Dif;       // Modulate Diffuse
Out *= 2;       // Modulate2X

 

return Out;

}

 

1. 다중 텍스처 처리일 경우 샘플러를 샘플러 레지스터에 명시적으로 선언을 해주어야 한다.

pDevice->SetTexture(StageIndex, pTexture)와 같은 함수를 실행 할 때 stageIndex에 해당하는 레지스터에 텍스처 포인터가 자리 잡고 이 텍스처를 샘플러가 샘플링 한다.

 

2. 모든 샘플링 함수는 샘플러와, 텍스처 좌표를 인수로 받는다. 따라서 픽셀 처리의 함수는 텍스처 좌표의 정보를 받아야한다.

 

3. 래스터라이즈 이후 만들어진 색상과, 텍스처의 색상을 modulate 한다.

 

*Update()*

 

static float c = 0;

 

c = 10.f * GetTickCount();

 

if (c>360.f)
  c -= 360.f;

 

D3DXMATRIX mtY;
D3DXMATRIX mtZ;


// 월드 행렬 갱신
D3DXMatrixIdentity(&m_mtWld);
D3DXMatrixRotationY(&mtY, D3DXToRadian(-c));
D3DXMatrixRotationZ(&mtZ, D3DXToRadian(-23.5f));

 

m_mtWld = mtY * mtZ;

 

구를 회전 시키기 위한 처리. z축은 고정값,  y축은 일정 시간 기준으로 계속해서 회전값을 바꾸면서 월드행렬에 적용시키고 있다.

 

*Render()*

 

m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);
m_pdev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
m_pdev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
m_pdev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

 

m_pdev->SetTransform(D3DTS_WORLD, &m_mtWld);


// Render
m_pdev->SetPixelShader(m_pPs);

 

m_pdev->SetFVF(VtxDUV1::FVF);
m_pdev->SetTexture(0, m_pTx0);
m_pdev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, m_iNvx - 2, m_pVtx, sizeof(VtxDUV1));

 

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


D3DXMATRIX mtI(1, 0, 0, 0,
                        0, 1, 0, 0,
                        0, 0, 1, 0,
                        0, 0, 0, 1);

 

m_pdev->SetTransform(D3DTS_WORLD, &mtI);

 

셰이더 파일에서 샘플러를 StageIndex 0번에 해당하는 레지스터에 등록했으므로 SetTexture 함수의 StageIndex에 0을 설정해준다.

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

  VtxDUV1() : p(0, 0, 0), d(0xFFFFFFFF) {}
  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), };
 };

 

LPDIRECT3DPIXELSHADER9  m_pPs;    // Pixel Shader
LPD3DXCONSTANTTABLE  m_pTbl;    // Constant Table

 

VtxDUV1  m_pVtx[4];   // Vertex Buffer
LPDIRECT3DTEXTURE9  m_pTx0;
LPDIRECT3DTEXTURE9  m_pTx1;
LPDIRECT3DTEXTURE9  m_pTx2;

 

포지션(xyz), 색상(diffuse), 텍스처(tex1)로 구성된 정점 데이터이다. 이번엔 사각형이므로 정점은 4개로 구성되고 , 3개의 텍스처(m_pTx0, m_pTx1, m_pTx2)를 사용한다. 

 

 *shader.fx*

// SetTexture에 해당하는 샘플러 ==> 레지스터에 지정
//sampler smpDif0 : register(s0); // pDev->SetTexture(0, ...)
//sampler smpDif1 : register(s1); // pDev->SetTexture(1, ...)


// Smapler state를 이용한 샘플러 객체 선언
sampler smpDif0 : register(s0) = sampler_state
{
    MinFilter = POINT;  // Filtering
    MagFilter = POINT;
    MipFilter = POINT;
    AddressU = Wrap;  // Addressing
    AddressV = Wrap;
};

sampler smpDif1 : register(s1) = sampler_state
{
    MinFilter = NONE;
    MagFilter = NONE;
    MipFilter = NONE;
    AddressU = Wrap;
    AddressV = Wrap;
};

sampler smpDif2 : register(s2) = sampler_state
{
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};


float4 PxlPrc( in float4 Dif : COLOR0, in float2 Tx0 : TEXCOORD0 ) : COLOR0
{
     float4 Out;
     float4 t0;
     float4 t1;
     float4 t2;

 

     t0 = tex2D(smpDif0, Tx0); // Sampling Texture0
     t1 = tex2D(smpDif1, Tx0); // Sampling Texture1
     t2 = tex2D(smpDif2, Tx0); // Sampling Texture2

 

     Out = t0 *.6 + t1 * .8;
     Out *= (t2*1.3f);

 

     Out = pow(Out, 1.5) * 1.5;

 

     Out.w = 1;     // Setup alpha = 1

 

     return Out;
}

 

sampler_state를 사용하여 샘플러를 레지스터에 등록함과 동시에 샘플러에 대해서 필터링과 어드레싱을 할수있다.

 

t0 = 지구, t1 = 다이렉트x 로고, t2 = 중간에 흰색으로 된 산모양  의 세가지 텍스처를 이용한다.

 

D3DXCreateTextureFromFile(m_pdev, "Texture/earth.bmp", &m_pTx0);
D3DXCreateTextureFromFile(m_pdev, "Texture/dx5_logo.bmp", &m_pTx1);
D3DXCreateTextureFromFile(m_pdev, "Texture/env0.png", &m_pTx2);

 

m_pVtx[0] = VtxDUV1(-1.05F, 1.02F, 0, 0, 0, D3DXCOLOR(1, 0, 0, 1));
m_pVtx[1] = VtxDUV1(1.05F, 1.02F, 0, 1, 0, D3DXCOLOR(0, 1, 0, 1));
m_pVtx[2] = VtxDUV1(1.05F, -1.02F, 0, 1, 1, D3DXCOLOR(0, 0, 1, 1));
m_pVtx[3] = VtxDUV1(-1.05F, -1.02F, 0, 0, 1, D3DXCOLOR(1, 0, 1, 1));

 

세 개의 텍스처 파일을 가져오고 정점 4개 각각 위치, uv좌표, 색상을 설정하고 있다.

 

*Render()*

m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);

 

m_pdev->SetPixelShader(m_pPs);

 

m_pdev->SetFVF(VtxDUV1::FVF);

 

m_pdev->SetTexture(0, m_pTx0);
m_pdev->SetTexture(1, m_pTx1);
m_pdev->SetTexture(2, m_pTx2);

 

m_pdev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, m_pVtx, sizeof(VtxDUV1));


m_pdev->SetTexture(0, NULL);
m_pdev->SetTexture(1, NULL);
m_pdev->SetTexture(2, NULL);

 

m_pdev->SetPixelShader(NULL);

 

StageIndex( 0, 1, 2 )에 3개의 텍스처를 설정해주고 있다.

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

  VtxDUV1() : p(0, 0, 0), d(0xFFFFFFFF) {}
  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), };
 };

 

LPDIRECT3DPIXELSHADER9  m_pPs;    // Pixel Shader
LPD3DXCONSTANTTABLE  m_pTbl;    // Constant Table

 

LPDIRECT3DTEXTURE9  m_pTx0;    // Texture 0
LPDIRECT3DTEXTURE9  m_pTx1;    // Texture 1

 

포지션(xyz), 색상(diffuse), 텍스처(tex1)로 구성된 정점 데이터이다. 2개의 텍스처(m_pTx0,m_pTx1)를 사용한다. 

 

*shader.fx*

 

// Multi Texturing Type
int  m_nMulti;


// Sampler
sampler SampDif0 : register(s0) = sampler_state
{
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

sampler SampDif1 : register(s1) = sampler_state
{
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

 

// Pixel Shader Main Function
float4 PxlPrc(float4 Tx0 : TEXCOORD0) : COLOR0
{
     float4 Out= 0;
     float4 t0 = tex2D( SampDif0, Tx0 );   // Sampling m_TxDif0
     float4 t1 = tex2D( SampDif1, Tx0 );   // Sampling m_TxDif1

 

     if (0 == m_nMulti)  Out = t0;
     else if (1 == m_nMulti) Out = t1;
     else if (2 == m_nMulti) Out = t0 * t1;   // Modulate
     else if (3 == m_nMulti) Out = t0 * t1 * 2;  // Modulate 2x
     else if (4 == m_nMulti) Out = t0 * t1 * 4;  // Modulate 4x
     else if (5 == m_nMulti) Out = t0 + t1;   // Add
     else if (6 == m_nMulti) Out = t0 + t1 - .5;  // Add signed
     else if (7 == m_nMulti) Out =(t0 + t1 - .5)*2; // Add signed
     else if (8 == m_nMulti) Out = t0 + t1 - t0*t1; // add smooth
     else if (9 == m_nMulti) Out = t0 - t1;   // sub
     else if (10== m_nMulti) Out = t1 - t0;   // sub
     else if (11== m_nMulti) Out = 1 - t0;   // Inverse t0
     else if (12== m_nMulti) Out = 1 - t1;   // Inverse t1
     else if (13== m_nMulti) Out = 1 - (t0 + t1); // Inverse (t0+t1)

 

     return Out;
}

 

다중 텍스처 처리1,2 과정을 함께 이용하여 if-else문을 사용하서 m_nMulti의 값과 일치하는 조건문에 해당하는 산술 연산을 하여 처리하고 있다.

 

t0 (지구), t1 (다이렉트x 로고) 2가지 텍스처를 사용하고 있다. 

 

*Render()*

 

HRESULT  hr = -1;

 

m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);

 

m_pdev->SetPixelShader(m_pPs);

 

m_pdev->SetFVF(VtxDUV1::FVF);
m_pdev->SetTexture(0, m_pTx0);
m_pdev->SetTexture(1, m_pTx1);

 

VtxDUV1 pVtx[4];

 

for (int i = 0; i <= 13; ++i)
{
  float x = -1.f + float(i % 4) / 2.f;
  float y = 1.f - float(i / 4) / 2.f;

 

  pVtx[0] = VtxDUV1(x + 0.f, y - 0.f, 0, 0, 0, D3DXCOLOR(1, 0, 0, 1));
  pVtx[1] = VtxDUV1(x + .5f, y - 0.f, 0, 1, 0, D3DXCOLOR(0, 1, 0, 1));
  pVtx[2] = VtxDUV1(x + .5f, y - .5f, 0, 1, 1, D3DXCOLOR(0, 0, 1, 1));
  pVtx[3] = VtxDUV1(x + 0.f, y - .5f, 0, 0, 1, D3DXCOLOR(0, 0, 1, 1));

 

  hr = m_pTbl->SetInt(m_pdev, "m_nMulti", i);
  hr = m_pdev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, pVtx, sizeof(VtxDUV1));
}

 

m_pdev->SetPixelShader(NULL);

 

m_nMulti값 (0~13) 총 14개의 텍스처 처리 연산의 종류가 있고 for문을 이용하여 사각형에 1개씩 처리하여 그리고 있다.

728x90

'Shader' 카테고리의 다른 글

17. Effect의 상태 설정.  (0) 2017.03.10
16. D3DEffect  (1) 2017.02.14
14. 텍스처 처리(단색화, 흐림효과)  (0) 2017.02.09
13. 픽셀 처리 사용자 함수  (0) 2017.02.09
12. 알록달록 사각형(간단한 픽셀 처리)  (0) 2017.02.09
Posted by 정망스
,


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