7.2后期处理 (Post-processing)


文档摘要

7.2后期处理 (Post-processing) Three.js 高级技术与特效:7.2 后期处理 (Post-processing) 详解与实践 后期处理 (Post-processing) 是 Three.js 中一种强大的技术,它允许我们在渲染场景的最终图像输出之前,对其应用各种视觉效果,例如模糊、色彩校正、景深、辉光等。通过后期处理,我们可以显著提升场景的视觉质量,使其更具电影感和艺术性。 后期处理的原理 简单来说,后期处理就像是在相机拍摄照片后,在图像处理软件中进行的调整。在 Three.

7.2后期处理 (Post-processing)

Three.js 高级技术与特效:7.2 后期处理 (Post-processing) 详解与实践

后期处理 (Post-processing) 是 Three.js 中一种强大的技术,它允许我们在渲染场景的最终图像输出之前,对其应用各种视觉效果,例如模糊、色彩校正、景深、辉光等。通过后期处理,我们可以显著提升场景的视觉质量,使其更具电影感和艺术性。

1. 后期处理的原理

简单来说,后期处理就像是在相机拍摄照片后,在图像处理软件中进行的调整。在 Three.js 中,我们首先将场景渲染到渲染目标 (Render Target) 中,然后将这个渲染目标作为输入,通过一系列的后期处理通道 (Post-processing Pass) 进行处理,最终将处理后的图像输出到屏幕上。

`graph TD

A[3D Scene] --> B(Renderer) B --> C(Render Target) C --> D{Post-processing Passes} D --> E(Final Image) style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#ccf,stroke:#333,stroke-width:2px style C fill:#ccf,stroke:#333,stroke-width:2px style D fill:#ccf,stroke:#333,stroke-width:2px style E fill:#f9f,stroke:#333,stroke-width:2px

`

2. 使用 EffectComposer

Three.js 提供了 EffectComposer 类来管理和执行后期处理通道。 EffectComposer 负责创建渲染目标、添加和执行通道,以及将最终图像输出到屏幕。

基本流程:

  1. 创建 WebGLRenderer: 这是 Three.js 的核心渲染器。

  2. 创建 SceneCamera: 定义要渲染的 3D 场景和观察视角。

  3. 创建 WebGLRenderTarget: 用于存储场景渲染结果的中间缓冲区。

  4. 创建 EffectComposer:WebGLRendererWebGLRenderTarget 传入 EffectComposer,以便管理后期处理流程。

  5. 添加后期处理通道 (Passes): 使用 composer.addPass() 方法将各种后期处理通道添加到 EffectComposer 中。

  6. 渲染循环: 在渲染循环中,调用 composer.render() 方法来执行后期处理并输出最终图像。

代码示例:

import * as THREE from 'three'; import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'; import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'; // 1. 创建渲染器 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 2. 创建场景和相机 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.z = 5; // 添加一个简单的立方体 const geometry = new THREE.BoxGeometry(); const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); // 3. 创建渲染目标 const renderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight); // 4. 创建 EffectComposer const composer = new EffectComposer(renderer, renderTarget); // 5. 添加 RenderPass (必须的第一个 Pass) const renderPass = new RenderPass(scene, camera); composer.addPass(renderPass); // 6. 渲染循环 function animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; // 使用 composer.render() 进行渲染 composer.render(); } animate();

解释:

  • EffectComposer 接管了 renderer.render() 的工作,将场景渲染到内部的渲染目标,然后执行添加的后期处理通道。

  • RenderPass 是一个特殊的 Pass,它负责将场景渲染到 EffectComposer 的内部渲染目标。 它通常是第一个被添加的 Pass,因为后续的 Pass 都依赖于它生成的场景图像。

3. 常用的后期处理通道 (Passes)

Three.js 提供了许多内置的后期处理通道,可以实现各种视觉效果。 我们也可以自定义 Pass 来实现更复杂的效果。

  • RenderPass: 如上所述,负责渲染场景。

  • ShaderPass: 允许你使用自定义的 GLSL 着色器进行图像处理。 这是创建自定义效果的强大工具。

  • BloomPass: 产生辉光效果,使场景中的明亮区域发光。

  • UnrealBloomPass: BloomPass 的改进版本,提供了更多的控制选项,可以产生更逼真的辉光效果。

  • FilmPass: 模拟胶片效果,增加噪点、扫描线和色彩偏移。

  • DotScreenPass: 模拟点阵屏幕效果。

  • GlitchPass: 产生故障艺术效果。

  • OutlinePass: 在模型周围添加轮廓线。

  • SMAAPass / FXAAShader: 抗锯齿效果,减少图像边缘的锯齿感。

  • SSAOPass / SSAOShader: 屏幕空间环境光遮蔽,模拟物体之间的阴影,增加场景的深度感。

  • DepthOfFieldPass: 景深效果,模拟相机聚焦的区域,使其他区域模糊。

  • GammaCorrectionShader: 伽马校正,调整图像的亮度,使其更符合人眼的感知。

  • ColorCorrectionShader: 颜色校正,调整图像的颜色,对比度,亮度。

代码示例:BloomPass

import * as THREE from 'three'; import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'; import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'; import { BloomPass } from 'three/examples/jsm/postprocessing/BloomPass'; // ... (创建 renderer, scene, camera, 立方体的代码与之前相同) ... // 创建 EffectComposer const composer = new EffectComposer(renderer); // 添加 RenderPass const renderPass = new RenderPass(scene, camera); composer.addPass(renderPass); // 添加 BloomPass const bloomPass = new BloomPass( 1, // strength 25, // kernelSize 4, // sigma : 高斯模糊的扩散程度 256 // blurResolution : 模糊效果的分辨率 ); composer.addPass(bloomPass); // 渲染循环 function animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; composer.render(); } animate();

代码示例:UnrealBloomPass

import * as THREE from 'three'; import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'; import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'; import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass'; // ... (创建 renderer, scene, camera, 立方体的代码与之前相同) ... // 创建 EffectComposer const composer = new EffectComposer(renderer); // 添加 RenderPass const renderPass = new RenderPass(scene, camera); composer.addPass(renderPass); // 添加 UnrealBloomPass const unrealBloomPass = new UnrealBloomPass( new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, // strength 0.4, // radius 0.85 // threshold ); composer.addPass(unrealBloomPass); // 渲染循环 function animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; composer.render(); } animate();

代码示例:FXAA抗锯齿

import * as THREE from 'three'; import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'; import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'; import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass'; import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader'; // ... (创建 renderer, scene, camera, 立方体的代码与之前相同) ... // 创建 EffectComposer const composer = new EffectComposer(renderer); // 添加 RenderPass const renderPass = new RenderPass(scene, camera); composer.addPass(renderPass); // 添加 FXAA Pass const fxaaPass = new ShaderPass(FXAAShader); const pixelRatio = renderer.getPixelRatio(); fxaaPass.material.uniforms['resolution'].value.x = 1 / (window.innerWidth * pixelRatio); fxaaPass.material.uniforms['resolution'].value.y = 1 / (window.innerHeight * pixelRatio); composer.addPass(fxaaPass); // 渲染循环 function animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; composer.render(); } animate();

4. 自定义后期处理通道 (ShaderPass)

ShaderPass 允许你使用自定义的 GLSL 着色器来创建独特的后期处理效果。 你需要提供顶点着色器和片元着色器代码。

步骤:

  1. 编写 GLSL 着色器代码: 顶点着色器负责处理顶点数据,片元着色器负责处理像素颜色。

  2. 创建 ShaderMaterial: 将着色器代码传递给 ShaderMaterial

  3. 创建 ShaderPass: 使用 ShaderMaterial 创建 ShaderPass

  4. 添加到 EffectComposer:ShaderPass 添加到 EffectComposer 中。

代码示例:简单的颜色反转效果

import * as THREE from 'three'; import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'; import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'; import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass'; // 顶点着色器 const vertexShader = ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `; // 片元着色器 const fragmentShader = ` uniform sampler2D tDiffuse; // 输入纹理 varying vec2 vUv; void main() { vec4 color = texture2D(tDiffuse, vUv); gl_FragColor = vec4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, color.a); // 颜色反转 } `; // ... (创建 renderer, scene, camera, 立方体的代码与之前相同) ... // 创建 EffectComposer const composer = new EffectComposer(renderer); // 添加 RenderPass const renderPass = new RenderPass(scene, camera); composer.addPass(renderPass); // 创建 ShaderMaterial const shaderMaterial = new THREE.ShaderMaterial({ vertexShader: vertexShader, fragmentShader: fragmentShader, uniforms: { tDiffuse: { value: null } // 输入纹理,由 EffectComposer 自动传递 } }); // 创建 ShaderPass const invertPass = new ShaderPass(shaderMaterial); composer.addPass(invertPass); // 渲染循环 function animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; composer.render(); } animate();

解释:

  • tDiffuseShaderPass 默认的输入纹理 uniform,它接收 EffectComposer 传递的渲染结果。

  • 在片元着色器中,我们使用 texture2D 函数从 tDiffuse 中采样颜色,然后进行颜色反转。

5. 后期处理的性能考虑

后期处理会消耗大量的 GPU 资源,特别是当使用多个 Pass 或复杂的着色器时。 需要注意以下几点来优化性能:

  • 减少 Pass 的数量: 只添加必要的 Pass。

  • 降低渲染目标的分辨率: 使用较小的渲染目标可以提高性能,但会降低图像质量。

  • 简化着色器代码: 避免在着色器中使用复杂的计算。

  • 使用 AdaptiveToneMappingPass: 可以自动调整图像的亮度,减少过度曝光或曝光不足的问题。

  • 使用 HalfFloatType 渲染目标: 在支持的情况下,可以使用 THREE.HalfFloatType 作为渲染目标的数据类型,以减少内存消耗和提高性能。

6. 总结

后期处理是 Three.js 中一个非常强大的工具,可以显著提升场景的视觉质量。 通过组合不同的 Pass 和自定义着色器,你可以创造出各种令人惊叹的效果。 但是,也要注意性能问题,并根据实际情况进行优化。 掌握后期处理技术,将使你的 Three.js 项目更上一层楼。


发布者: 作者: 转发
评论区 (0)
U