Move heavy gltf animation code to a cpp file
This commit is contained in:
parent
fbb032fe63
commit
5138e00c35
2 changed files with 116 additions and 80 deletions
|
|
@ -36,6 +36,9 @@ namespace psemek::gfx
|
|||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
static void canonicalize(geom::easing_type, std::vector<output_type> &)
|
||||
{}
|
||||
};
|
||||
|
||||
template <>
|
||||
|
|
@ -57,6 +60,8 @@ namespace psemek::gfx
|
|||
{
|
||||
return geom::normalized(v);
|
||||
}
|
||||
|
||||
static void canonicalize(geom::easing_type interpolation, std::vector<output_type> & output);
|
||||
};
|
||||
|
||||
template <>
|
||||
|
|
@ -78,6 +83,9 @@ namespace psemek::gfx
|
|||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
static void canonicalize(geom::easing_type, std::vector<output_type> &)
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -99,31 +107,7 @@ namespace psemek::gfx
|
|||
, output_(std::move(output))
|
||||
, interpolation_(interpolation)
|
||||
{
|
||||
if constexpr (path == gltf_asset::animation::channel::rotation)
|
||||
{
|
||||
if (interpolation == geom::easing_type::linear)
|
||||
{
|
||||
for (std::size_t i = 1; i < input_.size(); ++i)
|
||||
{
|
||||
if (geom::dot(output_[i - 1].coords, output_[i].coords) < 0.f)
|
||||
{
|
||||
output_[i] = - output_[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (interpolation == geom::easing_type::cubic)
|
||||
{
|
||||
for (std::size_t i = 1; i < input_.size(); ++i)
|
||||
{
|
||||
if (geom::dot(output_[3 * (i - 1) + 1].coords, output_[3 * i + 1].coords) < 0.f)
|
||||
{
|
||||
output_[3 * i + 0] = - output_[3 * i + 0];
|
||||
output_[3 * i + 1] = - output_[3 * i + 1];
|
||||
output_[3 * i + 2] = - output_[3 * i + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
traits::canonicalize(interpolation_, output_);
|
||||
}
|
||||
|
||||
gltf_animation_channel(gltf_animation_channel &&) = default;
|
||||
|
|
@ -135,51 +119,7 @@ namespace psemek::gfx
|
|||
return {input_.front(), input_.back()};
|
||||
}
|
||||
|
||||
output_type operator()(float time) const
|
||||
{
|
||||
auto it = std::lower_bound(input_.begin(), input_.end(), time);
|
||||
if (it == input_.begin())
|
||||
{
|
||||
if (interpolation_ == geom::easing_type::cubic)
|
||||
return output_[1];
|
||||
else
|
||||
return output_.front();
|
||||
}
|
||||
if (it == input_.end())
|
||||
{
|
||||
if (interpolation_ == geom::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 geom::easing_type::constant_left:
|
||||
return output_[i - 1];
|
||||
case geom::easing_type::linear:
|
||||
return traits::lerp(output_[i - 1], output_[i], t);
|
||||
case geom::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");
|
||||
}
|
||||
}
|
||||
output_type operator()(float time) const;
|
||||
|
||||
private:
|
||||
std::vector<float> input_;
|
||||
|
|
@ -187,6 +127,10 @@ namespace psemek::gfx
|
|||
geom::easing_type interpolation_;
|
||||
};
|
||||
|
||||
extern template struct gltf_animation_channel<gltf_asset::animation::channel::scale>;
|
||||
extern template struct gltf_animation_channel<gltf_asset::animation::channel::rotation>;
|
||||
extern template struct gltf_animation_channel<gltf_asset::animation::channel::translation>;
|
||||
|
||||
using gltf_scale_animation = gltf_animation_channel<gltf_asset::animation::channel::scale>;
|
||||
using gltf_rotation_animation = gltf_animation_channel<gltf_asset::animation::channel::rotation>;
|
||||
using gltf_translation_animation = gltf_animation_channel<gltf_asset::animation::channel::translation>;
|
||||
|
|
@ -201,17 +145,9 @@ namespace psemek::gfx
|
|||
, translation_(std::move(translation))
|
||||
{}
|
||||
|
||||
geom::interval<float> range() const
|
||||
{
|
||||
return scale_.range() | rotation_.range() | translation_.range();
|
||||
}
|
||||
geom::interval<float> range() const;
|
||||
|
||||
geom::affine_transform<float, 3, 3> operator()(float time) const
|
||||
{
|
||||
return geom::translation(translation_(time)).transform()
|
||||
* geom::quaternion_rotation(rotation_(time)).transform()
|
||||
* geom::scale(scale_(time)).transform();
|
||||
}
|
||||
geom::affine_transform<float, 3, 3> operator()(float time) const;
|
||||
|
||||
gltf_scale_animation const & scale() const { return scale_; }
|
||||
gltf_rotation_animation const & rotation() const { return rotation_; }
|
||||
|
|
|
|||
100
libs/gfx/source/gltf_animation.cpp
Normal file
100
libs/gfx/source/gltf_animation.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#include <psemek/gfx/gltf_animation.hpp>
|
||||
|
||||
namespace psemek::gfx
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
void gltf_animation_traits<gltf_asset::animation::channel::rotation>::canonicalize(geom::easing_type interpolation, std::vector<output_type> & output)
|
||||
{
|
||||
if (interpolation == geom::easing_type::linear)
|
||||
{
|
||||
for (std::size_t i = 1; i < output.size(); ++i)
|
||||
{
|
||||
if (geom::dot(output[i - 1].coords, output[i].coords) < 0.f)
|
||||
{
|
||||
output[i] = - output[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (interpolation == geom::easing_type::cubic)
|
||||
{
|
||||
for (std::size_t i = 3; i < output.size(); i += 3)
|
||||
{
|
||||
if (geom::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_ == geom::easing_type::cubic)
|
||||
return output_[1];
|
||||
else
|
||||
return output_.front();
|
||||
}
|
||||
if (it == input_.end())
|
||||
{
|
||||
if (interpolation_ == geom::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 geom::easing_type::constant_left:
|
||||
return output_[i - 1];
|
||||
case geom::easing_type::linear:
|
||||
return traits::lerp(output_[i - 1], output_[i], t);
|
||||
case geom::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>;
|
||||
|
||||
geom::interval<float> gltf_animation::range() const
|
||||
{
|
||||
return scale_.range() | rotation_.range() | translation_.range();
|
||||
}
|
||||
|
||||
geom::affine_transform<float, 3, 3> gltf_animation::operator()(float time) const
|
||||
{
|
||||
return geom::translation(translation_(time)).transform()
|
||||
* geom::quaternion_rotation(rotation_(time)).transform()
|
||||
* geom::scale(scale_(time)).transform();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue