18constexpr u32 kSamplesPerSecond = 30;
31const IdleSpec kIdleSpecs[] = {
33 {
"shoulder.r", glm::vec3(1, 0, 0), 0.025f, 0.00f},
34 {
"shoulder.l", glm::vec3(1, 0, 0), 0.025f, 0.05f},
36 {
"bicep.r", glm::vec3(0, 0, 1), -0.018f, 0.07f},
37 {
"bicep.l", glm::vec3(0, 0, 1), 0.018f, 0.12f},
39 {
"forearm.r", glm::vec3(0, 1, 0), 0.022f, 0.10f},
40 {
"forearm.l", glm::vec3(0, 1, 0), -0.022f, 0.15f},
42 {
"wrist.r", glm::vec3(1, 0, 0), 0.030f, 0.20f},
43 {
"wrist.l", glm::vec3(1, 0, 0), 0.030f, 0.25f},
45 {
"root", glm::vec3(1, 0, 0), 0.012f, 0.00f},
52 auto clip = std::make_shared<SkeletalAnimationClip>();
54 clip->duration = duration;
57 if (duration <= 0.0f || skeleton.
Size() == 0)
62 const u32 sampleCount =
static_cast<u32>(duration * kSamplesPerSecond) + 1;
64 for (
const auto &spec : kIdleSpecs)
72 const auto &bone = skeleton.
GetBones()[boneIx];
78 for (
u32 s = 0; s < sampleCount; ++s)
80 f32 t =
static_cast<f32>(s) /
static_cast<f32>(kSamplesPerSecond);
82 f32 cyclesPerLoop = 1.0f;
83 f32 phase = (t / duration + spec.phaseOffset) * cyclesPerLoop;
84 f32 angle = spec.amplitudeRad * ampScale * std::sin(phase * 6.283185307f);
86 glm::quat anim = glm::angleAxis(angle, glm::normalize(spec.axis));
88 glm::quat finalRot = bone.bindRot * anim;
93 clip->tracks.push_back(std::move(track));
std::shared_ptr< SkeletalAnimationClip > MakeBreathingIdleClip(const Skeleton &skeleton, f32 duration, f32 ampScale)
Build a looping breathing/sway clip targeting whichever of the canonical arm bones exist in skeleton....