| 45 | using namespace donut::engine::animation; |
| 46 | |
| 47 | float4 donut::engine::animation::Interpolate(const InterpolationMode mode, |
| 48 | const Keyframe& a, const Keyframe& b, const Keyframe& c, const Keyframe& d, const float t, const float dt) |
| 49 | { |
| 50 | switch (mode) |
| 51 | { |
| 52 | case InterpolationMode::Step: |
| 53 | return b.value; |
| 54 | |
| 55 | case InterpolationMode::Linear: |
| 56 | return lerp(b.value, c.value, t); |
| 57 | |
| 58 | case InterpolationMode::Slerp: { |
| 59 | quat qb = quat::fromXYZW(b.value); |
| 60 | quat qc = quat::fromXYZW(c.value); |
| 61 | quat qr = slerp(qb, qc, t); |
| 62 | return float4(qr.x, qr.y, qr.z, qr.w); |
| 63 | } |
| 64 | |
| 65 | case InterpolationMode::CatmullRomSpline: { |
| 66 | // https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Interpolation_on_the_unit_interval_with_matched_derivatives_at_endpoints |
| 67 | // a = p[n-1], b = p[n], c = p[n+1], d = p[n+2] |
| 68 | float4 i = -a.value + 3.f * b.value - 3.f * c.value + d.value; |
| 69 | float4 j = 2.f * a.value - 5.f * b.value + 4.f * c.value - d.value; |
| 70 | float4 k = -a.value + c.value; |
| 71 | return 0.5f * ((i * t + j) * t + k) * t + b.value; |
| 72 | } |
| 73 | |
| 74 | case InterpolationMode::HermiteSpline: { |
| 75 | // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#appendix-c-spline-interpolation |
| 76 | const float t2 = t * t; |
| 77 | const float t3 = t2 * t; |
| 78 | return (2.f * t3 - 3.f * t2 + 1.f) * b.value |
| 79 | + (t3 - 2.f * t2 + t) * b.outTangent * dt |
| 80 | + (-2.f * t3 + 3.f * t2) * c.value |
| 81 | + (t3 - t2) * c.inTangent * dt; |
| 82 | } |
| 83 | |
| 84 | default: |
| 85 | assert(!"Unknown interpolation mode"); |
| 86 | return b.value; |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | std::optional<dm::float4> Sampler::Evaluate(float time, bool extrapolateLastValues) const |
| 91 | { |