Skip to content

Latest commit

 

History

History
executable file
·
100 lines (72 loc) · 8.7 KB

opengl_yuanli.org

File metadata and controls

executable file
·
100 lines (72 loc) · 8.7 KB

OpenGL工作原理

1 基础图形管线

OpenGL中的图元只不过是顶点的集合以预定义的方式结合在一起罢了。例如,一个单独的点就是一个图元,它只需要一个顶点。三角形则是另外一个例子,它是由3个顶点组成的图元。在我们讨论不同种类的图元之前,先来看看一个图元是如何由独立的顶点组合而成的。

基础管线接受3个顶点个顶点并将它们转换成一个三角形。它还可能应用颜色、一个或多个纹理并且移动它们的位置。这种管线也是可编程的,实际上我们编写了两个程序,图形硬件执行它们来处理顶点数据,并在屏幕上填充像素。为了便于理解OpenGL上的这种基础处理工作,让我们来看一看OpenGL渲染管线的一个简化版本。

                    
  如何渲染一个三角形
                    +------------------------------------+
                    |    Application Code: C/C++, etc.   |
                    +------------------------------------+
                    |            OpenGL API              |
                    +-+-----------+-----------------+----+        客户机
                    --+-----------+-----------------+------------------------
                      |           |                 |   属性      服务器
                      |纹理       |Uniforms         | (输入)        
                      |           |         +-------+-------+           
                      |           +---------+   顶点着色器   |          
                      |           |         | void main(){  |
                      +-----------+---------+    ...        |
                      |           |         |    ...        |
                      |           |         |    }          |
                      |           |         +---+----+------+
                      |           |      Vertex |    |      
                      |纹理       |    Positions|    |  输出
                      |           |Uniforms     |    |      
                      |           |          ---+----+/--   
                      |           |          |Primitive     
                      |           |          |  --/+-       
                      |           |          | -/- |        
                      |           |          ++    |     
                      |           |                |        
                      |           |         +------+--------+
                      |           +---------+  片段着色器    |
                      |                     | void main(){  |
                      +---------------------+    ...        |
                                            |    ...        |
                                            |    }          |
                                            +------+--------+
                                                   |
                                                   |
                                             Result Graphics

2 客户机-服务器

首先请注意我们将管线分成了两部分。上半部分是客户端,而下半部分则是服务器端。就OpenGL而言:

  • 客户端:存储在CPU存储器中,并且在应用程序执行,或者在主系统内存驱动程序中执行。
  • 服务器端:驱动程序将渲染命令与数据结合起来,发送到服务器执行。在一台典型的桌面计算机上,服务器会跨越系统总线,实际上,它就是图形加速卡上的硬件和内存。

服务器和客户机上功能上也是异步的,我们希望两方面都尽可能不停的工作。

3 着色器

着色器是使用GLSL编写的程序。GLSL看起来与C语言非常类似,实际上GLSL语言的程序甚至是以我们熟悉的main函数开始的。这些着色器必须从源代码中编译和链接到一起,最终准备就绪的着色器程序随后在第一阶段构成顶点着色器,在第二阶段构成片段着色器。

这个简化模型中,顶点着色器处理从客户机输入的数据,应用变换,或者进行其他类型的数学运算来计算光照效果、位移、颜色值,等等。为了渲染一个共有3个顶点的三角形,顶点着色器将执行3次,也就是为每个顶点执行一次。在目前的硬件上有多个执行单元同时执行,这就意味着所有这3个顶点都可以同时进行处理。今天的图形处理器属于大规模并行计算机。不要将它们和CPU相比而被时钟速度蒙蔽,它们比图形操作要快上几个数量级。

现在,3个顶点都已经做好了光栅化的准备。图元组合(Primitive Assembly)框图意在说明3个顶点已经组合在了一起,而三角形已经逐个片段的进行了光栅化。每个片段都通过执行片段着色器而进行了填充,片段着色器会输出我们在屏幕上看到的最终颜色值。再强调一次,今天的硬件是大规模并行运算的,同时执行上百个甚至更多这种片段程序并不困难。

当然我们必须首先为这些着色器提供数据,否则什么都做不成。有3种向OpenGL着色器传递渲染数据的方法可供程序员选择,即 属性Uniform值纹理

3.1 属性

所谓属性就是一个对每个顶点都要做改变的数据元素。实际上,顶点位置本身就是一个属性。属性值可以是浮点数、整数或布尔数据。属性总是以四维向量的形式进行内部存储的,即使我们不会使用到所有分量。如果只用到前面3个,OpenGL会将第4个分量自动设为1。

属性会从本地客户机内存中复制存储在图形硬件中(这种情况的可能性最大)的一个缓冲区上。这些属性只供顶点着色器使用,对于片段着色器h来说没什么意义。还要声明一点,这些属性对每个顶点都要做改变,并不意味着它们的值不能重复,而只是说明对于每个顶点都有一个实际存储值。当然,通常情况下它们都是不同的,但是也有可能会有整个数组都是同一个值的情况。但是这种情况是非常浪费的,而且如果我们需要在某个批次中都是同一个值的数据元素,我们还有更好的方案。

3.2 Uniform值

Uniform值是一种对于整个批次的属性都取统一值的单个值,也就是说,它是不变的。我们通常设置完Uniform值就紧接着发出渲染一个图元批次的命令。Uniform变量实际上可以无次数限制地使用,我们可以设置一个应用于整个表面的单个颜色值,还可以设置一个时间值,在每次渲染某种类型的顶点动画时修改它(请注意,这里的Uniform变量在每个批次改变一次,而不是每个顶点改变一次)。Uniform变量一个最常见的应用实在顶点渲染中设置变换矩阵。

Uniform值在本质上像属性一样,可以是浮点值、整数或布尔值,但和属性不同的是,顶点着色器和片段着色器中都可以有Uniform变量。Uniform变量既可以是标量类型,也可以是矢量类型,我们也可以使用Uniform矩阵。从技术上来说,我们也可以使用属性矩阵,矩阵中每一列对应4个分量中的一个,但是我们通常不这么做。

3.3 纹理

从顶点着色器和片段着色器中都可以对纹理值进行采样和筛选。典型情况下,片段着色器对一个纹理进行采样,并在一个三角形的表面上应用图形数据。

但是,纹理数据的作用并不仅仅是表现图形。任何大型浮点数据块(例如消耗资源很大的函数的大型查询表)都可以通过这种方式传递给着色器。

3.4 输出

输出(Out)数据是作为一个阶段着色器的输出定义的,而在后续阶段的着色器则是作为输入(In)定义的。输出类型的数据可以简单地从一个阶段传递到下一个阶段,也可以以不同的方式插入。客户端的代码接触不到这些内部变量,但是它们在顶点着色器和片段着色器中(还可能包括可选的几何着色器)都进行了声明。顶点着色器为输出变量分配一个值,这个值是常量,也可以在图元被光栅化时插入到顶点之间。片段着色器对应的同名输入值接受这个常量或插入值。