本文档涵盖Three.js中高级着色器应用,以孔明灯特效为例,展示复杂着色器的实际应用。
最终效果如图:
1. 高级着色器应用概述
1.1 环境贴图与光照
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as dat from "dat.gui";
import vertexShader from "../shaders/flylight/vertex.glsl";
import fragmentShader from "../shaders/flylight/fragment.glsl";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
// 初始化场景
const scene = new THREE.Scene();
// 加载HDR环境贴图
const rgbeLoader = new RGBELoader();
rgbeLoader.loadAsync("./assets/2k.hdr").then((texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture; // 设置背景贴图
scene.environment = texture; // 设置环境贴图
});
1.2 渲染器高级设置
const renderer = new THREE.WebGLRenderer({ alpha: true });
// 启用色调映射以获得更好的视觉效果
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.2;
2. 孔明灯模型加载与着色器应用
2.1 GLTF模型加载
const gltfLoader = new GLTFLoader();
let LightBox = null;
gltfLoader.load("./assets/model/flyLight.glb", (gltf) => {
console.log(gltf);
// 获取孔明灯网格
LightBox = gltf.scene.children[1];
// 应用自定义着色器材质
LightBox.material = shaderMaterial;
// 批量创建孔明灯实例
for (let i = 0; i < 150; i++) {
let flyLight = gltf.scene.clone(true); // 克隆模型
let x = (Math.random() - 0.5) * 300; // 随机X位置
let z = (Math.random() - 0.5) * 300; // 随机Z位置
let y = Math.random() * 60 + 25; // 随机Y位置
flyLight.position.set(x, y, z);
// 添加旋转动画
gsap.to(flyLight.rotation, {
y: 2 * Math.PI,
duration: 10 + Math.random() * 30, // 随机持续时间
repeat: -1, // 无限重复
});
// 添加位置动画
gsap.to(flyLight.position, {
x: "+=" + Math.random() * 5, // X方向随机移动
y: "+=" + Math.random() * 20, // Y方向随机移动
yoyo: true, // 往返运动
duration: 5 + Math.random() * 10, // 随机持续时间
repeat: -1, // 无限重复
});
scene.add(flyLight);
}
});
3. 孔明灯顶点着色器详解
3.1 顶点着色器代码
precision lowp float;
varying vec4 vPosition;
varying vec4 gPosition;
void main(){
vec4 modelPosition = modelMatrix * vec4( position, 1.0 );
vPosition = modelPosition;
gPosition = vec4( position, 1.0 );
gl_Position = projectionMatrix * viewMatrix * modelPosition;
}
3.2 变量传递机制
vPosition:传递模型空间中的位置信息gPosition:传递原始几何位置信息- 这些变量将在片元着色器中使用
4. 孔明灯片元着色器详解
4.1 片元着色器代码
precision lowp float;
varying vec4 vPosition;
varying vec4 gPosition;
void main(){
vec4 redColor = vec4(1,0,0,1); // 红色
vec4 yellowColor = vec4(1,1,0.5,1); // 黄色
vec4 mixColor = mix(yellowColor,redColor,gPosition.y/3.0); // 基于Y坐标的颜色混合
// 根据面朝向设置不同颜色
if(gl_FrontFacing){
// 正面朝向相机的像素,添加高度影响和亮度调整
gl_FragColor = vec4(mixColor.xyz-(vPosition.y-20.0)/80.0-0.1,1);
}else{
// 背面像素使用基础颜色
gl_FragColor = vec4(mixColor.xyz,1);
}
}
4.2 颜色混合技术
// 基于Y坐标的颜色插值
vec4 mixColor = mix(yellowColor,redColor,gPosition.y/3.0);
4.3 面朝向判断
// 使用gl_FrontFacing区分正面和背面
if(gl_FrontFacing){
// 正面:添加高度影响和亮度调整
gl_FragColor = vec4(mixColor.xyz-(vPosition.y-20.0)/80.0-0.1,1);
}else{
// 背面:使用基础颜色
gl_FrontFacing = vec4(mixColor.xyz,1);
}
5. 自定义着色器材质创建
5.1 着色器材质初始化
// 创建孔明灯专用着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
vertexShader: vertexShader, // 顶点着色器
fragmentShader: fragmentShader, // 片元着色器
uniforms: {}, // uniform变量
side: THREE.DoubleSide, // 双面渲染
// transparent: true, // 透明渲染(可选)
});
6. 相机控制与视角设置
6.1 高级相机控制
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 启用阻尼效果
controls.autoRotate = true; // 自动旋转
controls.autoRotateSpeed = 0.1; // 自动旋转速度
controls.maxPolarAngle = (Math.PI / 3) * 2; // 最大极角限制
controls.minPolarAngle = (Math.PI / 3) * 2; // 最小极角限制
6.2 相机角度限制
// 限制相機垂直旋转范围,防止过度俯仰
controls.maxPolarAngle = (Math.PI / 3) * 2;
controls.minPolarAngle = (Math.PI / 3) * 2;
7. 动画系统集成
7.1 GSAP动画控制
// 旋转动画
gsap.to(flyLight.rotation, {
y: 2 * Math.PI, // 旋转一圈
duration: 10 + Math.random() * 30, // 随机持续时间
repeat: -1, // 无限重复
});
// 位置动画
gsap.to(flyLight.position, {
x: "+=" + Math.random() * 5, // X方向随机移动
y: "+=" + Math.random() * 20, // Y方向随机移动
yoyo: true, // 往返运动
duration: 5 + Math.random() * 10, // 随机持续时间
repeat: -1, // 无限重复
});
8. 性能优化策略
8.1 批量渲染优化
// 使用克隆技术批量创建对象
for (let i = 0; i < 150; i++) {
let flyLight = gltf.scene.clone(true);
// ...
scene.add(flyLight);
}
8.2 减少Draw Call
- 使用相同的着色器材质
- 合理组织渲染批次
- 利用实例化渲染技术
9. 着色器参数化设计
9.1 Uniform变量扩展
虽然当前示例中uniforms为空,但在实际应用中可以扩展:
const shaderMaterial = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader,
uniforms: {
uTime: { value: 0 }, // 时间
uBrightness: { value: 1.0 }, // 亮度
uColorMix: { value: 0.5 }, // 颜色混合系数
},
side: THREE.DoubleSide,
});
10. 故障排除与调试
10.1 常见问题
- 着色器编译错误:检查GLSL语法
- 性能问题:简化着色器计算
- 光照问题:检查环境贴图设置
- 动画卡顿:检查动画循环和更新频率
10.2 调试技巧
- 逐行注释:定位问题代码
- 变量输出:将中间值输出到颜色
- 简化模型:使用简单几何体测试着色器
总结
本章展示了Three.js中高级着色器的实际应用,以孔明灯特效为例:
- 环境贴图和高级渲染设置
- GLTF模型加载和着色器应用
- 复杂顶点和片元着色器的编写
- 动画系统与着色器的集成
- 相机控制和性能优化
- 批量对象管理和渲染优化
通过这种综合应用,可以创建出具有专业品质的3D视觉效果。