Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Skeleton/SkeletalAnimation.cpp
9912 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#include <Jolt/Jolt.h>
6
7
#include <Jolt/Skeleton/SkeletalAnimation.h>
8
#include <Jolt/Skeleton/SkeletonPose.h>
9
#include <Jolt/ObjectStream/TypeDeclarations.h>
10
#include <Jolt/Core/StreamIn.h>
11
#include <Jolt/Core/StreamOut.h>
12
13
JPH_NAMESPACE_BEGIN
14
15
JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation::JointState)
16
{
17
JPH_ADD_ATTRIBUTE(JointState, mRotation)
18
JPH_ADD_ATTRIBUTE(JointState, mTranslation)
19
}
20
21
JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation::Keyframe)
22
{
23
JPH_ADD_BASE_CLASS(Keyframe, JointState)
24
25
JPH_ADD_ATTRIBUTE(Keyframe, mTime)
26
}
27
28
JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation::AnimatedJoint)
29
{
30
JPH_ADD_ATTRIBUTE(AnimatedJoint, mJointName)
31
JPH_ADD_ATTRIBUTE(AnimatedJoint, mKeyframes)
32
}
33
34
JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(SkeletalAnimation)
35
{
36
JPH_ADD_ATTRIBUTE(SkeletalAnimation, mAnimatedJoints)
37
JPH_ADD_ATTRIBUTE(SkeletalAnimation, mIsLooping)
38
}
39
40
41
void SkeletalAnimation::JointState::FromMatrix(Mat44Arg inMatrix)
42
{
43
mRotation = inMatrix.GetQuaternion();
44
mTranslation = inMatrix.GetTranslation();
45
}
46
47
float SkeletalAnimation::GetDuration() const
48
{
49
if (!mAnimatedJoints.empty() && !mAnimatedJoints[0].mKeyframes.empty())
50
return mAnimatedJoints[0].mKeyframes.back().mTime;
51
else
52
return 0.0f;
53
}
54
55
void SkeletalAnimation::ScaleJoints(float inScale)
56
{
57
for (SkeletalAnimation::AnimatedJoint &j : mAnimatedJoints)
58
for (SkeletalAnimation::Keyframe &k : j.mKeyframes)
59
k.mTranslation *= inScale;
60
}
61
62
void SkeletalAnimation::Sample(float inTime, SkeletonPose &ioPose) const
63
{
64
// Correct time when animation is looping
65
JPH_ASSERT(inTime >= 0.0f);
66
float duration = GetDuration();
67
float time = duration > 0.0f && mIsLooping? fmod(inTime, duration) : inTime;
68
69
for (const AnimatedJoint &aj : mAnimatedJoints)
70
{
71
// Do binary search for keyframe
72
int high = (int)aj.mKeyframes.size(), low = -1;
73
while (high - low > 1)
74
{
75
int probe = (high + low) / 2;
76
if (aj.mKeyframes[probe].mTime < time)
77
low = probe;
78
else
79
high = probe;
80
}
81
82
JointState &state = ioPose.GetJoint(ioPose.GetSkeleton()->GetJointIndex(aj.mJointName));
83
84
if (low == -1)
85
{
86
// Before first key, return first key
87
state = static_cast<const JointState &>(aj.mKeyframes.front());
88
}
89
else if (high == (int)aj.mKeyframes.size())
90
{
91
// Beyond last key, return last key
92
state = static_cast<const JointState &>(aj.mKeyframes.back());
93
}
94
else
95
{
96
// Interpolate
97
const Keyframe &s1 = aj.mKeyframes[low];
98
const Keyframe &s2 = aj.mKeyframes[low + 1];
99
100
float fraction = (time - s1.mTime) / (s2.mTime - s1.mTime);
101
JPH_ASSERT(fraction >= 0.0f && fraction <= 1.0f);
102
103
state.mTranslation = (1.0f - fraction) * s1.mTranslation + fraction * s2.mTranslation;
104
JPH_ASSERT(s1.mRotation.IsNormalized());
105
JPH_ASSERT(s2.mRotation.IsNormalized());
106
state.mRotation = s1.mRotation.SLERP(s2.mRotation, fraction);
107
JPH_ASSERT(state.mRotation.IsNormalized());
108
}
109
}
110
}
111
112
void SkeletalAnimation::SaveBinaryState(StreamOut &inStream) const
113
{
114
inStream.Write((uint32)mAnimatedJoints.size());
115
for (const AnimatedJoint &j : mAnimatedJoints)
116
{
117
// Write Joint name and number of keyframes
118
inStream.Write(j.mJointName);
119
inStream.Write((uint32)j.mKeyframes.size());
120
for (const Keyframe &k : j.mKeyframes)
121
{
122
inStream.Write(k.mTime);
123
inStream.Write(k.mRotation);
124
inStream.Write(k.mTranslation);
125
}
126
}
127
128
// Save additional parameters
129
inStream.Write(mIsLooping);
130
}
131
132
SkeletalAnimation::AnimationResult SkeletalAnimation::sRestoreFromBinaryState(StreamIn &inStream)
133
{
134
AnimationResult result;
135
136
Ref<SkeletalAnimation> animation = new SkeletalAnimation;
137
138
// Restore animated joints
139
uint32 len = 0;
140
inStream.Read(len);
141
animation->mAnimatedJoints.resize(len);
142
for (AnimatedJoint &j : animation->mAnimatedJoints)
143
{
144
// Read joint name
145
inStream.Read(j.mJointName);
146
147
// Read keyframes
148
len = 0;
149
inStream.Read(len);
150
j.mKeyframes.resize(len);
151
for (Keyframe &k : j.mKeyframes)
152
{
153
inStream.Read(k.mTime);
154
inStream.Read(k.mRotation);
155
inStream.Read(k.mTranslation);
156
}
157
}
158
159
// Read additional parameters
160
inStream.Read(animation->mIsLooping);
161
result.Set(animation);
162
return result;
163
}
164
165
JPH_NAMESPACE_END
166
167