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把 blending 改为 NormalBlending,比较星系核心的亮度变化。
- 2把 depthWrite 改回 true,靠近观察粒子边缘出现的黑框。
- 3去掉 map,粒子会变成什么样子?
- 4让角速度与半径无关(去掉 / √r),观察旋臂为什么不再变形。
还没有输出。console.log 的内容会显示在这里。
运行中