Demo演示
几何着色器
几何Geometry glsl 发生在什么阶段?
-
图形渲染管线:
- 顶点数据——顶点着色器阶段——图元装配;(Geometry glsl )——光栅化阶段——裁切——片段着色器——测试和混合
- 可选的Geometry几何着色器(非必要)
- Geometry作用:对顶点数据随意更改,它能够变换为完全不同的图元,并且还能生成比原来更多的顶点。
在geometry glsl中:
-
输入图元值:
- (()内表示:一个图元所包含的最小顶点数)
-
指定输入:
- 需要声明从顶点着色器输入的图元类型:in关键字前声明一个布局修饰符,这个输入布局修饰符
- 输出图元值:
points
,line_strip
,triangle_strip
- 指定输出:
- 我们还需要指定几何着色器输出的图元类型,这需要在out关键字前面加一个布局修饰符 && 并设置一个它最大能够输出的顶点数量
理解指定输入输出图元值:
- 顶点数据是一系列顶点的集合,指定了输入图元值,决定多少个顶点作为一组输入(对顶点数据分组)
- 将这每组输入,几何变换为新的图元形状
in out:
- 将 vertex着色器阶段的输出out:gl_Position,gl_PointSize,gl_ClipDistance[];,作为geometry glsl的输入in:
- 接口块(Interface Block)类似struct,in / out + 块名(不同glsl中需要一致){……}实例名(不同glsl中无需一致)
- 定义一个接口块数组【】进行vertex和geometry之间的传输:
- (大多数的输入渲染图元包含多于1个的顶点,而几何着色器的输入是一个图元的所有顶点。)
- 为什么用接口快,不用普通的in/out?
- 输入图元作为数组【】,如果不用接口块,其实要写为in type name[],这种形式,接口块会更容易处理一点
如何访问输入图元的指定顶点:
- 实例名[0 / 1/ 2……]:一组输入图元中,第0/1/2……顶点
- 几何着色器中的fun函数:几何着色器至少生成一个输出图元
- EmitVertex发射顶点:调用时,会被添加到图元中来
- EndPrimitive结束:合成为指定的输出渲染图元
- glDrawArrays()中渲染的图元模式mode如何确定?
- 根据geometry中in的图元值就行,因为你是将这个图元值的顶点数作为一组绘制,至于geometry如何变换,不在mode的考虑中。
Geometry glsl作用:
- 图元形状是在GPU动态生成的,这会比在顶点缓冲中手动定义(大量的顶点数据)图形要高效很多。(例如仅传入一个顶点,可以动态生成多个顶点)
- 限制:
- 所有图元(绘制逻辑同时影响每个图元)都做重复的事情,无法改变
- geometry glsl对简单而且经常重复的形状来说是一个很好的优化工具(比如粒子,每个粒子顶点,都变换为如圆点、小箭头或星形的新图元)
理解向量:
-
向量是什么?
-
向量是一个抽象的概念,涉及一系列简单 /复杂的 公式定义
- 抽象概念:
- 被映射到 抽象(物理,渲染,数学……) / 具体(实际生活),从而解决实际的需求。
- 向量公式:
- 向量定义:在抽象3D空间中,向量近似箭头(长度+方向),当对箭头平移时,长度+方向都不会改变。世界中心映射为向量起点,顶点坐标的位置映射为向量的终点,
- 向量加减:可以改变物体到新的位置,也可以计算两个位置相对方向 / 距离……
- 应用:三角形表面的线根据向量相减求得:已知三个顶点坐标(向量),带入可得坐标间的连线(注意获得的新箭头方向,箭头终点坐标 - 箭头起点坐标)
- 向量叉乘:获取垂直于其它两个向量的一个向量
- 求法线:三角形表面的线映射为叉乘需要的两个向量,法线映射为叉乘的结果
- 向量归一化:获得长度为1,方向不变的向量
- 应用:对法线归一化,只关系方向,不关心长度
- 向量*标量:对向量本身操作,改变方向 / 大小
demo演示
实际应用:
- 顶点着色器处理的是单个顶点的位置计算,而几何着色器处理的是整个图元,可以对例如三角形图元操作,
-
爆破物体:
- 计算每个三角形(因为要以图元形式爆破)图元的法线(非顶点法线,顶点法线可以由vertex得到):归一化(向量相减 + 叉乘)
- 对于每个三角形的3个顶点,都沿着法线方向随glfwGetTime()移动移动:向量相乘 + 向量相加
Demo演示
-
法线可视化:
- 首先不使用几何着色器正常绘制场景,正常渲染所有顶点
- 再次绘制场景,但这次只显示通过几何着色器生成法向量(每个顶点一个法向量line_strip),
- 我们需要每个顶点 的法线:为了适配(观察和模型矩阵的)缩放和旋转,获取归一化的法线(这回已经是正确的方向了。
mat3 normalMatrix = mat3(transpose(inverse(view * model)));//计算法线矩阵
vs_out.normal = normalize(vec3(vec4(normalMatrix * aNormal, 0.0)));//将法线变换到正确方向