Maine

纵有疾风起,人生不言弃

菜鸟 OpenGL 入门 – 你好,三角形(一)

《菜鸟 OpenGL 入门 – 窗口(二)》 一节中,我们已经配置好了基本的 OpenGL 环境,现在已经有一个 OpenGL 窗口供我们接下来的学习了。
我们再学习每一门编程语言的时候,第一个程序往往都是一个 hello world,这似乎是编程界的惯例 (⊙﹏⊙)b,Hello world 程序往往都很简单,很容易理解,在学习 OpenGL 的时候,我们喜欢拿绘制一个三角形作为第一个程序,同样对于初学者而言,hello Triangle 程序的难度要比 hello world 大许多,因为在你成功输出一个图形之前,你必须先要了解很多图形相关的知识,这个过程对于初学者来说可能有一些困难,但请不要担心,只要你耐心的一步一步跟着接下来的文章走,文章结束的时候,你将学习到基本的 OpenGL 渲染流程,以及很多图形编程知识。

OpenGL 渲染管线

我们知道。在 OpenGL 中的任何事物都处于一个 3D 空间当中,而我们看到的屏幕却是一堆 2D 的像素,在这个过程当中,OpenGL 做的工作就是将 3D 数据转换为 2D 像素,这个过程又 OpenGL 的 图形渲染管线 处理的。我们来讨论一下 图形渲染管线 的具体流程。

下图描述了 OpenGL 图形渲染管线的流程。

OpenGL 图形渲染管线

如图,图形渲染管线接受一组3D坐标,最终转换成 2D 像素输出到屏幕上,图形渲染管线可以被划分为几个阶段,每个阶段将会把前一个阶段的输出作为输入。所有这些阶段都是高度专门化的(它们都有一个特定的函数),并且很容易并行执行。正是由于它们具有并行执行的特性,当今大多数显卡都有成千上万的小处理核心,它们在GPU上为每一个(渲染管线)阶段运行各自的小程序,从而在图形渲染管线中快速处理你的数据。这些小程序叫做 着色器 (Shader)。

有些着色器允许开发者自己配置,这就允许我们用自己写的着色器来替换默认的。这样我们就可以更细致地控制图形渲染管线中的特定部分了,而且因为它们运行在GPU上,所以它们可以给我们节约宝贵的CPU时间。OpenGL着色器是用OpenGL着色器语言(OpenGL Shading Language, GLSL)写成的,随后我们会花更多时间研究它。上图中,蓝色部分标注的使我们可以自定义着色器的地方,其中我们经常需要处理的就是 顶点着色器片段着色器

接下来,我们先概括介绍一下管线的每一部分。

下面介绍部分偏重于概念,提及到的概念如果不太理解,可以先 Pass 掉,但请牢牢记得我们提及的每一个概念的名字以及它的大概意思,等实践过后可以再回来细看看这些概念,以确保你真的理解了这些图像学知识。

顶点数据 – Vertex data

如果我们要渲染出来一个三角形,我们需要准备一个包含3个3D顶点的数组来标识,这个数组叫做 顶点数据 (Vertex data),顶点数据包含了一系列的顶点,在这个例子中是 3 个。每个顶点是一个 3D 坐标数据集合,也就是说,一个顶点不仅仅可以包含坐标信息,还可以包含额外的数据,比如我们可以为每一个顶点同时制定其颜色数据等,这些数据叫做 顶点属性

图元 – Primitive

我们已经传递给了管线一堆的数据,但管线又怎么知道怎么处理这些数据呢?比如上面我们传递了包含三个顶点的顶点数据给管线,我们想要得到一个填充的三角形,我们认为这是理所因当的,但对于管线来说,拿到这些数据,他也可以只给我们返回三个点而已,或者是三条线,这些都是有可能的,因此,我们需要给管线一些提示,告诉他我们的渲染类型,这些提示就是 图元,任何一个 OpenGL 的绘制函数都将把图元作为参数传递给OpenGL,其中几个图元是:GL_POINTSGL_TRIANGLESGL_LINE_STRIP

顶点着色器 – Vertex Shader

管线的第一部分是 顶点着色器,在这里,管线会将我们的顶点数据挨个作为输入。顶点着色器会对传递进来的每一个顶点进行处理,他的主要作用就是将我们传递的顶点坐标转化为 GLSL 所能识别的 3D 坐标类型,这个我们会在讨论顶点着色器的技术细节时详细说明。
另外,在这里,我们还可以对顶点数据做一些基本的处理,比如,我们想要对输入的坐标进行一些转换,就像常见的物体缩放,位移,旋转等,这些都是可以的,不过这些使我们后面要讨论的内容了。

图元装配 – Primitive Assembly

在这个阶段会把上个阶段(顶点着色器)输出的所有顶点作为输入,并装配为相应的图元形状,装配的依据就是 图元 部分介绍的,在调用 OpenGL 绘制函数的时候,我们传递的图元参数。如果是 GL_POINTS 将会按照点的形式去绘制,如果是 GL_TRIANGLES 将会绘制三角面。

几何着色器 – Geometry Shader

几何着色器把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。上图的例子中,它生成了另一个三角形。

光栅化阶段 – Rasterization Stage

这个阶段会把几何着色器的输出作为输入,他会把图元映射到屏幕像素上,并生成出供下一个阶段的 片段着色器 使用的 片段,同时,在执行片段着色器之前会执行一个裁剪的操作,将所有超出屏幕部分裁减掉,用于提升执行效率。

片段着色器 – Fragment Shader

片段着色器将光栅化输出的片段作为输入,片段着色器主要用于计算一个像素最终在屏幕上应该呈现出什么样的颜色,这里往往能够创造出非常令人惊讶的效果,片段着色器可以包含很多场景信息,比如:灯光,环境,阴影等等,用于制作出非常逼真的效果。

Alpha 测试 和 混合 – Test and Blending

最终的输出将会被传到最后一个阶段,叫做Alpha测试和混合 (Blending)阶段。这个阶段检测片段的对应的深度(和模板(Stencil))值(后面会讲),用它们来判断这个像素是其它物体的前面还是后面,决定是否应该丢弃。这个阶段也会检查alpha值(alpha值定义了一个物体的透明度)并对物体进行混合(Blend)。所以,即使在片段着色器中计算出来了一个像素输出的颜色,在渲染多个三角形的时候最后的像素颜色也可能完全不同。

看到这里,相信大家对 OpenGL 的管线基本流程应该有一个了解了,什么?还是一脸懵 😳?没关系,再看一遍就好了,实在不行,继续走吧,写写代码回来再看可能就清楚了。

之所以我们再开始编程之前要介绍这么多图形学的概念,是因为在现代OpenGL中,我们必须定义至少一个顶点着色器和一个片段着色器(因为GPU中没有默认的顶点/片段着色器),另外,在编程过程中,我们会不断的提及到上述的很多概念,以及整个流程。所以,在我们真的开始写代码之前,我们必须对这些概念起码有一个轮廓的印象,才能更加深刻的理解接下来我们写的代码。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注