1. 3D Direct Application
1.1 Displacement Mapping System
1.1.1 Displacement Mapping
1.1.1.1 Displacement Mapping
- 테셀레이션과 함께 사용하여 렌더링 품질을 더욱 높일 수 있는 변워 매핑 사용
- 법선 매핑이 단지 조명의 세부도만 개선할 뿐 실제 기하구조의 세부도는 개선X
- 표면의 굴곡과 균열을 묘사하는 높이 맵이라고 부르는 또 다른 맵을 이용하여 기하구조를 변형
- 법선 맵이 각 픽셀마다 세 색상 성분에 하나의 법선 벡터를 저장
- 높이 맵은 각 픽셀마다 하나의 색상 성분에 높이 값을 저장
- 테셀레이션으로 메시를 더 잘게 쪼개고 영역 셰이더에서 정점을 법선 벡터 방향으로 이동시킬 때의 이동량으로 쓰임
- 테셀레이션으로 기하구조에 삼각형을 추가하는 것 자체로 메시에 세부사항이 추가되지는 않음
- 한 삼각형을 여러 번 세분한다해도 원래 삼각형 평면에 더 많은 삼각형이 생기는 것
- 요철이나 균열 같은 세부사항을 추가하려면 테셀레이션된 정점들의 위치를 적절하게 변경
- 높이맵은 테셀레이션된 정점의 변위에 사용할 수 있는 입력 원본의 하나, 벡터 위치를 변위 시킬 때 공식 사용
- 정점을 표면의 바깥쪽을 향한 표면 법선 벡터가 가리키는 방향으로 일정 거리만큼 이동
1.1.1.2 Shader Code
- 변위 매핑을 렌더링 코드와 통합하려면 렌더링 코드가 테셀레이션을 지원
- 메시 기하구조의 해상도를 변위 매핑의 해상도에 걸맞은 수준으로 높일 수 있기 때문
- 기본 도형 위상구조를 밑의 코드로 설정
- 메시의 한 삼각형의 정점 세 개가 한 삼각형 패치의 제어점 세 개로 해석, 메시의 각 삼각형을 세분할 수 있게 됨
D3D11_PRIMITIVE_T0P0L0GY_3_C0NTR0L_P0INT_PATCHLIST
- 테셀레이션을 사용할 때 각 삼각형을 얼마나 세분할 것인지 결정
- 삼각형이 시점에 가까울수록 테셀레이션을 더 많이 수행하는 방식
- 정점 셰이더에서는 정점별로 거리에 따른 테셀레이션 계수를 계산해서 덮개 셰이더로 넘김
- 상수 버퍼에 거리 계산에 관여하는 최종적인 테셀레이션 계수들에 영향을 주는 변수 추가
- 구체적인 값은 렌더링할 장면에 따라 달라짐
cbuffer cbPerFrame /* 필요한 것만 작성 */
{ float gMaxTessDistance; float gMinTessDistance; float gMinTessFactor; float gMaxTessFactor; };
1.1.1.3 Vertex Shader
- 정점 셰이더에서 d의 거리에 따라 정규화된 테셀레이션 계수를 이용하여 결정
float d = distance(vout.PosW, gEyePosW);
float tess = saturate((gMinTessDistance - d) / (gMinTessDistance - gMaxTessDistance));
vout.TessFactor = gMinTessFactor + tess * (gMaxTessFactor - gMinTessFactor);
1.1.1.4 Hull Shader
- 상수 덮개 셰이더는 패치별로 평가, 메시의 소위 테셀레이션 계수들을 출력
- 테셀레이션 계수는 테셀레이터 단계가 패치를 얼마나, 어떻게 세분할 것인지 결정
- 테셀레이션 계수를 계산하는 작업은 정점 셰이더에서 결정
- 정점별 테셀레이션 계수들의 평균으로 변 테셀레이션 계수들을 계산
struct PatchTess { float EdgeTess[3] : SV_TessFactor; float InsideTess : SV_InsideTessFactor; };
- 정점 테셀레이션 계수들을 변을 따라 평균, 테셀레이션 계수들을 변의 속성에 근거해서 계산하는 것이 중요
- 여러 삼각형이 공유하는 변의 테셀레이션 계수가 그러한 모든 삼각형에서 동일, 그렇지 않으면 메시의 틈이 생김
pt.EdgeTess[0] = 0.5f * (patch[1].TessFactor + patch[2].TessFactor);
pt.EdgeTess[1] = 0.5f * (patch[2].TessFactor + patch[0].TessFactor);
pt.EdgeTess[2] = 0.5f * (patch[0].TessFactor + patch[1].TessFactor);
pt.InsideTess = pt.EdgeTess[0];
- 제어점 덮개 셰이더는 일단의 제어점들을 받아 일단의 제어점들을 출력
- 출력할 제어점마다 한 번씩 호출, 이번에 사용할 제어점 덮개 셰이더는 그대로 통과함
hout.PosW = p[i].PosW; hout.NormalW = p[i].NormalW; hout.TangentW = p[i].TangentW; hout.Tex = p[i].Tex;
1.1.1.5 Domain Shader
[domain("tri")]
DomainOut DS(PatchTess patchTess, float3 bary : SV_DomainLocation, const OutputPatch<HullOut, 3> tri)
- 테셀레이션 단계가 생성한 각 정점마다 실행, 테셀레이션된 패체에 대한 정점 셰이더
- 실질적인 변위 매핑이 일어나는 곳이 영역 셰이더
- 즉 높이맵에서 높이 값을 추출하여 정점 위치를 공식에 따라 법선 방향으로 이동시키는 작업
- 패치 특성들을 생성된 정점들에 대해 보간
- 보간 때문에 법선이 더 이상 단위 벡터가 아닐 수 있으므로 다시 정규화 진행
DomainOut dout;
dout.PosW = bary.x * tri[0].PosW + bary.y * tri[1].PosW + bary.z * tri[2].PosW;
dout.NormalW = bary.x * tri[0].NormalW + bary.y * tri[1].NormalW + bary.z * tri[2].NormalW;
dout.TangentW = bary.x * tri[0].TangentW + bary.y * tri[1].TangentW + bary.z * tri[2].TangentW;
dout.Tex = bary.x * tri[0].Tex + bary.y * tri[1].Tex + bary.z * tri[2].Tex;
dout.NormalW = normalize(dout.NormalW);
- 시점과의 거리에 근거해서 밉맵 수준을 선택
- 매 Mip Interval 단위마다 다음 번 밉맵 수준을 선택하고 [0, 6] 구간으로 한정
const float MipInterval = 20.0f;
float mipLevel = clamp((distance(dout.PosW, gEyePosW) - MipInterval) / MipInterval, 0.0f, 6.0f);
- 높이맵의 표본을 추출하여 정점 위치를 법선 방향으로 이동하고 동차 절단 공간으로 투영
float h = gNormalMap.SampleLevel(samLinear, dout.Tex, mipLevel).a;
dout.PosW += (gHeightScale * (h - 1.0)) * dout.NormalW;
dout.PosH = mul(float4(dout.PosW, 1.0f), gViewProj);
'C++ Algorithm & Study > Game Math & DirectX 11' 카테고리의 다른 글
[Direct11] 40. 3D Direct Application - Terrian Rendering #2 (0) | 2023.06.30 |
---|---|
[Direct11] 39. 3D Direct Application - Terrian Rendering #1 (0) | 2023.06.30 |
[Direct11] 37. 3D Direct Application - Normal 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 |