새소식

개발/Shader

[Snow Footprint] 02.Tessellator - 01 (Hull-Shader)

  • -

저번 포스팅에선 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://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을 할 수 있게 돼 기존에는 상상 할 수 없던 세밀한 표현을 할 수 있게 됐습니다.
아래 사진은 각 기술로 인해 같은 모델이 어떻게 달라지는 지를 보여줍니다.


(출처 : 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)를 결정합니다.

이런 작업은 병렬적으로 이루어지며 각 패치[각주:1]마다 한 번씩 발생합니다. 이 과정은 다음과 같이 간단한 형태로 표현 할 수 있습니다.

(출처 : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ff476340(v=vs.85).aspx#Hull_Shader_Stage)

여기서 처음 Hull Shader에 Input으로 들어오는 Patch Control Points는 낮은 차수[각주:2]를 표현하는 정점들입니다. 이를 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% 일치하며, 본 게시자가 공부하기 위해 추가적인 내용을 덧 붙인 것에 불과합니다. 따라서 본 내용에서 미숙한 표현이나 드러내지 못 한 정보가 있다면 위 링크에서 확인을 하시거나 댓글로 남겨주시면 해결하기 위해 노력하겠습니다.)

  1. 패치는 subdivision을 이루는 최소 형태를 말하며, 주로 삼각형 (triangle), 사각형 (quad)를 사용합니다. [본문으로]
  2. 그래픽에서 면은 무향그래프로 이루어져 있으며, 이런 무향그래프에서 각 정점에 연결된 간선의 개수를 차수라 한다. [본문으로]
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.