你的位置:首页 > 操作系统

[操作系统]OpenGL ES 3.0之Shading Language(八)


每个OpenGL ES 3.0程序要求一个顶点着色器和一个片段着色器去渲染一个图形。着色器概念是API 的中心,本篇将介绍着色器语言部分包含下面几项

  1、变量和变量类型
  2、矢量和矩阵创建及选择
  3、常量
  4、结构和阵列
  5、运算符、流控制和函数
  6、属性、只读变量和变量
  7、预处理和指令
  8、只读变量和变量压缩
  9、精度控制和不变性

一、变量和变量类型

  计算机图形学中,转换有两种基本的数据类型:矢量和矩阵。下图是OpenGL ES 着色器编程语言数据类型

                        

 

 变量可以在声明时初始化,或以后初始化,初始化是通过构造函数进行,也可做类型转换。

        

float myFloat = 1.0;float myFloat2 = 1; // ERROR: invalid type conversionbool myBool = true;int myInt = 0;int myInt2 = 0.0; // ERROR: invalid type conversionmyFloat = float(myBool); // Convert from bool -> floatmyFloat = float(myInt); // Convert from int -> floatmyBool = bool(myInt); // Convert from int -> bool

矢量同样可以转换

  

vec4 myVec4 = vec4(1.0); // myVec4 = {1.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 = myVec3vec2 myVec2 = vec2(myVec3); // myVec2 = {myVec3.x,// myVec3.y}myVec4 = vec4(myVec2, temp); // myVec4 = {myVec2.x,// myVec2.y,// temp.x, temp.y}

矩阵转换

  

mat3 myMat3 = mat3(1.0, 0.0, 0.0, // First column0.0, 1.0, 0.0, // Second column0.0, 1.0, 1.0); // Third column

 

二、矢量和矩阵元素

矩阵元素能够通过两种方式获取,使用“.”操作符或者数组下标。依据被给的元素的组成,每个被给的矩阵都能使用{x, y, z, w}, {r, g, b, a},或{s, t, r, q}表示。使用三种不同的命名表是因为有三种坐标顶点、颜色和贴图。x, r, 或s 表示矩阵里的第一个元素,不同的命名方式仅仅是为了使用方便。或者说你可以使用矩阵时混合使用矩阵命名方式,(但不能使用.xgr,只能一次使用一种命名规则)。当使用“.”时,你也可以重新排列一个矩阵。例如,

  

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 被考虑是两个vec2s,mat3 是3 个vec3s。对矩阵,单独的列被使用列下标[]选中。下面是例子:

mat4 myMat4 = mat4(1.0); // Initialize diagonal to 1.0(identity)vec4 colO = myMat4[0]; // Get colO vector out of the matrixfloat ml_l = myMat4[1][1]; // Get element at [1][1] in matrixfloat m2_2 = myMat4[2].z; // Get element at [2][2] in matrix

 

三、常量

  常量是在着色器中不可改变的数据类型。使用const修饰,必须在声明时初始化。

const float zero = 0.0;const float pi = 3.14159;const vec4 red = vec4(1.0, 0.0, 0.0, 1.0);const mat4 identity = mat4(1.0);

 

四、结构和数组

   结构

 像C 语言一样,可以集合几种变量成为结构。在OpenGL ES 结构如下:

struct fogStruct{  vec4 color;  float start;  float end;} fogVar;

这将产生新的变量类型fogStruct,和新的变量名fogVar。使用能够初始化构造函数变量。定义一个结构类型,定义一个结构,一个同名的构造函数也被定义,必须是一对一的。上面的结构能够被使用下面的语法初始化:

 

fogVar = fogStruct(vec4(0.0, 1.0, 0.0, 0.0), // color0.5, // start2.0); // end

结构的构造基于结构的类型,它把每个成员做输入参数。访问结构中的元素和C 语言相同。

vec4 color = fogVar.color;float start = fogVar.start;float end = fogVar.end;

  

  数组

OpenGL ES 数组语法和C 语言非常类似,索引以0 开始。下面是创建数组的例子:

 

float floatArray[4];vec4 vecArray[2];

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 语言非常类似。但OpenGL ES 语法有严格的语法限制,执行运算符的变量必须有相同的类型,二进制运算符(*, /, +, -)必须是浮点变量或者是整型变量。乘运算符能够在浮点、矢量、矩阵的组合中运行。例如:

 

float myFloat;vec4 myVec4;mat4 myMat4;myVec4 = myVec4 * myFloat; // Multiplies each component of myVec4// by a scalar myFloatmyVec4 = myVec4 * myVec4; // Multiplies each component of myVec4// together (e.g., myVec4 ^ 2 )myVec4 = myMat4 * myVec4; // Does a matrix * vector multiply of// myMat4 * myVec4myMat4 = myMat4 * myMat4; // Does a matrix * matrix multiply of// myMat4 * myMat4myMat4 = myMat4 * myFloat; // Multiplies each matrix component by// the scalar myFloat

比较运算符(==, !=, <, etc.)仅能够执行标量,矢量有专门的比较函数

 

六、函数

函数声明和C 语言一样,函数使用前,必须定义,它的原型必须给出。使用时非常类似C 语言。不同是参数使用上,提供特殊的变量限定词,指示变量是否能够被函数修改。那些限定词如下表:

使用如下:

vec4 myFunc(inout float myFloat, // inout parameterout vec4 myVec4, // out parametermat4 myMat4); // in parameter (default)

散射光计算函数。

vec4 diffuse(vec3 normal,vec3 light,vec4 baseColor){  return baseColor * dot(normal, light);}

OpenGL ES 函数不能递归,原因是一些编译工具执行这个函数时,这会让这个函数在线执行,最后使GPU 产生问题。

着色器语言也提供了内置函数。下面的例子是,在片段着色器中计算基本反射光的着色器代码。

float nDotL = dot(normal , light);float rDotV = dot(viewDir, (2.0 * normal) * nDotL C light);float specular = specularColor * pow(rDotV, specularPower);

 

七、流控制声明

   控制语句语法和C 类似,if-then-else 逻辑也被使用,例如:

  

if(color.a < 0.25){  color *= color.a;}else{  color = vec4(0.0);}

条件表达式的结果必须是布尔值。或者说表达式基于布尔值计算,或者计算结果是布尔值(例如比较运算)。

 

八、Uniforms

  Uniform

  是变量类型的一种修饰符。。uniform 是OpenGL ES  中被输入着色器的只读值。。uniform被使用存储各种着色器需要的数据,例如:转换矩阵、光照参数或者颜色。基本上各种输入着色器的常量参数像顶点和片段(但在编译时并不知道)应该是uniform。uniform 应该使用修饰词被声明为全局变量,如下:

uniform mat4 viewProjMatrix;uniform mat4 viewMatrix;uniform vec3 lightPosition;

uniform 的空间被顶点着色器和片段着色器分享。也就是说顶点着色器和片段着色器被链接到一起进入项目,它们分享同样的uniform。因此一个在顶点着色器中声明的uniform,相当于在片段着色器中也声明过了。当应用程序装载uniform 时,它的值在顶点着色器和片段着色器都可用。

另一个需要注意的是,uniform 被存储在硬件被称为常量存储,这是一种分配在硬件上的存储常量值的空间。因为这种存储需要的空间是固定的,在程序中这种uniform 的数量是受限的。这个限制能通过读gl_MaxVertexUniformVectors 和gl_MaxFragmentUniformVectors编译变量得出。( 或者用GL_MAX_VERTEX_UNIFORM_VECTORS 或GL_MAX_FRAGMENT_UNIFORM_ VECTORS 为参数调用glGetIntegerv)OpenGL ES 2.0必须至少提供256 个顶点着色器uniform 和224个片段着色器uniform。但可以更多,

  Uniform Blocks

  

uniform TransformBlock{mat4 matViewProj;mat3 matNormal;mat3 matTexGen;};layout(location = 0) in vec4 a_position;void main(){gl_Position = matViewProj * a_position;}