摘要
本文详细介绍了 Three.js 中着色器(Shader)的核心概念与实战应用。文章首先阐明着色器是运行在 GPU 上的小程序,主要分为控制几何体形状的顶点着色器和决定像素颜色的片段着色器,开发者可通过 ShaderMaterial 创建自定义材质。随后,文章通过三个递进的代码示例展示了着色器的具体用法:从最基础的纯红色立方体渲染,到利用 varying 变量和 mix 函数实现基于 UV 坐标的颜色渐变效果,再到通过 uniform 变量在 JavaScript 与 GLSL 之间传递时间参数,结合动画循环实现动态波浪形变。最后,文章强调了使用 ShaderMaterial 的注意事项,包括其不继承标准材质灯光系统需手动处理光照,以及着色器代码为字符串形式,需通过浏览器控制台排查 GPU 语法错误。
目录
一、什么是着色器
着色器是运行在 GPU 上的小程序,分为顶点着色器和片段着色器:
-
顶点着色器(Vertex Shader) :处理几何体顶点,控制物体的形状、位置和变形
-
片段着色器(Fragment Shader) :处理每个像素的颜色,决定物体表面的最终呈现
在 Three.js 中,通过 ShaderMaterial 可以创建自定义着色器材质。
二、基础示例:纯红色立方体
javascript
const vertexShader = `
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 纯红色
}
`;
const shaderMaterial = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
const geometry = new THREE.BoxGeometry(1, 1, 1);
const mesh = new THREE.Mesh(geometry, shaderMaterial);
scene.add(mesh);
三、渐变效果着色器
实现从顶部蓝色到底部绿色的渐变:
javascript
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
varying vec2 vUv;
void main() {
vec4 topColor = vec4(0.0, 0.0, 1.0, 1.0); // 蓝色
vec4 bottomColor = vec4(0.0, 1.0, 0.0, 1.0); // 绿色
float interpolate = vUv.y;
gl_FragColor = mix(topColor, bottomColor, interpolate);
}
`;
const shaderMaterial = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
四、带动画的波浪着色器
使用 uniform 变量传递时间,实现动态波浪效果:
javascript
const vertexShader = `
uniform float time;
void main() {
vec3 newPosition = position;
newPosition.y += sin(time + position.x * 5.0) * 0.2;
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
}
`;
const fragmentShader = `
void main() {
gl_FragColor = vec4(0.0, 0.5, 1.0, 1.0);
}
`;
const shaderMaterial = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader,
uniforms: {
time: { value: 0 }
}
});
// 在动画循环中更新 time
function animate() {
requestAnimationFrame(animate);
shaderMaterial.uniforms.time.value += 0.01;
renderer.render(scene, camera);
}
五、注意事项
-
ShaderMaterial不继承标准材质的灯光系统,需要手动处理光照逻辑 -
着色器代码是字符串形式,注意语法错误不会在 JavaScript 中报错,需在浏览器控制台查看 GPU 错误信息