Three.js 中实现辉光、景深和色彩校正这三种常用效果的方法:
javascript
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader.js';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.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);
// 可选:添加抗锯齿
const fxaaPass = new ShaderPass(FXAAShader);
composer.addPass(fxaaPass);
// 在动画循环中使用
function animate() {
composer.render();
}
javascript
javascript
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
import { MaskPass, ClearMaskPass } from 'three/examples/jsm/postprocessing/MaskPass.js';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
import { CopyShader } from 'three/examples/jsm/shaders/CopyShader.js';
const composer = new EffectComposer(renderer);
// 1. 渲染所有物体(无辉光)
const renderScene = new RenderPass(scene, camera);
composer.addPass(renderScene);
// 2. 创建辉光层
const bloomComposer = new EffectComposer(renderer);
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // 强度
0.4, // 半径
0.85 // 阈值
);
// 3. 设置需要辉光的物体
const glowLayer = new THREE.Layers();
glowLayer.set(1); // 使用第1层
// 需要辉光的物体添加到第1层
const glowObjects = []; // 存储需要辉光的物体
glowObjects.forEach(obj => {
obj.layers.enable(1);
});
// 4. 创建只渲染辉光物体的场景
const bloomScene = new THREE.Scene();
bloomScene.copy(scene); // 复制原场景
bloomScene.children = bloomScene.children.filter(child =>
glowObjects.includes(child) || child.layers.test(glowLayer)
);
const renderBloomScene = new RenderPass(bloomScene, camera);
bloomComposer.addPass(renderBloomScene);
bloomComposer.addPass(bloomPass);
// 5. 合并两个渲染结果
const finalComposer = new EffectComposer(renderer);
finalComposer.addPass(renderScene);
// 添加辉光层的遮罩
const maskPass = new MaskPass(scene, camera);
maskPass.inverse = true; // 反转遮罩
finalComposer.addPass(maskPass);
// 添加辉光
finalComposer.addPass(new ShaderPass(CopyShader));
finalComposer.addPass(new ClearMaskPass());
// 渲染
function animate() {
// 先渲染辉光层
bloomComposer.render();
// 再渲染最终合成
finalComposer.render();
}
javascript
class SelectiveBloom {
constructor(renderer, scene, camera) {
this.renderer = renderer;
this.scene = scene;
this.camera = camera;
// 创建辉光合成器
this.bloomComposer = new EffectComposer(renderer);
// 基础场景渲染
this.renderPass = new RenderPass(scene, camera);
this.bloomComposer.addPass(this.renderPass);
// 辉光效果
this.bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, 0.4, 0.85
);
this.bloomComposer.addPass(this.bloomPass);
// 创建纹理用于辉光物体
this.bloomTarget = new THREE.WebGLRenderTarget(
window.innerWidth,
window.innerHeight
);
// 需要辉光的物体列表
this.glowObjects = [];
// 创建用于混合辉光的材质
this.blendMaterial = new THREE.ShaderMaterial({
uniforms: {
baseTexture: { value: null },
bloomTexture: { value: this.bloomTarget.texture },
intensity: { value: 1.0 }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D baseTexture;
uniform sampler2D bloomTexture;
uniform float intensity;
varying vec2 vUv;
void main() {
vec4 baseColor = texture2D(baseTexture, vUv);
vec4 bloomColor = texture2D(bloomTexture, vUv);
// 混合辉光
gl_FragColor = baseColor + bloomColor * intensity;
}
`
});
}
addGlowObject(object) {
this.glowObjects.push(object);
// 为物体创建副本用于辉光渲染
const glowMaterial = new THREE.MeshBasicMaterial({
color: object.material.color || 0xffffff,
emissive: object.material.emissive || 0x000000
});
const glowMesh = new THREE.Mesh(object.geometry, glowMaterial);
glowMesh.position.copy(object.position);
glowMesh.rotation.copy(object.rotation);
glowMesh.scale.copy(object.scale);
this.glowScene.add(glowMesh);
}
render() {
// 1. 先渲染辉光物体到单独的目标
this.renderer.setRenderTarget(this.bloomTarget);
this.renderer.clear();
// 只渲染辉光物体
this.glowObjects.forEach(obj => {
const originalVisible = obj.visible;
obj.visible = true;
// 临时更改材质使其在辉光通道中更亮
const originalMaterial = obj.material;
const glowMaterial = new THREE.MeshBasicMaterial({
color: obj.material.color,
emissive: obj.material.emissive || 0x000000
});
obj.material = glowMaterial;
this.renderer.render(obj, this.camera);
// 恢复原状
obj.material = originalMaterial;
obj.visible = originalVisible;
});
// 2. 渲染整个场景
this.renderer.setRenderTarget(null);
this.renderer.render(this.scene, this.camera);
// 3. 应用辉光
this.blendMaterial.uniforms.baseTexture.value =
this.renderer.getContext().canvas;
const quad = new THREE.Mesh(
new THREE.PlaneGeometry(2, 2),
this.blendMaterial
);
const scene = new THREE.Scene();
scene.add(quad);
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
this.renderer.render(scene, camera);
}
}
javascript
// 使用多个渲染通道来实现选择性辉光
function createSelectiveBloom(scene, camera, renderer) {
const bloomLayer = 1;
// 主合成器
const finalComposer = new EffectComposer(renderer);
// 1. 渲染非辉光物体
const normalRender = new RenderPass(scene, camera);
finalComposer.addPass(normalRender);
// 2. 辉光合成器
const bloomComposer = new EffectComposer(renderer);
// 创建辉光场景(只包含辉光物体)
const bloomScene = new THREE.Scene();
const bloomCamera = camera.clone();
const bloomRenderPass = new RenderPass(bloomScene, bloomCamera);
bloomComposer.addPass(bloomRenderPass);
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, 0.4, 0.85
);
bloomComposer.addPass(bloomPass);
// 3. 混合辉光
const mixPass = new ShaderPass(
new THREE.ShaderMaterial({
uniforms: {
baseTexture: { value: null },
bloomTexture: { value: null },
mixRatio: { value: 0.8 }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D baseTexture;
uniform sampler2D bloomTexture;
uniform float mixRatio;
varying vec2 vUv;
void main() {
vec4 base = texture2D(baseTexture, vUv);
vec4 bloom = texture2D(bloomTexture, vUv);
gl_FragColor = base + bloom * mixRatio;
}
`,
transparent: true
})
);
return {
addGlowObject: function(obj) {
// 将物体克隆到辉光场景
const clone = obj.clone();
clone.layers.set(bloomLayer);
bloomScene.add(clone);
},
render: function() {
// 先渲染辉光
bloomComposer.render();
// 设置纹理
mixPass.uniforms.baseTexture.value =
finalComposer.renderTarget2.texture;
mixPass.uniforms.bloomTexture.value =
bloomComposer.renderTarget2.texture;
// 渲染最终结果
finalComposer.render();
}
};
}
javascript
import { BokehPass } from 'three/examples/jsm/postprocessing/BokehPass.js';
// 创建景深效果
const bokehPass = new BokehPass(scene, camera, {
focus: 10.0, // 焦点距离
aperture: 0.025, // 光圈大小
maxblur: 0.01 // 最大模糊度
});
// 添加到合成器
composer.addPass(bokehPass);
// 动态调整焦点
function updateFocus(targetDistance) {
bokehPass.uniforms['focus'].value = targetDistance;
bokehPass.uniforms['aperture'].value =
targetDistance * 0.0005; // 根据距离调整光圈
}
javascript
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
const DepthOfFieldShader = {
uniforms: {
'tDiffuse': { value: null },
'tDepth': { value: null },
'focus': { value: 1.0 },
'aperture': { value: 0.025 },
'maxblur': { value: 1.0 }
},
// ... 着色器代码
};
const dofPass = new ShaderPass(DepthOfFieldShader);
composer.addPass(dofPass);
javascript
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
import { ColorCorrectionShader } from 'three/examples/jsm/shaders/ColorCorrectionShader.js';
const colorCorrectionPass = new ShaderPass(ColorCorrectionShader);
// 调整参数
colorCorrectionPass.uniforms['powRGB'].value =
new THREE.Vector3(1.2, 1.2, 1.2); // 幂次校正
colorCorrectionPass.uniforms['mulRGB'].value =
new THREE.Vector3(1.1, 1.0, 0.9); // 乘法校正
composer.addPass(colorCorrectionPass);
javascript
import { LUTPass } from 'three/examples/jsm/postprocessing/LUTPass.js';
import { LUTCubeLoader } from 'three/examples/jsm/loaders/LUTCubeLoader.js';
// 加载 LUT 文件
const loader = new LUTCubeLoader();
loader.load('path/to/lut.cube', (result) => {
const lutPass = new LUTPass({
lut: result.texture3D,
intensity: 1.0
});
composer.addPass(lutPass);
});
javascript
// 创建自定义颜色校正着色器
const ColorAdjustShader = {
uniforms: {
'tDiffuse': { value: null },
'brightness': { value: 0.0 },
'contrast': { value: 1.0 },
'saturation': { value: 1.0 },
'exposure': { value: 1.0 },
'gamma': { value: 2.2 }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform float brightness;
uniform float contrast;
uniform float saturation;
uniform float exposure;
uniform float gamma;
varying vec2 vUv;
void main() {
vec4 color = texture2D(tDiffuse, vUv);
// 亮度调整
color.rgb += brightness;
// 对比度调整
color.rgb = ((color.rgb - 0.5) * max(contrast, 0.0)) + 0.5;
// 饱和度调整
float luminance = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
color.rgb = mix(vec3(luminance), color.rgb, saturation);
// 曝光调整
color.rgb *= exposure;
// Gamma校正
color.rgb = pow(color.rgb, vec3(1.0 / gamma));
gl_FragColor = color;
}
`
};
const colorAdjustPass = new ShaderPass(ColorAdjustShader);
composer.addPass(colorAdjustPass);
// 实时调整参数
gui.add(colorAdjustPass.uniforms.brightness, 'value', -0.5, 0.5).name('亮度');
gui.add(colorAdjustPass.uniforms.contrast, 'value', 0.5, 2.0).name('对比度');
gui.add(colorAdjustPass.uniforms.saturation, 'value', 0.0, 2.0).name('饱和度');
javascript
// 创建完整的后处理管道
class PostProcessingPipeline {
constructor(renderer, scene, camera) {
this.composer = new EffectComposer(renderer);
// 基础渲染
this.composer.addPass(new RenderPass(scene, camera));
// 辉光效果
this.bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.2, 0.4, 0.85
);
this.composer.addPass(this.bloomPass);
// 景深效果
this.bokehPass = new BokehPass(scene, camera, {
focus: 15.0,
aperture: 0.02,
maxblur: 0.005
});
this.composer.addPass(this.bokehPass);
// 色彩校正
this.colorPass = new ShaderPass(ColorAdjustShader);
this.composer.addPass(this.colorPass);
// 抗锯齿
this.fxaaPass = new ShaderPass(FXAAShader);
this.composer.addPass(this.fxaaPass);
}
setSize(width, height) {
this.composer.setSize(width, height);
}
render() {
this.composer.render();
}
}
// 使用
const pipeline = new PostProcessingPipeline(renderer, scene, camera);
function animate() {
pipeline.render();
requestAnimationFrame(animate);
}
javascript
// 1. 降低分辨率以提高性能
composer.setSize(window.innerWidth * 0.5, window.innerHeight * 0.5);
// 2. 仅在需要时启用效果
function toggleEffects(enabled) {
bloomPass.enabled = enabled;
bokehPass.enabled = enabled;
}
// 3. 使用低质量预设
const lowQualityBloom = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth / 2, window.innerHeight / 2),
1.0, 0.2, 0.6
);
// 4. 动态调整质量
function adjustQualityBasedOnFPS(fps) {
if (fps < 30) {
this.bloomPass.strength = 0.8;
this.bokehPass.maxblur = 0.002;
} else {
this.bloomPass.strength = 1.5;
this.bokehPass.maxblur = 0.01;
}
}
这些效果可以显著提升 Three.js 应用的视觉质量。建议根据具体需求选择合适的效果组合,并注意性能优化。