Graphics Programming

테셀레이션 셰이더(Tessellation Shader) 본문

Season 1/OpenGL

테셀레이션 셰이더(Tessellation Shader)

minseoklee 2015. 9. 18. 15:35

Tessellation: high-order primitive, 즉 patch를 작고 단순한 수많은 primitive들로 쪼개는 작업

 

OpenGL은 테셀레이션 엔진을 내장하고 있다. 이 엔진은 고정 기능이지만 여러 설정이 가능하다.

테셀레이션 엔진은 quadrilateral, triangle, line을 point, line, triangle으로 조각내어, 일반적인 래스터라이제이션 하드웨어가 바로 쓸 수 있게 만든다.

 

테셀레이션 단계는 3단계로 나뉜다.

1. Tessellation Control Shader(TCS): 입력되는 control point들을 처리하고 여러 테셀레이션 인자를 결정한다.

2. Fixed-function Tessellation Engine: patch를 단순한 primitive들로 변환한다.

3. Tessellation Evaluation Shader(TES): 테셀레이션 후 생성된 정점들을 처리한다.

 

patch가 정점 몇 개로 이루어지는가는 다음의 함수로 결정하며 그 기본값은 3이다.

void glPatchParameteri(GLenum pname, GLint value);

- pname에는 GL_PATCH_VERTICES

- value에는 정점 개수

 

TCS 예시(입력되는 patch가 정점 3개로 이루어질 때)

#version 450 core

 

layout(vertices=3) out; // 출력도 정점 3개 단위임을 명시

 

// 정점 셰이더에서 vec3 tc_color, vec2 tc_uv, vec3 tc_norm을 출력할 경우.

// 배열로 선언해야 한다. 각각의 크기는 3이다.

 

in vec3 tc_color[];
in vec2 tc_uv[];
in vec3 tc_norm[];

 

// 출력 역시 배열이여야 한다.

out vec3 te_color[];
out vec2 te_uv[];
out vec3 te_norm[];

 

void main() {

 // 하나의 셰이더에서 gl_InvocationID가 0, 1, 2까지 변화한다.
 if(gl_InvocationID == 0){
  gl_TessLevelInner[0] = 5.0;
  gl_TessLevelOuter[0] = 5.0;
  gl_TessLevelOuter[1] = 5.0;
  gl_TessLevelOuter[2] = 5.0;
 }
 gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;

 te_color[gl_InvocationID] = tc_color[gl_InvocationID];
 te_uv[gl_InvocationID] = tc_uv[gl_InvocationID];
 te_norm[gl_InvocationID] = tc_norm[gl_InvocationID];
}

 

TCS에는 다음과 같은 내장 변수들이 있다.

 

in gl_PerVertex {
 vec4 gl_Position;
        float gl_PointSize;
        float gl_ClipDistance[];
} gl_in[gl_MaxPatchVertices];

 

in int gl_PatchVerticesIn;
in int gl_PrimitiveID;
in int gl_InvocationID;

 

out gl_PerVertex {
        vec4 gl_Position;
        float gl_PointSize;
        float gl_ClipDistance[];
} gl_out[gl_VerticesOut];

 

patch out float gl_TessLevelOuter[4];
patch out float gl_TessLevelInner[2];

 

gl_TessLevelOuter와 gl_TessLevelnner는 테셀레이션 수준을 결정하는 인자로서 테셀레이션 모드에 따라 어느 값까지 쓰이는지가 달라진다.

이 모드는 TES에서 input layout qualifier를 이용하여 설정되며 quads, triangles, isolines 중 하나다.

 

모드가 quads일 경우 모든 값인다.

모드가 triangles일 경우 inner는 0, outer는 1,2,3만 쓰인다.

모드가 isolines일 경우 outer 0,1만 쓰인다.

 

patch 키워드는 정점 단위가 아니라 patch 단위로 데이터를 전송하기 위해 붙이며 TCS의 출력, TES의 입력 변수에 붙일 수 있다.

 

TES 예시

#version 450 core

 

// 삼각형 단위로 입력받는다(quads, triangles, isolines 중 하나)

// subdivision mode는 equal_spacing이다 (fractional_even_spacing 또는 fractional_odd_spacing 가능)

// 입력 순서는 시계 방향 (cw 또는 ccw. ccw가 기본값)

layout(triangles, equal_spacing, cw) in;

 

in vec3 te_color[];
in vec2 te_uv[];
in vec3 te_norm[];

 

out vec3 color;
out vec2 uv;
out vec3 norm;

 

void main() {
 gl_Position =
  (gl_TessCoord.x * gl_in[0].gl_Position +
  gl_TessCoord.y * gl_in[1].gl_Position +
  gl_TessCoord.z * gl_in[2].gl_Position);
 color = gl_TessCoord.x * te_color[0] + gl_TessCoord.y * te_color[1] + gl_TessCoord.z * te_color[2];
 uv = gl_TessCoord.x * te_uv[0] + gl_TessCoord.y * te_uv[1] + gl_TessCoord.z * te_uv[2];
 norm = gl_TessCoord.x * te_norm[0] + gl_TessCoord.y * te_norm[1] + gl_TessCoord.z * te_norm[2];
}

 

테셀레이션 엔진을 거치면 새로운 정점들이 생성되는데, 각 점에서의 attribute들을 직접 보간해줘야 한다.

gl_in[3]은 이 정점을 생성하는 데 사용된 3개의 정점을 나타낸다. gl_TessCoord는 보간에 필요한 인자들을 담는다.

 

Tessellation Point Mode

layout(triangles, point_mode) in;

입력은 원래대로 받지만 출력은 점으로

quads, triangles, isolines와 함께 사용 가능하다. 이 세 개는 여전히 gl_TessCoord와 inner/outer 레벨의 보간을 조절한다.

 

Comments