基于全屏 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 场景焕发新的视觉活力!

相关推荐
入秋16 小时前
Three.js 实战之电子围栏可根据模型自动生成
前端·前端框架·three.js
答案answer2 天前
three.js着色器(Shader)实现数字孪生项目中常见的特效
前端·three.js
KallkaGo7 天前
threejs复刻原神渲染(三)
前端·webgl·three.js
刘皇叔code8 天前
如何给Three.js中ExtrudeGeometry的不同面设置不同材质
webgl·three.js
vivo互联网技术9 天前
拥抱新一代 Web 3D 引擎,Three.js 项目快速升级 Galacean 指南
前端·three.js
你真的可爱呀13 天前
5.Three.js 学习(基础+实践)
学习·three.js
战场小包15 天前
弟弟想看恐龙,用文心快码3.5S快速打造恐龙乐园,让弟弟看个够
前端·three.js·文心快码
入秋15 天前
Three.js后期处理实战:镜头颜色、色差、点阵与颜色管道的深度解析
前端·three.js