资讯动态

three.js SAOPass 详解:Scalable Ambient Occlusion 屏幕空间环境光遮蔽后处理实现

发布时间:2026/9/8 23:14:13 来源:尧图企业网站定制
three.js SAOPass 详解Scalable Ambient Occlusion 屏幕空间环境光遮蔽后处理实现【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js导读SAOPassScalable Ambient Occlusion可缩放环境光遮蔽是 three.js 官方提供的后处理Post-processingPass 之一用于在 WebGL 渲染管线中为场景加入基于屏幕空间近似算法生成的环境光遮蔽效果让物体接触面、缝隙与角落处产生柔和的接触阴影从而显著提升画面立体感与真实感。本指南以 docs/pages/SAOPass.html.md 为骨架结合examples/jsm/postprocessing/SAOPass.js、examples/jsm/shaders/SAOShader.js与examples/jsm/shaders/DepthLimitedBlurShader.js等源码从构造方式、参数语义、内部多阶段渲染流程到可运行的完整示例帮助你直接把它接入自己的 EffectComposer 管线并理解其底层工作原理。一、SAOPass 是什么与 SSAOPass 的定位差异SAOPass是由社区开发者 Ludobaka 实现的屏幕空间环境光遮蔽算法其灵感与算法根源来自 Ben Houston 早前的 SAOScalable Ambient Occlusion实现demo 页面examples/webgl_postprocessing_sao.html中的标注同样注明 shader by Ben Houston / Post-processing pass by Ludobaka。在 three.js 的后处理体系中同类的算法还有SSAOPassScreen-Space Ambient Occlusion。官方对两者的定位差异非常明确SAOPass提供比SSAOPass更好的质量但开销也更高。因此在工程选型上追求性价比可以选择 SSAO对画面质量敏感、且 GPU 预算允许时再选择 SAO。SAOPass继承自后处理基类Pass接口约定与调度行为统一由 examples/jsm/postprocessing/Pass.js 定义。二、引入与最小接入示例SAOPass属于 three.js 的 addons附加组件不会被包含在核心构建中必须显式导入import { SAOPass } from three/addons/postprocessing/SAOPass.js;将其加入渲染管线的最小示例与源码 SAOPass.js 中的示例一致const composer new EffectComposer( renderer ); const renderPass new RenderPass( scene, camera ); composer.addPass( renderPass ); const saoPass new SAOPass( scene, camera ); composer.addPass( saoPass );需要注意的是SAOPass需要接入完整的 EffectComposer 管线才能工作而不是独立渲染它依赖RenderPass先把场景渲染进缓冲并且通常在其后追加一个OutputPass用于颜色空间/色调映射输出下文完整示例会给出整条管线。此外示例仓库中还提供官方 Demo 页面examples/webgl_postprocessing_sao.html可直接打开查看运行效果。三、构造函数new SAOPass( scene : Scene, camera : Camera, resolution : Vector2 )从 SAOPass.js 构造函数 可以看到参数定义参数类型说明sceneScene需要计算环境光遮蔽的场景。Pass 内部会用深度与法线信息重渲染该场景见第五部分源码分析。cameraCamera渲染所用相机。既支持透视相机也支持正交相机源码通过this.camera.isPerspectiveCamera判断并在 shader 中定义PERSPECTIVE_CAMERA宏见 SAOShader.js。resolutionVector2可选效果AO 纹理的渲染分辨率默认值为new Vector2( 256, 256 )。传入后内部会复制一份存于this.resolution。AO 纹理独立于主缓冲可低于屏幕分辨率以换取性能。示例// 以默认 256×256 分辨率计算 AO const saoPass new SAOPass( scene, camera ); // 以更高分辨率计算获得更精细的 AO 细节 const saoPassHi new SAOPass( scene, camera, new THREE.Vector2( 512, 512 ) );四、Properties属性详解.camera : Camera当前用于 AO 计算的相机与构造参数一致。.clear : boolean重写为默认执行一次清屏操作默认值为true。它覆盖了基类 Pass#clear 的默认false。.needsSwap : boolean被重写为关闭缓冲交换默认值为false。覆盖自 Pass#needsSwap 的默认true。在SAOPass中此标志为false意味着结果直接合成到readBuffer上内部通过自定义混合完成而不再与writeBuffer进行交换这一点与第五部分render()的源码行为一致。.params : ObjectSAO 的全部可调参数集中存放于该对象是实际调参的核心入口。下表列出 源码默认值 及官方示例页examples/webgl_postprocessing_sao.html的 GUI 可调范围并给出各参数作用参数默认值GUI 建议范围含义output0见下输出模式取SAOPass.OUTPUT枚举值saoBias0.5[-1, 1]遮蔽判断的偏置量用于抑制自遮蔽self-occlusion产生的黑斑噪点saoIntensity0.18[0, 1]AO 遮蔽强度越大阴影越深saoScale1[0, 10]遮蔽影响半径的空间比例因子与场景尺度相关saoKernelRadius100[1, 100]采样核半径像素级越大遮蔽范围越广、开销越高saoMinResolution0[0, 1]归一化的最小遮蔽分辨率阈值用于控制近处/远处细节参与度saoBlurtrue开关是否对 AO 纹理执行深度限制的双向高斯模糊以去除噪点saoBlurRadius8[0, 200]模糊核半径执行时会被Math.floor取整为整数见 SAOPass.jssaoBlurStdDev4[0.5, 150]高斯模糊标准差决定权重衰减速度saoBlurDepthCutoff0.01[0.0, 0.1]深度断裂处的视空间截止值相对比例防止模糊跨越边缘渗色其中output对应SAOPass.OUTPUT静态枚举定义于 SAOPass.js 末尾SAOPass.OUTPUT { Default: 0, // 默认混合结果原画面 × AO SAO: 1, // 仅输出 AO 遮蔽因子 Normal: 2 // 仅输出法线缓冲调试用 };各通道可分别用于最终合成与算法调试便于观察中间结果。.resolution : Vector2效果AO分辨率默认(256, 256)。修改后需通过setSize同步内部 RenderTarget。.scene : Scene用于渲染 AO 的场景与构造参数一致。五、Methods方法详解.render( renderer, writeBuffer, readBuffer, deltaTime, maskActive )执行 SAO 后处理的核心逻辑源码位置。deltaTime与maskActive参数在接口上保留由EffectComposer传入当前实现中并未实际使用形参注释掉。参数含义与基类一致rendererWebGLRenderer 渲染器writeBuffer写入缓冲理论上为本 Pass 的目标缓冲readBuffer读取缓冲可从中拿到上一 Pass 的结果此处即RenderPass渲染出的原始场景画面deltaTime距上一帧的时间差秒maskActive当前是否处于遮罩mask激活状态。.setSize( width, height )调整 Pass 尺寸源码。它会同步三个内部 RenderTarget 的尺寸并把新的尺寸写入各 shader 的sizeuniform同时刷新相机投影矩阵相关 uniform。EffectComposer在窗口尺寸变化时会自动调用它但你也可以在 composer.setSize 中随分辨率手动触发。.dispose()释放该实例分配的 GPU 相关资源源码。依次释放三个 RenderTarget、五个材质normalMaterial、saoMaterial、vBlurMaterial、hBlurMaterial、materialCopy以及fsQuad。当 Pass 不再使用时务必调用避免显存泄漏。覆盖自 Pass#dispose。六、内部工作原理多阶段渲染管线从源码实现可以还原出SAOPass.render()的完整执行流水线整个算法被拆解为若干个全屏或场景渲染阶段可选直通上一 Pass 结果若renderToScreen为true先用无混合的materialCopy将readBuffer纹理直接输出到屏幕保证直通预览与叠加效果一致SAOPass.js。参数上传与同步把params.saoBias、saoIntensity、saoScale、saoKernelRadius、saoMinResolution写入saoMaterial的 uniforms把相机 near/far 传入 SAO 材质与模糊材质深度截止值按saoBlurDepthCutoff × (camera.far − camera.near)换算为视空间绝对深度差当saoBlurRadius/saoBlurStdDev变化时通过BlurShaderUtils.configure()重新生成高斯权重与采样偏移SAOPass.js权重生成公式见 DepthLimitedBlurShader.js。渲染法线与深度使用MeshNormalMaterial作为scene.overrideMaterial重渲染整个场景到normalRenderTarget配合DepthStencilFormat/UnsignedInt248Type的DepthTexture一并得到法线与深度内部方法_renderOverrideSAOPass.js。这一阶段是后续 AO 估计的数据来源。SAO 主计算将场景法线贴图与深度贴图喂给SAOShader材质渲染到saoRenderTarget内部方法_renderPassSAOPass.js。可选的深度限制模糊当saoBlur为true时先垂直vBlurMaterial方向(0,1)模糊到blurIntermediateRenderTarget再水平hBlurMaterial方向(1,0)模糊回saoRenderTarget即两次分离式高斯模糊。结果合成按params.output选择数据源法线缓冲或 AO 缓冲对Default模式使用基于DstColorFactor/ZeroFactor的自定义混合把 AO 因子乘以到readBuffer上混合相关设置见 SAOPass.js其他输出模式则用NoBlending直接覆盖最终写入readBuffer或屏幕。需要指出深度限制模糊Depth Limited Blur是保证 SAO 质量的关键——普通高斯模糊会跨越深度不连续处产生边缘渗色bleeding而 DepthLimitedBlurShader.js 在采样时一旦发现相邻样本视空间深度差超过depthCutoff便停止累积权重从而保护边缘轮廓。七、完整可运行示例综合examples/webgl_postprocessing_sao.html的官方用法组装一套含 RenderPass → SAOPass → OutputPass 的完整管线如下import * as THREE from three; import { EffectComposer } from three/addons/postprocessing/EffectComposer.js; import { RenderPass } from three/addons/postprocessing/RenderPass.js; import { SAOPass } from three/addons/postprocessing/SAOPass.js; import { OutputPass } from three/addons/postprocessing/OutputPass.js; // 1. 基础场景 const renderer new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera( 65, window.innerWidth / window.innerHeight, 3, 10 ); camera.position.z 7; // 2. EffectComposer 管线RenderPass 先把场景画进缓冲 const composer new EffectComposer( renderer ); composer.addPass( new RenderPass( scene, camera ) ); // 3. 挂载 SAOPass const saoPass new SAOPass( scene, camera ); composer.addPass( saoPass ); // 4. 最后输出到屏幕负责正确的颜色空间转换与色调映射 composer.addPass( new OutputPass() ); // 5. 调参对象密集的小尺度场景建议适当调低 saoScale、调高 saoIntensity saoPass.params.output SAOPass.OUTPUT.Default; saoPass.params.saoBias 0.5; saoPass.params.saoIntensity 0.3; saoPass.params.saoScale 2; saoPass.params.saoKernelRadius 100; saoPass.params.saoBlurRadius 8; saoPass.params.saoBlurStdDev 4; // 6. 逐帧渲染 renderer.setAnimationLoop( () composer.render() );官方示例场景为 120 个随机分布的小球体组成的球簇见examples/webgl_postprocessing_sao.html适合直观观察球体间接触处的 AO 阴影变化。调试时可借助 GUI 把output切到SAOPass.OUTPUT.SAO纯 AO 图或SAOPass.OUTPUT.Normal法线图查看中间结果。窗口尺寸变化时需同步更新window.addEventListener( resize, () { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); composer.setSize( window.innerWidth, window.innerHeight ); } );八、调参与资源管理实践建议参数调优要点来自源码与官方示例的 GUI 区间saoScale需要与场景尺度适配源码在 shader 中以scale / cameraFar归一化SAOShader.js场景偏大时应调高该值否则 AO 范围会显得过小。saoIntensity控制在0.05 ~ 0.5之间可获得自然效果过大时接触处会发黑死寂。出现噪点/闪烁时优先增大saoBlurRadius与saoBlurStdDev或微调saoBias抑制自遮蔽而saoBlurDepthCutoff过大会让模糊跨越深度边缘导致边缘发虚该值默认0.01已是较稳妥的起点。AO 分辨率resolution默认256×256属于较保守的性能取向对高端设备可提高到512×512提升质量同时观察帧率预算。资源释放当 SAOPass 被移除或应用销毁时调用saoPass.dispose()释放其内部三个 RenderTarget 与全部材质、全屏四边形资源。深度缓冲兼容性说明SAOPass 内部创建独立深度纹理DepthStencilFormatUnsignedInt248Type不从场景现有深度缓冲复用因此在需要反转深度缓冲reversed depth buffer的渲染器配置下仍可正常工作shader 内通过USE_REVERSED_DEPTH_BUFFER宏适配见 SAOShader.js。该 Pass 仅适用于 WebGL 渲染器基于Pass/FullScreenQuad体系WebGPU 渲染器需使用对应的 TSL 后处理实现。九、相关文件索引类实现examples/jsm/postprocessing/SAOPass.js核心 AO 着色器examples/jsm/shaders/SAOShader.js深度限制模糊着色器与权重生成工具examples/jsm/shaders/DepthLimitedBlurShader.js后处理基类Pass与FullScreenQuadexamples/jsm/postprocessing/Pass.js官方示例 Demoexamples/webgl_postprocessing_sao.html同族对比实现SSAOexamples/jsm/postprocessing/SSAOPass.jsAPI 文档页docs/pages/SAOPass.html.md【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价