OpenGL ES 3.0学习实践
- android平台下OpenGL ES 3.0从零开始
- android平台下OpenGL ES 3.0绘制纯色背景
- android平台下OpenGL ES 3.0绘制圆点、直线和三角形
- android平台下OpenGL ES 3.0绘制彩色三角形
- android平台下OpenGL ES 3.0从矩形中看矩阵和正交投影
- android平台下OpenGL ES 3.0着色语言基础知识(上)
- android平台下OpenGL ES 3.0着色语言基础知识(下)
- android平台下OpenGL ES 3.0实例详解顶点属性、顶点数组
- android平台下OpenGL ES 3.0实例详解顶点缓冲区对象(VBO)和顶点数组对象(VAO)
- android平台下OpenGLES3.0绘制立方体的几种方式
本篇整理自《OpenGL ES 3.0 编程指南第2版》
着色器版本规范
OpenGL ES 3.0 顶点着色器
和片段着色器
的第1行总是声明着色器版本。声明着色器版本通知着色器编译器
预期在着色器中出现的语法和结构。编译器按照声明的着色语言版本检查着色器语法
。采用如下语法声明着色器使用OpenGL ES
着色语言3.00
版本:
#version 300 es
没有声明版本号的着色器被认定为使用OpenGL ES着色语言的1.00版本
。着色语言的1.00版本
用于OpenGLES2.0
。对于OpenGLES3.0
,作者决定匹配API和着色语言的版本号,这就是版本号从1.00跳到3.00
的原因。
变量和变量类型
在计算机图形中,两个基本数据类型组成了变换的基础:向量和矩阵。这两种数据类型 在OpenGLES着色语言中也是核心。
OpenGLES着色语言中的数据类型
变置分类 | 类 型 | 描 述 |
---|---|---|
标量 | float,int,uint,bool | 用于浮点、整数、无符号整数和布尔值的基于标标量的数据类型 |
浮点向量 | float,vec2,vec3,vec4 | 有1、2、3、4个分量的基于浮点的向量类型 |
整数向量 | int,ivec2,ivec3,ivec4 | 有1、2、3、4个分量的基于整数的向量类型 |
无符号整数向量 | uint,uvec2,uvec3,uvec4 | 有1、2、3、4个分量的基于无符号整数的向量类型 |
布尔向量 | bool,bvec2,bvec3,bvec4, | 有1、2.3、4个分量的基于布尔的向量类型 |
矩阵 | mat2(或mat2x2),mat2x3,2x2,2x3,2x4,3x2,3x3,3x4,4x2,4x3mat2x4,mat3x2, mat3(或mat3x3),mat3x4,mat4x2,mat4x3,mat4(或mat4x4) |
着色语言中的变量必须以某个类型声明。例如,下面的声明描述如何声明
一个标量、一 个向量和一个矩阵
:
vec4 vPosition;
mat4 mMatirx;
vec2 vOffset;
变量可以在声明时或者声明以后初始化。初始化通过使用构造器进行,构造器也用于类
型转换。
变量构造器
OpenGLES
着色语言在类型转换方面有非常严格的规则。也就是说变量只能陚值为相同类型的其他变量
或者与相同类型的变量进行运算。
来看看如何使用构造器初始化和转换标量值。
float myFloat = 1.0;
float myFloat2 = 1; //ERROR: 整数类型转换浮点类型错误
bool myBool = true;
int mylnt = 0;
int mylnt2 = 0.0; // ERROR: 浮点类型转换整数类型错误
myFloat = float(myBool); // 布尔值转换为浮点型
myFloat = float(mylnt); // 整型转换为浮点型
myBool = bool(mylnt); // 整型转换为布尔值
构造器可以用于转换和初始化向量数据类型。向量构造器的参数将被转换为与被构造的向量相同的基本类型(float、int或bool)。向量构造器的参数传递有两种基本方法:
- 如果只为向量构造器提供一个标量参数,则该值用于设置向量的所有值。
- 如果提供了多个标量或者向量参数,则向量的值从左到右使用这些参数设置。如果提供了多个标量参数,那么在向量中必须有至少和参数中一样多的分量。
构造向量的例子:
vec4 myVec4 = vec4(1.0); // myVec4 = {l.0, 1.0, 1.0, 1.0}
vec3 myVec3 = vec3(1.0,0.0,0.5);// myVec3 = {1.0, 0.0, 0.5}
vec3 temp = vec3(myVec3); // temp = myVec3
vec2 myVec2 = vec2(myVec3); // myVec2 = {myVec3.x,myVec3.y}
myVec4 = vec4(myVec2, temp); //myVec4 » {myVec2.x,myVec2.y,temp.x,temp.y}
下面是构造矩阵的一些基本规则:
- 如果只为矩阵构造器提供一个标量参数,则该值被放在矩阵的对角线上。例如:
mat4(1.0)
将创建一个4 x 4
的单位矩阵。 - 矩阵可以从多个向量参数构造。例如:
mat2可以从两个vec2构造
。 - 矩阵可以从多个标量参数构造一每个参数代表矩阵中的一个值,从左到右使用。矩阵的构造比刚才说明的基本规则更灵活,只要在矩阵初始化时提供足够多的分量,矩阵基本上可以从任何
标量和向量
的组合构造。OpenGLES中的矩阵以列优先顺序存储
。使用矩阵构造器时,参数按列填充矩阵。
mat3 myMat3 = mat3(1.0, 0.0, 0.0, //第一列
0.0, 1.0, 0.0, //第二列
0.0, 1.0, 1.0);//第三列
向量和矩阵分量
向量的单独分量可以用两种方式访问:
使用
'.'
运算符或者通过数组下标。根据组成向量的分量数,每个分量可以通过使用{x,y,z,w}
、{r,g,b,a}
或者{s,t,p,q}
组合访问。3种不同命名方案的原因是向量可以互换地用于表示数学上的向量、颜色和纹理坐标。
使用运算符时,可以在操作中重新排列向量的分量:
vec3 myVec3 = vec3(0.0, 1.0, 2.0); // myVec3 = {0.0, 1.0, 2.0}
vec3 temp;
temp = myVec3.xyz; // temp = {0.0, 1.0, 2.0}
temp = myVec3.xxx; // temp = {0.0, 0.0, 0.0}
temp = myVec3.zyx; // temp = {2.0, 1.0, 0.0}
除了
'.'
运算符之外,向量还可以使用数组下标"[]"
运算符访问。在数组下标中,元素[0]
对应于x
,元索[1]对应于y
,等等。
矩阵被看成由一些向量组成。例如:mat2可以看作两个vec2,mat3可以看作3个vec3
,等等。
对于矩阵,单独的列可以用数组下标运算符"[]"
选择,然后每个向量可以通过向量访问行为来访问。
mat4 myMat4 = mat4(1.0); // 将对角线初始化为1.0
vec4 myVec4 = myMat4[0]; // 从矩阵中获取myVec4向量
float m1_1 = myMat4[1][1]; // 在矩阵中获取 [1][1]处的元素
float m2_2 = myMat4[2][2]; // 在矩阵中获取 [2][2]处的元素
常量
可以将任何基本类型声明为常数变量。常数变量是着色器中不变的值。声明常量时,在声明中加入const限定符
。常数必须在声明时初始化。
const float zero = 0.0;
const float pi = 3.14159;
const vec4 red = vec4(0.0, 0.0, 1.0);
const mat4 identity = mat4(1.0);
正如在C或者C++中那样,声明为const的变量是只读的,不能在源代码中修改。
结构
除了使用语言中提供的基本类型之外,还可以和c语言一样将变量聚合成结构
。 OpenGL ES
着色语言中声明结构的语法如下例所示:
struct fogStruct
{
vec4 color;
float start;
float end;
} fogVar;
上述定义的是一个名为fogStruct
的新结构类型和一个新变量fogVar
。
结构可以用构造器初始化。在定义新的结构类型之后,也用与类型相同的名称定义一个新的结构构造器。结构中的类型和构造器中的类型必须是一对一的。
struct fogStruct
{
vec4 color;
float start;
float end;
} fogVar;
//构造初始化
fogVar = fogStruct(vec4(0.0, 1.0, 0.0, 0.0), //初始化颜色
0.5, //初始化 start
2.0); //初始化end
数组
数组的语法与C语言很相似,索引从0开始。数组可以用数组初始化构造器初始化
float a[4] = float[](1.0, 2.0, 3.0, 4.0);
float b[4] = float(4](1.0, 2.0, 3,0, 4.0);
vec2 c[2] = vec2[2](vec2(1.0), vec2(1.0));
函数
函数的声明方法和C语言中相同。如果函数在定义前使用,则必须提供原型声明。 OpenGLES着色语言函数和C语言函数的最明显的不同之处在于函数参数的传递方法。 OpenGLES着色语言提供特殊的限定符,定义函数是否可以修改可变参数。
OpenGL ES
中也提供了很多内建函数
。
限定符 | 描述 |
---|---|
in | (没有指定时的默认限定符) 这个限定符指定参数按值传送,函数不能修改 |
inout | 这个限定符规定变量按照引用传入函数,如果该值被修改,它将在函数退出后变化 |
out | 这个限定符表示该变量的值不被传入函数,但在函数返冋时将被修改 |
注意:
函数不能递归。GPU没有堆栈。
控制流语句
OpcnGL ES着色语言中的控制流语句的语法类似于C语言。
if(color.a < 0.25){
color *= color.a;
}
else{
color = vec4(0.0);
}
条件语句中测试的表达式求出的必须是一个布尔值。
参考
《OpenGL ES 3.0 编程指南第2版》