2009-01-14 04:37:51 -08:00
|
|
|
// Copyright (C) 2002-2009 Nikolaus Gebhardt
|
2007-09-04 11:51:42 -07:00
|
|
|
// This file is part of the "Irrlicht Engine".
|
|
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
|
|
|
|
#include "IrrCompileConfig.h"
|
|
|
|
#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
|
|
|
|
|
|
|
|
#include "CSkinnedMesh.h"
|
|
|
|
#include "CBoneSceneNode.h"
|
|
|
|
#include "IAnimatedMeshSceneNode.h"
|
|
|
|
#include "os.h"
|
|
|
|
|
|
|
|
namespace irr
|
|
|
|
{
|
|
|
|
namespace scene
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
//! constructor
|
|
|
|
CSkinnedMesh::CSkinnedMesh()
|
|
|
|
: SkinningBuffers(0), HasAnimation(0), PreparedForSkinning(0),
|
2008-02-12 07:31:35 -08:00
|
|
|
AnimationFrames(0.f), LastAnimatedFrame(0.f), LastSkinnedFrame(0.f),
|
2007-12-02 12:20:41 -08:00
|
|
|
BoneControlUsed(false), AnimateNormals(true), HardwareSkinning(0), InterpolationMode(EIM_LINEAR)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
|
|
|
setDebugName("CSkinnedMesh");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SkinningBuffers=&LocalBuffers;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! destructor
|
|
|
|
CSkinnedMesh::~CSkinnedMesh()
|
|
|
|
{
|
2007-09-05 05:11:28 -07:00
|
|
|
for (u32 i=0; i<AllJoints.size(); ++i)
|
|
|
|
delete AllJoints[i];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-05 05:11:28 -07:00
|
|
|
for (u32 j=0; j<LocalBuffers.size(); ++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-05 05:11:28 -07:00
|
|
|
if (LocalBuffers[j])
|
|
|
|
LocalBuffers[j]->drop();
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-05 05:11:28 -07:00
|
|
|
//! returns the amount of frames in milliseconds.
|
|
|
|
//! If the amount is 1, it is a static (=non animated) mesh.
|
2007-09-14 15:25:59 -07:00
|
|
|
u32 CSkinnedMesh::getFrameCount() const
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-05 05:11:28 -07:00
|
|
|
return core::floor32(AnimationFrames);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
|
|
|
|
IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
|
|
|
|
{
|
|
|
|
//animate(frame,startFrameLoop, endFrameLoop);
|
|
|
|
if (frame==-1)
|
|
|
|
return this;
|
|
|
|
|
|
|
|
animateMesh((f32)frame, 1.0f);
|
|
|
|
buildAll_LocalAnimatedMatrices();
|
|
|
|
skinMesh();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Keyframe Animation
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
//! Animates this mesh's joints based on frame input
|
|
|
|
//! blend: {0-old position, 1-New position}
|
|
|
|
void CSkinnedMesh::animateMesh(f32 frame, f32 blend)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
if ( !HasAnimation || LastAnimatedFrame==frame)
|
2007-09-04 11:51:42 -07:00
|
|
|
return;
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
LastAnimatedFrame=frame;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-05 05:11:28 -07:00
|
|
|
if (blend<=0.f)
|
2007-09-04 11:51:42 -07:00
|
|
|
return; //No need to animate
|
|
|
|
|
|
|
|
for (u32 i=0; i<AllJoints.size(); ++i)
|
|
|
|
{
|
2007-09-05 05:11:28 -07:00
|
|
|
//To Bitplane: The joints can be animated here with no input from their parents, but for setAnimationMode extra checks are needed to their parents
|
2008-02-12 07:31:35 -08:00
|
|
|
SJoint *joint = AllJoints[i];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
const core::vector3df oldPosition = joint->Animatedposition;
|
|
|
|
const core::vector3df oldScale = joint->Animatedscale;
|
|
|
|
const core::quaternion oldRotation = joint->Animatedrotation;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-05 05:11:28 -07:00
|
|
|
core::vector3df position = oldPosition;
|
|
|
|
core::vector3df scale = oldScale;
|
|
|
|
core::quaternion rotation = oldRotation;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
getFrameData(frame, joint,
|
|
|
|
position, joint->positionHint,
|
|
|
|
scale, joint->scaleHint,
|
|
|
|
rotation, joint->rotationHint);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (blend==1.0f)
|
|
|
|
{
|
2007-09-05 05:11:28 -07:00
|
|
|
//No blending needed
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->Animatedposition = position;
|
|
|
|
joint->Animatedscale = scale;
|
|
|
|
joint->Animatedrotation = rotation;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-05 05:11:28 -07:00
|
|
|
//Blend animation
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->Animatedposition = core::lerp(oldPosition, position, blend);
|
|
|
|
joint->Animatedscale = core::lerp(oldScale, scale, blend);
|
|
|
|
joint->Animatedrotation.slerp(oldRotation, rotation, blend);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2007-09-05 05:11:28 -07:00
|
|
|
//Note:
|
|
|
|
//_LocalAnimatedMatrix needs to be built at some point, but this function may be called lots of times for
|
2007-09-04 11:51:42 -07:00
|
|
|
//one render (to play two animations at the same time) _LocalAnimatedMatrix only needs to be built once.
|
|
|
|
//a call to buildAllLocalAnimatedMatrices is needed before skinning the mesh, and before the user gets the joints to move
|
|
|
|
|
|
|
|
//----------------
|
|
|
|
// Temp!
|
|
|
|
buildAll_LocalAnimatedMatrices();
|
|
|
|
//-----------------
|
|
|
|
}
|
2008-11-21 15:19:52 -08:00
|
|
|
|
|
|
|
updateBoundingBox();
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2007-09-09 15:40:28 -07:00
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
void CSkinnedMesh::buildAll_LocalAnimatedMatrices()
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<AllJoints.size(); ++i)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
SJoint *joint = AllJoints[i];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
//Could be faster:
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
if (joint->UseAnimationFrom &&
|
|
|
|
(joint->UseAnimationFrom->PositionKeys.size() ||
|
|
|
|
joint->UseAnimationFrom->ScaleKeys.size() ||
|
|
|
|
joint->UseAnimationFrom->RotationKeys.size() ))
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->LocalAnimatedMatrix=joint->Animatedrotation.getMatrix();
|
2007-12-01 19:36:11 -08:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
// --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() ---
|
|
|
|
f32 *m1 = joint->LocalAnimatedMatrix.pointer();
|
|
|
|
core::vector3df &Pos = joint->Animatedposition;
|
2007-11-27 06:05:57 -08:00
|
|
|
m1[0] += Pos.X*m1[3];
|
|
|
|
m1[1] += Pos.Y*m1[3];
|
|
|
|
m1[2] += Pos.Z*m1[3];
|
|
|
|
m1[4] += Pos.X*m1[7];
|
|
|
|
m1[5] += Pos.Y*m1[7];
|
|
|
|
m1[6] += Pos.Z*m1[7];
|
|
|
|
m1[8] += Pos.X*m1[11];
|
|
|
|
m1[9] += Pos.Y*m1[11];
|
|
|
|
m1[10] += Pos.Z*m1[11];
|
|
|
|
m1[12] += Pos.X*m1[15];
|
|
|
|
m1[13] += Pos.Y*m1[15];
|
|
|
|
m1[14] += Pos.Z*m1[15];
|
2007-12-01 19:36:11 -08:00
|
|
|
// -----------------------------------
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->GlobalSkinningSpace=false;
|
2007-10-01 21:01:08 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
if (joint->ScaleKeys.size())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-12-01 19:36:11 -08:00
|
|
|
/*
|
2007-09-04 11:51:42 -07:00
|
|
|
core::matrix4 scaleMatrix;
|
2008-02-12 07:31:35 -08:00
|
|
|
scaleMatrix.setScale(joint->Animatedscale);
|
|
|
|
joint->LocalAnimatedMatrix *= scaleMatrix;
|
2007-12-01 19:36:11 -08:00
|
|
|
*/
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
// -------- joint->LocalAnimatedMatrix *= scaleMatrix -----------------
|
2008-11-26 02:44:30 -08:00
|
|
|
core::matrix4& mat = joint->LocalAnimatedMatrix;
|
|
|
|
mat[0] *= joint->Animatedscale.X;
|
|
|
|
mat[1] *= joint->Animatedscale.X;
|
|
|
|
mat[2] *= joint->Animatedscale.X;
|
|
|
|
mat[3] *= joint->Animatedscale.X;
|
|
|
|
mat[4] *= joint->Animatedscale.Y;
|
|
|
|
mat[5] *= joint->Animatedscale.Y;
|
|
|
|
mat[6] *= joint->Animatedscale.Y;
|
|
|
|
mat[7] *= joint->Animatedscale.Y;
|
|
|
|
mat[8] *= joint->Animatedscale.Z;
|
|
|
|
mat[9] *= joint->Animatedscale.Z;
|
|
|
|
mat[10] *= joint->Animatedscale.Z;
|
|
|
|
mat[11] *= joint->Animatedscale.Z;
|
2007-12-01 19:36:11 -08:00
|
|
|
// -----------------------------------
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->LocalAnimatedMatrix=joint->LocalMatrix;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-05 05:11:28 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
void CSkinnedMesh::buildAll_GlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
if (!joint)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
for (u32 i=0; i<RootJoints.size(); ++i)
|
|
|
|
buildAll_GlobalAnimatedMatrices(RootJoints[i], 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Find global matrix...
|
2008-02-12 07:31:35 -08:00
|
|
|
if (!parentJoint || joint->GlobalSkinningSpace)
|
|
|
|
joint->GlobalAnimatedMatrix = joint->LocalAnimatedMatrix;
|
2007-09-04 11:51:42 -07:00
|
|
|
else
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->GlobalAnimatedMatrix = parentJoint->GlobalAnimatedMatrix * joint->LocalAnimatedMatrix;
|
2007-10-01 21:01:08 -07:00
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
for (u32 j=0; j<joint->Children.size(); ++j)
|
|
|
|
buildAll_GlobalAnimatedMatrices(joint->Children[j], joint);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2007-09-09 15:40:28 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
void CSkinnedMesh::getFrameData(f32 frame, SJoint *joint,
|
2007-09-04 11:51:42 -07:00
|
|
|
core::vector3df &position, s32 &positionHint,
|
|
|
|
core::vector3df &scale, s32 &scaleHint,
|
|
|
|
core::quaternion &rotation, s32 &rotationHint)
|
|
|
|
{
|
|
|
|
s32 foundPositionIndex = -1;
|
|
|
|
s32 foundScaleIndex = -1;
|
|
|
|
s32 foundRotationIndex = -1;
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
if (joint->UseAnimationFrom)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
const core::array<SPositionKey> &PositionKeys=joint->UseAnimationFrom->PositionKeys;
|
|
|
|
const core::array<SScaleKey> &ScaleKeys=joint->UseAnimationFrom->ScaleKeys;
|
|
|
|
const core::array<SRotationKey> &RotationKeys=joint->UseAnimationFrom->RotationKeys;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (PositionKeys.size())
|
|
|
|
{
|
|
|
|
foundPositionIndex = -1;
|
|
|
|
|
|
|
|
//Test the Hints...
|
2008-01-03 05:36:54 -08:00
|
|
|
if (positionHint>=0 && (u32)positionHint < PositionKeys.size())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
//check this hint
|
2008-01-03 05:36:54 -08:00
|
|
|
if (positionHint>0 && PositionKeys[positionHint].frame>=frame && PositionKeys[positionHint-1].frame<frame )
|
2007-09-04 11:51:42 -07:00
|
|
|
foundPositionIndex=positionHint;
|
|
|
|
else if (positionHint+1 < (s32)PositionKeys.size())
|
|
|
|
{
|
|
|
|
//check the next index
|
|
|
|
if ( PositionKeys[positionHint+1].frame>=frame &&
|
|
|
|
PositionKeys[positionHint+0].frame<frame)
|
|
|
|
{
|
|
|
|
positionHint++;
|
|
|
|
foundPositionIndex=positionHint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//The hint test failed, do a full scan...
|
|
|
|
if (foundPositionIndex==-1)
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<PositionKeys.size(); ++i)
|
|
|
|
{
|
|
|
|
if (PositionKeys[i].frame >= frame) //Keys should to be sorted by frame
|
|
|
|
{
|
|
|
|
foundPositionIndex=i;
|
|
|
|
positionHint=i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Do interpolation...
|
|
|
|
if (foundPositionIndex!=-1)
|
|
|
|
{
|
|
|
|
if (InterpolationMode==EIM_CONSTANT || foundPositionIndex==0)
|
|
|
|
{
|
|
|
|
position = PositionKeys[foundPositionIndex].position;
|
|
|
|
}
|
|
|
|
else if (InterpolationMode==EIM_LINEAR)
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
const SPositionKey& KeyA = PositionKeys[foundPositionIndex];
|
|
|
|
const SPositionKey& KeyB = PositionKeys[foundPositionIndex-1];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-09 15:40:28 -07:00
|
|
|
const f32 fd1 = frame - KeyA.frame;
|
|
|
|
const f32 fd2 = KeyB.frame - frame;
|
|
|
|
position = ((KeyB.position-KeyA.position)/(fd1+fd2))*fd1 + KeyA.position;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
|
|
|
|
|
|
if (ScaleKeys.size())
|
|
|
|
{
|
|
|
|
foundScaleIndex = -1;
|
|
|
|
|
|
|
|
//Test the Hints...
|
2008-01-03 05:36:54 -08:00
|
|
|
if (scaleHint>=0 && (u32)scaleHint < ScaleKeys.size())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
//check this hint
|
2008-01-03 05:36:54 -08:00
|
|
|
if (scaleHint>0 && ScaleKeys[scaleHint].frame>=frame && ScaleKeys[scaleHint-1].frame<frame )
|
2007-09-04 11:51:42 -07:00
|
|
|
foundScaleIndex=scaleHint;
|
|
|
|
else if (scaleHint+1 < (s32)ScaleKeys.size())
|
|
|
|
{
|
|
|
|
//check the next index
|
|
|
|
if ( ScaleKeys[scaleHint+1].frame>=frame &&
|
|
|
|
ScaleKeys[scaleHint+0].frame<frame)
|
|
|
|
{
|
|
|
|
scaleHint++;
|
|
|
|
foundScaleIndex=scaleHint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//The hint test failed, do a full scan...
|
|
|
|
if (foundScaleIndex==-1)
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<ScaleKeys.size(); ++i)
|
|
|
|
{
|
|
|
|
if (ScaleKeys[i].frame >= frame) //Keys should to be sorted by frame
|
|
|
|
{
|
|
|
|
foundScaleIndex=i;
|
|
|
|
scaleHint=i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Do interpolation...
|
|
|
|
if (foundScaleIndex!=-1)
|
|
|
|
{
|
|
|
|
if (InterpolationMode==EIM_CONSTANT || foundScaleIndex==0)
|
|
|
|
{
|
|
|
|
scale = ScaleKeys[foundScaleIndex].scale;
|
|
|
|
}
|
|
|
|
else if (InterpolationMode==EIM_LINEAR)
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
const SScaleKey& KeyA = ScaleKeys[foundScaleIndex];
|
|
|
|
const SScaleKey& KeyB = ScaleKeys[foundScaleIndex-1];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-09 15:40:28 -07:00
|
|
|
const f32 fd1 = frame - KeyA.frame;
|
|
|
|
const f32 fd2 = KeyB.frame - frame;
|
|
|
|
scale = ((KeyB.scale-KeyA.scale)/(fd1+fd2))*fd1 + KeyA.scale;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
|
|
|
|
|
|
if (RotationKeys.size())
|
|
|
|
{
|
|
|
|
foundRotationIndex = -1;
|
|
|
|
|
|
|
|
//Test the Hints...
|
2008-01-03 05:36:54 -08:00
|
|
|
if (rotationHint>=0 && (u32)rotationHint < RotationKeys.size())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
//check this hint
|
2008-01-03 05:36:54 -08:00
|
|
|
if (rotationHint>0 && RotationKeys[rotationHint].frame>=frame && RotationKeys[rotationHint-1].frame<frame )
|
2007-09-04 11:51:42 -07:00
|
|
|
foundRotationIndex=rotationHint;
|
|
|
|
else if (rotationHint+1 < (s32)RotationKeys.size())
|
|
|
|
{
|
|
|
|
//check the next index
|
|
|
|
if ( RotationKeys[rotationHint+1].frame>=frame &&
|
|
|
|
RotationKeys[rotationHint+0].frame<frame)
|
|
|
|
{
|
|
|
|
rotationHint++;
|
|
|
|
foundRotationIndex=rotationHint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//The hint test failed, do a full scan...
|
|
|
|
if (foundRotationIndex==-1)
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<RotationKeys.size(); ++i)
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
if (RotationKeys[i].frame >= frame) //Keys should be sorted by frame
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
foundRotationIndex=i;
|
|
|
|
rotationHint=i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Do interpolation...
|
|
|
|
if (foundRotationIndex!=-1)
|
|
|
|
{
|
|
|
|
if (InterpolationMode==EIM_CONSTANT || foundRotationIndex==0)
|
|
|
|
{
|
|
|
|
rotation = RotationKeys[foundRotationIndex].rotation;
|
|
|
|
}
|
|
|
|
else if (InterpolationMode==EIM_LINEAR)
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
const SRotationKey& KeyA = RotationKeys[foundRotationIndex];
|
|
|
|
const SRotationKey& KeyB = RotationKeys[foundRotationIndex-1];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-09 15:40:28 -07:00
|
|
|
const f32 fd1 = frame - KeyA.frame;
|
|
|
|
const f32 fd2 = KeyB.frame - frame;
|
|
|
|
const f32 t = fd1/(fd1+fd2);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
f32 t = 0;
|
2007-09-09 15:40:28 -07:00
|
|
|
if (KeyA.frame!=KeyB.frame)
|
|
|
|
t = (frame-KeyA.frame) / (KeyB.frame - KeyA.frame);
|
2007-09-04 11:51:42 -07:00
|
|
|
*/
|
|
|
|
|
2007-09-09 15:40:28 -07:00
|
|
|
rotation.slerp(KeyA.rotation, KeyB.rotation, t);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Software Skinning
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
//! Preforms a software skin on this mesh based of joint positions
|
|
|
|
void CSkinnedMesh::skinMesh()
|
|
|
|
{
|
|
|
|
if ( !HasAnimation)
|
|
|
|
return;
|
|
|
|
|
|
|
|
//----------------
|
2008-11-21 15:19:52 -08:00
|
|
|
// This is marked as "Temp!". A shiny dubloon to whomever can tell me why.
|
2007-09-04 11:51:42 -07:00
|
|
|
buildAll_GlobalAnimatedMatrices();
|
|
|
|
//-----------------
|
|
|
|
|
2007-12-01 19:36:11 -08:00
|
|
|
if (!HardwareSkinning)
|
2007-09-17 04:09:07 -07:00
|
|
|
{
|
2007-12-01 19:36:11 -08:00
|
|
|
//Software skin....
|
|
|
|
u32 i;
|
|
|
|
|
|
|
|
//rigid animation
|
|
|
|
for (i=0; i<AllJoints.size(); ++i)
|
2007-09-17 04:09:07 -07:00
|
|
|
{
|
2007-12-01 19:36:11 -08:00
|
|
|
for (u32 j=0; j<AllJoints[i]->AttachedMeshes.size(); ++j)
|
|
|
|
{
|
|
|
|
SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ];
|
|
|
|
Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix;
|
|
|
|
}
|
2007-09-17 04:09:07 -07:00
|
|
|
}
|
|
|
|
|
2007-12-01 19:36:11 -08:00
|
|
|
//clear skinning helper array
|
|
|
|
for (i=0; i<Vertices_Moved.size(); ++i)
|
|
|
|
for (u32 j=0; j<Vertices_Moved[i].size(); ++j)
|
|
|
|
Vertices_Moved[i][j]=false;
|
2007-09-17 04:09:07 -07:00
|
|
|
|
2007-12-01 19:36:11 -08:00
|
|
|
//skin starting with the root joints
|
|
|
|
for (i=0; i<RootJoints.size(); ++i)
|
|
|
|
SkinJoint(RootJoints[i], 0);
|
2007-12-07 07:25:07 -08:00
|
|
|
|
|
|
|
for (i=0; i<SkinningBuffers->size(); ++i)
|
2008-07-06 22:20:39 -07:00
|
|
|
(*SkinningBuffers)[i]->setDirty(EBT_VERTEX);
|
2007-12-07 07:25:07 -08:00
|
|
|
|
2007-12-01 19:36:11 -08:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2007-12-05 13:10:36 -08:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
void CSkinnedMesh::SkinJoint(SJoint *joint, SJoint *parentJoint)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
if (joint->Weights.size())
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
//Find this joints pull on vertices...
|
2008-02-12 07:31:35 -08:00
|
|
|
core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING);
|
|
|
|
jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
core::vector3df thisVertexMove, thisNormalMove;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
core::array<scene::SSkinMeshBuffer*> &buffersUsed=*SkinningBuffers;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-12 10:47:48 -07:00
|
|
|
//Skin Vertices Positions and Normals...
|
2008-02-12 07:31:35 -08:00
|
|
|
for (u32 i=0; i<joint->Weights.size(); ++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
SWeight& weight = joint->Weights[i];
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// Pull this vertex...
|
2008-02-12 07:31:35 -08:00
|
|
|
jointVertexPull.transformVect(thisVertexMove, weight.StaticPos);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (AnimateNormals)
|
2008-02-12 07:31:35 -08:00
|
|
|
jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-12 10:47:48 -07:00
|
|
|
if (! (*(weight.Moved)) )
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-12 10:47:48 -07:00
|
|
|
*(weight.Moved) = true;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-12 10:47:48 -07:00
|
|
|
if (AnimateNormals)
|
2008-02-12 07:31:35 -08:00
|
|
|
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
//*(weight._Pos) = thisVertexMove * weight.strength;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2007-09-12 10:47:48 -07:00
|
|
|
if (AnimateNormals)
|
2008-02-12 07:31:35 -08:00
|
|
|
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
//*(weight._Pos) += thisVertexMove * weight.strength;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
2008-11-21 15:19:52 -08:00
|
|
|
|
|
|
|
buffersUsed[weight.buffer_id]->boundingBoxNeedsRecalculated();
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Skin all children
|
2008-02-12 07:31:35 -08:00
|
|
|
for (u32 j=0; j<joint->Children.size(); ++j)
|
|
|
|
SkinJoint(joint->Children[j], joint);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
E_ANIMATED_MESH_TYPE CSkinnedMesh::getMeshType() const
|
|
|
|
{
|
|
|
|
return EAMT_SKINNED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Gets joint count.
|
2007-09-17 09:09:50 -07:00
|
|
|
u32 CSkinnedMesh::getJointCount() const
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
return AllJoints.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Gets the name of a joint.
|
2007-09-17 09:09:50 -07:00
|
|
|
const c8* CSkinnedMesh::getJointName(u32 number) const
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-17 09:09:50 -07:00
|
|
|
if (number >= AllJoints.size())
|
2007-09-04 11:51:42 -07:00
|
|
|
return 0;
|
|
|
|
return AllJoints[number]->Name.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Gets a joint number from its name
|
|
|
|
s32 CSkinnedMesh::getJointNumber(const c8* name) const
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
for (u32 i=0; i<AllJoints.size(); ++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
if (AllJoints[i]->Name == name)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! returns amount of mesh buffers.
|
|
|
|
u32 CSkinnedMesh::getMeshBufferCount() const
|
|
|
|
{
|
|
|
|
return LocalBuffers.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! returns pointer to a mesh buffer
|
|
|
|
IMeshBuffer* CSkinnedMesh::getMeshBuffer(u32 nr) const
|
|
|
|
{
|
|
|
|
if (nr < LocalBuffers.size())
|
|
|
|
return LocalBuffers[nr];
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Returns pointer to a mesh buffer which fits a material
|
|
|
|
IMeshBuffer* CSkinnedMesh::getMeshBuffer(const video::SMaterial &material) const
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<LocalBuffers.size(); ++i)
|
|
|
|
{
|
|
|
|
if (LocalBuffers[i]->getMaterial() == material)
|
|
|
|
return LocalBuffers[i];
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! returns an axis aligned bounding box
|
|
|
|
const core::aabbox3d<f32>& CSkinnedMesh::getBoundingBox() const
|
|
|
|
{
|
|
|
|
return BoundingBox;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! set user axis aligned bounding box
|
|
|
|
void CSkinnedMesh::setBoundingBox( const core::aabbox3df& box)
|
|
|
|
{
|
|
|
|
BoundingBox = box;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! sets a flag of all contained materials to a new value
|
|
|
|
void CSkinnedMesh::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<LocalBuffers.size(); ++i)
|
|
|
|
LocalBuffers[i]->Material.setFlag(flag,newvalue);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-14 02:30:34 -08:00
|
|
|
//! set the hardware mapping hint, for driver
|
|
|
|
void CSkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,
|
|
|
|
E_BUFFER_TYPE buffer)
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<LocalBuffers.size(); ++i)
|
|
|
|
LocalBuffers[i]->setHardwareMappingHint(newMappingHint, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! flags the meshbuffer as changed, reloads hardware buffers
|
|
|
|
void CSkinnedMesh::setDirty(E_BUFFER_TYPE buffer)
|
|
|
|
{
|
|
|
|
for (u32 i=0; i<LocalBuffers.size(); ++i)
|
|
|
|
LocalBuffers[i]->setDirty(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
//! uses animation from another mesh
|
2007-09-17 09:09:50 -07:00
|
|
|
bool CSkinnedMesh::useAnimationFrom(const ISkinnedMesh *mesh)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
bool unmatched=false;
|
|
|
|
|
|
|
|
for(u32 i=0;i<AllJoints.size();++i)
|
|
|
|
{
|
|
|
|
SJoint *joint=AllJoints[i];
|
|
|
|
joint->UseAnimationFrom=0;
|
|
|
|
|
|
|
|
if (joint->Name=="")
|
|
|
|
unmatched=true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(u32 j=0;j<mesh->getAllJoints().size();++j)
|
|
|
|
{
|
|
|
|
SJoint *otherJoint=mesh->getAllJoints()[j];
|
|
|
|
if (joint->Name==otherJoint->Name)
|
|
|
|
{
|
|
|
|
joint->UseAnimationFrom=otherJoint;
|
|
|
|
}
|
|
|
|
}
|
2008-02-12 07:31:35 -08:00
|
|
|
if (!joint->UseAnimationFrom)
|
|
|
|
unmatched=true;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
checkForAnimation();
|
|
|
|
|
|
|
|
return !unmatched;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//!Update Normals when Animating
|
2007-12-02 12:20:41 -08:00
|
|
|
//!False= Don't animate them, faster
|
|
|
|
//!True= Update normals (default)
|
2007-09-04 11:51:42 -07:00
|
|
|
void CSkinnedMesh::updateNormalsWhenAnimating(bool on)
|
|
|
|
{
|
|
|
|
AnimateNormals = on;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//!Sets Interpolation Mode
|
|
|
|
void CSkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode)
|
|
|
|
{
|
|
|
|
InterpolationMode = mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
core::array<scene::SSkinMeshBuffer*> &CSkinnedMesh::getMeshBuffers()
|
|
|
|
{
|
|
|
|
return LocalBuffers;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
core::array<CSkinnedMesh::SJoint*> &CSkinnedMesh::getAllJoints()
|
|
|
|
{
|
|
|
|
return AllJoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-17 09:09:50 -07:00
|
|
|
const core::array<CSkinnedMesh::SJoint*> &CSkinnedMesh::getAllJoints() const
|
|
|
|
{
|
|
|
|
return AllJoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-12-01 19:36:11 -08:00
|
|
|
//! (This feature is not implementated in irrlicht yet)
|
|
|
|
bool CSkinnedMesh::setHardwareSkinning(bool on)
|
|
|
|
{
|
|
|
|
if (HardwareSkinning!=on)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (on)
|
|
|
|
{
|
|
|
|
|
|
|
|
//set mesh to static pose...
|
|
|
|
for (u32 i=0; i<AllJoints.size(); ++i)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
SJoint *joint=AllJoints[i];
|
|
|
|
for (u32 j=0; j<joint->Weights.size(); ++j)
|
2007-12-01 19:36:11 -08:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
const u16 buffer_id=joint->Weights[j].buffer_id;
|
|
|
|
const u32 vertex_id=joint->Weights[j].vertex_id;
|
|
|
|
LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos;
|
|
|
|
LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal;
|
2008-11-21 15:19:52 -08:00
|
|
|
LocalBuffers[buffer_id]->boundingBoxNeedsRecalculated();
|
2007-12-01 19:36:11 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
HardwareSkinning=on;
|
|
|
|
}
|
2007-12-06 08:26:14 -08:00
|
|
|
return HardwareSkinning;
|
2007-12-01 19:36:11 -08:00
|
|
|
}
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
|
|
|
|
void CSkinnedMesh::CalculateGlobalMatrices(SJoint *joint,SJoint *parentJoint)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
if (!joint && parentJoint) // bit of protection from endless loops
|
2007-09-04 11:51:42 -07:00
|
|
|
return;
|
|
|
|
|
2007-09-09 15:40:28 -07:00
|
|
|
//Go through the root bones
|
2008-02-12 07:31:35 -08:00
|
|
|
if (!joint)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
for (u32 i=0; i<RootJoints.size(); ++i)
|
2008-02-12 07:31:35 -08:00
|
|
|
CalculateGlobalMatrices(RootJoints[i],0);
|
2007-09-04 11:51:42 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
if (!parentJoint)
|
|
|
|
joint->GlobalMatrix = joint->LocalMatrix;
|
2007-09-04 11:51:42 -07:00
|
|
|
else
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->GlobalMatrix = parentJoint->GlobalMatrix * joint->LocalMatrix;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->LocalAnimatedMatrix=joint->LocalMatrix;
|
|
|
|
joint->GlobalAnimatedMatrix=joint->GlobalMatrix;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
if (joint->GlobalInversedMatrix.isIdentity())//might be pre calculated
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->GlobalInversedMatrix = joint->GlobalMatrix;
|
|
|
|
joint->GlobalInversedMatrix.makeInverse(); // slow
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
for (u32 j=0; j<joint->Children.size(); ++j)
|
|
|
|
CalculateGlobalMatrices(joint->Children[j],joint);
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CSkinnedMesh::checkForAnimation()
|
|
|
|
{
|
|
|
|
u32 i,j;
|
|
|
|
//Check for animation...
|
|
|
|
HasAnimation = false;
|
|
|
|
for(i=0;i<AllJoints.size();++i)
|
|
|
|
{
|
|
|
|
if (AllJoints[i]->UseAnimationFrom)
|
|
|
|
{
|
|
|
|
if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() ||
|
|
|
|
AllJoints[i]->UseAnimationFrom->ScaleKeys.size() ||
|
|
|
|
AllJoints[i]->UseAnimationFrom->RotationKeys.size() )
|
|
|
|
{
|
|
|
|
HasAnimation = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-08 21:53:25 -07:00
|
|
|
//meshes with weights, are still counted as animated for ragdolls, etc
|
|
|
|
if (!HasAnimation)
|
|
|
|
{
|
|
|
|
for(i=0;i<AllJoints.size();++i)
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
if (AllJoints[i]->Weights.size())
|
|
|
|
HasAnimation = true;
|
2007-09-08 21:53:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
if (HasAnimation)
|
|
|
|
{
|
|
|
|
//--- Find the length of the animation ---
|
|
|
|
AnimationFrames=0;
|
|
|
|
for(i=0;i<AllJoints.size();++i)
|
|
|
|
{
|
|
|
|
if (AllJoints[i]->UseAnimationFrom)
|
|
|
|
{
|
|
|
|
if (AllJoints[i]->UseAnimationFrom->PositionKeys.size())
|
|
|
|
if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > AnimationFrames)
|
|
|
|
AnimationFrames=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame;
|
|
|
|
|
|
|
|
if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size())
|
|
|
|
if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > AnimationFrames)
|
|
|
|
AnimationFrames=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame;
|
|
|
|
|
|
|
|
if (AllJoints[i]->UseAnimationFrom->RotationKeys.size())
|
|
|
|
if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > AnimationFrames)
|
|
|
|
AnimationFrames=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HasAnimation && !PreparedForSkinning)
|
|
|
|
{
|
|
|
|
PreparedForSkinning=true;
|
|
|
|
|
|
|
|
//check for bugs:
|
|
|
|
for(i=0; i < AllJoints.size(); ++i)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
SJoint *joint = AllJoints[i];
|
|
|
|
for (j=0; j<joint->Weights.size(); ++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
const u16 buffer_id=joint->Weights[j].buffer_id;
|
|
|
|
const u32 vertex_id=joint->Weights[j].vertex_id;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
//check for invalid ids
|
|
|
|
if (buffer_id>=LocalBuffers.size())
|
|
|
|
{
|
2007-09-05 01:59:46 -07:00
|
|
|
os::Printer::log("Skinned Mesh: Weight buffer id too large", ELL_WARNING);
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else if (vertex_id>=LocalBuffers[buffer_id]->getVertexCount())
|
|
|
|
{
|
2007-09-05 01:59:46 -07:00
|
|
|
os::Printer::log("Skinned Mesh: Weight vertex id too large", ELL_WARNING);
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//An array used in skinning
|
|
|
|
|
|
|
|
for (i=0; i<Vertices_Moved.size(); ++i)
|
|
|
|
for (j=0; j<Vertices_Moved[i].size(); ++j)
|
|
|
|
Vertices_Moved[i][j] = false;
|
|
|
|
|
|
|
|
// For skinning: cache weight values for speed
|
|
|
|
|
|
|
|
for (i=0; i<AllJoints.size(); ++i)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
SJoint *joint = AllJoints[i];
|
|
|
|
for (j=0; j<joint->Weights.size(); ++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
const u16 buffer_id=joint->Weights[j].buffer_id;
|
|
|
|
const u32 vertex_id=joint->Weights[j].vertex_id;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->Weights[j].Moved = &Vertices_Moved[buffer_id] [vertex_id];
|
|
|
|
joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos;
|
|
|
|
joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
//joint->Weights[j]._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// normalize weights
|
|
|
|
normalizeWeights();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! called by loader after populating with mesh and bone data
|
|
|
|
void CSkinnedMesh::finalize()
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
u32 i;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
LastAnimatedFrame=-1;
|
|
|
|
LastSkinnedFrame=-1;
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
//calculate bounding box
|
|
|
|
for (i=0; i<LocalBuffers.size(); ++i)
|
|
|
|
{
|
|
|
|
LocalBuffers[i]->recalculateBoundingBox();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (AllJoints.size() || RootJoints.size())
|
|
|
|
{
|
|
|
|
// populate AllJoints or RootJoints, depending on which is empty
|
|
|
|
if (!RootJoints.size())
|
|
|
|
{
|
|
|
|
|
|
|
|
for(u32 CheckingIdx=0; CheckingIdx < AllJoints.size(); ++CheckingIdx)
|
|
|
|
{
|
|
|
|
|
|
|
|
bool foundParent=false;
|
|
|
|
for(i=0; i < AllJoints.size(); ++i)
|
|
|
|
{
|
|
|
|
for(u32 n=0; n < AllJoints[i]->Children.size(); ++n)
|
|
|
|
{
|
|
|
|
if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx])
|
|
|
|
foundParent=true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foundParent)
|
|
|
|
RootJoints.push_back(AllJoints[CheckingIdx]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
AllJoints=RootJoints;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i=0; i < AllJoints.size(); ++i)
|
|
|
|
{
|
|
|
|
AllJoints[i]->UseAnimationFrom=AllJoints[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
//Set array sizes...
|
|
|
|
|
|
|
|
for (i=0; i<LocalBuffers.size(); ++i)
|
|
|
|
{
|
|
|
|
Vertices_Moved.push_back( core::array<bool>() );
|
|
|
|
Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount());
|
|
|
|
}
|
|
|
|
|
|
|
|
//Todo: optimise keys here...
|
|
|
|
|
|
|
|
checkForAnimation();
|
|
|
|
|
|
|
|
if (HasAnimation)
|
|
|
|
{
|
|
|
|
//--- optimize and check keyframes ---
|
|
|
|
for(i=0;i<AllJoints.size();++i)
|
|
|
|
{
|
|
|
|
core::array<SPositionKey> &PositionKeys =AllJoints[i]->PositionKeys;
|
|
|
|
core::array<SScaleKey> &ScaleKeys = AllJoints[i]->ScaleKeys;
|
|
|
|
core::array<SRotationKey> &RotationKeys = AllJoints[i]->RotationKeys;
|
|
|
|
|
|
|
|
if (PositionKeys.size()>2)
|
2007-09-05 05:11:28 -07:00
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
for(u32 j=0;j<PositionKeys.size()-2;++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
if (PositionKeys[j].position == PositionKeys[j+1].position && PositionKeys[j+1].position == PositionKeys[j+2].position)
|
|
|
|
{
|
|
|
|
PositionKeys.erase(j+1); //the middle key is unneeded
|
2007-09-05 05:11:28 -07:00
|
|
|
--j;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
2007-09-05 05:11:28 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (PositionKeys.size()>1)
|
2007-09-05 05:11:28 -07:00
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
for(u32 j=0;j<PositionKeys.size()-1;++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
if (PositionKeys[j].frame >= PositionKeys[j+1].frame) //bad frame, unneed and may cause problems
|
|
|
|
{
|
|
|
|
PositionKeys.erase(j+1);
|
2007-09-05 05:11:28 -07:00
|
|
|
--j;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
2007-09-05 05:11:28 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (ScaleKeys.size()>2)
|
2007-09-05 05:11:28 -07:00
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
for(u32 j=0;j<ScaleKeys.size()-2;++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
if (ScaleKeys[j].scale == ScaleKeys[j+1].scale && ScaleKeys[j+1].scale == ScaleKeys[j+2].scale)
|
|
|
|
{
|
|
|
|
ScaleKeys.erase(j+1); //the middle key is unneeded
|
2007-09-05 05:11:28 -07:00
|
|
|
--j;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
2007-09-05 05:11:28 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (ScaleKeys.size()>1)
|
2007-09-05 05:11:28 -07:00
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
for(u32 j=0;j<ScaleKeys.size()-1;++j)
|
2007-09-05 05:11:28 -07:00
|
|
|
{
|
|
|
|
if (ScaleKeys[j].frame >= ScaleKeys[j+1].frame) //bad frame, unneed and may cause problems
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2007-09-05 05:11:28 -07:00
|
|
|
ScaleKeys.erase(j+1);
|
|
|
|
--j;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
2007-09-05 05:11:28 -07:00
|
|
|
}
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (RotationKeys.size()>2)
|
2007-09-05 05:11:28 -07:00
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
for(u32 j=0;j<RotationKeys.size()-2;++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
if (RotationKeys[j].rotation == RotationKeys[j+1].rotation && RotationKeys[j+1].rotation == RotationKeys[j+2].rotation)
|
|
|
|
{
|
|
|
|
RotationKeys.erase(j+1); //the middle key is unneeded
|
2007-09-05 05:11:28 -07:00
|
|
|
--j;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
2007-09-05 05:11:28 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
if (RotationKeys.size()>1)
|
2007-09-05 05:11:28 -07:00
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
for(u32 j=0;j<RotationKeys.size()-1;++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
if (RotationKeys[j].frame >= RotationKeys[j+1].frame) //bad frame, unneed and may cause problems
|
|
|
|
{
|
|
|
|
RotationKeys.erase(j+1);
|
2007-09-05 05:11:28 -07:00
|
|
|
--j;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
2007-09-05 05:11:28 -07:00
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
|
|
|
|
//Fill empty keyframe areas
|
|
|
|
if (PositionKeys.size())
|
|
|
|
{
|
|
|
|
SPositionKey *Key;
|
|
|
|
Key=&PositionKeys[0];//getFirst
|
|
|
|
if (Key->frame!=0)
|
|
|
|
{
|
|
|
|
PositionKeys.push_front(*Key);
|
|
|
|
Key=&PositionKeys[0];//getFirst
|
|
|
|
Key->frame=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Key=&PositionKeys.getLast();
|
|
|
|
if (Key->frame!=AnimationFrames)
|
|
|
|
{
|
|
|
|
PositionKeys.push_back(*Key);
|
|
|
|
Key=&PositionKeys.getLast();
|
|
|
|
Key->frame=AnimationFrames;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ScaleKeys.size())
|
|
|
|
{
|
|
|
|
SScaleKey *Key;
|
|
|
|
Key=&ScaleKeys[0];//getFirst
|
|
|
|
if (Key->frame!=0)
|
|
|
|
{
|
|
|
|
ScaleKeys.push_front(*Key);
|
|
|
|
Key=&ScaleKeys[0];//getFirst
|
|
|
|
Key->frame=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Key=&ScaleKeys.getLast();
|
|
|
|
if (Key->frame!=AnimationFrames)
|
|
|
|
{
|
|
|
|
ScaleKeys.push_back(*Key);
|
|
|
|
Key=&ScaleKeys.getLast();
|
|
|
|
Key->frame=AnimationFrames;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RotationKeys.size())
|
|
|
|
{
|
|
|
|
SRotationKey *Key;
|
|
|
|
Key=&RotationKeys[0];//getFirst
|
|
|
|
if (Key->frame!=0)
|
|
|
|
{
|
|
|
|
RotationKeys.push_front(*Key);
|
|
|
|
Key=&RotationKeys[0];//getFirst
|
|
|
|
Key->frame=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Key=&RotationKeys.getLast();
|
|
|
|
if (Key->frame!=AnimationFrames)
|
|
|
|
{
|
|
|
|
RotationKeys.push_back(*Key);
|
|
|
|
Key=&RotationKeys.getLast();
|
|
|
|
Key->frame=AnimationFrames;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Needed for animation and skinning...
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
CalculateGlobalMatrices(0,0);
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
//animateMesh(0, 1);
|
|
|
|
//buildAll_LocalAnimatedMatrices();
|
|
|
|
//buildAll_GlobalAnimatedMatrices();
|
2007-09-17 04:09:07 -07:00
|
|
|
|
|
|
|
//rigid animation for non animated meshes
|
|
|
|
for (i=0; i<AllJoints.size(); ++i)
|
|
|
|
{
|
|
|
|
for (u32 j=0; j<AllJoints[i]->AttachedMeshes.size(); ++j)
|
|
|
|
{
|
|
|
|
SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ];
|
|
|
|
Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix;
|
|
|
|
}
|
|
|
|
}
|
2008-09-30 07:41:22 -07:00
|
|
|
|
|
|
|
//calculate bounding box
|
|
|
|
if (LocalBuffers.empty())
|
|
|
|
BoundingBox.reset(0,0,0);
|
|
|
|
else
|
|
|
|
{
|
2008-10-01 14:07:45 -07:00
|
|
|
irr::core::aabbox3df bb(LocalBuffers[0]->BoundingBox);
|
|
|
|
LocalBuffers[0]->Transformation.transformBoxEx(bb);
|
|
|
|
BoundingBox.reset(bb);
|
|
|
|
|
|
|
|
for (u32 j=1; j<LocalBuffers.size(); ++j)
|
2008-09-30 07:41:22 -07:00
|
|
|
{
|
2008-10-01 14:07:45 -07:00
|
|
|
bb = LocalBuffers[j]->BoundingBox;
|
|
|
|
LocalBuffers[j]->Transformation.transformBoxEx(bb);
|
|
|
|
|
|
|
|
BoundingBox.addInternalBox(bb);
|
2008-09-30 07:41:22 -07:00
|
|
|
}
|
|
|
|
}
|
2008-11-21 15:19:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CSkinnedMesh::updateBoundingBox(void)
|
|
|
|
{
|
|
|
|
if(!SkinningBuffers)
|
|
|
|
return;
|
2008-09-30 07:41:22 -07:00
|
|
|
|
2008-11-21 15:19:52 -08:00
|
|
|
core::array<SSkinMeshBuffer*> & buffer = *SkinningBuffers;
|
|
|
|
BoundingBox.reset(0,0,0);
|
|
|
|
|
|
|
|
if (!buffer.empty())
|
|
|
|
{
|
|
|
|
for (u32 j=0; j<buffer.size(); ++j)
|
|
|
|
{
|
|
|
|
buffer[j]->recalculateBoundingBox();
|
|
|
|
core::aabbox3df bb = buffer[j]->BoundingBox;
|
|
|
|
buffer[j]->Transformation.transformBoxEx(bb);
|
|
|
|
|
|
|
|
BoundingBox.addInternalBox(bb);
|
|
|
|
}
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
scene::SSkinMeshBuffer *CSkinnedMesh::createBuffer()
|
|
|
|
{
|
|
|
|
scene::SSkinMeshBuffer *buffer=new scene::SSkinMeshBuffer();
|
|
|
|
LocalBuffers.push_back(buffer);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CSkinnedMesh::SJoint *CSkinnedMesh::createJoint(SJoint *parent)
|
|
|
|
{
|
|
|
|
SJoint *joint=new SJoint;
|
|
|
|
|
|
|
|
AllJoints.push_back(joint);
|
|
|
|
if (!parent)
|
|
|
|
{
|
|
|
|
//Add root joints to array in finalize()
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-09-09 15:40:28 -07:00
|
|
|
//Set parent (Be careful of the mesh loader also setting the parent)
|
2007-09-04 11:51:42 -07:00
|
|
|
parent->Children.push_back(joint);
|
|
|
|
}
|
|
|
|
|
|
|
|
return joint;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CSkinnedMesh::SPositionKey *CSkinnedMesh::createPositionKey(SJoint *joint)
|
|
|
|
{
|
|
|
|
if (!joint)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
joint->PositionKeys.push_back(SPositionKey());
|
2008-02-12 07:31:35 -08:00
|
|
|
return &joint->PositionKeys.getLast();
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CSkinnedMesh::SScaleKey *CSkinnedMesh::createScaleKey(SJoint *joint)
|
|
|
|
{
|
|
|
|
if (!joint)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
joint->ScaleKeys.push_back(SScaleKey());
|
2008-02-12 07:31:35 -08:00
|
|
|
return &joint->ScaleKeys.getLast();
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CSkinnedMesh::SRotationKey *CSkinnedMesh::createRotationKey(SJoint *joint)
|
|
|
|
{
|
|
|
|
if (!joint)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
joint->RotationKeys.push_back(SRotationKey());
|
2008-02-12 07:31:35 -08:00
|
|
|
return &joint->RotationKeys.getLast();
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CSkinnedMesh::SWeight *CSkinnedMesh::createWeight(SJoint *joint)
|
|
|
|
{
|
|
|
|
if (!joint)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
joint->Weights.push_back(SWeight());
|
2008-02-12 07:31:35 -08:00
|
|
|
return &joint->Weights.getLast();
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-13 23:35:40 -08:00
|
|
|
bool CSkinnedMesh::isStatic()
|
|
|
|
{
|
|
|
|
return !HasAnimation;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
void CSkinnedMesh::normalizeWeights()
|
|
|
|
{
|
2007-09-05 05:11:28 -07:00
|
|
|
// note: unsure if weights ids are going to be used.
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
// Normalise the weights on bones....
|
|
|
|
|
|
|
|
u32 i,j;
|
|
|
|
core::array< core::array<f32> > Vertices_TotalWeight;
|
|
|
|
|
|
|
|
for (i=0; i<LocalBuffers.size(); ++i)
|
|
|
|
{
|
|
|
|
Vertices_TotalWeight.push_back(core::array<f32>());
|
|
|
|
Vertices_TotalWeight[i].set_used(LocalBuffers[i]->getVertexCount());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<Vertices_TotalWeight.size(); ++i)
|
|
|
|
for (j=0; j<Vertices_TotalWeight[i].size(); ++j)
|
|
|
|
Vertices_TotalWeight[i][j] = 0;
|
|
|
|
|
|
|
|
for (i=0; i<AllJoints.size(); ++i)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
SJoint *joint=AllJoints[i];
|
|
|
|
for (j=0; j<joint->Weights.size(); ++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
if (joint->Weights[j].strength<=0)//Check for invalid weights
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->Weights.erase(j);
|
|
|
|
--j;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
Vertices_TotalWeight[ joint->Weights[j].buffer_id ] [ joint->Weights[j].vertex_id ] += joint->Weights[j].strength;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<AllJoints.size(); ++i)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
SJoint *joint=AllJoints[i];
|
|
|
|
for (j=0; j< joint->Weights.size(); ++j)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
const f32 total = Vertices_TotalWeight[ joint->Weights[j].buffer_id ] [ joint->Weights[j].vertex_id ];
|
2007-09-04 11:51:42 -07:00
|
|
|
if (total != 0 && total != 1)
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->Weights[j].strength /= total;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CSkinnedMesh::recoverJointsFromMesh(core::array<IBoneSceneNode*> &JointChildSceneNodes)
|
|
|
|
{
|
|
|
|
for (u32 i=0;i<AllJoints.size();++i)
|
|
|
|
{
|
|
|
|
IBoneSceneNode* node=JointChildSceneNodes[i];
|
|
|
|
SJoint *joint=AllJoints[i];
|
|
|
|
node->setPosition( joint->LocalAnimatedMatrix.getTranslation() );
|
|
|
|
node->setRotation( joint->LocalAnimatedMatrix.getRotationDegrees() );
|
|
|
|
|
|
|
|
//node->setScale( joint->LocalAnimatedMatrix.getScale() );
|
|
|
|
|
|
|
|
node->positionHint=joint->positionHint;
|
|
|
|
node->scaleHint=joint->scaleHint;
|
|
|
|
node->rotationHint=joint->rotationHint;
|
|
|
|
|
|
|
|
//node->setAbsoluteTransformation(joint->GlobalMatrix); //not going to work
|
|
|
|
|
|
|
|
//Note: This updateAbsolutePosition will not work well if joints are not nested like b3d
|
|
|
|
//node->updateAbsolutePosition();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
|
2007-09-17 09:09:50 -07:00
|
|
|
void CSkinnedMesh::transferJointsToMesh(const core::array<IBoneSceneNode*> &JointChildSceneNodes)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
for (u32 i=0; i<AllJoints.size(); ++i)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
const IBoneSceneNode* const node=JointChildSceneNodes[i];
|
2007-09-04 11:51:42 -07:00
|
|
|
SJoint *joint=AllJoints[i];
|
2007-10-01 21:01:08 -07:00
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
joint->LocalAnimatedMatrix.setTranslation(node->getPosition());
|
|
|
|
joint->LocalAnimatedMatrix.setRotationDegrees(node->getRotation());
|
2007-10-01 21:01:08 -07:00
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
//joint->LocalAnimatedMatrix.setScale( node->getScale() );
|
|
|
|
|
|
|
|
joint->positionHint=node->positionHint;
|
|
|
|
joint->scaleHint=node->scaleHint;
|
|
|
|
joint->rotationHint=node->rotationHint;
|
2007-10-01 21:01:08 -07:00
|
|
|
|
|
|
|
if (node->getSkinningSpace()==EBSS_GLOBAL)
|
|
|
|
joint->GlobalSkinningSpace=true;
|
|
|
|
else
|
|
|
|
joint->GlobalSkinningSpace=false;
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
//Remove cache, temp...
|
2008-02-12 07:31:35 -08:00
|
|
|
LastAnimatedFrame=-1;
|
|
|
|
LastSkinnedFrame=-1;
|
2007-11-27 06:05:57 -08:00
|
|
|
}
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
|
2007-11-27 06:05:57 -08:00
|
|
|
void CSkinnedMesh::transferOnlyJointsHintsToMesh(const core::array<IBoneSceneNode*> &JointChildSceneNodes)
|
|
|
|
{
|
|
|
|
for (u32 i=0;i<AllJoints.size();++i)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
const IBoneSceneNode* const node=JointChildSceneNodes[i];
|
2007-11-27 06:05:57 -08:00
|
|
|
SJoint *joint=AllJoints[i];
|
|
|
|
|
|
|
|
joint->positionHint=node->positionHint;
|
|
|
|
joint->scaleHint=node->scaleHint;
|
|
|
|
joint->rotationHint=node->rotationHint;
|
|
|
|
}
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
2007-09-05 05:11:28 -07:00
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
void CSkinnedMesh::createJoints(core::array<IBoneSceneNode*> &JointChildSceneNodes,
|
2008-02-12 07:31:35 -08:00
|
|
|
IAnimatedMeshSceneNode* AnimatedMeshSceneNode,
|
|
|
|
ISceneManager* SceneManager)
|
2007-09-04 11:51:42 -07:00
|
|
|
{
|
|
|
|
u32 i;
|
|
|
|
|
|
|
|
//Create new joints
|
|
|
|
for (i=0;i<AllJoints.size();++i)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
JointChildSceneNodes.push_back(new CBoneSceneNode(0, SceneManager, 0, i, AllJoints[i]->Name.c_str()));
|
2007-09-04 11:51:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//Match up parents
|
|
|
|
for (i=0;i<JointChildSceneNodes.size();++i)
|
|
|
|
{
|
|
|
|
IBoneSceneNode* node=JointChildSceneNodes[i];
|
2008-02-12 07:31:35 -08:00
|
|
|
const SJoint* const joint=AllJoints[i]; //should be fine
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
s32 parentID=-1;
|
|
|
|
|
|
|
|
for (u32 j=0;j<AllJoints.size();++j)
|
|
|
|
{
|
|
|
|
if (i!=j && parentID==-1)
|
|
|
|
{
|
2008-02-12 07:31:35 -08:00
|
|
|
const SJoint* const parentTest=AllJoints[j];
|
2007-09-04 11:51:42 -07:00
|
|
|
for (u32 n=0;n<parentTest->Children.size();++n)
|
|
|
|
{
|
|
|
|
if (parentTest->Children[n]==joint)
|
|
|
|
{
|
|
|
|
parentID=j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parentID!=-1)
|
|
|
|
node->setParent( JointChildSceneNodes[parentID] );
|
|
|
|
else
|
|
|
|
node->setParent( AnimatedMeshSceneNode );
|
|
|
|
|
|
|
|
node->drop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-09 15:40:28 -07:00
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
void CSkinnedMesh::convertMeshToTangents()
|
|
|
|
{
|
|
|
|
// now calculate tangents
|
|
|
|
for (u32 b=0; b < LocalBuffers.size(); ++b)
|
|
|
|
{
|
|
|
|
if (LocalBuffers[b])
|
|
|
|
{
|
|
|
|
LocalBuffers[b]->MoveTo_Tangents();
|
|
|
|
|
2008-02-12 07:31:35 -08:00
|
|
|
const s32 idxCnt = LocalBuffers[b]->getIndexCount();
|
2007-09-04 11:51:42 -07:00
|
|
|
|
|
|
|
u16* idx = LocalBuffers[b]->getIndices();
|
|
|
|
video::S3DVertexTangents* v =
|
|
|
|
(video::S3DVertexTangents*)LocalBuffers[b]->getVertices();
|
|
|
|
|
|
|
|
for (s32 i=0; i<idxCnt; i+=3)
|
|
|
|
{
|
|
|
|
calculateTangents(
|
|
|
|
v[idx[i+0]].Normal,
|
|
|
|
v[idx[i+0]].Tangent,
|
|
|
|
v[idx[i+0]].Binormal,
|
|
|
|
v[idx[i+0]].Pos,
|
|
|
|
v[idx[i+1]].Pos,
|
|
|
|
v[idx[i+2]].Pos,
|
|
|
|
v[idx[i+0]].TCoords,
|
|
|
|
v[idx[i+1]].TCoords,
|
|
|
|
v[idx[i+2]].TCoords);
|
|
|
|
|
|
|
|
calculateTangents(
|
|
|
|
v[idx[i+1]].Normal,
|
|
|
|
v[idx[i+1]].Tangent,
|
|
|
|
v[idx[i+1]].Binormal,
|
|
|
|
v[idx[i+1]].Pos,
|
|
|
|
v[idx[i+2]].Pos,
|
|
|
|
v[idx[i+0]].Pos,
|
|
|
|
v[idx[i+1]].TCoords,
|
|
|
|
v[idx[i+2]].TCoords,
|
|
|
|
v[idx[i+0]].TCoords);
|
|
|
|
|
|
|
|
calculateTangents(
|
|
|
|
v[idx[i+2]].Normal,
|
|
|
|
v[idx[i+2]].Tangent,
|
|
|
|
v[idx[i+2]].Binormal,
|
|
|
|
v[idx[i+2]].Pos,
|
|
|
|
v[idx[i+0]].Pos,
|
|
|
|
v[idx[i+1]].Pos,
|
|
|
|
v[idx[i+2]].TCoords,
|
|
|
|
v[idx[i+0]].TCoords,
|
|
|
|
v[idx[i+1]].TCoords);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CSkinnedMesh::calculateTangents(
|
|
|
|
core::vector3df& normal,
|
|
|
|
core::vector3df& tangent,
|
|
|
|
core::vector3df& binormal,
|
|
|
|
core::vector3df& vt1, core::vector3df& vt2, core::vector3df& vt3, // vertices
|
|
|
|
core::vector2df& tc1, core::vector2df& tc2, core::vector2df& tc3) // texture coords
|
|
|
|
{
|
|
|
|
core::vector3df v1 = vt1 - vt2;
|
|
|
|
core::vector3df v2 = vt3 - vt1;
|
|
|
|
normal = v2.crossProduct(v1);
|
|
|
|
normal.normalize();
|
|
|
|
|
|
|
|
// binormal
|
|
|
|
|
|
|
|
f32 deltaX1 = tc1.X - tc2.X;
|
|
|
|
f32 deltaX2 = tc3.X - tc1.X;
|
|
|
|
binormal = (v1 * deltaX2) - (v2 * deltaX1);
|
|
|
|
binormal.normalize();
|
|
|
|
|
|
|
|
// tangent
|
|
|
|
|
|
|
|
f32 deltaY1 = tc1.Y - tc2.Y;
|
|
|
|
f32 deltaY2 = tc3.Y - tc1.Y;
|
|
|
|
tangent = (v1 * deltaY2) - (v2 * deltaY1);
|
|
|
|
tangent.normalize();
|
|
|
|
|
|
|
|
// adjust
|
|
|
|
|
|
|
|
core::vector3df txb = tangent.crossProduct(binormal);
|
|
|
|
if (txb.dotProduct(normal) < 0.0f)
|
|
|
|
{
|
|
|
|
tangent *= -1.0f;
|
|
|
|
binormal *= -1.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-13 23:35:40 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-09-04 11:51:42 -07:00
|
|
|
} // end namespace scene
|
|
|
|
} // end namespace irr
|
|
|
|
|
|
|
|
#endif // _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
|
|
|
|
|