Cesium官方教程9--粒子系統
原文地址:https://cesiumjs.org/tutorials/Particle-Systems-Tutorial/
粒子系統介紹
這篇教程帶你學習Cesium的粒子相關API,比如如何在你的專案裡新增煙,火,火花等特效。
什麼是粒子系統?
粒子系統是一種圖形學技術,用來模擬複雜的物理效果。粒子系統是由一堆很小的圖片組成,看起來就像一些複雜的“含糊不清(fuzzy)”物件,就像火、煙、天氣、或者 ×××。這些複雜效果其實是通過控制每一個獨立的粒子的初始位置、速度、生命週期等屬性來完成。
粒子系統通常在電影和遊戲中應用廣泛。比如,用來表示飛機的損傷過程,藝術家或者開發人員先用粒子系統來展示飛機引擎的爆炸效果,然後在用另一個粒子系統表示飛機墜毀過程中的煙霧軌跡。
粒子系統基本概念
先通過程式碼看下基本的粒子系統:
效果是這樣的:
最終效果
上述程式碼裡建立了 ParticleSystem類的物件, 傳遞了一個物件引數,來控制每個獨立粒子 Particle 的外觀 。粒子從 ParticleEmitter中生成,它有一個位置和型別、生存一段時間後,就消亡。
部分屬性可以是動態的。注意示例程式碼裡並非用了一個color屬性,而是用了startColor 和endColor兩個顏色屬性。在粒子的整個時間中,根據時間在兩個顏色之間做插值。startScale和endScale屬性也是類似。
其他影響粒子系統效果的是maximum和minimum 屬性。對於每個有最小和最大引數配置的屬性,在粒子的初始化過程中會在這個最小最大值範圍內隨機,然後整個粒子的生存週期內都不會變化。比如,設定粒子的初始執行速度,可以直接設定 speed變數,也可以設定 minimumSpeed 和 maximumSpeed 變數做為隨機速度的上下邊界。允許類似設定的屬性包括:imageSize, speed, life, 和particleLife。
通過這些引數可以建立很多很多種粒子效果,具體可以試下Sandcastle的粒子系統示例。
掌握Cesium的粒子系統,等同於對這些不同引數非常熟悉。我們討論一些屬性的細節。
發射器( Emitters)
ParticleEmitter控制了粒子產生時候的位置以及初始速度方向。發射器依據 emissionRate來決定每秒產生多少粒子,根據發射器型別不同決定了粒子的隨機速度方向。
Cesium內建了各種粒子發射器。
BoxEmitter
BoxEmitter 類在盒子裡(box)裡隨機一個位置,沿著盒子的6個面的法向量向外運動。它接受一個Cartesian3 引數,定義了盒子的長寬高。
CircleEmitter
圓形發射器使用CircleEmitter類在圓形面上隨機一個位置,粒子方向是發射器的向上向量。它接受一個float引數指定了圓的半徑。
circleemitter
如果沒有指定發射器,預設使用圓形發射器。
ConeEmitter
錐形發射器類使用ConeEmitter在椎體頂點產生粒子,粒子方向在椎體內隨機一個角度向外。它接受一個float引數,制定了錐角。椎的方向沿著向上軸。
The ConeEmitter class initializes particles at the tip of a cone and directs them at random angles out of the cone. It takes a single float parameter specifying the angle of the cone. The cone is oriented along the up axis of the emitter.
SphereEmitter
球形發射器使用SphereEmitter類在球體內隨機產生粒子,初始速度是沿著秋心向外。它接受一個float引數指定了球體半徑。
配置粒子系統
Cesium有很多選項來調整粒子效果。
粒子發射速率
emissionRate 屬性控制每秒生成多少個粒子,用來調整粒子密度。
可以設定一個爆炸物件的陣列,用來控制在某個特定時刻產生爆炸效果。這是新增各種爆炸效果的最好方法。
給粒子增加下面的屬性:
在給定時刻,這些爆炸效果會產生隨機個粒子,在設定最少和最多值之間。
粒子的生命週期和粒子系統的生命週期
一些引數控制了粒子系統的生命週期,預設粒子系統一直執行。
設定lifetime屬性控制粒子的持續時間,同時需要設定loop屬性為false。比如設定一個粒子系統執行5秒:
設定particleLife 屬性為5.0 表示設定每個粒子的生命週期是5秒。為了每個粒子都有一個隨機生命週期,我們可以設定 minimumParticleLife 和 maximumParticleLife。比如下面的程式碼設定了粒子生命週期在5秒和10秒之間:
粒子樣式
顏色(Color)
除了設定image屬性來控制粒子的紋理外,還可以設定一個顏色值,這個值可以在粒子的生命週期內變化。這個在建立動態變化效果非常有用。
比如,下面程式碼使火焰粒子產生的時候是淡紅色,消亡的時候是半透明×××。
大小(Size)
通常粒子大小通過imageSize屬性控制。如果想設定一個隨機大小,每個粒子的寬度在minimumImageSize.x 和 maximumImageSize.x 之間隨機,高度在minimumImageSize.y 和 maximumImageSize.y之間隨機,單位為畫素。
下面程式碼建立了畫素大小在30~60之間的粒子:
和顏色一樣,粒子大小的倍率在粒子整個生命週期內,會在startScale 和 endScale屬性之間插值。這個會導致你的粒子隨著時間變大或者縮小。
下面程式碼使粒子逐漸變化到初始大小的4倍:
執行速度Speed
發射器控制了粒子的位置和方向,速度通過speed引數或者minimumSpeed和maximumSpeed 引數來控制。下面程式碼讓粒子每秒執行5~10米:
更新回撥(UpdateCallback)
為了提升模擬效果,粒子系統有一個更新函式。這個是個手動更新器,比如對每個粒子模擬重力或者風力的影響,或者除了線性插值之外的顏色插值方式等等。
每個粒子系統在模擬過程種,都會呼叫更新回撥函式來修改粒子的屬性。回撥函式傳過兩個引數,一個是粒子本身,另一個是模擬時間步長。大部分物理效果都會修改速率向量來改變方向或者速度。下面是一個粒子響應重力的示例程式碼:
var gravityScratch = new Cesium.Cartesian3();
function applyGravity(p, dt) {
// 計算每個粒子的向上向量(相對地心)
var position = p.position;
Cesium.Cartesian3.normalize(position, gravityScratch);
Cesium.Cartesian3.multiplyByScalar(gravityScratch, viewModel.gravity * dt, gravityScratch);
p.velocity = Cesium.Cartesian3.add(p.velocity, gravityScratch, p.velocity);
}
這個函式計算了一個重力方向,然後使用重力加速度(-9.8米每秒平方)去修改粒子的速度方向。 .
然後設定粒子系統的更新函式:
位置
粒子系統使用兩個轉換矩陣來定位:
modelMatrix : 把粒子系統從模型座標系轉到世界座標系。
emitterModelMatrix : 在粒子系統的區域性座標系內變換粒子發射器。
我們提供兩個屬性也是為了方便,當然可以僅僅設定一個,把另一個設定為單位矩陣。為了學習建立這個矩陣,我們嘗試把我們的粒子系統相對另一個entity。
首先建立一個entity。開啟Sandcastle 的 Hello World示例,敲入下面的程式碼:
在viewer裡建立了一個飛機模型。
下來,我們如何在場景種擺放我們的粒子系統。我們先給飛機的一個引擎上放一團火。首先給粒子系統建立一個模型矩陣,這個矩陣和飛機的位置和朝向完全相同。意思就是飛機的模型矩陣也要做為粒子系統的矩陣,這麼設定modelMatrix:
function computeModelMatrix(entity, time) {
var position = Cesium.Property.getValueOrUndefined(entity.position, time, new Cesium.Cartesian3());
if (!Cesium.defined(position)) {
return undefined;
}
var orientation = Cesium.Property.getValueOrUndefined(entity.orientation, time, new Cesium.Quaternion());
if (!Cesium.defined(orientation)) {
var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position, undefined, new Cesium.Matrix4());
} else {
modelMatrix = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation, new Cesium.Matrix3()), position, new Cesium.Matrix4());
}
return modelMatrix;
}
現在這個矩陣已經把粒子放到了飛機中心位置。可是我們想讓粒子在飛機的一個引擎上產生,所以我們再建立一個在模型座標系的平移矩陣。這麼計算:
function computeEmitterModelMatrix() {
hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, new Cesium.HeadingPitchRoll());
var trs = new Cesium.TranslationRotationScale();
trs.translation = Cesium.Cartesian3.fromElements(2.5, 4.0, 1.0, new Cesium.Cartesian3());
trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, new Cesium.Quaternion());
return Cesium.Matrix4.fromTranslationRotationScale(trs, new Cesium.Matrix4());
}
現在就可以去計算偏移矩陣了,我們先用一些基本引數建立粒子系統,程式碼如下:
這就做到了前面示例裡描述的效果,把粒子特效放到了飛機的引擎上。
最終效果
注意我們可以隨時更改模型或者發射器矩陣。比如,我們想通過通過去更改粒子發射器相對飛機的位置,我們只需要修改emitterModelMatrix,而保持 modelMatrix 不變。這樣就非常容易的在模型空間重新定位了。
這種定位方式並非直接設定一個position屬性,而是提供了一種有效的,靈活的矩陣變換方式,適應更多效果要求。
這就是粒子系統的基礎知識,很期待看到你用他們做出來的效果。
更多粒子系統特效,以及更高階的技術,請看更多粒子特效教程 。
更多示例程式碼:
粒子系統示例
粒子系統×××示例