📄 m2loader.cpp
字号:
//----------------------------------------------------
// 更新粒子系统
//----------------------------------------------------
void CM2Loader::UpdatePaticle(void)
{
if(!m_bHasParticle)
return;
if(m_LastTime != 0)
{
DWORD dt = g_GlobalTime - m_LastTime;
for(uint32 i=0; i<m_Header.nParticleEmitters; i++)
{
m_pParticle[i].Update(dt/1000.0f);
}
}
m_LastTime = g_GlobalTime;
}
//----------------------------------------------------
// 更新动画
//----------------------------------------------------
void CM2Loader::UpdateAnimation(void)
{
if(!m_bAnimated) return;
m_pAniController->Update(g_ElapsedTime);
if(g_GlobalTime - m_LastUpdate>=20)
{
m_LastUpdate = g_GlobalTime;
}
else
{
return;
}
m_CurAnimation = m_pAniController->GetAnim();
m_AnimationTime = m_pAniController->GetFrame();
int tmax = m_pAniController->GetFrameCount();
if(tmax==0)
tmax = 1;
if(m_bAnimBones)
CalculateBone();
if(m_bAnimGeometry)
{
// 顶点变换
D3DXVECTOR3 transVertex;
D3DXVECTOR3 transNormal;
ModelVertex *pVertex = (ModelVertex*)(m_pData+m_Header.ofsVertices);
ModelView *pView = (ModelView*)(m_pData+m_Header.ofsViews);
ModelGeoset *pSubMesh = (ModelGeoset*)(m_pData+pView->ofsSub);
for(uint32 j=0; j<pView->nSub; j++)
{
// 只变换显示的顶点(5.5ms降低至1.7ms处理时间平稳)
if(m_bShowSubMesh[j])
{
for(uint16 i=pSubMesh[j].vstart; i<(pSubMesh[j].vstart+pSubMesh[j].vcount); i++)
{
D3DXVECTOR3 v(0.0f, 0.0f, 0.0f), n(0.0f, 0.0f, 0.0f);
for(uint32 b=0; b<4; b++)
{
if(pVertex[i].weights[b]>0)
{
D3DXVec3TransformCoord(&transVertex, &pVertex[i].pos, &m_pBone[pVertex[i].bones[b]].m_matTrans);
D3DXVec3TransformCoord(&transNormal, &pVertex[i].normal, &m_pBone[pVertex[i].bones[b]].m_matRotate);
v += transVertex * ((float)pVertex[i].weights[b] / 255.0f);
n += transNormal * ((float)pVertex[i].weights[b] / 255.0f);
}
}
m_pVertex[i].m_position = v;
m_pVertex[i].m_normal = n;
// D3DXVec3Normalize(&m_pVertex[i].m_normal, &m_pVertex[i].m_normal);
}
}
}
}
// 粒子系统
/*
for(uint32 i=0; i<m_Header.nParticleEmitters; i++)
{
// int pt = ani.timeStart + (m_AnimationTime + (int)(tmax*m_pParticle[i].m_Tofs)) % tmax;
// m_pParticle[i].Setup(m_CurAnimation, pt);
}
*/
}
//--------------------------------------------------
// 计算骨架
//--------------------------------------------------
void CM2Loader::CalculateBone()
{
// 骨骼变换
for(uint32 i=0; i<m_Header.nBones; i++)
{
m_pBone[i].m_bCalc = false;
}
if(m_bChar)
{
int ani;
uint32 time;
//--------------------------------------------------
if(m_BoneLookup[BONE_ROOT] > -1)
{
for(int i=0; i<=m_BoneLookup[BONE_ROOT]; i++)
{
m_pBone[i].CalcMatrix(m_pBone, m_CurAnimation, m_AnimationTime);
}
}
//--------------------------------------------------
// secondary animation.
if(m_pAniController->IsChannelEnable(1))
{
ani = m_pAniController->GetAnim(1);
time = m_pAniController->GetFrame(1);
}
else
{
ani = m_CurAnimation;
time = m_AnimationTime;
}
// 组合动画
for(int i=0; i<5; i++)
{
if(m_BoneLookup[i] > -1)
m_pBone[m_BoneLookup[i]].CalcMatrix(m_pBone, ani, time);
}
if(m_BoneLookup[BONE_JAW] > -1)
m_pBone[m_BoneLookup[BONE_HEAD]].CalcMatrix(m_pBone, ani, time);
if(m_BoneLookup[BONE_JAW] > -1)
m_pBone[m_BoneLookup[BONE_JAW]].CalcMatrix(m_pBone, ani, time);
for(int i=18; i<27; i++)
{
if(m_BoneLookup[i] > -1)
m_pBone[m_BoneLookup[i]].CalcMatrix(m_pBone, ani, time);
}
}
else
{
for(int i=0; i<m_BoneLookup[BONE_ROOT]; i++)
{
m_pBone[i].CalcMatrix(m_pBone, m_CurAnimation, m_AnimationTime);
}
}
for(uint32 i=0; i<m_Header.nBones; i++)
{
m_pBone[i].CalcMatrix(m_pBone, m_CurAnimation, m_AnimationTime);
}
}
//--------------------------------------------------
// 关于灯光
// 1, 正确设置材质和法线
// 2, D3DRS_LIGHTING为TRUE
// 3, LightEnable为TRUE
// 4, 正确设置灯光SetLight
// 5, 设置D3DRS_AMBIENT环境光
//--------------------------------------------------
//--------------------------------------------------
// Skeletal
//--------------------------------------------------
void CM2Loader::RenderBone(void)
{
M2BoundVertex vertex[200];
int point = 0;
for(uint32 i=0; i<m_Header.nBones; i++)
{
if(m_pBone[i].m_Parent != -1)
{
vertex[point++].SetVertex(m_pBone[i].m_TransPoint);
vertex[point++].SetVertex(m_pBone[m_pBone[i].m_Parent].m_TransPoint);
}
}
g_pD3DDevice->SetFVF(M2BOUNDFVF);
g_pD3DDevice->SetTexture(0, NULL);
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
g_pD3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, point/2, vertex, sizeof(M2BoundVertex));
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
}
//--------------------------------------------------
// 包围体
//--------------------------------------------------
void CM2Loader::RenderBound(void)
{
// 包围体
g_pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_pD3DDevice->SetFVF(M2BOUNDFVF);
g_pD3DDevice->SetTexture(0, NULL);
g_pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, m_Header.nBoundingVertices, m_Header.nBoundingTriangles/3,
m_pBoundIndex, D3DFMT_INDEX16, m_pBoundVertex, sizeof(M2BoundVertex));
g_pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
}
//--------------------------------------------------
// Particle System
//--------------------------------------------------
void CM2Loader::RenderParticle(const D3DXMATRIX &matRotate)
{
//--------------------------------------------------
// 粒子系统的渲染
// 主要问题:
// 1, BillBoard在attachment根旋转时不正确 OK
// 2, Particle显示会清除人物显示地面背景(估计渲染顺利造成的, 粒子系统应放在模型外渲染)
// 3, 效果与Wowmodelviewer相差太大
//--------------------------------------------------
SET_TEXTURE_TYPE(0, 1007);
for(uint32 i=0; i<m_Header.nParticleEmitters; i++)
{
m_pParticle[i].Render(matRotate);
}
}
//--------------------------------------------------
// Render模型
//--------------------------------------------------
void CM2Loader::Render(void)
{
if(!m_bRender)
return;
// 暂时关闭灯光
g_pD3DDevice->LightEnable(0, TRUE);
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
// 注: 打开灯光人物头部显示有问题
/*
D3DMATERIAL9 mater;
mater.Diffuse.a = 1.0f;
mater.Diffuse.r = 1.0f;
mater.Diffuse.g = 1.0f;
mater.Diffuse.b = 1.0f;
mater.Ambient.a = 1.0f;
mater.Ambient.r = 1.0f;
mater.Ambient.g = 1.0f;
mater.Ambient.b = 1.0f;
mater.Emissive.a = 0.0f;
mater.Emissive.r = 0.0f;
mater.Emissive.g = 0.0f;
mater.Emissive.b = 0.0f;
mater.Power = 0.0f;
g_pD3DDevice->SetMaterial(&mater);
g_pD3DDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
*/
g_pD3DDevice->SetFVF(M2FVF);
unsigned long OldTex = 0;
for(size_t i=0; i<m_RenderPass.size(); i++)
{
M2RenderPass &pass = m_RenderPass[i];
if(m_bShowSubMesh[pass.m_SubMeshIndex])
{
unsigned long texHandle = 0;
if(m_SpecialTextureIndex[pass.m_TextureIndex]==-1)
texHandle = m_pTexture[pass.m_TextureIndex];
else
texHandle = m_ReplaceTexture[m_SpecialTextureIndex[pass.m_TextureIndex]];
if(OldTex != texHandle)
{
if(m_SpecialTextureIndex[pass.m_TextureIndex]!=-1 ||
m_pTexture[pass.m_TextureIndex]!=0)
{
SET_TEXTURE_TYPE(0, texHandle);
}
OldTex = texHandle;
}
// vertex start, vertex count, 图元数量, 索引数组, 格式, 顶点数组, 顶点格式
pass.OpenState(this);
g_pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, pass.m_VertexCount+pass.m_VertexStart,
pass.m_IndexCount/3, m_pVertexIndex+pass.m_IndexStart, D3DFMT_INDEX16, m_pVertex, sizeof(M2Vertex));
pass.CloseState();
}
}
g_pD3DDevice->LightEnable(0, FALSE);
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
}
//--------------------------------------------------
// 判断是否是动画模型
//--------------------------------------------------
bool CM2Loader::IsAnimation(void)
{
if(m_pData == NULL) return false;
m_bAnimGeometry = false;
m_bAnimBones = false;
m_bBillBoard = false;
ModelBoneDef *pBone = (ModelBoneDef*)(m_pData+m_Header.ofsBones);
ModelVertex *pVertex = (ModelVertex*)(m_pData+m_Header.ofsVertices);
for(size_t i=0; i<m_Header.nVertices && !m_bAnimGeometry; i++)
{
for(size_t nbone=0; nbone<4; nbone++)
{
if(pVertex[i].weights[nbone]>0)
{
ModelBoneDef &boneref = pBone[pVertex[i].bones[nbone]];
if(boneref.translation.type || boneref.rotation.type || boneref.scaling.type || (boneref.flags & 8))
{
if(boneref.flags & 8) // 需要每帧变换
{
m_bBillBoard = true;
}
// 顶点需要变换有顶点动画
m_bAnimGeometry = true;
break;
}
}
}
}
// 有顶点动画一定有骨架
if(m_bAnimGeometry)
m_bAnimBones = true;
else
{
for(size_t i=0; i<m_Header.nBones; i++)
{
ModelBoneDef &boneref = pBone[i];
if(boneref.translation.type || boneref.rotation.type || boneref.scaling.type)
{
m_bAnimBones = true;
break;
}
}
}
// 纹理动画
m_bAnimTextures = m_Header.nTexAnims > 0;
// 有摄像机, 灯光, 粒子系统即需要骨架
bool bAnimMisc = m_Header.nCameras>0 || m_Header.nLights>0 ||
m_Header.nParticleEmitters>0 || m_Header.nRibbonEmitters>0;
if(bAnimMisc) m_bAnimBones = true;
// 颜色变化动画animated colors
if(m_Header.nColors)
{
ModelColorDef *pColor = (ModelColorDef*)(m_pData+m_Header.ofsColors);
for(size_t i=0; i<m_Header.nColors; i++)
{
if(pColor[i].color.type!=0 || pColor[i].opacity.type!=0)
{
bAnimMisc = true;
break;
}
}
}
// 透明度动画animated opacity
if(m_Header.nTransparency && !bAnimMisc)
{
ModelTransDef *pTrans = (ModelTransDef*)(m_pData+m_Header.ofsTransparency);
for(size_t i=0; i<m_Header.nTransparency; i++)
{
if(pTrans[i].trans.type !=0 )
{
bAnimMisc = true;
break;
}
}
}
return m_bAnimGeometry || m_bAnimTextures;// || bAnimMisc;
}
//--------------------------------------------------
// 取得某骨架的变换矩阵
//--------------------------------------------------
D3DXMATRIX CM2Loader::GetAttachmentMatrix(int index)
{
D3DXMATRIX matRet;
D3DXMATRIX matBone;
int attachindex = m_AttachLookup[index];
if(attachindex>=0)
{
int boneindex = m_Attachment[attachindex].GetBoneIndex();
if(boneindex<0)
WriteLog(INFO_ERROR, "bone index < 0[CM2Loader::GetAttachmentMatrix]");
matBone = m_pBone[boneindex].m_matTrans;
m_Attachment[attachindex].GetMatrix(&matRet, &matBone);
}
else
{
D3DXMatrixIdentity(&matRet);
}
return matRet;
}
//--------------------------------------------------
// 根据动画ID设置当前动画
//--------------------------------------------------
void CM2Loader::SetAnimationByID(int channel, int group, int id, int loop /* = 0 */)
{
for(uint32 i=0; i<m_Header.nAnimations; i++)
{
if(m_pAni[i].animID == id)
{
break;
}
}
m_pAniController->SetAni(channel, group, i, loop);
}
//--------------------------------------------------
// 根据动画INDEX设置当前动画
//--------------------------------------------------
void CM2Loader::SetAnimationByIndex(int channel, int group, uint32 index, int loop /* = 0 */)
{
if(index<m_Header.nAnimations)
{
m_pAniController->SetAni(channel, group, index, loop);
}
}
//--------------------------------------------------
// 根据动画INDEX设置当前动画
//--------------------------------------------------
void CM2Loader::SetNextAnimation(void)
{
// m_CurAnimation++;
// if(m_CurAnimation>=m_Header.nAnimations)
// m_CurAnimation = 0;
}
void CM2Loader::PlayAnimation(void)
{
//m_pAniController->Play();
}
bool CM2Loader::IsPause(void)
{
return m_pAniController->IsPause();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -