我们之前说了一下GLSL的基础知识,详情可参见Android OpenGL ES - GLSL基础篇
上一张呢我们也了解了一下纹理,实现了我们的OpenGL 的第一张图片,不过可能我们对gl_Position
,gl_Fragcolor
,texture2D ( uTexture, vCoordinate)
等一些GLSL语法不是特别熟悉,本篇博客呢,是对GLSL的一些补充,也是为后面的博客打下基础。
PS:
无特殊说明,文中的 GLSL 均指 OpenGL ES 2.0 的着色语言。
GLSL 高级篇
invariant 限定符
invariant 可以作用于顶点着色器输出的任何一个 varying 变量。
当着色器被编译时,编译器会对其进行优化,这种优化操作可能引起指令重排序(instruction reordering),指令重排序可能引起的结果是当两个着色器进行相同的计算时无法保证得到相同的结果。
例如,在两个顶点着色器中,变量 gl_Position
使用相同的表达式赋值,并且当着色程序运行时,在表达式中传入相等的变量值,则两个着色器中 gl_Position
的值无法保证相等,这是因为两个着色器是分别单独编译的。这将会引起 multi-pass 算法的几何不一致问题。
通常情况下,不同着色器之间的这种值的差异是允许存在的。如果要避免这种差异,则可以将变量声明为invariant,可以单独指定某个变量或进行全局设置。
使用 invariant 限定符可以使输出的变量保持不变。invariant 限定符可以作用于之前已声明的变量使其具有不变性,也可以在声明变量时直接作为声明的一部分,可参考以下两段示例代码:
varying mediump vec3 Color;
// 使已存在的 color 变量不可变
invariant Color;
或
invariant varying mediump vec3 Color;
以上是仅有的使用 invariant 限定符情境。如果在声明时使用 invariant 限定符,则必须保证其放在存储限定符(varying)之前。
只有以下变量可以声明为 invariant:
- 由顶点着色器输出的内置的特殊变量
- 由顶点着色器输出的 varying 变量
- 向片段着色器输入的内置的特殊变量
- 向片段着色器输入的 varying 变量
- 由片段着色器输出的内置的特殊变量
为保证由两个着色器输出的特定变量的不变性,必须遵循以下几点:
- 该输出变量在两个着色器中都被声明为 invariant
- 影响输出变量的所有表达式、流程控制语句的输入值必须相同
- 对于影响输出值的所有纹理函数,纹理格式、纹理元素值和纹理过滤必须一致
- 对输入值的所有操作都必须一致。表达式及插值计算的所有操作必须一致,相同的运算数顺序,相同的结合性,并且按相同顺序计算。插值变量和插值函数的声明,必须有相同类型,相同的显式或隐式的精度precision限定符。影响输出值的所有控制流程必须相同,影响决定控制流程的表达式也必须遵循不变性的规则。
最基本的一点是:所有的 invariant 输出量的上游数据流或控制流必须一致。
此限定符情境比较少,这里就一笔带过了
内置变量
顶点着色器(Vertex Shader)内置变量
内置变量(输出) | 描述 | 单位或坐标系 |
---|---|---|
highp vec4 gl_Position; | 变换后的顶点位置 | 裁剪坐标系Vclip |
mediump float gl_PointSize; | 变换后的点大小(仅仅表达光栅化后点的大小) | 像素 |
gl_Position
,此变量用于写入齐次顶点位置坐标。一个完整的顶点着色器的所有执行命令都应该向此变量写入值。该值的输入同时也是图元装配、剪切(clipping)、剔除(culling)等对于图元的固定功能操作中的输入值。其决定了一个几何图形的位置与形状。
片段着色器(Fragment Shader)内置变量
内置变量(输入) | 描述 | 单位或坐标系 |
---|---|---|
mediump vec4 gl_FragCoord; | 片段在帧缓冲区窗口坐标内的位置 | 窗口坐标系 |
bool gl_FrontFacing; | 片段是否属于正面图元 | Bool |
mediump int gl_PointCoord | 片段所在点图元的二维坐标 | 范围是0.0到1.0 |
片段着色器可以写入gl_FragColor或gl_FragData []的一个或多个元素,但不能同时写入两者。gl_FragData数组的大小由内置常量gl_MaxDrawBuffers给出。
内置变量(输出) | 描述 | 单位或坐标系 |
---|---|---|
mediump vec4 gl_FragColor; | 片段颜色 | RGBA color |
mediump vec4 gl_FragData[n] | 用于颜色附件n的片段颜色 | RGBA color |
uniform 状态变量
GLSL 中还有一种内置的 uniform 状态变量, gl_DepthRange
它用来表明全局深度范围。
结构如下:
struct gl_DepthRangeParameters {
highp float near; // n
highp float far; // f
highp float diff; // f - n
};
uniform gl_DepthRangeParameters gl_DepthRange;
除了 gl_DepthRange 外的所有 uniform 状态常量都已在 GLSL 1.30 中废弃。
内置常量
内置常量 | 描述 | 最小值 |
---|---|---|
const mediump int gl_MaxVertexAttribs | 表示在vertex shader(顶点着色器)中可用的最大attributes数.这个值的大小取决于 OpenGL ES 在某设备上的具体实现,但不小于最小值 | 8 |
const mediump int gl_MaxVertexUniformVectors | 表示在vertex shader(顶点着色器)中可用的最大uniform vectors数. 这个值的大小取决于 OpenGL ES 在某设备上的具体实现,但不小于最小值 | 128 |
const mediump int gl_MaxVaryingVectors | 表示在vertex shader(顶点着色器)中可用的最大varying vectors数. 这个值的大小取决于 OpenGL ES 在某设备上的具体实现,但不小于最小值 | 8 |
const mediump int gl_MaxVertexTextureImageUnits | 表示在vertex shader(顶点着色器)中可用的最大纹理单元数(贴图). 这个值的大小取决于 OpenGL ES 在某设备上的具体实现, 甚至可以一个都没有(无法获取顶点纹理) | 0 |
const mediump int gl_MaxCombinedTextureImageUnits | 表示在 vertex Shader和fragment Shader总共最多支持多少个纹理单元. 这个值的大小取决于 OpenGL ES 在某设备上的具体实现,但不小于最小值 | 8 |
const mediump int gl_MaxTextureImageUnits | 表示在 fragment Shader(片元着色器)中能访问的最大纹理单元数,这个值的大小取决于 OpenGL ES 在某设备上的具体实现,但不小于最小值 | 8 |
const mediump int gl_MaxFragmentUniformVectors | 表示在 fragment Shader(片元着色器)中可用的最大uniform vectors数,这个值的大小取决于 OpenGL ES 在某设备上的具体实现,但不小于最小值 | 16 |
const mediump int gl_MaxDrawBuffers | 表示可用的drawBuffers数,在OpenGL ES 2.0中这个值为1, 在将来的版本可能会有所变化 | 1 |
内置函数
OpenGL提供了很多的内置函数,这些函数我们之后会经常用到,我们现在只贴出关于这些函数的官方文档说明,这对我们来说已经足够了,至于每个函数的实践,我们以后会在之后的博客中亲身体会。
小结
本章作为见Android OpenGL ES - GLSL基础篇的补充,可作为工具文档时而进行查阅。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。