OpenGL-曲面细分

曲面细分名词

TCS(细分控制着色器)

Tessellation control shader细分控制着色器
TCS 着色器获取由顶点处理器处理之后的数据
顶点在经过顶点着色器后 在顶点着色器中通过gl_Position = pos;输出 接着就会将这些顶点按照数组gl_in[]的方式传递给细分控制着色器(也就是说在细分控制着色器中 可以调用gl_in[]数组来获取从顶点着色器传入的顶点)而gl_in[]的大小 也就是多少个顶点算一组(gl_in[0],gl_in[1]…具体到gl_in[x]之后从gl_in[0]重新开始)由glPatchParameteri(GL_PATCH_VERTICES, 3);决定 现在就是gl_in[2]是最大的

并输出 patch

除此之外它也会产生 TLs

TES(细分曲面计算着色器)

Tessellation EValuation shader
在这里插入图片描述
输入为 质心坐标
输出为 顶点
每次调用只能生成一个顶点 不能丢弃顶点

TES的作用

TES 着色器的主要目的就是借助于 PG 阶段生成的坐标来生成曲面

将质心坐标变换到表示曲面的多项式中并计算出最终结果。结果就是新的顶点的位置
在 TES 着色器执行之后,产生的新的顶点会被作为三角形传递到渲染管线的下一阶段
所有生成的位于这个特定空间下的位置都会经过 TES 着色器进行处理

tes的偏移纹理实际上就是高度纹理,它记录了颜色纹理中每个像素在所在位置的高度信息。我们将会使用高度纹理在我们的网格模型的表面上产生起伏的状态。除此之外,TES 也可以访问 TCS 着色器的输出 patch。最后我们声明输出的顶点的属性。需要注意的是默认数组并没有在这里

控制点

在这里插入图片描述
这些被称为控制点的顶点定义了一个曲面

patch

一组顶点被称为一个patch
由glPatchParameteri(GL_PATCH_VERTICES, 3);设置多少个顶点为一个patch 这里为三个顶点组成一个patch
每一个patch执行一次细分计算着色器 也就是 假设我们是三个顶点为一组patch 那么顶点依次经过顶点着色器 传入细分控制着色器 但是并不会像流水线一样 顶点从顶点着色器传入细分控制着色器时 立即执行细分控制着色器 然后从细分控制器传出 而是等待三个顶点都从顶点着色器传入时才执行细分控制着色器再传出 此时这三个顶点组成一个patch 从控制着色器传出
在这里插入图片描述
上图为 绘制了6个点 但是一个patch是三个点组成
每个输出 patch,我们可以有不同的 TLs 值

TLs(曲面细分精细程度)

gl_TessLevelOuter [0] gl_in[0]顶点对应的那个边有多少个新生成的顶点数量
gl_TessLevelInner[0] 确定三角形中将会包含多少个圈
在三角域里面我们只需要使用 gl_TessLevelOuter 数组的前三个成员以及 gl_TessLevelInner 数组的第一个成员
在矩形域中 gl_TessLevelInner[0]是横 gl_TessLevelInner[1]是竖

例子

int TL = 3;
    //设置细分程度
    gl_TessLevelOuter[0] = 5; 
    gl_TessLevelOuter[1] = TL;
    gl_TessLevelOuter[2] = TL;
    //gl_TessLevelOuter[3] = TL;
    gl_TessLevelInner[0] = TL; 
    //gl_TessLevelInner[1] = TL;

在这里插入图片描述

固定功能阶段为图元生成(PG)

实际上就是这个部分进行设置 然后生成新的点

layout(Triangles,equal_spacing,ccw) in;

PG 借助于 TLs 中的信息并在此基础上在三角形内部生成一系列的点。每个点都是由这个三角形的质心坐标系确定的
在一般情况下 TLs 告诉 PG 三角形边上的线段的数量,并且一环一环的绕着三角形的中心来构造三角形

PG 阶段通过获取从 TCS 着色器中传入的 TLS(细分层级)以及其输出的拓扑结构,PG 会生成这个空间下的顶点信息和其生成的顶点的连通性;

图元生成器

将从细分控制着色器传进来的patch创建一组新的图元。
图元生成器计算不同数量的细分曲面程度并应用不同的细分曲面算法。每个所生成的顶点在一个抽象patch内具有一个规格化的位置(即,坐标范围在[0, 1]之内)。这个位置具有两个或三个分量,依赖于patch的类型。这些坐标通过内建的in vec3 gl_TessCoord;
输入提供给细分曲面计算着色器。

图元生成:

  1. 不受细分曲面控制着色器中用户定义的输出影响(或当没有细分曲面控制着色器时,也不受顶点着色器的影响)
  2. 不受细分曲面控制着色器的输出patch大小影响,
  3. 不受任一每个patch的细分曲面控制着色器输出的影响,
  4. 只受细分曲面程度的影响。
  5. 细分曲面阶段的图元生成部分完全对实际的顶点坐标与其它patch数据是不可见的。

图元生成系统的目的:

  1. 确定要生成多少个顶点
  2. 用哪个次序来生成它们
  3. 用哪种图元来构造它们。
    实际为这些顶点的每个顶点的数据,诸如位置、颜色等等,是通过细分曲面计算着色器来生成的,基于图元生成器所提供的信息。

总结着色器的作用

顶点着色器

网格顶点经过顶点着色器处理之后得到了世界坐标系下的位置、法线

细分曲面着色器

细分曲面过程并不对OpenGL典型的几何图元(点、线和三角形)进行操作,而是使用一个新的图元patch

如果企图渲染一个patch而没有任何细分曲面着色器(明确地说是一个细分曲面计算着色器;我们会看到细分曲面控制着色器是可选的),那么将也会得到一个GL_INVALID_OPERATION错误

TCS着色器

TCS 将每个三角形作为一个带三个控制点的 patch 并直接将其传递到 TES 中

gl_in中的元素个数与由glPatchParameteri()所指定的patch大小相同。在一个细分曲面着色器内部
变量gl_PatchVerticesIn提供了gl_in中的元素个数(就好比使用sizeof(gl_in) / sizeof(gl_in[0])进行查询)。

glPatchParameteri()设置了gl_in数组的数组大小

layout (vertices = 16) out;的作用

1.设置了gl_out数组的数组大小 设置输出patch顶点的个数为16
2.指定了细分曲面控制着色器将被执行多少次:对每个输出patch顶点执行一次。

gl_InvocationID变量

确定正在处理哪个输出顶点 该变量作为gl_out数组的一个索引

工作流程

生成细分曲面输出patch顶点,传递到细分曲面计算着色器,以及更新任一每个顶点的,或每个patch的属性值,若有必要的话。

指定细分曲面程度因子,控制图元生成器的操作。这些是特殊的细分曲面控制着色器变量,称为gl_TessLevelInner和gl_TessLevelOuter,并在细分曲面控制着色器中隐式声明。

TES着色器

PG 将一个等边三角形细分成多个小三角形并且为每个新产生的顶点都执行 TES 着色器
在每次的 TES 调用中,我们都可以访问顶点的质心坐标

对图元生成器发射的每个细分曲面坐标逐个执行,并负责确定从细分曲面坐标所得到的顶点的位置

layout(points, equal_spacing, ccw) in;

  1. Triangles 这是 PG 的工作域,其他两个选项是 quads 和 isolines;
    point_mode也可以生成点 迫使细分曲面的生成作为一系列的点
    ・ quads——单位正方形中的一个矩形域;域坐标:带有范围在[0, 1]内的u, v值的一个个坐标对(u, v)。
    ・ triangles——使用重心坐标的一个三角形域;域坐标:带有范围在[0, 1]内的a、b、c三个值的坐标(a, b, c),这里a+b+c=1。
    ・ isolines——跨单位正方形的一组线;域坐标:u值范围在[0, 1],v值范围在[0, 1)范围的(u, v)坐标对。

point_mode也可以生成点 迫使细分曲面的生成作为一系列的点
layout (triangles, equal_spacing, ccw, point_mode) in;

  1. equal_spacing 意味着三角形的边缘会被细分成等分的线段(根据 TLs)。你也可以使用 fractional_even_spacing 或者 fractional_odd_spacing 使得在线段长度上获得更加平滑的过渡,不论 TL 值是一个奇数整数还是一个偶数整数。例如,如果你使用 fractional_odd_spacing 并且 TL 值为 5.1,这意味着会有两个非常短的线段和 5 个比较长的线段。随着 TL 值增加到 7,所有线段的长度会变得十分接近。当 TL 值达到7,两个新的十分短的线段会被创建出来。fractional_even_spacing在处理偶数TL值时也是一样;
    ・ equal_spacing——细分曲面程度被裁减到[1, max]范围内,然后取整到下一个最大整数值。
    ・ fractional_even_spacing——值被裁减到[2, max]范围内,然后取整到下一个最大偶整数值n。边然后被划分为n-2条等长部分,以及两个剩余部分,每个在一端,剩余部分长度可能比其它长度要短。
    ・ fractional_odd_spacing——值被裁减到[1, max-1]范围内,然后取整到下一个最大奇整数值n。边然后被划分为n-2条等长部分,以及两个剩余部分,每个在一端,剩余部分长度可能比其它长度要短。

  2. ccw 意味着 PG 中输出的三角形会按照逆时针顺序(你同样可以使用 cw 将其设定为顺时针顺序)。你也许会想,在顺时针为正面的情况下为什么我们还要将其设置为逆时针方向。这是因为在这一节中我使用的模型( quad2.obj )是用 Blender 按照逆时针顺序生成的,我本应该在导入模型的时候将 Assimp 标志设置为 ‘aiProcess_FlipWindingOrder’ 这样在这里我们就能使用 cw 。我现在只是不想去修改 mesh.cpp 中的内容,底线就是无论你做什么,都要保证他们始终是一致的。

函数

glPatchParameteri(GLenum pname, GLint value)

使用value来指定一个patch中的顶点个数。pname必须设置为GL_PATCH_VERTICES。

  • 如果value小于零或大于GL_MAX_PATCH_VERTICES,将会产一个GL_INVALID_ENUM的错误。
  • 一个patch的默认顶点个数是三。如果一个patch的顶点个数小于参数value值,那么该patch将被忽略,从而不会有几何图形产生。

glPatchParameterfv(GLenum pname, const GLfloat *values);

当没有细分曲面控制着色器时,设置内部与外部细分曲面程度。

  • 参数pname要么是GL_PATCH_DEFAULT_OUTER_LEVEL,要么是GL_PATCH_DEFAULT_INNER_LEVEL。
  • 当pname是GL_PATCH_DEFAULT_OUTER_LEVEL时,参数values必须是含有四个单精度浮点值的数组,指定四个外部细分曲面程度。
  • 类似地,当pname是GL_PATCH_DEFAULT_INNER_LEVEL时,values必须是含有两个单精度浮点值的数组,指定两个内部细分曲面程度。

barrier()(GLSL内置函数)

该函数使得对于一个输入patch的所有控制着色器执行并等待所有这些着色器的执行到达那个函数的调用点,从而确保了可能要设置的所有数据值将被计算。
因为一个细分曲面控制着色器在执行时,它具有对所有patch顶点数据的访问,包括输入顶点和输出顶点。这可能会导致发射一次着色器调用,该调用需要使用来自另一个着色器调用的数据值,但是那个着色器调用尚未发生

gl_in数组实质

in gl_PerVertex {
    vec4 gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];

}gl_in[gl_PatchVerticesIn];

GLSL内置变量

gl_InvocationID:当前细分曲面着色器的输出顶点的调用索引 就是在一组patch中 这是第几个顶点

gl_PrimitiveID:当前输入patch的图元索引 也就是 这是第几个patch

gl_PatchVerticesIn:输入patch中的顶点个数,它作为gl_in数组变量中的元素个数
gl_TessLevelOuter[0]: 用于确定三角形每个边线上的线段的数量

gl_TessLevelInner[0] 确定三角形中将会包含多少个圈
在三角域里面我们只需要使用 gl_TessLevelOuter 数组的前三个成员以及 gl_TessLevelInner 数组的第一个成员

gl_PatchVerticesOut:输出patch中的顶点个数,它作为gl_out数组变量中的元素个数

gl_TessCoord:作为权值在二维向量和三维向量之间插值 有三个分量 代表与图元细分相关的被处理顶点的位置

流程

第一步是先把顶点传入顶点着色器
然后将顶点着色器中的顶点传入TCS着色器
在程序中通过glPatchParameteri设置组成patch的顶点数量
在TCS着色器中通过layout(vertices = 4) out; 设置传出patch的顶点数量
在TCS着色器中设置细分等级和细分程度
那传入TCS的目的是什么 1.设置细分程度 因为在这里可以计算摄像机和控制点的距离(控制点实际上就是从顶点着色器传进来的点)
2.将所有顶点分成patch
在TES着色器中获取从TCS传入的patch数组

TES的目的是什么 设置PG 这个PG应该会自己对整个曲面进行细分 但是获取不到相应的点

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值