介绍
Shader
是一种运行在 GPU
上的小程序,用于实现一些图形效果。在 Three.js
中,我们可以使用 GLSL ES
语言来编写 Shader
,并将其应用到材质上,从而实现各种图形效果。
可以做什么
-
实现各种图形效果,如光照、阴影、反射、折射等。
-
实现自定义的材质,如金属、塑料、玻璃等。
-
实现粒子效果,如烟雾、火焰、水波等。
-
实现动态纹理,如动态纹理、动态贴图等。
GLSL ES
GLSL ES
是一种用于编写 Shader
的编程语言,它是一种基于 C 语言的编程语言,具有 C 语言的大部分语法和特性。在 GLSL ES
中,我们可以使用一些特殊的语法和函数来实现各种图形效果。
基础语法
- 变量声明:在
GLSL ES
中,我们可以使用float
、int
、bool
等数据类型来声明变量,例如:
glsl
float x = 1.0;
int y = 2;
bool z = true;
- 函数声明:在
GLSL ES
中,我们可以使用void
、float
、int
等数据类型来声明函数,例如:
glsl
void myFunction(float a, int b) {
// 函数体
}
float myFunction2(int a) {
// 函数体
return 1.0;
}
- 循环和条件语句:在
GLSL ES
中,我们可以使用for
、while
、if
等循环和条件语句,例如:
glsl
for (int i = 0; i < 10; i++) {
// 循环体
}
if (x > 0.5) {
// 条件体
}
向量
在 GLSL ES
中,向量可以标时多种数据,也能进行多种数学运算。
例如,我们可以使用 vec3
来表示颜色,其中 vec3
是一个包含三个浮点数的向量,分别表示红、绿、蓝三个颜色通道的值。例如:
glsl
vec3 color = vec3(1.0, 0.0, 0.0); // 红色
我们也可以使用 vec3
来表示位置、方向、法线等,例如:
glsl
vec3 position = vec3(0.0, 0.0, 0.0); // 位置
vec3 direction = vec3(0.0, 0.0, 1.0); // 方向
vec3 normal = vec3(0.0, 1.0, 0.0); // 法线
常用关键字:
-
vec2: 二维向量,分量是浮点数。
-
vec3: 三维向量,分量是浮点数。
-
vec4: 四维向量,分量是浮点数。
-
ivec2: 二维向量,分量是整数。
-
ivec3: 三维向量,分量是整数。
-
ivec4: 四维向量,分量是整数。
-
bvec2: 二维向量,分量是布尔值。
-
bvec3: 三维向量,分量是布尔值。
-
bvec4: 四维向量,分量是布尔值。
-
mat2: 二维矩阵,包含两个二维向量。
-
mat3: 三维矩阵,包含三个三维向量。
-
mat4: 四维矩阵,包含四个四维向量。
着色器材质
在 Three.js
中,我们可以使用 ShaderMaterial
来创建一个着色器材质,并将其应用到几何体上,从而实现各种图形效果。
使用 ShaderMaterial
之前介绍了很多材质,例如:创建一个平面,使用基础网格材质 MeshBasicMaterial
。
js
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,
});
const mesh = new THREE.Mesh(geometry, material);
现在,我们使用 ShaderMaterial
来创建一个材质,并应用到平面上。
js
const geometry = new THREE.PlaneGeometry(100, 50);
const material = new THREE.ShaderMaterial({
vertexShader: "...", // 顶点着色器
fragmentShader: "...", // 片元着色器
});
const mesh = new THREE.Mesh(geometry, material);
设置顶点着色器
ShaderMaterial
顶点着色器属性 vertexShader
,是一个字符串,表示顶点着色器的代码。
js
const material = new THREE.ShaderMaterial({
vertexShader: "", // 顶点着色器
});
设置顶点着色器主函数
根据 GLSL ES
的语法,顶点着色器需要有一个主函数 main()
,函数无返回值,前面加上 void
关键字。
js
const material = new THREE.ShaderMaterial({
vertexShader: `
void main() {
// 顶点着色器代码
}
`,
});
内置变量
在 GLSL ES
中,我们可以使用 attribute
、uniform
、varying
等关键字来声明变量,这些变量可以在顶点着色器和片元着色器之间传递。
- gl_Position
gl_Position
是顶点着色器的一个内置变量,表示顶点的位置。在 GLSL ES
中,顶点着色器需要输出一个 vec4
类型的变量 gl_Position
,表示顶点的位置。
js
const material = new THREE.ShaderMaterial({
vertexShader: `
//注意在主函数外面声明,默认提供,不用自己写
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
`,
});
attribute: 顶点属性,只能在顶点着色器中使用,用于传递几何体的顶点数据,例如顶点的位置、法线、颜色等。
使用 ShaderMaterial
的时候,Threejs
会在内部把内置变量 position
与几何体的顶点位置数据 geometry.attributes.position
进行绑定,这就意味着,在顶点着色器代码中访问 position
变量,就相当于访问几何体的顶点位置数据。
- modelMatrix
modelMatrix
是顶点着色器的一个内置变量,表示模型的模型矩阵。在 GLSL ES
中,顶点着色器可以访问 mesh.matrixWorld
变量,用于计算顶点的位置。
js
const material = new THREE.ShaderMaterial({
vertexShader: `
uniform mat4 modelMatrix;
void main() {
gl_Position = modelMatrix * vec4(position, 1.0);
}
`,
});
使用 ShaderMaterial
的时候,Threejs
会自动获取模型世界矩阵 mesh.matrixWorld
的值,赋值给变量 modelMatrix
。这意味着,模型矩阵 modelMatrix
包含了模型自身的位置、缩放、姿态角度信息。
uniform: 全局变量,可以在顶点着色器和片元着色器中使用,用于传递全局数据,例如光源位置、颜色等。
js
const material = new THREE.ShaderMaterial({
vertexShader: `
uniform float opacity;//uniform声明透明度变量opacity
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
});
给 uniform
变量传值,在 Three.js
中,我们可以在创建 ShaderMaterial
的时候,通过 uniforms
属性来传递。
js
const material = new THREE.ShaderMaterial({
vertexShader: `
uniform float opacity;
void main() {
gl_Position = vec4(position, 1.0);
}
`,
fragmentShader: `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, opacity);
}
`,
uniforms: {
opacity: { value: 1.0 }, // 传递透明度变量opacity的值
},
});
- viewMatrix
viewMatrix
是顶点着色器的一个内置变量,表示视图矩阵。在 GLSL ES
中,顶点着色器可以访问 camera.matrixWorldInverse
变量,用于计算顶点的位置。
js
const material = new THREE.ShaderMaterial({
vertexShader: `
uniform mat4 viewMatrix;
void main() {
gl_Position = viewMatrix * modelMatrix * vec4(position, 1.0);
}
`,
});
- projectionMatrix
projectionMatrix
是顶点着色器的一个内置变量,表示投影矩阵。在 GLSL ES
中,顶点着色器可以访问 camera.projectionMatrix
变量,用于计算顶点的位置。
js
const material = new THREE.ShaderMaterial({
vertexShader: `
uniform mat4 projectionMatrix;
void main() {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}
`,
});
设置片元着色器
ShaderMaterial
片元着色器属性 fragmentShader
,是一个字符串,表示片元着色器的代码。
js
const material = new THREE.ShaderMaterial({
fragmentShader: "", // 片元着色器
});
- gl_FragColor
gl_FragColor
是片元着色器的一个内置变量,表示片元的颜色。在 GLSL ES
中,片元着色器需要输出一个 vec4
类型的变量 gl_FragColor
,表示片元的颜色。
js
const material = new THREE.ShaderMaterial({
fragmentShader: `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
}
`,
});
效果
js
//创建平面
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.ShaderMaterial({
vertexShader: `
void main() {
// 投影矩阵 * 视图矩阵 * 模型矩阵 * 顶点位置,如果不乘模型矩阵,则不会有模型变换
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
});
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
modelViewMatrix :视图矩阵 * 模型矩阵
js
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
注意: 每个语句后面要加分号,否则会报错。

Threejs基础系列课程差不多临近结尾了,大家还有什么想学的可以留言。接下来会准备一些项目实战教程,大家可以学到Threejs的应用,在做案例的过程中对之前的基础知识做补充,敬请期待吧!!!