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

♠ 结语

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

👉 本文属于原创文章,转载请评论留言,并在转载文章头部著名作者出处👈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/26736.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

有道云笔记也挺速度,也搞了个AI助手,能抗衡Notion AI?

前言 小编平时做技术笔记的时候,经常使用到的软件就是有道云笔记,最近无意间发现,笔记编写的页面中,竟然集成了AI助手!网易有道可真是低调!毕竟最近AI圈大火,竟然没有蹭一波热度,直…

决策树理论

这个文本讨论了决策树模型中的基尼系数。当数据集的所有数据属于同一类时,基尼系数为0,因为此时无需进行分类,已经属于同一类别。因此,选项B是正确的。 决策树是一种用于分类和预测的机器学习模型。基尼系数是衡量数据集纯度的指标…

苹果服务端通知v2处理(AppStore Server Notifications V2)

苹果服务端通知v2处理 关键词: App Store Server Notifications V2、Python源码、苹果订阅、JWS、x5c、JSON WEB TOKEN 背景 最近要接入苹果订阅功能,调研后发现订阅生命周期内的状态变更是通过苹果服务端通知返回的(什么时候普通内购也能加上减少掉单的概率)&am…

Qt在MySQL中存储音频文件

一、在存储音频视频等大文件时需要以二进制文件进行存储,首先需要了解mysql存储二进制文件的字段类型以及大小: 需要创建数据库中的图片类型为:二进制mediumblob类型,( TinyBlob 最大 255 Blob 最大 65K MediumBlob …

基于区域的图像分割

文章目录 基于区域的图像分割基本原理常用的算法实现步骤示例代码结论 基于区域的图像分割 基于区域的图像分割是数字图像处理中常用的一种方法,它通过将图像中的像素分配到不同的区域或对象来实现图像分割的目的。相比于基于边缘或阈值的方法,基于区域…

“智慧赋能 强链塑链”—— 汽车行业供应链管理数字化应用探讨

01车企供应链数字化的必要性 汽车供应链是一个复杂的系统,很多汽车企业因为供应链管理不当,造成资源浪费、成本高、客户满意度低等一系列问题;而汽车行业规模技术门槛高、配合协同复杂的特性,决定了其供应链缺口无法在短时间内填…

结构体大小的计算

结构体计算要遵循字节对齐原则。 结构体默认的字节对齐一般满足三个准则: 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需…

【利用AI让知识体系化】7种结构型模式

文章目录 结构型模式简介适配器模式装饰器模式代理模式外观模式桥接模式组合模式享元模式 结构型模式 简介 在设计模式中,结构型模式用于描述如何将对象和类组装成较大的结构,并灵活地处理对象之间的关系。 结构型模式包括以下几种: 适配器…

opencv 图像识别

opencv的目标是使计算机可以快速准确地从数字图像中提取和分析特征。它使用了许多新的算法和技术,例如改进的模板匹配、基于统计的特征分析以及深度学习等。opencv支持多种平台,包括 Windows、 MacOS、 Linux和 Android,开发者可以使用 OpenC…

浏览器相关前端开发事项

文章目录 存储浏览器持久化存储(F12->应用->存储)浏览器缓存(F12->内存)浏览器存储管理单位(域名/IP为单位)区别localStorage VS 浏览器缓存localStorage VS cookies 存储 浏览器持久化存储&…

【CORS策略: Multiple CORS header ‘Access-Control-Allow-Origin‘ not allowed导致的跨域问题】

引起跨域CORS报错的原因有很多种!!!!! 这里我的报错属于最后一条。 探索的原因 正常axios请求接口,调试接口时出现以下问题 Access to XMLHttpRequest at http://192.168.31.111:9000/api/user/sessio…

皮卡丘../../(目录遍历)/敏感信息泄露/PHP反序列化

一.目录遍历 1.概述 在web功能设计中,很多时候我们会要将需要访问的文件定义成变量,从而让前端的功能便的更加灵活。 当用户发起一个前端的请求时,便会将请求的这个文件的值(比如文件名称)传递到后台,后台再执行其对应的文件。 在这个过程中…

【MySQL数据库 | 第四篇】SQL通用语法及分类

目录 🤔SQL通用语法: 😊语句: 😊注释: 🤔SQL语句分类: 😊1.DDL语句: 😊2.DML语句: 😊3.DQL语言: &…

C++STL库之map

文章目录 关于仿函数stackdeque(双端对列)queuepriority_queuemap(重点)set(去重) 关于仿函数 //C不能重载的运算符sizeof、 ::、 ? :、 .、 *、 class Add { public:int operator()(int a, int b)const{return a b;} }; //函数对象,仿函数…

2022年长三角高校数学建模竞赛C题隧道的升级改造与设计解题全过程文档及程序

2022年长三角高校数学建模竞赛 C题 隧道的升级改造与设计 原题再现: 某地现存一旧式双洞隧道,现计划将该隧道在旧貌基础上升级改造。在升级改造前,需进行定标与设计。考虑到该隧道洞壁附着特殊涂料,无人机在洞内通信信号较差&am…

LIBEVENT 框架

LIBEVENT 框架 LAMPlibevent特点:libevent的功能libevent官网安装步骤Linux下libevent主要API介绍libevent使用步骤libevent 编程案例LAMP 从LAMP说起: 是一个缩写,它指一组通常一起使用来运行动态网站或者服务器的自由软件 Linux - 操作系统Apache - 网页服务器MySQL - 数据…

基于Yolov5目标检测的物体分类识别及定位(一) -- 数据集原图获取与标注

从本篇博客正式开始深度学习项目的记录,实例代码只会放通用的代码,数据集和训练数据也是不会全部放出。 系列文章: 基于Yolov5目标检测的物体分类识别及定位(一) -- 数据集原图获取与标注 基于Yolov5目标检测的物体分类…

Data Distillation: A Survey

本文是蒸馏学习综述系列的第二篇文章,Data Distillation: A Survey的一个翻译 数据蒸馏:综述 摘要1 引言2 数据蒸馏框架2.1 元模型匹配的数据蒸馏2.2 梯度匹配的数据蒸馏2.3 轨迹匹配的数据蒸馏2.4 分布匹配的数据蒸馏2.5 因式分解的数据蒸馏 3 数据模态…

python中Requests发送json格式的post请求方法

问题:做requests请求时遇到如下报错: {“code”:“500”,“message”:"JSON parse error: Cannot construct instance of com.bang.erpapplication.domain.User (although at least one Creator exists): no String-argument constructor/factory …

16.2:岛屿数量问题

文章目录 岛屿数量问题方法一:采用递归的方法方法二:使用并查集的方法(map)方法三:使用并查集的方法(数组) 岛屿数量问题 测试链接:https://leetcode.com/problems/number-of-islan…