大家好,接着上节继续为大家介绍OpenGL ES 3.x 着色器语言:shader language 。
8、运算符
优先级(越小越高) | 运算符 | 说明 | 结合性 |
---|---|---|---|
1 | () | 聚组:a*(b+c) | N/A |
2 | [] () . ++ -- | 数组下标__[],方法参数__fun(arg1,arg2,arg3),属性访问__a.b__,自增/减后缀__a++ a--__ | L - R |
3 | ++ -- + - ! | 自增/减前缀__++a --a__,正负号(一般正号不写)a ,-a,取反__!false__ | R - L |
4 | * / | 乘除数学运算 | L - R |
5 | + - | 加减数学运算 | L - R |
7 | < > <= >= | 关系运算符 | L - R |
8 | == != | 相等性运算符 | L - R |
12 | && | 逻辑与 | L - R |
13 | ^^ | 逻辑排他或(用处基本等于!=) | L - R |
14 | || | 逻辑或 | L - R |
15 | __? :__ | 三目运算符 | L - R |
16 | = += -= *= /= | 赋值与复合赋值 | L - R |
17 | , | 顺序分配运算 | L - R |
左值:表示一个储存位置,可以是变量,也可以是表达式,但表达式最后的结果必须是一个储存位置。
右值:表示一个值, 可以是一个变量或者表达式再或者纯粹的值。
操作符的优先级:决定含有多个操作符的表达式的求值顺序,每个操作的优先级不同。
操作符的结合性:决定相同优先级的操作符是从左到右计算,还是从右到左计算。
9、函数参数限定符
函数的参数默认是以拷贝的形式传递的,也就是值传递,任何传递给函数参数的变量,其值都会被复制一份,然后再交给函数内部进行处理.。我们可以为参数添加限定符来达到传递引用的目的,OpenGL提供的参数限定符如下:
限定符 | 说明 |
---|---|
< none: default > | 默认使用 in 限定符 |
in | 复制到函数中在函数中可读写 |
out | 返回时从函数中复制出来 |
inout | 复制到函数中并在返回时复制出来 |
10、函数示例
注意:GLSL中的函数不能递归
vec4 getPosition(){
vec4 v4 = vec4(0.,0.,0.,1.);
return v4;
}
void doubleSize(inout float size){
size= size*2.0 ;
}
void main() {
float psize= 10.0;
doubleSize(psize);
gl_Position = getPosition();
gl_PointSize = psize;
}
11、精度限定
GLSL在进行光栅化着色的时候,会产生大量的浮点数运算,这些运算可能是当前设备所不能承受的,所以GLSL提供了3种浮点数精度,我们可以根据不同的设备来使用合适的精度。
在变量前面加上 highp
mediump
lowp
即可完成对该变量的精度声明。
lowp float color;
mediump vec2 Coord;
lowp ivec2 foo(lowp mat3);
highp mat4 m;
我们一般在片元着色器(fragment shader)最开始的地方加上 precision mediump float;
便设定了默认的精度,这样所有没有显式表明精度的变量都会按照设定好的默认精度来处理。
可以设置变量的默认精度
,如果变量声明时没有使用精度限定符,将会拥有该类型的默认精度,默认精度可以在顶点或者片段着色器的开头指定:
precision highp float;
precision mediump int;
同时,在顶点着色器
中,如果没有指定默认精度,int 和 float 值的默认精度都是highp
,但是在片段着色器
中,float没有默认的精度,每个着色器必须声明一个默认的float精度
,或者为float变量手动指定精度。
12、变量修饰符
修饰符 | 说明 |
none | 默认类型 |
const | 声明变量或函数的参数为只读类型 |
uniform | 在运行时shader无法改变uniform变量,一般用来放置程序传递给shader的变换矩阵,材质,光照参数等等 |
in | 出入着色器的变量 |
out | 着色器传出的变量 |
const:
和C语言类似,被const限定符修饰的变量初始化后不可变,除了局部变量,函数参数也可以使用const修饰符。但要注意的是结构变量可以用const修饰, 但结构中的字段不行。
const变量必须在声明时就初始化 const vec3 v3 = vec3(0.,0.,0.)。
局部变量只能使用const限定符。函数参数只能使用const限定符。
uniform:
uniform变量是全局
且只读
的,在整个shader执行完毕前其值不会改变,他可以和任意基本类型变量组合,一般我们使用uniform变量来放置:外部程序传递来的环境数据(如点光源位置,模型的变换矩阵等等) ,这些数据在运行中显然是不需要被改变的。
13、流程控制
主要有for、while、do while、if else 等。
for (l = 0; l < numLights; l++)
{
if (!lightExists[l]);
continue;
color += light[l];
}
...
while (i < num)
{
sum += color[i];
i++;
}
...
do{
color += light[lightNum];
lightNum--;
}while (lightNum > 0)
...
if (true)
discard;
else
……
14、内建变量
在 vertex Shader 中:
output 类型的内置变量:
变量 | 说明 | 单位 |
---|---|---|
highp vec4 gl_Position ; |
gl_Position 放置顶点坐标信息 | vec4 |
mediump float gl_PointSize ; |
gl_PointSize 需要绘制点的大小,(只在gl.POINTS模式下有效) | float |
在 fragment Shader 中:
input 类型的内置变量:
变量 | 说明 | 单位 |
---|---|---|
mediump vec4 gl_FragCoord ; |
片元在framebuffer画面的相对位置 | vec4 |
bool gl_FrontFacing ; |
标志当前图元是不是正面图元的一部分 | bool |
mediump vec2 gl_PointCoord ; |
经过插值计算后的纹理坐标,点的范围是0.0到1.0 | vec2 |
output 类型的内置变量:
变量 | 说明 | 单位 |
---|---|---|
mediump vec4 fragColor ; |
设置当前片点的颜色 | vec4 RGBA color |
mediump vec4 fragData[n] |
设置当前片点的颜色,使用glDrawBuffers数据数组 | vec4 RGBA color |
15、着色器程序的基本结构
#version 300 es
uniform mat4 uMVPMatrix;
layout (location = 3) in vec3 aPosition;
layout (location = 2) in vec4 aColor;
out vec4 vColor;
void positionShift(){
……
}
void main(){
positionShift();
vColor = aColor;
}
最后,欢迎大家一起交流学习:微信:liaosy666 ; QQ:2209115372 。