Implement smooth frame transition for animated mesh

This commit is contained in:
Benau 2021-02-05 14:41:39 +08:00
parent 01de29670a
commit fa4318b6ad
6 changed files with 67 additions and 14 deletions

View File

@ -61,7 +61,8 @@ void CAnimatedMeshSceneNode::setCurrentFrame(f32 frame)
// if you pass an out of range value, we just clamp it
CurrentFrameNr = core::clamp ( frame, (f32)StartFrame, (f32)EndFrame );
beginTransition(); //transit to this frame if enabled
// STK calls setCurrentFrame each frame for steering animation
//beginTransition(); //transit to this frame if enabled
}
@ -82,6 +83,7 @@ void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs)
{
Transiting=0.f;
TransitingBlend=0.f;
setTransitionTime(0.f);
}
}
@ -189,6 +191,8 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame()
#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
return 0;
#else
if (Transiting != 0.0f)
animateJoints(false);
// As multiple scene nodes may be sharing the same skinned mesh, we have to
// re-animate it every frame to ensure that this node gets the mesh that it needs.
@ -804,9 +808,12 @@ void CAnimatedMeshSceneNode::setTransitionTime(f32 time)
return;
TransitionTime = ttime;
if (ttime != 0)
{
setJointMode(EJUOR_CONTROL);
beginTransition();
}
else
setJointMode(EJUOR_NONE);
setJointMode(EJUOR_READ);
}

View File

@ -71,7 +71,7 @@ struct Armature
std::vector<core::matrix4> m_joint_matrices;
std::vector<core::matrix4> m_interpolated_matrices;
std::vector<LocRotScale> m_interpolated_matrices;
std::vector<std::pair<core::matrix4, bool> > m_world_matrices;
@ -140,9 +140,27 @@ struct Armature
}
// ------------------------------------------------------------------------
/* Because matrix4 in windows is not 64 bytes */
void getPose(float frame, std::array<float, 16>* dest)
void getPose(float frame, std::array<float, 16>* dest,
float frame_interpolating = -1.0f, float rate = -1.0f)
{
getInterpolatedMatrices(frame);
if (frame_interpolating != -1.0f && rate != -1.0f)
{
auto copied = m_interpolated_matrices;
getInterpolatedMatrices(frame_interpolating);
for (unsigned i = 0; i < m_interpolated_matrices.size(); i++)
{
m_interpolated_matrices[i].m_loc =
copied[i].m_loc.getInterpolated(
m_interpolated_matrices[i].m_loc, rate);
m_interpolated_matrices[i].m_rot =
m_interpolated_matrices[i].m_rot.slerp(
m_interpolated_matrices[i].m_rot, copied[i].m_rot, rate);
m_interpolated_matrices[i].m_scale =
copied[i].m_scale.getInterpolated(
m_interpolated_matrices[i].m_scale, rate);
}
}
for (auto& p : m_world_matrices)
{
p.second = false;
@ -178,8 +196,8 @@ struct Armature
{
m_interpolated_matrices[i] =
frame >= float(m_frame_pose_matrices.back().first) ?
m_frame_pose_matrices.back().second[i].toMatrix() :
m_frame_pose_matrices.front().second[i].toMatrix();
m_frame_pose_matrices.back().second[i] :
m_frame_pose_matrices.front().second[i];
}
return;
}
@ -215,14 +233,14 @@ struct Armature
interpolated.m_scale =
m_frame_pose_matrices[frame_2].second[i].m_scale.getInterpolated
(m_frame_pose_matrices[frame_1].second[i].m_scale, interpolation);
m_interpolated_matrices[i] = interpolated.toMatrix();
m_interpolated_matrices[i] = interpolated;
}
}
// ------------------------------------------------------------------------
core::matrix4 getWorldMatrix(const std::vector<core::matrix4>& matrix,
core::matrix4 getWorldMatrix(const std::vector<LocRotScale>& lrs,
unsigned id)
{
core::matrix4 mat = matrix[id];
core::matrix4 mat = lrs[id].toMatrix();
int parent_id = m_parent_infos[id];
if (parent_id == -1)
{
@ -232,7 +250,7 @@ struct Armature
if (!m_world_matrices[parent_id].second)
{
m_world_matrices[parent_id] = std::make_pair
(getWorldMatrix(matrix, parent_id), true);
(getWorldMatrix(lrs, parent_id), true);
}
m_world_matrices[id] =
std::make_pair(m_world_matrices[parent_id].first * mat, true);

View File

@ -119,12 +119,14 @@ s32 SPMesh::getJointIDWithArm(const c8* name, unsigned* arm_id) const
} // getJointIDWithArm
// ----------------------------------------------------------------------------
void SPMesh::getSkinningMatrices(f32 frame, std::array<float, 16>* dest)
void SPMesh::getSkinningMatrices(f32 frame, std::array<float, 16>* 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]);
m_all_armatures[i].getPose(frame, &dest[accumulated_joints],
frame_interpolating, rate);
accumulated_joints += m_all_armatures[i].m_joint_used;
}

View File

@ -152,7 +152,8 @@ public:
// ------------------------------------------------------------------------
std::vector<Armature>& getArmatures() { return m_all_armatures; }
// ------------------------------------------------------------------------
void getSkinningMatrices(f32 frame, std::array<float, 16>* dest);
void getSkinningMatrices(f32 frame, std::array<float, 16>* dest,
float frame_interpolating = -1.0f, float rate = -1.0f);
// ------------------------------------------------------------------------
s32 getJointIDWithArm(const c8* name, unsigned* arm_id) const;
// ------------------------------------------------------------------------

View File

@ -48,6 +48,7 @@ SPMeshNode::SPMeshNode(IAnimatedMesh* mesh, ISceneNode* parent,
m_first_render_info = render_info;
m_animated = false;
m_skinning_offset = -32768;
m_saved_transition_frame = -1.0f;
m_is_in_shadowpass = true;
} // SPMeshNode
@ -83,6 +84,7 @@ void SPMeshNode::setMesh(irr::scene::IAnimatedMesh* mesh)
{
m_glow_color = video::SColorf(0.0f, 0.0f, 0.0f);
m_skinning_offset = -32768;
m_saved_transition_frame = -1.0f;
m_animated = false;
m_mesh = static_cast<SPMesh*>(mesh);
CAnimatedMeshSceneNode::setMesh(mesh);
@ -167,7 +169,8 @@ IMesh* SPMeshNode::getMeshForCurrentFrame()
{
return m_mesh;
}
m_mesh->getSkinningMatrices(getFrameNr(), m_skinning_matrices.data());
m_mesh->getSkinningMatrices(getFrameNr(), m_skinning_matrices.data(),
m_saved_transition_frame, TransitingBlend);
updateAbsolutePosition();
for (Armature& arm : m_mesh->getArmatures())
@ -211,4 +214,22 @@ SPShader* SPMeshNode::getShader(unsigned mesh_buffer_id) const
return NULL;
} // getShader
// ----------------------------------------------------------------------------
void SPMeshNode::setTransitionTime(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

@ -52,6 +52,8 @@ private:
bool m_is_in_shadowpass;
float m_saved_transition_frame;
std::vector<std::array<float, 16> > m_skinning_matrices;
video::SColorf m_glow_color;
@ -167,6 +169,8 @@ public:
assert(mb_id < m_texture_matrices.size());
m_texture_matrices[mb_id] = tm;
}
// ------------------------------------------------------------------------
virtual void setTransitionTime(f32 Time);
};
}