Normal Mapping
Normal Map을 이용한 접선 공간에서의 수직 축인 Normal을 추출하여 Light 연산을 하는 방식이다.
기존 World 기준 Normal값을 이용하여 Tangent를 추출해야하는데, 삼각형을 이루는 점 3개를 통해 Tangent를 유도한다.
Binormal의 경우 Normal값과 Tangent값만 있다면 외적을 통해 구할 수 있으므로 공간 절약을 위해 Shader 측에서 하기로 한다.
위 이미지에서 오브젝트 또는 World Space Normal Mapping(왼쪽), Tangent Space Normal Mapping(오른쪽)을 통해
왼쪽의 World 기준 축을 잡게 되면 좀더 세밀한 Light연산이 불가능하다. 오른쪽 이미지처럼 정점 기준 표면의 축을 기준으로 Normal 값을 적용시키게 된다면 좀 더 정밀한 Light 연산을 통해 깊이 있는 이미지를 출력할 수 있게 될 것이다.
// Tanget 값 설정..
for (unsigned int i = 0; i < pMesh->m_MeshFace.size(); i++)
{
int index0 = pMesh->m_MeshFace[i]->m_VertexIndex[0];
int index1 = pMesh->m_MeshFace[i]->m_VertexIndex[1];
int index2 = pMesh->m_MeshFace[i]->m_VertexIndex[2];
Vertex* vertex0 = pMesh->m_VertexList[index0];
Vertex* vertex1 = pMesh->m_VertexList[index1];
Vertex* vertex2 = pMesh->m_VertexList[index2];
DirectX::SimpleMath::Vector3 ep1 = vertex1->m_Pos - vertex0->m_Pos;
DirectX::SimpleMath::Vector3 ep2 = vertex2->m_Pos - vertex0->m_Pos;
DirectX::SimpleMath::Vector2 uv1 = { vertex1->m_UV.x - vertex0->m_UV.x,
vertex1->m_UV.y - vertex0->m_UV.y };
DirectX::SimpleMath::Vector2 uv2 = { vertex2->m_UV.x - vertex0->m_UV.x,
vertex2->m_UV.y - vertex0->m_UV.y };
float den = 1.0f / (uv1.x * uv2.y - uv2.x * uv1.y);
// 현재 픽셀 쉐이더에서 연산을 통해 T, B, N을 얻는데
// 픽셀 쉐이더 내의 연산은 버텍스 쉐이더의 연산에 비해 호출 횟수가 차원이 다르게 크므로 부하가 올 수 있다..
// 법선맵의 픽셀의 색은 픽셀 쉐이더 안이 아니면 얻을수 없기 때문에 픽셀 쉐이더에서 연산을 한다고 한다..
/// 현재 연산과정을 버텍스 쉐이더로 옮겨둠
DirectX::SimpleMath::Vector3 tangent = (ep1 * uv2.y - ep2 * uv1.y) * den;
tangent.Normalize();
// 유사 정점은 값을 누적하여 쉐이더에서 평균값을 사용하도록 하자..
vertex0->m_Tanget += tangent;
vertex1->m_Tanget += tangent;
vertex2->m_Tanget += tangent;
}
Face Vertex 3개를 이용하여 Tangent Normal 구하는 방식.
VertexOut Mesh_VS(MeshVertexIn vin)
{
...
Tangent = mul((float3x3) gMeshWorld, vin.TangentL);
N = vout.NormalW;
T = normalize(Tangent - dot(Tangent, N) * N);
B = cross(N, T);
vout.TBNW = float3x3(T, B, N);
};
Vertex Shader에서 Normal, Tangent를 이용하여 Binormal 구한 후 TBN 행렬 저장.
PixelOut Deferred_PS(VertexIn pin)
{
...
normalW = mul(2.0f * gNormalMap.Sample(gSamWrapLinear, pin.Tex).rgb - 1.0f, pin.TBNW);
...
};
Normal Texture는 [0 ~ 1] 사이의 값이 들어있지만 우리가 필요한 Vector 값은 [-1 ~ 1] 이므로 rgb 값을 변환 시켜준다.
Vertex Shader에서 구해둔 TBN과 연산을 하여 Normal값 추출.
화면상에 Normal값을 출력한 화면.
Normal Map 적용 비교 출력 화면.
'DirectX 11' 카테고리의 다른 글
[DirectX 11] Animation (0) | 2021.12.18 |
---|---|
[DirectX 11] Skinning Mesh (0) | 2021.12.18 |
[DirectX 11] Gamma Correction (0) | 2021.12.18 |
[DirectX 11] Deferred Rendering GBuffer (0) | 2021.12.14 |
[DirectX 11] Shadow Map (0) | 2021.12.14 |