1. 3D Direct Application
1.1 Normal Mapping
1.1.1 Normal Mapping System
1.1.1.1 Normal Mapping
- 보통의 Texture Mapping에서 법선 벡터들이 여전히 덜 조밀한 정점 수준에 정의되어 삼각형을 따라 보간
- 표면 법선들을 좀 더 높은 해상도에서 지정
- 조명의 세부도가 높아지지만 메시 기하구조 자체의 세부도까지는 높아지지 않음
- 테셀레이션과 결합된 Normal Mapping을 사용하면 메시의 세부도를 높일 수 있음
- 벽돌 Texture를 사용할 때 올록볼록한 요철 형태에 비해 너무 매끄러워 부자연스럽게 보이는 경우 발생
- 메시 기하구조가 매끄럽기 때문에 이러한 현상 발생, 조명 계산은 메시 기하구조에 근거하여 수행하므로 일치X
- 광원이 동적으로 움직이는 상황에 Texture Map에 있는 세부사항들이 조명에 제대로 반영되게 하는 기법 사용
1.1.1.2 Normal Map
- Normal Map의 경우 Texture지만 픽셀마다 RGB 색상 자료를 담는 것이 아닌 법선 정보를 담음
- 번선 맵의 각 픽셀은 X, Y ,Z 성분을 담으며, 하나의 법선 벡터를 정의
- Normal Map을 각 성분 당 8비트로 이루어진 24비트 이미지 형식에 저장, 각 성분마다 0 ~ 255까지 값을 담을 수 있음
- 단위 벡터를 24비트 형식으로 변환, 단위 벡터는 [-1, 1]의 범위를 가지고 있음
- 이를 [0, 1] 구간으로 이동 및 255의 값을 곱하면 24비트 형식으로 압축할 수 있음
- Normal Map을 사용하기 위해 [0, 255] 구간의 압축된 Texture 좌표 성분에서 [-1, 1] 구간의 원래 벡터 성분 값 복원
- 위의 방법으로 부터 구해진 함수를 역함수를 통해 구하게 되면 복원할 수 있음
float3 normaIT = gNormalMap.Sample(gTriLinearSam, pin.Tex);
- 위의 코드로 0부터 1까지 만족하는 정규화된 성분들로 이루어진 색상 벡터가 설정
- 복원 과정의 일부가 이미 자동으로 일어남, 즉 [0, 255] 구간의 정수를 255로 나눠 [0, 1] 구간을 만드는 작업이 끝남
- 이후 [-1, 1]로 값을 변경
normalT = 2.0f * normalT - l.Of;
1.1.1.3 Tangent Space
- 3차원 Texture가 입혀진 삼각형이 Texture Mapping을 할 때 왜곡이 일어나지 않는 경우
- Texture 공간은 삼각형 평면에 놓여 삼각형과 접함
- 삼각형 면 법선 N을 도입하여 삼각형 평면과 접하며 기저벡터 T, B, N으로 이루어진 3차원 좌표계가 형성
- 좌표계로 정의되는 공간을 삼각형의 Texture Space & Tangent Space, 접공간은 삼각형마다 다름
- 빛은 세계 공간을 기준으로 하므로 조명 공식을 계산하려면 법선 벡터와 빛이 같은 공간에 있어야 함
- 접공간 좌표계를 삼각형 정점들이 기준으로 하는 물체 공간 좌표계와 연관
- Texture 좌표들을 물체 공간으로 이동하면 세계 행렬을 이용하여 물체 공간 좌표를 세계 공간 좌표로 변환
1.1.1.4 Vertex Tangent Space
- Texture 공간을 법선 매핑에 그대로 사용하면 조명 결과가 삼각형 별로 나누어진 것 같은 모습이 나타남
- 접공간이 삼각형의 면 전체가 일정하기 때문, 접벡터들을 정점별로 지정
- 정점 법선으로 매끄러운 표면을 흉내 낼때 방식으로 접벡터들의 평균을 계산해서 적용
- 일반적으로 펴균으로 구한 TBN 기저들은 다시 정규 직교화를 통해 서로 직교인 단위벡터들로 만들 필요가 있음
- 흔히 그람 슈미트 절차를 이용하여 재정규화 작업을 수행
struct NormalMap { XMFLOAT3 Pos; XMFLOAT3 Normal; XMFLOAT2 Tex; XMFLOAT3 TangentU; }
- 위를 통해 메시의 각 정점마다 정규 직교 TBN 기저가 생성 & 물체 공간 좌표계에 상대적인 TBN 기저 좌표를 알고 있음
- 접공간의 좌표를 물체 공간으로 변환해 주는 행렬의 성분들도 결정, 행렬은 직교행렬이므로 전치행렬이 역행렬임
- 조명 계산 시 법선 벡터를 접공간에서 세계 공간으로 변환
- 법선을 접공간에서 물체 공간으로 변환 후 세계 형렬을 이용하여 물체 공간에서 세계 공간으로 변환
- 즉 접공간에서 세계공간으로 바로가고 싶으면 접공간 기저벡터들을 직접 세계공간 좌표로 서술
- 그런 좌표들은 TBN 기저를 물체공간 좌표에서 세계 공간 좌표로 변환해서 얻을 수 있음
1.1.2 Tangent Space Shader
- Normal Map을 이용하여 프로그램 초기화 시점에서 이미지 파일로 부터 2차원 Texture를 생성
- 각 삼각형마다 접벡터 T를 계산
- 메시의 각 정점마다 메시에서 정점을 공유하는 모든 삼각형의 접벡터의 평균을 내서 정점별 접벡터를 구함
- 정점 셰이더에서 정점 법선 벡터와 접벡터를 세계 공간으로 변환하고, 그 결과를 픽셀 셰이더로 출력
- 주어진 픽셀 위치에서의 TBN 기저를 삼각형 표면을 따라 보간된 접벡터와 법선 벡터를 이용해서 구축
- 법선 맵에서 추출한 법선 벡터를 기저를 이용해서 접공간에서 세계 공간으로 변환
- 세계 공간 법선 벡터를 조명 계산에 사용
1.1.2.1 Normal Sample To World Space
float3 NormalSampleToWorldSpace(float3 normalMapSample, float3 unitNormalW, float3 tangentW);
- Normal Map이 [0, 255]의 구간에서 Texture를 샘플링을 통해 각 성분이 [0, 1]로 변환
- 이후 단위 벡터 [-1, 1]의 구간으로 변환하기 위해 밑의 코드 적용
float3 normalT = 2.0f * normalMapSample - 1.0f;
- 정규 직교 기저를 생성하여 접공간에서 세계 공간으로 변환
- 보간을 거치고 난 접벡터와 법선 벡터는 더 이상 정규직교가 아닐 수 있음
- T의 N방향 부분을 T에서 빼서 N에 직교하는 벡터를 얻음
float3 N = unitNormalW; float3 T = normalize(tangentW - dot(tangentW, N) * N); float3 B = cross(N, T);
float3x3 TBN = float3x3(T, B, N); float3 bumpedNormalW = mul(normalT, TBN);
return bumpedNormalW;
- 위에서 만든 함수를 통해 픽셀 셰이더에서 적용하여 접공간에서 세계 공간으로 변환된 Normal Map 사용
- 이후 조명, 입방체 맵핑에 적용
float3 normalMapSample = gNormalMap.Sample(samLinear, pin.Tex).rgb;
float3 bumpedNormalW = NormalSampleToWorldSpace(normalMapSample, pin.NormalW, pin.TangentW);
'C++ Algorithm & Study > Game Math & DirectX 11' 카테고리의 다른 글
[Direct11] 39. 3D Direct Application - Terrian Rendering #1 (0) | 2023.06.30 |
---|---|
[Direct11] 38. 3D Direct Application - Displacement Mapping (0) | 2023.06.30 |
[Direct11] 36. 3D Direct Application - Dynamic Cube Mapping System (0) | 2023.06.27 |
[Direct11] 35. 3D Direct Application - Cube Mapping System (0) | 2023.06.27 |
[Direct11] 34. 3D Direct Application - Picking System (0) | 2023.06.27 |