Add animation support in GEVulkanAnimatedMeshSceneNode

This commit is contained in:
Benau 2022-07-26 00:12:35 +08:00
parent b75dec1fbc
commit 8e1de345fb
7 changed files with 237 additions and 1 deletions

View File

@ -14,6 +14,7 @@ class SPMeshLoader;
namespace GE
{
struct Armature;
class GESPMBuffer;
class GEVulkanSceneManager;
@ -31,6 +32,7 @@ private:
unsigned m_bind_frame, m_total_joints, m_joint_using, m_frame_count;
std::vector<Armature> m_all_armatures;
public:
// ------------------------------------------------------------------------
GESPM();
@ -70,6 +72,17 @@ public:
virtual E_ANIMATED_MESH_TYPE getMeshType() const { return EAMT_SPM; }
// ------------------------------------------------------------------------
virtual void finalize();
// ------------------------------------------------------------------------
std::vector<Armature>& getArmatures() { return m_all_armatures; }
// ------------------------------------------------------------------------
void getSkinningMatrices(f32 frame, std::vector<core::matrix4>& dest,
float frame_interpolating = -1.0f, float rate = -1.0f);
// ------------------------------------------------------------------------
s32 getJointIDWithArm(const c8* name, unsigned* arm_id) const;
// ------------------------------------------------------------------------
bool isStatic() const { return m_all_armatures.empty(); }
// ------------------------------------------------------------------------
unsigned getJointCount() const { return m_joint_using; }
};

View File

@ -1,6 +1,10 @@
#include "ge_spm.hpp"
#include "ge_animation.hpp"
#include "ge_spm_buffer.hpp"
#include <algorithm>
namespace GE
{
GESPM::GESPM()
@ -42,6 +46,54 @@ void GESPM::finalize()
m_bounding_box.reset(0.0f, 0.0f, 0.0f);
for (unsigned i = 0; i < m_buffer.size(); i++)
m_bounding_box.addInternalBox(m_buffer[i]->getBoundingBox());
for (Armature& arm : getArmatures())
{
arm.getInterpolatedMatrices((float)m_bind_frame);
for (auto& p : arm.m_world_matrices)
{
p.second = false;
}
for (unsigned i = 0; i < arm.m_joint_names.size(); i++)
{
core::matrix4 m;
arm.getWorldMatrix(arm.m_interpolated_matrices, i).getInverse(m);
arm.m_joint_matrices[i] = m;
}
}
} // finalize
// ----------------------------------------------------------------------------
void GESPM::getSkinningMatrices(f32 frame, std::vector<core::matrix4>& dest,
float frame_interpolating, float rate)
{
unsigned accumulated_joints = 0;
for (unsigned i = 0; i < m_all_armatures.size(); i++)
{
m_all_armatures[i].getPose(frame, &dest[accumulated_joints],
frame_interpolating, rate);
accumulated_joints += m_all_armatures[i].m_joint_used;
}
} // getSkinningMatrices
// ----------------------------------------------------------------------------
s32 GESPM::getJointIDWithArm(const c8* name, unsigned* arm_id) const
{
for (unsigned i = 0; i < m_all_armatures.size(); i++)
{
const Armature& arm = m_all_armatures[i];
auto found = std::find(arm.m_joint_names.begin(),
arm.m_joint_names.end(), name);
if (found != arm.m_joint_names.end())
{
if (arm_id != NULL)
{
*arm_id = i;
}
return (int)(found - arm.m_joint_names.begin());
}
}
return -1;
} // getJointIDWithArm
}

View File

@ -1,8 +1,11 @@
#include "ge_vulkan_animated_mesh_scene_node.hpp"
#include "ge_animation.hpp"
#include "ge_spm.hpp"
#include "ISceneManager.h"
#include "../../../lib/irrlicht/source/Irrlicht/CBoneSceneNode.h"
#include <limits>
namespace GE
{
@ -14,6 +17,7 @@ GEVulkanAnimatedMeshSceneNode::GEVulkanAnimatedMeshSceneNode(irr::scene::IAnimat
: irr::scene::CAnimatedMeshSceneNode(mesh, parent, mgr, id, position,
rotation, scale)
{
m_saved_transition_frame = -1.0f;
} // GEVulkanAnimatedMeshSceneNode
// ----------------------------------------------------------------------------
@ -31,4 +35,101 @@ void GEVulkanAnimatedMeshSceneNode::OnRegisterSceneNode()
ISceneNode::OnRegisterSceneNode();
} // OnRegisterSceneNode
// ----------------------------------------------------------------------------
void GEVulkanAnimatedMeshSceneNode::setMesh(irr::scene::IAnimatedMesh* mesh)
{
CAnimatedMeshSceneNode::setMesh(mesh);
cleanJoints();
GESPM* spm = getSPM();
if (!spm || spm->isStatic())
return;
unsigned bone_idx = 0;
m_skinning_matrices.resize(spm->getJointCount());
for (Armature& arm : spm->getArmatures())
{
for (const std::string& bone_name : arm.m_joint_names)
{
m_joint_nodes[bone_name] = new CBoneSceneNode(this,
SceneManager, 0, bone_idx++, bone_name.c_str());
m_joint_nodes.at(bone_name)->drop();
m_joint_nodes.at(bone_name)->setSkinningSpace(EBSS_GLOBAL);
}
}
} // setMesh
// ----------------------------------------------------------------------------
void GEVulkanAnimatedMeshSceneNode::OnAnimate(irr::u32 time_ms)
{
GESPM* spm = getSPM();
if (!spm || spm->isStatic())
{
IAnimatedMeshSceneNode::OnAnimate(time_ms);
return;
}
// first frame
if (LastTimeMs == 0)
LastTimeMs = time_ms;
// set CurrentFrameNr
buildFrameNr(time_ms - LastTimeMs);
LastTimeMs = time_ms;
spm->getSkinningMatrices(getFrameNr(), m_skinning_matrices,
m_saved_transition_frame, TransitingBlend);
recursiveUpdateAbsolutePosition();
for (Armature& arm : spm->getArmatures())
{
for (unsigned i = 0; i < arm.m_joint_names.size(); i++)
{
m_joint_nodes.at(arm.m_joint_names[i])->setAbsoluteTransformation
(AbsoluteTransformation * arm.m_world_matrices[i].first);
}
}
IAnimatedMeshSceneNode::OnAnimate(time_ms);
} // OnAnimate
// ----------------------------------------------------------------------------
irr::scene::IBoneSceneNode* GEVulkanAnimatedMeshSceneNode::getJointNode(const irr::c8* joint_name)
{
auto ret = m_joint_nodes.find(joint_name);
if (ret != m_joint_nodes.end())
return ret->second;
return NULL;
} // getJointNode
// ----------------------------------------------------------------------------
irr::scene::IBoneSceneNode* GEVulkanAnimatedMeshSceneNode::getJointNode(irr::u32 joint_id)
{
irr::u32 idx = 0;
for (auto& p : m_joint_nodes)
{
if (joint_id == idx)
return p.second;
idx++;
}
return NULL;
} // getJointNode
// ----------------------------------------------------------------------------
void GEVulkanAnimatedMeshSceneNode::setTransitionTime(irr::f32 Time)
{
if (Time == 0.0f)
{
TransitingBlend = TransitionTime = Transiting = 0;
m_saved_transition_frame = -1.0;
}
else
{
const u32 ttime = (u32)core::floor32(Time * 1000.0f);
TransitionTime = ttime;
Transiting = core::reciprocal((f32)TransitionTime);
TransitingBlend = 0.0f;
m_saved_transition_frame = getFrameNr();
}
} // setTransitionTime
}

View File

@ -3,12 +3,32 @@
#include "../source/Irrlicht/CAnimatedMeshSceneNode.h"
#include <cassert>
#include <string>
#include <vector>
#include <unordered_map>
namespace GE
{
class GESPM;
class GEVulkanAnimatedMeshSceneNode : public irr::scene::CAnimatedMeshSceneNode
{
private:
std::unordered_map<std::string, irr::scene::IBoneSceneNode*> m_joint_nodes;
float m_saved_transition_frame;
std::vector<irr::core::matrix4> m_skinning_matrices;
// ------------------------------------------------------------------------
void cleanJoints()
{
for (auto& p : m_joint_nodes)
removeChild(p.second);
m_joint_nodes.clear();
m_skinning_matrices.clear();
}
public:
// ------------------------------------------------------------------------
GEVulkanAnimatedMeshSceneNode(irr::scene::IAnimatedMesh* mesh,
@ -17,6 +37,20 @@ public:
const irr::core::vector3df& rotation = irr::core::vector3df(0, 0, 0),
const irr::core::vector3df& scale = irr::core::vector3df(1.0f, 1.0f, 1.0f));
// ------------------------------------------------------------------------
~GEVulkanAnimatedMeshSceneNode() { cleanJoints(); }
// ------------------------------------------------------------------------
virtual void setMesh(irr::scene::IAnimatedMesh* mesh);
// ------------------------------------------------------------------------
virtual void OnAnimate(irr::u32 time_ms);
// ------------------------------------------------------------------------
virtual irr::scene::IBoneSceneNode* getJointNode(const irr::c8* joint_name);
// ------------------------------------------------------------------------
virtual irr::scene::IBoneSceneNode* getJointNode(irr::u32 joint_id);
// ------------------------------------------------------------------------
virtual irr::u32 getJointCount() const { return m_joint_nodes.size(); }
// ------------------------------------------------------------------------
virtual void setTransitionTime(irr::f32 Time);
// ------------------------------------------------------------------------
GESPM* getSPM() const;
// ------------------------------------------------------------------------
virtual void OnRegisterSceneNode();

View File

@ -114,6 +114,11 @@ scene::IAnimatedMesh* B3DMeshLoader::createMesh(io::IReadFile* f)
stk_material->getTexture();
gebuf->recalculateBoundingBox();
}
ge_spm->m_bind_frame = spm->m_bind_frame;
ge_spm->m_total_joints = spm->m_total_joints;
ge_spm->m_joint_using = spm->m_joint_using;
ge_spm->m_frame_count = spm->m_frame_count;
std::swap(ge_spm->m_all_armatures, spm->m_all_armatures);
ge_spm->finalize();
ge_spm->setMinMax(min.toIrrVector(), max.toIrrVector());
spm->drop();

View File

@ -335,6 +335,26 @@ scene::IAnimatedMesh* SPMeshLoader::createMesh(io::IReadFile* f)
}
spm->m_all_armatures = std::move(m_all_armatures);
}
#ifndef SERVER_ONLY
else if (ge_spm)
{
GE::GESPM* spm = static_cast<GE::GESPM*>(m_mesh);
spm->m_bind_frame = m_bind_frame;
spm->m_joint_using = m_joint_count;
// Because the last frame in spm is usable
if (has_armature)
{
spm->m_frame_count = m_frame_count + 1;
}
for (unsigned i = 0; i < m_all_armatures.size(); i++)
{
// This is diffferent from m_joint_using
spm->m_total_joints +=
(unsigned)m_all_armatures[i].m_joint_names.size();
}
spm->m_all_armatures = std::move(m_all_armatures);
}
#endif
m_mesh->finalize();
scene::CSkinnedMesh* cmesh = dynamic_cast<scene::CSkinnedMesh*>(m_mesh);
if (cmesh && !real_spm && has_armature)

View File

@ -48,6 +48,7 @@
#include "IMeshManipulator.h"
#include <algorithm>
#include <ge_animation.hpp>
#include <ge_spm.hpp>
#define SKELETON_DEBUG 0
@ -1295,11 +1296,21 @@ void KartModel::initInverseBoneMatrices()
m_model_filename.c_str());
striaght_frame = 0.0f;
}
std::vector<GE::Armature> armatures;
#ifndef SERVER_ONLY
using namespace SP;
SPMesh* spm = dynamic_cast<SPMesh*>(m_mesh);
GE::GESPM* ge_spm = dynamic_cast<GE::GESPM*>(m_mesh);
if (spm)
armatures = spm->getArmatures();
else if (ge_spm)
armatures = ge_spm->getArmatures();
#endif
if (!armatures.empty())
{
for (GE::Armature& arm : spm->getArmatures())
for (GE::Armature& arm : armatures)
{
arm.getInterpolatedMatrices(striaght_frame);
for (auto& p : arm.m_world_matrices)