📄 m2particle.cpp
字号:
//--------------------------------------------------
// Desc: M2 Particle System
//--------------------------------------------------
#include "M2Particle.h"
#include "M2Loader.h"
#include "Common.h"
#define MAX_M2PARTICLES 1000
D3DXVECTOR4 FromARGB(uint32 color)
{
const float a = ((color & 0xFF000000) >> 24) / 255.0f;
const float r = ((color & 0x00FF0000) >> 16) / 255.0f;
const float g = ((color & 0x0000FF00) >> 8) / 255.0f;
const float b = ((color & 0x000000FF) ) / 255.0f;
return D3DXVECTOR4(r, g, b, a);
}
template<class T>
T lifeRamp(float life, float mid, const T &a, const T &b, const T &c)
{
if(life<=mid) return InterpolateLinear<T>(life / mid, a, b);
else return InterpolateLinear<T>((life-mid) / (1.0f-mid), b, c);
}
M2ParticleSystem::M2ParticleSystem():
m_Emitter(NULL),
m_pModel(NULL),
m_ParentBone(NULL),
m_hTexture(0),
m_Mid(0),
m_fRemain(0)
{
m_Blend = 0;
m_Order = 0;
m_Type = 0;
m_AnimID = 0;
m_AnimTime = 0;
m_Rows = 0;
m_Cols = 0;
m_Slowdown = 0;
m_Rotation = 0;
m_Tofs = 0;
}
M2ParticleSystem::~M2ParticleSystem()
{
delete m_Emitter;
}
void M2ParticleSystem::Init(uint8* pData, ModelParticleEmitterDef &emitter, int *pGlobalSequence)
{
m_Speed.Init(emitter.params[0], pData, pGlobalSequence); // 发射速度
m_Variation.Init(emitter.params[1], pData, pGlobalSequence); // 速度变化(0-1)
m_Spread.Init(emitter.params[2], pData, pGlobalSequence); // 相对发射器发射方向的扩散角度(0-PI)
m_Lat.Init(emitter.params[3], pData, pGlobalSequence);
m_Gravity.Init(emitter.params[4], pData, pGlobalSequence); // 重力
m_Lifespan.Init(emitter.params[5], pData, pGlobalSequence); // 寿命
m_Rate.Init(emitter.params[6], pData, pGlobalSequence); // 发射率
m_Areal.Init(emitter.params[7], pData, pGlobalSequence); // 发射区域的长度
m_Areaw.Init(emitter.params[8], pData, pGlobalSequence); // 发射区域的宽度
m_Deacceleration.Init(emitter.params[9], pData, pGlobalSequence);// 向心力
m_Enabled.Init(emitter.en, pData, pGlobalSequence);
for(int i=0; i<3; i++)
{
m_Colors[i] = FromARGB(emitter.p.colors[i]);
m_Sizes[i] = emitter.p.sizes[i];
}
m_Mid = emitter.p.mid;
m_Slowdown = emitter.p.slowdown;
m_Rotation = emitter.p.rotation;
m_Position = FixCoordSystemVector(emitter.pos);
/*
texture = model->textures[emitter.texture];
*/
m_Blend = emitter.blend;
m_Rows = emitter.rows;
m_Cols = emitter.cols;
m_Type = emitter.s1;
m_Order = emitter.s1>0 ? -1 : 0;
m_ParentBone = m_pModel->m_pBone + emitter.bone;
switch(emitter.type)
{
case 1:
m_Emitter = new PlaneEmitter(this);
break;
case 2:
m_Emitter = new SphereEmitter(this);
break;
}
m_bBillboard = !(emitter.flags & 0x1000);
// diagnosis test info
m_Flags = emitter.flags;
m_AnimID = m_AnimTime = 0;
m_fRemain = 0;
m_Tofs = rand()/(float)RAND_MAX;
for(int i=0; i<m_Rows*m_Cols; i++)
{
TexCoordSet texcoord;
InitTile(texcoord.tc, i);
m_Tiles.push_back(texcoord);
}
}
void M2ParticleSystem::InitTile(D3DXVECTOR2 *tilecoord, int num)
{
D3DXVECTOR2 oldtilecoord[4];
D3DXVECTOR2 a,b;
int x = num % m_Cols;
int y = num / m_Cols;
a.x = x * (1.0f / m_Cols);
b.x = (x+1) * (1.0f / m_Cols);
a.y = y * (1.0f / m_Rows);
b.y = (y+1) * (1.0f / m_Rows);
oldtilecoord[0] = a;
oldtilecoord[2] = b;
oldtilecoord[1].x = b.x;
oldtilecoord[1].y = a.y;
oldtilecoord[3].x = a.x;
oldtilecoord[3].y = b.y;
for(int i=0; i<4; i++)
{
tilecoord[(i+4-m_Order) & 3] = oldtilecoord[i];
}
}
void M2ParticleSystem::Update(float dt)
{
float fgrav = m_Gravity.GetValue(m_AnimID, m_AnimTime);
float fdeaccel = m_Deacceleration.GetValue(m_AnimID, m_AnimTime);
// spawn new particles
if(m_Emitter)
{
float frate = m_Rate.GetValue(m_AnimID, m_AnimTime);
float flife = 1.0f;
float ftospawn = (dt * frate / flife) + m_fRemain;
if(ftospawn < 1.0f)
{
m_fRemain = ftospawn;
if(m_fRemain<0.0f) m_fRemain = 0.0f;
}
else
{
int tospawn = (int)ftospawn;
if((tospawn + m_Particles.size()) > MAX_M2PARTICLES)
tospawn = (int)m_Particles.size() - MAX_M2PARTICLES;
m_fRemain = ftospawn - (float)tospawn;
float w = m_Areal.GetValue(m_AnimID, m_AnimTime) * 0.5f;
float l = m_Areaw.GetValue(m_AnimID, m_AnimTime) * 0.5f;
float spd = m_Speed.GetValue(m_AnimID, m_AnimTime);
float var = m_Variation.GetValue(m_AnimID, m_AnimTime);
float spr = m_Spread.GetValue(m_AnimID, m_AnimTime);
float spr2 = m_Lat.GetValue(m_AnimID, m_AnimTime);
bool en = m_Enabled.GetValue(m_AnimID, m_AnimTime) != 0;
if(en)
{
for(int i=0; i<tospawn; i++)
{
M2Particle p = m_Emitter->NewParticle(m_AnimID, m_AnimTime, w, l, spd, var, spr, spr2);
m_Particles.push_back(p);
}
}
}
}
float mspeed = 1.0f;
for(M2ParticleList::iterator it = m_Particles.begin(); it != m_Particles.end(); )
{
M2Particle &p = *it;
p.m_speed += p.m_down * fgrav * dt - p.m_dir * fdeaccel * dt;
if(m_Slowdown>0)
{
mspeed = expf(-1.0f * m_Slowdown * p.m_flife);
}
p.m_pos += p.m_speed * mspeed * dt;
p.m_flife += dt;
float rlife = p.m_flife / p.m_fmaxlife;
// calculate size and color based on lifetime
p.m_fsize = lifeRamp<float>(rlife, m_Mid, m_Sizes[0], m_Sizes[1], m_Sizes[2]);
p.m_color = lifeRamp<D3DXVECTOR4>(rlife, m_Mid, m_Colors[0], m_Colors[1], m_Colors[2]);
if(rlife >= 1.0f)
m_Particles.erase(it++);
else
++it;
}
}
void M2ParticleSystem::Render(const D3DXMATRIX &matRotate)
{
D3DXMATRIX matTrans;
D3DXMatrixIdentity(&matTrans);
if(m_bBillboard)
{ D3DXMATRIX matTemp; g_pD3DDevice->GetTransform(D3DTS_VIEW, &matTemp); float temp; D3DXMatrixInverse(&matTemp, &temp, &matTemp); if(m_Flags == 569) { // Faith shoulders, do cylindrical billboarding matTrans = matTemp; matTrans._12 = 0.0f; matTrans._14 = 0.0f; matTrans._21 = 0.0f; matTrans._23 = 0.0f; matTrans._24 = 0.0f; matTrans._32 = 0.0f; matTrans._34 = 0.0f; matTrans._41 = 0.0f; matTrans._42 = 0.0f; matTrans._43 = 0.0f; } else { // Spherical billboarding matTrans = matTemp; matTrans._14 = 0.0f; matTrans._24 = 0.0f; matTrans._34 = 0.0f; matTrans._41 = 0.0f; matTrans._42 = 0.0f; matTrans._43 = 0.0f; } }
D3DXVECTOR3 bv0;
D3DXVECTOR3 bv1;
D3DXVECTOR3 bv2;
D3DXVECTOR3 bv3;
float f = 0.5f;
float ftemp;
D3DXMATRIX matRot;
D3DXMatrixInverse(&matRot, &ftemp, &matRotate);
matTrans *= matRot;
D3DXVec3TransformCoord(&bv0, &D3DXVECTOR3(+f, +f, 0), &matTrans);
D3DXVec3TransformCoord(&bv1, &D3DXVECTOR3(-f, +f, 0), &matTrans);
D3DXVec3TransformCoord(&bv2, &D3DXVECTOR3(-f, -f, 0), &matTrans);
D3DXVec3TransformCoord(&bv3, &D3DXVECTOR3(+f, -f, 0), &matTrans);
m_Index = 0;
for(M2ParticleList::iterator it = m_Particles.begin(); it != m_Particles.end(); )
{
M2Particle &p = *it;
m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv0, 0xffffffff, m_Tiles[it->m_tile].tc[0]);
m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv1, 0xffffffff, m_Tiles[it->m_tile].tc[1]);
m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv2, 0xffffffff, m_Tiles[it->m_tile].tc[2]);
m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv2, 0xffffffff, m_Tiles[it->m_tile].tc[2]);
m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv3, 0xffffffff, m_Tiles[it->m_tile].tc[3]);
m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv0, 0xffffffff, m_Tiles[it->m_tile].tc[0]);
++it;
}
g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAREF, 0x2f);
//g_pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_pD3DDevice->SetFVF(M2PARTICLEFVF);
g_pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, m_Index/3, m_Vertex, sizeof(M2ParticleVertex));
g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
//g_pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
}
void M2ParticleSystem::Setup(int anim, int time)
{
m_AnimID = anim;
m_AnimTime = time;
}
D3DXMATRIX g_matSpread;
void CalcSpreadMatrix(float Spread1,float Spread2, float w, float l)
{
float angle[2];
float c[2];
float s[2];
D3DXMATRIX matTemp;
angle[0] = RandomFloat(-Spread1, Spread1)/2.0f;
angle[1] = RandomFloat(-Spread2, Spread2)/2.0f;
for(int i=0; i<2; i++)
{
c[i]=cos(angle[i]);
s[i]=sin(angle[i]);
}
D3DXMatrixIdentity(&g_matSpread);
g_matSpread._11 *= l;
g_matSpread._22 *= l;
g_matSpread._33 *= w;
D3DXMatrixIdentity(&matTemp);
matTemp._22 = c[0];
matTemp._23 = s[0];
matTemp._32 = -s[0];
matTemp._33 = c[0];
// Rotate X
g_matSpread *= matTemp;
D3DXMatrixIdentity(&matTemp);
matTemp._11 = c[1];
matTemp._12 = s[1];
matTemp._21 = -s[1];
matTemp._22 = c[1];
// Rotate Z
g_matSpread *= matTemp;
}
M2Particle PlaneEmitter::NewParticle(int animID, int time, float w, float l, float spd, float var, float spr, float spr2)
{
M2Particle particle;
//Spread Calculation
D3DXMATRIX matRot;
CalcSpreadMatrix(spr, spr, 1.0f, 1.0f);
matRot = m_PS->m_ParentBone->m_matRotate*g_matSpread;
if(m_PS->m_Flags == 1041)
{
// Trans Halo
D3DXVECTOR3 pos = (m_PS->m_Position + D3DXVECTOR3(RandomFloat(-l, l), 0, RandomFloat(-w, w)));
D3DXVec3TransformCoord(&particle.m_pos, &pos, &m_PS->m_ParentBone->m_matTrans);
float fangle = RandomFloat(0.0f, 2*AS_PI);
particle.m_pos = D3DXVECTOR3(0.0f, m_PS->m_Position.y + 0.15f, m_PS->m_Position.y) +
D3DXVECTOR3(cos(fangle)/8.0f, 0.0f, sin(fangle)/8.0f);
D3DXVECTOR3 dir(0.0f, 1.0f, 0.0f);
particle.m_speed = dir * spd * RandomFloat(0.0f, var);
}
/*
else if(m_PS->m_Flags == 25 && m_PS->m_ParentBone->m_Parent<1)
{
// Weapon Flame
particle.m_pos = m_PS->m_ParentBone->m_Point + (m_PS->m_Position +
D3DXVECTOR3(RandomFloat(-l, l), RandomFloat(-l, l), RandomFloat(-w, w)));
D3DXVECTOR3 dir;
D3DXVec3TransformCoord(&dir, &D3DXVECTOR3(0.0f, 1.0f, 0.0f), &matRot);
}
*/
else if(m_PS->m_Flags == 25 && m_PS->m_ParentBone->m_Parent>0)
{
// Weapon with built-in Flame (Avenger lightsaber!)
// particle.m_pos = m_PS->m_ParentBone->m_matTrans * (m_PS->m_Position +
// D3DXVECTOR3(RandomFloat(-l, l), RandomFloat(-l, l), RandomFloat(-w, w)));
// Vec3D dir = Vec3D(sys->parent->mat.m[1][0],sys->parent->mat.m[1][1], sys->parent->mat.m[1][2]) * Vec3D(0.0f, 1.0f, 0.0f);
// p.speed = dir.normalize() * spd * randfloat(0, var*2);
}else if(m_PS->m_Flags == 17 && m_PS->m_ParentBone->m_Parent<1)
{
// Weapon Glow
// particle.m_pos = m_PS->m_ParentBone->m_Point * (m_PS->m_Position +
// D3DXVECTOR3(RandomFloat(-l, l), RandomFloat(-l, l), RandomFloat(-w, w)));
}
else
{
particle.m_pos = m_PS->m_Position + D3DXVECTOR3(RandomFloat(-l, l), 0, RandomFloat(-w, w));
D3DXVec3TransformCoord(&particle.m_pos, &particle.m_pos, &m_PS->m_ParentBone->m_matTrans);
D3DXVECTOR3 dir;
D3DXVec3TransformCoord(&dir, &D3DXVECTOR3(0.0f, 1.0f, 0.0f), &matRot);
particle.m_down = D3DXVECTOR3(0.0f, -1.0f,0.0f);
D3DXVec3Normalize(&dir, &dir);
particle.m_speed = dir * spd * (1.0f + RandomFloat(-var, var));
}
if(!m_PS->m_bBillboard)
{ /* D3DXVECTOR3 look = particle.m_dir; look.x=p.dir.y; look.y=p.dir.z; look.z=p.dir.x; Vec3D up = ( look % p.dir).normalize(); Vec3D right = (up % p.dir).normalize(); up = (p.dir % right).normalize(); // calculate the billboard matrix p.mface.m[0][1] = right.x; p.mface.m[1][1] = right.y; p.mface.m[2][1] = right.z; p.mface.m[0][2] = up.x; p.mface.m[1][2] = up.y; p.mface.m[2][2] = up.z; p.mface.m[0][0] = p.dir.x; p.mface.m[1][0] = p.dir.y; p.mface.m[2][0] = p.dir.z;
*/
}
particle.m_flife = 0.0f;
particle.m_fmaxlife = m_PS->m_Lifespan.GetValue(animID, time);
particle.m_origin = particle.m_pos;
particle.m_tile = RandomInt(0, m_PS->m_Rows*m_PS->m_Cols-1);
return particle;
}
M2Particle SphereEmitter::NewParticle(int animID, int time, float w, float l, float spd, float var, float spr, float spr2)
{
M2Particle particle;
return particle;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -