[DirectX11] Tessellation

jaehyeonLee·2025년 1월 29일

Tessellation

Tessellation은 정점을 세분화하여 더 많은 폴리곤을 생성하는 기법이다

pipeline 에서 hullshader-> Tessellation State-> Domain-Shader stage로 순서를 지나게 되며 주로 지형, 캐릭터 모델 , 곡면등에 사용이된다.
기본적으로 지형의 폴리곤은 아래와 같이 구성된다.

카메라가 가까이 가면, 폴리곤이 세분화되어 더 정밀한 표현이 가능하다.

반대로, 멀리 있는 지형은 단순한 폴리곤 형태로 유지된다

Tessellation의 성능 최적화 효과
테셀레이션을 사용하면 LOD(Level of Detail) 기법과 결합하여 최적화할 수 있다.

가까운 오브젝트는 세밀하게,
먼 오브젝트는 단순하게 표현하여 성능을 향상시킨다.
이러한 방식으로 Tessellation을 적용하면 기존보다 더 효율적인 렌더링이 가능하게 된다.

Hull-Shader 단계

패치당 한 번 호출되는 Hull shader는 하위표면을 정의하는 입력제어점을 패치를 구성하는 제어점으로 변환한다고 하는데 이는 간단하게 설명하면 분할 옵션을 설정하는 단계라고 보면된다.
밑의 코드역할:
패치(4개의 정점)의 중심 좌표를 계산
카메라 거리 기반으로 세분화 정도 조정 (tess 계산)
4개의 정점을 그대로 전달 (HullOut)

struct PatchTess
{
	float EdgeTess[4]   : SV_TessFactor;
	float InsideTess[2] : SV_InsideTessFactor;
};

PatchTess ConstantHS(InputPatch<VertexOut, 4> patch, uint patchID : SV_PrimitiveID)
{
	PatchTess pt;

	float3 centerL = 0.25f * (patch[0].PosL + patch[1].PosL + patch[2].PosL + patch[3].PosL);
	float3 centerW = mul(float4(centerL, 1.0f), gWorld).xyz;

	float d = distance(centerW, gEyePosW);

	// Tessellate the patch based on distance from the eye such that
	// the tessellation is 0 if d >= d1 and 60 if d <= d0.  The interval
	// [d0, d1] defines the range we tessellate in.

	const float d0 = 20.0f;
	const float d1 = 100.0f;
	float tess = 64.0f * saturate((d1 - d) / (d1 - d0));

	// Uniformly tessellate the patch.

	pt.EdgeTess[0] = tess;
	pt.EdgeTess[1] = tess;
	pt.EdgeTess[2] = tess;
	pt.EdgeTess[3] = tess;

	pt.InsideTess[0] = tess;
	pt.InsideTess[1] = tess;

	return pt;
}
struct HullOut
{
	float3 PosL : POSITION;
};

[domain("quad")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(4)]
[patchconstantfunc("ConstantHS")]
[maxtessfactor(64.0f)]
HullOut HS(InputPatch<VertexOut, 4> p,
	uint i : SV_OutputControlPointID,
	uint patchId : SV_PrimitiveID)
{
	HullOut hout;

	hout.PosL = p[i].PosL;

	return hout;
}

Tessellation stage

테셀레이터는 Hull shader를 파이프라인에 바인딩하여 초기화된 고정 함수 단계이다 분할기 단계의 목적은 도메인(사각형, 삼각형 또는 선)을 여러 개의 더 작은 개체(삼각형, 점 또는 선)로 세분화하는 것이다.
Hull shader에서 넘긴 옵션들을 하드웨어가 받아서 실행하는 단계이다.

Domain-Shader Stage

Tessellator에서 생성한 새로운정점을 입력으로 받고 새로운 정점의 위치를 lerp 및 변형을 하는 단계이다.
밑 코드에서의 역할
Quad 내부의 위치 기반으로 보간(lerp)된 정점을 계산
높이 변형

[domain("quad")]
DomainOut DS(PatchTess patchTess,
	float2 uv : SV_DomainLocation,
	const OutputPatch<HullOut, 4> quad)
{
	DomainOut dout;

	// Bilinear interpolation.
	float3 v1 = lerp(quad[0].PosL, quad[1].PosL, uv.x);
	float3 v2 = lerp(quad[2].PosL, quad[3].PosL, uv.x);
	float3 p = lerp(v1, v2, uv.y);

	// Displacement mapping
	p.y = 0.3f * (p.z * sin(p.x) + p.x * cos(p.z));

	dout.PosH = mul(float4(p, 1.0f), gWorldViewProj);

	return dout;
}
profile
이재현의 필기노트

0개의 댓글