在上一篇OpenGL 下的坐标系的最后部分,我们已经了解了着色器渲染的流程。下面就来学习一下基础图形渲染管线。

OpenGL基础图形渲染管线

在OpenGL中,无论是使用可编程管线,还是使用固定管线,那么它的渲染管线流程都是一样的。 首先我们来看一下渲染管线流程图:



1.客户端--服务端

管线分为上下2部分,上部分是Client客户端,下半部分则是Server服务端。 这里的客户端并非是我们在平时开发中说的iOS客户端、Android客户端。这里的客户端指的是在CPU上所存储的代码,比如OpenGL的API和C/C++的代码。这里的Server端调用的是GPU芯片,然后不断从客户端把数据(颜色)传递到服务端来执行。

专业解释为:客户端是存储在CPU存储器中的,并且在应用程序中执行,或者在主系统内存的驱动程序中执⾏。驱动程序会将渲染命令和数据组合起来,发送给服务器执⾏。 客户端和服务端在功能上也是异步的。 它们是各自独立的软件块或硬 件块。客户端不不断的把数据块和命令块组合在一起输送到缓冲区,然后缓冲区就会发送到服务器执⾏。

2.着色器

着⾊器是使⽤用GLSL编写的程序,看起来与C语⾔⾮常类似。 着⾊器 须从源代码中编译和链接在一起。最终准备就绪的着⾊器程序。 四种着色器:顶点着色器(必要)、细分着色器(可选)、几何着色器(可选)、片元着色器(必要)。顶点着色器和片元着色器 是每个OpenGL程序必不可少的部分,下面着重介绍一下。

顶点着色器:处理从客户机输⼊的数据、应⽤用变换、进行其他的类型的数学运算来计算关照效果、位移、颜⾊值等等,在渲染时有几个顶点,顶点着色器执行几次,而且对每个点的执行是同时的。

片元着色器:这是管线最后一部分,用来处理OpenGL 光栅化之后生成的单独片元,在这个阶段里面,计算一个偏远的颜色和深度值,然后传递到管线的片元测试和混合的模块。 如果说顶点着色器决定了一个图元应该位于屏幕的什么位置,那么片元着色器就是决定片元的颜色。

3.向OpenGL 着色器传递渲染数据的三种通道

Attributes属性:用来表示一个顶点的数据,并且这个数据可能会不断地改变,比如:颜色数据,顶点数据,纹理坐标,光照法线等;而且属性可以是浮点型,整型,布尔型等等;

实际上,顶点位置本身 就是一个属性,而且,属性总是以四维向量的形式进行内部存储的,即使我们不会使⽤所有的 4个分量。⼀个顶点位置可能存储(x,y,z),将占有4个分量中的3个。

Uniform:uniform变量是外部程序传递给顶点着色器和片元着色器的变量。uniform传入的是一个比较统一的数据,用于图元(图元:OpenGL 中的图元只不过是顶点的集合以预定义的方式结合在一起罢了。)的批次处理,而不是每个顶点改变一次。比如:在顶点渲染中变换矩阵,光照参数和颜色空间转换等信息。

Uniform变量实际上可以无数次限制地使用,设置一个应用于整个表面的单个颜色值,还可以设置一 个时间值。在每次渲染某种类型的顶点动画时修改它。

Texture Data纹理数据:纹理最通常的作用是装饰我们的物体模型,使得物体表面拥有图案。但在OpenGL中,纹理的作用不单单表现在图形上,它也可以用来存储大量的数据,一个典型的例子就是利用纹理存储地形信息。

Attributes属性数据可以直接传递到顶点着色器,不可以直接传递到片元着色器,可以通过顶点着色器间接传递到片元着色器,(在设计Attributes时就设计成了只给顶点着色器使用)。 Uniform数据是可以直接传递到顶点着色器和片元着色器的。 Texture Data纹理数据也是可以直接传递到顶点着色器和片元着色器,(在顶点着⾊器、⽚元着⾊器中都可以对纹理数据进⾏采样和筛选。)不过,一般情况下,纹理单元数据传入顶点着色器是没有必要的。(不过要根据场景来看,如果说有个应用场景是需要把纹理坐标放大,那么这是是就可以在顶点着色器完成,也可以在片元着色器完成。)

4.使用存储着色器

在OpenGL 3.0以前的版本,OpenGL包含一个固定管线,它可以在不使用着色器的环境下处理几何与像素数据。从3.1版本开始,固定管线从核心模式中去除,因此我们必须使用着色器来完成工作。现代OpenGL渲染管线严重依赖着色器来处理传入的数据,我们一般会使用GLSL(OpenGL Shading Language)编写着色器程序,GLSL语法类似于C语言,GLSL编译以后运行在GPU端。下面我们就先来介绍着色器

4.1 存储着色器

存储着色器可以由GLTools的C++类GLShaderManager进行管理,GLShaderManager中的函数UseStockShader会选择一个存储着色器并提供这个着色器的Uniform值,该函数完成的东西就是对我们的顶点数据进一步的加工,比如设置顶点颜色,设置顶点光照的强度,设置顶点纹理等。

4.2 存储着色器的使用

(1)GLShaderManager 的初始化

GLShaderManager  shaderManager;
shaderManager.InitializeStockShaders();
复制代码

(2)GLShaderManager 的属性


存储着⾊色器为每⼀个变量都使用⼀致的内部变量命名规则和相同的属性槽。 (3)GLShanderManager 的 uniform值 一般情况下,要对几何图形进行渲染,我们需要给对象递交属性矩阵,⾸先要绑定我们想要使⽤用的着色程序上,并提供程序的uniform值。但是GLShanderManager类可以暂时的为我们来工作,利用useStockShader函数,选择一个存储着色器并提供这个存储着色器的Uniform的值。

GLShaderManager::UserStockShader(GLeunm shader...);
复制代码

4.3 单元着色器(Identity)

GLShaderManager::UserStockShader(GLT_ATTRIBUTE_VERTEX,GLfloat vColor[4]);
复制代码

单元着⾊器:只是简单地使用默认笛卡尔坐标系(坐标范围(-1.0, 1.0))。所有的片段都应用同一种颜色,⼏何图形为实⼼和未渲染的。 需要设置存储着⾊器⼀个属性:GLT_ATTRIBUTE_VERTEX(顶点分量) vColor[4] :表示需要设置的颜色

4.4 平面着色器(Flat)

GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
复制代码

平面着色器:平面着色器将统一着色器进行了渲染,允许为几何图形变换指定一个4x4的变换矩阵,经常被称为"模型视图投影矩阵"; 在绘制图形时,可以应用变换(模型/投影变化)。 参数GLT_SHADER_FLAT:表示平面着色器 参数GLfloat mvp[16]:表示允许变化的4x4矩阵 参数GLfloat vColor[4]:表示需要设置的颜色

4.5 上色着色器(Shaded)

GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
复制代码

上色着色器:在⼏何图形中应用的变换矩阵。 需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和GLT_ATTRIBUTE_COLOR(颜⾊分量) 2个属性。颜⾊值将被平滑地插入顶点之间(称之为平滑着色), 参数GLT_SHADER_SHADED:表示上色着色器 参数GLfloat mvp[16]:表示需要设置的颜色

4.6 默认光源着色器(Light)

GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);
复制代码

默认光源着色器:默认光源着⾊器,会使绘制的图形产生阴影和关照的效果。 需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和GLT_ATTRIBUTE_NORMAL(表面法线) 可以把默认光源想象成太阳 参数GLT_SHADER_DEFAULT_LIGHT:表示默认光源着色器 参数GLfloat mvMatrix[16]:模型视图矩阵4x4 参数GLfloat pMatrix[16]:投影矩阵4x4 参数GLfloat vColor[4]:颜色值

4.7 点光源着⾊器(Light_Dife)

GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vColor[4]);
复制代码

点光源着色器:点光源着⾊器和默认光源着⾊器很相似,区别在于: 光源位置是特定的。同样会使绘制的图形产生阴影和光照效果, 同样需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和GLT_ATTRIBUTE_NORMAL(表⾯法线)。 参数GLT_SHADER_DEFAULT_LIGHT_DIEF: 表示点光源着⾊色器 参数GLfloat mvMatrix[16]: 模型视图矩阵 4x4 参数GLfloat pMatrix[16]: 投影矩阵 4x4 参数GLfloat vLightPos[3]: 视点坐标光源位置 参数GLfloat vColor[4]: 漫反射的颜⾊值

4.8 纹理替换矩阵着色器(Replace)

GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);
复制代码

着⾊器通过给定的模型视图投影矩阵,使⽤绑定到 nTextureUnit (纹理单元) 指定纹理单元的纹理对几何图形进行变化。 ⽚段颜色:是直接从纹理样本中直接获取的。 需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和GLT_ATTRIBUTE_NORMAL(表面法线) 参数GLT_SHADER_TEXTURE_REPLACE:纹理替换矩阵着色器 参数GLfloat mvMatrix[16]:模型视图矩阵4x4 参数GLint nTextureUnit:纹理单元

4.9 纹理调整着⾊器

GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,G
Lfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit);
复制代码

将一个纹理通过漫反射照明计算机进行调整(相乘)。光线在视觉空间中的位置是给定的。 需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和GLT_ATTRIBUTE_TEXTURE0(纹理坐标)、GLT_ATTRIBUTE_NORMAL(表⾯法线) 参数GLT_SHADER_TEXTURE_MODULATE:纹理调整着⾊器 参数GLfloat mvMatrix[16]:模型视图矩阵4x4 参数GLfloat vColor[4]:漫反射的颜⾊值 参数GLint nTextureUnit:纹理单元

4.10 纹理光源着⾊器

GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit);
复制代码

这种着色器将⼀个纹理通过漫反射照明计算机进行调整(相乘)。光线在视觉空间中的位置是给定的。需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和 GLT_ATTRIBUTE_TEXTURE0(纹理坐标)、GLT_ATTRIBUTE_NORMAL(表⾯法线) 参数GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF:表示纹理光源着⾊器 参数GLfloat mvMatrix[16]:模型矩阵4x4 参数GLfloat pMatrix[16]:投影矩阵4x4 参数GLfloat vLightPos[3]:视觉空间中点光源位置 参数GLfloat vBaseColor[4]:颜色值(几何图形的基本色) 参数GLint nTextureUnit:纹理单元