※ 제 개인 공부이므로 풀 소스 코드는 작성하지 않습니다. ※
※ 생략 되어 있는 부분이 많습니다. ※
{
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
포지션과, 법선 벡터 데이터로 이루어진 정점 구조체 이다.
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 이다.
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 값을 설정해준다.
셰이더에서 정점에서 카메라를 바라보는 시선 벡터를 구할때의 정점이 월드 공간의 좌표이기때문에 일치 시켜주기 위해서이다.
'Shader' 카테고리의 다른 글
13. 픽셀 처리 사용자 함수 (0) | 2017.02.09 |
---|---|
12. 알록달록 사각형(간단한 픽셀 처리) (0) | 2017.02.09 |
10. 분산 조명 효과를 내보자. (0) | 2017.02.07 |
9. 안개 효과를 내보자. (0) | 2017.02.06 |
8. 텍스처를 입혀보자. (지구) (0) | 2017.02.06 |