5#include <glm/ext/matrix_transform.hpp>
6#include <glm/gtc/quaternion.hpp>
7#include <glm/gtc/type_ptr.hpp>
17template <
typename Key>
18usize FindKeyIndex(
const std::vector<Key> &keys,
f32 time)
20 for (
usize i = 0; i + 1 < keys.size(); ++i)
22 if (time < keys[i + 1].time)
27 return keys.empty() ? 0 : keys.size() - 1;
30glm::vec3 InterpolateVec3(
const std::vector<KeyFrameVec3> &keys,
f32 time)
34 return glm::vec3(0.0f);
38 return keys.front().value;
40 auto i0 = FindKeyIndex(keys, time);
41 auto i1 = std::min(i0 + 1, keys.size() - 1);
44 return keys[i0].value;
46 f32 dt = keys[i1].time - keys[i0].time;
47 f32 t = dt > 0.0f ? (time - keys[i0].time) / dt : 0.0f;
48 t = std::clamp(t, 0.0f, 1.0f);
49 return glm::mix(keys[i0].value, keys[i1].value, t);
52glm::quat InterpolateQuat(
const std::vector<KeyFrameQuat> &keys,
f32 time)
56 return glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
60 return keys.front().value;
62 auto i0 = FindKeyIndex(keys, time);
63 auto i1 = std::min(i0 + 1, keys.size() - 1);
66 return keys[i0].value;
68 f32 dt = keys[i1].time - keys[i0].time;
69 f32 t = dt > 0.0f ? (time - keys[i0].time) / dt : 0.0f;
70 t = std::clamp(t, 0.0f, 1.0f);
71 return glm::slerp(keys[i0].value, keys[i1].value, t);
74glm::mat4 ComposeTRS(
const glm::vec3 &translation,
const glm::quat &rotation,
const glm::vec3 &scale)
77 mat = glm::translate(mat, translation);
78 mat = mat * glm::mat4_cast(rotation);
79 mat = glm::scale(mat, scale);
86 const auto &bones = skeleton.
GetBones();
89 for (
usize i = 0; i < bones.size(); ++i)
98 const auto &bones = skeleton.
GetBones();
104 for (
usize i = 0; i < bones.size(); ++i)
110 for (
const auto &track : clip.
tracks)
112 if (track.boneIndex < 0 ||
static_cast<usize>(track.boneIndex) >= bones.size())
118 const Bone &bone = bones[track.boneIndex];
119 glm::vec3 t = track.positions.empty() ? bone.
bindPos : InterpolateVec3(track.positions, time);
120 glm::quat r = track.rotations.empty() ? bone.
bindRot : InterpolateQuat(track.rotations, time);
121 glm::vec3 s = track.scales.empty() ? bone.
bindScale : InterpolateVec3(track.scales, time);
129 const auto &bones = skeleton.
GetBones();
136 std::vector<glm::mat4> globalTransforms(bones.size(), glm::mat4(1.0f));
138 for (
usize i = 0; i < bones.size(); ++i)
140 const auto &bone = bones[i];
141 if (bone.parentIndex < 0)
146 globalTransforms[i] = globalTransforms[bone.parentIndex] * pose.
localTransforms[i];
148 pose.
finalPalette[i] = globalTransforms[i] * bone.offsetMatrix;
Per-frame skeletal pose: local bone transforms + final GPU palette.
Per-bone TRS keyframe tracks driving a Skeleton.
Bone hierarchy + bind/offset matrices for GPU-skinned meshes.
const std::vector< Bone > & GetBones() const
float f32
32-bit IEEE float — the standard GL scalar type.
size_t usize
Platform-native unsigned size type.
void ComputePalette(const Skeleton &skeleton, Pose &pose)
Concatenate parent transforms and apply offsetMatrix to produce the GPU palette.
void ResetPoseToBind(const Skeleton &skeleton, Pose &pose)
Resize pose buffers to match skeleton and reset to bind pose.
void EvaluatePose(const SkeletalAnimationClip &clip, const Skeleton &skeleton, f32 time, Pose &pose)
Sample clip at time and write each animated bone's TRS into pose.localTransforms.
Per-frame pose state for a Skeleton.
std::vector< glm::mat4 > localTransforms
Animated TRS per bone (parent-relative).
std::vector< glm::mat4 > finalPalette
Skinning matrices: globalPose * offsetMatrix.
std::vector< BoneTrack > tracks