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
No related branches found
No related tags found
1 merge request!53Resolve "Kamera - Kamerafahrt mit Interpolation"
......@@ -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
......
#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 {
* PilotCameraController.
*/
class CameraController {
public:
/**
......
......@@ -108,12 +108,6 @@ namespace vkcv::camera {
* @return The specified camera controller object.
*/
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:
......@@ -152,12 +146,14 @@ namespace vkcv::camera {
* @return The camera object by @p cameraHandle.
* @throws std::runtime_error If @p cameraHandle is not a valid camera handle.
*/
[[nodiscard]]
Camera& getCamera(const CameraHandle& cameraHandle);
/**
* @brief Returns the stored camera object set as the active camera.
* @return The active camera.
*/
[[nodiscard]]
Camera& getActiveCamera();
/**
......@@ -171,6 +167,7 @@ namespace vkcv::camera {
* @brief Returns the handle of the stored active camera object.
* @return The active camera handle.
*/
[[nodiscard]]
CameraHandle getActiveCameraHandle() const;
/**
......@@ -188,6 +185,7 @@ namespace vkcv::camera {
* @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.
*/
[[nodiscard]]
ControllerType getControllerType(const CameraHandle& cameraHandle);
/**
......
......@@ -19,8 +19,7 @@ namespace vkcv::camera {
enum class ControllerType {
NONE,
PILOT,
TRACKBALL,
TRACE
TRACKBALL
};
/** @} */
......
......@@ -41,53 +41,78 @@ namespace vkcv::camera {
}
}
void CameraManager::mouseButtonCallback(int button, int action, int mods){
if(button == GLFW_MOUSE_BUTTON_2 && action == GLFW_PRESS){
void CameraManager::mouseButtonCallback(int button, int action, int mods) {
const ControllerType type = getControllerType(getActiveCameraHandle());
if ((button == GLFW_MOUSE_BUTTON_2) && (action == GLFW_PRESS)) {
glfwSetInputMode(m_window.getWindow(), GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
else if(button == GLFW_MOUSE_BUTTON_2 && action == GLFW_RELEASE){
} else
if ((button == GLFW_MOUSE_BUTTON_2) && (action == GLFW_RELEASE)) {
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 yoffset = static_cast<float>(y - m_lastY) / m_window.getHeight();
m_lastX = x;
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) {
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) {
switch (action) {
case GLFW_RELEASE:
switch (key) {
case GLFW_KEY_TAB:
if (m_activeCameraIndex + 1 == m_cameras.size()) {
m_activeCameraIndex = 0;
}
else {
m_activeCameraIndex++;
}
return;
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(m_window.getWindow(), 1);
return;
default:
break;
}
default:
getActiveController().keyCallback(key, scancode, action, mods, getActiveCamera());
break;
const ControllerType type = getControllerType(getActiveCameraHandle());
if (action == GLFW_RELEASE) {
switch (key) {
case GLFW_KEY_TAB:
if (m_activeCameraIndex + 1 == m_cameras.size()) {
m_activeCameraIndex = 0;
} else {
m_activeCameraIndex++;
}
return;
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(m_window.getWindow(), 1);
return;
default:
break;
}
}
if (type == ControllerType::NONE) {
return;
}
getControllerByType(type).keyCallback(key, scancode, action, mods, getActiveCamera());
}
void CameraManager::gamepadCallback(int gamepadIndex) {
const ControllerType type = getControllerType(getActiveCameraHandle());
// handle camera switching
GLFWgamepadstate gamepadState;
glfwGetGamepadState(gamepadIndex, &gamepadState);
......@@ -96,22 +121,23 @@ namespace vkcv::camera {
if (time - m_inputDelayTimer > 0.2) {
int switchDirection = gamepadState.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] - gamepadState.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT];
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;
}
else if (std::less<int>{}(m_activeCameraIndex, 0)) {
} else
if (std::less<int>{}(m_activeCameraIndex, 0)) {
m_activeCameraIndex = m_cameras.size() - 1;
}
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?
}
getActiveController().gamepadCallback(gamepadIndex, getActiveCamera(), m_frameTime); // handle camera rotation, translation
}
CameraController& CameraManager::getActiveController() {
const ControllerType type = getControllerType(getActiveCameraHandle());
return getControllerByType(type);
if (type == ControllerType::NONE) {
return;
}
getControllerByType(type).gamepadCallback(gamepadIndex, getActiveCamera(), m_frameTime); // handle camera rotation, translation
}
CameraHandle CameraManager::addCamera(ControllerType controllerType) {
......@@ -185,9 +211,17 @@ namespace vkcv::camera {
}
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) {
getActiveController().updateCamera(deltaTime, getActiveCamera());
getControllerByType(type).updateCamera(m_frameTime, getActiveCamera());
}
}
......
#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/asset/asset_loader.hpp>
#include <vkcv/shader/GLSLCompiler.hpp>
......@@ -104,9 +106,22 @@ int main(int argc, const char** argv) {
drawcall.useDescriptorSet(0, descriptorSet);
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,
uint32_t swapchainWidth, uint32_t swapchainHeight) {
......@@ -123,6 +138,10 @@ int main(int argc, const char** argv) {
}
cameraManager.update(dt);
cameraManager.getCamera(camHandle0).setPosition(
interp(static_cast<float>(std::fmod<double>(t, 10.0)))
);
glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();
vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment