着色器语言(GLSL)基础学习一

着色器语言主要特性:

  1. 着色器语言是一门高级的图形编辑语言和过程语言。
  2. 顶点着色器和片元着色器使用相同的语言。
  3. 基于C/C++语法及流程控制,但该语言不支持double,byte,short,long数据类型,取消了union,enum,unsigned以及位运算。

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

基本类型

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

GLSL的int类型 的取值范围是16位精度。
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)

向量与矩阵的乘法规则:
在这里插入图片描述
在这里插入图片描述

矩阵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)

矩阵乘法规则:
在这里插入图片描述


变量限定符

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

1.const:
被const限定符修饰的变量初始后不可变,出了局部变量,函数参数也可以使用const修饰符。结构变量可以用const修饰,但结构中的字段不行。
const变量必须在声明时就初始化

const vec3 v=vec3(0.0,0.0,0.0);

局部变量只能使用const限定符;函数参数只能使用const限定符。
2.attribute:
attribute变量是全局只读的,它只能在vertext shader中使用,只能与浮点数,向量或矩阵变量组合,一般attribute变量用来防止程序传递来的模型顶点,法线,颜色,纹理等数据,它可以访问数据缓冲区。

attribute vec4 a_Position;

3.uniform:
uniform变量是全局且只读的,在整个shader执行完毕前其值不会改变,它可以和任意基本类型变量组合,一般我们使用uniform变量来放置外部程序传递来的环境数据(如光源位置,模型的变换矩阵等等),这些数据在运行中显然不需要被改变。

uniform vec4 lightPosition;

4.varying:
varying变量是vertex shader与fragment shader之间的信使,一般在vertex shader中修改然后在fragment shader使用它,但不能在fragment shader中修改它。

//顶点着色器
varying vec4 v_Color;
void main(){ 
    ...
    v_Color = vec4(1.,1.,1.,1);
}

//片元着色器
...
varying vec4 v_Color;
void main() {
  gl_FragColor = v_Color;
}
...

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

你可能感兴趣的:(WebGL)