高级特性
本章将介绍 Three.js 的高级特性,包括后期处理、自定义着色器、模型加载、性能优化等内容,帮助你创建更专业、更高效的 3D 应用。
后期处理
后期处理是在渲染完成后对图像进行额外处理的技术,可以实现模糊、发光、色彩校正等效果。
基础设置
后期处理需要使用 EffectComposer:
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
// 创建后期处理组合器
const composer = new EffectComposer(renderer);
// 添加渲染通道(必需)
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
// 添加发光效果
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // 强度
0.4, // 半径
0.85 // 阈值
);
composer.addPass(bloomPass);
// 在渲染循环中使用 composer
function animate() {
requestAnimationFrame(animate);
composer.render();
}
常用后期处理效果
BloomPass / UnrealBloomPass
发光效果,让亮部区域产生光晕:
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // 强度
0.4, // 半径
0.85 // 阈值(只有亮度超过这个值的区域才会发光)
);
FilmPass
老电影效果,添加噪点和扫描线:
import { FilmPass } from 'three/addons/postprocessing/FilmPass.js';
const filmPass = new FilmPass(
0.35, // 噪点强度
0.5, // 扫描线强度
2048, // 扫描线数量
false // 是否灰度
);
GlitchPass
故障效果:
import { GlitchPass } from 'three/addons/postprocessing/GlitchPass.js';
const glitchPass = new GlitchPass();
ShaderPass
自定义着色器效果:
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { VignetteShader } from 'three/addons/shaders/VignetteShader.js';
const vignettePass = new ShaderPass(VignetteShader);
vignettePass.uniforms.offset.value = 1.0;
vignettePass.uniforms.darkness.value = 1.5;
组合多个效果
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { FXAAShader } from 'three/addons/shaders/FXAAShader.js';
import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js';
const composer = new EffectComposer(renderer);
// 渲染通道
composer.addPass(new RenderPass(scene, camera));
// 发光效果
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.5, 0.4, 0.85
);
composer.addPass(bloomPass);
// 伽马校正
composer.addPass(new ShaderPass(GammaCorrectionShader));
// 抗锯齿
const fxaaPass = new ShaderPass(FXAAShader);
fxaaPass.uniforms.resolution.value.set(
1 / window.innerWidth,
1 / window.innerHeight
);
composer.addPass(fxaaPass);
自定义着色器
着色器是运行在 GPU 上的小程序,可以创建独特的视觉效果。
着色器基础
Three.js 使用 GLSL 着色器语言。顶点着色器处理顶点位置,片元着色器处理像素颜色。
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
uniform float uTime;
varying vec2 vUv;
void main() {
vec3 color = vec3(vUv.x, vUv.y, sin(uTime) * 0.5 + 0.5);
gl_FragColor = vec4(color, 1.0);
}
`;
ShaderMaterial
使用 ShaderMaterial 创建自定义材质:
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0 },
uColor: { value: new THREE.Color(0x00ff00) },
uTexture: { value: texture }
},
vertexShader,
fragmentShader,
side: THREE.DoubleSide,
transparent: true
});
// 在动画中更新 uniform
function animate() {
requestAnimationFrame(animate);
material.uniforms.uTime.value = clock.getElapsedTime();
renderer.render(scene, camera);
}
内置变量和属性
Three.js 提供了一些内置变量:
顶点着色器内置属性:
position:顶点位置normal:顶点法线uv:UV 坐标color:顶点颜色
内置 uniform:
modelMatrix:模型矩阵viewMatrix:视图矩阵projectionMatrix:投影矩阵modelViewMatrix:模型视图矩阵normalMatrix:法线矩阵cameraPosition:相机位置
示例:波浪效果
const vertexShader = `
uniform float uTime;
uniform float uWaveHeight;
varying vec2 vUv;
varying float vElevation;
void main() {
vUv = uv;
vec3 pos = position;
float elevation = sin(pos.x * 5.0 + uTime) * uWaveHeight;
elevation += sin(pos.y * 3.0 + uTime * 0.5) * uWaveHeight * 0.5;
pos.z += elevation;
vElevation = elevation;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`;
const fragmentShader = `
uniform vec3 uColorA;
uniform vec3 uColorB;
varying vec2 vUv;
varying float vElevation;
void main() {
float mixStrength = (vElevation + 0.1) * 5.0;
vec3 color = mix(uColorA, uColorB, mixStrength);
gl_FragColor = vec4(color, 1.0);
}
`;
const geometry = new THREE.PlaneGeometry(10, 10, 64, 64);
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0 },
uWaveHeight: { value: 0.2 },
uColorA: { value: new THREE.Color(0x0066ff) },
uColorB: { value: new THREE.Color(0x00ff88) }
},
vertexShader,
fragmentShader,
side: THREE.DoubleSide
});
const plane = new THREE.Mesh(geometry, material);
plane.rotation.x = -Math.PI / 2;
scene.add(plane);
模型加载
Three.js 支持加载多种 3D 模型格式,最常用的是 GLTF/GLB 格式。
GLTFLoader
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load(
'model.glb',
(gltf) => {
// 加载成功
const model = gltf.scene;
scene.add(model);
// 处理动画
if (gltf.animations.length > 0) {
const mixer = new THREE.AnimationMixer(model);
gltf.animations.forEach((clip) => {
mixer.clipAction(clip).play();
});
}
},
(progress) => {
// 加载进度
console.log((progress.loaded / progress.total * 100) + '% loaded');
},
(error) => {
// 加载错误
console.error('Error loading model:', error);
}
);
处理加载的模型
loader.load('model.glb', (gltf) => {
const model = gltf.scene;
// 调整模型大小
model.scale.set(0.5, 0.5, 0.5);
// 调整模型位置
model.position.set(0, 0, 0);
// 遍历模型设置阴影
model.traverse((child) => {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
scene.add(model);
});
其他加载器
// OBJ 格式
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
const objLoader = new OBJLoader();
// FBX 格式
import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';
const fbxLoader = new FBXLoader();
// STL 格式
import { STLLoader } from 'three/addons/loaders/STLLoader.js';
const stlLoader = new STLLoader();
// 纹理加载
import { TextureLoader } from 'three';
const textureLoader = new TextureLoader();
// HDR 环境贴图
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
const rgbeLoader = new RGBELoader();
加载管理器
使用 LoadingManager 管理多个资源的加载:
import { LoadingManager } from 'three';
const manager = new LoadingManager();
manager.onStart = (url, loaded, total) => {
console.log(`Started loading: ${url}`);
};
manager.onProgress = (url, loaded, total) => {
console.log(`Progress: ${loaded}/${total}`);
};
manager.onLoad = () => {
console.log('All resources loaded');
};
manager.onError = (url) => {
console.error(`Error loading: ${url}`);
};
const loader = new GLTFLoader(manager);
粒子系统
粒子系统可以创建雨、雪、火焰、烟雾等效果。
基础粒子
const particleCount = 1000;
const geometry = new THREE.BufferGeometry();
const positions = new Float32Array(particleCount * 3);
const colors = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
positions[i * 3] = (Math.random() - 0.5) * 20;
positions[i * 3 + 1] = (Math.random() - 0.5) * 20;
positions[i * 3 + 2] = (Math.random() - 0.5) * 20;
colors[i * 3] = Math.random();
colors[i * 3 + 1] = Math.random();
colors[i * 3 + 2] = Math.random();
}
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
const material = new THREE.PointsMaterial({
size: 0.1,
vertexColors: true,
transparent: true,
opacity: 0.8
});
const particles = new THREE.Points(geometry, material);
scene.add(particles);
使用纹理的粒子
const textureLoader = new THREE.TextureLoader();
const particleTexture = textureLoader.load('particle.png');
const material = new THREE.PointsMaterial({
size: 0.5,
map: particleTexture,
transparent: true,
blending: THREE.AdditiveBlending,
depthWrite: false
});
粒子动画
function animate() {
requestAnimationFrame(animate);
const positions = particles.geometry.attributes.position.array;
for (let i = 0; i < particleCount; i++) {
positions[i * 3 + 1] -= 0.01; // 向下移动
// 超出范围后重置
if (positions[i * 3 + 1] < -10) {
positions[i * 3 + 1] = 10;
}
}
particles.geometry.attributes.position.needsUpdate = true;
renderer.render(scene, camera);
}
性能优化
几何体优化
合并几何体减少绘制调用:
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
const geometries = [];
for (let i = 0; i < 100; i++) {
const geometry = new THREE.BoxGeometry(1, 1, 1);
geometry.translate(
Math.random() * 10 - 5,
Math.random() * 10 - 5,
Math.random() * 10 - 5
);
geometries.push(geometry);
}
const mergedGeometry = mergeGeometries(geometries);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(mergedGeometry, material);
scene.add(mesh);
实例化渲染适合大量相同几何体:
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const count = 1000;
const mesh = new THREE.InstancedMesh(geometry, material, count);
const matrix = new THREE.Matrix4();
for (let i = 0; i < count; i++) {
matrix.setPosition(
Math.random() * 20 - 10,
Math.random() * 20 - 10,
Math.random() * 20 - 10
);
mesh.setMatrixAt(i, matrix);
}
scene.add(mesh);
材质优化
共享材质减少内存使用:
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
for (let i = 0; i < 100; i++) {
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
}
简化材质避免不必要的计算:
// 如果不需要光照,使用 MeshBasicMaterial
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
// 如果不需要高光,使用 MeshLambertMaterial
const material = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
渲染优化
限制阴影范围:
directionalLight.shadow.camera.near = 1;
directionalLight.shadow.camera.far = 20;
directionalLight.shadow.camera.left = -10;
directionalLight.shadow.camera.right = 10;
directionalLight.shadow.camera.top = 10;
directionalLight.shadow.camera.bottom = -10;
降低分辨率:
// 降低渲染分辨率
renderer.setSize(window.innerWidth * 0.5, window.innerHeight * 0.5, false);
// 限制像素比
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
按需渲染:
let needsRender = true;
function animate() {
if (needsRender) {
renderer.render(scene, camera);
needsRender = false;
}
requestAnimationFrame(animate);
}
// 只在需要时触发渲染
controls.addEventListener('change', () => {
needsRender = true;
});
内存管理
释放资源:
function disposeObject(obj) {
if (obj.geometry) {
obj.geometry.dispose();
}
if (obj.material) {
if (Array.isArray(obj.material)) {
obj.material.forEach(m => m.dispose());
} else {
obj.material.dispose();
}
}
}
// 移除对象时释放资源
scene.remove(mesh);
disposeObject(mesh);
清理纹理:
texture.dispose();
WebXR 支持
Three.js 支持 VR 和 AR 开发:
import { VRButton } from 'three/addons/webxr/VRButton.js';
renderer.xr.enabled = true;
document.body.appendChild(VRButton.createButton(renderer));
function animate() {
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
}
小结
Three.js 的高级特性可以创建更专业、更丰富的 3D 体验:
- 后期处理在渲染后添加视觉效果
- 自定义着色器实现独特的视觉表现
- 模型加载支持各种 3D 格式
- 粒子系统创建动态特效
- 性能优化确保流畅的用户体验
掌握这些高级特性,你就可以创建专业级的 3D Web 应用了。