用三维粒子打造数字展厅:从零到可交互的可视化系统
这是一篇通俗易懂的技术博客,带你理解一个基于 Web 的三维粒子化展示系统是如何工作、如何使用以及如何扩展。无论你是前端开发者还是产品同学,都可以通过这篇文章快速把握它的设计思路与实践方法。
为什么选择粒子化
- 粒子系统适合表达"星空、烟雾、能量波"等具有群体行为的视觉效果,且可在交互中带来强烈的沉浸感。
- 在数字展厅场景中,把图片、文字或 3D 模型"粒子化",可以获得更具艺术性的呈现方式,并支持多样的动态效果与交互调节。
能力一览(你能做什么)
- 四种展示模式:随机云海、文本成像、图片成像、GLTF 模型采样。
- 多种动态特效:爆裂回流、星环涡旋、光爆冲击波、黑洞吞噬、瀑布云幕、彩虹换色、风洞回旋、星群聚散、波纹干涉、球壳成像、网格阵列等。
- 交互与功能:上传与拖拽、预设选择、参数调节、截图保存、视角重置、FPS 监控。
系统截图:



演示视频上传到谷歌云盘:
https://drive.google.com/file/d/1Vi0we39LJLQA4hQER1mqF61S2Qm4qk5c/view?usp=drive_link

技术选型(为什么这样搭)
- React + TypeScript:组件化构建 UI 与状态管理,类型安全、维护轻松。
- Vite:快速开发与构建,支持现代浏览器特性与热更新。
- three + React Three Fiber(R3F):在 React 中优雅管理 three 的渲染生命周期,用组件写 3D。
- drei:提供常用的 three 辅助控件(如相机控制)。
- postprocessing:实现 Bloom 等后期效果,增强视觉表现力。
架构总览(系统由哪些部分组成)
- 页面入口:挂载 React 应用,加载样式与主组件。
- 主应用组件:控制模式与特效切换、管理上传与预设、驱动参数面板与场景。
- 粒子场景组件:管理几何数据(位置、颜色、目标点)、自定义着色器、逐帧动力学更新。
- 图片采样模块(含工作线程):将图片采样为目标点云与颜色;异步处理保证流畅度。
- UI 面板:
- 上传面板:图片/GLB 上传与拖拽、预设、文本输入。
- 参数面板:调节 Bloom、粒子尺寸、反中心斥力、遮罩空洞、运动速度、相机角度、粒子数量;支持截图与视角重置。
- 资源预设:示例图片与模型预设,便于快速演示。
渲染管线(一步步把粒子画出来)
- Canvas 与 R3F:R3F 提供
Canvas容器与useFrame钩子,每一帧更新粒子位置与着色器参数。 - 粒子几何:使用
Points(点云)与BufferGeometry,在缓冲区中存储位置 (position) 与颜色 (color)。 - 点精灵着色器:
- 顶点着色器控制点大小,并把世界坐标与颜色传到片元阶段。
- 片元着色器绘制圆形点精灵,支持遮罩空洞(硬边/软边)与彩虹色相偏移,并根据设备像素比调整清晰度。
示意伪代码(逐帧更新):
ts
for (i = 0; i < N; i++) {
// 噪声驱动的基础流动
velocities[i] += curlNoise(positions[i]) * step
// 叠加特效:以"速度场"的方式影响粒子
if (effect === 'vortex') velocities[i] += tangentialFlow(positions[i]) * step
if (effect === 'shockwave') velocities[i] += radialWave(positions[i], time) * step
if (effect === 'waterfall') velocities[i] += downwardFlow(positions[i], time) * step
if (effect === 'blackhole') velocities[i] += inwardFlow(positions[i], radius) * step
// 目标吸引(文字/图片/GLTF)
velocities[i] += (targets[i] - positions[i]) * attractStrength * step
// 抗中心斥力与鼠标交互
velocities[i] += antiCenterRepel(positions[i])
velocities[i] += mouseRepel(positions[i], mouse)
// 阻尼与积分
velocities[i] *= damping
positions[i] += velocities[i]
}
图片如何变成粒子(工作线程的作用)
- 基本思路:把图片绘制到隐藏画布 → 读取像素 → 基于亮度与饱和度筛选采样点 → 映射到三维坐标 → 同步颜色。
- 关键参数:
- Gamma(亮度增强):控制采样时的明暗分布,使细节更"可见"。
- 动态阈值分位(亮度百分位):在不同图片中自适应地选择亮度阈值,避免过暗或过亮导致点太少或太多。
- 饱和度阈值 + 白背景剔除:跳过"低饱和且高亮"的区域,常用于去除纯白背景。
- 透明度阈值:过滤掉透明像素。
- 为什么用工作线程:像素扫描与统计是 CPU 密集型任务,放到线程中可避免主线程卡顿。
示意伪代码(采样逻辑):
ts
const data = readImagePixels()
const freq = brightnessHistogram(data, gamma)
const threshold = findDynamicThreshold(freq, quantile)
for (each pixel in data step k) {
const bright = brightness(pixel, gamma)
const sat = saturation(pixel)
const isWhiteBg = sat < satMin && bright >= whiteMin
if (alpha > alphaMin && !isWhiteBg && (bright > threshold || sat >= satMin)) {
pts.push(mapTo3D(x, y))
cols.push(color(pixel, fidelity))
}
}
文本与模型采样(直观理解)
- 文本:把文字绘制到画布,取其"白色区域"的像素作为目标点,自动调整字号以适配画布大小。
- GLTF 模型:读取网格的顶点位置,按步长稀疏采样形成目标点云,并做统一尺度映射,保证整体大小适中。
特效的原理(通俗解释)
- 爆裂回流:先给粒子一个"向外"的速度脉冲,再用目标吸引把它们拉回,形成呼吸式爆散与回归。
- 星环涡旋:围绕中心构建切向速度场(像旋风),距离越远旋转越快,形成星环旋转的视觉效果。
- 光爆冲击波:随半径传播的正弦波,粒子在波峰处被推动、在波谷处回落,像"声波环"由内向外扩散。
- 黑洞吞噬:向中心收敛,遮罩在片元着色器阶段把"圆心区域"裁掉,保证可见的空洞。
- 瀑布云幕:整体向下叠加小幅摆动,形成瀑布云的"飘散"感。
- 彩虹换色:在着色器中对色相做周期性偏移,颜色随时间变化,形成彩虹般的流动。
- 风洞回旋、星群聚散、波纹干涉、球壳成像、网格阵列:分别通过速度场或目标映射构造出直观的群体行为。
交互与参数(如何控制场景)
- 工具栏:一键切换特效,随时返回默认效果。
- 参数面板:
- 视觉:Bloom 阈值与强度、粒子尺寸、遮罩空洞半径与边缘软硬。
- 动力学:反中心斥力强度与半径、运动速度。
- 相机:水平角与俯仰角、视角重置。
- 规模:粒子数量与 FPS 监控。
- 上传面板:图片/GLB 文件拖拽与选择、预设资源、文本输入与应用;支持颜色保真、适配策略切换(保持比例/铺满裁剪)。
- 截图:将当前画面保存为图像,便于留存与分享。
性能与优化建议(顺畅很重要)
- 控制粒子数量与尺寸:数量越多负担越重;点越大着色器片元计算越多。
- 合理使用 Bloom:过强的后期会增加负载,可适度降低或关闭。
- 速度步长与阻尼:步长过大容易"抖",阻尼过小容易"乱";二者平衡能带来更稳的视觉。
- 资源大小:尽量使用体积适中的图片与模型,降低网络与解析压力。
- 线程分工:将采样计算放到工作线程,主线程专注渲染与交互。
快速上手与扩展(立刻试试)
- 安装依赖:
npm install - 开发启动:
npm run dev - 生产构建:
npm run build - 本地预览:
npm run preview - 扩展建议:
- 新增一个特效的思路:
- 在逐帧更新中,设计新的速度场函数,如
swirlFlow(p, t)。 - 根据粒子位置与时间返回速度增量,叠加到
velocities[i]。 - 结合参数面板添加可调节项(强度、半径、频率)。
- 在逐帧更新中,设计新的速度场函数,如
- 接入音频:通过音频频谱的幅值,映射到吸引力或脉冲强度,形成"随音乐起舞"的效果。
- 新增一个特效的思路:
示意伪代码(新增特效框架):
ts
function updateFrame(time) {
for (i = 0; i < N; i++) {
const p = positions[i]
velocities[i] += swirlFlow(p, time) * intensity * step
positions[i] += velocities[i] * damping
}
}
常见问题(FAQ)
- 图片太暗/太亮:提高或降低 Gamma;调整亮度阈值分位(quantile)。
- 白底去不掉:提高白亮阈值并设置更大的饱和度阈值。
- 卡顿明显:减少粒子数量、减小粒子尺寸、降低 Bloom 强度,或避免同时叠加多个强特效。
- 端口占用:更换开发端口或关闭占用端口的程序后再启动预览。
总结与下一步
-
该系统以"速度场 + 目标吸引 + 着色器表达"为核心,既能满足艺术化展示,也能为更多展陈场景(多图序列、镜头关键帧、热点卡片等)提供基础。
-
下一步可以尝试:
- 加入镜头关键帧系统,实现自动漫游与镜头语言。
- 设计热点卡片,在粒子图像之上叠加信息层。
- 接入多媒体资源与主题皮肤,打造更完整的展示体验。
-
项目源码:项目地址