基于全屏 Quad 的 Three.js 后处理全解析

一、问题背景:

最近在使用three渲染点云的时候遇到一个问题,当我缩放相机到离得很远的时候,这时调整不透明度,就会变得很白很亮,开始我以为可以通过调整设置来解决,就测试深度写入、测试、混合模式之间的各种组合,但是效果都不理想。后面借鉴已有的edl渲染,终于解决这个问题了。

二、后处理核心原理:全屏 Quad 的妙用

在 Three.js 中,后处理的本质是对渲染结果进行二次加工。而 "全屏 Quad"(全屏平面)是实现这一过程的核心载体,其原理可概括为:

  1. 第一步:渲染场景到缓冲区
    先将 3D 场景渲染到一个离屏缓冲区(WebGLRenderTarget),得到包含颜色、深度信息的纹理。

  2. 第二步:用全屏 Quad 加工纹理
    创建一个铺满屏幕的平面(2x2 大小,刚好覆盖标准化设备坐标 NDC),通过自定义着色器材质对第一步得到的纹理进行处理,最终将结果渲染到屏幕。

  3. 核心工具:Utils.screenPass
    具体来说就是封装一个全屏 Quad、场景和相机,在得到纹理图之后,通过把纹理的深度、颜色等信息发送给自定义着色器来二次加工并输出至屏幕。其核心逻辑是通过render方法动态替换材质,实现不同效果的快速切换。

    实现步骤:

  • 定义着色器材质

    javascript

    ini 复制代码
    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

ini 复制代码
// 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

kotlin 复制代码
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 场景焕发新的视觉活力!

相关推荐
Mintopia11 小时前
Three.js 材质与灯光:一场像素级的光影华尔兹
前端·javascript·three.js
Mintopia16 小时前
Three.js 3D 世界中的噪声运动:当数学与像素共舞
前端·javascript·three.js
阿怼丶11 天前
🔥Three.js轮廓线高亮神器来啦!自定义高亮选中效果只需一个类搞定!
前端·three.js
小桥风满袖11 天前
Three.js-硬要自学系列36之专项学习包围盒
前端·css·three.js
Mintopia11 天前
Three.js 模块化开发:代码界的乐高搭建指南
前端·javascript·three.js
刘皇叔code11 天前
Three.js中LightProbe的应用
three.js
小桥风满袖12 天前
Three.js-硬要自学系列35之专项学习盒子辅助器
前端·css·three.js
魂断蓝桥66612 天前
如何基于three.js(webgl)引擎架构,实现3D机房园区,数据中心消防系统
webgl·数字孪生·three.js·物联网3d·3d机房·、3d工厂、3d工业园区、智慧制造、智慧工业、智慧工厂·bim管理系·3d消防·消防演习模拟
Mintopia13 天前
Three.js 魔法融合术:让 UI 与 3D 场景跳起双人探戈
前端·javascript·three.js