OpenGL 基本知识

417 阅读8分钟

一. OpenGL 渲染架构

首先在 OpenGL 渲染图形的时候有一些概念需要明确:

  • Client:客户端指的是我们在CPU上存储的一些代码, 比如我们会编写C/C++代码和使用OpenGL的一些API。
  • Server:服务端其实就是我们 GPU。
  • Vertex Shader:顶点着色器是 OpenGL 中用于计算顶点属性的程序,一般用来处理图形的每个顶点的变换(平移、旋转、缩放等)。
  • Primitive Assembly:图元装配、光栅化其实是一种将几何图形变为二位图形的过程,也叫做把顶点数据转为片元的过程。
  • Fragment Shader:片元着色器是 OpenGL 中用于计算片段(像素)颜色的程序,一般用来处理图形中每个像素点的计算和填充。
  • Render:渲染,其实就是图形绘制。

关于Attributes UniformsTexture Data参见下文第二部分,这里简单理解为一种数据传输的通道。

Client 通过 Attributes UniformsTexture Data 这三种方式把数据传递给我们的顶点着色器Vertex Shader和片元着色器Fragment Shader。在平时开发过程中我们一般很少把Texture Data传递给Fragment Shader使用。

二. OpenGL数据传递的三种方式

我们将传递数据的方式在 OpenGL 里面称之为通道,比较常见的通道有 attribute,uniform,Texture 等等,他们都可以存储多个参数值,按需填充使用。

  • attribute 属性(顶点着色器使用)可以存储的值:

    • 颜色数据
    • 顶点数据
    • 纹理坐标
    • 光照法线
  • uniform 标准参数(顶点着色器和片元着色器均可使用)可以存储的值:

    • 顶点变换计算矩阵(顶点着色器计算顶点坐标变换)
    • 颜色空间转换矩阵(片元着色器将视频的 YUV 颜色空间通过矩阵计算转为 OpenGL 使用的 RGBA)
  • Texture 纹理(顶点着色器和片元着色器均可使用,一般清空都是片元着色器使用)可以存储的值:

    • 滤镜(对图片本身做处理,比如修改图片的颜色值)
    • 渲染一个图形(直接使用设定的色值渲染三角形,而不需要用一个三角形图片填充进去来做出渲染)
    • 像素填充(混合图层的颜色填充)

三. OpenGL 提供的存储着色器

OpenGL 提供的存储着色器为 GLShaderManager,调用 InitializeStockShaders() 初始化。使用GLShaderManager的时候有一个好处就是我们不必知道哪些工作由顶点着色器完成,哪些工作由片元着色器完成,我们只需要使用 GLShaderManager 调用 UserStockShader() 方法,传不同的参数即可。下面介绍一些不同的着色器。

  • 单元着色器 UserStockShader(GLT_SHADER_IDENTITY, GLfloat vColor[4])

    • 参数 1:存储着色器种类-单元着色器
    • 参数 2:长度为 4 的颜色数组(每个元素分别代表R,G,B,A)

    使用场景:绘制默认 OpenGL 坐标系(-1,1)下图形,图形所有片段都会以一种颜色填充。

  • 平面着色器 UserStockShader(GLT_SHADER_FLAT, GLfloat mvp[16], GLfloat vColor[4])

    • 参数 1:存储着色器种类-平面着色器
    • 参数 2:允许变化的 4x4 矩阵
    • 参数 2:长度为 4 的颜色数组(每个元素分别代表R,G,B,A)

    使用场景:在绘制图形时,可以用于变换(模型、投影变化)。m 代表模型 model,v 代表视图 view,p 代表投影 perspection!

  • 上色着色器 UserStockShader(GLT_SHADER_SHADED, GLfloat mvp[16])

    • 参数 1:存储着色器种类-上色着色器
    • 参数 2:允许变化的 4x4 矩阵

    使用场景:在绘制图形时,可以用于变换(模型、投影变化)。颜色将会平滑地插入到顶点之间称为平滑着色

  • 默认光源着色器 UserStockShader(GLT_SHADER_DEFAULT_LIGHT, GLfloat mvMatrix[16], GLfloat pMatrix[16], GLfloat vColor[4])

    • 参数 1:存储着色器种类-默认光源着色器
    • 参数 2:模型 4x4 矩阵
    • 参数 3:投影 4x4 矩阵
    • 参数 4:长度为 4 的颜色数组(每个元素分别代表R,G,B,A)

    使用场景:在绘制图形时,可以用于变换(模型、投影变化)这种着色器会使图形产生阴影和光照效果。

  • 点光源着色器 UserStockShader(GLT_SHADER_POINT_LIGHT_DIEF, GLfloat mvMatrix[16], GLfloat pMatrix[16], GLfloat vLightPos[3], GLfloat vColor[4])

    • 参数 1:存储着色器种类-点光源着色器
    • 参数 2:模型 4x4 矩阵
    • 参数 3:投影 4x4 矩阵
    • 参数 4:点光源位置(x,y,z)
    • 参数 5:漫反射长度为 4 的颜色值数组(每个元素分别代表R,G,B,A)

    使用场景:在绘制图形时,可以用于变换(模型、投影变化)这种着色器会使图形产生阴影和光照效,它于默认光源着色器非常类似,区别是只是光源位置可能是特定的。

  • 纹理替换着色器 UserStockShader(GLT_SHADER_TEXTURE_REPLACE, GLfloat mvMatrix[16], GLint nTextureUnit)

    • 参数 1:存储着色器种类-纹理替换着色器
    • 参数 2:模型 4x4 矩阵
    • 参数 3:纹理单元

    使用场景:在绘制图形时,可以用于变换(模型、投影变化)这种着色器通过给定的模型视图投影矩阵,使用纹理单元来进行颜色填充,其中每个像素点的颜色是从纹理中获取。

  • 纹理调整着色器 UserStockShader(GLT_SHADER_TEXTURE_MODULATE, GLfloat mvMatrix[16], GLfloat vColor[4], GLint nTextureUnit)

    • 参数 1:存储着色器种类-纹理调整着色器
    • 参数 2:模型 4x4 矩阵
    • 参数 3:长度为 4 的颜色数组(每个元素分别代表R,G,B,A)
    • 参数 4:纹理单元

    使用场景:在绘制图形时,可以用于变换(模型、投影变化)这种着色器通过给定的模型视图投影矩阵,着色器将一个基本色乘以一个取自纹理单元 nTextureUnit 的纹理,将颜色与纹理进行颜色混合后才填充到片段中。

  • 纹理光源着色器 UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF, GLfloat mvMatrix[16], GLfloat pMatrix[16], GLfloat vLightPos[3], GLfloat vBaseColor[4], GLint nTextureUnit)

    • 参数 1:存储着色器种类-纹理光源着色器
    • 参数 2:模型 4x4 矩阵
    • 参数 3:投影 4x4 矩阵
    • 参数 4:点光源位置(x, y, z)
    • 参数 5:长度为 4 的颜色数组(每个元素分别代表R,G,B,A),几何图形的基本颜色
    • 参数 6:纹理单元

    使用场景:在绘制图形时,可以用于变换(模型、投影变化)这种着色器通过给定的模型视图投影矩阵,着色器将一个纹理通过漫反射照明计算进行调整(相乘)。

四. 正投影和透视投影的 API 使用

正投影相对于透视投影不会出现远小近大的情况。

  • 正投影 API: API CLFrumStum::SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, GLfloat zMin, GLfloat zMax)

    • xMin: x坐标的最小值
    • xMax: x坐标的最大值
    • yMin: y坐标的最小值
    • yMax: y坐标的最大值
    • zMin: z坐标的最小值
    • zMax: z坐标的最大值
  • 透视投影 API:CLFrumStum::SetPerspective(float fFov, float fAspect, float fNear, float fFar)

    • fFov: 垂直方向上的视场角度
    • fAspect: 窗口的宽高纵横比(w/h)
    • fNear: 近裁剪面距离
    • fFar: 近裁剪面距离

    透视投影模型结构图

    参考文章:透视投影矩阵

五. OpenGL 常见图元

图元类型:就是顶点的连接方式,在 OpenGL 中,只有点,线,三角形。

图元 描述
GL_POINTS 每个顶点在屏幕上都是单独点
GL_LINES 每一对儿顶点定义一个线段
GL_LINES_STRIP 一个从第一个顶点依次经过每一个后续顶点而绘制的线条
GL_LINES_LOOP 和GL_LINES_STRIP相同,但是最后一个顶点和第一个顶点连接闭合起来
GL_TRIANGLES 每三个顶点定义一个三角形
GL_TRIANGLES_STRIP 共用一个条带(strip)上的顶点形成一组新三角形
GL_TRIANGLES_FAN 以一个原点为中心呈扇形排列,共用相邻顶点的三角形

图元类型示意

对于 OpenGL 光栅化最受欢迎的就是三角形,3 个顶点就能构成一个三角形,在默认情况下,OpenGL 任务逆时针方向连接顶点的多边形称之为正面,顺时针方向连接顶点的多边形称之为反面。

OpenGL 的三角形带的优点: 用前 3 个顶点指定第一个三角形之后,对于接下来的每一个三角形,只需要再指定一个顶点就可以了。当需要绘制大量的三角形的时候采用这个方法能节省大量的程序代码和数据存储空间。提供运算性能和节省带宽。更少的顶点意味着数据从内存传输到图形显卡的速度更快,并且顶点着色器需要处理的次数也变少了。

六. OpenGL 工具类 GLBatch

  • 创建 GLBatch void GLBatch::Begin(GLenum primitive, GLuint nVerts, GLuint nTextureUnits = 0)

    • 参数 1:图元类型
    • 参数 2:顶点个数
    • 参数 3:1 组或者 2 组纹理坐标(可选参数,默认为 0)
  • 复制顶点数据(一个由 3 分量 x,y,x 顶点组成的数组)void GLBatch::CopyVerterxData3f(GLfloat *vVerts)

  • 复制表面法线数据 void GLBatch::CopyNormalDataf(GLfloat *vNorms)

  • 复制颜色数据 void GLBatch::CopyColorData4f(GLfloat *vColors)

  • 复制纹理坐标数据 void GLBatch::CopyTexCoordData2f(GLfloat *vTextCoords, GLuint uiTextureLayer)

  • 结束数据复制 void GLBatch::End(void)

  • 绘制图形 void GLBatch::Draw(void)