跳到主要内容
3D Playground
Three.js 核心第 12 / 13 节

粒子:Points 星系

进阶WebGL

Points:一个顶点就是一个粒子

THREE.Points 和 Mesh 一样由几何体和材质组成,但它不画三角形:几何体里的每个顶点都会被画成一个始终面向相机的正方形。8 万个粒子只需要一个几何体、一次绘制调用。

几何体:位置和颜色

粒子的数据都放在 BufferGeometry 的属性里:

  • position:每个粒子的 xyz。
  • color:每个粒子的 rgb,材质要开启 vertexColors: true 才会读取。

示例的星系生成规则很简单:随机半径(用 Math.pow 让更多粒子靠近中心)、平均分配到若干条旋臂、角度随半径增加而偏转(形成螺旋)、再加一点随机散布。颜色从中心的暖橙色渐变到外缘的冷蓝色。

PointsMaterial 的关键参数

  • size 与 sizeAttenuation:开启衰减时,远处的粒子显得更小,符合透视。背景星尘关闭了衰减,所以无论多远都是固定像素大小。
  • map:粒子的贴图。我们在 canvas 上画一个径向渐变,得到柔和的光点,而不是硬边方块。
  • transparent: true + depthWrite: false:透明粒子如果写入深度,会把后面粒子的柔和边缘“挡住”,出现黑框。
  • blending: THREE.AdditiveBlending:加法混合,重叠的颜色相加。粒子越密越亮,星系核心自然发光,而且不需要按距离排序。

让它动起来

最简单的方式是旋转整个 Points 对象,但真实星系是差速旋转:内圈转得快、外圈转得慢。示例为每个粒子记录半径和初始角度,每帧按 角速度 ∝ 1 / √r 重新计算位置,然后设置 position.needsUpdate = true。

几万个粒子在 JS 里逐个更新是可行的;数量上到百万级时,应把运动挪到顶点着色器中(自定义 ShaderMaterial),只传一个时间 uniform。

调整 branches、spin 和 randomness,几秒钟就能“设计”出完全不同的星系。

核心 API

THREE.PointsTHREE.PointsMaterialTHREE.BufferGeometryTHREE.BufferAttributeTHREE.CanvasTextureTHREE.AdditiveBlendingmaterial.sizeAttenuationmaterial.vertexColors

动手试试

  1. 1把 blending 改为 NormalBlending,比较星系核心的亮度变化。
  2. 2把 depthWrite 改回 true,靠近观察粒子边缘出现的黑框。
  3. 3去掉 map,粒子会变成什么样子?
  4. 4让角速度与半径无关(去掉 / √r),观察旋臂为什么不再变形。
运行中