粒子系统实现与原理

Posted 微小的鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了粒子系统实现与原理相关的知识,希望对你有一定的参考价值。

粒子系统简介:

粒子系统是指计算机图形学中模拟特定现象的技术,它在模仿自然现象、物理现象及空间扭曲上具备得天独厚的优势,能为我们实现一些真实自然而又带有随机性的效果(如爆炸、烟花、水流)提供了方便。Cocos2d-x引擎中就为我们提供了强大的粒子系统(确实Billboard Particle 是参考的cocos的源代码)。
cocos粒子系统源代码

粒子系统的分类:

现代的 Particle 有三种
• Billboard Particle
• Mesh Particle
• Ribbon Particle

作者本人先实现的是第一种 Billboard Particle粒子,后面还会实现 Mesh Particle。其实这两种斌没有本质上的区别,都是mesh+实例化+内存粒子+粒子的运动变换(可以各种物理量模拟仿真,甚至实现对象群)的管理等等,但是Billboard Particle粒子这种是最原始最简单的粒子,可以直接一张纹理或者播放序列帧,额Mesh Particle更通用,首先理论上可以是任意模型,而Billboard Particle粒子只是公告板或者通俗的说是四边形。再者发射的Mesh的材质可以任意,比Billboard Particle粒子效果更美更灵活~
相较而言,UE的粒子更多,还有另外三种:

粒子的属性:

粒子的属性包括很多,也包括各种受力,物理量的粒子。比如最常见的基本, 粒子属性: 坐标,初速度大小、速度的方向,大小,颜色,生命周期、质量、粒子的纹理(可以作成序列帧)等等。同时包括随机量!这个很关键 随机范围为 [start - variance/2, start + variance/2]-[end - variance/2, end + variance/2];

粒子发射器:

获取到所有的粒子,掌管整个粒子系统中该发射器发射的粒子,包括生命周期、消亡等等!除此之前粒子发射器有三个作用:
– 具体规定粒子产生的规则
– 具体规定粒子模拟的逻辑
– 描述如何渲染粒子(特别是透明混合等等的问题)

发射器属性:
发射器也有很多的属性,包括发射器的位置,比如我在项目中经常用的区域发射器,就有区域坐标属性,在该区域内随机new 粒子cell,甚至还可以做一个镂空,所以需要镂空坐标。对于线性发射器属性包括start的坐标,还有end的坐标

粒子的运动物理量-力场:

除此之外粒子还要受力场的影响
除此之外粒子还要受力场的影响,常见的三种力场:

本人身为物理课代表大学后特别工作以来物理有一些还给物理老师,所以复习啦一下下面理出各种力,匀变速运动,圆周运动等等的公式
1、 最常见的重力是一种全局设置,适用于场景中的所有物理系统。G = g*m;其中m为质量,g为重力加速度,G为重力。
2、空气阻力特别要指出,空气阻力跟速度的平方程正比,而且!空气阻力方向与运动方向或者说速度方向相反!

3、引力N/R^2 引力的大小N与所粒子当前与引力中心点的距离R,根据欧拉公式获取sqrt((x1-x2)2+((y1-y2)2+(z1-z2)^2)

匀变速运动公式:
速度:v1 = v0+at 其中v0初速度,a为加速度,t通常为当前一帧的时间。
位置公式 S=v0
t + (1/2 *a *t)
平均速度:V =( v1 +v2)/2
牛二定律:F=am 其中a为加速度,m为粒子的质量

圆周运动公式

1、v(线速度)=S/t=2πr/T=ωr=2πrf (S代表弧长,t代表时间,r代表半径) 。
2、ω(角速度)=θ/t=2π/T=2πn (θ表示角度或者弧度) 。   3、T(周期)=2πr/v=2π/ω 。
4、n(转速)=1/T=v/2πr=ω/2π 。
5、Fn(向心力)=mrω2=mv2/r=mr4π2/T2=mr4π2f2 。
6、an(向心加速度)=rω2=v2/r=r4π2/T2=r4π2n2 。   
7、vmax(过最高点时的最小速度)=√gr (无杆支撑)。。

粒子系统的通用核心实现:

这里主要是抛砖引玉,粒子更关注的是位置、与生命周期管理以及内存性能等等问题!至于渲染都是通用的就比如粒子也可以使用PBR,或者各种特效比如溶解,自发光、Glitter等等都是通用的这里就不特地在重复。

生命周期管理:

GLuint nr_particles = 500;             //预设置粒子的总数*每个粒子消耗内存数量 = 总数
std::vector<Particle> particles;       //粒子数组 方便管理粒子
for (GLuint i = 0; i < nr_particles; ++i) 
    particles.push_back(Particle());



GLuint nr_new_particles = 2; 
// Add new particles
for (GLuint i = 0; i < nr_new_particles; ++i) 
    
         int unusedParticle = FirstUnusedParticle();
         RespawnParticle(particles[unusedParticle], object, offset); 
     
// Update all particles for 
(GLuint i = 0; i < nr_particles; ++i) 
     
        Particle &p = particles[i]; p.Life -= dt; 
        // reduce life 
        if (p.Life > 0.0f)  
            // particle is alive, thus update 
            p.Position -= p.Velocity * dt;
            p.Color.a -= dt * 2.5; 
    
 

//但是为了提高利用率,找到第一个消亡的粒子然后用一个新产生的粒子来更新它
GLuint lastUsedParticle = 0;
    GLuint FirstUnusedParticle()
        
            // Search from last used particle, this will usually return almost instantly  for
            (GLuint i = lastUsedParticle; i < nr_particles; ++i)
                
                    if (particles[i].Life <= 0.0f)
                        
                            lastUsedParticle = i;
                             return i;
                    
    
            // Otherwise, do a linear search for
     (GLuint i = 0; i < lastUsedParticle; ++i)
            
                if (particles[i].Life <= 0.0f)
                     lastUsedParticle = i; return i;
                
            
     // Override first particle if all others are alive
     lastUsedParticle = 0;
     return 0;
    

粒子的渲染顶点着色器:

帧粒子或者 Billboard Particle 的vs:

#version 330 core 
layout (location = 0) 
in vec4 vertex;     // <vec2 position, vec2 texCoords> 
out vec2 TexCoords; 
out vec4 ParticleColor; 
uniform mat4 projection; 
uniform vec2 offset; 
uniform vec4 color;
     void main()  
                    float scale = 10.0f; 
                    TexCoords = vertex.zw;
                    ParticleColor = color; 
                    gl_Position = projection * vec4((vertex.xy * scale) + offset, 0.0, 1.0); 
                    

粒子的渲染片元着色器:

最简单的帧粒子或者 Billboard Particle 的实现ps:

#version 330 core 
in vec2 TexCoords; 
in vec4 ParticleColor; 
out vec4 color; 
uniform sampler2D sprite; 
    void main() 
                     color = (texture(sprite, TexCoords) * ParticleColor);
     

粒子材质的设置:

particleRender:getStateBlock():setDepthTest( true );    --始终开着
particleRender:getStateBlock():setDepthWrite( );        --可以选择true 或者 false来设置是否深度写入。需要粒子的遮挡关系:粒子最后渲染队列中渲染,开启混合,深度测试始终打开,深度写入关闭,片元 将无法通过深度测试。
particleRender:getStateBlock():setBlend( true );        --公告板的粒子要开启混合,粒子的渲染顺序要当做半透明的方式排序

特殊粒子的几种实现:

1、point sprites实现拖尾的粒子

在filament中的案例有point_sprites 效果如图:

//拖尾的核心

   	static Vertex kVertices[NUM_POINTS];
    static float kPointSizes[NUM_POINTS];
    static uint16_t kIndices[NUM_POINTS];
    constexpr float dtheta = M_PI * 2 / NUM_POINTS;
    constexpr float dsize = MAX_POINT_SIZE / NUM_POINTS;
    constexpr float dcolor = 256.0f / NUM_POINTS;
    for (int i = 0; i < NUM_POINTS; i++) 
        const float theta = dtheta * i;
        const uint32_t c = dcolor * i;
        kVertices[i].position.x = cos(theta);
        kVertices[i].position.y = sin(theta);
        kVertices[i].color = 0xff000000u | c | (c << 8u) | (c << 16u);
        kPointSizes[i] = MIN_POINT_SIZE + dsize * i;
        kIndices[i] = i;
    

2、追随粒子

本人最近实现了一种追随的粒子,跟随着某一点运动而运动,运动的轨迹是曲线的。
实现核心原理:每次update,识别点的pos 减去粒子当前的位置pos1得到的向量修改粒子的速度的方向(发射器或者粒子初始位置任意),速度大小恒定不变。

3、基于GPU的粒子

上述的两种都是基于CPU的粒子,因为它们都是在GPU中进行运算的,其实对于大量的顶点或者变换还是GPU最擅长,而且能充分发挥GPU的性能!感兴趣的可以详细看一下


github地址:keijiro/Skinner: Special Effects with Skinned Mesh in Unity (github.com)

Skinner is a collection of special effects that use vertices of an
animating skinned mesh as emitting points. It uses a special
replacement shader to convert vertex positions into GPU-friendly data,
and thus it avoids spending extra memory and CPU time for handling
them (uses GPU resources instead).

  • Skinner 是一种特效,它使用动画技术中的蒙皮网格的顶点作为发射点。 它使用特殊的替换着色器将顶点位置转换为GPU能识别并且使用的数据,从而避免花费额外的内存和CPU时间来处理它们(而是使用GPU资源)。

粒子系统的性能优化:

CPU的粒子:

GPU的粒子:

  • 高并行运算,适合大量粒子的模拟计算
  • 可以释放CPU功耗来进行游戏本身计算
  • 方便获得深度缓冲来做遮挡判断

参考资料:

Skinned Mesh原理解析和一个最简单的实现示例_n5的博客-CSDN博客
结合源码看《我所理解的cocos2dx-3.0》—— 粒子系统_fztfztfzt的博客-CSDN博客
GAMES104_Lecture12_Effects.pdf (boomingtech.com)

[激光原理与应用-17]:《激光原理与技术》-3- 激光的产生原理:微观粒子能级电子光子受激辐射

目录

第1章 微观粒子的能级与玻尔兹曼分布

1.1 宏观物理的物理规律:

1.2 微观粒子的物理规律:

1.3 微观粒子能量的离散化:能级与跃迁

1.4 微观粒子位置的不确定性分布:玻尔兹曼分布

 第2章 光的产生

2.1 自发辐射

2.2 受激接收

2.3 受激辐射


第1章 微观粒子的能级与玻尔兹曼分布

1.1 宏观物理的物理规律:

科学研究的对象是客观物质世界。在物理学的长期发展中人们将所研究的客观物质世界按其大小分成两个范围,一个是宏观世界,一个是微观世界。两者是相对而言的。

人们把由大量分子、原子和光子组成的物体称做宏观物体,如牛顿力学描述的质点、电磁场(或光)等等。这些宏观物体的总和构成了物理学研究的宏观世界。宏观世界满足的规律称为宏观规律。经典力学、经典电磁理论、经典统计理论都是描述宏观世界的理论。

与此相反,人们把分子、原子、原子核、质子、中子、电子光子等称为微观客体。微观客体遵循的物理学规律称为微观规律,它们与宏观规律有着极大的差别。符合微观规律的客观物质世界称为微观世界。量子理论就是描述微观世界的一种理论激光研究的电子光子的相互作用关系!不同不同原子的不同能量级之间电子的跃迁与不同频率的光子一一对应。

宏观世界亦称“大宇宙”。是宏观物体和宏观现象的总称。肉眼能见的物体都是宏观物体。宏观现象一般指宏观物体和场在宏观的空间范围内的各种现象,如人的活动,电磁波的传播等,有时运动量很大的微观粒子在大范围内的现象也称宏观现象,如加速器中基本粒子的运动等。再看,宇宙天体,广漠辽阔的天体,我们看到的是一片蓝天,其实它是由各种天体组成的:太阳系、银河系、总星系。人类借助现代天文望远镜,已经可以看到10多亿颗星球。宇宙空间并非是空白,而是由亿万颗星球天体组成的“大家庭”。

1.2 微观粒子的物理规律:

光子是微观粒子,有必要了解一下微观世界中微观粒子的物理规律

1.3 微观粒子能量的离散化:能级与跃迁

 

光子能量能量单载光子

光子的能量与电磁辐射频率成正比因此,等价地,与波长成反比。

光子频率越高,能量越高。同样地,光子的波长越长,其能量就越低。

光子即光量子(light quantum),电磁辐射的量子,传递电磁相互作用的规范粒子,记为γ。

其静止质量为零,不带电荷,其能量为普朗克常量和电磁辐射频率的乘积,E=hv,

 

 

1.4 微观粒子位置的不确定性分布:玻尔兹曼分布

在微观世界中,我们无法预知每个粒子的确切的位置,但我们可以知道众多粒子的分布规律。

玻尔兹曼分布是描述理想气体在受保守外力作用或保守外力场的作用不可忽略时,处于热平衡状态下的气体分子按能量的分布规律。

麦克斯韦-玻尔兹曼分布是一个描述一定温度下微观粒子运动速度的概率分布,在物理学化学中有应用。最常见的应用是统计力学的领域。任何(宏观)物理系统的温度都是组成该系统的分子原子运动的结果。这些粒子有一个不同速度的范围,而任何单个粒子的速度都因与其它粒子的碰撞而不断变化。

然而,对于大量粒子(不是个别粒子)来说,处于一个特定的速度范围的粒子所占的比例却几乎不变,如果系统处于或接近处于动态平衡

麦克斯韦-玻尔兹曼分布具体说明了这个比例,对于任何速度范围,作为系统的温度的函数

它以詹姆斯·麦克斯韦路德维希·玻尔兹曼命名。

 

 第2章 光的产生

2.1 自发辐射

 自发辐射是在没有任何外界作用下,激发态原子自发地从高能级(激发态)向低能级(基态)跃迁,同时辐射出一个光子的过程。该过程也是我们日常生活中许多光源的辐射机理,像霓虹灯、荧光灯、LED等常见光源辐射本质上都属于自发辐射。

自发辐射中,各个原子在自发跃迁过程中是彼此无关的,不同原子产生的自发辐射光在频率、相位、偏振方向及传播方向都有一定的任意性。

在没有外来作用的情况下,处于激发态的原子自发地向低能态或基态跃迁时辐射光子的现象。

一般光源的发光过程多属发光原子的自发辐射过程

量子力学体系的状态在外界作用下发生跳跃式变化的过程。原子在光的照射下从高(低)能级跳到低(高)能级的现象,就是一种量子跳跃过程。在不受光照的条件下,处于激发状态的原子在电磁场真空的作用下仍可跃迁到较低能级,称为自发跃迁。根据能量守恒定律,量子跃迁前后两状态的能量是不同的,放出或吸收一个光子,将有hv的能量差。量子跃迁是一种随机现象,具有明显的概率统计性。这是量子力学规律的根本特征。

根据能量守恒,辐射出去的能量来源于两个方面:

(1)物体自身的热量,随着辐射的过程,物体的温度要降低。

(2)其他能量的转换,如电能、生物能、其他热能等。

2.2 受激接收

受激吸收是处于低能级El的原子受到外来光子的激励下,在满足能量恰好等于低、高两能级之差ΔE时,该原子就吸收这部分能量。

能够被吸收的光子的频率取决于E2和E1能级的能量差与光子自身的能量的大小无关。只与光子的频率相关。

这为后续自发辐射或受激发射创造了条件。

在一个宏观系统中,有多少个粒子处于“受激接收”,实际上是一个动态变化的过程,但总体概率符合概率分布的规律。

2.3 受激辐射

受激辐射,即处于激发态的发光原子在外来辐射场的作用下,向低能态或基态跃迁时,辐射光子的现象。此时,外来辐射的能量必须恰好是原子两能级的能量差。受激辐射发出的光子和外来光子的频率、位相、传播方向以及偏振状态完全相同。这是与自发辐射从高能态向低能态跳转时发出的光子在频率、相位、偏振方向及传播方向都有一定的任意性是完全不同的。

受激辐射是产生激光的必要条件,如下图所示:

 

 

备注:

(1)幅度

在受激辐射模式下,对外来的入射光子的强度和功率要求不高,但对频率或波长的精度要求却很高,因此,受激辐射只接收特定波长的光子,并产生大量同频率(波长)的光子。

(2)种子源

种子源是一种低功率、低能量、但频率或波长高稳定性的激光源,可以是连续激光源,也可以是高稳定性的脉冲激光源。如皮秒激光器的1064ns激光源。

以上是关于粒子系统实现与原理的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D 粒子系统实现一个简单的爆炸效果

Unity3D中暂停时的动画及粒子效果实现

canvas动画——粒子系统

Unity3d 粒子系统里,如果粒子做多了怎么统一修改参数

Unity3D ParticleSystem粒子系统

Unity3D粒子系统粒子不跟随旋转