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

相关推荐
叫我詹躲躲18 小时前
基于 Three.js 的 3D 地图可视化:核心原理与实现步骤
前端·three.js
map_3d_vis1 天前
JSAPIThree 加载单体三维模型学习笔记:SimpleModel 简易加载方式
学习笔记·three.js·gltf·glb·初学者·三维模型·mapvthree·jsapithree·simplemodel
Addisonx5 天前
深度复盘 III: 核心逻辑篇:构建 WebGL 数字孪生的“业务中枢”与“安全防线”
webgl·three.js
爱看书的小沐5 天前
【小沐学WebGIS】基于Three.JS绘制二三维地图地球晨昏效果(WebGL / vue / react )
javascript·vue.js·gis·webgl·three.js·opengl·晨昏线
Addisonx8 天前
深度复盘: WebGL 数字孪生前端架构:如何打造高颜值、高性能的 Web 3D 可视化系统
three.js
BUG创建者10 天前
thee.js完成线上展厅demo
开发语言·前端·javascript·css·html·css3·three.js
一千柯橘19 天前
从摄影新手到三维光影师:Three.js 核心要素的故事
前端·three.js
big男孩21 天前
OrbitControls 的完整原理
three.js
答案answer22 天前
一些经典的3D编辑器开源项目
前端·开源·three.js
上车函予24 天前
geojson-3d-renderer:从原理到实践,打造高性能3D地理可视化库
前端·vue.js·three.js