Skip to content

Commit

Permalink
Interpolatiors: Add zoom interpolator
Browse files Browse the repository at this point in the history
  • Loading branch information
bwrsandman committed Apr 1, 2024
1 parent baf38ed commit 6dce747
Show file tree
Hide file tree
Showing 4 changed files with 391 additions and 0 deletions.
218 changes: 218 additions & 0 deletions src/Common/ZoomInterpolator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*******************************************************************************
* Copyright (c) 2018-2024 openblack developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/openblack/openblack
*
* openblack is licensed under the GNU General Public License version 3.
*******************************************************************************/

#include "ZoomInterpolator.h"

#include <glm/vec3.hpp>

using namespace openblack;

template <>
ZoomInterpolator<float>::ZoomInterpolator(float p)
: p0(p)
, p1(p)
, v0(0.0f)
, v1(0.0f)
{
}

template <>
ZoomInterpolator<float>::ZoomInterpolator(float p0, float p1, float v0, float v1)
: p0(p0)
, p1(p1)
, v0(v0)
, v1(v1)
{
}

template <>
ZoomInterpolator<double>::ZoomInterpolator(double p)
: p0(p)
, p1(p)
, v0(0.0)
, v1(0.0)
{
}

template <>
ZoomInterpolator<double>::ZoomInterpolator(double p0, double p1, double v0, double v1)
: p0(p0)
, p1(p1)
, v0(v0)
, v1(v1)
{
}

template <>
ZoomInterpolator3f::ZoomInterpolatorVec(glm::vec3 p)
: p0(p)
, p1(p)
, v0(0.0f)
, v1(0.0f)
{
}

template <>
ZoomInterpolator3f::ZoomInterpolatorVec(glm::vec3 p0, glm::vec3 p1, glm::vec3 v0, glm::vec3 v1)
: p0(p0)
, p1(p1)
, v0(v0)
, v1(v1)
{
}

template <typename T>
requires std::floating_point<T>
inline T PositionAtImpl(T p0, T p1, T v0, T v1, T t)
{
// Catch singularity
if (p0 == p1)
{
return p0;
}

const auto pr = p1 - p0;

// Turn velocities into slopes. Can divide by pr since t goes from 0 to 1
const auto m0 = v0 / pr;
const auto m1 = v1 / pr;

// Compute point on scaled down curve
const auto t2 = t * t;
const auto t3 = t2 * t;
const auto t4 = t2 * t2;
const auto result = //
t * m0 + //
t2 * (static_cast<T>(-3) * m0 - static_cast<T>(3) * m1 + static_cast<T>(6)) +
t3 * (static_cast<T>(3) * m0 + static_cast<T>(5) * m1 - static_cast<T>(8)) +
t4 * (-m0 - static_cast<T>(2) * m1 + static_cast<T>(3));

// Scale and translate point on curve
return result * pr + p0;
}

template <typename T>
requires std::floating_point<T>
inline T VelocityAtImpl(T p0, T p1, T v0, T v1, T t)
{
if (p0 == p1)
{
return 0;
}

const auto pr = p1 - p0;

// Turn velocities into slopes. Can divide by pr since t goes from 0 to 1
const auto m0 = v0 / pr;
const auto m1 = v1 / pr;

// Derivative of position function with respect to t
const auto t2 = t * t;
const auto t3 = t2 * t;
const auto result = //
m0 + //
t * 2 * (static_cast<T>(-3) * m0 - static_cast<T>(3) * m1 + static_cast<T>(6)) +
t2 * 3 * (static_cast<T>(3) * m0 + static_cast<T>(5) * m1 - static_cast<T>(8)) +
t3 * 4 * (-m0 - static_cast<T>(2) * m1 + static_cast<T>(3));

// Scale back to the original problem's units (since m0 and m1 were scaled down by dp)
return result * pr;
}

template <typename T>
requires std::floating_point<T>
inline T AccelerationAtImpl(T p0, T p1, T v0, T v1, T t)
{
if (p0 == p1)
{
return 0;
}

const auto pr = p1 - p0;

// Turn velocities into slopes. Can divide by pr since t goes from 0 to 1
const auto m0 = v0 / pr;
const auto m1 = v1 / pr;

// Second derivative of position function with respect to t to find acceleration
const auto t2 = t * t;
const auto result = //
2 * (static_cast<T>(-3) * m0 - static_cast<T>(3) * m1 + static_cast<T>(6)) +
t * 6 * (static_cast<T>(3) * m0 + static_cast<T>(5) * m1 - static_cast<T>(8)) +
t2 * 12 * (-m0 - static_cast<T>(2) * m1 + static_cast<T>(3));

// Scale back to the original problem's units (since m0 and m1 were scaled down by pr)
return result * pr;
}

template <>
float ZoomInterpolator<float>::PositionAt(float t) const
{
return PositionAtImpl(p0, p1, v0, v1, t);
}

template <>
double ZoomInterpolator<double>::PositionAt(double t) const
{
return PositionAtImpl(p0, p1, v0, v1, t);
}

template <>
float ZoomInterpolator<float>::VelocityAt(float t) const
{
return VelocityAtImpl(p0, p1, v0, v1, t);
}

template <>
double ZoomInterpolator<double>::VelocityAt(double t) const
{
return VelocityAtImpl(p0, p1, v0, v1, t);
}

template <>
float ZoomInterpolator<float>::AccelerationAt(float t) const
{
return AccelerationAtImpl(p0, p1, v0, v1, t);
}

template <>
double ZoomInterpolator<double>::AccelerationAt(double t) const
{
return AccelerationAtImpl(p0, p1, v0, v1, t);
}

template <>
glm::vec3 ZoomInterpolator3f::PositionAt(float t) const
{
return {
PositionAtImpl(p0.x, p1.x, v0.x, v1.x, t),
PositionAtImpl(p0.y, p1.y, v0.y, v1.y, t),
PositionAtImpl(p0.z, p1.z, v0.z, v1.z, t),
};
}

template <>
glm::vec3 ZoomInterpolator3f::VelocityAt(float t) const
{
return {
VelocityAtImpl(p0.x, p1.x, v0.x, v1.x, t),
VelocityAtImpl(p0.y, p1.y, v0.y, v1.y, t),
VelocityAtImpl(p0.z, p1.z, v0.z, v1.z, t),
};
}

template <>
glm::vec3 ZoomInterpolator3f::AccelerationAt(float t) const
{
return {
AccelerationAtImpl(p0.x, p1.x, v0.x, v1.x, t),
AccelerationAtImpl(p0.y, p1.y, v0.y, v1.y, t),
AccelerationAtImpl(p0.z, p1.z, v0.z, v1.z, t),
};
}
60 changes: 60 additions & 0 deletions src/Common/ZoomInterpolator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*******************************************************************************
* Copyright (c) 2018-2024 openblack developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/openblack/openblack
*
* openblack is licensed under the GNU General Public License version 3.
*******************************************************************************/

#pragma once

#include <concepts>

#include <glm/detail/qualifier.hpp>

namespace openblack
{

// Called Zoomer in vanilla, this is a 5 degree (quintic) polynomial.
// It has degrees of freedom in start and end position, velocity.
// The acceleration, jerk and snap are based off the first 5 taylor series
// expansion elements of the exp function.
// It takes as input t as an interpolation factor between 0 and 1
template <typename T>
requires std::floating_point<T>
struct ZoomInterpolator
{
T p0;
T p1;
T v0;
T v1;

explicit ZoomInterpolator(T p);
ZoomInterpolator(T p0, T p1, T v0, T v1);

[[nodiscard]] T PositionAt(T t) const;
[[nodiscard]] T VelocityAt(T t) const;
[[nodiscard]] T AccelerationAt(T t) const;
};

template <glm::length_t L, typename T, glm::qualifier Q = glm::defaultp>
requires std::floating_point<T>
struct ZoomInterpolatorVec
{
glm::vec<L, T, Q> p0;
glm::vec<L, T, Q> p1;
glm::vec<L, T, Q> v0;
glm::vec<L, T, Q> v1;

explicit ZoomInterpolatorVec(glm::vec<L, T, Q> p);
ZoomInterpolatorVec(glm::vec<L, T, Q> p0, glm::vec<L, T, Q> p1, glm::vec<L, T, Q> v0, glm::vec<L, T, Q> v1);

[[nodiscard]] glm::vec<L, T, Q> PositionAt(T t) const;
[[nodiscard]] glm::vec<L, T, Q> VelocityAt(T t) const;
[[nodiscard]] glm::vec<L, T, Q> AccelerationAt(T t) const;
};

using ZoomInterpolator3f = ZoomInterpolatorVec<3, float, glm::defaultp>;

} // namespace openblack
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ endmacro ()
openblack_setup_and_add_test(test_game_initialize test_game_initialize.cpp)
openblack_setup_and_add_test(test_load_scene test_load_scene.cpp)
openblack_setup_and_add_test(test_fixed test_fixed.cpp)
openblack_setup_and_add_test(test_interpolator test_interpolator.cpp)
openblack_setup_and_add_json_test(
test_mobile_wall_hug mobile_wall_hug/test_mobile_wall_hug.cpp
)

0 comments on commit 6dce747

Please sign in to comment.