저번 포스팅에선 Wave Deformer 예시를 갖고 Deformer 연산에 대한 이해와 비선형 Deform 작업에서 Normal을 구하는 방법 두 가지
(J Matrix, 근사수치기법)에 대해 공부했습니다.
이번 포스팅에선 저번 예제에서 보였던 각진 물결을 보다 부드럽게 만들기 위해 Tessellation 기술에 대한 전반적인 지식을 익혀 볼 것 입니다.
이런 지식을 익힌 후 기존 예제를 보강하는 방식으로 포스팅이 진행 될 것입니다.
1. Tessellation이란?
MSDN에서는 Tessellation을 다음과 같이 설명했습니다. "GPU를 통해 low-detail subdivision surface를 high-detail subdivision surface로 변환해주는 작업을 Tessellation이라 한다.". 이런 Tessellation 작업은 Direct3D 11 버전부터 프로그래머가 조정 할 수 있게 3개의 Stage로 세분화되어 그래픽 파이프라인에 추가됐습니다.
![](https://t1.daumcdn.net/cfile/tistory/995214445A34BEDB19)
(출처 : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ff476340(v=vs.85).aspx)
추가된 Stage는 위 사진과 같이 Hull-Shader Stage, Tessellator Stage, Domain-Shader Stage 입니다. 각 스테이지에 대한 설명은 이후 천천히 끄적여 보겠습니다.
위에서 설명한 Tessellator는 저희에게 큰 이득을 줍니다. 몇 가지 예를 들면, Tessellation 기술은 메모리와 대역폭 절약을 도왔고 이를 통해 우리는 저해상도 모델에서 훨씬 세밀한 표현을 할 수 있게 됐습니다. 또한 Displacement Mapping을 할 수 있게 돼 기존에는 상상 할 수 없던 세밀한 표현을 할 수 있게 됐습니다.
아래 사진은 각 기술로 인해 같은 모델이 어떻게 달라지는 지를 보여줍니다.
![](https://t1.daumcdn.net/cfile/tistory/990BD8405A34C07312)
(출처 : http://vsts2010.tistory.com/542?category=128642)
처음은 가장 기본형태의 low-subdivision surface model이며 두 번째는 Tessellation이 적용된 상태의 모델, 세 번째는 Displacement Mapping이 적용된 모델입니다.
2. Hull-Shader Stage
기존 Tessellation 작업이 생기기 전, 우리는 Vertex Shader Stage에서 정점의 World-View-Projection과 Displacement 모두를 처리했었습니다. 하지만 Tessellator가 파이프라인에 추가되면서 우리는 이런 작업들을 분리 할 필요가 생겼습니다.
때문에 Tessellation이 목적인 경우, Vertex Shader의 역할이 Tessellation의 시작 단계인 'Hull Shader에서 사용 할 데이터의 전달' 정도로 축소 됩니다. 즉, Vertex Shader에선 World-View-Projection가 수행되서는 안됩니다. 그 이유는 테셀레이션에선 Vertex Shader에 들어온 정점을 사용하는게 아니라 Vertex Shader에서 들어온 데이터를 기반으로 새로운 정점들을 생성하기 때문입니다. 때문에 우리는 Vertex Shader 단계에선 Projection을 하는게 아니라 그 이전 단계인 정점의 월드 변환까지만 진행해야 합니다.
이후 Hull Shader는 '폴리곤을 어떻게 분할할 것 인가?' (Hull-Main Shader)와 '폴리곤을 얼마나 분할할 것인가?' (Hull-Constant Shader)를 결정합니다.
이런 작업은 병렬적으로 이루어지며 각 패치마다 한 번씩 발생합니다. 이 과정은 다음과 같이 간단한 형태로 표현 할 수 있습니다.
![](https://t1.daumcdn.net/cfile/tistory/992E504A5A34C93018)
(출처 : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ff476340(v=vs.85).aspx#Hull_Shader_Stage)
여기서 처음 Hull Shader에 Input으로 들어오는 Patch Control Points는 낮은 차수를 표현하는 정점들입니다. 이를 Hull Shader를 통해 더 높은 차수를 갖는 면을 만들며, 이 면을 이루는 Patch Control Points들이 이후 Domain-Shader Stage에서 사용됩니다.
MSDN에 나와있는 Hull-Main Shader의 가장 간단한 형태는 다음과 같습니다.
[domain("quad")] // patch는 quad 형태
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(16)] // 1~32 까지 지정 가능
[patchconstantfunc("SubDToBezierConstantsHS")] // Hull-Constant Shader 함수 지정
BEZIER_CONTROL_POINT MainHS( InputPatch ip,
uint i : SV_OutputControlPointID,
uint PatchID : SV_PrimitiveID )
{
VS_CONTROL_POINT_OUTPUT Output;
// Insert code to compute Output here.
return Output;
}
이 Hull-Main Shader는 앞서 말씀드렸듯, '폴리곤을 어떻게 분할 할 것 인가'를 지정하는 코드입니다.
다음은 '폴리곤을 얼마나 분할할 것 인가?'를 지정하는 Hull-Constant Shader의 기본 형태 코드입니다.
#define MAX_POINTS 32
// Patch Constant Function
HS_CONSTANT_DATA_OUTPUT
SubDToBezierConstantsHS( InputPatch ip,
uint PatchID : SV_PrimitiveID )
{
HS_CONSTANT_DATA_OUTPUT Output;
// Insert code to compute Output here
return Output;
}
이 Function의 결과에 '폴리곤을 얼마나 많이 분할 할 것인가?'에 대한 정보가 담깁니다.
이런 정보를 HS_CONSTANT_DATA_OUTPUT 구조체에 담고 있으며
이 구조체는 patch의 형태에 따라 담는 내용이 달라집니다.
사각형의 경우
// Output patch constant data.
struct HS_CONSTANT_DATA_OUTPUT
{
float Edges[4] : SV_TessFactor;
float Inside[2] : SV_InsideTessFactor;
...
};
삼각형의 경우
// Output patch constant data.
struct HS_CONSTANT_DATA_OUTPUT
{
float Edges[3] : SV_TessFactor;
float Inside : SV_InsideTessFactor;
...
};
와 같은 구조체를 사용하게 됩니다.
(SV_TessFactor와 SV_InsideTessFactor에 대한 설명은 다음 Tessellator Stage 포스팅에서 추가 설명하겠습니다.)
이렇게 나온 Output은 이후 Tessellator Stage에서 사용하게 됩니다.
Tessellator Stage는 프로그래머가 조작 할 수 없는 Stage이기에 다음 포스팅에서는 내부적으로 어떤 과정을 거치는 지
에 대한 개념 설명 포스팅이 올라갈 예정입니다.
(본 내용은 http://vsts2010.tistory.com/520 의 내용과 거의 99% 일치하며, 본 게시자가 공부하기 위해 추가적인 내용을 덧 붙인 것에 불과합니다. 따라서 본 내용에서 미숙한 표현이나 드러내지 못 한 정보가 있다면 위 링크에서 확인을 하시거나 댓글로 남겨주시면 해결하기 위해 노력하겠습니다.)