Normal mapping (bump mapping)
rasterizer 단계에서 정점과 정점 사이를 보간할 때 텍스쳐가 밋밋하게 보이는 단점이 있음
이를 방지하려면 정점 개수를 늘리면 되지만, 그렇게 되면 성능이 크게 떨어질 수 있음
color 텍스쳐의 uv 좌표에 해당하는 normal 벡터들을 다른 텍스쳐로 저장
raterizer 때 해당 color와 대응하는 normal 벡터를 이용하여 빛을 계산하여 음영을 나타냄
노말맵 텍스쳐가 대부분 파란색인 이유
=> 노말맵은 물체의 접하는 면을 기준으로 하는 좌표계(tangent space) 사용
=> x,y,z = T, B, N
=> 접하는 면을 만드는 T와 B 벡터는 특정 공식을 이용하여 도출
=> T와 B에 직각인 N을 기저로 함
=> 벡터 값들을 rgb로 나타낼 때 b값이 크기 때문
TS -> VS
RGB 0 ~ 255 데이터들을 방향 벡터로 만들기 위해 -1.0 ~ 1.0으로 변환
TBN을 기저로하는 좌표계를 XYZ로 하는 좌표계로 회전 변환 행렬 사용하여 좌표 추출
쉐이더 파일에서는 널 체크 불가능
=>
사용 여부를 데이터로 넘겨줌
cbuffer MATERIAL_PARAMS : register(b2)
{
...
int g_text_on_0;
int g_text_on_1;
int g_text_on_2;
int g_text_on_3;
int g_text_on_4;
};
material 파라미터에 texture 사용 여부 데이터 추가
struct VS_IN
{
float3 pos : POSITION;
float2 uv : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
};
struct VS_OUT
{
float4 pos : SV_Position;
float2 uv : TEXCOORD;
float3 viewPos : POSITION;
float3 viewNormal : NORMAL;
float3 viewTangent : TANGENT;
float3 viewBinormal : BINORMAL;
};
vertex shader 입력 데이터에 tangent 추가
출력 데이터에 tangent와 binormal 벡터 추가
VS_OUT VS_Main(VS_IN input)
{
...
output.viewNormal = normalize(mul(float4(input.normal, 0.f), g_matWV).xyz);
output.viewTangent = normalize(mul(float4(input.tangent, 0.f), g_matWV).xyz);
output.viewBinormal = normalize(cross(output.viewTangent, output.viewNormal));
return output;
}
vertex shader에서 tangent와 binormal 벡터를 구하도록 구현
binormal을 구할 때 벡터 순서에 따라 방향이 바뀜을 주의
float4 PS_Main(VS_OUT input) : SV_Target
{
float4 color = float4(1.f, 1.f, 1.f, 1.f);
if (g_tex_on_0)
{
color = g_tex_0.Sample(g_sam_0, input.uv);
}
float3 viewNormal = input.viewNormal;
if (g_tex_on_1)
{
float3 tangentSpaceNormal = g_tex_1.Sample(g_sam_0, input.uv).xyz;
tangentSpaceNormal = (tangentSpaceNormal - 0.5f) * 2.f;
float3x3 matTBN = { input.viewTangent, input.viewBinormal, input.viewNormal };
viewNormal = normalize(mul(tangentSpaceNormal, matTBN));
}
...
}
pixel shader에서 텍스쳐 사용 유무 데이터를 통하여 텍스쳐를 덮어쓰도록 구현
샘플러를 통하여 샘플링 시 데이터 값이 0.0 ~ 1.0 사이 값으로 나옴
해당 값을 방향 벡터로 사용하기 위하여
-1 ~ 1 사이로 나오도록 조정하여 tangentSpaceNormal 대입
해당 방향 벡터를 변환 행렬로 곱하여 view space로 좌표계 변환