diff --git a/config/Sources.cmake b/config/Sources.cmake index 6cf9c6f4663c4307ee6c9350941cbe6e2f2b5a2c..1b3af31e82a5475d7d0791848fee123d62bf917c 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -54,6 +54,8 @@ set(vkcv_sources ${vkcv_include}/vkcv/PipelineConfig.hpp ${vkcv_source}/vkcv/PipelineConfig.cpp + ${vkcv_include}/vkcv/Interpolation.hpp + ${vkcv_include}/vkcv/Logger.hpp ${vkcv_include}/vkcv/ShaderStage.hpp diff --git a/include/vkcv/Interpolation.hpp b/include/vkcv/Interpolation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c38a7aa746e36a3a58a0c3dd1c94db549ba101e7 --- /dev/null +++ b/include/vkcv/Interpolation.hpp @@ -0,0 +1,121 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/Interpolation.hpp + * @brief Structure for interpolation + */ + +#include <algorithm> +#include <cmath> +#include <functional> +#include <vector> + +namespace vkcv { + + template<typename V, typename T = double> + struct interpolation_function { + typedef std::function<V(const V&, const V&, T)> type; + }; + + template<typename V, typename T = double> + struct interpolation_state { + T time; + V value; + + bool operator<(const interpolation_state& other) const { + return time < other.time; + } + }; + + template<typename V, typename T = double> + struct interpolation { + private: + typename interpolation_function<V, T>::type m_function; + std::vector< interpolation_state<V, T> > m_states; + + public: + interpolation(const typename interpolation_function<V, T>::type& function) + : m_function(function), m_states() {} + + interpolation(const interpolation& other) = default; + interpolation(interpolation&& other) noexcept = default; + + ~interpolation() = default; + + interpolation& operator=(const interpolation& other) = default; + interpolation& operator=(interpolation&& other) noexcept = default; + + void clear() { + m_states.clear(); + } + + void add(T time, const V& value) { + interpolation_state<V, T> state; + state.time = time; + state.value = value; + m_states.insert( + std::lower_bound(m_states.begin(), m_states.end(), state), + state + ); + } + + V operator()(T time) const { + interpolation_state<V, T> state; + state.time = time; + + auto end = std::lower_bound(m_states.begin(), m_states.end(), state); + auto start = end != m_states.begin()? (end - 1) : m_states.begin(); + + if (end == m_states.end()) { + end = start; + } + + const T ratio = (time - (*start).time) / ((*end).time - (*start).time); + + return m_function( + (*start).value, + (*end).value, + std::clamp<T>( + ratio, + static_cast<T>(0), + static_cast<T>(1) + ) + ); + } + + }; + + template<typename V, typename T = double> + interpolation<V, T> linearInterpolation() { + return interpolation<V, T>([](const V& start, const V& end, T ratio) { + return start * (static_cast<T>(1) - ratio) + end * ratio; + }); + } + + template<typename V, typename T = double> + interpolation<V, T> cubicInterpolation() { + return interpolation<V, T>([](const V& start, const V& end, T ratio) { + const T r0 = (static_cast<T>(1) - ratio) * (static_cast<T>(1) - ratio); + const T r1 = ratio * ratio; + + return ( + start * r0 + + start * r0 * ratio * static_cast<T>(2) + + end * r1 * (static_cast<T>(1) - ratio) * static_cast<T>(2) + + end * r1 + ); + }); + } + + template<typename V, typename T = double> + interpolation<V, T> cosInterpolation() { + return interpolation<V, T>([](const V& start, const V& end, T ratio) { + const T cos_ratio = (static_cast<T>(1) - std::cos( + ratio * static_cast<T>(M_PI) + )) / static_cast<T>(2); + + return start * (static_cast<T>(1) - cos_ratio) + end * cos_ratio; + }); + } + +} \ No newline at end of file diff --git a/modules/camera/CMakeLists.txt b/modules/camera/CMakeLists.txt index 0bc5ce6cbbab55abebce376820f2ba398267cdd5..dbe5c85c0ae839a0b0ab8c3de059c442d22f2d59 100644 --- a/modules/camera/CMakeLists.txt +++ b/modules/camera/CMakeLists.txt @@ -18,8 +18,6 @@ set(vkcv_camera_sources ${vkcv_camera_source}/vkcv/camera/PilotCameraController.cpp ${vkcv_camera_include}/vkcv/camera/TrackballCameraController.hpp ${vkcv_camera_source}/vkcv/camera/TrackballCameraController.cpp - ${vkcv_camera_include}/vkcv/camera/InterpolationLinear.hpp - ${vkcv_camera_source}/vkcv/camera/InterpolationLinear.cpp ) # adding source files to the project diff --git a/modules/camera/include/vkcv/camera/InterpolationLinear.hpp b/modules/camera/include/vkcv/camera/InterpolationLinear.hpp deleted file mode 100644 index cdcf0af62603b6db642a2db81ec610ab8e48cedc..0000000000000000000000000000000000000000 --- a/modules/camera/include/vkcv/camera/InterpolationLinear.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#include <glm/glm.hpp> -#include <GLFW/glfw3.h> -#include <vkcv/camera/Camera.hpp> -#include <vector> - -namespace vkcv::camera { - - class InterpolationLinear{ - - private: - - Camera& m_camera; - double m_timeSinceStart; - std::vector<glm::vec3> m_positions; - - - public: - - InterpolationLinear(Camera &camera); - - /** - * @brief Add position vector to be approached. The positions are approached in the order in which they where added. - * - * @param pos - */ - void addPosition(const glm::vec3& pos); - - /** - * @brief Set the Camera object - * - * @param camera - */ - void setCamera(Camera camera); - - /** - * @brief Resets timer - * - */ - void resetTimer(); - - /** - * @brief Updates the camera with the interpolated position values - * - */ - void updateCamera(); - }; - -} \ No newline at end of file diff --git a/modules/camera/src/vkcv/camera/InterpolationLinear.cpp b/modules/camera/src/vkcv/camera/InterpolationLinear.cpp deleted file mode 100644 index ac73f095f00d5a755dbda34d062e29b11508bd32..0000000000000000000000000000000000000000 --- a/modules/camera/src/vkcv/camera/InterpolationLinear.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "vkcv/camera/InterpolationLinear.hpp" -#include <vkcv/Logger.hpp> -#include <iostream> - - -namespace vkcv::camera { - - InterpolationLinear::InterpolationLinear(Camera &camera) - : m_camera(camera) { - resetTimer(); - } - - void InterpolationLinear::resetTimer() { - m_timeSinceStart = glfwGetTime(); - } - - void InterpolationLinear::addPosition(const glm::vec3& pos) { - m_positions.push_back(pos); - } - - glm::vec3 interpolate(glm::vec3 posA, glm::vec3 posB, double time, double duration) { - glm::vec3 posDiff = posB - posA; - glm::vec3 posInterp = posA + (posDiff * static_cast<float>(time / duration)); - return posInterp; - } - - void InterpolationLinear::updateCamera() { - - if (m_positions.size() < 2) { - vkcv_log(LogLevel::ERROR, "At least 2 positions needed for interpolation."); - return; - } - double t = glfwGetTime() - m_timeSinceStart; - double segmentDuration = 2.0; - int numberOfSegments = m_positions.size()-1; - double totalDuration = numberOfSegments * segmentDuration; - double modt = fmod(t, totalDuration); - - int currentSegment = static_cast<int>((modt / totalDuration) * numberOfSegments); - - glm::vec3 posInterp = interpolate(m_positions[currentSegment], m_positions[currentSegment+1], fmod(modt, segmentDuration), segmentDuration); - - // const glm::vec3 front = m_camera.getFront(); - // const glm::vec3 up = m_camera.getUp(); - - // m_camera.lookAt(posInterp, front+posInterp, up); - - m_camera.setPosition(posInterp); // always look at center - } -} \ No newline at end of file diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index cc6d93a2efa37f3b3f1d6a45fe03a28ace686226..0070b51eb51f81422af49b641a860f75ec832b3f 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -1,11 +1,10 @@ #include <iostream> #include <vkcv/Core.hpp> #include <vkcv/Image.hpp> +#include <vkcv/Interpolation.hpp> #include <vkcv/Pass.hpp> #include <vkcv/Sampler.hpp> #include <vkcv/camera/CameraManager.hpp> -#include <vkcv/camera/InterpolationLinear.hpp> -#include <chrono> #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> @@ -115,14 +114,14 @@ int main(int argc, const char** argv) { cameraManager.getCamera(camHandle1).setPosition(glm::vec3(0, 0, -3)); cameraManager.getCamera(camHandle2).setPosition(glm::vec3(0, 0, -3)); - vkcv::camera::InterpolationLinear interp (cameraManager.getCamera(camHandle0)); + auto interp = vkcv::linearInterpolation<glm::vec3, float>(); - interp.addPosition(glm::vec3(5,5,-5)); - interp.addPosition(glm::vec3(0,5,-5)); - interp.addPosition(glm::vec3(0,-3,-3)); - interp.addPosition(glm::vec3(3,0,-6)); - interp.addPosition(glm::vec3(5,5,5)); - interp.addPosition(glm::vec3(5,5,-5)); + interp.add( 0.0f, glm::vec3(+5, +5, -5)); + interp.add( 2.0f, glm::vec3(+0, +5, -5)); + interp.add( 4.0f, glm::vec3(+0, -3, -3)); + interp.add( 6.0f, glm::vec3(+3, +0, -6)); + interp.add( 8.0f, glm::vec3(+5, +5, +5)); + interp.add(10.0f, glm::vec3(+5, +5, -5)); core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, uint32_t swapchainWidth, uint32_t swapchainHeight) { @@ -139,7 +138,9 @@ int main(int argc, const char** argv) { } cameraManager.update(dt); - interp.updateCamera(); + cameraManager.getCamera(camHandle0).setPosition( + interp(static_cast<float>(std::fmod<double>(t, 10.0))) + ); glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();