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

news2024/11/27 4:01:57
前言
本篇在讲什么

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.coloradmin.cn/o/598385.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CI/CD:如何使用 GitLab 执行 SpringBoot 前后端分离项目的持续集成与持续交付(持续部署)?

一、GitLab Runner 安装 官网各系统 & 各方式安装说明:https://docs.gitlab.com/runner/install/ 本文基于阿里云 CentOS 安装 GitLab Runner (Linux Shell 方式,非 Docker 方式) 1.1 GitLab Runner 介绍 GitLab Runner 是…

GPT面试知识点

0.GPT的模型结构 GPT是一个基于Transformer的生成式预训练模型。使用Transformer中的解码器部分 它由一系列的模块化的Transformer Blocks组成。每一个Block包含一个多头自注意力机制(Multi-Head Self-Attention mechanism)以及一个位置前馈网络(position-wise feedforward n…

Redis - 原理篇

✨作者:猫十二懿 ❤️‍🔥账号:CSDN 、掘金 、个人博客 、Github、语雀 🎉公众号:猫十二懿 Redis(原理篇) 一、数据结构 1.1 动态字符串SDS 我们都知道Redis中保存的Key是字符串,value往往是字符串或者字…

Spring Boot如何实现分布式锁的自动释放

Spring Boot如何实现分布式锁的自动释放 在分布式系统中,为了保证数据的一致性和可靠性,常常需要使用分布式锁。在实际开发中,我们可以使用 Redis、Zookeeper 等分布式系统来实现分布式锁。本文将介绍如何使用 Spring Boot 来实现分布式锁的…

Android Input子系统 - kernel

目录 前言 数据结构 输入子系统流程 前言 上一节有展示Android Input子系统的架构图,这里我们关心Linux kernel层 可以看到kernel层分为三层: 输入子系统设备驱动:处理与硬件相关的信息,调用input API注册输入设备,并把数据往上报 输入子系统核心层:为事件处理层和设…

关于QGroundControl的软件架构的理解

首先QGC是基于QT平台开发,个人理解软件架构即为项目前后端结构,以及前后端数据交互的逻辑。下面是对QGroundControl源码的一些个人理解,写这个博客只是为了记录下来,防止时间久了忘记,过程中看了一些大佬的博客来帮助理…

服务运营 |摘要: Healthcare Management Science 近期论文汇总

推文作者:李舒湉 罗毓灵 编者按 Healthcare Management Science 近期论文汇总 Healthcare Management Science 论文精选(三月下) 1Monitoring policy in the context of preventive treatment of cardiovascular disease https://link.sprin…

SQL——视图检查选项 local

create table stue ( id int auto_increment primary key comment 客户编号, name varchar(20) comment 客户名称, mima varchar(100) comment客户密码 , phonr varchar(20) comment 客户电话, xb char(2) …

【目录】《电路》上下、《电力电子学》、《数字电路》

1、知乎----作为电力电子专业的学生,有哪些专业书籍值得反复阅读? 一门课 / 一本书 经不经典,直接去 中国大学MOOC 上搜一搜就知道了 《电路》 电路主要讲:电压、电阻、电容的一些计算公式 《电力电子学》 https://www.zhih…

Hexo 搭建博客并推送GitHub

初始Hexo npm install hexo-cli -g hexo init blog cd blog npm install hexo server浏览器访问:http://localhost:4000/ 设置GitHub 1、首先要注册一个Github账号,新建一个name.github.io的仓库,也就是new repository。 因为博主之前创建…

Sui主网升级至V1.2.0版本

升级要点 [API行为调整] — 因rpc方法导致的UserInputError、 SuiRpcInputError、SuiError::TransactionNotFound以及SuiError::TransactionsNotFound报错,现在返回错误代码为32602,取代了32000。此信息已在#11833 #11928中更正。 修复了get_coin_meta…

Python实战基础18-文件操作

1、文件的打开和关闭 1.1 操作文件的整体过程 打开文件,或者新建立一个文件读/写数据关闭文件 1.2 打开文件 在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件。 open(文件路径,访问模式) …

【教程】在 Visual Studio 2015 上对 C++ 进行单元测试

更新中 目录 前言环境Visual Studio 2015 提供的单元测试工具创建 C 测试框架在测试项目内测试一个函数测试另一个 Project 的函数参考 前言 本文的测试环境是 Visual Studio 2015,高级别版本(如,2017,2022)的操作略有…

SpringBoot + 规则引擎 URule,太强了!

一、背景 前段时间,在做项目重构的时候,遇到很多地方需要做很多的条件判断。当然可以用很多的if-else判断去解决,但是当时也不清楚怎么回事,就想玩点别的。于是乎,就去调研了规则引擎。 当然,市面上有很多…

[unity]如何并行for循环

序 并行for循环 计算着色器里可以弄,但是那个得先了解一堆api,比如什么setBuffer unity 的 job system好像也可以弄,但是那个也得先了解一堆api 这些都是大而全的,有没有那种,没那么神通广大但是比较容易上手的&am…

【CocosCreator入门】CocosCreator组件 | TiledTile(地图块)组件

📢博客主页:肩匣与橘📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢本文由肩匣与橘编写,首发于CSDN🙉📢生活依旧是美好而又温柔的,你也是✨ …

HIve技术详解(一)

第1章 Hive基本概念 1.1 Hive 1.1.1 Hive的产生背景 在那一年的大数据开源社区,我们有了HDFS来存储海量数据、MapReduce来对海量数据进行分布式并行计算、Yarn来实现资源管理和作业调度。但是面对海量数据和负责的业务逻辑,开发人员要编写MR来对数据进…

3.3 最长公共子序列

博主简介:一个爱打游戏的计算机专业学生博主主页: 夏驰和徐策所属专栏:算法设计与分析 1.什么是子序列? 我的理解: 在字符串或序列中,子序列是指从原始序列中删除零个或多个元素后得到的序列,…

Spring Boot如何实现分布式事务的协调和管理

Spring Boot如何实现分布式事务的协调和管理 在分布式系统中,事务是非常重要的一部分,可以保证多个操作在一个原子性的操作中完成,确保数据的一致性和可靠性。在分布式系统中,分布式事务需要考虑多个服务之间的数据一致性和事务提…

论文排版!

目录 Visio画图后,粘贴到word白边太宽? 【IEEE论文投稿word中双栏情况下插入单栏效果图片】 论文排版之Word双栏排版问题解决 Word公式居中,公式序号靠右(制表位实现) 请问word如何实现这种长公式的排版&#xff1…