一、Tessellation
1. Tessellation Primitive Modes
First thing first,若想使用tessellation shader,在draw的时候要使用:
glDrawArrays(GL_PATCHS, ...)
tessellation control shader接收一系列顶点(这些顶点的合集被称为patch),输出一系列点(输出的点被称为control point)至tessellation evaluation shader。
首先,在cpp声明tcs接受多少顶点为一个patch:
声明了4个顶点输入为1个patch。
glPatchParameteri(GL_PATCH_VERTICES, 4);
TCS
然后在tcs的开头使用out关键字声明输出的控制点数量:
// tessellation control shader
#version 420 core
layout (vertices = 4) out; // 输出4个控制点
void main(void)
{
if (gl_InvocationID == 0)
{
gl_TessLevelInner[0] = 9.0;
gl_TessLevelInner[1] = 7.0;
gl_TessLevelOuter[0] = 3.0;
gl_TessLevelOuter[1] = 5.0;
gl_TessLevelOuter[2] = 3.0;
gl_TessLevelOuter[3] = 5.0;
}
// 一般情况下tcs输出控制点与输入点数量保持一致。当然也可以有其他算法,这里不赘述。
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
在tcs的main函数中声明细分参数:gl_TessLevelInner【】和gl_TessLevelOuter【】。这是两个数组,分别表示内部空间的细分和边的细分。具体细分法则取决于tes。
TES
TES接受控制点、输出细分出的点。
在tes的开头声明细分模式。可选项有quads, triangles, or isolines。
输入的控制点存在gl_in[]数组中。每个细分出的结果点的重心坐标放在gl_TessCoord。
可以根据重心坐标和控制点的位置计算本点的gl_Position。同样地,可以直接按重心公式计算,也可使用其他算法(如贝塞尔曲面);
tessellation evaluation shader
#version 420 core
layout (quads) in; // 声明输入的控制点将组成一个四边形。
// layout (quads, point_mode) in // 若只想把细分之后的点画出来,则加上point_mode
void main(void)
{
vec4 p1 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);
vec4 p2 = mix(gl_in[2].gl_Position, gl_in[3].gl_Position, gl_TessCoord.x);
gl_Position = mix(p1, p2, gl_TessCoord.y);
}
2. Tessellation Subdivision mode
同样是在TES中layout声明。有三种模式:
equal_spacing 将gl_TessLevelOuter向上取整,然后均分成该份数;默认;
fractional_even_spacing 将gl_TessLevelOuter向下取偶数整数,然后大部分均分成该份数,剩下的小部分分两半;
fractional_odd_spacing 将gl_TessLevelOuter向下取奇数整数,然后大部分均分成该份数,剩下的小部分分两半;
好处就是在动态设置gl_TessLevelOuter时,后两种模式能平滑过渡。