테셀레이션을 사용하는 이유

1. GPU상의 동적 LOD

 

2. 효율적인 물리 및 애니메이션 계산

ㄴ 물리와 애니메이션을 저다각형 메시에 대해 수행하고, 그 저다각형 메시를 테셀레이션해서 고다각형 버전을 만들면 물리 및 애니메이션 계산을 낮은 세부도에서 수행함으로써 계산량을 줄일 수 있다.

 

3. 메모리 절약

ㄴ 메모리에는 저다각형 버전을 담아두고 GPU 테셀레이션으로 즉석에서 고다각형 버전을 생성하는 방식을 사용하면 메모리를 절약할 수 있다.

 

테셀레이션 단계들은 정점 셰이더 단계와 기하 셰이더 단계 사이에 위치할 수 있으며, 생략 가능하다.

1. 덮개 셰이더 단계

2. 테셀레이터 단계

3. 영역 셰이더 단계

 

14.1 테셀레이션 기본도형 위상구조

IASetPrimitiveTopology 메서드로 삼각형이 아닌 제어점들로 이루어진 패치를 입력으로 설정

D3D_PRIMITIVE_TOPOLOGY_N_CONTROL_POINT_PATCHLIST (N은 1부터 32 까지 있음)

제어점이 5개 이상인 패치는 보통 곡면을 구현하기 위해 사용된다.

 

14.2 덮개 셰이더

두 종류의 셰이더로 구성됨

1. 상수 덮개 셰이더

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

사각형 패치에 대한 테셀레이션의 경우 6개의 테셀레이션 개수를 지정할 수 있다.

변 테셀레이션 계수 4개와 내부 테셀레이션 계수 2개

 

모든 테셀레이션 계수가 0이면 그 패치는 폐기된다.

 

테셀레이션 정도를 결정하는데 흔히 쓰이는 측정치

1. 카메라와의 거리

2. 화면 영역 포괄도 (물체가 화면의 픽셀을 몇개나 덮는지)

3. 방향 (시점에 따라 물체의 윤곽선으로 보이는 삼각형들은 다른 삼각형들보다 세분하면 자연스럽다.)

4. 표면 거칠기 (표면 거칠기가 높은 세부사항이 많은 표면은 테셀레이션 정도를 높일 필요가 있다.)

 

2. 제어점 덮개 셰이더

제어점을 받아서 제어점을 출력하는데, 제어점 개수를 증강할 수 있다.

struct HullOut
{
	float3 PosL : POSITION;
};

[domain("quad")] // 패치의 종류 tri, quad, isoline 중 하나
[partitioning("integer")] // 테셀레이션 단위가 정수 // 분수는 fractional_even 또는 fractional_odd
[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;
}

14.3 테셀레이터 단계

상수 덮개 셰이더가 출력한  테셀레이션 계수들에 기초해서 패치들을 테셀레이션하고 정점들을 생성해 출력한다.

 

14.4 영역 셰이더

테셀레이터 단계에서 출력된 정점마다 한 번씩 호출됨, 동차 절단 공간으로 변환하는 역할

세 가지 종류의 입력을 받는다.

1. 테셀레이션된 정점 위치의 매개변수화된 좌표 (u, v)

2. 제어점 덮개 셰이더가 출력한 제어점

3. 상수 덮개 셰이더가 출력한 테셀레이션 계수들

struct DomainOut
{
	float4 PosH : SV_POSITION;
};

[domain("quad")]
DomainOut DS(PatchTess patchTess, // 상수 덮개 셰이더가 출력한 테셀레이션 계수들
		float2 uv : SV_DomainLocation, // 테셀레이터 단계에서 얻은 정점의 매개변수화된 좌표
           	const OutputPatch<HullOut, 4> quad) // 제어점 덮개 셰이더가 출력한 제어점 패치
{
	DomainOut dout;
    
    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);
    
    float4 posW = mul(float4(p, 1.0f), gWorld); //
    dout.PosH = mul(posW, gViewProj); 			// 동차 좌표계로 변환
    
    return dout;
}

14.6 삼차 베지에 사각형 패치

다수의 제어점을 이용해서 곡면을 생성하는 방법

삼차 베지어 매개변수 공식
삼차 베지에 곡선
삼차 베지에 곡선의 도함수 (곡선의 접선 벡터를 계산할 때 유용)

14.6.2. 삼차 베지에 곡면

영역 셰이더에서 계산이 일어남

 

테셀레이터 단계에서 만들어진 정점의 좌표 uv의 0과 1사이의 v.x 와 uv.y 값을 삼차 베지에 공식의 t에 집어 넣음

테셀레이션되어 생성된 정점들 각각의 위치 (정점 한 개) 를 계산하는데 16개의 제어점이 모두 쓰인다.

 

1.

사각형 패치 대신 삼각형 패치를 테셀레이션 한 결과
삼각형 패치를 입력으로 받는 영역 셰이더 함수
정점 버퍼에 넣을 정점 배열도 수정한다.

5.

2차 베지에 곡면에 대한 매개변수 방정식 p(u, v)

7. 8.

제어점이 아홉 개인 이차 베지에 곡면

베지에 곡면 예제를 제어점이 아홉 개인 이차 베지에 곡면을 사용하도록 만들고, 곡면에 색조와 조명을 적용했다.

기존 3차 베지에 곡면 구현을 위해 16개의 제어점이 사용되던 것을 9개로 줄였다.

베지에 곡면 관련 함수를 수정하였다.

픽셀 셰이더에서 조명을 계산하기 위해 법선 벡터를 u, v에 대한 편미분 계수를 외적함으로써 구했고, uv 값은 텍스처 좌표값에 대응되도록 하였다.

 

연습문제 파일

https://github.com/lemonyun/Directx12_study/tree/main/14

 

GitHub - lemonyun/Directx12_study: 2022/06/10

2022/06/10. Contribute to lemonyun/Directx12_study development by creating an account on GitHub.

github.com

 

+ Recent posts