Three.js HorizontalBlurShader 详解:水平高斯模糊着色器的原理、参数设置与两个实战集成方案 Three.js HorizontalBlurShader 详解水平高斯模糊着色器的原理、参数设置与两个实战集成方案【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js本篇技术指南围绕 Three.js 官方文档中 HorizontalBlurShader 模块页 所描述的着色器展开深入剖析其 9 采样、标准差 2.7 的高斯模糊算法与tDiffuse、h两个 uniform 的含义并结合仓库中的后处理与实时阴影示例讲解它在 EffectComposer 与 ShaderMaterial 两种使用场景下的完整接法。读完本文你将能独立实现任意分辨率的水平/垂直两级模糊流水线并学会如何为它设置正确的模糊步长。HorizontalBlurShader 是什么HorizontalBlurShader是 Three.js 以**插件addon**形式提供的一段预置 GLSL 着色器描述对象存放于 examples/jsm/shaders/HorizontalBlurShader.js。官方文档module-HorizontalBlurShader.html.md对它的定位只有一句话但信息密度很高Two pass Gaussian blur filter (horizontal and vertical blur shaders). —— 它自身只是两趟高斯模糊中的水平方向那一半必须与配套的 VerticalBlurShader 组合先水平后垂直地依次执行才能在两个轴上形成完整的二维高斯模糊效果。之所以拆成两次一维卷积而不是一次二维卷积是因为二维高斯核具有可分离性对N×N大小的核做全卷积每个像素需要N²次纹理采样而拆成水平一趟、垂直一趟后每像素只需2×N次采样。以本文的 9 采样核为例两趟总共 18 次采样远小于单趟二维 9×981 次采样是后期处理中典型的性能优化手段。Import显式导入与 addons 路径映射与核心模块不同HorizontalBlurShader 属于examples/jsm下的附加代码需要显式导入。文档给出了标准写法import { HorizontalBlurShader } from three/addons/shaders/HorizontalBlurShader.js;这里的three/addons/*不是虚拟路径而是由当前仓库 package.json 中的导出映射声明的./examples/jsm/*: ./examples/jsm/*, ./addons: ./examples/jsm/Addons.js, ./addons/*: ./examples/jsm/*也就是说three/addons/shaders/HorizontalBlurShader.js实际解析到本仓库的 examples/jsm/shaders/HorizontalBlurShader.js。如果不使用打包器别名也可以直接在 HTML 模块脚本中按仓库内真实路径导入import { HorizontalBlurShader } from ./examples/jsm/shaders/HorizontalBlurShader.js;此外聚合入口 examples/jsm/Addons.js 通过export * from ./shaders/HorizontalBlurShader.js;把它统一导出了因此习惯整包引用的项目也可以从three/addons一并获得。着色器对象结构源码解析从 HorizontalBlurShader.js 的源码可见该对象由name、uniforms、vertexShader和fragmentShader四个字段构成符合ShaderMaterial~Shader的标准对象结构可直接喂给THREE.ShaderMaterial或后处理ShaderPassconst HorizontalBlurShader { name: HorizontalBlurShader, uniforms: { tDiffuse: { value: null }, h: { value: 1.0 / 512.0 } }, vertexShader: /* glsl */ varying vec2 vUv; void main() { vUv uv; gl_Position projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); }, fragmentShader: /* glsl */ uniform sampler2D tDiffuse; uniform float h; varying vec2 vUv; void main() { vec4 sum vec4( 0.0 ); sum texture2D( tDiffuse, vec2( vUv.x - 4.0 * h, vUv.y ) ) * 0.051; sum texture2D( tDiffuse, vec2( vUv.x - 3.0 * h, vUv.y ) ) * 0.0918; sum texture2D( tDiffuse, vec2( vUv.x - 2.0 * h, vUv.y ) ) * 0.12245; sum texture2D( tDiffuse, vec2( vUv.x - 1.0 * h, vUv.y ) ) * 0.1531; sum texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633; sum texture2D( tDiffuse, vec2( vUv.x 1.0 * h, vUv.y ) ) * 0.1531; sum texture2D( tDiffuse, vec2( vUv.x 2.0 * h, vUv.y ) ) * 0.12245; sum texture2D( tDiffuse, vec2( vUv.x 3.0 * h, vUv.y ) ) * 0.0918; sum texture2D( tDiffuse, vec2( vUv.x 4.0 * h, vUv.y ) ) * 0.051; gl_FragColor sum; } };顶点着色器非常简单把模型自带 UV 原样透传到片段阶段再照常计算裁剪空间位置负责让一个全屏四边形恰好覆盖一帧画面片段着色器仅在vUv.x方向偏移采样vUv.y保持不变——这正是水平二字的由来。对称的 VerticalBlurShader.js 只是把所有偏移换到了vUv.yuniform 名相应改为v其余完全相同。两个 uniformtDiffuse 与 h文档与源码共同确认了水平着色器只暴露两个 uniform含义如下uniform类型默认值含义tDiffusesampler2Dnull待模糊的输入纹理通常是上一趟渲染得到的RenderTarget.texturehfloat1.0 / 512.0水平方向相邻纹素在 UV 坐标上的步长即每偏移 1 个像素对应的 UV 距离h的取值逻辑非常关键。纹理坐标vUv的取值范围是[0, 1]而1 个像素在这套坐标系里恰是1 / 纹理宽度。因此文档明确要求h and v parameters should be set to 1 / width and 1 / height即水平趟把h设为输入纹理宽度的倒数垂直趟把v设为输入纹理高度的倒数。例如在 webgl_postprocessing_advanced.html 示例中width window.innerWidth随后用到了1 / 宽度量级的赋值。默认值1.0 / 512.0对应输入纹理宽 512 像素时的经验取值当渲染目标分辨率改变时必须重新设置否则模糊半径会与像素数脱节。9 采样权重与标准差 2.7 的高斯核文档给出了三组算法特征参数与片段着色器代码一一对应9 samples per pass每趟在中心像素两侧各取 4 个样本连同中心共 9 次纹理采样偏移量-4h, -3h, -2h, -1h, 0, h, 2h, 3h, 4hstandard deviation 2.7权重分布按标准差 σ≈2.7 的高斯曲线w(k) ∝ e^(−k²/(2σ²))计算中心权重最高、向两侧快速衰减权重和为 19 个权重2×(0.051 0.0918 0.12245 0.1531) 0.1633 1.0保证模糊后图像整体亮度不发生变化。各采样点的偏移与权重可整理为下表偏移量−4h−3h−2h−1h01h2h3h4h权重0.0510.09180.122450.15310.16330.15310.122450.09180.051代码中也体现了这一对称结构同一偏移量的两次采样共用一个权重故九行采样仅出现五个权重常量。对每个采样点都乘上高斯权重再累加等效于对每个纹素做一次离散的一维高斯加权平均水平趟结束再交给垂直趟两个方向各自独立卷积后相乘即得到完整的二维高斯模糊。从权重比例反推中心权重 0.1633、邻域 0.1531比值约 0.94 对应e^(−1/(2σ²))可验证文档标注的 σ2.7 是自洽的。集成方案一EffectComposer 中的后处理模糊链在渲染→后期处理架构里HorizontalBlurShader 最常见的归宿是被 ShaderPass 包装进EffectComposer。仓库示例 webgl_postprocessing_advanced.html 展示了它与 VerticalBlurShader 的成对导入import { EffectComposer } from three/addons/postprocessing/EffectComposer.js; import { RenderPass } from three/addons/postprocessing/RenderPass.js; import { ShaderPass } from three/addons/postprocessing/ShaderPass.js; import { GammaCorrectionShader } from three/addons/shaders/GammaCorrectionShader.js; import { HorizontalBlurShader } from three/addons/shaders/HorizontalBlurShader.js; import { VerticalBlurShader } from three/addons/shaders/VerticalBlurShader.js;随后构造两个 ShaderPass 并写入正确的步长示例画面被一分为二故取半屏分辨率const effectHBlur new ShaderPass( HorizontalBlurShader ); const effectVBlur new ShaderPass( VerticalBlurShader ); effectHBlur.uniforms[ h ].value 2 / ( width / 2 ); effectVBlur.uniforms[ v ].value 2 / ( height / 2 );把二者按先 H 后 V的顺序挂进合成器即可composerScene.addPass( effectHBlur )之后再添加垂直趟及其他效果颜色滤镜、晕影、Gamma 校正等。注意ShaderPass会把着色器对象包装成内部材质运行期间通过pass.uniforms访问并驱动tDiffuse由 ShaderPass 自动接入上一趟的输出纹理无需手工指定模糊趟应放在需要柔化的画面效果之后、色调映射/Gamma 校正之前。集成方案二作为 ShaderMaterial 柔化实时接触阴影不经过 EffectComposer 时还可以直接把该着色器对象交给new THREE.ShaderMaterial( HorizontalBlurShader )再结合离屏RenderTarget手工编排渲染顺序。仓库示例 webgl_shadow_contact.html 正是这么做的——先用深度着色器把阴影区域绘制到一张 256 分辨率渲染目标上再对其做水平垂直两次模糊得到柔化的半影边缘const horizontalBlurMaterial new THREE.ShaderMaterial( HorizontalBlurShader ); horizontalBlurMaterial.depthTest false; const verticalBlurMaterial new THREE.ShaderMaterial( VerticalBlurShader ); verticalBlurMaterial.depthTest false;示例中的每帧模糊流程见 webgl_shadow_contact.html形成一条清晰的乒乓渲染链renderTarget → blurPlane(水平模糊) → renderTargetBlur → blurPlane(垂直模糊) → renderTargetfunction blurShadow( amount ) { blurPlane.visible true; // 水平方向模糊写入 renderTargetBlur blurPlane.material horizontalBlurMaterial; blurPlane.material.uniforms.tDiffuse.value renderTarget.texture; horizontalBlurMaterial.uniforms.h.value amount * 1 / 256; renderer.setRenderTarget( renderTargetBlur ); renderer.render( blurPlane, shadowCamera ); // 垂直方向模糊写回 renderTarget blurPlane.material verticalBlurMaterial; blurPlane.material.uniforms.tDiffuse.value renderTargetBlur.texture; verticalBlurMaterial.uniforms.v.value amount * 1 / 256; renderer.setRenderTarget( renderTarget ); renderer.render( blurPlane, shadowCamera ); blurPlane.visible false; }这段代码有几点值得注意的实操细节这里把h写成amount * 1/256正对应渲染目标宽度为 256时的1/width规则amount相当于以像素计的模糊半径缩放系数tDiffuse不再由框架注入而是手工把上一趟渲染目标的纹理赋给材质 uniform模糊所用的blurPlane是一块受shadowCamera正交投影控制的平面因为模糊只关心 UV 采样不参与实际深度测试因此材质关闭了depthTest两次渲染分别写往两个不同的渲染目标再写回避免了在同一纹理上读写导致的采样脏数据。这套H 趟→V 趟的模式本质上与 EffectComposer 方案相同只是渲染流程完全由你掌控适合作为某个中间步骤如阴影、反射、辉光预滤波嵌入到自定义多趟渲染管线中。使用要点与易错点必须成对使用HorizontalBlurShader 只沿 x 轴卷积仅使用它会出现单向拉伸的模糊条纹务必紧跟一趟 VerticalBlurShader。按实际渲染目标分辨率设置步长默认值1/512只适配 512 宽输入。换用不同分辨率时把h设为1/宽度、v设为1/高度若要维持相同的像素级模糊半径还需要同步缩放偏移倍数。tDiffuse不能留空直接使用ShaderMaterial时必须手动喂入待模糊纹理EffectComposer/ShaderPass场景下则由框架逐趟传递。注意渲染顺序作为后期效果应置于场景渲染与最终颜色输出之间需要与 GammaCorrectionShader 等配合时模糊趟通常在线性空间完成。大模糊半径时可改用多趟或替代方案9 采样的固定核在离线渲染目标如 256 接触阴影上表现良好若需要极宽的模糊可考虑叠加多次执行或选用仓库内其它专用方案如可调核宽度的 ConvolutionShader、深度感知的 DepthLimitedBlurShader 以及模拟移轴效果的 HorizontalTiltShiftShader。调试技巧若模糊后画面与输入几乎无差别先检查h是否被设成了 0零步长使 9 个采样点重叠于中心加权后等于原图若只有水平方向可见模糊则说明垂直趟缺失或v未生效。小结HorizontalBlurShader 是 Three.js 附加着色器集合里结构最简、用途最广的成员之一一个name、两个 uniform、一段透传 UV 的顶点着色器和一段 9 采样的水平高斯卷积片段着色器。它与 VerticalBlurShader 构成的两趟模糊管线既是 webgl_postprocessing_advanced.html 演示的通用后期模糊步骤也是 webgl_shadow_contact.html 中柔化实时接触阴影的核心工具。理解h 1/width这一纹素步长约定就能把它无缝迁移到任何分辨率与任何自定义多趟渲染流程中。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考