OpenGL学习笔记(十三)

OpenGL 高级篇(四)

1.几何着色器基础

在顶点和片段着色器之间有一个可选的着色器,叫做几何着色器(Geometry Shader)。几何着色器以一个或多个表示为一个单独基本图形(primitive)的顶点作为输入,比如可以是一个点或者三角形。几何着色器在将这些顶点发送到下一个着色阶段之前,可以将这些顶点转变为它认为合适的内容。几何着色器有意思的地方在于它可以把(一个或多个)顶点转变为完全不同基本图形(primitive),从而生成比原来多得多的顶点。
直接用一个例子深入了解一下:
在这里插入图片描述
每个几何着色器开始位置需要声明输入的基本图形(primitive)类型,这个输入是从顶点着色器中接收到的。在in关键字前面声明一个layout标识符。这个输入layout修饰符可以从一个顶点着色器接收以下基本图形值:
在这里插入图片描述
这是能够给渲染函数的几乎所有的基本图形。如果选择以GL_TRIANGLES绘制顶点,要把输入修饰符设置为triangles。括号里的数字代表一个基本图形所能包含的最少的顶点数。
当需要指定一个几何着色器所输出的基本图形类型时,就在out关键字前面加一个layout修饰符。和输入layout标识符一样,输出的layout标识符也可以接受以下基本图形值:

  • points
  • line_strip
  • triangle_strip

使用这3个输出修饰符可以从输入的基本图形创建任何想要的形状。为了生成一个三角形,定义一个triangle_strip作为输出,然后输出3个顶点。
几何着色器同时希望设置一个它能输出的顶点数量的最大值(如果超出了这个数值,OpenGL就会忽略剩下的顶点),可以在out关键字的layout标识符上做这件事。在这个特殊的情况中,将使用最大值为2个顶点,来输出一个line_strip。
这种情况,会奇怪什么是线条:一个线条是把多个点链接起来表示出一个连续的线,它最少有两个点来组成。每个后一个点在前一个新渲染的点后面渲染,可以看看下面的图,其中包含5个顶点:
在这里插入图片描述
为生成更有意义的结果,需要某种方式从前一个着色阶段获得输出。GLSL提供了一个内建变量,它叫做gl_in,它的内部看起来像这样:
in gl_Vertex
{
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_in[];

要注意的是,它被声明为一个数组,因为大多数渲染基本图形由一个以上顶点组成,几何着色器接收一个基本图形的所有顶点作为它的输入。
使用前一个顶点着色阶段的顶点数据,就可以开始生成新的数据了,这是通过2个几何着色器函数EmitVertex和EndPrimitive来完成的。几何着色器需要去生成 / 输出至少一个你定义为输出的基本图形。在例子里打算至少生成一个线条(line strip)基本图形。
在这里插入图片描述
该例子里,发射了两个顶点,它们被从顶点原来的位置平移了一段距离,然后调用EndPrimitive将这两个顶点结合为一个单独的有两个顶点的线条。
这个几何着色器接收一个基本图形——点,作为它的输入,使用输入点作为它的中心,创建了一个水平线基本图形。如果渲染它,结果就会像这样:
在这里插入图片描述

2.使用几何着色器

为了展示几何着色器的使用,将渲染一个简单的场景,在场景中只绘制4个点,这4个点在标准化设备坐标的z平面上。这些点的坐标是:
在这里插入图片描述
顶点着色器只在z平面绘制点,所以只需要一个基本顶点着色器:
在这里插入图片描述
会简单地为所有点输出绿色,直接在片段着色器里进行硬编码:
在这里插入图片描述
为点的顶点生成一个VAO和VBO,然后使用glDrawArrays进行绘制:
在这里插入图片描述
运行:在黑色场景中有四个绿点
在这里插入图片描述
创建一个叫pass - through的几何着色器,它用一个point基本图形作为它的输入,并把它无修改地传到下一个着色器。
在这里插入图片描述
这个几何着色器应该很容易理解。它简单地将它接收到的输入的无修改的顶点位置发射出去,然后生成一个point基本图形。
一个几何着色器需要像顶点和片段着色器一样被编译和链接,但是这次将使用GL_GEOMETRY_SHADER作为着色器的类型来创建这个着色器:
在这里插入图片描述
编译着色器的代码和顶点、片段着色器的基本一样。要记得检查编译和链接错误!
运行:在黑色场景中有四个绿点
直观感觉和没使用几何着色器一样!但是事实上,仍能绘制证明几何着色器工作了的点
在这里插入图片描述

3.绘制几个房子

将在每个点上使用几何着色器绘制一个房子。可以通过把几何着色器的输出设置为triangle_strip来达到这个目的,总共要绘制3个三角形:两个用来组成方形和另表示一个屋顶。
在这里插入图片描述
在OpenGL中三角形带(triangle strip)绘制起来更高效,因为它所使用的顶点更少。第一个三角形绘制完以后,每个后续的顶点会生成一个毗连前一个三角形的新三角形:每3个毗连的顶点都能构成一个三角形。若有6个顶点,它们以三角形带的方式组合起来,会得到这些三角形:(1, 2, 3)、(2, 3, 4)、(3, 4, 5)、(4, 5, 6) 因此总共可以表示出4个三角形。一个三角形带至少要用3个顶点才行,它能生曾N - 2个三角形;6个顶点我们就能创建6 - 2 = 4个三角形。
在这里插入图片描述
使用一个三角形带作为一个几何着色器的输出,可以轻松创建房子的形状,只要以正确的顺序来生成3个毗连的三角形。下面的图像显示,需要以何种顺序来绘制点,才能获得需要的三角形,图上的蓝点代表输入点:
在这里插入图片描述
这个几何着色器生成5个顶点,每个顶点是点(point)的位置加上一个偏移量,来组成一个大三角形带。接着最后的基本图形被像素化,片段着色器处理整三角形带,结果是绘制的每个点生成一个绿房子:
在这里插入图片描述
可以看到,每个房子实则是由3个三角形组成,都是仅仅使用空间中一点来绘制的。绿房子看起来还是不够漂亮,所以再给每个房子加一个不同的颜色。将在顶点着色器中为每个顶点增加一个额外的代表颜色信息的顶点属性。
下面是更新了的顶点数据:
在这里插入图片描述
然后更新顶点着色器,使用一个接口块来项几何着色器发送颜色属性:
在这里插入图片描述
接着还需要在几何着色器中声明同样的接口块(使用一个不同的接口名):
在这里插入图片描述
因为几何着色器把多个顶点作为它的输入,从顶点着色器来的输入数据总是被以数组的形式表示出来,即使现在只有一个顶点。
注意:不是必须使用接口块来把数据发送到几何着色器中。还可以这么写:

in vec3 vColor[];

如果顶点着色器发送的颜色向量是out vec3 vColor那么接口块就会在比如几何着色器这样的着色器中更轻松地完成工作。事实上,几何着色器的输入可以非常大,把它们组成一个大的接口块数组会更有意义。
然后还要为下一个像素着色阶段声明一个输出颜色向量:

out vec3 fColor;

因为片段着色器只需要一个(已进行了插值的)颜色,传送多个颜色没有意义。fColor向量这样就不是一个数组,而是一个单一的向量。当发射一个顶点时,为了它的片段着色器运行,每个顶点都会储存最后在fColor中储存的值。
对于这些房子来说,可以在第一个顶点被添加,对整个房子上色前,只使用来自顶点着色器的颜色填充fColor一次:
在这里插入图片描述
运行:所有的分房子便都有了自己的颜色
在这里插入图片描述
可以稍微改变一下,给最后一个顶点定义白色,就像在屋顶上落了一些雪。
在这里插入图片描述
运行:所有的分房子便都有了自己的颜色,且屋顶有一点白色
在这里插入图片描述

4.爆破物体

前面学习了绘制房子,现在学习撬起物体缺口,形成爆炸式物体!虽然这个也不会经常用到,但是它能向你展示一些几何着色器的强大之处。
当说对一个物体进行爆破(Explode)的时候并不是说将要把之前的那堆顶点炸掉,但是打算把每个三角形沿着它们的法线向量移动一小段距离。效果是整个物体上的三角形看起来就像沿着它们的法线向量爆炸了一样。
纳米服上的三角形的爆炸式效果看起来如下图所示:
这样一个几何着色器效果的一大好处是,它可以用到任何物体上,无论它们多复杂。
在这里插入图片描述
因为打算沿着三角形的法线向量移动三角形的每个顶点,则需要先计算它的法线向量
首先计算出一个向量,它垂直于三角形的表面,使用这三个得到的顶点就能做到。使用叉乘获取一个垂直于两个其他向量的向量。
下面的几何着色器函数做的正是这件事,它使用3个输入顶点坐标获取法线向量:
在这里插入图片描述
这里使用减法获取了两个向量a和b,它们平行于三角形的表面。两个向量相减得到一个两个向量的差值,由于所有3个点都在三角形平面上,任何向量相减都会得到一个平行于平面的向量。一定要注意,如果调换了a和b的叉乘顺序,得到的法线向量就会使反的,顺序很重要!
在这里插入图片描述
知道了如何计算法线向量,就能创建一个explode函数,函数返回的是一个新向量,它把位置向量沿着法线向量方向平移:
在这里插入图片描述
爆炸效果的完整的几何着色器如下图所示,它使用模型加载器,绘制出一个模型:
在这里插入图片描述
注意同样在发射一个顶点前输出了合适的纹理坐标。
也不要忘记在OpenGL代码中设置time变量:
在这里插入图片描述
最后的结果是一个随着时间持续不断地爆炸的3D模型(不断爆炸不断回到正常状态)。

显示法向量

思路是这样的:先不用几何着色器,正常绘制场景,然后再次绘制一遍场景,但这次只显示通过几何着色器生成的法线向量。几何着色器把一个三角形基本图形作为输入类型,用它们生成3条和法线向量同向的线段,每个顶点一条。伪代码应该是这样的:

shader.Use();
DrawScene();
normalDisplayShader.Use();
DrawScene();

这次会创建一个使用模型提供的顶点法线,而不是自己去生成。为了适应缩放和旋转会在把它变换到裁切空间坐标前,使用法线矩阵来法线(几何着色器用他的位置向量做为裁切空间坐标,所以还要把法线向量变换到同一个空间)。
在这里插入图片描述
在这里插入图片描述
由于把法线显示出来通常用于调试的目的,可以在片段着色器的帮助下把它们显示为单色的线。
在这里插入图片描述

  • 先使用普通着色器来渲染你的模型,
  • 然后使用特制的法线可视着色器,会看到这样的效果:
  • 它给了一种非常有效的检查一个模型的法线向量是否有错误的方式。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42050609/article/details/125219291