OpenGL设计模式
OpenGL是按照客户机-服务器
模式设计的。需要注意的是并非指我们平常所理解的移动端与后端。
客户端:
- 负责发送OpenGL指令
-
CPU
上面存储的代码,比如OpenGLApi,C和C++代码
服务端:
- 负责接收OpenGL命令并执行相应的操作
- 调用的是
GPU
芯片
进一步阐述
-
客户端 是存储在
CPU
储存器中的,并且在应用程序
中执行或者在主系统内存中驱动程序
中执行。驱动程序
会将渲染命令
和数组
组合起来,发送给 服务器 执行! -
服务器和客户端在
功能上也是异步
的。客户端不断的把数据块和命令块组合在⼀起输送到缓冲区,然后缓冲区就会发送到服务器执行
如果服务端停止工作等待客户端,或者客户端停止工作来等待服务端做好接受更多的命令和准备,我们把这种情况成为 管线停滞。
OpenGL渲染架构
OpenGL渲染架构首先理解下绘图过程
无非是把数据从系统内存
中复制到图形卡
,然后绘制出图形
。
中间涉及到 着色器 的流程。顶点着色器 处理从客户端输入的数据,用数学运算来计算光照效果、位移、颜色值等。有几个顶点,顶点着色器就要执行几次。
通过图元装配,将顶点组成在一起,变成 图元
进而通过裁剪、转换窗口坐标、光栅化,输入到 片元着色器 ,片元着色器,将对应的栅格(像素)填充为具体的颜色。
在这里,顶点着色(包括细分和几何着色)决定了一个图元应该位于屏幕的什么位置,呈现什么形状;而 片元着色 使用这些信息来决定某个片元的颜色应该是什么。
对于渲染流程详细流程,有兴趣可以移步OpenGL渲染流程。
这其中,渲染数据是如何在着色器中传递的?我们继续看上面的OpenGL渲染架构图。
客户端向服务端传递数据的方式
- Attributes
就是对每⼀个顶点都要作出改变的数据元素。实际上,顶点位置本身就是一个属性.。属性可以是浮点类型,整型,布尔类型等。
- 常用属性传递的数据
顶点数据(x,y,z,w),颜色值,光照计算法线,投影矩阵、模型矩阵,纹理坐标(图片映射坐标)
- 属性总是以四维向量的形式进行内部存储
- 属性会从本地客户端内存中复制存储在图像硬件中的一个缓冲区中
- 属性只供顶点着色器使用,对片段着色器没有意义
Attributes 只能输入到顶点着色器,无法“直接”输入到片元着色器
- Texture Data
对纹理进行采样和筛选。纹理数据的作用不仅仅是表现图形。很多图形文件格式都是以无符号字节形式对颜色分量进行存储的,但我们仍然可以设置浮点纹理。这就是说,任何大型浮点数据块(例如消耗资源很大的函数的大型查询表)都可以通过这种方式传递给着色器。
纹理数据 可以直接输入到顶点着色器, 也可以直接输入到片元着色器
- Uniforms
通过设置 Uniform 变量就紧接着发送一个图元批次处理命令。Uniform 变量实际上可以无限次的使⽤。 设置一个应用于整个表⾯面的单个颜色值,还可也是一个时间值。
uniform变量最常见的应用是在顶点渲染中设置变换矩阵
Uniforms 可以直接输入到顶点着色器,也可以直接输入到片元着色器
- Ins and Outs
着色器之间可以按照固定流程 in 和 out,相应地,数据也可以逐层传递
在OpenGL中通过GLBatch(是GLTools中包含的简单容器类)批次类来设置图元连接方式和组装顶点数据:
GLBatch可以作为7种图元的简单批次容器使用。而且它知道在使用GL_ShaderManager支持的任意存储着色器时如何对图元进行渲染。
使用 GLBatch 类非常简单。首先对批次进行初始化,告诉这个类它代表哪种图元,其中包括的顶点数,以及(可选)一组或两组纹理坐标。
参数1:图元
参数2:顶点数
参数3:一组或者2组纹理坐标(可选)
void GLBatch::Begin(GLeunm primitive,GLuint nVerts,GLuint nTexttureUnints = 0);
//绘制图形
void GLBatch::Draw(void);
然后,至少要复制一个由3分量(x, y, z)顶点组成的数组。
//复制顶点数据(⼀一个由3分量量x,y,z顶点组成的数组)
void GLBatch::CopyVerterxData3f(GLfloat *vVerts);
还可以选择复制表面发现、颜色和纹理坐标。
//复制表⾯法线数据
void GLBatch::CopyNormalDataf(GLfloat *vNorms);
//复制颜色数据
void GLBatch::CopyColorData4f(GLfloat *vColors);
//复制纹理坐标数据
void GLBatch::CopyTexCoordData2f(GLFloat *vTextCoords, GLuint uiTextureLayer);
完成上述工作以后,可调用End来表明已经完成了数据复制工作,并且将设置内部标记,以通知这个类包含哪些属性。
//结束数据复制
void GLBatch::End(void);
基本图元连接方式
基本图元图元 | 描述 |
---|---|
GL_POINTS | 每个顶点在屏幕上都是单独点 |
GL_LINES | 每⼀对顶点定义⼀个线段 |
GL_LINE_STRIP | 一个从第⼀个顶点依次经过每⼀个后续顶点而绘制的线条 |
GL_LINE_LOOP | 和GL_LINE_STRIP相同,但是最后⼀个顶点和第⼀个顶点连接起来了 |
GL_POLYGON | 每4个顶点定义一个新的四边形 |
GL_QUADS | 每4个顶点连接并内部填充 |
GL_QUAD_STRIP | 形成四边形后2个顶点复用 |
GL_TRIANGLES | 每3个顶点定义⼀个新的三角形 |
GL_TRIANGLE_STRIP | 共⽤一个条带(strip)上的顶点的一组三⻆形 |
GL_TRIANGLE_FAN | 以⼀个圆点为中⼼呈扇形排列,共⽤相邻顶点的⼀组三⻆形 |
- 三角形带
对于很多表面或者形状⽽⾔,我们会需要绘制⼏个相连的三角形. 这时我们可以使用GL_TRIANGLE_STRIP 图元绘制一串相连三角形,从而节省大量的时间。
三角形带- 三角形扇
对于很多表面或者形状⽽⾔言,我们会需要绘制⼏个相连的三角形. 这时我们可以使用GL_TRIANGLE_FAN 图元绘制一组围绕一个中心点相连的三⻆形。
三角形扇运用三角形带和三角形扇优点:
- 复用:⽤前3个顶点指定第1个三角形之后,对于接下来的每一个三⻆形,只需要再指定1个顶点。需要绘制⼤量的三角形时,采用这种⽅法可以节省⼤量的程序代码和数据存储空间
- 效率:提供运算性能和节省带宽。更少的顶点意味着数据从内存传输到图形卡的速度更快,并且顶点着色器需要处理的次数也更少了了。
几种固定管线下的着色器
单元着⾊器
参数1: 单元着⾊器-GLT_SHADER_IDENTITY
参数2: 颜⾊值
GLShaderManager::UserStockShader(GLT_SHADER_IDENTITY,
GLfloat vColor[4]);
使⽤场景:只是简单地使用默认的笛卡尔坐标系(坐标范围-1.0~1.0)。 图形所有片段都会以⼀种颜⾊填充,无法做变化,属于最基本的单元着色器。
平⾯着⾊器
参数1: 平⾯着⾊器-GLT_SHADER_FLAT
参数2: 允许变化的4*4矩阵
参数3: 颜⾊色值
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,
GLfloat mvp[16],
GLfloat vColor[4]);
使⽤场景:将单位着色器进行了扩展,允许为集合图形变换指定一个 4 x 4 的变换矩阵
上⾊着⾊器
参数1: 上⾊着⾊器-GLT_SHADER_SHADED
参数2: 允许变化的4*4矩阵
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,
GLfloat mvp[16]);
使⽤场景:唯一的 Uniform 值就是在几何图形中应用的变换矩阵。GLT_ATTRIBUTE_VERTEX 和 GLT_ATTRIBUTE_COLOR 在这种着色器中都会使用。颜色值将被平滑地插入顶点之间(称为平滑着色)。
默认光源着⾊器
参数1: 默认光源着⾊器-GLT_SHADER_DEFAULT_LIGHT
参数2: 模型4*4矩阵
参数3: 投影4*4矩阵
参数4: 颜⾊值
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,
GLfloat mvMatrix[16],
GLfloat pMatrix[16],
GLfloat vColor[4]);
使⽤场景:这种着色器使对象产生阴影和光照的效果。需要模型视图矩阵、投影矩阵和作为基本色的颜色值等 Uniform 值。所需的属性有 GLT_ATTRIBUTE_VERTEX(顶点分量)和 GLT_ATTRIBUTE_NORMAL(表面法线)。
点光源着⾊器
参数1: 点光源着⾊器-GLT_SHADER_POINT_LIGHT_DIEF
参数2: 模型4*4矩阵
参数3: 投影4*4矩阵
参数4: 点光源的位置
参数5: 漫反射颜⾊值
GLShaderManager::UserStockShader(GLT_SHADER_POINT_LIGHT_DIEF,
GLfloat mvMatrix[16],
GLfloat pMatrix[16],
GLfloat vLightPos[3],
GLfloat vColor[4]);
使⽤场景:和默认光源着色器很相似,但光源位置可能是待定的。接受 4 个 Uniform 值,即模型视图矩阵、投影矩阵、视点坐标系中的光源位置和对象的基本漫反射颜色。同样所需的属性有 GLT_ATTRIBUTE_VERTEX(顶点分量)和 GLT_ATTRIBUTE_NORMAL(表面法线)。
纹理替换矩阵着⾊器
参数1: 纹理替换矩阵着⾊器-GLT_SHADER_TEXTURE_REPLACE
参数2: 模型4*4矩阵
参数3: 纹理单元
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,
GLfloat mvMatrix[16],
GLint nTextureUnit);
使⽤场景:着色器通过给定的模型视图投影矩阵,使用绑定到 nTextureUnit(纹理单元) 指定的纹理单元的纹理对几何图形进行变换。片段颜色是从纹理样本中直接获取的。所需的属性有 GLT_ATTRIBUTE_VERTEX(顶点分量)和 GLT_ATTRIBUTE_NORMAL(表面法线)。
纹理调整着⾊器
参数1: 纹理调整着⾊器-GLT_SHADER_TEXTURE_MODULATE
参数2: 模型4*4矩阵
参数3: 颜⾊值
参数4: 纹理单元
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,
GLfloat mvMatrix[16],
GLfloat vColor[4],
GLint nTextureUnit);
使⽤场景:这种着色器将一个基本色乘以一个取自纹理单元 nTextureUnit 的纹理。所需的属性有 GLT_ATTRIBUTE_VERTEX(顶点分量)和 GLT_ATTRIBUTE_TEXTURE0(纹理坐标)。
纹理光源着⾊器
参数1:纹理光源着⾊器-GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF
参数2: 模型4*4矩阵
参数3: 投影4*4矩阵
参数4: 点光源位置
参数5: 颜⾊值
参数6: 纹理单元
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,
GLfloat mvMatrix[16],
GLfloat pMatrix[16],
GLfloat vLightPos[3],
GLfloat vBaseColor[4],
GLint nTextureUnit);
使⽤用场景:这种着色器将一个纹理通过漫反射照明计算进行调整(相乘),光线在视觉空间中的位置是给定的。这种着色器接受 5 个 Uniform 值,即模型视图矩阵、投影矩阵、视觉空间中的光源位置、几何图形的基本色和将要使用的纹理单元。所需的属性有 GLT_ATTRIBUTE_VERTEX(顶点分量)、GLT_ATTRIBUTE_NORMAL(表面法线)和 GLT_ATTRIBUTE_TEXTURE0(纹理坐标)。
网友评论