☰
Three.js HorizontalBlurShader 详解:水平高斯模糊着色器的原理、参数设置与两个实战集成方案
2026/10/8 18:50:57 网站建设 项目流程

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×9=81 次采样,是后期处理中典型的性能优化手段。

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或后处理ShaderPass:

const 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.y,uniform 名相应改为v,其余完全相同。

两个 uniform:tDiffuse 与 h

文档与源码共同确认了水平着色器只暴露两个 uniform,含义如下:

uniform类型默认值含义
tDiffusesampler2Dnull待模糊的输入纹理,通常是上一趟渲染得到的RenderTarget.texture
hfloat1.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, +4h);
  • standard deviation 2.7:权重分布按标准差 σ≈2.7 的高斯曲线w(k) ∝ e^(−k²/(2σ²))计算,中心权重最高、向两侧快速衰减;
  • 权重和为 1:9 个权重2×(0.051 + 0.0918 + 0.12245 + 0.1531) + 0.1633 = 1.0,保证模糊后图像整体亮度不发生变化。

各采样点的偏移与权重可整理为下表:

偏移量−4h−3h−2h−1h0+1h+2h+3h+4h
权重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(垂直模糊) → renderTarget
function 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 方案相同,只是渲染流程完全由你掌控,适合作为某个中间步骤(如阴影、反射、辉光预滤波)嵌入到自定义多趟渲染管线中。

使用要点与易错点

  1. 必须成对使用:HorizontalBlurShader 只沿 x 轴卷积,仅使用它会出现"单向拉伸"的模糊条纹;务必紧跟一趟 VerticalBlurShader。
  2. 按实际渲染目标分辨率设置步长:默认值1/512只适配 512 宽输入。换用不同分辨率时,把h设为1/宽度、v设为1/高度;若要维持相同的"像素级模糊半径",还需要同步缩放偏移倍数。
  3. tDiffuse不能留空:直接使用ShaderMaterial时必须手动喂入待模糊纹理;EffectComposer/ShaderPass场景下则由框架逐趟传递。
  4. 注意渲染顺序:作为后期效果应置于场景渲染与最终颜色输出之间;需要与 GammaCorrectionShader 等配合时,模糊趟通常在线性空间完成。
  5. 大模糊半径时可改用多趟或替代方案:9 采样的固定核在离线渲染目标(如 256 接触阴影)上表现良好;若需要极宽的模糊,可考虑叠加多次执行,或选用仓库内其它专用方案,如可调核宽度的 ConvolutionShader、深度感知的 DepthLimitedBlurShader 以及模拟移轴效果的 HorizontalTiltShiftShader。
  6. 调试技巧:若模糊后画面与输入几乎无差别,先检查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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询