[GPU프로그래밍] 11.Using Tessellation Shaders
◾ Tessellation shader
- primitive 단위로 진행
- primitive를 생성하기 때문에 gs보다 먼저 진행
- ex) control point의 정보를 사용해 곡선을 그릴 때, line을 쪼개서 점의 위치 계산하고 line segment 생성
- 자동으로 geometry를 쪼개서 구성하기 때문에
Subdivide Geometry
기존 pipeline으로 들어간 geometry보다 밀도있는 geometry를 내보냄 (GPU내에서)
- 쪼갤 정도는 levels of detail에 따라 자동으로 조절된다
TCS/TPG/TES
- Tesselation shader의 진행 방식은 3단계로 나눠진다
- TCS에서 쪼갤 방법 및 정도에 대해 지정하고, 그 정보에 따라 TPG가 쪼개고, 쪼개진 버텍스별로 TPG에서 계산
Patch Primitive
- 실제로 렌더링되는 primitive는 아니고, 계산에 이용되는 추가 정보를 묶어서 TCS와 TES에 보내는 용도
- 한 Patch당 몇 개의 버텍스를 묶을건지 직접 정해준다
- ex) 삼각형은 3개, bezier curve는 4개
- 주로 control points의 set 역할
- Tessellation shader가 활성화되어있다면
GL_PATCHES
형태의 primitive만 사용해서 렌더링할 수 있다
- 각 patch에 묶을 수 있는 최대 버텍스 개수 확인 (시스템에 따라 다름)
❗ TCS/TPG/TES
1. TCS (Tessellation control shader)
- parameter space상에서 얼마나 쪼갤 것인지 대한 변수값 설정
gl_TessLevelInner
, gl_TessLevelOuter
- 같은 patch에 속한 vertex 정보를 가져올 수 있어서 (기존 vs와 차이점) 그 정보로 patch에 대한 계산해서 TES로 넘겨줌
- 한 patch primitive의 각 vertex마다 실행
2. TPG (Tessellation primitive generator)
- TCS에서 지정한 것에 대한 알고리즘을 따라 Input patch를 쪼개서 primitive 생성
코드X
- parameter값 생성 및 연결 정보 결정
- 각 버텍스는 parameter space에서의 위치 정보
u, v, w
로 구성 -> [0, 1]
- 이 정보는 TES에서 계산하는데 사용
3. TES (Tessellation evaluation shader)
- 쪼개져서 생성된 primitive의 형태 지정
- quads면 사각형 형태로, isolines이면 곡선 형태로, triangles면 삼각형 형태
- primitive의 각 버텍스별로 정보(위치 등) 계산
- TPG에서 생성된 parameter-space 버텍스마다 실행
👀 아래부터는 Geometry shader를 사용하는 예제 4가지
1. Bezier Curve
- 4개의 control point
- Cubic Bezier curve
- TCS에서 outer tessellation level을 지정해서 line segments의 개수 정의
- TES에서 u, v parameter와 patch의 버텍스 정보를 사용해 bezier curve 식 계산 (line이라 u, v 둘 중 하나만 쓰긴함)
- OpenGL Application에서
📃 Code
OpenGL Application
- 4개의 control points를 patch primitive로 묶어 pipeline으로 보냄
- patch별 버텍스 개수 지정
- patch primitive로 4개의 control points 그리기
- Segments의 개수(LoD), isolines(같은 값을 연결한 선)의 개수, 라인 컬러 uniform variables 설정
- 이 예제에서 isolines의 개수는 라인 하나니까 1
vertex Shader
- 라인만 그리므로 2D
- TES에서 계산할거라 변환도 X
tessellation control shader
gl_InvocationID
: 현재 TCS를 부른 vertex가 patch내에서 몇번째 index인지
- 들어온 patch vertex값을 그대로 내보냄
- 쪼개질 정보 TPG로 전달
tessellation evaluation shader
- 쪼개진 primitive의 형태가 결정되며 들어옴
- parameter
u
값과 patch의 vertex값으로 bezier 계산
- 계산된 3D 좌표에 MVP를 곱해서 최종 position 계산
fragment shader
2. 2D Quad
Level parameter
- TPG는 여섯개의 level parameter에 기반하여 (u, v) parameter space를 쪼갠다
- Outer level 0~3 (4개)
- Inner level 0~1 (2개)
- 각각
gl_TessLevelOuter
과 gl_TessLevelInner
배열에 저장
Linear interpolation
- 쿼드를 쪼갤 때, 쿼드의 4개의 버텍스를 interpolation해서 쿼드 위의 한 점
u, v
을 계산한다
- TPG에서 parametric coordinate set이 결정되고, 이에 해당하는 위치는 TES에서 Interpolation해서 계산
📃 Code
OpenGL Application
- Outer/Inner tessellation level은 유니폼 변수로 전달
- 반시계 방향으로 네 개의 버텍스를 담은 patch primitive 세팅
vertex shader
tessellation control shader
- 유니폼 변수로 받은 Outer/Inner tessellation level 내보내기
tessellation evaluation shader
- quad patch를 equal_spacing(균일한 간격으로), counter clock wise 방향으로 받아오기
- u, v parameter값과 patch의 버텍스로 linear interpolation하여 위치 계산
- 계산된 3D 좌표에 MVP를 곱해서 최종 position 계산
geometry shader
- 쪼개지는 것을 보기 위해 gs에서 테두리 그리기 (삼각형 면만 그리면 안보이니까)
fragment shader
3. 3D Surface
- 여러개의 patch로 이루어진 3D surface를 쪼개보자
- teapot에는 한 patch당 4x4개의 버텍스가 들어있으며, cubic Bezier surface를 구성하기 위한 16개의 control points로 사용된다
- 보내는 정보 (4x4 vertex)는 똑같은데 다른 디테일을 가진 surface를 만들 수 있다
-> ts를 사용하면 적은 정보로도 복잡한 모델을 만들 수 있고, 병렬연산으로 계산 속도도 빠르다
Cubic Bezier Surface Interpolation
- 이전 2D와 동일한 원리로 가로/세로 방향으로 계산
- 어떤 위치
u, v
에 있는지에 따라 control point로부터 받는 영향이 다른 것
Pij
: control point
Normal vector
- 쪼개진 surface마다 노말을 알아야 shading 계산 가능하므로 노말을 구해야함
원래는 surface를 주변 삼각형의 노말들을 평균내서 구했음
- 근데 지금은 surface에 대한 식(parametric bezier surface)이 있으므로, 이 식을 활용하여 노말을 구한다
- u, v 방향으로 편미분하여 평면에 접하는 두 접선을 구하고, 두 접선을 외적하여 수직인 벡터=노멀을 구한다 -> 근사가 아닌 정확한 노말!
📃 Code
OpenGL Application
- patch별 16개의 버텍스 개수 지정
- 16-vertex patch primitive로 control points 그리기
- but, control point가 매번 3D 모델에 주어지는게 아니라서 어려울 수 있음
tessellation control shader
- 들어온 patch vertex값을 그대로 내보냄
- 유니폼 변수로 받은 tessellation level 내보내기 (이 예제는 Outer/Inner 전부 같은 레벨)
tessellation evaluation shader
- 한 patch의 16개의 vertex를 control point로 설정
- bezier interpolation하여 나온 3D 위치
- camera coordinate로 변환하고, surface식을 편미분하여 구한 normal도 cc로 변환해서 fs로 보냄 -> shading 계산
- MVP를 곱해서 최종 위치 계산
geometry/fragment shader
4. Tessellating based on Depth
- tessellation level의 값을 유니폼이 아닌 depth의 값으로 계산 (linear interpolation)
Level-of-detail (LOD)
- 카메라와의 거리(또는 다른 요인)와 오브젝트의 지오메트리 복잡성을 연관시킴
📃 Code
OpenGL Application
- tessellation level과 depth의 최대/최소값 설정 (유니폼 변수)
- depth가 작으면 level이 최대
- depth가 크면 level이 최소
tessellation control shader
- 실제 depth를 구하려면 sqaure root를 사용하게 되고 계산양이 너무 많아짐..
- 그래서 control point를 cc로 변환하고 z값으로 depth를 근사한다
- [0, 1]범위의 depth로 tessellation level interpolation
❗issues
- tessellation level은 patch마다 주어지는 값인데, ts에서 계산하면 patch의 vertex마다 즉, 16번 계산하게된다
- 매번 depth값이 약간씩 달라서 그 안에서 level값이 차이날 수 있다 -> 그 중 하나 사용됨
- patch끼리 이웃하는데, patch별로 level이 달라지면 어긋나보일 수 있음
- level이 낮으면 틈이 벌어질 수 있음