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

 

이번엔 법선벡터를 나타내는 D3DXVECTOR3 n, D3DFVF_NORMAL 추가된다.

 

 *shader.fx*

 

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

 

float3x3 m_mtRot; // Rotation

 

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

 

static float m_Sat_A = 0.5f; // Saturation Flag A
static float m_Sat_B = 0.5f; // Saturation Flag B


// 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 N;

 

  SvsOut Out = (SvsOut)0;    // Initialized to 0
  P = Pos;
  P = mul(P, m_mtWld);    // Transform World
  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;    // 빛의 반대 방향 벡터

 

  float  ReflectIntensity = saturate(m_Sat_A * dot(N, L) + m_Sat_B);

 

  Out.Pos = P;
  Out.Dif = m_LgtDif * ReflectIntensity;

 

  return Out;
}

 

굵은 부분을 위주로 보면 되는 셰이더 코드 이다.

빛의 방향과 정점의 법선벡터를 이용하여 반사될 빛의 세기를 구하여 정점의 diffuse에 설정하는 과정이다.

 

분산 조명은 램버트 확산 이론에 기초를 두고 있다고 한다.

빛의 세기를 빛의 방향(L)과, 정점의 법선 벡터(N)와의 내적을 통해서 구한다.

 

반사 밝기 = Dot(N, L)

 

이 공식을 그대로 적용하면 값의 범위가 -1.0 ~ +1.0이 나오는데 음수 값에선 보이지 않으므로

음수 값을 제거 하기 위해서 saturation을 적용한다.

 

반사 밝기 = saturate( Dot(N, L) )

 

하지만 현실 세계에서 빛은 공기 때문에 산란이 생겨서 90도가 넘어도 약간의 반사가 있다고 한다.그래서 아래와 같은 공식으로 이런 부분을 처리할 수 있다고 한다.

 

반사 밝기 = (Dot(N, L) + 1) /2

 

이 공식을 일반화 시키면 아래와 같다. a(Saturation Flag A), b(Saturation Flag B)

 

반사 밝기 = saturate ( a * Dot(N, L) + b )

 

외부에서 Saturation 값을 바꾸고 싶으면 static 키워드를 해제 하면 되고, 정점의 법선 벡터(N) 같은 경우는 내적을 구하는 dot() 함수를 사용하기 전에 회전과 같이 정점의 상태가 변환 되는 경우에는,

N = mul(Nor, m_mtRot); 과 같이 변환을 먼저 법선벡터에 적용해주고 해야 한다. 

 

구를 만들기위한 정점 데이터 설정

 

// 버텍스 생성
 INT iNSphereSegments = 128;
 m_iNvx = 2 * iNSphereSegments*(iNSphereSegments + 1);

 

 FLOAT fDeltaRingAngle = (D3DX_PI / iNSphereSegments);
 FLOAT fDeltaSegAngle = (2.0f * D3DX_PI / iNSphereSegments);

 

 m_pVtx = new CTest11::VtxN[m_iNvx];
 CTest11::VtxN* pV = m_pVtx;

 

 // Generate the group of rings for the sphere
 for (DWORD ring = 0; ring < iNSphereSegments; ring++)
 {
      FLOAT r0 = 50 * sinf((ring + 0) * fDeltaRingAngle);
      FLOAT r1 = 50 * sinf((ring + 1) * fDeltaRingAngle);
      FLOAT y0 = 50 * cosf((ring + 0) * fDeltaRingAngle);
      FLOAT y1 = 50 * cosf((ring + 1) * fDeltaRingAngle);

 

      // Generate the group of segments for the current ring
      for (DWORD seg = 0; seg < (iNSphereSegments + 1); seg++)
      {
           FLOAT x0 = r0 * sinf(seg * fDeltaSegAngle);
           FLOAT z0 = r0 * cosf(seg * fDeltaSegAngle);
           FLOAT x1 = r1 * sinf(seg * fDeltaSegAngle);
           FLOAT z1 = r1 * cosf(seg * fDeltaSegAngle);

 

           // Add two vertices to the strip which makes up the sphere
           // (using the transformed normal to generate texture coords)
           pV->p.x = x0;
           pV->p.y = y0;
           pV->p.z = z0;

           pV->n = pV->p;
           D3DXVec3Normalize(&pV->n, &pV->n);

           pV++;


           pV->p.x = x1;
           pV->p.y = y1;
           pV->p.z = z1;

           pV->n = pV->p;
           D3DXVec3Normalize(&pV->n, &pV->n);

           pV++;
      }

 }

정점 마다 법선 벡터 구하고 정규화 해서 &pV->n, 정점 법선 벡터에 값 넣어 주고 있다.

 

Render()

 

HRESULT hr = 0;

 

m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);

 

D3DXMATRIX mtViw;   // View Matrix

D3DXMATRIX mtPrj;   // Projection Matrix

 

D3DXMATRIX mtWld;   // World Matirx
D3DXMATRIX mtWVP;

 

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);

 

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_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(CTest11::VtxN));

 

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

 

랜더 함수에서 추가 된 부분중 굵게 표시된 부분만 보면 될 듯 하다. 빛의 색상과, 정규화를 통해 빛의 방향을 구하여 셰이더 안의 m_LgtDif, m_LgtDir에 각각 설정하고 있다.

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), };
 };


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

 

 D3DXMATRIX  m_mtWld;   // World Matrix

 

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

 

정점들의 포지션 p와, 색상값 d로 구성된 정점 구조체, m_iNvx는 구를 형성하는 정점의 갯수이다.

 

*shader.fx*

 

float4x4 m_mtWorld; // World Matrix
float4x4 m_mtView; // View Matrix
float4x4 m_mtProj; // Projection Matrix

 

float4 m_FogColor; // Fog 색상
float m_FogEnd; // Fog 끝 값
float m_FogBgn; // Fog 시작 값

 

// For Vertex Processing Output
struct SvsIn
{
  float3 Pos : POSITION ; // dcl_position0
  float4 Dif : COLOR0  ; // dcl_color0
};

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


SvsOut VtxPrc( SvsIn In)
{
  float4 vcOut;
  float FogFactor;

  SvsOut Out = (SvsOut)0;    // Initialized to 0

 

  // 정점의 변환: 월드, 뷰
  vcOut = float4(In.Pos, 1);
  vcOut = mul(vcOut, m_mtWorld);
  vcOut = mul(vcOut, m_mtView);

 

  // 정점의 뷰 변환 과정의 z/(Fog 끝 값 - Fog 시작 값)을 Fog Factor로 저장
  FogFactor = vcOut.z/(m_FogEnd - m_FogBgn);

 

  // 정점의 정규 변환
  vcOut = mul(vcOut, m_mtProj);

 

  // 출력 Diffuse를 정점 Diffuse와 포그 색상과 혼합
  float4 Fog = m_FogColor * FogFactor + In.Dif * (1.0 - FogFactor);

 

  // 혼합 값을 출력 색상으로 지정
  Out.Dif = Fog;
  Out.Pos = vcOut;


  return Out;
}

안개 효과를 나타내는데 있어 여러 방법이 있는듯 하다 그중에서 대표적으로는,

선형 포그(Linear Fog), 지수 포그(Exponential Fog)로 분류 된다.

선형 포그는 전체적으로 선형적으로 변화하고, exp 포그는 급격히 변화하다가 천천히, exp2는 천천히 변화하다가 급격히 변화 하는 것을 볼수 있다.

 

선형 포그와, 지수 포그 계산법엔 각각의 공식이 있고, 필요한 값들 또한 조금씩은 다른것 같다.

 

선형 포그는 포그가 적용되는 시작거리(start), 종료되는 종료거리(end)가 필요하고,

지수 포그는 포그의 밀도를 나타내는 (Density (0 ~ 1.0)) 필요하다.

 

기본적으로 포그는 물체가 멀리 있으면 포그의 색상에 가까워야 하고, 가까울수록 물체의 색상에 가까워야 된다는 개념 하에 FogFactor 라고 하는 거리에 정도에 따라 계산되는 값인 포그 계수를 이용하여 계산 하는듯 하다.

 

현재 셰이더 파일에서 사용하고 있는 방법은 선형 포그이고 빨간색으로 된 부분이 선형 포그 계산 공식 부분이다.

 

지수 포그(exp, exp2) 공식은 다음과 같다.

 

Fog Factor EXP = 1/exp(뷰 변환 후 정점의 z  * Fog Density)

Fog Factor EXP2 = 1/exp( pow(뷰 변환 후 정점의 z  * Fog Density, 2)

 

이러한 과정을 통해 fog값을 구하게 되면 출력 Diffuse에 이 값을 설정해주어 안개 효과가 나타나도록 한다는 것이다.

 

Render()

 

HRESULT hr = 0;
 
m_pdev->SetRenderState(D3DRS_LIGHTING, FALSE);


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

 

D3DXCOLOR FogColor(1.0F, 1.0F, 0.2F, 1); // Fog Color
FLOAT  FogEnd = 120.f; // Fog End
FLOAT  FogBgn = 0.f;  // Fog Begin

 

m_pdev->GetTransform(D3DTS_VIEW, &mtViw);
m_pdev->GetTransform(D3DTS_PROJECTION, &mtPrj);
 
// Render
m_pdev->SetVertexShader(m_pVs);
m_pdev->SetVertexDeclaration(m_pFVF);

 

hr = m_pTbl->SetMatrix(m_pdev, "m_mtWorld", &m_mtWld);
hr = m_pTbl->SetMatrix(m_pdev, "m_mtView", &mtViw);
hr = m_pTbl->SetMatrix(m_pdev, "m_mtProj", &mtPrj);
hr = m_pTbl->SetVector(m_pdev, "m_FogColor", (D3DXVECTOR4*)&FogColor);
hr = m_pTbl->SetFloat(m_pdev, "m_FogEnd", FogEnd);
hr = m_pTbl->SetFloat(m_pdev, "m_FogBgn", FogBgn);

 

m_pdev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, m_iNvx - 2, m_pVtx, sizeof(VtxD));

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

 

지금 이 코드에서는 정점의 diffuse 값에 안개 효과를 적용하고 있기 때문에 나중에 텍스처가 적용되면 안개가 재대로 표현되지 못한다. 그래서 안개 표현은 픽셀 셰이더에서 처리하는 것이 좋다고 한다.


728x90
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), };
 };

 

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

 

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

 

이번에는 텍스처가 추가 되면서, u,v좌표를 나타낼 float u,v와, FVF의 D3DFVF_TEX1, 그리고 텍스처 데이터가 저장될 LPDIRECT3DTEXTURE9 형의 m_pTbl이 추가 되었다.

 

*shader.fx*

 

float4x4 m_mtWVP;    // World * View * Projection Matrix


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


SvsOut VtxPrc( float3 Pos : POSITION, float4 Dif : COLOR0, float4 Tx0 : TEXCOORD0)
{
  SvsOut Out = (SvsOut)0;     // Initialized to 0

 

  Out.Pos = mul(float4(Pos, 1), m_mtWVP); // Transform
  Out.Dif = Dif;


  Out.Tx0 = Tx0;

  return Out;
}

 

텍스처를 나타내는 TEXCOORDO0이 추가 되었다. 그 외에는 이전 내용들과 같다.

 

m_pVtx[0] = VtxDUV1(-0.95F, 0.95F, 0, 0, 0, D3DXCOLOR(1, 0, 1, 1)); //색깔
m_pVtx[1] = VtxDUV1(0.95F, 0.95F, 0, 1, 0, D3DXCOLOR(1, 1, 0, 1));  //색깔
m_pVtx[2] = VtxDUV1(0.95F, -0.95F, 0, 1, 1, D3DXCOLOR(0, 1, 1, 1)); //색깔
m_pVtx[3] = VtxDUV1(-0.95F, -0.95F, 0, 0, 1, D3DXCOLOR(1, 1, 1, 1)); //색깔(하얀색)

 

D3DXCreateTextureFromFile(m_pdev, "Texture/earth.bmp", &m_pTx0);

 

D3DXCreateTextureFromFile 함수를 사용해서 텍스처 이미지를 읽어온다.

현재 작성대로의 정점들의 색깔로 지정하고 텍스처와 함께 랜더링 하면 왼쪽

정점들의 색깔을 모두 하얀색으로 하면 오른쪽과 같이 나온다.

 

Render()

 

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

 

D3DXMatrixIdentity(&mtWld);

 

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

 

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);

 

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

 

// Setup Constant Register
D3DXMATRIX mtWVP = mtWld * mtViw * mtPrj;
m_pTbl->SetMatrix(m_pdev, "m_mtWVP", &mtWVP);

 

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

 

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

 

텍스처를 사용하기때문에. SetSamplerState 함수를 통해 필터링 보간을 해준다. 여기선 종류를 보여주기 위해 3개를 다 작성한것 같다. 이후엔 똑같이 변환 과정과, SetTexture 함수를 통해 텍스처를 적용하고 랜더링 한다.

728x90
Posted by 정망스
,
728x90

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

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

 

 

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) {}
 };

 

 struct VtxD
 {
      D3DXVECTOR3 p;
      DWORD d;

      VtxD() : p(0, 0, 0), d(0xFFFFFFFF) {}
      VtxD(FLOAT X, FLOAT Y, FLOAT Z, DWORD D) : p(X, Y, Z), d(D) {}
      enum { FVF = (D3DFVF_XYZ | D3DFVF_DIFFUSE), };
 };

 

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

LPD3DXCONSTANTTABLE  m_pTbl;

D3DXMATRIX  m_mtWld;   // World Matrix

 

VtxIdx  m_pIdx[12];   // Index Buffer
VtxD  m_pVtx[24];   // Vertex Buffer

 

이번엔  m_pldx의 인덱스 버퍼와, 인덱스 구조체인 VtxIdx가 추가 되었다.

 

*shader.fx*

 

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


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


SvsOut VtxPrc( float3 Pos : POSITION, float4 Dif: COLOR0 )
{
     float4 P;

     SvsOut Out = (SvsOut)0;    // Initialized to 0

 

     P = float4(Pos, 1);     // Expand intto float4 and Setting w=1
     P = mul(P, m_mtWld);    // Transform World
     P = mul(P, m_mtViw);    // Transform View
     P = mul(P, m_mtPrj);    // Transform Projection

 

     Out.Pos = P;      // Copy to Output Register Position
     Out.Dif = Dif;      // Copy to Output Register Diffuse

 

     return Out;
}

 

입력받는 정점좌표와, 색상 데이터를 이용하여 출력 해주는 것은 여태까지와 똑같다 다만 추가 된것은 월드, 뷰, 투영 행렬을 mul 함수를 이용하여 각각 적용해주면서 변환 화는 과정을 보여주고 있다.

 

                             -----정점 데이터-----

// front
 m_pVtx[0] = VtxD(-1.f, -1.f, -1.f, D3DXCOLOR(1.0F, 0.0F, 0.0F, 1.0F));
 m_pVtx[1] = VtxD(-1.f, 1.f, -1.f, D3DXCOLOR(0.0F, 1.0F, 0.0F, 1.0F));
 m_pVtx[2] = VtxD(1.f, 1.f, -1.f, D3DXCOLOR(0.0F, 0.0F, 1.0F, 1.0F));
 m_pVtx[3] = VtxD(1.f, -1.f, -1.f, D3DXCOLOR(1.0F, 0.0F, 1.0F, 1.0F));

 

 // back
 m_pVtx[4] = VtxD(-1.f, -1.f, 1.f, D3DXCOLOR(1.0F, 1.0F, 0.0F, 1.0F));
 m_pVtx[5] = VtxD(1.f, -1.f, 1.f, D3DXCOLOR(0.0F, 1.0F, 1.0F, 1.0F));
 m_pVtx[6] = VtxD(1.f, 1.f, 1.f, D3DXCOLOR(1.0F, 0.0F, 0.0F, 1.0F));
 m_pVtx[7] = VtxD(-1.f, 1.f, 1.f, D3DXCOLOR(1.0F, 0.0F, 1.0F, 1.0F));

 

 // top
 m_pVtx[8] = VtxD(-1.f, 1.f, -1.f, D3DXCOLOR(0.0F, 0.0F, 1.0F, 1.0F));
 m_pVtx[9] = VtxD(-1.f, 1.f, 1.f, D3DXCOLOR(0.0F, 1.0F, 0.0F, 1.0F));
 m_pVtx[10] = VtxD(1.f, 1.f, 1.f, D3DXCOLOR(1.0F, 0.0F, 1.0F, 1.0F));
 m_pVtx[11] = VtxD(1.f, 1.f, -1.f, D3DXCOLOR(0.0F, 1.0F, 1.0F, 1.0F));

 

 // bottom
 m_pVtx[12] = VtxD(-1.f, -1.f, -1.f, D3DXCOLOR(1.0F, 1.0F, 0.0F, 1.0F));
 m_pVtx[13] = VtxD(1.f, -1.f, -1.f, D3DXCOLOR(0.0F, 1.0F, 0.0F, 1.0F));
 m_pVtx[14] = VtxD(1.f, -1.f, 1.f, D3DXCOLOR(0.0F, 0.0F, 1.0F, 1.0F));
 m_pVtx[15] = VtxD(-1.f, -1.f, 1.f, D3DXCOLOR(1.0F, 0.0F, 0.0F, 1.0F));

 

 // left
 m_pVtx[16] = VtxD(-1.f, -1.f, 1.f, D3DXCOLOR(1.0F, 1.0F, 0.0F, 1.0F));
 m_pVtx[17] = VtxD(-1.f, 1.f, 1.f, D3DXCOLOR(1.0F, 0.0F, 1.0F, 1.0F));
 m_pVtx[18] = VtxD(-1.f, 1.f, -1.f, D3DXCOLOR(0.0F, 1.0F, 1.0F, 1.0F));
 m_pVtx[19] = VtxD(-1.f, -1.f, -1.f, D3DXCOLOR(1.0F, 0.0F, 1.0F, 1.0F));

 

 // right
 m_pVtx[20] = VtxD(1.f, -1.f, -1.f, D3DXCOLOR(1.0F, 1.0F, 0.0F, 1.0F));
 m_pVtx[21] = VtxD(1.f, 1.f, -1.f, D3DXCOLOR(0.0F, 1.0F, 0.0F, 1.0F));
 m_pVtx[22] = VtxD(1.f, 1.f, 1.f, D3DXCOLOR(1.0F, 0.0F, 1.0F, 1.0F));
 m_pVtx[23] = VtxD(1.f, -1.f, 1.f, D3DXCOLOR(0.0F, 0.0F, 1.0F, 1.0F));

 

                            -----인덱스 데이터-----

 

// front
 m_pIdx[0] = VtxIdx(0, 1, 2);
 m_pIdx[1] = VtxIdx(0, 2, 3);

 

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

 

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

 

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

 

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

 

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

 

정점 데이터, 인덱스 데이터 설정, 사각형은 앞,뒤,위,아래,왼쪽,오른쪽 총 6면이고,

면당 삼각형 2개(정점 4개)이므로 정점 데이터는 6 x 4 = 24개, 인덱스 데이터는 6 x 2 =12개 이다.

 

update()

 

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

 

        // 회전하는 월드 행렬 구성
FLOAT  fAngle = D3DXToRadian(GetTickCount() * 0.1f);
D3DXMatrixRotationY(&mtRotY, fAngle*1.f);
D3DXMatrixRotationZ(&mtRotZ, fAngle*1.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()

 

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

 

D3DXMatrixIdentity(&mtWld);

 

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


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

 

// 상수 연결: 상수 테이블 사용
m_pTbl->SetMatrix(m_pdev, "m_mtWld", &m_mtWld);
m_pTbl->SetMatrix(m_pdev, "m_mtViw", &mtViw);
m_pTbl->SetMatrix(m_pdev, "m_mtPrj", &mtPrj);

 

m_pdev->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 24, 12, m_pIdx, D3DFMT_INDEX16, m_pVtx, sizeof(VtxD));

 

m_pdev->SetVertexShader(NULL);

 

 

셰이더 파일에 있는 m_mtWld(월드 행렬), m_mtViw(뷰 행렬), m_mtPrj(투영 행렬)에 각각 상수 테이블을 이용하여 설정해주고.

 

DrawIndexedPrimitiveUP 함수를 이용하여 인덱스와, 정점 데이터를 통한 사각형을 그려준다.

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) : p(X, Y, Z), d(D) {}

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

 

LPDIRECT3DVERTEXSHADER9  m_pVs; 
LPDIRECT3DVERTEXDECLARATION9  m_pFVF; 

LPD3DXCONSTANTTABLE  m_pTbl;

VtxD  m_pVtx[4];

 

정점은 포지션과, 색상(Diffuse)를 갖고 잇고, 사각형을 만들꺼니까 정점 4개가 필요하다.

 

*shader.fx*

 

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


float4x4 m_mtWld;     // World * View * Projection Matrix
float4x4 m_mtViwPrj;     // View * Projection Matrix

 

SvsOut VtxPrc( float3 Pos: POSITION, float4 Dif: COLOR0 )
{
     float4 P;
     SvsOut Out = (SvsOut)0;    // Initialized to 0

 

     P  = float4(Pos,1);   // Expand into float4 and setting w=1
     P  = mul(P, m_mtWld);   // Transform World
     P  = mul(P, m_mtViwPrj);  // Transform View * Projection

 

     Out.Pos = P;      // Copy Output Position
     Out.Dif = Dif;      // Copy Output Diffuse

 

     return Out;
}

 

SvsOut 정점 구조체를 이용하여 출력 시켜주고 있다. 이전까지와의 다른 점이라면 정점의 위치가 될 float4형 p 변수에 월드행렬(m_mtWld), 뷰*투영행렬(m_mtViwPrj)을 mul함수를 사용하여 곱해줌으로써 정점을 변환하고 있다.

 

입력으로 받는 정점의 포지션은 float3 형 이지만 파이프라인은 float4형을 사용하기 때문에 float4형으로 만들어주고 마지막 인수인 w에 1을 입력해 준다.

 

m_pVtx[0] = VtxD(-50, 0, 0, D3DXCOLOR(1, 0, 0, 1));
m_pVtx[1] = VtxD(50, 0, 0, D3DXCOLOR(0, 1, 0, 1));
m_pVtx[2] = VtxD(50, 80, 0, D3DXCOLOR(0, 0, 1, 1));

m_pVtx[3] = VtxD(-50, 80, 0, D3DXCOLOR(1, 0, 1, 1));

 

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

 

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

 

float fAngle = D3DXToRadian(GetTickCount()*0.1f);
D3DXMatrixRotationY(&mtWld, fAngle);
mtWld._43 -= 1.f;

 

m_pdev->GetTransform(D3DTS_VIEW, &mtViw);    // Device에서 뷰 행렬을 가져온다.
m_pdev->GetTransform(D3DTS_PROJECTION, &mtPrj);   // Device에서 투영 행렬을 가져온다.

 

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

 

// 전역 변수 값 설정: 상수 테이블 사용
m_pTbl->SetMatrix(m_pdev, "m_mtWld", &mtWld);    // World Matrix
m_pTbl->SetMatrix(m_pdev, "m_mtViwPrj", &(mtViw * mtPrj)); // View * Projection Matrix

 

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

 

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

 

D3DRS_CULLMODE 모드를 NONE으로 해주면 컬링을 하지 않아 앞면 뒷면 다 보이게 된다. 우린 사각형을 Y축을 기준으로 계속해서 돌릴꺼니까 양면이 보여야 되니까.

 

GetTransform() 를 이용해서 각각의 행렬을 가져오고, SetMatrix()을 이용하여 셰이더 파일의 m_mtWld와, m_mtViwprj에 접근하여 값을 설정해준다.

 

D3DXToRadian(GetTickCount()*0.1f)을 이용해서 움직일 각도를 계산하고 D3DXMatrixRotationY() 을 이용해서 월드행렬에 적용해줌으로써 계속해서 Y각도가 바뀌는 사각형이 랜더링 되는 것이다.

 

mtWld._43 -= 1.f; 이 부분은 딱히 쓰이는 부분은 없는거 같은데. 월드 행렬의 _43이라고 하면 z축을 나타내는것으로 z축에 -1만큼 움직여라 라고 보면 된다.

 

마지막으로 월드 행렬(m_mtWld)와, 뷰*투영 행렬(m_mtViwPrj)를 따로 사용할 필요없이 셋다 곱해서 하나의 행렬로 사용해도 된다.

 

여기서는 월드행렬에 계속해서 로테이션Y를 해주기 위해서 따로 사용한거 같다. 셰이더 파일에도 보면 그렇기 때문에 float4x4형을 2개 만들어 각각 월드, 뷰*투영 행렬로 사용하고 있는듯 하다.

 

뭐 결론은.. 특별히 처리할 내용이 없는 부분이라면 미리 행렬들을 곱해서 사용하면 된다는것.

728x90
Posted by 정망스
,


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