diff --git a/lib/graphics_engine/include/ge_spm.hpp b/lib/graphics_engine/include/ge_spm.hpp index dcb0098ea..9ff604ea4 100644 --- a/lib/graphics_engine/include/ge_spm.hpp +++ b/lib/graphics_engine/include/ge_spm.hpp @@ -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 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& getArmatures() { return m_all_armatures; } + // ------------------------------------------------------------------------ + void getSkinningMatrices(f32 frame, std::vector& 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; } }; diff --git a/lib/graphics_engine/src/ge_spm.cpp b/lib/graphics_engine/src/ge_spm.cpp index 43a4f9dcd..eb78b4d03 100644 --- a/lib/graphics_engine/src/ge_spm.cpp +++ b/lib/graphics_engine/src/ge_spm.cpp @@ -1,6 +1,10 @@ #include "ge_spm.hpp" + +#include "ge_animation.hpp" #include "ge_spm_buffer.hpp" +#include + 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& 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 + } diff --git a/lib/graphics_engine/src/ge_vulkan_animated_mesh_scene_node.cpp b/lib/graphics_engine/src/ge_vulkan_animated_mesh_scene_node.cpp index 8b047fa36..140721960 100644 --- a/lib/graphics_engine/src/ge_vulkan_animated_mesh_scene_node.cpp +++ b/lib/graphics_engine/src/ge_vulkan_animated_mesh_scene_node.cpp @@ -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 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 + } diff --git a/lib/graphics_engine/src/ge_vulkan_animated_mesh_scene_node.hpp b/lib/graphics_engine/src/ge_vulkan_animated_mesh_scene_node.hpp index 0d7d595b3..049f19fbe 100644 --- a/lib/graphics_engine/src/ge_vulkan_animated_mesh_scene_node.hpp +++ b/lib/graphics_engine/src/ge_vulkan_animated_mesh_scene_node.hpp @@ -3,12 +3,32 @@ #include "../source/Irrlicht/CAnimatedMeshSceneNode.h" +#include +#include +#include +#include + namespace GE { class GESPM; class GEVulkanAnimatedMeshSceneNode : public irr::scene::CAnimatedMeshSceneNode { +private: + std::unordered_map m_joint_nodes; + + float m_saved_transition_frame; + + std::vector 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(); diff --git a/src/graphics/b3d_mesh_loader.cpp b/src/graphics/b3d_mesh_loader.cpp index d84374a8d..866b63903 100644 --- a/src/graphics/b3d_mesh_loader.cpp +++ b/src/graphics/b3d_mesh_loader.cpp @@ -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(); diff --git a/src/graphics/sp_mesh_loader.cpp b/src/graphics/sp_mesh_loader.cpp index 48df248a8..9be99bffe 100644 --- a/src/graphics/sp_mesh_loader.cpp +++ b/src/graphics/sp_mesh_loader.cpp @@ -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(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(m_mesh); if (cmesh && !real_spm && has_armature) diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index 4f6327183..8c1179ad1 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -48,6 +48,7 @@ #include "IMeshManipulator.h" #include #include +#include #define SKELETON_DEBUG 0 @@ -1295,11 +1296,21 @@ void KartModel::initInverseBoneMatrices() m_model_filename.c_str()); striaght_frame = 0.0f; } + std::vector armatures; + +#ifndef SERVER_ONLY using namespace SP; SPMesh* spm = dynamic_cast(m_mesh); + GE::GESPM* ge_spm = dynamic_cast(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)