zoukankan      html  css  js  c++  java
  • 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属性,而是提供了一种有效的,灵活的矩阵变换方式,适应更多效果要求。
    这就是粒子系统的基础知识,很期待看到你用他们做出来的效果。
    更多粒子系统特效,以及更高级的技术,请看更多粒子特效教程

     
    烟花

    更多示例代码:




  • 相关阅读:
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (四) 自动化部署
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (三) 服务观测
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (二) 部署微服务程序
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (一) 部署 Nacos
    C++知识点
    libmkl 学习笔记
    基于tesseract-OCR进行中文识别
    poco编译与运行
    Linux下的I/O复用与epoll详解(转载)
    高并发网络编程之epoll详解(转载)
  • 原文地址:https://www.cnblogs.com/cesium1/p/10063053.html
Copyright © 2011-2022 走看看