diff --git a/src/animation/spring.hpp b/src/animation/spring.hpp new file mode 100644 index 0000000..bb6bb95 --- /dev/null +++ b/src/animation/spring.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_SPRING_HPP +#define ANTKEEPER_SPRING_HPP + +/** + * Performs numeric, damped springing on a value and velocity. + * + * @tparam T Value type. + * @tparam S Scalar type. + * + * @param[in,out] x0 Start value, which will be oscillated by this function. + * @param[in,out] v Velocity, which will be modified by this function. + * @param[in] x1 End value. + * @param[in] z Damping ratio, which can be undamped (z = 0), underdamped (z < 1), critically damped (z = 1), or overdamped (z > 1). + * @param[in] w Angular frequency of the oscillation, in radians per second (2pi = 1Hz). + * @param[in] dt Delta time, in seconds. + */ +template +void spring(T& x0, T& v, const T& x1, S z, S w, S dt); + +template +void spring(T& x0, T& v, const T& x1, S z, S w, S dt) +{ + const S w2_dt = w * w * dt; + const S w2_dt2 = w2_dt * dt; + const S f = z * w * dt * S(2) + S(1); + const T det_x = x0 * f + v * dt + x1 * w2_dt2; + const T det_v = v + (x1 - x0) * w2_dt; + const S inv_det = S(1) / (f + w2_dt2); + + x0 = det_x * inv_det; + v = det_v * inv_det; +} + +#endif // ANTKEEPER_SPRING_HPP diff --git a/src/game/bootloader.cpp b/src/game/bootloader.cpp index f5a6dd6..a8b2977 100644 --- a/src/game/bootloader.cpp +++ b/src/game/bootloader.cpp @@ -888,12 +888,12 @@ void setup_controls(game_context* ctx) ctx->rotate_ccw_control = new control(); ctx->rotate_ccw_control->set_activated_callback ( - std::bind(&camera_system::rotate, ctx->camera_system, math::radians(-45.0f)) + std::bind(&camera_system::rotate, ctx->camera_system, math::radians(-90.0f)) ); ctx->rotate_cw_control = new control(); ctx->rotate_cw_control->set_activated_callback ( - std::bind(&camera_system::rotate, ctx->camera_system, math::radians(45.0f)) + std::bind(&camera_system::rotate, ctx->camera_system, math::radians(90.0f)) ); // Create menu back control diff --git a/src/game/systems/camera-system.cpp b/src/game/systems/camera-system.cpp index dc0e3d2..3518442 100644 --- a/src/game/systems/camera-system.cpp +++ b/src/game/systems/camera-system.cpp @@ -20,6 +20,7 @@ #include "camera-system.hpp" #include "game/components/camera-subject-component.hpp" #include "game/components/transform-component.hpp" +#include "animation/spring.hpp" #include "scene/camera.hpp" #include "math/math.hpp" #include @@ -69,12 +70,16 @@ void camera_system::update(double t, double dt) float source_azimuth = math::wrap_radians(std::atan2(-xz_direction.y, xz_direction.x) - math::half_pi); float source_elevation = elevation; - std::cout << "azimuth: " << math::degrees(azimuth) << "\n"; - std::cout << "source azimuth: " << math::degrees(source_azimuth) << "\n"; - float smooth_factor = 0.1f; float smooth_azimuth = math::lerp_angle(source_azimuth, azimuth, smooth_factor); float smooth_elevation = math::lerp_angle(source_elevation, elevation, smooth_factor); + + + smooth_azimuth = source_azimuth; + float shortest_angle = math::wrap_radians(azimuth - source_azimuth); + static float velocity = 0.0f; + spring(smooth_azimuth, velocity, smooth_azimuth + shortest_angle, 1.0f, 2.0f * math::two_pi, dt); + quaternion_type smooth_azimuth_rotation = math::angle_axis(smooth_azimuth, float3{0.0f, 1.0f, 0.0f}); quaternion_type smooth_elevation_rotation = math::angle_axis(smooth_elevation, float3{-1.0f, 0.0f, 0.0f}); quaternion_type smooth_rotation = math::normalize(smooth_azimuth_rotation * smooth_elevation_rotation);