用于在three.js中实现后期处理效果。该类管理了产生最终视觉效果的后期处理过程链。 后期处理过程根据它们添加/插入的顺序来执行,最后一个过程注1会被自动渲染到屏幕上。
EffectComposer( renderer : WebGLRenderer, renderTarget : WebGLRenderTarget )
renderer -- 用于渲染场景的渲染器。 renderTarget -- (可选)一个预先配置的渲染目标,内部由 EffectComposer 使用。
一 概述
一个用于处理后期效果的工具,可以通过一系列Pass(处理单元)实现各种复杂的后期效果,如模糊、景深、轮廓线、抗锯齿等
EffectComposer
是一个附加组件,必须显式导入
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
其基本工作流程分为三步:
- 创建
EffectComposer
实例 - 配置
EffectComposer
实例,添加渲染目标注2及一系列(有序的)Pass - 在渲染循环中调用
EffectComposer
实例的render方法进行渲染,取代webGLRenderer
注3
二 实现
1 导入
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js"; // 渲染场景
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js"; // 描边
import { OutputPass } from "three/addons/postprocessing/OutputPass.js"; // 解决整体变暗bug
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js"; // 自定义通道
import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js"; // 抗锯齿
2 初始化
let composer, outlinePass, effectFXAA;
const mouse = new THREE.Vector2();
const raycaster = new THREE.Raycaster(); // 射线
let selectedObjects = []; //
function initComposer() {
composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
outlinePass = new OutlinePass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
scene,
camera
);
outlinePass.visibleEdgeColor.set("#f71b1b"); // 可见部分的描边颜色
outlinePass.hiddenEdgeColor.set("#ac6b20"); // 不可见部分的描边颜色
composer.addPass(outlinePass);
// 到这里发现整体变暗bug,添加OutputPass以解决
const outputPass = new OutputPass();
composer.addPass(outputPass);
// 抗锯齿
effectFXAA = new ShaderPass(FXAAShader);
effectFXAA.uniforms["resolution"].value.set(
1 / window.innerWidth,
1 / window.innerHeight
);
composer.addPass(effectFXAA);
}
3 判断点击
function checkIntersection(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// 设置射线起点为鼠标位置,射线的方向为相机视角方向
raycaster.setFromCamera(mouse, camera);
// 计算射线相交
const intersects = raycaster.intersectObject(scene, true);
if (intersects.length > 0) {
outlinePass.selectedObjects = [intersects[0].object];
} else {
outlinePass.selectedObjects = [];
}
}
4 调用
onMounted(() => {
initComposer();
addEventListener("dblclick", checkIntersection);
function animate() {
requestAnimationFrame(animate);
// renderer.render(scene, camera);
composer.render();
}
animate();
});
三 备注
注1
所谓“最后一个过程”,即是Pass链上的最后一次通道。最后一次通道不会绘制在一个渲染目标上,因为我们可以直接将其放在画布上,这样用户就可以看到最后的结果了
注2
“渲染目标”是Three.js特定的名词,其他地方通常会称其为缓冲区
我们并不是直接在画布上进行渲染,而是在我们称之为"渲染目标"的地方进行渲染。这个渲染目标将会给我们一个非常类似于常规纹理的纹理。说得更简单一点,我们是在一个纹理上进行渲染,而不是在屏幕上的画布上。(也就是webgl中离屏渲染的概念,一个简单的例子是将离屏渲染的东西作为纹理添加到物体上,最后渲染到画布中)
然后,这个纹理被应用到一个面对摄像头并覆盖整个视图的平面上(画布)。这个平面使用了一个特殊的片元着色器的材质,该着色器将进行后期处理效果。如果后期处理效果只是将图像变红,那么它只需在那个片元着色器中将像素的红色值乘以一个值(通常不只只是调整颜色值这么简单)。最后显示到画布上。
在three.js中,这些后处理效果(effects),被称为通道(passes)
注3
function animate() {
requestAnimationFrame(animate);
// renderer.render(scene, camera); // webGLRenderer
composer.render(); // EffectComposer的render方法
}
调用了EffectComposer
的render方法后不需再调用webGLRenderer的render
参考文档
Three.js 如何使用后期处理(How to use post-processing)
【Three.js】知识梳理二十:Three.js后处理EffectComposer