Cesium官方教程9--粒子系統


原文地址:https://cesiumjs.org/tutorials/Particle-Systems-Tutorial/

粒子系統介紹

這篇教程帶你學習Cesium的粒子相關API,比如如何在你的項目里添加煙,火,火花等特效。


 
最終效果

什么是粒子系統?

粒子系統是一種圖形學技術,用來模擬復雜的物理效果。粒子系統是由一堆很小的圖片組成,看起來就像一些復雜的“含糊不清(fuzzy)”對象,就像火、煙、天氣、或者 煙花。這些復雜效果其實是通過控制每一個獨立的粒子的初始位置、速度、生命周期等屬性來完成。
粒子系統通常在電影和游戲中應用廣泛。比如,用來表示飛機的損傷過程,藝術家或者開發人員先用粒子系統來展示飛機引擎的爆炸效果,然后在用另一個粒子系統表示飛機墜毀過程中的煙霧軌跡。

粒子系統基本概念

先通過代碼看下基本的粒子系統:

var particleSystem = viewer.scene.primitives.add(new Cesium.ParticleSystem({ // Particle appearance image : '../../SampleData/fire.png', imageSize : new Cesium.Cartesian2(20, 20); startScale : 1.0, endScale : 4.0, // Particle behavior particleLife : 1.0, speed : 5.0, // Emitter parameters emitter : new Cesium.CircleEmitter(0.5), emissionRate : 5.0, emitterModelMatrix : computeEmitterModelMatrix(), // Particle system parameters modelMatrix : computeModelMatrix(), lifetime : 16.0 })); 

效果是這樣的:


 
最終效果

上述代碼里創建了 ParticleSystem類的對象, 傳遞了一個對象參數,來控制每個獨立粒子 Particle 的外觀 。粒子從 ParticleEmitter中生成,它有一個位置和類型、生存一段時間后,就消亡。
部分屬性可以是動態的。注意示例代碼里並非用了一個color屬性,而是用了startColorendColor兩個顏色屬性。在粒子的整個時間中,根據時間在兩個顏色之間做插值。startScaleendScale屬性也是類似。

其他影響粒子系統效果的是maximum和minimum 屬性。對於每個有最小和最大參數配置的屬性,在粒子的初始化過程中會在這個最小最大值范圍內隨機,然后整個粒子的生存周期內都不會變化。比如,設定粒子的初始運行速度,可以直接設置 speed變量,也可以設置 minimumSpeedmaximumSpeed 變量做為隨機速度的上下邊界。允許類似設置的屬性包括:imageSize, speed, life, 和particleLife

通過這些參數可以創建很多很多種粒子效果,具體可以試下Sandcastle的粒子系統示例

掌握Cesium的粒子系統,等同於對這些不同參數非常熟悉。我們討論一些屬性的細節。

發射器( Emitters)

ParticleEmitter控制了粒子產生時候的位置以及初始速度方向。發射器依據 emissionRate來決定每秒產生多少粒子,根據發射器類型不同決定了粒子的隨機速度方向。
Cesium內置了各種粒子發射器。

BoxEmitter

BoxEmitter 類在盒子里(box)里隨機一個位置,沿着盒子的6個面的法向量向外運動。它接受一個Cartesian3 參數,定義了盒子的長寬高。

particleSystem : { image : '../../SampleData/fire.png', emissionRate: 50.0, emitter: new Cesium.BoxEmitter(new Cesium.Cartesian3(10.0, 10.0, 10.0)) } 
 
boxemitter

CircleEmitter
圓形發射器使用CircleEmitter類在圓形面上隨機一個位置,粒子方向是發射器的向上向量。它接受一個float參數指定了圓的半徑。

particleSystem : { image : '../../SampleData/fire.png', emissionRate: 50.0, emitter: new Cesium.CircleEmitter(5.0) } 
 
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.

particleSystem : { image : '../../SampleData/fire.png', emissionRate: 50.0, emitter: new Cesium.ConeEmitter(Cesium.Math.toRadians(30.0)) } 
 
coneemitter

SphereEmitter
球形發射器使用SphereEmitter類在球體內隨機產生粒子,初始速度是沿着秋心向外。它接受一個float參數指定了球體半徑。

particleSystem : { image : '../../SampleData/fire.png', emissionRate: 50.0, emitter: new Cesium.SphereEmitter(5.0) } 

[站外圖片上傳中...(image-90334b-1542985116768)]

配置粒子系統

Cesium有很多選項來調整粒子效果。

粒子發射速率
emissionRate 屬性控制每秒生成多少個粒子,用來調整粒子密度。
可以設定一個爆炸對象的數組,用來控制在某個特定時刻產生爆炸效果。這是添加各種爆炸效果的最好方法。

給粒子增加下面的屬性:

bursts : [
    new Cesium.ParticleBurst({time : 5.0, minimum : 300, maximum : 500}), new Cesium.ParticleBurst({time : 10.0, minimum : 50, maximum : 100}), new Cesium.ParticleBurst({time : 15.0, minimum : 200, maximum : 300}) ], 

在給定時刻,這些爆炸效果會產生隨機個粒子,在設定最少和最多值之間。

粒子的生命周期和粒子系統的生命周期
一些參數控制了粒子系統的生命周期,默認粒子系統一直運行。
設置lifetime屬性控制粒子的持續時間,同時需要設置loop屬性為false。比如設定一個粒子系統運行5秒:

particleSystem : { lifetime: 5.0, loop: false } 

設置particleLife 屬性為5.0 表示設置每個粒子的生命周期是5秒。為了每個粒子都有一個隨機生命周期,我們可以設置 minimumParticleLife 和 maximumParticleLife。比如下面的代碼設置了粒子生命周期在5秒和10秒之間:

particleSystem : { minimumParticleLife: 5.0, maximumParticleLife: 10.0 } 

粒子樣式

顏色(Color)
除了設定image屬性來控制粒子的紋理外,還可以設定一個顏色值,這個值可以在粒子的生命周期內變化。這個在創建動態變化效果非常有用。
比如,下面代碼使火焰粒子產生的時候是淡紅色,消亡的時候是半透明黃色。

particleSystem : { startColor: Cesium.Color.RED.withAlpha(0.7), endColor: Cesium.Color.YELLOW.withAlpha(0.3) } 

大小(Size)
通常粒子大小通過imageSize屬性控制。如果想設置一個隨機大小,每個粒子的寬度在minimumImageSize.x 和 maximumImageSize.x 之間隨機,高度在minimumImageSize.y 和 maximumImageSize.y之間隨機,單位為像素。
下面代碼創建了像素大小在30~60之間的粒子:

particleSystem : { minimumImageSize : new Cesium.Cartesian2(30.0, 30.0), maximumImageSize : new Cesium.Cartesian2(60.0, 60.0) } 

和顏色一樣,粒子大小的倍率在粒子整個生命周期內,會在startScale 和 endScale屬性之間插值。這個會導致你的粒子隨着時間變大或者縮小。
下面代碼使粒子逐漸變化到初始大小的4倍:

particleSystem : { startScale: 1.0, endScale: 4.0 } 

運行速度Speed
發射器控制了粒子的位置和方向,速度通過speed參數或者minimumSpeed和maximumSpeed 參數來控制。下面代碼讓粒子每秒運行5~10米:

particleSystem : { minimumSpeed: 5.0, maximumSpeed: 10.0 } 

更新回調(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米每秒平方)去修改粒子的速度方向。 .
然后設置粒子系統的更新函數:

particleSystem: { forces: applyGravity } 

位置

粒子系統使用兩個轉換矩陣來定位:

  • modelMatrix : 把粒子系統從模型坐標系轉到世界坐標系。
  • emitterModelMatrix : 在粒子系統的局部坐標系內變換粒子發射器。
    我們提供兩個屬性也是為了方便,當然可以僅僅設置一個,把另一個設置為單位矩陣。為了學習創建這個矩陣,我們嘗試把我們的粒子系統相對另一個entity。
    首先創建一個entity。打開Sandcastle 的 Hello World示例,敲入下面的代碼:
var entity = viewer.entities.add({ // 加載飛機模型 model : { uri : '../../SampleData/models/CesiumAir/Cesium_Air.gltf', minimumPixelSize : 64 }, position : Cesium.Cartesian3.fromDegrees(-112.110693, 36.0994841, 1000.0) }); viewer.trackedEntity = entity; 

在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()); } 

現在就可以去計算偏移矩陣了,我們先用一些基本參數創建粒子系統,代碼如下:

var particleSystem = viewer.scene.primitives.add(new Cesium.ParticleSystem({ image : '../../SampleData/fire.png', startScale : 1.0, endScale : 4.0, particleLife : 1.0, speed : 5.0, imageSize : new Cesium.Cartesian2(20, 20), emissionRate : 5.0, lifetime : 16.0, modelMatrix : computeModelMatrix(entity, Cesium.JulianDate.now()), emitterModelMatrix : computeEmitterModelMatrix() })); 

這就做到了前面示例里描述的效果,把粒子特效放到了飛機的引擎上。


 
最終效果

注意我們可以隨時更改模型或者發射器矩陣。比如,我們想通過通過去更改粒子發射器相對飛機的位置,我們只需要修改emitterModelMatrix,而保持 modelMatrix 不變。這樣就非常容易的在模型空間重新定位了。
這種定位方式並非直接設定一個position屬性,而是提供了一種有效的,靈活的矩陣變換方式,適應更多效果要求。
這就是粒子系統的基礎知識,很期待看到你用他們做出來的效果。
更多粒子系統特效,以及更高級的技術,請看更多粒子特效教程

 
煙花

更多示例代碼:





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM