98 lines
2.7 KiB
C++
98 lines
2.7 KiB
C++
#include <psemek/gfx/gltf_animation.hpp>
|
|
|
|
namespace psemek::gfx
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
void gltf_animation_traits<gltf_asset::animation::channel::rotation>::canonicalize(math::easing_type interpolation, std::vector<output_type> & output)
|
|
{
|
|
if (interpolation == math::easing_type::linear)
|
|
{
|
|
for (std::size_t i = 1; i < output.size(); ++i)
|
|
{
|
|
if (math::dot(output[i - 1].coords, output[i].coords) < 0.f)
|
|
{
|
|
output[i] = - output[i];
|
|
}
|
|
}
|
|
}
|
|
else if (interpolation == math::easing_type::cubic)
|
|
{
|
|
for (std::size_t i = 3; i < output.size(); i += 3)
|
|
{
|
|
if (math::dot(output[(i - 3) + 1].coords, output[i + 1].coords) < 0.f)
|
|
{
|
|
output[i + 0] = - output[i + 0];
|
|
output[i + 1] = - output[i + 1];
|
|
output[i + 2] = - output[i + 2];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
template <gltf_asset::animation::channel::path_t path>
|
|
gltf_animation_channel<path>::output_type gltf_animation_channel<path>::operator()(float time) const
|
|
{
|
|
auto it = std::lower_bound(input_.begin(), input_.end(), time);
|
|
if (it == input_.begin())
|
|
{
|
|
if (interpolation_ == math::easing_type::cubic)
|
|
return output_[1];
|
|
else
|
|
return output_.front();
|
|
}
|
|
if (it == input_.end())
|
|
{
|
|
if (interpolation_ == math::easing_type::cubic)
|
|
return output_[output_.size() - 2];
|
|
else
|
|
return output_.back();
|
|
}
|
|
|
|
auto i = it - input_.begin();
|
|
|
|
float td = (input_[i] - input_[i - 1]);
|
|
float t = (time - input_[i - 1]) / td;
|
|
|
|
switch (interpolation_)
|
|
{
|
|
case math::easing_type::constant_left:
|
|
return output_[i - 1];
|
|
case math::easing_type::linear:
|
|
return traits::lerp(output_[i - 1], output_[i], t);
|
|
case math::easing_type::cubic:
|
|
{
|
|
// see https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_007_Animations.html#cubic-spline-interpolation
|
|
float t2 = t * t;
|
|
float t3 = t * t2;
|
|
return traits::normalize(output_type::zero()
|
|
+ output_[3 * (i - 1) + 1] * ( 2.f * t3 - 3.f * t2 + 1.f)
|
|
+ output_[3 * (i - 1) + 2] * ( t3 - 2.f * t2 + t ) * td
|
|
+ output_[3 * (i + 0) + 1] * (- 2.f * t3 + 3.f * t2 )
|
|
+ output_[3 * (i + 0) + 0] * ( t3 - t2 ) * td
|
|
);
|
|
}
|
|
default:
|
|
throw util::exception("Unknown glTF animation interpolation type");
|
|
}
|
|
}
|
|
|
|
template struct gltf_animation_channel<gltf_asset::animation::channel::scale>;
|
|
template struct gltf_animation_channel<gltf_asset::animation::channel::rotation>;
|
|
template struct gltf_animation_channel<gltf_asset::animation::channel::translation>;
|
|
|
|
math::interval<float> gltf_animation::range() const
|
|
{
|
|
return scale_.range() | rotation_.range() | translation_.range();
|
|
}
|
|
|
|
math::trs<float, 3> gltf_animation::operator()(float time) const
|
|
{
|
|
return {translation_(time), rotation_(time), scale_(time)};
|
|
}
|
|
|
|
}
|