android平台下OpenGL ES 3.0着色语言基础知识(上)

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版》

你可能感兴趣的:(android平台下OpenGL ES 3.0着色语言基础知识(上))