Cesium開發(fā)高級篇 | 04粒子系統(tǒng)

在三維GIS系統(tǒng)中,我們經(jīng)常會看到一些常見的特效,比如雨雪霧天氣、煙火、爆炸、噴泉等,這些都可以通過粒子系統(tǒng)實現(xiàn),今天我就來帶領(lǐng)大家學習一下Cesium中的粒子系統(tǒng)。

1.什么是粒子系統(tǒng)

粒子系統(tǒng)是一種圖形技術(shù),可以模擬復雜的物理效果。粒子系統(tǒng)是小圖像的集合,即由一堆很小的圖片組成,當把它們聚集到一起觀看時,就會形成一個復雜的“模糊不清”的物體,如火、煙、天氣或煙花等。這些復雜的效果其實是通過控制每一個粒子對象的初始位置、速度、生命周期等行為來完成的,可以說粒子系統(tǒng)控制著每個粒子對象隨著時間的顯示和變化。

2.粒子系統(tǒng)創(chuàng)建示例及參數(shù)說明

首先,我們從一個簡單的示例說起。實現(xiàn)代碼如下:

//初始化設(shè)置ParticleSystem的各項參數(shù),因為這是一個動態(tài)變化的粒子,所以有
start、end和min、max等參數(shù)設(shè)置
const particleSystem = scene.primitives.add(
    new Cesium.ParticleSystem({
        //每個粒子的圖像
        image: "../../SampleData/smoke.png",

        //設(shè)置發(fā)射出的圖像大小
        imageSize: new Cesium.Cartesian2(
           viewModel.particleSize,
           viewModel.particleSize
        ),

        //startColor endColor,代替color使得粒子的顏色在粒子的生命過程中會在
        這兩種顏色之間平滑地混合。
        startColor: Cesium.Color.LIGHTSEAGREEN.withAlpha(0.7),
        endColor: Cesium.Color.WHITE.withAlpha(0.0),

        //設(shè)置粒子圖發(fā)射之后的最小/最大速度(以米/秒為單位),值越大,尾巴飄的越高
        minimumSpeed: viewModel.minimumSpeed,
        maximumSpeed: viewModel.maximumSpeed,

        //startScale endScale,代替scale設(shè)置粒子在生命周期內(nèi)顯示的初始和結(jié)束尺寸,
        //也是動態(tài)混合的作用。 值越大,初始時粒子圖的大小越大
        startScale: viewModel.startScale,
        endScale: viewModel.endScale,

        //particleLife:設(shè)置該值將會覆蓋minimumParticleLife和maximumParticleLife
  
        //minimumParticleLife:設(shè)置粒子壽命的可能持續(xù)時間的最小界限(以秒為單位),粒子的實際壽命將隨 
        //機生成

        //maximumParticleLife:設(shè)置粒子壽命的可能持續(xù)時間的最大界限(以秒為單位),粒子的實際壽命將隨 
        //機生成
        //值越大,尾巴越長
        minimumParticleLife: viewModel.minimumParticleLife,
        maximumParticleLife: viewModel.maximumParticleLife,

        //每秒發(fā)射的粒子數(shù)。數(shù)值越大,越濃密
        emissionRate: viewModel.emissionRate,

        //粒子系統(tǒng)生命周期內(nèi),按照指定周期,爆發(fā)一定數(shù)量的粒子。三個參數(shù)(time,minimum,maximum)
        bursts: [
           // 爆炸出的粒子的密度
           new Cesium.ParticleBurst({
             time: 5.0,
              minimum: 10,
              maximum: 100,
           }),
           new Cesium.ParticleBurst({
              time: 10.0,
              minimum: 50,
              maximum: 100,
           }),
           new Cesium.ParticleBurst({
              time: 15.0,
              minimum: 200,
              maximum: 300,
           }),
        ],

        //粒子系統(tǒng)會發(fā)射多久粒子,以秒為單位。默認為最大值
        lifetime: 16.0,
            
        // 粒子系統(tǒng)的粒子發(fā)射器;包括四種發(fā)射器:圓形、錐體、球體、長方體
        emitter: new Cesium.CircleEmitter(2.0),

        //modelMatrix: 4x4變換矩陣,將粒子系統(tǒng)從模型轉(zhuǎn)換為世界坐標。
        //4x4變換矩陣,用于在粒子系統(tǒng)內(nèi)部坐標系中轉(zhuǎn)換粒子系統(tǒng)發(fā)射器。  
        emitterModelMatrix: computeEmitterModelMatrix(),

       //一組強制回調(diào)?;卣{(diào)被傳遞一個粒子和上次的差值
       //每幀都要調(diào)用的回調(diào)函數(shù)來更新粒子。此updateCallback作用是用來改變粒子系統(tǒng)在每一個時間步長的屬 
       //性,可以強制改變粒子系統(tǒng)的顏色、大小等值。在updateCallback更改gravity重力參數(shù),值越大,煙霧 
       //離模型越近的地方飄的越高,可能出現(xiàn)負值,此時煙霧會向下方飄。
       updateCallback: applyGravity,
    })
 );

上述通過實例化ParticleSystem,創(chuàng)建了一個卡車后部煙霧效果的粒子系統(tǒng),實例化參數(shù)(如粒子發(fā)射速率,粒子生命周期,粒子顏色、大小、運行速度等)對象控制了單個粒子對象隨時間變化的外觀和行為。如果要想實現(xiàn)不同的粒子效果,還需要對上述參數(shù)進行調(diào)整。上述示例的結(jié)果如下圖所示:


示例.gif

如果在運行過程中要更改粒子系統(tǒng)的屬性, 則需要在ParticleSystem中調(diào)用UpdateCallback更新函數(shù),粒子系統(tǒng)使用modelMatrix和emitterModelMatrix兩個轉(zhuǎn)換矩陣來定位。粒子系統(tǒng)中的每個粒子是如何生成的呢,這就靠下面要講的粒子發(fā)射器了。

3.粒子發(fā)射器

粒子發(fā)射器產(chǎn)生的粒子都有一個位置和類型,存活一段時間后然后消亡。粒子發(fā)射器則控制了粒子產(chǎn)生時的初始位置、速度和方向,并依據(jù)粒子發(fā)射頻率(emissionRate)來決定每秒產(chǎn)生多少粒子,并通過發(fā)射器類型決定粒子的發(fā)射速度和方向。無論是哪種粒子發(fā)射器都繼承了基類ParticleEmitter,Cesium內(nèi)置了如下四種粒子發(fā)射器:
(1)BoxEmitter 盒形發(fā)射器
定義了個盒型,將粒子隨機地放置在盒子里的隨機一個位置,并且具有從盒子中心發(fā)出的初始速度,然后沿著盒子的6個面的法向量向外運動,通過傳遞Cartesian3類型的參數(shù),來定了盒子的長寬高。

盒形發(fā)射器.gif

(2)CircleEmitter 圓形發(fā)射器
定義了一個圓形,在圓形面中的隨意一個位置發(fā)射具有沿著z矢量的初始速度的粒子,可通過Number類型的參數(shù)控制圓的半徑。Cesium默認的發(fā)射器為圓形發(fā)射器。

圓形發(fā)射器.gif

(3)ConeEmitter 錐形發(fā)射器
定義了一個的錐體,在錐體頂點產(chǎn)生粒子,并向錐體內(nèi)隨機一個方向運動,參數(shù)可控制圓錐體的角度。

錐形發(fā)射器.gif

(4)SphereEmitter 球形發(fā)射器
定義了一個球體,在球體內(nèi)隨機產(chǎn)生粒子,并沿著球心向外運動,可通過參數(shù)指定球體的半徑。

球形發(fā)射器.GIF

4.粒子系統(tǒng)更新回調(diào)函數(shù)

UpdateCallback回調(diào)函數(shù)充當了每個粒子的手動更新程序,它接受兩個參數(shù),一個是粒子本身,另一個是仿真時間步長。每個粒子系統(tǒng)在仿真過程中都會調(diào)用更新回調(diào)函數(shù)來修改粒子的屬性,從而進一步自定義粒子系統(tǒng)。比如對于重力、風或顏色更改等效果的模擬,下面是一個粒子相應重力的示例代碼:

        const gravityScratch = new Cesium.Cartesian3();

        function applyGravity(p, dt) {
          // 計算每個粒子的向上向量(相對地心) 
          const 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
          );
        }

該函數(shù)計算了一個重力方向,并使用重力加速度(-9.8米每秒平方)來改變粒子的速度,然后設(shè)置成粒子的更新回調(diào)函數(shù)。

5.粒子系統(tǒng)位置

有了粒子系統(tǒng)的創(chuàng)建、相關(guān)參數(shù)的位置之后,我們要把顯示的粒子效果具體放在什么位置進行展示呢,這就涉及到粒子系統(tǒng)的定位了。Cesium為我們提供了兩個Matrix4變換矩陣來定位粒子系統(tǒng)以方便開發(fā),當然你也可以設(shè)置一個,而把另一個設(shè)置為單位矩陣。
1)modelMatrix:模型矩陣,將粒子系統(tǒng)從模型轉(zhuǎn)換為世界坐標;
2)emitterModelMatrix:粒子發(fā)射器模型矩陣,在粒子系統(tǒng)的局部坐標系內(nèi)變換粒子發(fā)射器。
我們在創(chuàng)建粒子的時候,粒子發(fā)射器一般都會都會相對于某一個entity或primitive進行定位,用到的就是modelMatrix。如下示例給粒子系統(tǒng)創(chuàng)建了一個模型矩陣,將粒子定位在行駛中的卡車位置中心:

      const entity = viewer.entities.add({
          availability: new Cesium.TimeIntervalCollection([
            new Cesium.TimeInterval({
              start: start,
              stop: stop,
            }),
          ]),
          model: {
            uri: "../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck.glb",
            minimumPixelSize: 64,
          },
          viewFrom: new Cesium.Cartesian3(-100.0, 0.0, 100.0),
          position: position,
          orientation: new Cesium.VelocityOrientationProperty(position),
        });
        viewer.trackedEntity = entity;

        viewer.scene.preUpdate.addEventListener(function (scene, time) {
          particleSystem.modelMatrix = computeModelMatrix(entity, time);
          
          // Account for any changes to the emitter model matrix.
          particleSystem.emitterModelMatrix=computeEmitterModelMatrix();
        });

        function computeModelMatrix(entity, time) {
          return entity.computeModelMatrix(time, new Cesium  .Matrix4());
        }

而為了使粒子系統(tǒng)定位在卡車的后面,我們需要創(chuàng)建一個在模型坐標系中的平移矩陣,也就是上述示例中的效果,模型矩陣的計算代碼如下:

        const emitterModelMatrix = new Cesium.Matrix4();
        const translation = new Cesium.Cartesian3();
        const rotation = new Cesium.Quaternion();
        let hpr = new Cesium.HeadingPitchRoll();
        const trs = new Cesium.TranslationRotationScale();

        function computeEmitterModelMatrix() {
          hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, hpr);
          trs.translation = Cesium.Cartesian3.fromElements(
            -4.0,
            0.0,
            1.4,
            translation
          );
          trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, rotation);
          return Cesium.Matrix4.fromTranslationRotationScale(
            trs,
            emitterModelMatrix
          );
        }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容