three.js DotScreenPass 使用指南:3 步做出复古网点滤镜
【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js
three.js 的 DotScreenPass 是一个后处理通道,挂在 EffectComposer 通道链末尾,把整幅画面重绘成半色调网点滤镜效果。它最典型的场景,是给复古电视、报纸印刷、怀旧游戏画面加上点阵颗粒质感。本文带你看清最小接入代码、参数调优、运行时调参与 shader 原理。
📺 效果先睹:网点滤镜渲染结果长什么样
场景照常渲染完之后,这个通道会用一整屏的圆点把亮度信息重新"印"出来。想象把报纸凑近看:页面上的油墨变成一粒粒错落的网点;或者回想老式 CRT 电视:亮部细碎发白,暗部点阵连成粗颗粒。画面颜色会被压成接近单色的明暗,只有 alpha 通道原样保留。
仓库官方示例中,它和胶片、辉光等滤镜同屏对比展示,右下角那块布满网点的头像就是这个通道的输出。
三步接入:最小接入代码
第一步,显式引入 addon。DotScreenPass 不在核心包里,它位于 three/addons 目录,必须单独 import。
第二步,建好 EffectComposer(后处理调度器,按顺序串起各个渲染通道),并加一个 RenderPass(把场景渲进缓冲区的第一个通道)。
第三步,用 addPass 把滤镜挂到链尾。链尾通道的结果会直接输出到屏幕。
import * as THREE from 'three'; import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; import { DotScreenPass } from 'three/addons/postprocessing/DotScreenPass.js'; const composer = new EffectComposer( renderer ); composer.addPass( new RenderPass( scene, camera ) ); const dot = new DotScreenPass( new THREE.Vector2( 0, 0 ), 0.5, 0.8 ); composer.addPass( dot );官方示例 webgl_postprocessing_advanced.html 第 166 行用的正是这组参数。
⚙️ 参数调优速查:center、angle、scale
构造函数签名是new DotScreenPass( center, angle, scale ),三个参数全部可选。不传时沿用 DotScreenShader.js 里定义的默认值:
| 参数 | 控制什么 | 默认值 | 调大 / 调小分别看到什么 |
|---|---|---|---|
center | 网点阵列的相位中心,类型为 Vector2 | ( 0.5, 0.5 ) | 点阵整体随之平移,点本身不变形 |
angle | 阵列的旋转角,单位是弧度 | 1.57(约 90°) | 网点阵列持续转向;设为 0 得到正交排布 |
scale | 网点密度系数 | 1.0 | 越大,点越小越密;越小,点越大越粗,颗粒感更强 |
scale 的方向和直觉相反:你以为调大是放大网点,实际是加密。想要粗颗粒的复古感,把它往 0.5 甚至更低调。
运行时调参写法:让网点转起来
想让网点动起来?改一行就行。pass.uniforms是实时调参入口,材质和它共享同一份 uniform 引用,改完下一帧立即生效,无需重建通道:
function animate() { requestAnimationFrame( animate ); dot.uniforms.angle.value += 0.01; // 网点持续旋转 dot.uniforms.scale.value = 0.6 + 0.3 * Math.sin( Date.now() * 0.001 ); // 网点呼吸脉动 composer.render(); } animate();tDiffuse和tSize这两个 uniform 不用你管。每次 render() 时,通道会自动写入上一通道的结果纹理和缓冲区实际宽高,详见 DotScreenPass.js 的 render 实现。
渲染管线机制也值得说一句:它继承自 Pass 基类,每帧由 EffectComposer 调度,从 readBuffer 拿上一通道结果,画进 writeBuffer(链尾则画到屏幕)。内部用一个全屏三角形(FullScreenQuad)遍历所有像素,让每个屏幕像素都执行一次片元着色器。
三步看懂算法:亮度提取、坐标旋转、正弦调制
滤镜核心在片元着色器里。源码注释标明算法源自 glfx.js 项目(以仓库最新源码为准)。拆成三步:
- 亮度提取:取输入像素 R、G、B 三通道均值
average,得到灰度亮度; - 坐标旋转缩放:把 uv 换算到像素坐标(
vUv * tSize),以center为原点,按angle做二维旋转,再乘上scale——三个参数就是这样起作用的; - 正弦调制:对旋转后的 x、y 分别取 sin 再相乘,得到 [-1, 1] 间的周期值,放大 4 倍后叠加到亮度基底
average * 10 - 5上,半色调观感由此而来。
简化后的核心片段:
float average = ( color.r + color.g + color.b ) / 3.0; // 亮度提取 vec2 tex = vUv * tSize - center; // 换算到像素空间 vec2 p = vec2( c*tex.x - s*tex.y, s*tex.x + c*tex.y ) * scale; // 旋转 + 缩放 float pattern = sin( p.x ) * sin( p.y ) * 4.0; // 正弦调制 gl_FragColor = vec4( average * 10.0 - 5.0 + pattern, color.a );想换成斜 45° 新闻纸排布或彩色分色网点,照着pattern()的结构改片段着色器,再替换 pass 的 material 即可。
实战搭配:后处理组合链与 dispose 时机
网点滤镜很少单独出场。常见的 three.js 后处理组合是:RenderPass 先渲场景,GammaCorrectionShader 把线性色阶校正到 sRGB,再接 DotScreenPass,最后用 FilmPass 加胶片颗粒、VignetteShader 压暗四角。色彩校正放网点之前,颗粒和渐晕放网点之后,质感层次更清楚。
composer.addPass( new RenderPass( scene, camera ) ); composer.addPass( new ShaderPass( GammaCorrectionShader ) ); // 校正色阶 const dot = new DotScreenPass( new THREE.Vector2( 0, 0 ), 0.5, 0.8 ); composer.addPass( dot ); composer.addPass( new FilmPass( 0.35, 0.2, 1024, false ) ); // 叠加胶片颗粒 const vignette = new ShaderPass( VignetteShader ); // 四周压暗 vignette.uniforms.offset.value = 1.6; vignette.uniforms.darkness.value = 0.95; composer.addPass( vignette ); dot.dispose(); // 切换场景或重建通道链时调用,释放材质与全屏几何体适用边界:这个 pass 属于 WebGLRenderer 的传统管线,Pass.js 的模块注释也写明它只服务于该体系(以仓库最新源码为准)。项目若走 WebGPU + TSL(Three Shading Language,节点式着色语言),后处理通常改用节点写法,替代实现以仓库最新源码为准。
🚧 避坑清单
- addon 必须显式引入:核心包不含 DotScreenPass,漏了 import 会直接拿到 undefined。它已被 Addons.js 统一导出,走
three/addons入口按需引用即可。 - scale 反直觉:调大是点变密变小,不是点变大。想要粗颗粒就往小调。
- 切换场景记得 dispose:pass 持有 ShaderMaterial 和全屏几何体,不调 dispose() 会留下 GPU 资源泄漏。
- 仅限 WebGLRenderer 传统管线:别把它塞进 WebGPU 节点管线,接口对不上。
- 别手动填 tDiffuse / tSize:它们由 render() 每帧自动赋值,自己缓存引用容易拿到过期纹理。
一句话收尾
把 DotScreenPass 挂到 EffectComposer 链尾,用 center、angle、scale 调出网点密度与走向,再配一层 Gamma 校正和渐晕,你的 WebGL 画面就有了报纸级别的复古质感——切场景或退出页面时,记得补一句dispose()。
【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考