第五部分-后期特效与着色器——26. 着色器基础
26. 着色器基础
1. 概述
着色器(Shader)是在 GPU 上运行的小程序,用于控制顶点位置和像素颜色。Three.js 允许通过 ShaderMaterial 编写自定义着色器,实现高级视觉效果。
┌─────────────────────────────────────────────────────────────┐ │ 着色器工作流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 顶点数据 ──► 顶点着色器 ──► 片元着色器 ──► 像素颜色 │ │ (Vertex) (Fragment) │ │ │ │ 顶点着色器:处理顶点位置、法线、UV 等 │ │ 片元着色器:处理每个像素的颜色、光照、纹理等 │ │ │ └─────────────────────────────────────────────────────────────┘2. 着色器类型
2.1 顶点着色器(Vertex Shader)
顶点着色器处理每个顶点的位置和属性。
// 基础顶点着色器 void main() { // 计算顶点位置 vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); gl_PointSize = 1.0; gl_Position = projectionMatrix * mvPosition; }2.2 片元着色器(Fragment Shader)
片元着色器处理每个像素的颜色。
// 基础片元着色器 uniform vec3 color; void main() { gl_FragColor = vec4(color, 1.0); }3. ShaderMaterial
3.1 基本用法
constvertexShader=`varying vec2 vUv; void main() { vUv = uv; vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); gl_PointSize = 1.0; gl_Position = projectionMatrix * mvPosition; }`;constfragmentShader=`uniform vec3 uColor; varying vec2 vUv; void main() { gl_FragColor = vec4(uColor, 1.0); }`;constmaterial=newTHREE.ShaderMaterial({uniforms:{uColor:{value:newTHREE.Color(0xff6600)}},vertexShader:vertexShader,fragmentShader:fragmentShader});3.2 ShaderMaterial 属性
| 属性 | 说明 |
|---|---|
uniforms | 全局变量(如时间、颜色) |
vertexShader | 顶点着色器代码 |
fragmentShader | 片元着色器代码 |
transparent | 是否透明 |
side | 渲染面 |
wireframe | 线框模式 |
4. Uniforms
Uniforms 是着色器的全局变量,可以在 JavaScript 中更新。
constuniforms={uTime:{value:0},uColor:{value:newTHREE.Color(0xff6600)},uTexture:{value:texture},uResolution:{value:newTHREE.Vector2(800,600)}};// 更新 uniformfunctionanimate(){uniforms.uTime.value+=0.01;requestAnimationFrame(animate);}5. 内置变量
5.1 顶点着色器内置变量
| 变量 | 类型 | 说明 |
|---|---|---|
position | vec3 | 顶点位置(局部坐标) |
normal | vec3 | 顶点法线 |
uv | vec2 | UV 坐标 |
modelViewMatrix | mat4 | 模型视图矩阵 |
projectionMatrix | mat4 | 投影矩阵 |
5.2 片元着色器内置变量
| 变量 | 类型 | 说明 |
|---|---|---|
gl_FragColor | vec4 | 输出颜色 |
gl_FragCoord | vec4 | 片元屏幕坐标 |
varying | 自定义 | 从顶点着色器传递的数据 |
6. Varying 变量
Varying 变量用于在顶点着色器和片元着色器之间传递数据。
// 顶点着色器 varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } // 片元着色器 varying vec2 vUv; void main() { gl_FragColor = vec4(vUv.x, vUv.y, 0.5, 1.0); }7. 完整示例
import*asTHREEfrom'three';import{OrbitControls}from'three/examples/jsm/controls/OrbitControls.js';constscene=newTHREE.Scene();scene.background=newTHREE.Color(0x000000);constcamera=newTHREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);camera.position.set(2,2,3);camera.lookAt(0,0,0);constrenderer=newTHREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(renderer.domElement);constcontrols=newOrbitControls(camera,renderer.domElement);controls.enableDamping=true;// 创建纹理constcanvas=document.createElement('canvas');canvas.width=512;canvas.height=512;constctx=canvas.getContext('2d');ctx.fillStyle='#ff6600';ctx.fillRect(0,0,canvas.width,canvas.height);ctx.fillStyle='#ffffff';ctx.font='Bold 40px Arial';ctx.fillText('Three.js',canvas.width/2-100,canvas.height/2);consttexture=newTHREE.CanvasTexture(canvas);// 顶点着色器constvertexShader=`varying vec2 vUv; varying vec3 vPosition; void main() { vUv = uv; vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); vPosition = mvPosition.xyz; gl_PointSize = 1.0; gl_Position = projectionMatrix * mvPosition; }`;// 片元着色器constfragmentShader=`uniform float uTime; uniform vec3 uColor; uniform sampler2D uTexture; varying vec2 vUv; varying vec3 vPosition; void main() { // 波浪效果 float wave = sin(vUv.x * 20.0 + uTime) * cos(vUv.y * 20.0 + uTime) * 0.5 + 0.5; // 纹理采样 vec4 texColor = texture2D(uTexture, vUv); // 渐变效果 vec3 gradient = vec3(vUv.x, vUv.y, 0.5); // 颜色混合 vec3 finalColor = mix(uColor, texColor.rgb, 0.5); finalColor = mix(finalColor, gradient, 0.3); finalColor += vec3(wave * 0.3); // 边缘暗角 float vignette = 1.0 - length(vUv - 0.5) * 0.8; finalColor *= vignette; gl_FragColor = vec4(finalColor, 1.0); }`;// 创建材质constuniforms={uTime:{value:0},uColor:{value:newTHREE.Color(0xff6600)},uTexture:{value:texture}};constmaterial=newTHREE.ShaderMaterial({uniforms:uniforms,vertexShader:vertexShader,fragmentShader:fragmentShader,side:THREE.DoubleSide});// 创建几何体constgeometry=newTHREE.SphereGeometry(1,64,64);constmesh=newTHREE.Mesh(geometry,material);scene.add(mesh);// GUI 控制importGUIfrom'lil-gui';constgui=newGUI();gui.add(uniforms.uColor.value,'r',0,1).name('红色').onChange(()=>uniforms.uColor.value.setHSL(uniforms.uColor.value.r,1,0.5));gui.add(uniforms.uColor.value,'g',0,1).name('绿色');gui.add(uniforms.uColor.value,'b',0,1).name('蓝色');// 动画functionanimate(){requestAnimationFrame(animate);uniforms.uTime.value+=0.01;mesh.rotation.y+=0.005;controls.update();renderer.render(scene,camera);}animate();window.addEventListener('resize',onWindowResize,false);functiononWindowResize(){camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);}8. 常见效果示例
8.1 波浪效果
float wave = sin(position.y * 5.0 + uTime) * 0.1; vec3 newPosition = position + vec3(0.0, wave, 0.0);8.2 颜色渐变
vec3 color1 = vec3(1.0, 0.0, 0.0); vec3 color2 = vec3(0.0, 0.0, 1.0); vec3 finalColor = mix(color1, color2, vUv.x);8.3 溶解效果
float dissolve = texture2D(uNoiseTexture, vUv).r; if (dissolve < uProgress) discard;9. 总结
| 类型 | 用途 |
|---|---|
| 顶点着色器 | 处理顶点位置 |
| 片元着色器 | 处理像素颜色 |
| Uniforms | 全局变量 |
| Varying | 顶点→片元传递 |
| ShaderMaterial | 自定义材质 |
| 内置变量 | 说明 |
|---|---|
position | 顶点位置 |
uv | UV 坐标 |
normal | 法线 |
modelViewMatrix | 模型视图矩阵 |
projectionMatrix | 投影矩阵 |
