DAY 16
1
Modern Web

## 用 Three.js 來當個創世神 (15)：粒子系統 - 雪花 Part.2

You know nothing, Jon Snow. 在實作粒子系統的動畫效果時，踩到了個大坑，本篇將會繼續完成前一天的雪花飄落動畫，並分享實作中遇到的問題及可以優化效能的部分。

Photo by Zack Sharf on IndieWire

## 動畫效果實作

``````function createPoints() {
...
for (let i = 0; i < particleCount; i++) {
...
point.velocityX = THREE.Math.randFloat(-0.16, 0.16) // 粒子橫向移動速度
point.velocityY = THREE.Math.randFloat(0.1, 0.3) // 粒子縱向移動速度
...
}

points = new THREE.Points(geometry, material)
}

// 雪花落下循環動畫
function pointsAnimation() {
points.geometry.vertices.forEach(function(v) {
v.y = v.y - v.velocityY
v.x = v.x - v.velocityX

if (v.y <= -250) v.y = 250
if (v.x <= -250 || v.x >= 250) v.velocityX = v.velocityX * -1
})

points.geometry.verticesNeedUpdate = true // 告訴渲染器需更新頂點位置
}
``````

## 關於其他踩到的雷

### 1. 動畫不連續 - Demo

``````for (let i = 0; i < scene.children.length; i++) {
var object = scene.children[i]
if (object instanceof THREE.Points) {
object.position.y -= 0.16
if (object.position.y < 0) {
object.position.y = 100
}
}
}
``````

``````function render() {
const array = points.geometry.attributes['position'].array
let offset = 1
for (let i = 0; i < particleCount; i++) {
array[offset] -= THREE.Math.randFloat(0.1, 0.3)
if (array[offset] < -250) array[offset] = 250
offset += 3
}
points.geometry.attributes.position.needsUpdate = true
...
requestAnimationFrame(render)
renderer.render(scene, camera)
}
``````

### 2. 堆積特別多的一層 - Demo

``````function pointsAnimation() {
points.geometry.vertices.forEach(function(v) {
v.y = v.y - 0.5
if (v.y <= 0) v.y = 250
})
points.geometry.verticesNeedUpdate = true
}
``````

## 可優化的部分

### 1. BufferGeometry

``````function createPoints() {
const geometry = new THREE.BufferGeometry()
const vertices = []

material = new THREE.PointsMaterial({
size: 5
})

const range = 500
for (let i = 0; i < particleCount; i++) {
const x = Math.random() * range - range / 2
const y = Math.random() * range - range / 2
const z = Math.random() * range - range / 2

vertices.push(x, y, z)
}

// 加個 position 屬性記錄各頂點位置
'position',
new THREE.Float32BufferAttribute(vertices, 3)
)

points = new THREE.Points(geometry, material)
}
``````