iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 19
1

昨天學會了如何利用粒子系統做爆炸特效,今天我們要來將特效套用至專案中,來實作苦力怕自爆的效果,並且利用更多層的爆炸、由黑到白不同的顏色,來模擬得更真實一些。

18_front

Photo by Cristian Escobar on Unsplash


這是本系列第 18 篇,如果還沒看過第 17 篇可以點以下連結前往:

用 Three.js 來當個創世神 (17):粒子系統 - 爆炸


觀察預期效果

在實作之前,最重要的是先觀察預期的爆炸效果是怎麼樣的,這邊找到另一個有慢動作的苦力怕爆炸影片。從慢動作可以觀察到,苦力怕的爆炸有以下幾個重點:

  1. 在第一個瞬間苦力怕會直接消失
  2. 緊接著是好幾個一團一團的爆炸
  3. 每一團有不同顏色
  4. 每一團爆炸間有間隔的出現

瞭解了狀況之後以下就開始來實作了!

 

今日目標

18_demo

請參考完整原始碼成果展示,使用 explosionTrigger 來觸發苦力怕爆炸、 resetCreeper 來重置苦力怕。

不知道是不是筆者每天被鐵人賽 deadline 追趕壓力大,實際上操作起來好像也蠻像舒壓小遊戲的。
 

專案實作

這邊我們拿第 11 篇的模板來做,在那篇文章中,已經準備好了苦力怕爆炸的前置膨脹動作,而剩下的就是要將爆炸特效套上去並模擬得更像一些,就可以完成了。

1. 爆炸物件設定

首先先將上一篇中的 Explosion 物件加進去:

// points
const pointCount = 1000
const movementSpeed = 10
let explosion = [] // 爆炸物件陣列
let size = 10
const smokeTexture = textureLoader.load('./smoke.png')

class Explosion {
  constructor(x, y, z, color) {
    ...
    this.material = new THREE.PointsMaterial({
      size: size,
      color: color,
      map: smokeTexture,
      blending: THREE.CustomBlending,
      depthWrite: false,
      transparent: true,
      opacity: 0.7
    })
	 ...
  }
  ...
}

主要是做一些參數的調整來讓爆炸效果更像,除了比較基本的粒子數、爆炸速度、粒子尺寸外,這裡讓新增爆炸物件時還能定義粒子顏色,而這邊各層爆炸的顏色下面會指定由黑到白共五種顏色,但遇到一個問題是不管怎麼改都是白色,後來在各種 try & error 後也將各種融合模式試了一輪:

THREE.NoBlending
THREE.NormalBlending
THREE.AdditiveBlending
THREE.SubtractiveBlending
THREE.MultiplyBlending
THREE.CustomBlending

後來改為 THREE.CustomBlending 時就成功了,看文件這種融合模式還可以設定幾種不同的算法,不過文件也沒提到這幾種融合模式差在哪,稍微 google 一下後意外地找到這篇文章中有個 depthWrite: false 覺得很眼熟,設定這個屬性後爆炸粒子就可以正確穿透地板,也一起去把前面第 15 篇中關於 depthTest 的問題修正了。

詳細的原因應可參考這篇,大概瀏覽的意思應是 depthTest 會關掉比較多遮蔽的效果,而其他圖學的內容之後有空再來深入研究。

 

2. 用 dat.GUI 設定爆炸開關與重置

this.explosionTrigger = function() {
  for (let i = 0; i < scene.children.length; i++) {
    const object = scene.children[i]

    // 場景內有苦力怕才爆炸
    if (object.name === 'creeper') {
      // 清除之前爆炸粒子
      if (explosion) {
        const len = explosion.length
        if (len > 0) {
          for (let i = 0; i < len; i++) {
            explosion[i].destroy()
          }
        }
        explosion.length = 0
      }

      // 移除苦力怕
      scene.remove(creeperObj.creeper)

      // 產生爆炸
      explosion[0] = new Explosion(0, 0, 0, 0x000000)
      explosion[1] = new Explosion(5, 5, 5, 0x333333)
      explosion[2] = new Explosion(-5, 5, 10, 0x666666)
      explosion[3] = new Explosion(-5, 5, 5, 0x999999)
      explosion[4] = new Explosion(5, 5, -5, 0xcccccc)
    }
  }
}

這邊利用 dat.GUI 做一個觸發爆炸的開關,首先簡單做了一下防呆,就是當場景中沒有苦力怕物件時就不做爆炸效果,若有的話則先清掉之前的爆炸粒子殘骸,然後在爆炸前先把苦力怕從場景中移除。

而這裡新的 explosion 改為陣列,總共觸發五個爆炸,分別給予不同的爆炸中心與由黑到白的顏色,讓爆炸的煙霧更逼真一些。

this.resetCreeper = function() {
  scene.add(creeperObj.creeper)
}

重置則非常單純,只是將苦力怕加回場景。

 

3. 爆炸動畫設定

function render() {
  if (explosion) {
    const len = explosion.length
    if (len > 0) {
      for (let i = 0; i < len; i++) {
        explosion[i].update()
      }
    }
  }
  ...
  requestAnimationFrame(render)
  renderer.render(scene, camera)
}

爆炸動畫的設定也很單純,只做了每個爆炸的 update(),原本有考慮加上爆炸時間差的效果,但暫時還沒做出來,就只先將爆炸速度調快達到比較像的爆炸效果。

 

4. 調整相機設定

// 相機設定
camera = new THREE.PerspectiveCamera(
  60,
  window.innerWidth / window.innerHeight,
  20,
  1000
)
camera.position.set(50, 50, 50)
camera.lookAt(scene.position)

前面提到關於相機近平面距離這裡設 20

 

待優化的部分

1. 爆炸時間差

還可以補上每一層爆炸間的時間差,效果會更逼真。

2. 融合模式與 depthTest

在粒子材質中,關於融合模式與 dapthTest、depthWrite 不算完全理解他們的作用,可以再深入研究。

 

今日小結

今天完成了苦力怕的自爆動畫,也替粒子系統與專案中苦力怕相關的部分做個收尾,明天開始會進入第二部分來研究物理引擎,之後會開始實做遊戲中的射擊效果,我們明天見!

最後再附上今天的完整原始碼成果展示


上一篇
用 Three.js 來當個創世神 (17):粒子系統 - 爆炸
下一篇
用 Three.js 來當個創世神 (19):3D 物理引擎初探
系列文
用 Three.js 來當個創世神31

尚未有邦友留言

立即登入留言