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;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void canonicalize(geom::easing_type, std::vector<output_type> &)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
@ -57,6 +60,8 @@ namespace psemek::gfx
|
||||||
{
|
{
|
||||||
return geom::normalized(v);
|
return geom::normalized(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void canonicalize(geom::easing_type interpolation, std::vector<output_type> & output);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
@ -78,6 +83,9 @@ namespace psemek::gfx
|
||||||
{
|
{
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void canonicalize(geom::easing_type, std::vector<output_type> &)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -99,31 +107,7 @@ namespace psemek::gfx
|
||||||
, output_(std::move(output))
|
, output_(std::move(output))
|
||||||
, interpolation_(interpolation)
|
, interpolation_(interpolation)
|
||||||
{
|
{
|
||||||
if constexpr (path == gltf_asset::animation::channel::rotation)
|
traits::canonicalize(interpolation_, output_);
|
||||||
{
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gltf_animation_channel(gltf_animation_channel &&) = default;
|
gltf_animation_channel(gltf_animation_channel &&) = default;
|
||||||
|
|
@ -135,51 +119,7 @@ namespace psemek::gfx
|
||||||
return {input_.front(), input_.back()};
|
return {input_.front(), input_.back()};
|
||||||
}
|
}
|
||||||
|
|
||||||
output_type operator()(float time) const
|
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<float> input_;
|
std::vector<float> input_;
|
||||||
|
|
@ -187,6 +127,10 @@ namespace psemek::gfx
|
||||||
geom::easing_type interpolation_;
|
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_scale_animation = gltf_animation_channel<gltf_asset::animation::channel::scale>;
|
||||||
using gltf_rotation_animation = gltf_animation_channel<gltf_asset::animation::channel::rotation>;
|
using gltf_rotation_animation = gltf_animation_channel<gltf_asset::animation::channel::rotation>;
|
||||||
using gltf_translation_animation = gltf_animation_channel<gltf_asset::animation::channel::translation>;
|
using gltf_translation_animation = gltf_animation_channel<gltf_asset::animation::channel::translation>;
|
||||||
|
|
@ -201,17 +145,9 @@ namespace psemek::gfx
|
||||||
, translation_(std::move(translation))
|
, translation_(std::move(translation))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
geom::interval<float> range() const
|
geom::interval<float> range() const;
|
||||||
{
|
|
||||||
return scale_.range() | rotation_.range() | translation_.range();
|
|
||||||
}
|
|
||||||
|
|
||||||
geom::affine_transform<float, 3, 3> operator()(float time) 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
gltf_scale_animation const & scale() const { return scale_; }
|
gltf_scale_animation const & scale() const { return scale_; }
|
||||||
gltf_rotation_animation const & rotation() const { return rotation_; }
|
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