粒子系统(Particle System)
粒子系统表示三维计算机图形学中模拟一些特定的模糊现象的技术,而这些现象用其它传统的渲染技术难以实现的真实感的游戏图形。经常使用粒子系统模拟的现象,有火、爆炸、烟、水流、火花、落叶、云、雾、雪、尘、流星尾迹或者象发光轨迹这样的抽象视觉效果等等。
粒子系统的特点
- 整个现象都是由很多个独立的图像效果组成,这些图像效果都有自己的位置、移动轨迹等特点;
- 这些独立的图像效果组合或者叠加起来,就形成了要模拟的现象;
- 独立的图像效果经过一段生命周期之后会从屏幕上消失,进而可以将其状态重置并重新利用;
粒子系统的组成
- 粒子类:每个单独的粒子是整个粒子特效的一个基本组成部分,每个粒子都具有大量属性,比如粒子图片、生命时长、方向、速度、加速度等,这些属性能够决定粒子的外观及行为表现。
- 粒子发射器:实际上是所有粒子的管理者,是用来进行粒子生成、粒子控制、回收粒子的管理器类。
属性设置
粒子系统中可以设置的属性如下所示,不同平台可能略有差异,但所遵守的标准相同,所以基本大同小异。
Cocos
使用OpenGL
混合原理对图形进行渲染绘制。混合就是指把两种颜色混在一起,具体一点就是把某一像素位置原来的颜色和将要画上去的颜色,通过某种方式混在一起,从而实现特殊的效果。它是一种常用的技巧,通常可以用来实现半透明,你也可以通过不同的设置得到不同的混合结果,产生一些有趣或者奇怪的图象。具体可以参考:
https://www.andersriggelsen.dk/glblendfunc.php,下面是混合的集中模式,可以作用于src,
BlendFactor
枚举类型及其作用。
含义 | 作用 |
---|---|
ONE | 全部使用 |
ZERO | 全部不用 |
SRC_ALPHA | 使用源颜色的透明度 |
SRC_COLOR | 使用源颜色 |
DST_ALPHA | 使用目标颜色的透明度 |
DST_COLOR | 使用目标颜色 |
ONE_MINUS_SRC_ALPHA | 减去源颜色的透明度 |
ONE_MINUS_SRC_COLOR | 减去源颜色 |
ONE_MINUS_DST_ALPHA | 减去目标颜色的透明度 |
ONE_MINUS_DST_COLOR | 减去目标颜色 |
关于粒子在cocos中的使用。
cocos create
中提供了界面友好的工具供我们使用,粒子的简单使用可以参考: https://docs.cocos.com/creator/manual/zh/asset-workflow/particle.html
我们可以在cocos中编辑这些粒子效果,在编辑的过程中可以预览到粒子的实时效果,粒子相关的特性基本在plist
中声明即可。
如果我们需要在cocos中通过代码的形式控制到粒子动画的播放和停止的话,可以resetSystem()
来控制器展现,利用stopSystem
控制其隐藏。示例代码如下:
//mA 表示要控制的粒子 ,即 mA: cc.ParticleSystem;
if(this.mA.active) {
this.mA.stopSystem();
} else {
this.mA.resetSystem();
}
关于颜色计算
关于cocos源码的实现
ParticleTest
测试类入口。
CCParticleExamples
测试主体类,主要在这里实现。
CCParticleSystem
是粒子系统的基类,提供对粒子的创建和更新管理。
ParticleSystemQuad
是CCParticleSystem
的子类,实现不需要批次结点时也能够实现粒子系统的OPENGL顶点和索引缓冲的创建和渲染.
CCParticleBatchNode
粒子系统的批次节点,用于将使用相同纹理的粒子系统进行同批次渲染优化处理。
粒子系统实现类在CCParticleSystem
中,其中包含了粒子系统的大部分实现,下面是粒子系统中的几个重要方法实现。
将粒子添加到粒子系统的实现(*)
这个是整个粒子系统运行的必要条件,想要粒子系统运行起来,必须得先将粒子加入到粒子系统中。相关代码也比较复杂,比较多。
这里就不贴出具体的代码,只给出关键的代码:
void ParticleSystem::addParticles(int count)
{
//life
//position
//color
//size
// rotation
// position
// Mode Gravity:
针对上面的属性做赋值处理
}
粒子更新的实现
// ParticleSystem - MainLoop
void ParticleSystem::update(float dt)
{
// 省略了一些属性的设置调整。
// 需要被重载的更新粒子的对应矩形顶点缓冲信息块的虚函数,在这里进行界面更新
updateParticleQuads();
_transformSystemDirty = false;
if (_visible && ! _batchNode)
{
postStep();
}
}
粒子的属性的动态设置都会在update中来完成,然后利用updateParticleQuads
来更新指定粒子的顶点缓冲中的位置数据,他的具体实现在CCParticleSystemQuad
垒中,那么postStep
做了什么呢,我们来看他的实现,同样,他的实现也在CCParticleSystemQuad
中,
//针对不使用批次结点时的VBO顶点缓冲的更新。
void ParticleSystemQuad::postStep()
{
//绑定顶点缓冲区对象。
glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
//用_quads中数据更新绑定的缓冲区数据。
// Option 1: Sub Data
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_quads[0])*_totalParticles, _quads);
// Option 2: Data
// glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * particleCount, quads_, GL_DYNAMIC_DRAW);
// Option 3: Orphaning + glMapBuffer
// glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0])*_totalParticles, nullptr, GL_STREAM_DRAW);
// void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
// memcpy(buf, _quads, sizeof(_quads[0])*_totalParticles);
// glUnmapBuffer(GL_ARRAY_BUFFER);
//取消绑定缓冲区对象。
glBindBuffer(GL_ARRAY_BUFFER, 0);
CHECK_GL_ERROR_DEBUG();
}
停止粒子系统的实现
这个实现就很简单了,主要把_isActive
设置为false
即可。把开始到当前的运行秒数_elapsed
用_duration
赋值, 然后把每秒发射的粒子数_elapsed
置为0,代码如下:
void ParticleSystem::stopSystem()
{
_isActive = false;
_elapsed = _duration;
_emitCounter = 0;
}
粒子重新启动的实现
粒子系统重新启动的实现也很简单,主要是把所有的粒子的生命值置为0。
void ParticleSystem::resetSystem()
{
_isActive = true;
_elapsed = 0;
for (int i = 0; i < _particleCount; ++i)
{
_particleData.timeToLive[i] = 0.0f;
}
}
关于粒子系统属性的设置
cocos 支持两种方式的属性设置,一种是通过字典,一种是通过plist文件。
通过字典的方式,就是手动去将元素的值赋值给字典,然后通过initWithDictionary
方法来实现赋值,这种方式比较麻烦,而且也比较容易遗漏,所以我们一般采用第二种方式,即通过plist
文件的形式来赋值。我们可以借助其他工具,生成plist文件,然后通过ParticleSystem::initWithFile
来读取这个文件,进行赋值。
术语
混合
就是把两种颜色混在一起。
具体一点,就是把某一像素位置原来的颜色和将要画上去的颜色,通过某种方式混在一起,从而实现特殊的效果。
假设我们需要绘制这样一个场景:透过红色的玻璃去看绿色的物体,那么可以先绘制绿色的物体,再绘制红色玻璃。在绘制红色玻璃的时候,利用“混合”功能,把将要绘制上去的红色和原来的绿色进行混合,于是得到一种新的颜色,看上去就好像玻璃是半透明的。
前面我们已经提到,混合需要把原来的颜色和将要画上去的颜色找出来,经过某种方式处理后得到一种新的颜色。这里把将要画上去的颜色称为“源颜色”,如上例中的红色;把原来的颜色称为“目标颜色”,如上例中的绿色。
目的颜色:先画上的颜色(相当于内容)。
源颜色: 后画上去的颜色(相当于背景)。
VAO 用于存储顶点数据,包括顶点颜色、坐标、法线,以及顶点的indices。
VBO 用于存储图形处理器将怎么使用VBO里面的数据,及顶点数据中哪些是坐标、哪些是颜色、哪些是法线等信息。