今天將利用前兩天製作的雪花特效,套用至專案中,除了調整邊界值外,還會試著更換粒子貼圖來達到不一樣場景的效果!
Photo by Fancycrave on Unsplash
這是本系列第 16 篇,如果還沒看過第 15 篇可以點以下連結前往:
用 Three.js 來當個創世神 (15):粒子系統 - 雪花 Part.2
苦力怕:我住的城巿從不下雪,記憶卻堆滿冷的感覺。
鐵人賽寫著寫著轉眼間已經十一月,看著苦力怕的世界下起雪來,才想到離聖誕節也不遠了。啊,剛好應景,老師,音樂下,點播一首 Eason 的「聖誕結」!
今天的目標是來將前兩天做的雪花特效,加到苦力怕的場景中,除了一些邊界參數的微調外,也試著加入幾個有趣的小互動,讀者可以透過右上角的控制面板來「播放背景音樂」及「更換粒子特效場景」,感覺這樣的場景不來首歌真是太可惜了,下面就開始來實作吧!
基本上今天的內容不太複雜,主要是整合第 12 篇及第 15 篇的內容,調整邊界值與粒子數之外,加上一些適合的功能。
// 粒子系統全域變數宣告
const particleCount = 15000
let points
let material
const textureLoader = new THREE.TextureLoader()
const snowTexture = textureLoader.load('./snowflake.png')
// 粒子系統初始化
function createPoints() {
const geometry = new THREE.Geometry()
material = new THREE.PointsMaterial({
size: 5,
map: snowTexture,
blending: THREE.AdditiveBlending,
// depthTest: false, // 遮蔽效果
transparent: true,
opacity: 0.5
})
const range = 300
for (let i = 0; i < particleCount; i++) {
const x = THREE.Math.randInt(-range / 2, range / 2)
const y = THREE.Math.randInt(0, range * 20)
const z = THREE.Math.randInt(-range / 2, range / 2)
const point = new THREE.Vector3(x, y, z)
point.velocityX = THREE.Math.randFloat(-0.16, 0.16)
point.velocityY = THREE.Math.randFloat(0.1, 0.3)
geometry.vertices.push(point)
}
points = new THREE.Points(geometry, material)
scene.add(points)
}
// 粒子系統動畫
function pointsAnimation() {
points.geometry.vertices.forEach(function(v) {
if (v.y >= -7) {
v.x = v.x - v.velocityX
v.y = v.y - v.velocityY
}
if (v.x <= -150 || v.x >= 150) v.velocityX = v.velocityX * -1
})
points.geometry.verticesNeedUpdate = true
}
首先將初始化粒子系統的函式加入,並調整邊界值,因為後面粒子動畫的部分要設計成落在地板上就靜止在地面上,形成積雪的感覺,為了不要讓雪太快下完,這邊讓粒子多一點(15000 顆),並讓頂點 y 座標隨機值(降雪起源點邊界)設定高一點(6000),這場雪大概足以下六分鐘左右。
另外這邊有個筆者解不掉的問題,就是前面有提到粒子材質中有個屬性 depthTest
,將它關掉可以讓雪花重疊時不會有背景遮擋的違和感,但因為關掉了遮擋的效果就會穿透其他物體,如下圖:
所以權衡之下暫時還是先開起來,讀者若有更好的解法歡迎留言解答,感恩。
另外為了讓苦力怕能在雪景中有散步的效果,將地板加大外,稍微調整了動畫,讓它能隨機走動,將原本回原點的動畫改成隨機移動(見程式碼中 handleNewTweenBackTarget
),但轉身的動畫有些地方不太對,但這邊就先不細調動畫了,畢竟主角是粒子特效。
更新:轉身動畫不順暢是因為目前是在 15 秒內,同時移動與轉身,要流暢就需將流程改為先 1 秒轉身,再做 14 秒移動。
然後為了增加一點苦力怕漫步在雪景中的孤寂感,特別在補間動畫的地方加了「移動點光源」,跟隨著苦力怕一起移動。
這是個心血來潮的部分,就是覺得這樣的場景、這樣的燈光與這樣欲說還休的表情,就該來一首「聖誕結」,實作上也不難,就是在 HTML 加入 audio tag,並且利用 dat.GUI
來做播放與暫停的功能。
const sound = document.querySelector('audio')
let musicPlayback = false
...
this.togglePlayMusic = function() {
if (musicPlayback) {
sound.pause()
musicPlayback = false
} else {
sound.play()
musicPlayback = true
}
}
苦力怕:臉上的,揪竟是雨水還是淚水?
因為下雨跟下雪的動畫都是差不多的,最後試著來做個場景切換,將材質的雪花貼圖換成雨滴貼圖:
(圖源)
並透過 dat.GUI
切換貼圖及粒子尺寸:
this.changeScene = function() {
if (sceneType === 'SNOW') {
material.map = rainTexture
material.size = 2
sceneType = 'RAIN'
} else {
material.map = snowTexture
material.size = 5
sceneType = 'SNOW'
}
}
今天將前面專案套上了前兩天做的雪花特效,並試著更換雨滴貼圖就能有另一種效果,也利用 dat.GUI 做了一些有趣的互動,替粒子特效場景做個收尾,明天將來挑戰另一個粒子系統的應用 —— 爆炸,我們明天見!