OpenGL-着色器
时间:2022-08-22 19:30:01
OpenGL渲染架构
组成模块
OpenGL渲染架构主要分为两个模块
- Client: 上层代码和OpenGL API方法,这部分在CPU中运行。
- Server: OpenGL这部分是底层渲染处理GPU中运行。
流程
- 通过调用上层代码OpenGL API该方法以通道的形式将图形渲染的相关数据传输到服务器中的顶点着色器和片元着色器GPU处理。
- 服务器接收通道传输的数据,交给相应的着色器进行渲染,并将最终结果渲染到屏幕上。
- 在此过程中,顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)可使用两部分GLSL其他部分由语言自定义编程OpenGL无法修改底层控制。
数据通道
从图中可以看出,客户端和服务器有三种数据传输渠道
-
Attributes
数据只能直接传输到顶点着色器,但可以通过GLSL语言间接传输到片元着色器中。它主要用于传输经常改变的数据,如纹理坐标、光法线、顶点坐标、颜色数据、投影矩阵、模型矩阵等。
-
Uniform
数据可以直接传输到顶点着色器和片元着色器。它主要用于传输不经常改变的数据。例如,旋转矩阵和视频的颜色控制器YUV数据。
-
Texture Data
纹理数据可以直接传输到顶点着色器和片元着色器。由于纹理数据是在片元着色器中进行的,Texture Data通道通常将纹理数据传输到片元着色器,并将其传输到顶点着色器。
着色器(Shader)
Shader实际上一段执行GPU上的程序,此程序使用OpenGL ES SL写语言。它是一个简单的程序,描述顶点或像素特征。在OpenGL ES中常用的shader有两种:vertex shader和fragment shader。Geometry Shader(几何着色器)是继Vertex Shader和Fragment Shader之后,由Shader Model 引入的新着色器。还有一个compute Shader由Shader Model 提供通用计算能力的着色器引入。
不同阶段的着色器可以对应不同版本GLSL。
可编程着色器简介
一、顶点着色器(Vertex Shader)
对于发送给GPU的每一个Vertex(顶点)一次执行Vertex Shader。其功能是将每个顶点在虚拟空间中的三维坐标转换为可显示在屏幕上的二维坐标,并配备z-buffer深度信息。Vertex Shader可操作的属性有:位置、颜色、纹理坐标,但不能创造新的顶点。
vertex shader主要完成以下工作:
- 基于点操作的矩阵乘法位置变换。
- 每个点的颜色值按照光照公式计算。
- 纹理坐标的生成或转换。
Vertex Shader输入数据如下:
-
Attributes: 由 vertext array 提供的顶点数据,如空间位置、法向量、纹理坐标和顶点颜色,是针对每个顶点的数据。该属性仅在顶点着色器中,片元着色器中没有属性。该属性可以理解为每个顶点的输入数据。OpenGL ES 2.0 规定了所有实现应该支持的最大属性个数不能少于 8 个。
注:Vertex Attributes 属性数据为每点。与一个index序号绑定。可通过外部程序 glBindAttribLocation将一个attribute 名与一个index绑定起来。当然,OPENGL ES 内部将自动绑定所有权attributes.只需通过外部程序 glGetAttribLocation获取指定attribute名的index。 给Attribute可通过传值 glVertexAttribPointer函数或者glVertexAttrib4fv。
-
Uniforms: uniforms只读常量数据由应用程序传输到着色器。这些数据通常是变换矩阵、光参数、颜色等。由 uniform 修饰符的变量属于全局变量,可以看到顶点着色器和片元着色器,也就是说,如果这两个着色器连接到同一个 个program Object,他们分享同一份 uniform 全局变量集。因此如果在这两个着色器中都声明了同名的 uniform 变量应确保同名变量完全相同:同名 同类型,因为它们实际上是相同的变量。此外,uniform 变量存储在常量存储区,因此限制 uniform 变量的数量,OpenGL ES 2.0 还规定了所有实现应支持的最大顶点着色器 uniform 变量数不得少于 128 个,最大的片元着色器 uniform 变量数不得少于 16 个。
-
Samplers: 一种特殊的 uniform,在vertex shader可选,用于呈现纹理。sampler 可用于顶点着色器和片元着色器。
-
Shader program: 由 main 声明的程序源代码描述了在顶点执行的操作:如坐标变换,计算光公式以生成 per-vertex 颜色或计算纹理坐标。
Vertex Shader输出为:
- Varying: varying 用于存储顶点着色器的输出数据,当然也存储片元着色器的输入数据,varying 在光栅化处理阶段,变量最终会被线性插入。如果顶点着色器声明的话 varying 在进一步传输到下一阶段之前,变量必须传输到片元着色器中,因此顶点着色器中声明 varying 变量应在片元着色器中重新声明同名同类型 varying 变量。OpenGL ES 2.0 它还规定了所有实现都应该得到最大的支持 varying 变量数不得少于 8 个。
- 至少应在顶点着色器阶段输出位置信息-即内建变量:gl_Position,每一点都是固有的Varying,表示点的空间位置。另外两个可选变量为:gl_FrontFacing 和 gl_PointSize。
二、片元着色器(Fragment Shader)
Pixel Shader众所周知(像素着色器)Fragment Shader(片元着色器)计算每个像素的颜色和其他属性。采用光值、凹凸贴图、阴影、镜面高光、半透明等处理,计算像素颜色并输出。它还可以改变像素的深度(z-buffering)或在激活多个渲染目标时输出多种颜色。一个Pixel Shader由于它只在一个像素上操作,不知道场景的几何形状,所以不能产生复杂的效果。
Fragment Shader输入数据如下:
- Varyings: 正如我前面所说,顶点着色器阶段输出 varying 变量在光栅化阶段被线性插值计算后输出到片元着色器作为其输入,即上图 gl_FragCoord,gl_FrontFacing 和 gl_PointCoord。OpenGL ES 2.0 它还规定了所有实现都应该得到最大的支持 varying 变量数不得少于 8 个。
- Uniforms: 正如前面所说,这是片元着色器的常量,如雾化参数、纹理参数等;OpenGL ES 2.0 还规定了所有实现应支持的最大片元着色器 uniform 变量数不得少于 16 个。
- Samples: 一种特殊的 uniform,用于呈现纹理。
- Shader program: 由main一段程序源代码,描述在片元上执行的操作。
FragmentShader输出为:
只有在顶点着色器阶段 varying 输出变量-即内建变量:gl_FragColor。
三、曲面细分着色器
可选着色器。包括曲面细分控制着色器(TCS,Tessellation Control Shader)用曲面细分评估着色(TES,Tessellation Evaluation Shader)。
TCS一组被称为控制点(CP,Control Points)顶点组。控制点不定义为三角形,形、五边形等多边形形式,而是定义为一个几何表面,这个表面通常由多项式来定义,而且移动其中一个控制点将会影响整个表面。这个通常在一些图形软件中,用户可以通过移动一组控制点来随意改变模型表面或者曲线形状,一组控制点通常称为一个Patch。
顶点着色与片元着色在编程上的差异
- 精度: 着色语言定了三种级别的精度:lowp, mediump, highp。我们可以在 glsl 脚本文件的开头定义默认的精度。如下代码定义在 float 类型默认使用 highp 级别的精度
precision highp float;
在顶点着色阶段,如果没有用户自定义的默认精度,那么 int 和 float 都默认为 highp 级别;而在片元着色阶段,如果没有用户自定义的默认精度,那么就真的没有默认精度了,我们必须在每个变量前放置精度描述符。此外,OpenGL ES 2.0 标准也没有强制要求所有实现在片元阶段都支持 highp 精度的。我们可以通过查看是否定义 GL_FRAGMENT_PRECISION_HIGH 来判断具体实现是否在片元着色器阶段支持 highp 精度,从而编写出可移植的代码。当然,通常我们不需要在片元着色器阶段使用 highp 级别的精度,推荐的做法是先使用 mediump 级别的精度,只有在效果不够好的情况下再考虑 highp 精度。 - attribute: 修饰符只可用于顶点着色。这个前面已经说过了。
- invariant: 或由于精度的不同,或因为编译优化的原因,在顶点着色和片元着色阶段同样的计算可能会得到不同的结果,这会导致一些问题(z-fighting)。因此 glsl 引入了 invariant 修饰符来修饰在两个着色阶段的同一变量,确保同样的计算会得到相同的值。
OpenGL ES着色语言是两种紧密关联的语言。这些语言用来在OpenGL ES处理管线的可编程处理器创建着色器。 在本文档中,除非另外说明,一个语言功能适用于所有语言,并且通用用法将把他们当做一个语言来看待。特定语言将指出它们的目标处理器:顶点(vertext)或片元(fragment)。
任何被着色器使用的OpenGL ES状态值都会自动地被跟踪并且作用于着色器上。这个自动状态跟踪机制允许应用程序为状态管理而使用OpenGL ES状态命令,并且这些状态值自动地应用在着色器上。
固定着色器简介
固定着色器是一些系统封装好的非可编程着色器
初始化着色器管理器
//没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。初始化一个渲染管理器。
GLShaderManager shaderManager = shaderManager.InitializeStockShaders();
选择着色器类型
// Use a stock shader, and pass in the parameters needed
GLint UseStockShader(GLT_STOCK_SHADER nShaderID, ...);
1.单元着色器
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
参数1: 固定着色器种类 - 单元着色器。
参数2: 颜色。
使⽤场景: 绘制默认OpenGL 坐标系(-1,1)下图形,图形所有⽚段都会以⼀种颜⾊填充。只能绘画一些图形,如三角形、矩形等,对于平移、缩放等形状变化无能为力。
2.平面着色器
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLflfloat mvp[16],GLflfloat vColor[4]);
参数1: 固定着⾊器种类 - 平⾯着⾊器。
参数2: 允许变化的4*4矩阵。
参数3: 颜色。
使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化)。使用最多的固定着色器。
3.上色着色器
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLflfloat mvp[16]);
参数1: 固定着色器种类 - 上色着色器。
参数2: 允许变化的4*4矩阵。
使用场景: 在绘制图形时,可以应用变换(模型/投影变化),颜色将会平滑的插入到顶点之间称为平滑着色。
4.默认光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLflfloat mvMatrix[16],GLflfloat pMatrix[16],GLflfloat vColor[4]);
参数1: 固定着色器种类 - 默认光源着色器。
参数2: 模型4*4矩阵。
参数3: 投影4*4矩阵。
参数3: 颜色值。
使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器会使绘制的图形产生阴影和光照的效果。
5.点光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_POINT_LIGHT_DIEF,GLflfloat mvMatrix[16],GLflfloat pMatrix[16],GLflfloat vLightPos[3],GLflfloat vColor[4]);
参数1: 固定着色器种类 - 点光源着色器。
参数2: 模型4*4矩阵。
参数3: 投影4*4矩阵。
参数4: 点光源的位置
参数5: 颜色值。
使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器会使绘制的图形产生阴影和光照的效果。它与默认光源着色器非常类似,区别只是光源位置可以是特定的。
6.纹理替换矩阵着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLflfloat mvMatrix[16],GLint nTextureUnit);
参数1: 固定着色器种类 - 纹理替换矩阵着色器。
参数2: 模型4*4矩阵。
参数3: 纹理单元。
使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器通过给定的模型视图投影矩阵,使用纹理单元来进行颜色填充,其中每个像素点的颜色是从纹理中获取。
7.纹理调整着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLflfloat mvMatrix[16],GLflfloat vColor[4],GLint nTextureUnit);
参数1: 固定着色器种类 - 纹理调整着色器。
参数2: 模型4*4矩阵。
参数3: 颜色值
参数4: 纹理单元。
使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器通过给定的模型视图投影矩阵,着色器将一个基本色乘以一个取自纹理单元nTextureUnit的纹理,将颜色与纹理进行颜色混合后才填充到片段中。
8.纹理光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLflfloat mvMatrix[16],GLflfloat pMatrix[16],GLflfloat vLightPos[3],GLflfloat vBaseColor[4],GLint nTextureUnit);
参数1: 固定着色器种类 - 纹理光源着色器。
参数2: 模型4*4矩阵。
参数3: 投影4*4矩阵。
参数4: 点光源的位置。
参数5: 颜色值(几何图形的基本色)。
参数6: 纹理单元
使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器通过给定的模型视图投影矩阵,着色器将一个纹理通过漫反射照明计算进行调整(相乘)。是一个中和了纹理、光源、颜色的综合性着色器。