
Tessellation은 렌더링 파이프라인에서 아직 다뤄보지 않은 Hull Shader, Tesselator, Domain Shader의 과정을 의미한다.
카메라의 거리에 따라 LOD(Level Of Detail)를 통해 Mesh의 폴리곤 수를 늘렸다가 줄이는 것이다. 가장 많이 사용되는 예는 Terrain인데, 멀리 있는 지형도 가까이 있는 나무와 같이 표현한다면 많은 부하가 생길 것이기 때문에 카메라가 멀어지면 간략하게 표현하도록 동적 LOD를 이용한다. Hull Shader과 Domain Shader은 우리가 조작하지만 Tessleator Stage는 조작한 것에 따라 자동으로 생성되는 것이다.
// Control Point HS
[domain("tri")] // 패치의 종류 (tri, quad, isoline)
[partitioning("integer")] // subdivision mode (integer 소수점 무시, fractional_even, fractional_odd)
[outputtopology("triangle_cw")] // (triangle_cw, triangle_ccw, line)
[outputcontrolpoints(3)] // 하나의 입력 패치에 대해, HS가 출력할 제어점 개수
[patchconstantfunc("ConstantHS")] // ConstantHS 함수 이름
HS_OUT HS_Main(InputPatch<VS_OUT, 3> input, int vertexIdx : SV_OutputControlPointID, int patchID : SV_PrimitiveID)
{
HS_OUT output = (HS_OUT)0.f;
output.pos = input[vertexIdx].pos;
output.uv = input[vertexIdx].uv;
return output;
}
Hull Shader은 Vertex Shader에서 넘겨준 값을 InputPatch로 받는다. 정점들을 control point, 그것들의 집합을 patch라고 하는데 ControlPoint 개수만큼 HS_Main을 실행한다. 위 코드에서는 입력값의 pos, uv를 그대로 넘기고 있다.
struct PatchTess
{
float edgeTess[3] : SV_TessFactor;
float insideTess : SV_InsideTessFactor;
};
struct HS_OUT
{
float3 pos : POSITION;
float2 uv : TEXCOORD;
};
// Constant HS
PatchTess ConstantHS(InputPatch<VS_OUT, 3> input, int patchID : SV_PrimitiveID)
{
PatchTess output = (PatchTess)0.f;
output.edgeTess[0] = 1;
output.edgeTess[1] = 2;
output.edgeTess[2] = 3;
output.insideTess = 1;
return output;
}

그리고 ConstantHS에서는 Patch 단위로 계산한다. edgeTess는 삼각형의 각 변을 의미하고 2는 변을 기준으로 삼각형 2개로 쪼개기, 3은 변을 기준으로 3개로 쪼개는 것을 뜻한다. 가까이 있을 수록 많이 쪼개고 멀리 있을 수록 적개 쪼갠다.
아예 안그리고 싶으면 0으로 세팅하면 안 그린다. 쪼개면 그 수만큼 정점이 추가되므로 이제 Domain Shader을 실행한다.
struct DS_OUT
{
float4 pos : SV_Position;
float2 uv : TEXCOORD;
};
[domain("tri")]
DS_OUT DS_Main(const OutputPatch<HS_OUT, 3> input, float3 location : SV_DomainLocation, PatchTess patch)
{
DS_OUT output = (DS_OUT)0.f;
float3 localPos = input[0].pos * location[0] + input[1].pos * location[1] + input[2].pos * location[2];
float2 uv = input[0].uv * location[0] + input[1].uv * location[1] + input[2].uv * location[2];
output.pos = mul(float4(localPos, 1.f), g_matWVP);
output.uv = uv;
return output;
}

Hull Shader에서 추가된 정점을 포함하여 모든 정점에 대하여 Domain Shader 계산을 한다. 그리고 좌표를 정점이 추가되기 전 정점들을 기준으로 상대적인 위치로 구한다. 중앙에 새로 추가된 정점은 세 정점에 대해 모두 같은 거리이므로 0.33, 0.33, 0.33 이다. 그리고 기존 Vertex Shader에서 곱해줬지만 Tessellation추가 후에는 matWVP를 여기서 곱해준다.
'그래픽스' 카테고리의 다른 글
| [DX12] Picking (0) | 2022.07.31 |
|---|---|
| [DX12] Terrain (0) | 2022.07.31 |
| [DX12] Shadow Mapping (0) | 2022.07.30 |
| [DX12] Instancing (0) | 2022.07.30 |
| [DX12] Particle System (0) | 2022.07.29 |