Now properly serialize and deserialize rigged models

This commit is contained in:
Antoine Pilote
2023-09-17 20:16:04 -04:00
parent dd66c15794
commit c0f1178e7d
7 changed files with 143 additions and 37 deletions

View File

@@ -34,6 +34,27 @@ p = j[#p]; \
#define DESERIALIZE_VEC2(v, p) \
p = Vector2(v["x"], v["y"]);
#define SERIALIZE_MAT4(lbl, m) \
{ \
int i = 0; \
for (int l = 0; l < 4; l++) { \
for (int k = 0; k < 4; k++) { \
j[lbl][i] = m[l][k]; \
i++; \
} \
} \
}
#define DESERIALIZE_MAT4(lbl, m) \
{ \
int i = 0; \
for(int l = 0; l < 4; l++) { \
for(int k = 0; k < 4; k++) { \
m[l][k] = j[lbl][i];\
i++; \
} \
} \
}
#define SERIALIZE_OBJECT(v) j[#v] = v->Serialize();
#define SERIALIZE_OBJECT_REF(v) j[#v] = v.Serialize();

View File

@@ -11,6 +11,11 @@ namespace Nuake
m_PositionTimestamps = std::vector<float>();
m_RotationTimestamps = std::vector<float>();
m_ScaleTimestamps = std::vector<float>();
m_PositionTransform = Matrix4(1.0f);
m_RotationTransform = Matrix4(1.0f);
m_ScaleTransform = Matrix4(1.0f);
m_FinalTransform = Matrix4(1.0f);
}
float BoneTransformTrack::GetScaleFactor(float lastTime, float nextTime, float animationTime)
@@ -22,7 +27,7 @@ namespace Nuake
return scaleFactor;
}
Nuake::Matrix4 BoneTransformTrack::InterpolatePosition(float time)
Matrix4 BoneTransformTrack::InterpolatePosition(float time)
{
if (m_Positions.size() == 0)
{
@@ -34,14 +39,20 @@ namespace Nuake
return glm::translate(Matrix4(1.0f), m_Positions[0]);
}
// This returns the last position when we are at the last keyframe
int p0Index = GetPositionIndex(time);
if (p0Index == m_Positions.size() - 1)
{
return glm::translate(Matrix4(1.0f), m_Positions[p0Index]);
}
int p1Index = p0Index + 1;
float scaleFactor = GetScaleFactor(m_PositionTimestamps[p0Index], m_PositionTimestamps[p1Index], time);
glm::vec3 finalPosition = glm::mix(m_Positions[p0Index], m_Positions[p1Index], scaleFactor);
Vector3 finalPosition = glm::mix(m_Positions[p0Index], m_Positions[p1Index], scaleFactor);
return glm::translate(Matrix4(1.0f), finalPosition);
}
Nuake::Matrix4 BoneTransformTrack::InterpolateRotation(float time)
Matrix4 BoneTransformTrack::InterpolateRotation(float time)
{
if (m_Rotations.size() == 0)
{
@@ -54,17 +65,21 @@ namespace Nuake
return glm::toMat4(rotation);
}
// This returns the last rotation when we are at the last keyframe
int p0Index = GetRotationIndex(time);
if (p0Index == m_Rotations.size() - 1)
{
return glm::toMat4(m_Rotations[p0Index]);
}
int p1Index = p0Index + 1;
float scaleFactor = GetScaleFactor(m_RotationTimestamps[p0Index],
m_RotationTimestamps[p1Index], time);
glm::quat finalRotation = glm::slerp(m_Rotations[p0Index],
m_Rotations[p1Index], scaleFactor);
float scaleFactor = GetScaleFactor(m_RotationTimestamps[p0Index], m_RotationTimestamps[p1Index], time);
Quat finalRotation = glm::slerp(m_Rotations[p0Index],m_Rotations[p1Index], scaleFactor);
finalRotation = glm::normalize(finalRotation);
return glm::toMat4(finalRotation);
}
Nuake::Matrix4 BoneTransformTrack::InterpolateScale(float time)
Matrix4 BoneTransformTrack::InterpolateScale(float time)
{
if (m_Scales.size() == 0)
{
@@ -72,14 +87,21 @@ namespace Nuake
}
if (1 == m_Scales.size())
{
return glm::scale(glm::mat4(1.0f), m_Scales[0]);
}
// This returns the last rotation when we are at the last keyframe
int p0Index = GetScaleIndex(time);
if (p0Index == m_Scales.size() - 1)
{
return glm::scale(Matrix4(1.0f), m_Scales[p0Index]);
}
int p1Index = p0Index + 1;
float scaleFactor = GetScaleFactor(m_ScaleTimestamps[p0Index],
m_ScaleTimestamps[p1Index], time);
glm::vec3 finalScale = glm::mix(m_Scales[p0Index], m_Scales[p1Index], scaleFactor);
return glm::scale(glm::mat4(1.0f), finalScale);
float scaleFactor = GetScaleFactor(m_ScaleTimestamps[p0Index], m_ScaleTimestamps[p1Index], time);
Vector3 finalScale = glm::mix(m_Scales[p0Index], m_Scales[p1Index], scaleFactor);
return glm::scale(Matrix4(1.0f), finalScale);
}
json BoneTransformTrack::Serialize()

View File

@@ -59,25 +59,11 @@ namespace Nuake
m_Scales.push_back(scale);
}
int GetPositionIndex(float animationTime)
{
if (m_Positions.size() == 0)
{
return 0;
}
for (int index = 0; index < m_Positions.size() - 1; index++)
{
if (animationTime < m_PositionTimestamps[index + 1])
{
return index;
}
}
assert(0);
}
void Update(float time)
{
// We cannot use const reference here because we would compare the reference to previous pos
// to the m_PositionTransform and previous pos always equale.
// Making the hasChanged always false. We would end up comparing the same values always.
const Matrix4 previousPos = m_PositionTransform;
const Matrix4 previousRot = m_RotationTransform;
const Matrix4 previousSca = m_ScaleTransform;
@@ -97,6 +83,24 @@ namespace Nuake
return m_FinalTransform;
}
int GetPositionIndex(float animationTime)
{
if (m_Positions.size() == 0)
{
return 0;
}
for (int index = 0; index < m_Positions.size() - 1; index++)
{
if (animationTime < m_PositionTimestamps[index + 1])
{
return index;
}
}
return static_cast<int>(m_Positions.size()) - 1;
}
/* Gets the current index on mKeyRotations to interpolate to based on the
current animation time*/
int GetRotationIndex(float animationTime)
@@ -108,7 +112,8 @@ namespace Nuake
return index;
}
}
assert(0);
return static_cast<int>(m_Rotations.size()) - 1;
}
/* Gets the current index on mKeyScalings to interpolate to based on the
@@ -122,7 +127,8 @@ namespace Nuake
return index;
}
}
assert(0);
return static_cast<int>(m_Scales.size()) - 1;
}
float GetScaleFactor(float lastTime, float nextTime, float animationTime);
@@ -158,7 +164,7 @@ namespace Nuake
}
else
{
m_CurrentTime = time;
m_CurrentTime = std::max(time, m_Duration);
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
#include "src/Resource/Serializable.h"
namespace Nuake
{
@@ -14,5 +15,47 @@ namespace Nuake
Matrix4 FinalTransform = Matrix4(1.0f);
int32_t Id = -1;
int32_t EntityHandle = 0;
json Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_MAT4("Transform", Transform);
SERIALIZE_MAT4("Offset", Offset);
SERIALIZE_VAL(Name);
SERIALIZE_VAL(ChildrenCount);
SERIALIZE_VAL(Id);
SERIALIZE_VAL(EntityHandle);
uint32_t i = 0;
for (auto& c : Children)
{
j["Children"][i] = c.Serialize();
i++;
}
END_SERIALIZE();
}
bool Deserialize(json j)
{
DESERIALIZE_MAT4("Transform", Transform);
DESERIALIZE_MAT4("Offset", Offset);
DESERIALIZE_VAL(Name);
DESERIALIZE_VAL(ChildrenCount);
DESERIALIZE_VAL(Id);
DESERIALIZE_VAL(EntityHandle);
if (j.contains("Children"))
{
for (uint32_t i = 0; i < ChildrenCount; i++)
{
SkeletonNode newChildren;
newChildren.Deserialize(j["Children"][i]);
Children.push_back(std::move(newChildren));
}
}
return true;
}
};
}

View File

@@ -71,6 +71,7 @@ namespace Nuake
if (this->Path != "")
{
j["Path"] = this->Path;
j["SkeletonNode"] = m_SkeletonRoot.Serialize();
}
else
{
@@ -86,10 +87,9 @@ namespace Nuake
for (auto& animation : m_Animations)
{
j["m_Animations"][a] = animation->Serialize();
a++;
}
}
END_SERIALIZE();
}
@@ -108,6 +108,13 @@ namespace Nuake
m_NumAnimation = m_Animations.size();
m_CurrentAnimation = 0;
if (j.contains("SkeletonNode"))
{
SkeletonNode skeletonNode;
skeletonNode.Deserialize(j["SkeletonNode"]);
m_SkeletonRoot = std::move(skeletonNode);
}
this->Path = j["Path"];
}
else

View File

@@ -35,6 +35,7 @@ namespace Nuake
bool Deserialize(const json& j)
{
ModelPath = j["ModelPath"];
ModelResource = CreateRef<SkinnedModel>();
if (j.contains("ModelResource"))

View File

@@ -47,17 +47,18 @@ namespace Nuake
{
const std::string& boneName = bone.Name;
auto& animationTrack = animation->GetTrack(boneName);
auto animationTrack = animation->GetTrack(boneName);
Entity& boneEntity = m_Scene->GetEntity(boneName);
Entity& boneEnt = m_Scene->GetEntityByID(bone.EntityHandle);
///assert(boneEnt.GetHandle() == boneEntity.GetHandle());
if (boneEnt.IsValid())
{
auto& transformComponent = boneEnt.GetComponent<TransformComponent>();
bone.FinalTransform = transformComponent.GetGlobalTransform() * bone.Offset;
//if (!animationTrack.IsEmpty())
if (!animationTrack.IsEmpty())
{
// Get Update transform
animationTrack.Update(time);
@@ -76,7 +77,12 @@ namespace Nuake
transformComponent.Dirty = false;
}
}
else
{
// Find bone
}
for (auto& childBone : bone.Children)
{
UpdateBonePositionTraversal(childBone, animation, time);