OpenGL

2017-09-12  本文已影响24人  rogerwu1228

1, OpenGL 编程模型

2, 管线流程(重点,每一个细节都要讲清楚)

渲染流水线,就是一系列有序的处理阶段的序列,用于把我们应用中的数据转化到OpenGL生成一个最终的图像。下图是OpenGL4.3使用的流水线。

Snip20170918_1.png

上图中,蓝色的方块表示是可编程的shader阶段。
OpenGL从我们提供的几何数据(顶点和几何图元)出发,首先使用了一系列shader阶段来处理它:vertex shading,tessellation shading(它本身就包含了两种shaders),接着是geometry shading,然后再传递给光栅化程序(rasterizer);光栅化程序将会为每个在裁剪区域(clipping region)内部的图元生成fragments,然后再为每个fragment执行一个fragment shader。
如你所见,shaders真是无处不在啊!不是所有的阶段都是需要的。如上面所说,只有vertex和fragment shaders是我们必须实现的。Tessellation和geometry shaders都是可选的。
下面,我们对每个阶段进行更深入地解释。下面的内容难度系数五颗星(对新手。)!但是,请坚持看下去!它们很重要!

准备顶点数组数据(vertex array data)
即进行顶点规格定义。应用将会建立一个有序的顶点列表,然后发送给OpenGL。这些顶点定义了图元的边界。图元是基本的绘制形状,如点、线、三角形。这些顶点列表是如何被组织成一个个图元的会在后面的阶段里进行处理。
这个阶段会处理一些顶点数组对象(Vertex Array Objects)顶点缓存对象(Vertex Buffer Objects)。VAO定义了每个顶点包含的信息,而VBO则是顶点本身的数据所在。
一个顶点的数据就是一系列顶点属性(vertex attributes)。每一个attribute都是一个数据的集合,用于后面的阶段进行处理。虽然这些attributes定义了一个顶点,但没有要求说一个顶点的attributes集合中必须包含了位置和法线信息。实际上,attribute数据是完全任意的,它们仅仅是“数据”,在这个准备阶段不会有人在意你传递的到底是什么attribute,它们的真正含义会在顶点处理阶段进行解读。
OpenGL要求所有的数据都必须存储在缓存对象中(buffer objects)。缓存对象是OpenGL管理的一些内存空间。“想要让我办事,请先把你的东西放到我的地盘!”把数据放到这些缓存里有很多方法,但最常见的是使用glBufferData()来实现。当然这里面还有一些其他步骤,我们后面会讲到。

在我们定义了顶点相关信息后,我们可以通过调用OpenGL的绘图操作来要求按一个个几何图元绘制到屏幕上。这些操作例如有glDrawArrays()。我们后面会讲到。这个绘制的过程意味着我们把顶点数据传递给OpenGL服务器。

对于通过绘制命令绘制的每一个顶点,OpenGL将调用一个vertex shader来处理关于这个顶点的相关信息。Vertex shader接受从上个阶段传递来的attribute作为输入,然后把每一个输入顶点转换成一个输出顶点(这个关系是1对1的,不会多也不会少)。和输入的顶点信息不同,输出的顶点数据有一些必需的要求——vertex shader必须填充一个位置信息。
Vertex shaders的复杂性可以变化非常大,有的很简单,就是仅仅复制数据然后传递给下一个流水线阶段,我们称这种为pass-through shader;有的很复杂,会执行很多操作来计算顶点的屏幕位置(通常使用变换矩阵来完成,后面会讲到),还可能会进行光照计算来计算顶点的颜色,或者其他技术。
通常,一个应用会包含多个vertex shader,但同一时间只有一个会被激活(active)。

Primitive assembly就是把vertex shader输出的顶点数据集合在一起,并把它组合成一个图元的过程。用户渲染的图元的类型决定了这个过程是如何工作的。
这个过程的输出是一个有序的简单图元(点、线或者三角形)序列。

Tessellation,读 泰斯类什,可以翻译成曲面细分。在vertex shader处理了每一个顶点的相关信息后,如果tessellation shader阶段被激活的话,它就会继续处理这些数据。在后面我们会看到tessellation使用patchs来描述一个对象的形状,并且允许细化(tessellate)相对简单的patch集合,来增加几何图元的数量,提高模型的平滑度和真实度。Tessellation Shading阶段可以使用两个shaders来控制patch数据,以及中间一个固定函数的tessellator来生成最终的形状。
更多内容可以参见这篇文章(虽然是DirectX的。。。)

这一阶段允许在光栅化之前处理单独的几何图元,包括创建新的图元。这一阶段同样是可选的,但是会很有用!后面会讲到。
Geometry shader会处理每一个输入的图元,然后返回0个或更多的输出图元。它的输入是primitive assembly的输出图元。因此如果我们按triangle strip看待一个图元,那么geometry shader看到的就会使一系列三角形。
然而也有一些输入的图元类型是专门为geometry shaders定义的。这些相邻的图元可以让GS了解关于相邻顶点的信息。
GS的输出可以是0个多更多的简单图元。GS可以移除图元,或者根据一个输入图元来输出更多的图元来细分(tessellate)它们。GS甚至可以改变图元的类型,比如把点图元编程三角形,把线图元变成点。

Geometry shader或者primitive assembly的输出会被写入一系列的缓存对象。这被称为transform feedback模式。它允许我们通过vertex和geometry shaders来变换数据,然后再等待后续使用。
通过舍弃光栅化的结果,流水线可以在这步就停止了。这允许transform feedback成为渲染的唯一输出。

然后就进入图元裁剪和适当的剔除阶段了。
裁剪以为着,如果有图元处于视野的边界上,即一部分在内部一部分在外部,那么它就会被裁剪成一些小的图元。而且,vertex shader可以在空间内定义一些裁剪平面,这些裁剪平面又会引起额外的裁剪。
三角面的剔除同样在这一阶段完成。处于视野范围以外,或者在裁剪平面的边界内部的图元,都会被提出。

在裁剪完成后,更新后的图元就会被发送给光栅化程序去生成fragments。那么什么是fragment呢?一个fragment可以看成是一个“候选像素”。这类像素在帧缓存中的一块区域中。一个fragment仍可以被拒绝(reject),并且永远不会更新它的相关像素位置。
Wiki上把fragment成为是一个状态的集合,用于计算一个像素的最终数据。一个fragment的状态包含了它在屏幕空间的位置信息,样本覆盖(sample coverage,如果开启了multisampling的话),以及一些其他由vertex或者geometry shader输出的数据。这些数据集合是通过该fragment对应的顶点数据进行插值计算而得的。这个插值计算是由输出这些数据的shader定义的。

处理fragments是后面两个阶段的任务——fragment shading和per-fragment操作。

最后一个我们可以编程控制颜色的阶段就是fragment shading。在这个阶段,我们使用一个shader来决定该fragment的最终颜色(其实下个阶段,per-fragment操作仍可以进行最后的颜色修改)和它的深度值(depth value)。在fragment shaders里我们可以进行非常强大的纹理映射的工作。如果一个fragment shader认为某个fragment不应该绘制出来,它还可以终结一个fragment的处理过程。这个过程称为fragment discard。
一个fragment shader会输出一个颜色列表、一个深度值和一个stencil值。Fragment shaders不可以为一个fragment设置stencil,但是它们可以控制颜色和深度值。
我们可以想来区分vertex shading(包括tessellation和geometry shading)和fragment shading:vertex shading决定了一个图元在屏幕上的位置,而fragment shading使用这些信息来决定该fragment的颜色。

从fragment处理器输出的fragment数据会再通过一系列的步骤。
第一个步骤就是各种剔除检验(culling tests)。如果开启了stencil test,如果一个fragment没有通过检验它就会被剔除,而不会写入到帧缓存中;如果开启了depth test,如果一个fragment没有通过检验它就会被剔除,而不会写入到帧缓存中。只要没有通过任何一个检验,fragments都会被剔除,不会添加到帧缓存中。
如果一个fragment成功通过了所有的检测,它就会直接写入帧缓存中,更新它的像素颜色(也可能是深度值)。如果blending被开启了,该fragment的颜色会和当前的像素颜色进行混合去产生一个新的颜色,再写入帧缓存中。
最后,fragment数据被写入帧缓存中。Masking operation允许用户避免写入特定的值。写颜色、深度和stencil都可以被mask成on或者off;单独的颜色通道也可以。

3, 着色器编程

3, 光照

4, FBO/PBO/VBO/RBO

5, 基础概念

世界坐标系是一个特殊的坐标系, 他建立了描述其他坐标系需要的参考框架,也就是说能够用世界坐标系描述其他坐标系的位置,而不能用更大的,外部的坐标系来描述世界坐标系

物体坐标系是和特定物体相关的坐标系, 每个物体都有他们独特的坐标系.

相机坐标系和观察者密切相关.

Mipmap是多级渐远纹理,也是目前应用最为广泛的纹理映射(map)技术之一。简单来说,就是实现 “实物(图片)看起来近大远小,近处清晰远处模糊”的效果。它简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个。由于距离远,解析度不高也不会被用户注意到。同时,多级渐远纹理另一加分之处是它的性能非常好

参考:http://blog.csdn.net/chenchao868/article/details/4768716
http://www.360doc.com/content/15/1205/14/16593919_518090882.shtml

http://www.jianshu.com/p/f214a3d49752

上一篇 下一篇

猜你喜欢

热点阅读