文章目录
- 前言
- OpenGL ES基础
- 一段基本的着色器代码
- 大小写和分号
- 数据值类型、命名规范、类型转换
- 运算符
 
- 矢量和矩阵
- 矢量和矩阵类型
- 矢量构造、访问
- 矩阵构造、访问
- 矢量矩阵运算规则
 
- 特殊类型—结构体和数组
- 结构体
- 数组
 
- 取样器
- 总结
前言
着色器语言通过控制GPU来进行前端图形的渲染,WebGL使用名为GLSL ES的规范进行着色器语言的编写,GLSL ES是在OpenGL的基础上进行一定的精简后形成的,它的语法与C语言有些类似。 本文对webgl常用到的GLSL ES知识进行记录。
 着色器以字符串的形式存储在javascript中
OpenGL ES基础
一段基本的着色器代码
   // 顶点着色器
	const vertex =  `
		attribute vec4 aPosition;
		void main() {
			gl_Position = aPosition;
			gl_PointSize = 10.0;
		}
	`
	// 片元着色器
	const fragment =  `
		precision highp float;
		uniform vec4 uColor;
		void main(){
			gl_FragColor = uColor;
		}
	`
大小写和分号
- 大小写敏感
const vertex =  `
		// 不会报错,aPosition和aposition是两个不同的变量
		attribute vec4 aPosition;
		attribute vec4 aposition;
		void main() {
			gl_Position = aPosition;
			gl_PointSize = 10.0;
		}
	`
- 强制分号
const vertex =  `
		attribute vec4 aposition  // 运行会报错
		void main() {
			gl_Position = aPosition;
			gl_PointSize = 10.0;
		}
	`
- 执行次序
着色器的执行从main函数开始逐行运行,无论是顶点着色器还是片元着色器都有且只有一个main函数作为整个程序的入口,该函数由void声明,不接受任何参数,也没有返回值。
- 注释
着色器的注释与js相同, // 进行单行注释;/* xxx */ 进行多行注释。
数据值类型、命名规范、类型转换
GLSL 是强类型语言,数据声明时必须指定类型。GLSL支持整形(int),浮点型(float),布尔(bool)三种数据类型。
const vertex =  `
		void main() {
			int ten = 10; // 整型
			float pie = 3.14; // 浮点型
			bool isOk = true; // 布尔型
			
			gl_Position = aPosition;
			gl_PointSize = 10.0;
		}
	`
变量的命名需要遵守以下规则:
- 只包括a-z,A-Z,0-9,_,无其它特殊字符
- 首位不能是数字
- 不能以gl_、webgl_、_webgl_开头
- 避免与webgl内置关键字或者保留字重名
不同类型的变量之间不能直接相互赋值,但是通过内置函数进行类型转换后可以:
| 名称 | 参数类型 | 含义 | 
|---|---|---|
| int ( x ) | float / bool | 转换为整数 | 
| float ( x ) | int / bool | 转换为小数 | 
| bool ( x ) | float / int | 转换为布尔 | 
运算符

矢量和矩阵
矢量和矩阵类型
| 类型 | GLSL ES类型 | 含义 | 
|---|---|---|
| 矢量 | vec2、vec3、vec4 | 长度为2、3、4,元素类型为float的矢量 | 
| 矢量 | ivec2、ivec3、ivec4 | 长度为2、3、4,元素类型为int的矢量 | 
| 矢量 | bvec2、bvec3、bvec4 | 长度为2、3、4,元素类型为bool的矢量 | 
| 矩阵 | mat2、mat3、mat4 | 维度为2 * 2、3 * 3、4 * 4,元素类型为float的矩阵 | 
矢量构造、访问
- 矢量构造函数赋值
const vertex =  `
		void main() {
			vec4 vector4 = vec4(1.0, 1.0, 1.0, 1.0); // 普通赋值
			vec4 vector4_copy = vec4(vector4); // 复制
			vec2 vector2 = vec2(vector4); // 取vector4前两个值组成矢量
			vec4 vector4_copy2 = vec4(2.0); // vec4(2.0, 2.0, 2.0, 2.0)
			vec4 vector4_new = vec4(vector2, vector2); // 组装成一个vec4
			
			···
		}
	`
- 矢量访问
可以通过 . 进行访问
const vertex =  `
		void main() {
			vec4 vector4 = vec4(1.0, 2.0, 3.0, 1.0); // 普通赋值
			
			float v1 = vector4.x  // 1.0
			vec2 v2 = vector4.xy  // vec2(1.0, 1.0)
			vec2 v2_ = vector4.zx  // vec2(3.0, 1.0)
			···
		}
	`
也可以通过 [ ] 获取下标进行访问
const vertex =  `
		void main() {
			vec4 vector4 = vec4(1.0, 2.0, 3.0, 1.0); // 普通赋值
			
			float v1 = vector4[0]  // 1.0
		}
	`
矩阵构造、访问
- 矩阵赋值
矩阵传入值必须是列主序的

 像上面整个矩阵,赋值方式如下:
mat m4 = (
	a,  e,  i,  m,
    b,  f,  j,  n,
    c,  g,  k,  o,
    d,  h,  l,  p
)
// 或者
vec4 vec1 = (a,  e,  i,  m)
vec4 vec2 = (b,  f,  j,  n)
vec4 vec3 = (c,  g,  k,  o)
vec4 vec4 = (d,  h,  l,  p)
mat4 m4 = mat4(vec1, vec2, vec3, vec4)
- 矩阵访问
可以通过 . 和 [ ] 进行访问
const vertex =  `
		void main() {
			vmat m4 = (
				a,  e,  i,  m,
   				b,  f,  j,  n,
    			c,  g,  k,  o,
    			d,  h,  l,  p
			)
			vec4 v4_ = vector4[3];  // [m, n, o, p]
			float v4_2 = vector4[3][1] ; // n
			vec4 v4_2 = vector4[3].y;  // n
			···
		}
	`
矢量矩阵运算规则
- 当矩阵之间进行计算时(+ 、- 、* 、/),遵从矩阵运算规则。
- 矢量之间进行计算时(+ 、- 、* 、/),对应位置上的元素进行相应计算。
- 矩阵矢量之间进行计算时(* 、/),当向量在左,计算规则按照1 * n的矩阵与n阶矩阵相乘;当向量在右边,按照n阶矩阵与n*1的矩阵相乘。
特殊类型—结构体和数组
结构体
GLSL ES支持使用结构体来创建用户自定义的类型,与C++十分类似:
// 定义结构体pen
struct pen {
	vec4 color;
	float lenght;
}
// 声明pen类型的对象
pen pen1, pen2;
// 给结构体赋值
pen1 = pen(vec4(1.0,0.0,0.0,1.0, 10.1);
// 访问结构体
vec4 pen1_color = pen1.color;
float pen1_length = pen1.length;
数组
GLSL ES同时也支持数据类型,但是仅支持一维数组,数组不支持pop()和push()操作,数组不能一次性初始化,必须显式地对每个元素初始化。
// 声明数组
float floatArray[4]; // 元素类型是float,长度是4的数组
vec4 vec4Array[2]; // 元素类型是vec4,长度是2的数组
// 数组赋值
floatArray[0] = 0.0;
floatArray[1] = 1.0;
floatArray[2] = 2.0;
floatArray[3] = 3.0;
vec4Array[0] = (0.0,0.0,0.0,0.0);
vec4Array[1] = (1.0,1.0,1.0,1.0);
取样器
GLSL ES支持一种名为取样器(sampler的变量类型获取纹理,取样器变量必须是uniform变量,取样器支持两种类型sampler2D和samplerCube,sampler2D的使用见webgl纹理贴图机制,samplerCube是立方体纹理,使用和sampler2D差不多,唯一区别就是在使用gl.texImage2D()进行图像分配给纹理对象时,要把六个面的数据都分配一次。
总结
OpenGL ES基础
- 一段基本的着色器代码
- 大小写和分号
- 数据值类型、命名规范、类型转换
- 运算符
矢量和矩阵
- 矢量和矩阵类型
- 矢量构造、访问
- 矩阵构造、访问
- 矢量矩阵运算规则
特殊类型—结构体和数组
- 结构体
- 数组
取样器



















