OpenGL超级宝典第八章学习笔记:基元处理之曲面细分

前言
本篇在讲什么

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_spacingfractional_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

♠ 结语

若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。

👉 本文属于原创文章,转载请评论留言,并在转载文章头部著名作者出处👈
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值