粒子系统是一个游戏引擎必不可少的部分,粒子系统的实现并没有统一的标准,各类3D动画软件和游戏引擎的实现也不尽相同。
本套粒子系统基于3ds max的标准,实现了max9绝大部分的粒子参数调节功能。暂不支持3dsmax的粒子流源。粒子动画在3dsmax中做好后可以直接导出,所见即所得,连粒子编辑器都省了。实现了公告板粒子、模型粒子、Metaball流体粒子、粒子繁殖、粒子附着模型,空间扭曲等功能。
导出的动画依托于MC_Particle来驱动粒子系统的参数随关键帧而改变(MC_Particle是引擎中关键帧动画的派生类)。关键帧动画可以通过附着曲线控制器灵活设置粒子路径、旋转朝向等。在关键帧上还可以调节其它animatable参数,比如粒子发射密度、速度、大小、空间扭曲参数等。
另外仿照max中的刀光插件,做了一套专门绘制刀光拖尾的小组件。
粒子可调参数类型:
//粒子绘制类型
enum ParticleDrawType
{
PDT_PLANE = 0,//3d面 3d自旋
PDT_CROSS2 = 1,//双十字交叉面
PDT_CROSS3 = 2,//三十字交叉面
PDT_BILLBORD = 3,//公告板 z自旋
PDT_MESH = 4,//模型
PDT_METABALL = 5,//水滴
PDT_NUM
};
//粒子发射方向类型
enum ParticleDirType
{
PMT_ObjUp , //初始[0, 1,0],跟随物体变换
PMT_ObjDown , //初始[0,-1,0],跟随物体变换
PMT_Rand , //随机
PMT_Fix , //固定轴 对于cloud不一定等同于物体的dir
PMT_FaceNormal , //沿附着面法线
};
//粒子旋转类型
enum ParticleRotType
{
PRT_RotRand , //随机轴自旋
PRT_RotFixed , //固定轴自旋
PRT_RotTumble , //翻滚
PRT_RotMotion , //粒子自动朝向运动方向,并且绕head旋转,对于公告板类型无效
};
//粒子发射方向异性类型
enum ParticleDirVariationType
{
PDVT_Add = 0, //直接相加
PDVT_Spot, //锥角平均
PDVT_Spot2, //锥角正太分布
};
//发射器形状类型
enum EmitterShapeType
{
EST_POINT = 0,//点
EST_PLANE = 1,//面
EST_BOX = 2,//正方体
EST_SPHERE = 3,//球
EST_AIRSPHERE = 4,//空心球
EST_CYLINDER = 5,//圆柱
EST_MESH = 6,//附着模型
EST_SPAWN = 9,//只能通过别的粒子拖尾或繁殖
EST_NUM
};
//贴图 uv类型
enum TextureUVType
{
TU_Face , //面uv
TU_Life , //根据life平滑移动v坐标,每个粒子再随机u坐标,
TU_Life2 , //根据life幻灯片移动v坐标
TU_Dist , //根据距离
TU_Dist2 ,
};
//粒子繁殖类型
enum ParticleSpawnType
{
PST_None ,//无繁殖
PST_DieOnCollision ,//碰撞导向板时死亡
PST_SpawnOnCollision,//碰撞导向板时繁殖
PST_SpawnOnDeath ,//死亡时繁殖
PST_SpawnTrails ,//拖尾繁殖
};
//空间扭曲类型
enum SpaceWrapType
{
SWT_Gravity , //重力
SWT_Wind , //风力,类似重力,多了湍流
SWT_Drag , //风阻 水阻 墙阻
SWT_Vortex , //旋涡
SWT_Deflector , //导向板
};
效果:
添加了地面导向板、粒子拖尾、粒子附模
metaball 粒子:
更多参数见3dsmax粒子修改器或下面的头文件:
//========================================================
// @Date: 2016.05
// @File: Include/Render/Particle.h
// @Brief: Particle
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#pragma once
#ifndef __Particle__H__
#define __Particle__H__
#include "General/String.h"
#include "Math/Mathlib.h"
#include "Math/MathLibIncDbg.h"
#include "Render/Texture.h"
/**
1,一般勾选面贴图否则贴图颜色随生命变化
2,发射器的形状可以靠附着模型表面来指定, 粒子速度指向面法线方向
5,可以驱动metallball,但不承担SPH模拟。
todo: 将导向板风力等导出到额外物体 棍扫落叶:风力SpaceWind绑定到骨骼
*/
class File;
class Curve;
class MetaballSys3D;
class VertexBuffer;
class IndexBuffer;
class ListItemUpdater;
namespace RendSys
{
class Mesh;
class MovieClip;
class MC_Frame;
class ParticleEmitter;
//粒子
class Particle
{
public:
Particle();
inline void Update(float timeFrame);
void ForcePos(vec3& pos);
void ForceSpeed(vec3& speed);
void Wander(vec3& pos1,vec3& pos2);
Particle* prev;
Particle* next;
vec3 pos; //位置
vec3 posSpeed; //速度
float size; //大小
vec3 rotAxis; //粒子产生时 生成旋转轴
float rotSpeed; //旋转速度
float rot; //粒子产生时 =rotPhase;
float life; //生命
float lifeReverse; //剩余生命
bool doFlected; //是否执行导向板反弹
bool deflected; //反弹标记
//气泡运动
vec3 bubbleDis; //方向+长度
float lastSinBubble;
float bubble; //气泡当前相位 0~twopi
float bubbleSpeed;
float d; //d[8] 距离导向板的有向距 目前一个发射器最多只支持一个导向板
int generation; //粒子代数
int spawnNum; //繁殖或拖尾数量
float u; //u坐标
Color color; //颜色
Color colorSpeed;
};
//粒子发射方向类型
enum ParticleDirType
{
PMT_ObjUp , //初始[0, 1,0],跟随物体变换
PMT_ObjDown , //初始[0,-1,0],跟随物体变换
PMT_Rand , //随机
PMT_Fix , //固定轴 对于cloud不一定同物体的dir
PMT_FaceNormal , //沿附着面法线
};
const char* ParticleDirTypeToString(int enumeration);
bool StringToParticleDirType(const char* str,int& type);
//粒子旋转类型
enum ParticleRotType
{
PRT_RotRand , //随机轴自旋
PRT_RotFixed , //固定轴自旋
PRT_RotTumble , //翻滚
PRT_RotMotion , //粒子自动朝向运动方向,并且绕head旋转,对于公告板类型无效
};
const char* ParticleRotTypeToString(int enumeration);
bool StringToParticleRotType(const char* str,int& type);
//粒子发射方向异性类型
enum ParticleDirVariationType
{
PDVT_Add = 0, //直接相加
PDVT_Spot, //锥角平均
PDVT_Spot2, //锥角正太
};
//粒子绘制类型
enum ParticleDrawType
{
PDT_PLANE = 0,//3d面 3d自旋
PDT_CROSS2 = 1,//双十字交叉面
PDT_CROSS3 = 2,//三十字交叉面
PDT_BILLBORD = 3,//公告板 z自旋
PDT_MESH = 4,//模型
PDT_METABALL = 5,//水滴
PDT_NUM
};
const char* ParticleDrawTypeToString(int enumeration);
bool StringToParticleDrawType(const char* str,int& type);
//发射器形状类型
enum EmitterShapeType
{
EST_POINT = 0,//点
EST_PLANE = 1,//面
EST_BOX = 2,//正方体
EST_SPHERE = 3,//球
EST_AIRSPHERE = 4,//空心球
EST_CYLINDER = 5,//圆柱
EST_MESH = 6,//附着模型
EST_SPAWN = 9,//只能通过别的粒子拖尾或繁殖
EST_NUM
};
const char* EmitterShapeTypeToString(int enumeration);
bool StringToEmitterShapeType(const char* str,int& type);
//贴图 uv类型
enum TextureUVType
{
TU_Face , //面uv
TU_Life , //根据life平滑移动v坐标,每个粒子再随机u坐标,可以做出烟花效果?? 会出现正方形方框
TU_Life2 , //根据life幻灯片移动v坐标
TU_Dist , //根据距离
TU_Dist2 ,
};
const char* TextureUVTypeToString(int enumeration);
bool StringToTextureUVType(const char* str,int& type);
//粒子繁殖类型
enum ParticleSpawnType
{
PST_None ,//无繁殖
PST_DieOnCollision ,//碰撞导向板时死亡
PST_SpawnOnCollision,//碰撞导向板时繁殖
PST_SpawnOnDeath ,//死亡时繁殖
PST_SpawnTrails ,//拖尾繁殖
};
const char* ParticleSpawnTypeToString(int enumeration);
bool StringToParticleSpawnType(const char* str,int& type);
//空间扭曲类型
enum SpaceWrapType
{
//SWT_Motor , //
//SWT_Push , //
//SWT_PBomb , //
//SWT_PathFollow , //
//SWT_Displace , //
SWT_Gravity , //重力
SWT_Wind , //风力,类似重力,多了湍流
SWT_Drag , //风阻 水阻 墙阻
SWT_Vortex , //旋涡
SWT_Deflector , //导向板
};
const char* SpaceWrapTypeToString(int enumeration);
bool StringToSpaceWrapType(const char* str,int& type);
//空间扭曲
class SpaceWrap
{
public:
SpaceWrap();
virtual ~SpaceWrap();
virtual SpaceWrap* Clone();
virtual void DebugRender();
virtual void Advance(float time){};
/*virtual*/ inline void AffectParticle(Particle* pariticle,float time){};
String name;
int spaceWrapType;
bool active;
vec3 pos,dir;
vec3 posL;
mat4 transform;
};
//重力
class SpaceGravity:public SpaceWrap
{
public:
SpaceGravity();;
virtual SpaceGravity* Clone();
/*virtual*/inline void AffectParticle(Particle* pariticle,float time);
int type; //0 Planar Spherical
float strength; //强度
float decay; //衰减
float strength_tempori;
};
//目前只有风力提供衰减,方便玩家通过风力和粒子交互
class SpaceWind:public SpaceWrap
{
public:
SpaceWind();;
virtual SpaceWind* Clone();
virtual void Advance(float time);
/*virtual*/inline void AffectParticle(Particle* pariticle,float time);
int type; //0 Planar Spherical
float strength; //强度
float decay; //衰减
float turbulence; //湍流强度default: 1.0 -- animatable
float frequency; //湍流频率
float scale;
float turbulenceTime;
float stengthA;
float stengthB;
vec3 dirA;
vec3 dirB;
float strength_tempori;
};
//风阻 水阻 墙阻
class SpaceDrag:public SpaceWrap
{
public:
SpaceDrag();;
virtual SpaceDrag* Clone();
/*virtual*/inline void AffectParticle(Particle* pariticle,float time);
int type; //0 Planar Spherical
float strength; //强度
float decay; //衰减
float turbulence; //湍流强度default: 1.0 -- animatable
float frequency; //湍流频率
float scale;
float turbulenceTime;
float stengthA;
float stengthB;
vec3 dirA;
vec3 dirB;
};
//旋涡
class SpaceVortex:public SpaceWrap
{
public:
SpaceVortex();;
virtual SpaceVortex* Clone();
/*virtual*/inline void AffectParticle(Particle* pariticle,float time);
float taperstrength; //变尖强度 default: 100.0 ; Taper_Length
float tapershape; //松紧 default: 1.0 ; Taper_Curve Range=1.0 to 4.0.
bool rangeless; //是否限制范围Unlimited_Range
float axialstrength; //default: 0.1 轴向运动速度 Axial_Drop_Strength
float axialrange; //轴向阻尼开始衰减的位置(距离icon中心 而不是轴线) default: 100.0 Axial_Range
float axialfalloff; //轴向阻尼衰减到零的位置 default: 1000.0 Axial_Falloff
float axialdamping; //轴向阻尼 每帧减少百本比 default: 5.0 Axial_Damping
//particle motion parallel to the drop axis is restrained per frame. Default=5.0. Range=0 to 100.
float rotationstrength; //旋转速度 default: 0.5 Orbital_Speed_Strength
float rotationrange; //旋转阻尼开始衰减的位置 default: 100.0 Orbital_Range
float rotationfalloff; //旋转阻尼衰减到零的位置 default: 1000.0 Orbital_Falloff
float rotationdamping; //旋转阻尼 每帧减少百本比default: 5.0 Orbital_Damping
float radialstrength; //径向速度 default: 0.5 Radial_Pull_Strength
float radialrange; //径向阻尼开始衰减的位置 default: 100.0 Radial_Range
float radialfalloff; //径向阻尼衰减到零的位置 default: 1000.0 Radial_Falloff
float radialdamping; //径向阻尼 每帧减少百本比default: 5.0 Radial_Damping
bool direction; //是否逆时针
};
////!导向板碰撞后增殖(子弹扫射冒烟 箭群碰墙落下插地)
////!蘑菇云 时间碰撞器触发后爆开
class SpaceDeflector:public SpaceWrap
{
public:
enum ReactorAction
{
RT_REFLECT = 0,//反射
RT_TARGETPOS, //定点反弹
RT_TARGETDIR, //定向反弹
RT_REDUCELIFE //减life
};
//竖直反弹板加速
SpaceDeflector();;
virtual SpaceDeflector* Clone();
/*virtual*/inline bool AffectParticle(Particle* particle,float time);
ReactorAction m_action;
//!定点反弹
vec3 m_targetPos;
//!定向反弹
vec3 m_targetDir;
//!法线反弹
int type; //0
float width; //大小
float length;
float bounce; //强度
float variation; //强度异性
float chaos; //反射角异性
float friction; //摩擦
float inheritVelocity; //运动继承
float d; //原点到面有向距离
float width_tempori ;
float length_tempori;
};
/**粒子发射器
* snow rain 跟随摄像机 瞬间产生线
* 瀑布 火焰 流体 流体模型碰撞 吸魔
*/
class ParticleEmitter
{
friend class Particle;
friend class ParticleEditorGui;
public:
struct Vertex
{
float x, y, z;
float u, v, w;
float r, g, b,a;
};
ParticleEmitter();
ParticleEmitter(const ParticleEmitter& emitter);
void operator= (const ParticleEmitter& emitter);
virtual ~ParticleEmitter();
//重置发射器
void IdentityEmitter();
void GotoAndPlay(float timeFrame);
void Free();
void LoadFromFile(const char* filename);
void SaveToFile (const char* filename);
void LoadingUpdate();
void InitBuffer();
void Render();
void Update(float time);
void EmitParticle(Particle* particle);
void EmitParticle(Particle* parent,Particle* particle);
//mat对发射器的作用分两种,1只改变新发射的粒子,2改变所有存活粒子(todo)
void SetEmitterMat(const mat4& mat);
//空间扭曲只改变位置大小?不改变旋转
void OffsetSpaceWrap(const vec3& pos,float fitScale);
//空间扭曲改变旋转,一般不旋转重力
void OffsetSpaceWrap(const mat4& mat);
//emitterdef
void SetEmitterBound(vec3& bound);
void SetEmitterShapeType(EmitterShapeType type);
void SetParticleNum(int num);
bool SetTexture(const char* fileName);
RendSys::MovieClip* GetEmitterMovie() const;
void SetEmitterMovie(RendSys::MovieClip* movie);
bool SetParticleMovie(const char* fileName);
bool SetParticleMovie(RendSys::MovieClip* movie);
//SpaceWrap
bool AddSpaceWrap(SpaceWrap* spaceWrap);
//
void UpdateAllItems(ListItemUpdater& updater);
protected:
//构建缓存区
void BuildBuffer();
//从活动列表删除,加入非活动列表头部
void PushInactive(Particle* particle);
Particle* PopInactive();
protected:
Particle* m_activeParticles; //活动粒子链表
Particle* m_inactiveParticles; //非活动粒子链表
int m_activeParticleNum;
float m_toResetParticleNum;
float m_regulatorTime;
TexturePtr m_texture;
//!作为粒子的模型,顶点拷贝同一批次渲染
RendSys::MovieClip* m_particleMovie;
//!表面发射模型,可能被克隆多个实体
RendSys::MovieClip* m_emitterShapeMovie;
//!使得仅有旋转时也能产生运动继承 只有PCloud、 framemovie+PArray时有效
//对于SuperSpray发射点无偏移所以无效,对于boneMovie需要lastMixMesh才有效
//mat4 m_lastEmitterShapeFrame;
//流体粒子渲染器
MetaballSys3D* m_metaballSys;
Particle* m_particles; //所有粒子数组
Vertex* m_vertexs;
VertexBuffer* m_vertexBuffer;
IndexBuffer* m_indexBuffer;
public://can not animatable def
String m_emitterName;
//随机种子
int m_emitterSeed;
//发射器形状类型
EmitterShapeType m_emitterShapeType;
//!表面发射模型名字
String m_emitterShapeMovieName;
int m_emitterMaxParticle;
ParticleDrawType m_particleDrawType;
String m_particleMovieName;
//metaball 参数
float m_particleMetaTension;//张力 数值越大 水滴越难融合 和3dsmax有出入 要求0.1~0.5之间
float m_particleMetaTensionVariation;
float m_particleMetaRenderCoarsness;//渲染粗糙度
float m_particleLife;
float m_particleLifeVariation;
//!考虑到效率,序列贴图必须在一张纹理中
String m_textureName;
int m_opacityType;
TextureUVType m_textureUVType;
int m_textureUTile;
float m_textureFrameTime;
public://animatable def
mat4 m_emitterMatrix; //发射器变换矩阵
vec3 m_emitterSpeed; //发射器运动速度,用作运动继承,不是粒子发射速度
//<<粒子生成
vec3 m_emitterBound; //发射盒
float m_emitterDensity; //!每帧发射个数:<=0时不发射
Color m_particleStartColor;
Color m_particleEndColor;
float m_particleSpeed; //粒子发射速度
float m_particleSpeedVariation; //粒子速度异性
ParticleDirType m_particleDirType; //粒子方向类型
float m_particleDirVariation; //粒子方向异性
int m_particleDirVariationType; //粒子方向异性类型
vec3 m_particleFixDir; //固定轴向时使用
float m_particleSize; //粒子大小
float m_particleSizeVariation; //粒子大小异性
float m_particleSizeGrowTime; //粒子出生到最大的时间(0.01~m_size)
float m_particleSizeFadeTime; //粒子最大到死亡的时间(m_size~m_size/10)
//<<翻滚
//3dsmax 中只产生粒子旋转效果无位移效果
float m_tumble; //翻滚 翻滚时自旋失效 todo:翻滚和粒子运动速度有相关性 生命周期内多次随机改变翻滚轴 翻滚速度为正弦波
float m_tumbleSpeed;
//<<气泡运动
//可以代替上面的翻滚效果
//3dsmax 中只产生粒子位移效果
float m_particleBubble ; //气泡运动幅度 运动速度无关 沿轴叠加正弦位移
float m_particleBubbleVariation ;
float m_particleBubblePeriod ;
float m_particleBubblePeriodVariation;
//<<旋转
ParticleRotType m_particleRotType; //0:随机轴 1:固定轴 2:运动方向
float m_motionStretch; //for 2 rot_motion
vec3 m_particleRotAxis; //自旋轴
float m_particleRotAxisVariation;
float m_particleRotSpeed;
float m_particleRotSpeedVariation;
float m_particleRotPhase;
float m_particleRotPhaseVariation;
//<<运动继承 animatable
//3dsmax中旋转运动不会产生运动继承
float m_particleMotionInherit; //运动继承的例子数量
float m_particleMotionInheritMultiplier; //继承强度
float m_particleMotionInheritVariation; //强度异性
//<<粒子繁殖
//粒子繁殖后可能模型 大小 速度 旋转 生命值都可能变
//??todo 采用有别于3dsmax的改进方案:添加发射形状类型EST_SPAWN???
#define MaxSpawnGeneration 4
enum ChaosType
{
CT_Slow = 0, //根据spawn_Speed_Chaos减慢粒子速度
CT_Fast = 1, //加快
CT_Both = 2,
CT_Down = 0, //变小
CT_Up = 1, //变大
//CT_Both = 2,
CT_Fixed = -1,//Chaos固定,而不在范围内随机
};
ParticleSpawnType m_spawnType;
float m_spawn_Affects; //执行繁殖的例子百分比
int m_spawn_Generations; //繁殖代数
int m_spawn_Multiply; //繁殖个数
float m_spawn_MultiplyVariation;
int m_lifeAfterCollision; //碰撞后存活帧数
float m_lifeAfterCollisionVariation;
float m_spawn_DirChaos; //0~1 子粒子继承父粒子速度后的改变. 0不变. 1完全随机 0.5随机到90度
float m_spawn_SpeedChaos; //0~1 子粒子速度改变
ChaosType m_spawn_SpeedType;
bool m_spawnInheritVelocity; //inherit the speed of their parents, in addition to the effect of the .spawn_Speed_Chaos value.
float m_spawn_Scale_Chaos;
ChaosType m_spawnScaleType;
int m_spawnLifeQueue[MaxSpawnGeneration]; // 每一代的粒子寿命
float m_objectMutationQueue[MaxSpawnGeneration]; // 每一代的粒子模型
//<<空间扭曲
//todo animatable
#define MaxSpaceWrap 8
SpaceWrap* m_spaceWraps[MaxSpaceWrap]; //
int m_spaceWrapNum;
//适用性缩放 影响的因素有 粒子大小、速度 发射器boundbox 空间扭曲力
//粒子的出生的位置、速度都被m_emitterMatrix自动缩放了
//发射器boundbox、speed也自动计算了
float m_fitScale;
};
//!刀光拖尾,配合uv可以做出闪电尾光、水墨尾光、或火花甩出去的特效(拖尾隐形延长)。
//!配合骨骼动画,使拖体不总是一条直线,可以做出更炫的效果
//!在长直面片上,流动的视觉幻象会减弱
//!水墨也可以用截屏来做
class StripTail
{
public:
struct Vertex
{
float x, y, z;
float u, v, w;
};
enum TailType
{
Tail_U,
Tail_V,
};
StripTail(int nodeNum,int stepNum,float stepLife,const char* texture);
~StripTail();
void AddStep(Vertex* nodes);
void Update(float time);
void Render(int option);
Vertex* m_stepVertexs;
float* m_stepLifes;
Vertex* m_bufVertexs;
VertexBuffer* m_vertexBuffer;
IndexBuffer* m_indexBuffer;
#ifdef _DEBUG
Vertex(* m_debugStepVertexs)[100];
float(* m_debugStepLifes)[100];
#endif
Vertex* m_toAddVertex;
//int* m_indexs;
int m_startStepIndex;
int m_opacityType;
//int m_endIndex;
int m_stepNum;
int m_nodeNum;
float m_cdTime;
float m_cdMaxTime;
float m_maxStepLifes;
TailType m_tailType;
TexturePtr m_texture;
int m_activeStepNum;
};
}
#endif
粒子出生设置部分源码:看似有些复杂,速度并不是很慢。
void ParticleEmitter::EmitParticle(Particle* particle)
{
particle->generation = 0;
vec3 faceNormal,faceTangent;
//==================^_^pos
{
vec3 halfEmitterBound = m_emitterBound*0.5f;
switch(m_emitterShapeType)
{
case EST_PLANE:
case EST_BOX:
{
particle->pos.x = halfEmitterBound.x * RandRange(-1.0,1.0);
particle->pos.y = halfEmitterBound.y * RandRange(-1.0,1.0);
particle->pos.z = halfEmitterBound.z * RandRange(-1.0,1.0);
break;
}
case EST_SPHERE:
{
////先绕z轴旋转theta1 再绕y轴旋转theta2 错误方法不均匀的分布
//float theta1 = RandRange(0.0f,TWOPI);
//float theta2 = RandRange(0.0f,TWOPI);
//float len = RandRange(-1.0,1.0);
//float radLevel = cosf(theta1)*len; //水平半径
//float ex = halfEmitterBound.x *radLevel * cosf(theta2);
//float ey = halfEmitterBound.y *sinf(theta1)*len;
//float ez = halfEmitterBound.z *radLevel * sinf(theta2);
//particle->pos += vec3(ex,ey,ez);
//正确方法1: 先绕z轴旋转theta1 再绕新的y'轴旋转theta2 得到球面上的随机点, 乘以(在半径上随机取长度开3次方)
//正确方法2:
while(1)
{
particle->pos.x = RandRange(-1.0,1.0);
particle->pos.y = RandRange(-1.0,1.0);
particle->pos.z = RandRange(-1.0,1.0);
if (particle->pos.LengthSq()<1)
{
particle->pos.x *= halfEmitterBound.x;
particle->pos.y *= halfEmitterBound.y;
particle->pos.z *= halfEmitterBound.z;
break;
}
}
break;
}
case EST_AIRSPHERE:
{
while(1)
{
particle->pos.x = RandRange(-1.0,1.0);
particle->pos.y = RandRange(-1.0,1.0);
particle->pos.z = RandRange(-1.0,1.0);
if (particle->pos.LengthSq()<1)
{
particle->pos.Normalize();
particle->pos.x *= halfEmitterBound.x;
particle->pos.y *= halfEmitterBound.y;
particle->pos.z *= halfEmitterBound.z;
break;
}
}
break;
}
case EST_CYLINDER:
{
while(1)
{
particle->pos.x = RandRange(-1.0,1.0);
particle->pos.y = 0;
particle->pos.z = RandRange(-1.0,1.0);
if (particle->pos.LengthSq()<1)
{
particle->pos.x *= halfEmitterBound.z;//halfEmitterBound.x;
particle->pos.y = RandRange(-1.0,1.0)*halfEmitterBound.y;
particle->pos.z *= halfEmitterBound.z;
break;
}
}
break;
}
//case EST_AIRCYLINDER:
// {
// while(1)
// {
// particle->pos.x = RandRange(-1.0,1.0);
// particle->pos.y = 0;
// particle->pos.z = RandRange(-1.0,1.0);
// if (particle->pos.LengthSq()<1)
// {
// particle->pos.Normalize();
// particle->pos.x *= halfEmitterBound.x;
// particle->pos.y = RandRange(-1.0,1.0)*halfEmitterBound.y;
// particle->pos.z *= halfEmitterBound.z;
// break;
// }
// }
// break;
// }
case EST_MESH:
{
if (m_emitterShapeMovie)
{
//对于framemovie 旋转不产生运动继承,位移已经体现在m_emitterSpeed中
//对于bonemovie m_lastEmitterShapeFrame无效,应该保存last mixmesh
//if (m_particleMotionInherit>0 && m_particleMotionInheritMultiplier>0)
//{
// //带运动继承
// m_emitterShapeMovie->GetRandMeshPoint(m_lastEmitterShapeFrame,particle->pos,faceNormal,faceTangent,m_emitterSpeed);
//}
//else
{
//不带运动继承
m_emitterShapeMovie->GetRandMeshPoint(particle->pos,faceNormal,faceTangent);
}
}
break;
}
default:
break;
}
if (m_emitterShapeType!=EST_MESH)
{
particle->pos = m_emitterMatrix * particle->pos;
}
}
//==================^_^speed
{
float randSpeed = m_particleSpeed;
if(m_particleSpeedVariation>_EPSILON)
randSpeed *= RandRange(1-m_particleSpeedVariation,1+m_particleSpeedVariation);
if (m_particleDirType==PMT_Rand)
{
//异向失效
particle->posSpeed.x = RandRange(-1.0,1.0);
particle->posSpeed.y = RandRange(-1.0,1.0);
particle->posSpeed.z = RandRange(-1.0,1.0);
particle->posSpeed.Normalize();
particle->posSpeed *= randSpeed;
}
else if (m_particleDirType==PMT_Fix) //设置m_emitterMatrix即可
{
particle->posSpeed = m_particleFixDir*randSpeed;
if (m_particleDirVariation>_EPSILON)
{
if (m_particleDirVariationType==PDVT_Add)
{
//速度相加
float randDir = m_particleDirVariation*randSpeed;
//particle->posSpeed.x += RandRange(-m_particleDirVariation,m_particleDirVariation);
//particle->posSpeed.y += RandRange(-m_particleDirVariation,m_particleDirVariation);
//particle->posSpeed.z += RandRange(-m_particleDirVariation,m_particleDirVariation);
particle->posSpeed.x += RandRange(-randDir,randDir);
particle->posSpeed.y += RandRange(-randDir,randDir);
particle->posSpeed.z += RandRange(-randDir,randDir);
}
}
}
else if (m_particleDirType==PMT_FaceNormal)
{
particle->posSpeed.x = 0;
particle->posSpeed.y = 0;
particle->posSpeed.z = randSpeed;
if (m_particleDirVariation>_EPSILON)
{
if (m_particleDirVariationType==PDVT_Add)
{
//速度相加
float randDir = m_particleDirVariation*randSpeed;
//particle->posSpeed.x += RandRange(-m_particleDirVariation,m_particleDirVariation);
//particle->posSpeed.y += RandRange(-m_particleDirVariation,m_particleDirVariation);
//particle->posSpeed.z += RandRange(-m_particleDirVariation,m_particleDirVariation);
particle->posSpeed.x += RandRange(-randDir,randDir);
particle->posSpeed.y += RandRange(-randDir,randDir);
particle->posSpeed.z += RandRange(-randDir,randDir);
}
else if (m_particleDirVariationType==PDVT_Spot)
{
vec3 dir;
GetRandDir(m_particleDirVariation,dir);
particle->posSpeed.x = dir.x*randSpeed;
particle->posSpeed.y = dir.z*randSpeed;//dir.y*randSpeed;
particle->posSpeed.z = dir.y*randSpeed;//dir.z*randSpeed;
}
}
//转到face坐标系
//mat4 TBN;
//TBN.LookAt(faceTangent,faceBitangent,faceNormal,vec3());
//TBN.InverseLookAt(); //equal transpose
//particle->posSpeed = TBN*particle->posSpeed;
vec3 faceBitangent = faceNormal.Cross(faceTangent);
mat3 TBN;//= mat3(faceTangent, faceBitangent, faceNormal);
TBN.mat[0] = faceTangent.x; TBN.mat[3] = faceBitangent.x; TBN.mat[6] = faceNormal.x;
TBN.mat[1] = faceTangent.y; TBN.mat[4] = faceBitangent.y; TBN.mat[7] = faceNormal.y;
TBN.mat[2] = faceTangent.z; TBN.mat[5] = faceBitangent.z; TBN.mat[8] = faceNormal.z;
particle->posSpeed = TBN*particle->posSpeed;//vec3(0,0,randSpeed);
}
else if (m_particleDirType==PMT_ObjUp
||m_particleDirType==PMT_ObjDown)
{
particle->posSpeed.x = 0;
particle->posSpeed.y = randSpeed;
particle->posSpeed.z = 0;
if (m_particleDirVariation>_EPSILON)
{
if (m_particleDirVariationType==PDVT_Add)
{
//速度相加
float randDir = m_particleDirVariation*randSpeed;
//particle->posSpeed.x += RandRange(-m_particleDirVariation,m_particleDirVariation);
//particle->posSpeed.y += RandRange(-m_particleDirVariation,m_particleDirVariation);
//particle->posSpeed.z += RandRange(-m_particleDirVariation,m_particleDirVariation);
particle->posSpeed.x += RandRange(-randDir,randDir);
particle->posSpeed.y += RandRange(-randDir,randDir);
particle->posSpeed.z += RandRange(-randDir,randDir);
}
else if (m_particleDirVariationType==PDVT_Spot)
{
vec3 dir;
GetRandDir(m_particleDirVariation,dir);
particle->posSpeed.x = dir.x*randSpeed;
particle->posSpeed.y = dir.y*randSpeed;
particle->posSpeed.z = dir.z*randSpeed;
}
}
if (m_particleDirType==PMT_ObjDown)
particle->posSpeed.y *= -1;
//转到obj坐标系
m_emitterMatrix.AffectNormal(particle->posSpeed);
}
}
//运动继承
if (m_particleMotionInherit>_EPSILON) //运动继承的粒子数量
{
if (RandRange(0.0f,1.0f)<m_particleMotionInherit)
{
//if ( m_emitterShapeType==EST_MESH &&
// (m_emitterShapeMovie->m_type == MovieClip::MT_BONE || m_emitterShapeMovie->m_type == MovieClip::MT_VERTEXANIM)
// )
//{
//仅有旋转也会产生运动继承
// speed = per trigion speed;
//}
//else
{
//仅有旋转不产生运动继承
particle->posSpeed += m_emitterSpeed*m_particleMotionInheritMultiplier*RandRange(1-m_particleMotionInheritVariation,1+m_particleMotionInheritVariation);
}
}
}
//if (particle->posSpeed.Length()>100)
//{
// int a = 0;
//}
//超级喷射第一帧移动距离均匀分布, 避免出现空白
particle->pos += particle->posSpeed*(RandRange(0.0f,1.0f));
//==================^_^
{
particle->size = m_particleSize;
if(m_particleSizeVariation>_EPSILON)
{
particle->size *= RandRange(1-m_particleSizeVariation,1+m_particleSizeVariation);
}
particle->rot = m_particleRotPhase;
particle->rot *= RandRange(1-m_particleRotPhaseVariation,1.0f);
particle->rotSpeed = m_particleRotSpeed;
particle->rotSpeed *= RandRange(1-m_particleRotSpeedVariation,1+m_particleRotSpeedVariation);
if (m_particleDrawType==PDT_BILLBORD)
{
particle->rotSpeed *= (Rand()%2)?1:-1;
}
if (m_particleRotType == PRT_RotRand)
{
//非均匀分布 todo
particle->rotAxis = vec3(RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f));
particle->rotAxis.Normalize();
}
else if (m_particleRotType == PRT_RotFixed)
{
particle->rotAxis = m_particleRotAxis;
if (m_particleRotAxisVariation>_EPSILON)
{
//0~pi
mat4 mat;
mat.FromAxisAngle(vec3(RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f)),m_particleRotAxisVariation);
mat.AffectNormal(particle->rotAxis);
particle->rotAxis.Normalize();
}
}
else if (m_particleRotType == PRT_RotTumble)
{
particle->rotAxis = vec3(RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f));
particle->rotAxis.Normalize();
}
particle->life = 0;
particle->lifeReverse = m_particleLife;
if(m_particleLifeVariation>_EPSILON)
particle->lifeReverse *= RandRange(1-m_particleLifeVariation,1.0f);
}
//==================^_^
particle->bubble = 0;
particle->lastSinBubble = 0;
if (m_particleBubble>_EPSILON)
{
particle->bubbleDis = vec3(RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f),RandRange(-1.0f,1.0f))*m_particleBubble*RandRange(1.0f-m_particleBubbleVariation,1.0f);
particle->bubbleSpeed = TWOPI/(m_particleBubblePeriod*RandRange(1-m_particleBubblePeriodVariation,1+m_particleBubblePeriodVariation));
}
else
{
particle->bubbleSpeed = 0;
}
//==================^_^
if (m_spawnType==PST_SpawnTrails
||m_spawnType==PST_SpawnOnCollision
||m_spawnType==PST_SpawnOnDeath
&&RandRange(0.0f,1.0f)<=m_spawn_Affects)
{
particle->spawnNum = m_spawn_Multiply*RandRange(1-m_spawn_MultiplyVariation,1+m_spawn_MultiplyVariation);
}
else
{
particle->spawnNum = 0;
}
//==================^_^
SpaceWrap* psw;
SpaceWrap** ppsw = m_spaceWraps;
SpaceWrap** swEnd = m_spaceWraps+m_spaceWrapNum;
for (ppsw=m_spaceWraps;ppsw!=swEnd;ppsw++)
{
psw = *ppsw;
switch(psw->spaceWrapType)
{
case SWT_Deflector:
particle->d = Dot(psw->dir, particle->pos) - ((SpaceDeflector*)psw)->d;
break;
case SWT_Vortex:
particle->posSpeed -= psw->dir*((SpaceVortex*)psw)->axialstrength;//默认朝下 初始化时只叠加一次
break;
}
}
//
if (m_textureUVType==TU_Life)
{
//particle->u = RandRange(0.0f,1.0f);
//float rat = particle->lifeReverse/this->m_particleLife;
//if (rat<0) rat = 0;
//else if(rat>1) rat = 1;
//particle->color = this->m_particleStartColor*rat + this->m_particleEndColor*(1-rat);
particle->color = Color(RandRange(0.0f,1.0f),RandRange(0.0f,1.0f),RandRange(0.0f,1.0f),1);
particle->colorSpeed = Color(0,0,0,0.5f/particle->lifeReverse);
}
else
{
particle->color = m_particleStartColor;
particle->colorSpeed = (m_particleEndColor-m_particleStartColor)*(1.0f/particle->lifeReverse);
}
particle->doFlected = true;
}
完