本篇在讲什么 OpenGL蓝宝书第八章学习笔记之曲面细分 本篇适合什么 适合初学OpenGL的小白 本篇需要什么 对C++语法有简单认知 对OpenGL有简单认知 最好是有OpenGL超级宝典蓝宝书 依赖Visual Studio编辑器 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 |
★提高阅读体验★ 👉 ♠ 一级标题 👈👉 ♥ 二级标题 👈👉 ♣ 三级标题 👈👉 ♦ 四级标题 👈 |
目录
- ♠ 曲面细分
- ♥ 曲面细分基元模式
- ♣ 使用四边形拆分基元
- ♣ 使用三角形的曲面细分
- ♣ 使用等值线的曲面细分
- ♣ 曲面细分点模式
- ♥ 曲面细分子分段模式
- ♣ 等间距模式
- ♣ 分段长度模式
- ♣ 控制环绕顺序
- ♥ 数据在曲面细分着色器之间的传递
- ♠ 推送
- ♠ 结语
♠ 曲面细分
在第三章管线的学习当中我们已经对细分曲面阶段有了一定的了解,这一章节我们在对其进行一遍系统一点的学习
细分曲面位于顶点着色器和几何着色器之间,分为了三个阶段分别是曲面细分控制着色器(TCS)、固定功能型曲面细分引擎以及曲面细分评估着色器(TES)
曲面细分控制着色器负责生成3项数据
- 生成单个面片的内外曲面细分因子
- 生成单个输出控制点的位置和其他属性
- 生成单个面片的用户定义的变量
曲面细分引擎将确定大基元如何拆分成小基元
曲面细分评估着色器接受上二者传递的数据、处理后输出至基元装配
♥ 曲面细分基元模式
曲面细分模式用于确定怎么拆分基元的,拆分的方式有三种分别是四边形、三角形或等值线,下面我们挨个看个例子
注:
以下所有示例均摘自OpenGL超级宝典配套资源代码tessmodes
,可自行查看
注:
以下示例均设置默认顶点和片元着色器,文中不在累述
♣ 使用四边形拆分基元
下方是一个简单的使用四边形拆分基元的曲面细分控制着色器和曲面细分评估着色器的例子
- 曲面细分控制着色器
# version 420 core
layout (vertices = 4) out;
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;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
- 曲面细分控制着色器
# version 420 core
layout (quads) in;
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);
}
上述着色器运行后的效果如下图所示
我们简单介绍一下着色器代码中比较重要的部分
要点1:
gl_TessLevelInner
用来控制内部细分的等级
要点2:gl_TessLevelOuter
用来控制外部细分的等级
要点3:layout (quads) in
四边形模式的特殊限定符
我们可以很明显的看出来外部边被分成了5-3-5-3,对应着我们上部分gl_TessLevelOuter
设置的细分等级
我们也可以很明显的看出来内部被分成了9*7的区域,对应着我们上部分gl_TessLevelInner
设置的细分等级
♣ 使用三角形的曲面细分
同理我们先看一下着色器代码和最终的显示效果
- 曲面细分控制着色器
# version 420 core
layout (vertices = 3) out;
void main(void)
{
if (gl_InvocationID == 0)
{
gl_TessLevelInner[0] = 5.0;
gl_TessLevelOuter[0] = 8.0;
gl_TessLevelOuter[1] = 8.0;
gl_TessLevelOuter[2] = 8.0;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
- 曲面细分控制着色器
# version 420 core
layout (triangles) in;
void main(void)
{
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);
}
上述着色器运行后的效果如下图所示
我们简单介绍一下着色器代码中比较重要的部分
要点1:
gl_TessLevelInner
数组的第一个元素,该级别应用于曲面细分三角形的整个内部区域
要点2:gl_TessLevelOuter
数组的前三个元素用于设置三角形三条边的曲面细分因子
要点3:layout (triangles) in
三角形模式的特殊限定符
我们可以很明显的看出来三条边都被分成了8分,对应着我们上部分gl_TessLevelOuter
设置的细分等级
下图依次展示了gl_TessLevelInner
内部细分等级2-5的效果,细分等级越大,内部细分的越复杂
♣ 使用等值线的曲面细分
同理我们先看一下着色器代码和最终的显示效果
- 曲面细分控制着色器
# version 420 core
layout (vertices = 4) out;
void main(void)
{
if (gl_InvocationID == 0)
{
gl_TessLevelOuter[0] = 5.0;
gl_TessLevelOuter[1] = 5.0;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
- 曲面细分控制着色器
# version 420 core
layout (isolines) in;
void main(void)
{
float r = (gl_TessCoord.y + gl_TessCoord.x / gl_TessLevelOuter[0]);
float t = gl_TessCoord.x * 2.0 * 3.14159;
gl_Position = vec4(sin(t) * r, cos(t) * r, 0.5, 1.0);
}
上述着色器运行后的效果如下图所示
我们简单介绍一下着色器代码中比较重要的部分
要点1:
gl_TessLevelInner
不在使用
要点2:gl_TessLevelOuter
的前两个分量中的两个外部曲面细分因子分别用于确定线条数量以及每条线上的线段数量
要点3:layout (isolines) in
等值线模式的特殊限定符
♣ 曲面细分点模式
使用point_model
布局限定符,可将生成的顶点按照独立点进行渲染
- 曲面细分控制着色器
# version 420 core
layout (triangles, point_mode) in;
void main(void)
{
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);
}
♥ 曲面细分子分段模式
在一定情况下我们可以调整对已生成基元的边缘的分段方式,下面介绍一下几种分段方式的效果和特定布局限定符
♣ 等间距模式
使用限定符equal_spacing
,在着色器中的写法如下,效果就是边缘等分,如下图
layout (triangles, equal_spacing) in;
♣ 分段长度模式
使用限定符fractional_even_spacing
或fractional_odd_spacing
,在着色器中的写法如下,效果就是根据情况对边缘进行不等分,如下图
layout (triangles, fractional_even_spacing) in;
layout (triangles, fractional_odd_spacing) in;
♣ 控制环绕顺序
使用以下布局限定符指定顺时针环绕顺序
layout (cw) in;
要指定曲面细分引擎所生成的基元环绕顺序是逆时针,需要添加此限定符
layout (ccw) in;
♥ 数据在曲面细分着色器之间的传递
曲面细分控制着色器的输入和输出都用数组表示,输入数组的尺寸根据每个面片中的控制点数量确定,通过调用以下函数设置
glPatchParameteri(GL_PATCH_VERTICES,n);
注:
表示每个面片的顶点数量。默认情况下,每个面片的顶点数量为3
曲面细分控制着色器的输出也是数组,但其尺寸通过着色器前方的顶点输出布局限定符设置
某些简单的渲染流程可以不包含
曲面细分控制着色器,当不存在曲面细分控制着色器时,所有内外部曲面细分等级
的默认值为1.0
。可通过调用glPatchParameterfv()
更改此设置,其原型为
void glPatchParameterfv (GLenum pnameconst GLfloat * values);
♠ 推送
- Github
https://github.com/KingSun5
♠ 结语
若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。