OpenGL ES2 学习教程4——Shader语言

shader语言能够当作是特殊的C语言,专门用来建立顶点片断着色器程序的语言。像第二节里的程序数组

// vertex shader
attribute vec4 vPosition;
void main() {
  gl_Position = vPosition;
}
// fragment shader
precision mediump float;
void main() {
  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}

基本类型

  • 标量 float int boolapp

  • 浮点矢量 float vec2 vec3 vec4函数

  • 整数矢量 int ivec2 ivec3 ivec4工具

  • 布尔矢量 bool bvec2 bvec3 bvec4oop

  • 矩阵 mat2 mat3 mat4(分别是22,33,4*4的浮点型矩阵)性能

  • void类型(表示没函数返回或空的参数)void测试

  • 采样器(用于指定纹理)sampler2D samplerCube优化

结构体和数组

struct type-name { // 结构体不支持嵌套
    members
} struct-name;  // 结构体也能够声明为数组,struct-name[]

float foo[3];
// 只支持一维数组

修饰符(限定符)

  • none 默认限定符:默认定义变量都是none,局部可读写变量或参数。ui

  • const 常量限定符:编译时的常量,或表示只读的函数参数,结构体的成员不能声明为常量,结构体变量能够。code

  • attribute 属性限定符:能够由应用程序指定经过GLES传给顶点着色器的每个顶点数据,只能用在顶点着色器。值为只读,只能被是定为float vec2 vec3 vec4 mat2 mat3 mat4,不能被定义为数组和结构体。GLES规定至少支持8个属性,每一个属性被存储为4个份量的存储单元,所以能够将float这样的变量组合为一个vec4来节约空间。典型的被用来储存位置、法线、贴图坐标和颜色数据。着色器里被声明为属性的变量是只读资源,不能被修改。

  • uniform 全局限定符:在图元处理期间不会被改变的值,能够由应用程序经过GLES传给顶点片断着色器的全局变量。被全部的着色器共享。uniform存储各类着色器须要的数据,例如:转换矩阵、光照参数或者颜色。基本上各类输入着色器的常量参数像顶点和片断(但在编译时并不知道)都应该是uniform。他们在硬件中被放在称为“常量存储区(constant store)“中。一样它也有数量限制的,GLES规定至少128个顶点着色器uniform和16个片断着色器uniform。

  • varying 易变限定符:通过插值的易变变量,由顶点着色器传给片断着色器,易变变量在顶点着色器和片断着色器中要使用相同的类型和名字。只有在片断着色器中静态使用的易变变量才须要在顶点着色器中成对定义。不能用结构体定义,只能声明为浮点型标量,矢量和矩阵。一样有数量限制。包括属性和全局变量最大值都由glGetIntegerv查询(GL_MAX_VERTEX_ATTRIBUTE,GL_MAX_VERTEX_UNIFORM_VECTORS,GL_MAX_FRAGMENT_UNIFORM_VECTORS,GL_MAX_VARYING_VECTORS)。

GLint maxVertexAttribs;
GLint maxVertexUniforms;
GLint maxFragmentUniforms;
GLint maxVaryings;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs); 
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &maxVertexUniforms);
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &maxFragmentUniforms);
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
//在我手机上的输出:
//I/GLES-Tutorial(18378): maxVertexAttribs: 16
//I/GLES-Tutorial(18378): maxVertexUniforms: 256
//I/GLES-Tutorial(18378): maxFragmentUniforms: 224
//I/GLES-Tutorial(18378): maxVaryings: 16

构造器

shader语言有着很是严格的类型判断,不支持隐式转化,类型的转化必须用构造器。

float fA = 1.0;
bool bB = true;
int iC = 0;
fA = float(bB); // convert bool to float

vec4 myVec4 = vec4(1.0); // myVec4 = {1.0, 1.0, 1.0, 1.0}
vec3 myVec3 = vec3(1.0, 0.0, 0.5);
vec3 temp = vec3(myVec3);

struct light {
    float intensity;
    vec3 position;
};
light lightVar = light(3.0, vec3(1.0));

份量

矢量的份量名称:{x,y,z,w}表示顶点; {r,g,b,a}表示颜色;{s,t,p,q}表示纹理坐标。

每一个份量用点号链接(例如v2.x(一个float变量),v3.rg(一个vec2变量))。

不一样组的份量不能混合使用(例如v4.xgba不合法),可是顺序能够任意,能够重复(例如v3.yyxx(一个vec4变量)),但不能超过4个,由于编译器不知道转化成什么类型(例如v4.xyzwxy不合法)。

矩阵的份量就是用下标表示,注意的是矩阵是以列优先的。

mat4 m;
m[1] = vec4(1.0); // 矩阵第二列设置为{1.0, 1.0, 1.0, 1.0}
m[2][0] = 1.0;

操做符

和C语言相似,可是更加严格。执行操做的变量必须是相同的基本类型,二进制运算加减乘除必须是浮点型或整型。

函数

函数参数须要加上限定词,指示这个变量是否可以被函数修改。

举个栗子:

vec4 myFunc(inout float myFloat, // inout parameter 
            mat4 myMat4,         // in parameter (default)
            out vec4 myVec4);    // out parameter
  • in 默认修饰符,表示为输入,不能被函数修改

  • inout 表示为引用,能够被修改

  • out 表示不是函数输入,它的值在函数返回后将被修改

shader语言提供许多内置函数,例如dot

流程控制语句

Shader语言支持简单的if-else;可是条件结果必须是布尔值。

循环语句限制很是严格:必须有循环迭代变量,他必须是增长或减小的,中止的条件必须匹配索引而且为常量表达式,在循环内部不能改变迭代的值。这些限制使得编译器可以把循环语句展开。

// 合法的栗子
for (int i = 0; i < 5; i++)
{
    sum += i;
}
// 不合法的栗子1
float myArray[5];
for (int i = 0; i < 5; i++)
{
    sum += myArray[i] // 不容许出现很是量表达式
}
// 不合法的栗子2
uniform in loopIter;
for (int i = 0; i < loopIter; i++) // 中止条件不是常量表达式
{
    sum += i;
}

预处理指令

#define  #undef  #if  #ifdef  #ifndef  #else  #elif  #endif
__LINE__    // 在着色器中的当前行号
__FILE__    // GLES2中老是0
__VERSION__ // GLES的版本 (e.g., 100)
GL_ES       // 被定义为1

#version 100   // GLES Shading Language v1.00, 老是要放在最开头

#extension extension_name : behavior
// behavior能够是require, enable, warn,disable
#extension GL_OES_texture_3D : enable  // 若是3D贴图扩展不被支持让预编译产生警告

注意和C++不一样,宏不能带参数。

精度控制

精度控制可以被使用在任何浮点和整型数变量。能够设置为高highp,中mediump,低lowp。

highp vec4 position;
varying lowp vec4 color;
// 默认的精度能够这么设置在头部
precision highp float;
precision mediump int;

不变性

GLES中,invariance是被用于任何顶点着色器的变量输出的关键字。因为着色器编译时可能进行优化,一些指令被从新整理,可能两个着色器中间相同的计算产出不一样的值来。在多通道着色器的特殊状况下,一样的物体使用透明混合(alpha blending)来绘制时能形成清晰度的不一样。引入invariance,着色器会让一样的输入计算后输出的值相同。

invariant gl_Position;  // 声明不变性输出

// 可使用#pragma来保证全局变量的不变性
#pragma STDGL invariant(all)  // 它将限制编译器的优化,除非必要最好不用,会致使性能降低

编辑工具

在Mac下可使用Shader Builder(apple-opengl找到 graphics tools的连接,去下载对应你XCode版本的)来编写、运行、测试OpenGL shaders

相关文章
相关标签/搜索