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

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

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

struct VtxRHWDUV1
 {
  D3DXVECTOR4 p;
  DWORD d;
  FLOAT u, v;

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

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

 

VtxRHWDUV1 m_pVtx[4];   // Vertex Buffer

LPDIRECT3DVERTEXDECLARATION9  m_pFVF;    // Declarator
LPDIRECT3DPIXELSHADER9  m_pPs;    // Pixel Shader
LPD3DXCONSTANTTABLE  m_pTbl;    // Constant Table

LPDIRECT3DTEXTURE9  m_pTx;    // Texture 0

 

이번 정점 데이터의 구조는 w값을 추가로 가지는 XYZRHW, 색상값을 가지는 DIFFUSE, 텍스처를 나타내는 TEX1의 구조로 되어있다.

 

XYZ : 3d 공간상의 좌표, 정점의 변환이 완료되지 않은 좌표(스크린 좌표)

XYZRHW : 2d 인터페이스 좌표에 사용, 정점의 변환이 완료된 좌표(윈도우 좌표)

 

스크린 좌표 : 중심점(0,0) 가운데, 우측으로 x, 위로 y

윈도우 좌표 : 중심점(0,0) 좌측상단, 우측으로 x, 아래로 y 

 

*shader.fx*(단색화)

 

sampler SampDif : register(s0);

 

float4 PxlPrc(float2 Tx0 : TEXCOORD0 /* Texture Coordinate */) : COLOR
{
     float4 Out=0.0F;
     float4 MonoColor ={0.5F, 1.0F, 2.0F, 1.0F};  // 단색화 색상(색상 :   )
     float4 MonoWeight={0.299F, 0.587F, 0.114F, 0.0F}; // 단색화 비중

 

     Out = tex2D( SampDif, Tx0 ); // 샘플링

     Out = dot(Out, MonoWeight);  // 내적(dot)로 단색화
     Out *= MonoColor;    // 단색화 색상을 곱함

 

     Out *= 3.0F;     // Aux: 전체 밝기를 올림
     Out.a = 1.0F;     // 불투명 픽셀로 설정

 

     return Out;
}

 

tex2D 함수를 통해 SampDif(텍스처)에서 Tx0(좌표)의 픽셀값을 가져와 이 값을 MonoWeight(단색화 비중)값과 내적을 시켜 준다.

 

그러면 현재 좌표 픽셀의 단색화 값이 나오게 되고 여기에 MonoColor(단색화 색상)을 곱해주면 비율만큼 색상이 입혀지게 된다.

 

현재 이 코드에는 단색화 비중이 초록색에 가까울수록 제일 높고 파란색에 가까울 경우 낮다.

 

그래서 위 결과 사진을 보면 원본 사진에서 파란색일 경우 연한 파란색이 되고 초록색일 경우 찐한 파란색이 되고 있다.  

 

*shader.fx*(흐림 효과)

 

sampler SampDif : register(s0);

 

float4 PxlPrc(float2 Tx0 : TEXCOORD0 /* Texture Coordinate */) : COLOR
{
     float4 Out=0.0F;

     // 흐림 효과의 픽셀은 인접한 픽셀에 비중을 곱한 값을 누적해서 결정
     // 텍스처 좌표를 변화시키면서 인접한 픽셀을 샘플링
     // Gaussian 분포: exp (x*x/Delta) 값을 픽셀의 비중으로 설정

     for(int x=-4; x<=4; ++x)
     {
          float2 T = Tx0;
          T.x += (2.f * x)/1024.f;      // 텍스처 좌표를 변화시킨다
          Out += tex2D( SampDif, T ) * exp( (-x*x)/8.f); 
// 픽셀을 샘플링하고 가우스 분포 함수로 구한 비중 값을 곱한 후 더한다.

     }

 

     Out *= 0.24F; // 전체 명도를 낮춤
     Out.a = 1.0f; // 불투명 픽셀로 설정

 

     return Out;
}

 

흐림 효과는 인접한 픽셀에 비중 값을 곱하고 더하고를  최종 색상을 만들어 낸다.

 

여기서는 대표적인 알고리즘인 Gaussian Blur을 이용한 방법이다.

Gaussian Blur은 인접한 픽셀까지의 거리를 가지고 비중 값을 exp() 함수로 결정한다.

 

최종 색상 = 

 

인접한 픽셀의 텍스처 좌표를 변화시킨 후에 tex2D() 함수를 사용하여 좌표에 해당하는 픽셀값(P)에 Gaussian 분포값 (exp (x*x/Delta))을 곱하면 최종색상이 나오고 이 값을 출력될 값(Out)에 더해주는것을 for문을 이용해 반복적으로 적용한다.

*shader.fx*(단색화 + 흐림효과)

 

sampler SampDif : register(s0);

 

float4 PxlPrc(float2 Tx0 : TEXCOORD0 /* Texture Coordinate */) : COLOR
{
     float4 Out=0.0F;
     float4 MonoColor ={0.5F, 1.0F, 2.0F, 1.0F};
     float4 MonoWeight={0.8F, 0.9F, 1.0F, 0.0F};

 

     // 텍스처 좌표를 변화시키면서 인접한 픽셀을 샘플링
     // Gaussian 분포: exp (x*x/Delta) 값을 픽셀의 비중으로 설정
     for(int x=-4; x<=4; ++x)
     {
          float2 T = Tx0;
          
T.x += (2.f * x)/1024.f;      // 텍스처 좌표를 변화시킨다
          Out += tex2D( SampDif, T ) * exp( (-x*x)/8.f); // 픽셀을 샘플링하고 가우스 분포 함수로 구한 비중 값을 곱한 후 더한다.
     }

     Out = dot(Out, MonoWeight);  // 단색화
     Out *= MonoColor;    // 단색에 적용할 색상을 곱함


     Out *= 0.18F;     // 전체 명도를 낮춤
     Out.a = 1.0f;     // 불투명 픽셀로 설정

 

     return Out;
}

단색화와 흐림효과 2개를 동시에 적용한 셰이더 파일.

 

*Render()*

 

m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);
m_pdev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

 

m_pdev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
m_pdev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

 

m_pdev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
m_pdev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
m_pdev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);

 

m_pdev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
m_pdev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
m_pdev->SetSamplerState(0, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP);

 

m_pdev->SetVertexDeclaration(m_pFVF);
m_pdev->SetPixelShader(m_pPs);

 

m_pdev->SetFVF(VtxRHWDUV1::FVF);
m_pdev->SetTexture(0, m_pTx);

 

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


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

 

m_pdev->SetTexture(0, NULL);

m_pdev->SetPixelShader(NULL);

 

SetSamplerState() 함수를 사용하여 u,v,w 값 [0,1]의 범위를 벗어난 정규화 되지 않은 텍스처 좌표에대한 처리를 CLAMP 모드로 설정해주고 있다.

728x90
Posted by 정망스
,
728x90

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

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

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

  VtxD() : p(0, 0, 0), d(0xFFFFFFFF) {}
  VtxD(FLOAT X, FLOAT Y, FLOAT Z, DWORD D = 0XFFFFFFFF) : p(X, Y, Z), d(D) {}

  enum { FVF = (D3DFVF_XYZ | D3DFVF_DIFFUSE) };

 };

 

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

INT   m_nType;   // Pixel Processing Type

VtxD  m_pVtx[4];   // Vertex Buffer

 

포지션과, 색상 값으로 구성된 정점 데이터이다.

 

*shader.fx*


// Pixel Processing Type
int g_nPxlPrc = 2;


// 1.Color Inversion
float4 PxlInverse(float4 Input)
{
     return 1 - Input;
}

// 2.Color Monotone
float4 PxlMonotone(float4 InColor)
{
     float4 Out = 0.f;
     float4 d = float4(0.299, 0.587, 0.114, 0);
     float4 t = InColor;
 
     Out = dot(d, t);
     Out.w = 1;
     return Out;
}

// Main Pixel Processing
float4 PxlPrc( in float4 iDif : COLOR0  // From Vertex Processing
) : COLOR0
{
     float4 Out=float4(0,0,0,1);

     if(1== g_nPxlPrc)
      Out = PxlInverse(iDif);
 
     else if(2 == g_nPxlPrc)
      Out = PxlMonotone(iDif);
 
     else
      Out = iDif;

 

     return Out;
}

 

if문을 통해서 g_nPxlPrc의 값이 0이면 기존색상, 1이면 색상 반전, 2이면 단색화 과정을 처리하고 있다.

 

*Render()*

 

HRESULT hr = 0;

 

m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);

 

m_pdev->SetPixelShader(m_pPs);

 

m_nType = 2;

 

// 픽셀 shader 전역 변수 값 설정
hr = m_pTbl->SetInt(m_pdev, "g_nPxlPrc", m_nType);

 

m_pdev->SetFVF(VtxD::FVF);
m_pdev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, m_pVtx, sizeof(VtxD));

 

m_pdev->SetPixelShader(NULL);

 

m_nType의 int형 값을 셰이더의 전역 변수 g_nPxlPrc에 설정해주면서 설정 값에 따른 픽셀 처리 과정을 하게끔 하고 있다.

728x90
Posted by 정망스
,
728x90

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

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

struct VtxD
 {
  D3DXVECTOR3 p;
  DWORD d;

  VtxD() : p(0, 0, 0), d(0xFFFFFFFF) {}
  VtxD(FLOAT X, FLOAT Y, FLOAT Z, DWORD D = 0XFFFFFFFF) : p(X, Y, Z), d(D) {}

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

 

LPDIRECT3DDEVICE9  m_pDev;    // Device

LPDIRECT3DPIXELSHADER9  m_pPs;    // Pixel Shader
VtxD  m_pVtx[4];   // Vertex Buffer

 

이번엔 픽셀 셰이더를 사용하기 때문에, LPDIRECT3DPIXELSHADER9 가 새로 추가 되었다.

 

*shader.fx*

 

1. 

// float4 PxlPrc(float4 iDif : COLOR0  // From Vertex Processing
//     ) : COLOR0
// {
//  return iDif;
// }

 

2.
void PxlPrc( in float4 iDif : COLOR0  // From Vertex Processing
   , out float4 oDif: COLOR0  // Output oC0
)
{
 oDif = iDif;
}

 

프로그램 가능한 픽셀 파이프라인은 픽셀의 샘플링(Sampling)와, 다중 텍스처 처리(Multi-Texturing)이다.

 

픽셀 파이프라인에 입력되는 데이터는 정점 처리 과정의 Rastering을 통해서 만들어진 픽셀, 텍스처 좌표, 텍스처 이다.

 

픽셀 처리의 결과는 색상이기 때문에 출력은 float4형이고 시맨틱은 COLOR로 한다.

 

1번은 반환형이 있는 함수를 작성할때, 2번은 void형으로 함수를 작성할때의 방법이다.

 

Create()

 

HRESULT hr = 0;

 

hr = D3DXCompileShaderFromFile(
  "data/Shader.fx"
  , NULL
  , NULL
  , "PxlPrc" // shader 실행 함수
  , "ps_2_0" // shader 버전
  , dwFlags
  , &pShd
  , &pErr
  , NULL
 );

 

hr = m_pdev->CreatePixelShader((DWORD*)pShd->GetBufferPointer(), &m_pPs);

 

정점 처리와 마찬가지로 픽셀 처리도 D3DXCompileShaderFromFile 함수를 사용해서 컴파일을 해야 한다.

 

이 후 컴파일 결과를 가지고 CreatePixelShader 함수를 사용해서 픽셀 셰이더를 생성한다.

 

Render()

 

m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);

 

m_pdev->SetPixelShader(m_pPs);  // Pixel Shader 사용

 

m_pdev->SetFVF(VtxD::FVF);
m_pdev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, m_pVtx, sizeof(VtxD));

 

m_pdev->SetPixelShader(NULL);  // Pixel Shader 해제

 

그전 정점 처리 과정과 다른건 SetPixelShader() 함수를 사용해서 픽셀 셰이더의 사용과 해제를 알려준다는 것이다.

그리고 SetFVF라는 함수가 새로 나왔는데 그전 정점 처리 과정에서 사용하던 SetVertexDeclaration() 함수와 사용 의미는 거의 같다고 한다. 차이점은 정점 정보 선언을 SetVertexDeclaration을 이용할 경우 훨씬 많은 데이터를 포함할수가 있다는 이유 때문에 사용한다고 한다.

728x90
Posted by 정망스
,
728x90

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

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

 struct VtxN
 {
   D3DXVECTOR3 p;
   D3DXVECTOR3 n;

   VtxN() : p(0, 0, 0), n(0, 0, 0) {}
   VtxN(FLOAT X, FLOAT Y, FLOAT Z
    , FLOAT Nx, FLOAT Ny, FLOAT Nz) : p(X, Y, Z), n(Nx, Ny, Nz) {}

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


LPDIRECT3DVERTEXSHADER9  m_pVs;    // Vertex Shader
LPDIRECT3DVERTEXDECLARATION9  m_pFVF;    // Declarator
LPD3DXCONSTANTTABLE  m_pTbl;

 

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

 

INT   m_iNvx;    // Vertex Number
VtxN*  m_pVtx;    // Vertex Buffer

 

포지션과, 법선 벡터 데이터로 이루어진 정점 구조체 이다.

 

*shader.fx* (퐁 반사)

 

float4x4 m_mtWld; // World Matrix
float4x4 m_mtViw; // View Matrix
float4x4 m_mtPrj; // Projection Matrix

 

float3x3 m_mtRot; // Rotation

 

float3 m_vcCam; // Camera Position
float m_fSharp; // Sharpness


float3 m_LgtDir; // Lighting Direction
float4 m_LgtDif; // Lighting Color


// For Vertex Processing Output
struct SvsOut
{
 float4 Pos : POSITION ; // oPos
 float4 Dif : COLOR0  ; // oD0
};


SvsOut VtxPrc( float4 Pos : POSITION0   , float3 Nor : NORMAL0)
{
 float4 P;
 float3 X;
 float3 N;

 

 SvsOut Out = (SvsOut)0;    // Initialized to 0
 P = Pos;
 P = mul(P, m_mtWld);    // Transform World
 X = P;        // Save Transformed Position
 P = mul(P, m_mtViw);    // Transform View
 P = mul(P, m_mtPrj);    // Transform Projection

 

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

 

 float3 L = -m_LgtDir;    // Lighting Direction is -Light
 float3 E = normalize(m_vcCam - X); // Normalize Eye Vector
 float3 R = reflect(-L, N);   // Reflection Vector

 

 float  Phong = saturate(dot(R, E)); // Dot R, E

 

 Phong = pow(Phong, m_fSharp);  // Phong Reflection Intensity

 

 Out.Pos = P;      // Output Position
 Out.Dif = m_LgtDif * Phong;   // Output Diffuse = Light Color * Phong

 

 return Out;
}

 

퐁 반사는 정점의 법선 벡터(N)에 의해 반사되는 빛의 반사 벡터(R)와 정점에서 바라보는 카메라에 대한 시선 벡터(E)의 내적의 결과에 멱승(Power)으로 하이라이트(Sharpness) 세기를 구한다.

 

정점의 법선 벡터(N)와 빛의 방향 벡터(L)을 이용하여 반사 벡터(R)을 구한 후 반사의 세기를 결정한다.

 

R = 2 * dot(N, L) * N – L

퐁 반사 밝기 = power(Dot(R, E), Sharpness)

 

D3D에선 반사 벡터를 구해주는 내장 함수 reflect() 가 있다 이 함수는 빛의 방향을 반대 방향으로 값을 주어야 한다. 

 

reflect(L, N) = L - 2 * dot(L, N) * N

반사 벡터 R = reflect(-L, N)

 

멱승(Power)을 구하는 함수는 pow() 이다.

   

float3 m_vcLgt;        // 빛의 방향 벡터

float3 vcNor;  // 정점의 법선 벡터

float3 vcEye;  // 정점에서 카메라 위치를 바라본 시선 방향 벡터

float3  vcR = reflect(-m_vcLgt, vcNor);

float4  Phong = pow( dot(vcR,  vcEye), m_fSharp);

 

주의 해야 할 것은.

1.반사 벡터를 정점에서 카메라의 위치를 바라본 시선 방향 벡터를 구할 때는 구하기 전에 정점의 위치를 월드 변환 시켜 주어야 한다. 카메라와 같은 월드 공간에 위치 시켜 계산 하기 위해서 이다.

 

2.반사 벡터를 구할때는 법선 벡터에 회전 변환을 적용 한 후 구해야 한다.

법선 벡터는 정규화를 통해 법선 벡터의 방향만을 알아내기 위함이기 때문에 방향에 영향을 주는 것은 회전 변환 이기 때문이다.

 

loat4x3 m_mtWld;      // 월드 행렬

float3x3 m_mtRot;      // 회전 행렬

float3  m_vcCam;      // 카메라 위치

float3  m_vcLgt;      // 빛의 방향 벡터

 

float3 vcPos = mul(float4(In.Pos, 1), m_mtWld);      // 위치의 월드 변환

float3 vcNor = mul(In.Nor, m_mtRot);         // 법선의 회전 변환

float3 vcEye = normalize( m_vcCam - vcPos);  // 시선 벡터의 정규화

float3 vcRfc = reflect(-m_vcLgt, vcNor);     // 반사 벡터

float4 Phong = pow( dot(vcRfc, vcEye), m_fSharp); // 퐁 반사 세기

 

*shader.fx* (블린-퐁 반사) 

 

float4x4 m_mtWld; // World Matrix
float4x4 m_mtViw; // View Matrix
float4x4 m_mtPrj; // Projection Matrix

 

float3x3 m_mtRot; // Rotation

 

float3 m_vcCam; // Camera Position
float m_fSharp; // Sharpness


float3 m_LgtDir; // Lighting Direction
float4 m_LgtDif; // Lighting Color


// For Vertex Processing Output
struct SvsOut
{
 float4 Pos : POSITION ; // oPos
 float4 Dif : COLOR0  ; // oD0
};


SvsOut VtxPrc( float4 Pos : POSITION0   , float3 Nor : NORMAL0)
{
 float4 P;
 float3 X;
 float3 N;

 

 SvsOut Out = (SvsOut)0;    // Initialized to 0
 P = Pos;
 P = mul(P, m_mtWld);    // Transform World
 X = P;        // Save Transformed Position

 P = mul(P, m_mtViw);    // Transform View
 P = mul(P, m_mtPrj);    // Transform Projection

 

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

 

 float3 L = -m_LgtDir;    // Lighting Direction is -Light
 float3 E = normalize(m_vcCam - X); // Normalize Eye Vector
 float3 H = normalize(E + L);  // Half Vector

 

 float  Blinn = saturate(dot(N, H)); // Dot N, H

 

 Blinn = pow(Blinn, m_fSharp);  // Blinn-Phong Reflection Intensity

 

 Out.Pos = P;      // Output Position
 Out.Dif = m_LgtDif * Blinn;   // Output Diffuse = Light Color * Blinn

 

 return Out;
}

 

블린-퐁 반사는 반사 벡터와, 시선 벡터를 사용하지 않고, 하프 벡터와, 정점의 법선 벡터를 이용한다.

 

Half 벡터 = normalize(E + L)

Blinn-Phong 반사 세기 = Dot(N, H)^Sharpness

 

여기서 하프 벡터란, 두 벡터 ( E(시선 벡터), L(빛의 방향 벡터) )의 덧셈으로 인해 이루어지는 평행사변형의 대각선 성분을 하프 벡터라고 한다.

 

두 벡터가 정규화 되어 길이가 1인 벡터라면 평행사변형의 모든 변의 길이가 1이 되고 대각선분이 평행사변형을 두 개의 삼각형으로 나눌 경우 두 삼각형이 두변의 길이가 같고 사이각이 같은 합동 삼각형이 되므로 E, L 벡터의 사이각을 정확하게 2등분 하기 때문에,

 

하프 벡터 H = E + L 에 정규화를 하면 H = E + L / | E + L | 가 되는것이고

위의 셰이더 코드 부분에선 float3 H = normalize(E + L);  // Half Vector 이다.

 

Render()

 

HRESULT hr = 0;

 

m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);

 

D3DXMATRIX mtViw;   // View Matrix
D3DXMATRIX mtPrj;   // Projection Matrix

 

D3DXMATRIX mtWld;   // World Matirx
D3DXVECTOR4 vcCam;   // Camera Position

 

FLOAT  fSharp = 10.f; // Sharpness

 

D3DXCOLOR color(1, 0.6f, 1, 0);
D3DXVECTOR4 vcLgt(-1, -1, 0.f, 0);

 

D3DXVec4Normalize(&vcLgt, &vcLgt);


// Get View and Projection Matrix
m_pdev->GetTransform(D3DTS_VIEW, &mtViw);
m_pdev->GetTransform(D3DTS_PROJECTION, &mtPrj);


D3DXMATRIX mtViwI;
D3DXMatrixInverse(&mtViwI, NULL, &mtViw);
vcCam = D3DXVECTOR4(mtViwI._41, mtViwI._42, mtViwI._43, 0);

 

m_pdev->SetVertexDeclaration(m_pFVF);
m_pdev->SetVertexShader(m_pVs);

 

hr = m_pTbl->SetMatrix(m_pdev, "m_mtWld", &m_mtWld);
hr = m_pTbl->SetMatrix(m_pdev, "m_mtViw", &mtViw);
hr = m_pTbl->SetMatrix(m_pdev, "m_mtPrj", &mtPrj);
hr = m_pTbl->SetMatrix(m_pdev, "m_mtRot", &m_mtRot);

 

hr = m_pTbl->SetVector(m_pdev, "m_vcCam", &vcCam);
hr = m_pTbl->SetFloat(m_pdev, "m_fSharp", fSharp);
hr = m_pTbl->SetVector(m_pdev, "m_LgtDir", &vcLgt);
hr = m_pTbl->SetVector(m_pdev, "m_LgtDif", (D3DXVECTOR4*)&color);

 

m_pdev->SetTexture(0, NULL);
m_pdev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, m_iNvx - 2 , m_pVtx, sizeof(CTest12::VtxN));

 

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

 

뷰 행렬을 얻어와서 역행렬을 구해 월드상의 카메라 위치를 알아와 vcCam에 x,y,z 값을 설정해준다.

셰이더에서 정점에서 카메라를 바라보는 시선 벡터를 구할때의 정점이 월드 공간의 좌표이기때문에 일치 시켜주기 위해서이다.

728x90
Posted by 정망스
,


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