OpenGL-渲染架构

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(纹理坐标)。

你可能感兴趣的:(OpenGL-渲染架构)