OpenGL-ES 学习(10) ---- OpenGL-ES Shader语言语法
目录
- Shader 举例
- Shader 语法
- 版本规范声明
- 变量和定法方法
- 向量构造方法
- 矩阵构造方法
- 结构,数组,函数定义
- 结构
- 数组
- 函数
- 内建函数
- 条件语句和运算符
- 统一变量
- 统一变量块
- Shader 输入输出
- 插值限定符
- 预处理命令
- 精度限定符
- 不变性
Shader 举例
一个典型的简单的 Shader
程序:
const char vShaderStr[] ="#version 300 es \n""layout(location = 0) in vec4 a_position; \n""layout(location = 1) in vec4 a_color; \n""out vec4 v_color; \n""void main() \n""{ \n"" v_color = a_color; \n"" gl_Position = a_position; \n""}";
Shader 语法
版本规范声明
定义在 Shader
程序的第一行;
Shader
版本规范 没有声明版本号的默认将会使用 1.0
版本,但是3.0
版本中显然定义了更多的功能
变量和定法方法
分类 | 类型 | 描述 |
---|---|---|
浮点向量 | 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 个分量基于bool的向量类型 |
矩阵 | mat2 mat2x3 mat2x4 mat3x2 mat3 mat3x4 mat4x2 mat4 | 2-2 2-3 2-4 等不同的向量类型 |
OpenGL ES 的变量只能赋值为同类型的其他变量
或者和同类型的其他变量进行运算
举例:
float myFloat = 1.0
float myFloat2 = 1 **定义错误,类型转换错误**
bool myBool = true
int myInt = 0
int myInt2 = 0.0 **定义错误,类型转换错误**
myFloat = float(myBool) **类型转换 bool -> float**
myFloat = float(myInt) **类型转换 int -> float**
myBool=bool(myInt) **类型转换 int -> bool**
向量构造方法
定义方法 | 含义 |
---|---|
vec4 myVec4 = vec4(1.0) | vec4 myVec4 = vec4{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 = myVec3 |
vec2 myVec2 = vec2(myVec3) | myVec2 = {myVec3.x, myVec3.y} |
myVec4 = vec4(myVec2, temp) | myVec4 {myVec2.x, myVecy, temp.x, temp.y} |
矩阵构造方法
矩阵的每个分量可以用 {r, g, b, a} {x, y, z, w} {s, t, p, q}
- 矩阵分量如果只设定为一个标量参数,那么该值将会被放置在对角线上
- 矩阵可以从多个向量参数构造,
mat2
可以用两个vec2
构造 - 矩阵可以从多个标量参数构造
结构,数组,函数定义
结构
结构可以认为是C语言中的结构体的概念
struct {vec4 color;float start;float end;
} fogVar;
数组
数组与C语言类型 从 0
开始索引
float floatArray[4];
vec4 vecArray[2];
数组的构造初始化形式:
float floatArray[4] = float[](1.0, 2.0, 3.0,4.0);
float floatArray[4] = float[4](1.0, 2.0, 3.0,4.0);
vec2 c[2] = vec2[2](vec(1.0), vec2(1.0)))
函数
声明方法和C语言相同,如果函数在定义之前使用,那么必须要提供原型声明,区别在于参数的传递方法,Open-GL ES
中的限定符:
限定符 | 描述 |
---|---|
in | 没有指定时的默认限定符 这个限定值按照参数值传递,函数不能修改 |
inout | 这个限定符按照引用传入参数,在函数退出后会变化 |
out | 该变量不被传入函数,在函数返回时会被修改 |
函数不能递归
内建函数
常用的内建函数都是有的,比如 sin
,cos
等等
条件语句和运算符
举例:
if(color.a < 0.25)
条件语句中测试的表达式必须是一个 bool 值
统一变量
统一变量是应用程序通过 Open-GL ES API
传入的, Shader
只是读取 Uniform
的值
uniform mat4 viewProjMatrix;
uniform mat4 viewMatrix;
uniform vec3 lightPosition;
注意统一变量的命名空间在 VertexShader
和 PixelShader
都是共享的,也就是说,如果 VertexShader
和 PixelShader
一起链接到一个程序对象,它们就会共享同一组统一变量,如果在VertexShader
和 PixelShader
声明同一个同一变量,那么两个声明必须匹配
统一变量通常保存在硬件中,这个区域被叫做常量存储,是硬件中为存储常量值而分配的特殊空间,因为常量的大小一般是固定的,所以程序中可以使用统一变量数量受到限制,OpenGL ES 3.0
实现必须提供 256 个顶点统一向量和224 个片段统一向量
统一变量块
统一变量缓冲区对象可以通过一个缓冲区对象支持统一变量数据的存储,具备下面的优势:
- 统一变量的缓冲区数据可以在多个程序之间共享,但是只需要设置一次
- 统一变量对象可以存储大量的统一变量数据
- 在缓冲区对象之间切换比单独加载一个统一变量更加高效
Shader 输入输出
顶点输入变量用于指定 VetexShader
每个顶点的输入,用 in
关键字指定;它们通常存储位置,法线,纹理坐标和颜色 这样的数据
顶点输入是为绘制的每个顶点指定的数据;本质上,应用程序会为每个顶点创建一个顶点数组,该数组包含位置和颜色。
底层硬件通常可以在输入Vertex shader
的数量上有限制,OpenGL ES 3.0
实现可支持的最小属性为 16个
#version 300 es
uniform mat4 u_matViewProjection;
layout(location = 0) in vec4 a_position
layout(location = 1) in vec4 a_color
out vec3 v_color
void main(void) {gl_position = u_matViewProjection * a_positionv_color = a_color;
}#version 300 es
precision medium floatin vec3 v_color
layout(location = 0) out vec4 o_fragColor
void main()
{o_fragColor = vec4(v_color, 1.0)
}
插值限定符
OpenGL ES
支持两种插值
- 线性插值,平滑着色
- 平面着色
定义了顶点着色器在基本图元中的插值形式:
线性插值:
smooth out vec3 v_color
smooth in vec3 v_color
平面着色
flat out vec3 v_color
flat in vec3 v_color
预处理命令
#define
#undef
#if
#ifdef
#ifndef
#else
#elif
#endif
__LINE__
__FILE__
#version
GL_ES#error
#extension
#pragma
精度限定符
精度限定符可以用作任何基于浮点数或者整数的变量的精度,关键字为
lowp
,meidump
,highp
示例:
highp vec4 position;
varying lowp vec4 color;
mediump float specularExp;
也可以对类型指定默认精度
presision highp float;
presision medium int;
为 float
指定的精度将用作基于浮点值的变量的默认精度,
- 在
VertexShader
,没有指定默认精度,为int
和float
的值都是 highp; - 但是在
Pixel Shader
没有默认的精度值,每个Pixel Shader 必须指定一个精度
不变性
OpenGL-ES
规定的 invariant
关键字可以用于任何可变顶点的 Shader
输出;
在 Shader
编译的时候,编译器进行优化,可能导致指令的重新排序; 这种指令的重排意味着两个 Shader
之间的等价计算不能保证产生完全相同的结果,这种不一致性在多变的Shader
特效的时候尤其会有可能产生问题,在这种情况下,相同的对象会用Alpha 混合绘制在自身上方,如果计算输出位置的数值的精度不完全一样,精度差异就会产生伪像。这个对象通常表现为深度冲突(Z Fighting
),
可以将变量定义为 invariant
变量,比如:
invarient gl_positioninvarirent textCoord
一旦某个输出变量声明了不变性,编译器便保证相同的计算和 Shader
输入的条件下计算结果相同,
也可以用 #pragma
让所有的变量保持不变:
#pragma STDGL invarient(all)