Skip to content
Snippets Groups Projects
Commit d7d49aa2 authored by Tobias Frisch's avatar Tobias Frisch
Browse files

Merge branch '54-kamera-kamerafahrt-mit-interpolation' into 'develop'

Resolve "Kamera - Kamerafahrt mit Interpolation"

Closes #54

See merge request !53
parents c39f5e51 b2bcd613
Branches
Tags
1 merge request!53Resolve "Kamera - Kamerafahrt mit Interpolation"
...@@ -54,6 +54,8 @@ set(vkcv_sources ...@@ -54,6 +54,8 @@ set(vkcv_sources
${vkcv_include}/vkcv/PipelineConfig.hpp ${vkcv_include}/vkcv/PipelineConfig.hpp
${vkcv_source}/vkcv/PipelineConfig.cpp ${vkcv_source}/vkcv/PipelineConfig.cpp
${vkcv_include}/vkcv/Interpolation.hpp
${vkcv_include}/vkcv/Logger.hpp ${vkcv_include}/vkcv/Logger.hpp
${vkcv_include}/vkcv/ShaderStage.hpp ${vkcv_include}/vkcv/ShaderStage.hpp
......
#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
...@@ -22,7 +22,6 @@ namespace vkcv::camera { ...@@ -22,7 +22,6 @@ namespace vkcv::camera {
* PilotCameraController. * PilotCameraController.
*/ */
class CameraController { class CameraController {
public: public:
/** /**
......
...@@ -108,12 +108,6 @@ namespace vkcv::camera { ...@@ -108,12 +108,6 @@ namespace vkcv::camera {
* @return The specified camera controller object. * @return The specified camera controller object.
*/ */
CameraController& getControllerByType(ControllerType controllerType); CameraController& getControllerByType(ControllerType controllerType);
/**
* @briof A method to get the currently active controller for the active camera.
* @return Reference to the active #CameraController
*/
CameraController& getActiveController();
public: public:
...@@ -152,12 +146,14 @@ namespace vkcv::camera { ...@@ -152,12 +146,14 @@ namespace vkcv::camera {
* @return The camera object by @p cameraHandle. * @return The camera object by @p cameraHandle.
* @throws std::runtime_error If @p cameraHandle is not a valid camera handle. * @throws std::runtime_error If @p cameraHandle is not a valid camera handle.
*/ */
[[nodiscard]]
Camera& getCamera(const CameraHandle& cameraHandle); Camera& getCamera(const CameraHandle& cameraHandle);
/** /**
* @brief Returns the stored camera object set as the active camera. * @brief Returns the stored camera object set as the active camera.
* @return The active camera. * @return The active camera.
*/ */
[[nodiscard]]
Camera& getActiveCamera(); Camera& getActiveCamera();
/** /**
...@@ -171,6 +167,7 @@ namespace vkcv::camera { ...@@ -171,6 +167,7 @@ namespace vkcv::camera {
* @brief Returns the handle of the stored active camera object. * @brief Returns the handle of the stored active camera object.
* @return The active camera handle. * @return The active camera handle.
*/ */
[[nodiscard]]
CameraHandle getActiveCameraHandle() const; CameraHandle getActiveCameraHandle() const;
/** /**
...@@ -188,6 +185,7 @@ namespace vkcv::camera { ...@@ -188,6 +185,7 @@ namespace vkcv::camera {
* @return The type of the camera controller of the specified camera object. * @return The type of the camera controller of the specified camera object.
* @throws std::runtime_error If @p cameraHandle is not a valid camera handle. * @throws std::runtime_error If @p cameraHandle is not a valid camera handle.
*/ */
[[nodiscard]]
ControllerType getControllerType(const CameraHandle& cameraHandle); ControllerType getControllerType(const CameraHandle& cameraHandle);
/** /**
......
...@@ -19,8 +19,7 @@ namespace vkcv::camera { ...@@ -19,8 +19,7 @@ namespace vkcv::camera {
enum class ControllerType { enum class ControllerType {
NONE, NONE,
PILOT, PILOT,
TRACKBALL, TRACKBALL
TRACE
}; };
/** @} */ /** @} */
......
...@@ -41,53 +41,78 @@ namespace vkcv::camera { ...@@ -41,53 +41,78 @@ namespace vkcv::camera {
} }
} }
void CameraManager::mouseButtonCallback(int button, int action, int mods){ void CameraManager::mouseButtonCallback(int button, int action, int mods) {
if(button == GLFW_MOUSE_BUTTON_2 && action == GLFW_PRESS){ const ControllerType type = getControllerType(getActiveCameraHandle());
if ((button == GLFW_MOUSE_BUTTON_2) && (action == GLFW_PRESS)) {
glfwSetInputMode(m_window.getWindow(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(m_window.getWindow(), GLFW_CURSOR, GLFW_CURSOR_DISABLED);
} } else
else if(button == GLFW_MOUSE_BUTTON_2 && action == GLFW_RELEASE){ if ((button == GLFW_MOUSE_BUTTON_2) && (action == GLFW_RELEASE)) {
glfwSetInputMode(m_window.getWindow(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(m_window.getWindow(), GLFW_CURSOR, GLFW_CURSOR_NORMAL);
} }
getActiveController().mouseButtonCallback(button, action, mods, getActiveCamera());
if (type == ControllerType::NONE) {
return;
}
getControllerByType(type).mouseButtonCallback(button, action, mods, getActiveCamera());
} }
void CameraManager::mouseMoveCallback(double x, double y){ void CameraManager::mouseMoveCallback(double x, double y) {
const ControllerType type = getControllerType(getActiveCameraHandle());
auto xoffset = static_cast<float>(x - m_lastX) / m_window.getWidth(); auto xoffset = static_cast<float>(x - m_lastX) / m_window.getWidth();
auto yoffset = static_cast<float>(y - m_lastY) / m_window.getHeight(); auto yoffset = static_cast<float>(y - m_lastY) / m_window.getHeight();
m_lastX = x; m_lastX = x;
m_lastY = y; m_lastY = y;
getActiveController().mouseMoveCallback(xoffset, yoffset, getActiveCamera());
if (type == ControllerType::NONE) {
return;
}
getControllerByType(type).mouseMoveCallback(xoffset, yoffset, getActiveCamera());
} }
void CameraManager::scrollCallback(double offsetX, double offsetY) { void CameraManager::scrollCallback(double offsetX, double offsetY) {
getActiveController().scrollCallback(offsetX, offsetY, getActiveCamera()); const ControllerType type = getControllerType(getActiveCameraHandle());
if (type == ControllerType::NONE) {
return;
}
getControllerByType(type).scrollCallback(offsetX, offsetY, getActiveCamera());
} }
void CameraManager::keyCallback(int key, int scancode, int action, int mods) { void CameraManager::keyCallback(int key, int scancode, int action, int mods) {
switch (action) { const ControllerType type = getControllerType(getActiveCameraHandle());
case GLFW_RELEASE:
switch (key) { if (action == GLFW_RELEASE) {
case GLFW_KEY_TAB: switch (key) {
if (m_activeCameraIndex + 1 == m_cameras.size()) { case GLFW_KEY_TAB:
m_activeCameraIndex = 0; if (m_activeCameraIndex + 1 == m_cameras.size()) {
} m_activeCameraIndex = 0;
else { } else {
m_activeCameraIndex++; m_activeCameraIndex++;
} }
return; return;
case GLFW_KEY_ESCAPE: case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(m_window.getWindow(), 1); glfwSetWindowShouldClose(m_window.getWindow(), 1);
return; return;
default: default:
break; break;
} }
default:
getActiveController().keyCallback(key, scancode, action, mods, getActiveCamera());
break;
} }
if (type == ControllerType::NONE) {
return;
}
getControllerByType(type).keyCallback(key, scancode, action, mods, getActiveCamera());
} }
void CameraManager::gamepadCallback(int gamepadIndex) { void CameraManager::gamepadCallback(int gamepadIndex) {
const ControllerType type = getControllerType(getActiveCameraHandle());
// handle camera switching // handle camera switching
GLFWgamepadstate gamepadState; GLFWgamepadstate gamepadState;
glfwGetGamepadState(gamepadIndex, &gamepadState); glfwGetGamepadState(gamepadIndex, &gamepadState);
...@@ -96,22 +121,23 @@ namespace vkcv::camera { ...@@ -96,22 +121,23 @@ namespace vkcv::camera {
if (time - m_inputDelayTimer > 0.2) { if (time - m_inputDelayTimer > 0.2) {
int switchDirection = gamepadState.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] - gamepadState.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT]; int switchDirection = gamepadState.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] - gamepadState.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT];
m_activeCameraIndex += switchDirection; m_activeCameraIndex += switchDirection;
if (std::greater<int>{}(m_activeCameraIndex, m_cameras.size() - 1)) {
if (std::greater<int>{}(m_activeCameraIndex, m_cameras.size() - 1)) {
m_activeCameraIndex = 0; m_activeCameraIndex = 0;
} } else
else if (std::less<int>{}(m_activeCameraIndex, 0)) { if (std::less<int>{}(m_activeCameraIndex, 0)) {
m_activeCameraIndex = m_cameras.size() - 1; m_activeCameraIndex = m_cameras.size() - 1;
} }
uint32_t triggered = abs(switchDirection); uint32_t triggered = abs(switchDirection);
m_inputDelayTimer = (1-triggered)*m_inputDelayTimer + triggered * time; // Only reset timer, if dpad was pressed - is this cheaper than if-clause? m_inputDelayTimer = (1-triggered)*m_inputDelayTimer + triggered * time; // Only reset timer, if dpad was pressed - is this cheaper than if-clause?
} }
getActiveController().gamepadCallback(gamepadIndex, getActiveCamera(), m_frameTime); // handle camera rotation, translation if (type == ControllerType::NONE) {
} return;
}
CameraController& CameraManager::getActiveController() {
const ControllerType type = getControllerType(getActiveCameraHandle()); getControllerByType(type).gamepadCallback(gamepadIndex, getActiveCamera(), m_frameTime); // handle camera rotation, translation
return getControllerByType(type);
} }
CameraHandle CameraManager::addCamera(ControllerType controllerType) { CameraHandle CameraManager::addCamera(ControllerType controllerType) {
...@@ -185,9 +211,17 @@ namespace vkcv::camera { ...@@ -185,9 +211,17 @@ namespace vkcv::camera {
} }
void CameraManager::update(double deltaTime) { void CameraManager::update(double deltaTime) {
m_frameTime = deltaTime; const ControllerType type = getControllerType(getActiveCameraHandle());
if (type != ControllerType::NONE) {
m_frameTime = deltaTime;
} else {
m_frameTime = 0.0;
return;
}
if (glfwGetWindowAttrib(m_window.getWindow(), GLFW_FOCUSED) == GLFW_TRUE) { if (glfwGetWindowAttrib(m_window.getWindow(), GLFW_FOCUSED) == GLFW_TRUE) {
getActiveController().updateCamera(deltaTime, getActiveCamera()); getControllerByType(type).updateCamera(m_frameTime, getActiveCamera());
} }
} }
......
#include <iostream> #include <iostream>
#include <vkcv/Core.hpp> #include <vkcv/Core.hpp>
#include <vkcv/Image.hpp> #include <vkcv/Image.hpp>
#include <vkcv/Interpolation.hpp>
#include <vkcv/Pass.hpp> #include <vkcv/Pass.hpp>
#include <vkcv/Sampler.hpp> #include <vkcv/Sampler.hpp>
#include <vkcv/camera/CameraManager.hpp> #include <vkcv/camera/CameraManager.hpp>
#include <vkcv/asset/asset_loader.hpp> #include <vkcv/asset/asset_loader.hpp>
#include <vkcv/shader/GLSLCompiler.hpp> #include <vkcv/shader/GLSLCompiler.hpp>
...@@ -104,9 +106,22 @@ int main(int argc, const char** argv) { ...@@ -104,9 +106,22 @@ int main(int argc, const char** argv) {
drawcall.useDescriptorSet(0, descriptorSet); drawcall.useDescriptorSet(0, descriptorSet);
vkcv::camera::CameraManager cameraManager(window); vkcv::camera::CameraManager cameraManager(window);
auto camHandle = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
cameraManager.getCamera(camHandle).setPosition(glm::vec3(0, 0, -3)); auto camHandle0 = cameraManager.addCamera(vkcv::camera::ControllerType::NONE);
auto camHandle1 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
auto camHandle2 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL);
cameraManager.getCamera(camHandle1).setPosition(glm::vec3(0, 0, -3));
cameraManager.getCamera(camHandle2).setPosition(glm::vec3(0, 0, -3));
auto interp = vkcv::linearInterpolation<glm::vec3, float>();
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, core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt,
uint32_t swapchainWidth, uint32_t swapchainHeight) { uint32_t swapchainWidth, uint32_t swapchainHeight) {
...@@ -123,6 +138,10 @@ int main(int argc, const char** argv) { ...@@ -123,6 +138,10 @@ int main(int argc, const char** argv) {
} }
cameraManager.update(dt); cameraManager.update(dt);
cameraManager.getCamera(camHandle0).setPosition(
interp(static_cast<float>(std::fmod<double>(t, 10.0)))
);
glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();
vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>(); vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment