概述
本文将详细介绍如何使用 Three.js 的后期处理系统来创建各种视觉效果。后期处理是在场景渲染完成后,对最终图像进行额外处理的技术,可以用来实现发光、模糊、故障效果等多种视觉增强效果。
准备工作
首先,我们需要引入必要的 Three.js 库和后期处理模块:
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as dat from "dat.gui";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
// 导入后期效果合成器
import {EffectComposer} from 'three/examples/jsm/postprocessing/EffectComposer';
// three框架本身自带效果
import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass';
import {DotScreenPass} from 'three/examples/jsm/postprocessing/DotScreenPass';
import {SMAAPass} from 'three/examples/jsm/postprocessing/SMAAPass';
import {SSAARenderPass} from 'three/examples/jsm/postprocessing/SSAARenderPass';
import {GlitchPass} from 'three/examples/jsm/postprocessing/GlitchPass';
import {UnrealBloomPass} from 'three/examples/jsm/postprocessing/UnrealBloomPass';
import {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass';
场景初始化
首先,我们需要创建一个基本的 Three.js 场景:
// 初始化场景
const scene = new THREE.Scene();
// 创建透视相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerHeight / window.innerHeight,
1,
50
);
// 设置相机位置
camera.position.set(0, 0, 3);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
scene.add(camera);
// 加入辅助轴,帮助我们查看3维坐标轴
// const axesHelper = new THREE.AxesHelper(5);
// scene.add(axesHelper);
环境设置
设置环境纹理和光照:
// 加载纹理
const textureLoader = new THREE.TextureLoader();
// 添加环境纹理
const cubeTextureLoader = new THREE.CubeTextureLoader();
const envMapTexture = cubeTextureLoader.load([
"textures/environmentMaps/0/px.jpg",
"textures/environmentMaps/0/nx.jpg",
"textures/environmentMaps/0/py.jpg",
"textures/environmentMaps/0/ny.jpg",
"textures/environmentMaps/0/pz.jpg",
"textures/environmentMaps/0/nz.jpg",
]);
scene.background = envMapTexture;
scene.environment = envMapTexture;
// 添加方向光
const directionLight = new THREE.DirectionalLight('#ffffff', 1);
directionLight.castShadow = true;
directionLight.position.set(0, 0, 200);
scene.add(directionLight);
模型加载
加载 3D 模型:
// 模型加载
const gltfLoader = new GLTFLoader();
gltfLoader.load('./models/DamagedHelmet/glTF/DamagedHelmet.gltf', (gltf) => {
console.log(gltf);
const mesh = gltf.scene.children[0];
scene.add(mesh);
});
后期处理合成器设置
这是后期处理的核心部分,创建效果合成器并添加各种通道:
// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
// 合成效果
const effectComposer = new EffectComposer(renderer);
effectComposer.setSize(window.innerWidth, window.innerHeight);
// 添加渲染通道
const renderPass = new RenderPass(scene, camera);
effectComposer.addPass(renderPass);
// 点效果
const dotScreenPass = new DotScreenPass();
dotScreenPass.enabled = false;
effectComposer.addPass(dotScreenPass);
// 抗锯齿
const smaaPass = new SMAAPass();
effectComposer.addPass(smaaPass);
// 发光效果
const unrealBloomPass = new UnrealBloomPass();
effectComposer.addPass(unrealBloomPass);
// 屏幕闪动
// const glitchPass = new GlitchPass();
// effectComposer.addPass(glitchPass)
发光效果参数调节
设置发光效果的参数并添加 GUI 控制:
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;
unrealBloomPass.strength = 1;
unrealBloomPass.radius = 0;
unrealBloomPass.threshold = 1;
// 添加GUI控制
gui.add(renderer,'toneMappingExposure').min(0).max(2).step(0.01);
gui.add(unrealBloomPass,'strength').min(0).max(2).step(0.01);
gui.add(unrealBloomPass,'radius').min(0).max(2).step(0.01);
gui.add(unrealBloomPass,'threshold').min(0).max(2).step(0.01);
自定义着色器后期处理
创建自定义着色器效果:
// 着色器写渲染通道
const shaderPass = new ShaderPass(
{
uniforms:{
tDiffuse:{
value:null
},
uColor:{
value:new THREE.Color(colorParams.r,colorParams.g,colorParams.b)
}
},
vertexShader:`
varying vec2 vUv;
void main(){
vUv = uv;
gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
}
`,
fragmentShader:`
varying vec2 vUv;
uniform sampler2D tDiffuse;
uniform vec3 uColor;
void main(){
vec4 color = texture2D(tDiffuse,vUv);
// gl_FragColor = vec4(vUv,0.0,1.0);
color.xyz+=uColor;
gl_FragColor = color;
}
`
}
);
effectComposer.addPass(shaderPass);
// 颜色参数控制
const colorParams = {
r:0,
g:0,
b:0
}
gui.add(colorParams,'r').min(-1).max(1).step(0.01).onChange((value)=>{
shaderPass.uniforms.uColor.value.r = value;
});
gui.add(colorParams,'g').min(-1).max(1).step(0.01).onChange((value)=>{
shaderPass.uniforms.uColor.value.g = value;
});
gui.add(colorParams,'b').min(-1).max(1).step(0.01).onChange((value)=>{
shaderPass.uniforms.uColor.value.b = value;
});
技术效果着色器
添加技术感的后期处理效果:
const normalTexture = textureLoader.load('./textures/interfaceNormalMap.png');
const techPass = new ShaderPass({
uniforms:{
tDiffuse:{
value:null
},
uNormalMap:{
value:null
},
uTime:{
value:0
}
},
vertexShader:`
varying vec2 vUv;
void main(){
vUv = uv;
gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
}
`,
fragmentShader:`
varying vec2 vUv;
uniform sampler2D tDiffuse;
uniform sampler2D uNormalMap;
uniform float uTime;
void main(){
vec2 newUv = vUv;
newUv += sin(newUv.x*10.0+uTime*0.5)*0.03;
vec4 color = texture2D(tDiffuse,newUv);
// gl_FragColor = vec4(vUv,0.0,1.0);
vec4 normalColor = texture2D(uNormalMap,vUv);
// 设置光线的角度
vec3 lightDirection = normalize(vec3(-5,5,2)) ;
float lightness = clamp(dot(normalColor.xyz,lightDirection),0.0,1.0) ;
color.xyz+=lightness;
gl_FragColor = color;
}
`
})
techPass.material.uniforms.uNormalMap.value = normalTexture;
effectComposer.addPass(techPass);
渲染循环
设置渲染循环并应用后期处理:
const clock = new THREE.Clock();
function animate(t) {
controls.update();
const time = clock.getElapsedTime();
requestAnimationFrame(animate);
// 使用渲染器渲染相机看这个场景的内容渲染出来
// renderer.render(scene, camera);
techPass.material.uniforms.uTime.value = time;
effectComposer.render();
}
animate();
窗口大小调整
处理窗口大小变化:
// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix();
// 更新渲染器
renderer.setSize(window.innerWidth, window.innerHeight);
// 设置渲染器的像素比例
renderer.setPixelRatio(window.devicePixelRatio);
effectComposer.setSize(window.innerWidth, window.innerHeight);
effectComposer.setPixelRatio(window.devicePixelRatio);
});
各种后期处理效果介绍
- RenderPass: 基础渲染通道,负责渲染原始场景
- DotScreenPass: 点阵屏幕效果,产生类似扫描线的视觉效果
- SMAAPass: 智能抗锯齿处理,提高画面质量
- UnrealBloomPass: 虚幻引擎风格的发光效果,使明亮区域产生光晕
- GlitchPass: 故障效果,模拟信号干扰的视觉效果
- ShaderPass: 自定义着色器效果,可实现任意的后期处理效果
总结
通过这个项目,我们学习了如何使用 Three.js 的后期处理系统:
- 创建 EffectComposer 作为后期处理的核心
- 添加不同类型的 Pass 来实现各种效果
- 通过参数调节控制效果强度
- 实现自定义着色器后期处理
- 在渲染循环中使用 composer.render() 替代传统的 renderer.render()
后期处理技术是提升三维场景视觉效果的重要手段,能够显著增强画面的表现力和沉浸感。掌握这些技术可以让你的 Three.js 应用更具视觉冲击力。