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


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