首页
/ three.js PostProcessing 类解析:从 r183 弃用到 RenderPipeline 迁移指南

three.js PostProcessing 类解析:从 r183 弃用到 RenderPipeline 迁移指南

2026-09-07 14:14:10作者:咎岭娴Homer

导读

本文以 three.js 官方文档 PostProcessing.html.md 为骨架,系统讲解 PostProcessing 后处理管理模块的 API 形态、其自 r183 起正式弃用并被 RenderPipeline 取代的完整背景,以及将既有后处理代码平滑迁移到 RenderPipeline 的实操路径。读完本文你将掌握:PostProcessing/RenderPipeline 的构造参数与属性语义、基于 TSL 节点构建后处理链(passrenderOutput、FXAA 等)的标准写法、outputColorTransform 关闭的适用场景,以及源码级的执行原理。

说明:官方文档给出的 PostProcessing.html.md 实质是一条 API 弃用说明(含构造函数签名),正文将以其为核心骨架,同时依据仓库内 RenderPipeline.html.mdPostProcessing.js 源码RenderPipeline.js 源码 展开纵深剖析。


一、PostProcessing 是什么

1.1 类定位

PostProcessing 是 three.js 中负责渲染管线与后处理效果链管理的模块。其核心 API 文档(PostProcessing.html.md)给出的构造函数为:

new PostProcessing( renderer : Renderer, outputNode : Node.<vec4> )
  • renderer:对渲染器(renderer)的引用;
  • outputNode:可选输出节点,类型为 Node<vec4>

它承担三类职责:

  1. 持有渲染器引用与最终输出节点;
  2. 以全屏四边形(QuadMesh)方式把一整条节点链渲染到屏幕;
  3. 统一编排渲染管线在每帧动画循环中的执行入口。

1.2 它是如何工作的

从源码看,PostProcessing 本身几乎不含业务逻辑——它只是 RenderPipeline 的向后兼容包装类。见 PostProcessing.js

class PostProcessing extends RenderPipeline {

	constructor( renderer, outputNode ) {

		warnOnce( 'PostProcessing: "PostProcessing" has been renamed to "RenderPipeline". Please update your code to use "THREE.RenderPipeline" instead.' ); // @deprecated, r183

		super( renderer, outputNode );

	}

}

真实的工作负载全部继承自 RenderPipeline。这也是为什么文档会在类简介里用加粗醒目标注:

Deprecated: since r183. Use RenderPipeline instead. PostProcessing has been renamed to RenderPipeline. This class is a wrapper for backward compatibility and will be removed in a future version.

即:自 r183 起弃用,新代码应使用 RenderPipeline;该类仅作兼容包装,未来版本将被移除。构造函数体中的 warnOnce(...) 调用意味着只要代码里仍 new THREE.PostProcessing(...),控制台就会收到一次明确的迁移提示,便于开发者定位遗留用法。

从源码结构看,包装类同时承接了弃用警告的打印与转发构造参数两项工作,可以在不断言新 API 功能的前提下尽量平滑地运行旧程序。


二、替代者 RenderPipeline 的完整能力

从官方文档 RenderPipeline.html.md 可知,RenderPipeline 本身的能力如下:

This module is responsible to manage the rendering pipeline setups in apps. You usually create a single instance of this class and use it to define the output of your render pipeline and post processing effect chain.

Note: This module can only be used with WebGPURenderer.

  • 它用于管理应用中的渲染管线设置;
  • 通常只需创建一个实例,用它定义渲染管线输出与后处理效果链;
  • 只适用于 WebGPURenderer(在 TSL 场景下对应 three/webgpu 构建入口)。传统 WebGLRenderer 下的后处理不在此 API 范畴。

2.1 构造函数

new RenderPipeline( renderer : Renderer, outputNode : Node.<vec4> )

参数与 PostProcessing 完全一致,其中 renderer 为必传,outputNode 可选。源码中 outputNode 的默认值是:

constructor( renderer, outputNode = vec4( 0, 0, 1, 1 ) )

即未显式给出输出节点时,渲染管线会输出一个不透明的白色全屏颜色(RGBA = (0,0,1,1))。这一细节意味着只传 renderer 也可以构造实例,但直到为 outputNode 赋予真正的效果链之前,画面不会反映你的场景。

2.2 属性一览

官方文档列出了四个公开属性,逐一说明其语义、默认值与源码依据(RenderPipeline.js):

属性 类型 默认值 说明
.context Object(只读) null(内部 _contextData 渲染管线栈的当前上下文对象
.needsUpdate Node<vec4>(实为布尔) true 输出节点改变后必须置为 true,触发内部上下文重建
.outputColorTransform boolean true 是否启用默认输出色调映射与色彩空间变换;设为 false 后须自行用 renderOutput() 控制变换顺序
.outputNode Node<vec4> vec4(0,0,1,1) 定义渲染管线最终输出的节点,通常是整条效果链的最后一环
.renderer Renderer 对渲染器的引用(只读语义)

提示:文档中将 .needsUpdate 类型写作 Node.<vec4>,实际源码里是布尔标记(初始 true)。渲染器每帧在 _update() 中检查该标记,必要时调用 _updateContext() 重建材质与上下文后再复位为 false


三、基于 TSL 的标准后处理写法

从源码与示例可以看到,RenderPipeline 与 TSL(Three Shading Language)节点体系深度绑定:outputNode 本身就是一个 Node<vec4>,而非传统“EffectComposer + 多 Pass 对象”的处理器列表。

3.1 最小示例(来自官方文档)

RenderPipeline.html.md 给出的最小用法为:

const renderPipeline = new RenderPipeline( renderer );
const scenePass = pass( scene, camera );

renderPipeline.outputNode = scenePass;
  • pass( scene, camera ) 来自 three/tsl,它把一个场景渲染通道封装为可连接的 TSL 节点;
  • 直接赋给 outputNode 后,动画循环调用 renderPipeline.render() 而非 renderer.render()

3.2 多效果链实战:webgpu_postprocessing.html

examples/webgpu_postprocessing.html 展示了把点阵化(dotScreen)与 RGB 错位(rgbShift)串成链的写法:

renderPipeline = new THREE.RenderPipeline( renderer );

const scenePass = pass( scene, camera );
const scenePassColor = scenePass.getTextureNode().toInspector( 'Scene Color' );

const dotScreenPass = dotScreen( scenePassColor );
dotScreenPass.scale.value = 0.3;

const rgbShiftPass = rgbShift( dotScreenPass );
rgbShiftPass.amount.value = 0.001;

renderPipeline.outputNode = rgbShiftPass;

function animate() {

	object.rotation.x += 0.005;
	object.rotation.y += 0.01;

	renderPipeline.render();

}

要点:

  • 每个效果函数(dotScreenrgbShift)返回节点对象,可直接“喂给”下一个效果;
  • 效果参数以 .value 暴露为可写句柄(如 dotScreenPass.scale.value),便于在动画循环或 UI 面板里动态调整;
  • toInspector()Inspector 配合可把中间结果可视化(示例中渲染器 renderer.inspector = new Inspector());
  • 动画循环中调用的是 renderPipeline.render(),不是 renderer.render()

3.3 outputColorTransform=false 与 FXAA:颜色空间时序问题

outputColorTransform 是迁移者最容易忽略、也最容易出错的开关。RenderPipeline.html.md 对此有专门说明:

Whether the default output tone mapping and color space transformation should be enabled or not. This is enabled by default but it must be disabled for effects that expect to be executed after tone mapping and color space conversion. A typical example is FXAA which requires sRGB input. When set to false, the app must control the output transformation with RenderOutputNode.

含义拆解:

  • three.js 默认把**色调映射(tone mapping)与色彩空间转换(如线性的工作色彩空间 → sRGB)**放在管线末端一次性完成,这是 .outputColorTransform = true 的行为;
  • FXAA 类抗锯齿需要 sRGB 输入——它必须运行在色调映射与色彩空间转换之后。若让变换先做、FXAA 后做(顺序颠倒),画面会出现错误;
  • 因此需要关闭默认自动变换(false),再用 renderOutput( ... ) 在节点链中手动安排转换时机。

官方文档给出了对应的 renderOutput 用法:

const outputPass = renderOutput( scenePass );

examples/webgpu_postprocessing_fxaa.html 是上述理论的完整落地,其导入结构为:

import * as THREE from 'three/webgpu';
import { pass, renderOutput } from 'three/tsl';
import { fxaa } from 'three/addons/tsl/display/FXAANode.js';

核心片段(节选):

renderPipeline = new THREE.RenderPipeline( renderer );

// 关闭默认输出变换,改用 renderOutput() 手动控制顺序
renderPipeline.outputColorTransform = false;

const scenePass = pass( scene, camera ).toInspector( 'Color' );
const outputPass = renderOutput( scenePass );

// FXAA 必须在 sRGB 下计算(即在色调映射与色彩空间转换之后)
const fxaaPass = fxaa( outputPass );
renderPipeline.outputNode = fxaaPass;

链式结构:scene → pass → renderOutput → fxaa → outputNode。即:场景先走 pass,紧接着做颜色变换(tone mapping + sRGB 转换),再交给 fxaa 进行 sRGB 输入下的抗锯齿,最后输出。

源码层面,outputColorTransform 的分支逻辑在 RenderPipeline.js_updateContext() 中:

let outputNode = this.outputNode;

if ( this.outputColorTransform === true ) {

	outputNode = renderOutput( outputNode, toneMapping, outputColorSpace );

} else {

	contextData.toneMapping = toneMapping;
	contextData.outputColorSpace = outputColorSpace;

}

可见:

  • true(默认):管线自动用 renderOutput( outputNode, toneMapping, outputColorSpace ) 包裹输出节点,把渲染器当前的 renderer.toneMappingrenderer.outputColorSpace 应用到末端;
  • false:不自动包裹,改由用户在链中显式调用 renderOutput(),代码负责变换的先后顺序。

同时 render() 内部的执行序也印证了这一设计(相关实现见源码 RenderPipeline.js):

  1. _update():若渲染器的 toneMapping/outputColorSpace 与内部缓存不一致或 needsUpdate === true,重建上下文;
  2. 触发 onBeforePipelineCallbacks
  3. 临时把渲染器置为 NoToneMapping + workingColorSpace,避免 renderer 层面的默认变换与管线内变换叠加冲突;
  4. 用内部 QuadMesh 渲染整条节点链(期间临时关闭 xr.enabled,XR 会话不干扰全屏后处理);
  5. 恢复渲染器原色调映射、色彩空间,触发 onAfterPipelineCallbacks

因此在设置 outputColorTransform = false 且链内显式使用 renderOutput() 时,需要理解:整个“颜色变换”过程已完全由节点链掌控,链路中一旦遗漏转换节点,输出将停留在工作色彩空间(线性)而缺少 sRGB 转换。


四、RenderPipeline 的方法与内部状态机

4.1 方法清单

方法 签名 说明
.render() render() : void 动画循环唯一渲染入口;必须用它替代 renderer.render()
.renderAsync() renderAsync() : Promise 异步版本;已弃用,源码中会打印警告
.dispose() dispose() : void 释放内部资源(释放 _quadMesh 的材质)

4.2 render() vs renderAsync()

官方文档 RenderPipeline.html.md 对二者的注释完全一致:

When RenderPipeline is used to apply rendering pipeline and post processing effects, the application must use this version of render() / renderAsync() inside its animation loop (not the one from the renderer).

即:一旦启用 RenderPipeline,动画循环里渲染画面的是它的 render(),renderer 的同名方法不再负责出画。

renderAsync() 已在文档中标为 Deprecated(返回一个在渲染完成后 resolve 的 Promise)。其源码实现(见 RenderPipeline.js)会打印弃用警告并指出替代方案:

async renderAsync() {

	warnOnce( 'RenderPipeline: "renderAsync()" has been deprecated. Use "render()" and "await renderer.init();" when creating the renderer.' ); // @deprecated r181

	await this.renderer.init();

	this.render();

}

因此 r181 之后建议的做法是:创建渲染器时先 await renderer.init(),动画循环内直接调用 renderPipeline.render(),无需再使用异步渲染。

4.3 内部状态机(_update / _updateContext)

RenderPipeline.js 源码可还原其更新流程:

  • 构造函数初始化 _toneMapping = renderer.toneMapping_outputColorSpace = renderer.outputColorSpace,并创建一块名为 'Render Pipeline'QuadMesh,材质是 NodeMaterialname = 'RenderPipeline');
  • _update() 监听渲染器当前 tone mapping / outputColorSpace 变化,一旦变化即置 needsUpdate = true,随后调用 _updateContext() 重建上下文并把 needsUpdate 复位;
  • _updateContext() 依据 outputColorTransform 分支决定是否自动包裹 renderOutput(...),随后把结果写入 _quadMesh.material.fragmentNode,并以 context( contextData ) 作为材质的 contextNode,同时置 material.needsUpdate = true 强制重编译。

正是这种“渲染管线状态 → 材质片段节点”的映射关系,让 outputNode 里的任意节点链都能在每帧被动态重算与重编译。


五、从 PostProcessing 到 RenderPipeline 的迁移清单

由于 PostProcessing 只是 RenderPipeline 的空壳子类,迁移几乎全是机械替换。依据文档与源码,可按下述步骤操作:

  1. 类名替换new THREE.PostProcessing( renderer, outputNode ) 改为 new THREE.RenderPipeline( renderer, outputNode )

  2. 渲染入口替换 把动画循环里的 postProcessing.render() 改到 renderPipeline.render()(语义未变)。

  3. 去除 renderAsync 依赖 若旧代码用了 renderAsync(),先检查渲染器创建处是否 await renderer.init();是则直接改 render(),否则在初始化流程中补上 init()

  4. 检查 outputNode 链 确认 outputNode 依然是“最后一环”节点。新代码建议直接用 TSL 节点函数(passrenderOutputfxaabloom 等)串联,避免把传统 EffectComposer 式多 Pass 对象塞给 outputNode

  5. 有意为之才关闭 outputColorTransform 只有 FXAA 这类需要“后颜色变换”输入的效果才置 false,并在链内显式调用 renderOutput(...);否则保持默认 true 让系统自动完成色调映射与色彩空间转换。

  6. 旧代码的保留与清理计划 PostProcessing 目前仍能运行,但属于过渡产物,官方文档明示将在未来版本移除。长期维护的项目应尽快迁移,并可在代码中 grep PostProcessing(构建产物为 build/three.webgpu.jsbuild/three.webgpu.nodes.js)定位残留引用。


六、源码与示例索引

核心实现

官方文档

可直接运行的示例(均使用 WebGPURenderer + RenderPipeline)


七、常见问题与注意事项

  1. 为什么 new PostProcessing 时控制台出现警告? 这是 PostProcessing.js 中的 warnOnce() 有意为之,提醒 r183 起改名,属预期行为。

  2. 能否把 PostProcessing/RenderPipeline 用在 WebGLRenderer 上? 不能。官方文档明确 “This module can only be used with WebGPURenderer”。需要 WebGL 后处理时,应使用 examples/jsm/postprocessing/ 下的传统 EffectComposer 体系(与本文 TSL 体系相互独立)。

  3. renderPipeline.render() 与 renderer.render() 能否混用? 文档要求使用 RenderPipeline 时在动画循环调用 renderPipeline.render(),否则整条节点链不会输出。RenderPipeline 内部会临时改写 renderer 的 tone mapping 与色彩空间设置并在渲染后恢复,这一行为本身是自洽的,混用反而会打乱管线。

  4. outputColorTransform = false 后画面发灰/发暗怎么办? 说明链中缺少 renderOutput(...)。该模式下系统不再自动包裹颜色变换,需要在合适位置(通常在被 FXAA 等后颜色空间效果消费之前)显式插入 renderOutput( ... ),形成“先转换、后处理”的时序。


版本与适用前提:本文所有 API 行为、弃用节点(r183 弃用 PostProcessing、r181 弃用 renderAsync)与源码片段,均依据当前仓库 src/renderers/common/RenderPipeline.jssrc/renderers/common/PostProcessing.js 及官方文档核实。TSL 后处理仅在 three/webgpuWebGPURenderer)下可用。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389