一、问题背景:
最近在使用three渲染点云的时候遇到一个问题,当我缩放相机到离得很远的时候,这时调整不透明度,就会变得很白很亮,开始我以为可以通过调整设置来解决,就测试深度写入、测试、混合模式之间的各种组合,但是效果都不理想。后面借鉴已有的edl渲染,终于解决这个问题了。
二、后处理核心原理:全屏 Quad 的妙用
在 Three.js 中,后处理的本质是对渲染结果进行二次加工。而 “全屏 Quad”(全屏平面)是实现这一过程的核心载体,其原理可概括为:
- 第一步:渲染场景到缓冲区
先将 3D 场景渲染到一个离屏缓冲区(WebGLRenderTarget
),得到包含颜色、深度信息的纹理。 - 第二步:用全屏 Quad 加工纹理
创建一个铺满屏幕的平面(2x2 大小,刚好覆盖标准化设备坐标 NDC),通过自定义着色器材质对第一步得到的纹理进行处理,最终将结果渲染到屏幕。 - 核心工具:
Utils.screenPass
具体来说就是封装一个全屏 Quad、场景和相机,在得到纹理图之后,通过把纹理的深度、颜色等信息发送给自定义着色器来二次加工并输出至屏幕。其核心逻辑是通过render
方法动态替换材质,实现不同效果的快速切换。实现步骤:
-
定义着色器材质:
javascript
const invertMaterial = new THREE.ShaderMaterial({ uniforms: { uSceneTexture: { value: null } // 接收场景纹理 }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; // 传递纹理坐标 gl_Position = vec4(position, 1.0); // 全屏Quad坐标 } `, fragmentShader: ` uniform sampler2D uSceneTexture; varying vec2 vUv; void main() { vec4 color = texture2D(uSceneTexture, vUv); gl_FragColor = vec4(1.0 - color.rgb, color.a); // 反色计算 } ` });
-
使用
screenPass
渲染:
javascript
// 1. 创建渲染目标,用于存储场景原始渲染结果
const renderTarget = new THREE.WebGLRenderTarget(
window.innerWidth,
window.innerHeight
);
// 2. 先将场景渲染到目标缓冲区
renderer.render(scene, camera, renderTarget);
// 3. 传入反色材质,用screenPass渲染到屏幕
invertMaterial.uniforms.uSceneTexture.value = renderTarget.texture;
Utils.screenPass.render(renderer, invertMaterial);
- screenPass函数实现:
javascript
const screenPass = new function () {
// @ts-expect-error
this.screenScene = new THREE.Scene();
// @ts-expect-error
this.screenQuad = new THREE.Mesh(new THREE.PlaneGeometry(2, 2, 1));
// @ts-expect-error
this.screenQuad.material.depthTest = true;
// @ts-expect-error
this.screenQuad.material.depthWrite = true;
// @ts-expect-error
this.screenQuad.material.transparent = true;
// @ts-expect-error
this.screenScene.add(this.screenQuad);
// @ts-expect-error
this.camera = new THREE.Camera();
// @ts-expect-error
this.render = function (renderer, material, target) {
this.screenQuad.material = material;
if (typeof target === 'undefined') {
renderer.render(this.screenScene, this.camera);
} else {
renderer.render(this.screenScene, this.camera, target);
}
};
}();
三、总结:
上面就是基于全屏 Quad 的全流程了,也算是后处理框架中最灵活、最易扩展的方案。通过Quad
自定义着色器我们可以快速实现从简单颜色调整到复杂辉光、边缘检测的各种效果。核心要点在于:
-
理解 “渲染→加工→再渲染” 的后处理流水线;
-
掌握着色器中纹理采样和像素操作的技巧;
-
学会组合多个后处理步骤实现复杂效果。
希望本文能帮助你打开后处理的大门,让你的 3D 场景焕发新的视觉活力!