着色器语言(上)

609 阅读5分钟

着色器语言主要特性:

  1. 着色器语言是一门高级的图形编辑语言和过程语言。
  2. 顶点着色器和片元着色器使用相同的语言。
  3. 基于C/C++语法及流程控制,但该语言不支持double,byte,short,long数据类型,取消了union,enum,unsigned以及位运算。
  4. 完美支持向量与矩阵的各种操作。
  5. 通过类型限定符来管理输入和输出。
  6. 拥有大量的内置函数来提供丰富的功能。

语言组成:标量,向量,矩阵,采样器,结构体,数组,空类型

基本类型

类型说明
void空类型,既不返回任何值
bool布尔类型,true/false(标量)
int带符号的整数 signed integer(标量)
float带符号的浮点数 floating scalar(标量)
vec2,vec3,vec4n维浮点数向量 n-component floating point vector
bvec2,bvec3,bvec4n维布尔向量 boolea vector
ivec2,ivec3,ivec4n维整数向量 signed integer vector
mat2,mat3,mat42维(2* 2),3维(3* 3),4维(4*4)浮点数矩阵 float matrix
sampler2D2D纹理 a 2D texture
sampler3D3D纹理 a 3D texture
samplerCube盒纹理 cube mapped texture

旧版GLSL的int类型的取值范围是16位精度,现在是32位精度了。

GLSL的向量可以看做是同样类型的标量组成,如2维向量表示为v2(x,y),3维向量表示为v3(x,y,z) 向量在着色器语言中,用于存储以及操作颜色,位置,纹理坐标等。

单独访问某个分量的基本语法为<向量名>·<分量名>,如颜色向量color(r,g,b,a),color.r=0.6。

GLSL中,矩阵是按列顺序组织的,一个矩阵可以看做由几个列向量组成。如mat3可以看做3个vec3组成。 对于矩阵的访问,可以将矩阵看成列向量的数组。如,matrix为mat4,访问第二列,使用matrix[1],其值为一个vec4,取得第三列的第二个分量,使用matrix[2][1],其值为float;

采样器,如sampler2D等,其专门用来进行纹理采样的相关操作。一般情况下,一个采样器变量代表一副或一套纹理贴图,采样器变量不能在着色器中初始化,一般情况下采样器变量都用uniform限定符来修饰,从宿主语言中(如java)接受传递进着色器的值。

基本结构和数组

类型说明
结构struct type-name{} 类似C语言的结构体
数组float foo[3] glsl只支持1维数组,数组可以是结构体成员

基本类型间的运算:

GLSL中,没有隐式类型的转换,原则上要求左右两侧表达式(left-value = right-value)的类型必须一致,如果类型不同,必须使用显示转换(使用构造函数转换);

1.float与int
同类型之间直接运算,不同类型需要显示转换。

int a=int(2.0); 
float a=float(2)*6.0+2.3;

2.float与vec(向量)/mat(矩阵)
vec,mat其实是由float复合而成的,当他们与float预算时,其实就是每一个分量分别于float进行运算,即逐分量运算。GLSL里大部分涉及vec,mat的运算都是逐分量运算,逐分量运算是线性的,如vec与float运算的结果还是vec。

vec3 v=vec3(1.0,2.0,3.0);
mat3 m=mat3(1.0);
float f=10.0;
vec3 a=f*v;          //vec3(10.0,20.0,30.0)
vec3 b=v*f;  	     //vec3(10.0,20.0,30.0)
mat3 c=f*m;;	     //mat3(10.0)
mat3 d=m*f;	     //mat3(10.0)

int与vec,mat之间是不可运算的,因为vec和mat中的每一个分量都是float类型的,无法与int逐分量运算。

3.vec与vec(向量与向量)
两向量间的运算必须保证操作数的阶数都相同,即维度相同,否则不能计算。计算方式为两操作数在同位置上的分量分别进行运算,且阶数不变,其本质还是逐分量进行。

vec3 a=vec3(1.0,2.0,3.0); 
vec3 b=vec3(0.1,0.2,0.3); 
vec3 c=a+b; //vec3(1.1,2.2,3.3) 
vec3 d=a*b; //vec3(0.1,0.4,0.9)

4.vec与mat(向量与矩阵)
要保证操作数的阶数相同,且vec与mat只存在乘法运算,且结果为vec(向量)。计算方式和线性代数中的矩阵乘法相同。

vec2 v=vec2(10.0,20.0);
mat2 m=mat2(1.0,2.0,3.0,4.0);
vec2 a=m*v;		//vec2((1.0*10.0+3.0*20.0),(2.0*10.0+4.0*20.0))  --vec2(70,100)
vec2 b=v*m		//vec2((10.0*1.0+20.0*2.0),(10.0*3.0+20.0*4.0))  --vec2(50,110)

向量与矩阵的乘法规则:

矩阵.png

矩阵A,B,C; C=A*B 乘法运算注意事项:
1.A的列数等于B的行数;
2.A的行数为C的行数,B的列数为C的列数;
3.C的第m行第n列元素等于A的第m行的各个元素与B的第n列的对应元素相乘之和 4.mat与mat(矩阵和矩阵)
必须操作数的阶数相同,乘法运算为线性代数运算方式。其余的运算仍然为逐分量运算

 mat2 a=mat2(1.0,2.0,3.0,4.0);
 mat2 b=mat2(10.0,20.0,30.0,40.0);
 mat2 c=a+b;//mat2(11.0,22.0,33.0,44.0);
 mat2 d=a*b;//mat2((1.0*10.0+3.0*20.0),(2.0*10.0+4.0*20.0),(1.0*30.0+3.0*40.0),(2.0*30.0+4.0*40.0))    --mat2(70.0,100.0,150.0,220.0)

着色器、.png

变量限定符

修饰符说明
none(默认的,可省略)本地变量,可读可写,函数的输入参数即是这种类型
const声明变量或函数的参数为只读类型
attribute只能存在于vertex shader(顶点着色器)中,一般用于保存顶点或法线数据,他可以在数据缓冲区读取数据
uniform在运行时shader无法改变uniform变量,一般用来放置程序传递给shader的变换矩阵,从材质,光照参数等等
varying主要负责在vertex(定点着色器)和fragment(片元着色器)之间传递变量

要注意全局变量限制符只能为 const、attribute、uniform和varying中的一个.不可复合