OpenGL ES 2.0编程指导阅读笔记(五)OpenGL ES Shading Language
变量和变量类型
计算机图形学中,两种基本的数据类型形成了变换的基础---向量和矩阵。这两种数据类型也是OpenGL ES Shading Language的中心,其标量、向量、矩阵数据类型如下:
变量类别 | 类型 |
---|---|
标量 | float,int, bool |
浮点向量 | float,vec2,vec3,vec4 |
整型向量 | int,ivec2,ivec3,ivec4 |
布尔向量 | bool,bvec2,bvec3,bvec4 |
矩阵 | mat2,mat3,mat4 |
注意:矩阵都是浮点型的,且行列数相等。
变量构造函数
OpenGL ES Shading Language对于类型转换有非常严格的规则,变量仅能赋值给同类型的变量,也仅可以和同类型的变量进行运算。类型变换则需要通过构造函数实现。
向量同样通过构造函数来初始化和类型转换。
- 当传递一个标量给向量构造函数时,它被赋值给向量所有分量。
- 当传递多个标量或一个向量给向量构造函数时,它会从低到高依次赋值。
- 当传递多个标量给构造函数时,其数量最少不少于向量的分量数。
对于矩阵构造函数:
- 当传递一个标量时,构造该标量的单位矩阵;
- 可以通过多个向量来构造矩阵;
- 可以通过多个标量来构造矩阵。
- 只要数据个数足够,可以通过任意标量和向量组合来构造矩阵。
OpenGL ES以列优先的方式存储矩阵,因此构造矩阵时,数据被按列映射。
向量和矩阵分量
可以使用"."操作符或下标来访问向量分量。
可以使用{x,y,z,w}、{r,g,b,a}、{s,t,r,q}(称为swizzle)来表示向量的第1、2、3、4个分量。
这来自向量、颜色、纹理坐标的通常表示。
实际使用中,可以使用任何一种,但是不能混用。
注意,OpenGL ES 2.0不强制要求支持动态索引,即以非uniform的变量作为下标。
矩阵的分量可以通过下标取出其分量,然后将该分量视作向量使用。
常量
常量必须在声明时初始化。
结构体
当定义一个结构体之后,就定义了一个具有和该类型相同名称的构造函数。
数组
许多OpenGL ES实现不支持使用编译时未知的变量作为索引,除非该变量是uniform。
OpenGL ES Shading Language没有在创建时就对数组进行初始化的语法,仅能之后对各个分量分别初始化。
操作符
操作符的用法与C语言基本相同,除了部分操作符可以是浮点、向量、矩阵之间混用。
函数
函数的用法与C语言基本相同,除了OpenGL ES Shading Language采用in、inout、out(称为参数修饰符,parameter qualifier)来表示一个变量是否能被函数所修改,变量默认是in。
需要注意的是,OpenGL ES Shading Language中函数不能是迭代的。
内建函数
参见附件B。
控制流语句
控制流语句的条件必须是布尔值或者结果为布尔值的表达式。
OpenGL ES中的for循环的使用有非常严格的限制:
- 必须有编译时可确定的迭代次数
- 必须仅有一个循环变量
- 循环变量必须使用简单的语句增减(i++、i--、i+=constant、i-=constant)
- 结束条件必须是循环索引和一个常量表达式的比较
- 循环内不得改变迭代器的值
- 不要求硬件必须支持循环
- 要求循环可以被编译器展开
Uniform
Uniform变量是保存应用通过OpenGL ES 2.0 API传递给shader的只读数值的变量。
基本上,所有对所有顶点或片元不变的但编译时未知shader的参数都应以uniform的方式传递。
Uniform在全局命名域声明并且要求有uniform修饰符。
注意:
- Uniform变量的命名域对vertex和fragment shader是共享的。
- 硬件支持的Uniform变量数量是有限的,可以通过GL_MAX_VERTEX_UNIFORM_VECTORS和GL_MAX_FRAGMENT_UNIFORM_VECTORS查询。OpenGL ES 2.0要求最少支持128个vertex uniform vector和16个fragment uniform vector。
Attribute
Attribute变量仅能在vertex shader中使用,用来指定每个顶点独有的数据给vertex shader。
硬件支持的attribute数量是有限的,可以通过GL_MAX_VERTEX_ATTRIBUTES来查询。OpenGL ES 2.0要求最少支持8个attribute。
Vraying
Varying变量用来保存vertex shader的输出、fragment的输入,需要varying类型修饰符。
Vraying数量同样有限,可以通过GL_MAX_VARYING_VECTORS查询。OpenGL ES 2.0要求最少支持8个Varying。
预处理器和导语
多数行为和C语言一致。
#error会在编译时引起一个错误。
#pragma用于指定特定实现用的导语。
#version用于指示编译器语言的版本,对于OpenGL ES Shading Language v1.00,使用100
#extension用于指定扩展的行为,可以是require、enable、warn、disable
Uniform和Vraying打包
为了节省物理存储的使用,uniform和varying会被打包。假设存储空间被组织成列数为4的阵列,每列可以存储一个向量分量。
打包遵循以下原则:
- 变量打包后生成的代码复杂度依然是常数
- 即,不会重新排序,这会要求生成额外的指令来拼接未打包数据
- 打包不会导致性能的损失
精度修饰符
精度修饰符使得shader编写者可以指定shader变量执行的计算的精度,对于某些实现来说,这样可以获得更好的性能和更低的功耗。
OpenGL ES Spec并未要求多精度计算必须支持,因此,实现中忽略精度修饰符然后将所有计算都按最高精度来进行也是可以的。
精度修饰符有lowp、mediump、highp三种。可以用precision lowp/mediump/highp int/float来指定默认的精度修饰符。
Vertex shader中变量的默认精度为highp,fragment shader中没有默认精度,必须指定,且OpenGL ES 2.0并不要求fragment shader一定要支持highp精度。
另外,需要注意不同的实现中,精度修饰符代表的范围和精度是不同的。
Invariance
invariant修饰符可以用在vertex shader的任意varying输出上。
编译器编译时可能进行优化,对指令重新排序。指令的重新排序可能导致等效的指令在不同shader上产生不同的结果,而在multipass shader等场景下在同一物体上绘制自身时,这可能引起z fighting。
Invariance的引入使得shader编写者可以指定当某个变量用于计算输出时,其值需要严格一致。
本文作者:xvsay
本文链接:https://www.cnblogs.com/belatedluck/p/17050420.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步