diff --git a/modules/camera/CMakeLists.txt b/modules/camera/CMakeLists.txt index 28080bf2b1cd3bbc88d6c13d7ef26a43d7c3e19a..73f2dd1c81be9c6cadf563f7936bfaba8c1d0025 100644 --- a/modules/camera/CMakeLists.txt +++ b/modules/camera/CMakeLists.txt @@ -11,10 +11,13 @@ set(vkcv_camera_include ${PROJECT_SOURCE_DIR}/include) set(vkcv_camera_sources ${vkcv_camera_include}/vkcv/camera/Camera.hpp ${vkcv_camera_source}/vkcv/camera/Camera.cpp - ${vkcv_camera_include}/vkcv/camera/TrackballCamera.hpp - ${vkcv_camera_source}/vkcv/camera/TrackballCamera.cpp ${vkcv_camera_include}/vkcv/camera/CameraManager.hpp ${vkcv_camera_source}/vkcv/camera/CameraManager.cpp + ${vkcv_camera_include}/vkcv/camera/CameraController.hpp + ${vkcv_camera_include}/vkcv/camera/PilotCameraController.hpp + ${vkcv_camera_source}/vkcv/camera/PilotCameraController.cpp + ${vkcv_camera_include}/vkcv/camera/TrackballCameraController.hpp + ${vkcv_camera_source}/vkcv/camera/TrackballCameraController.cpp ) # adding source files to the project diff --git a/modules/camera/include/vkcv/camera/Camera.hpp b/modules/camera/include/vkcv/camera/Camera.hpp index ff8fda811eaad7a99dbb940601f9e5904025255e..dc9f2dcb3038655f51fb2404abc21f98a2120399 100644 --- a/modules/camera/include/vkcv/camera/Camera.hpp +++ b/modules/camera/include/vkcv/camera/Camera.hpp @@ -1,101 +1,199 @@ #pragma once +#define GLM_DEPTH_ZERO_TO_ONE +#define GLM_FORCE_LEFT_HANDED #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_access.hpp> -namespace vkcv { +namespace vkcv::camera { - class Camera { + /** + * @brief Used to create a camera which governs the view and projection matrices. + */ + class Camera final { protected: glm::mat4 m_view; glm::mat4 m_projection; - int m_width; - int m_height; - float m_near; float m_far; - float m_fov; - float m_ratio; - glm::vec3 m_up; + glm::vec3 m_up; glm::vec3 m_position; - float m_cameraSpeed; + glm::vec3 m_center; + float m_pitch; float m_yaw; - - int m_fov_nsteps; - float m_fov_min; - float m_fov_max; - - bool m_forward; - bool m_backward; - bool m_left; - bool m_right; + + /** + * @brief Sets the view matrix of the camera to @p view + * @param[in] view The view matrix + */ + void setView(const glm::mat4& view); + + /** + * @brief Sets the projection matrix of the camera to @p projection + * @param[in] projection The projection matrix + */ + void setProjection(const glm::mat4& projection); public: - Camera(); - virtual ~Camera(); + /** + * @brief The default constructor of the camera + */ + Camera(); + /** + * @brief The destructor of the camera (default behavior) + */ + ~Camera(); + + /** + * @brief Sets the perspective object according to @p fov, @p ratio, @p near and @p far. This leads to changes in the projection matrix of the camera + * @param[in] fov The desired field of view in radians + * @param[in] ratio The aspect ratio + * @param[in] near Distance to near clipping plane + * @param[in] far Distance to far clipping plane + */ void setPerspective(float fov, float ratio, float near, float far); - const glm::mat4 getView() const; - - void getView(glm::vec3 &x, glm::vec3 &y, glm::vec3 &z, glm::vec3 &pos); - - glm::mat4 updateView(double deltatime); - - void lookAt(glm::vec3 position, glm::vec3 center, glm::vec3 up); - + /** + * @brief Gets the view matrix of the camera + * @return The view matrix of the camera + */ + const glm::mat4& getView() const; + + /** + * @brief Sets the view matrix of the camera according to @p position, @p center and @p up + * @param[in] position The position of the camera + * @param[in] center The target position the camera is looking at + * @param[in] up The vector that defines which direction is 'up' depending on the camera's orientation + */ + void lookAt(const glm::vec3& position, const glm::vec3& center, const glm::vec3& up); + + /** + * @brief Gets the current projection of the camera + * @return The current projection matrix + */ const glm::mat4& getProjection() const; - void setProjection(const glm::mat4 projection); - + /** + * @brief Gets the model-view-projection matrix of the camera with y-axis-correction applied + * @return The model-view-projection matrix + */ + glm::mat4 getMVP() const; + + /** + * @brief Gets the near and far bounds of the view frustum of the camera. + * @param[out] near The near bound of the view frustum + * @param[out] far The far bound of the view frustum + */ void getNearFar(float &near, float &far) const; - void setUp(const glm::vec3 &Up); - + /** + * @brief Gets the current field of view of the camera in radians + * @return[in] The current field of view in radians + */ float getFov() const; + /** + * @brief Sets the field of view of the camera to @p fov in radians + * @param[in] fov The new field of view in radians + */ void setFov(float fov); - - void changeFov(double fov); - - void updateRatio(int width, int height); + /** + * @brief Gets the current aspect ratio of the camera + * @return The current aspect ratio of the camera + */ float getRatio() const; + /** + * @brief Updates the aspect ratio of the camera with @p ratio and, thus, changes the projection matrix + * @param[in] ratio The new aspect ratio of the camera + */ + void setRatio(float ratio); + + /** + * @brief Sets @p near and @p far as new values for the view frustum of the camera. This leads to changes in the projection matrix according to these two values. + * @param[in] near The new near bound of the view frustum + * @param[in] far The new far bound of the view frustum + */ void setNearFar(float near, float far); + /** + * @brief Gets the current front vector of the camera in world space + * @return The current front vector of the camera + */ glm::vec3 getFront() const; - - glm::vec3 getPosition() const; - - void setPosition( glm::vec3 position ); - + + /** + * @brief Sets the front vector of the camera in world space to @p front + * @param[in] front The new front vector of the camera + */ + void setFront(const glm::vec3& front); + + /** + * @brief Gets the current position of the camera in world space + * @return The current position of the camera in world space + */ + const glm::vec3& getPosition() const; + + /** + * @brief Sets the position of the camera to @p position + * @param[in] position The new position of the camera + */ + void setPosition( const glm::vec3& position ); + + /** + * @brief Gets the center point. + * @return The center point. + */ + const glm::vec3& getCenter() const; + + /** + * @brief Sets @p center as the new center point. + * @param[in] center The new center point. + */ + void setCenter(const glm::vec3& center); + + /** + * @brief Gets the pitch value of the camera in degrees. + * @return The pitch value in degrees. + */ float getPitch() const; + /** + * @brief Sets the pitch value of the camera to @p pitch in degrees. + * @param[in] pitch The new pitch value in degrees. + */ void setPitch(float pitch); + /** + * @brief Gets the yaw value of the camera in degrees. + * @return The yaw value in degrees. + */ float getYaw() const; + /** + * @brief Sets the yaw value of the camera to @p yaw. + * @param[in] yaw The new yaw value in degrees. + */ void setYaw(float yaw); - void panView( double xOffset, double yOffset ); - - void updatePosition(double deltatime); - - void moveForward(int action); - - void moveBackward(int action); - - void moveLeft(int action); - - void moveRight(int action); - - + /** + * @brief Gets the up vector. + * @return The up vector. + */ + const glm::vec3& getUp() const; + + /** + * @brief Sets @p up as the new up vector. + * @param[in] up The new up vector. + */ + void setUp(const glm::vec3 &up); }; } diff --git a/modules/camera/include/vkcv/camera/CameraController.hpp b/modules/camera/include/vkcv/camera/CameraController.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5fe7aba586068beff15525617d8e4817662746b7 --- /dev/null +++ b/modules/camera/include/vkcv/camera/CameraController.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "Camera.hpp" +#include "vkcv/Window.hpp" + +namespace vkcv::camera { + + /** + * @brief Used as a base class for defining camera controller classes with different behaviors, e.g. the + * #PilotCameraController. + */ + class CameraController { + + public: + + /** + * @brief The constructor of the #CameraController (default behavior). + */ + CameraController() = default; + + /** + * @brief Updates @p camera in respect to @p deltaTime. + * @param[in] deltaTime The time that has passed since last update. + * @param[in] camera The camera object. + */ + virtual void updateCamera(double deltaTime, Camera &camera) = 0; + + /** + * @brief A callback function for key events. + * @param[in] key The keyboard key. + * @param[in] scancode The platform-specific scancode. + * @param[in] action The key action. + * @param[in] mods The modifier bits. + * @param[in] camera The camera object. + */ + virtual void keyCallback(int key, int scancode, int action, int mods, Camera &camera) = 0; + + /** + * @brief A callback function for mouse scrolling events. + * @param[in] offsetX The offset in horizontal direction. + * @param[in] offsetY The offset in vertical direction. + * @param[in] camera The camera object. + */ + virtual void scrollCallback( double offsetX, double offsetY, Camera &camera) = 0; + + /** + * @brief A callback function for mouse movement events. + * @param[in] x The horizontal mouse position. + * @param[in] y The vertical mouse position. + * @param[in] camera The camera object. + */ + virtual void mouseMoveCallback(double offsetX, double offsetY, Camera &camera) = 0; + + /** + * @brief A callback function for mouse button events. + * @param[in] button The mouse button. + * @param[in] action The button action. + * @param[in] mods The modifier bits. + * @param[in] camera The camera object. + */ + virtual void mouseButtonCallback(int button, int action, int mods, Camera &camera) = 0; + }; + +} \ No newline at end of file diff --git a/modules/camera/include/vkcv/camera/CameraManager.hpp b/modules/camera/include/vkcv/camera/CameraManager.hpp index 4e52eccea25e8544a9a5cc89d0dc74ddd0e023c6..69c4b311a561b9f3ce27e3d9906d68f21e2334ac 100644 --- a/modules/camera/include/vkcv/camera/CameraManager.hpp +++ b/modules/camera/include/vkcv/camera/CameraManager.hpp @@ -1,40 +1,186 @@ #pragma once -#include "TrackballCamera.hpp" +#include "PilotCameraController.hpp" +#include "TrackballCameraController.hpp" +#include "CameraController.hpp" #include "vkcv/Window.hpp" #include <GLFW/glfw3.h> #include <functional> -namespace vkcv{ +namespace vkcv::camera { + /** + * @brief Used for specifying existing types of camera controllers when adding a new controller object to the + * #CameraManager. + */ + enum class ControllerType { + NONE, + PILOT, + TRACKBALL, + TRACE + }; + + /** + * @brief Used for managing an arbitrary amount of camera controllers. + */ class CameraManager{ private: - std::function<void(int, int, int, int)> e_keyHandle; - std::function<void(double, double)> e_mouseMoveHandle; - std::function<void(double, double)> e_mouseScrollHandle; - std::function<void(int, int, int)> e_mouseButtonHandle; - std::function<void(int, int)> e_resizeHandle; - - Window &m_window; - Camera m_camera; - float m_width; - float m_height; -// std::shared_ptr<vkcv::TrackballCamera> m_trackball; - - bool m_roationActive = false; - double m_lastX ; - double m_lastY ; - - void bindCamera(); + std::function<void(int, int, int, int)> m_keyHandle; + std::function<void(double, double)> m_mouseMoveHandle; + std::function<void(double, double)> m_mouseScrollHandle; + std::function<void(int, int, int)> m_mouseButtonHandle; + std::function<void(int, int)> m_resizeHandle; + + Window& m_window; + std::vector<Camera> m_cameras; + std::vector<ControllerType> m_cameraControllerTypes; + uint32_t m_activeCameraIndex; + + PilotCameraController m_pilotController; + TrackballCameraController m_trackController; + + double m_lastX; + double m_lastY; + + /** + * @brief Binds the camera object to the window event handles. + */ + void bindCameraToEvents(); + + /** + * @brief A callback function for key events. Currently, cycling between all existing camera controllers via Tab, + * window closure via Esc and polling key events from the active camera controller are supported. + * @param[in] key The keyboard key. + * @param[in] scancode The platform-specific scancode. + * @param[in] action The key action. + * @param[in] mods The modifier bits. + */ void keyCallback(int key, int scancode, int action, int mods); - void scrollCallback( double offsetX, double offsetY); - void mouseMoveCallback( double offsetX, double offsetY); + + /** + * @brief A callback function for mouse scrolling events. + * @param[in] offsetX The offset in horizontal direction. + * @param[in] offsetY The offset in vertical direction. + */ + void scrollCallback(double offsetX, double offsetY); + + /** + * @brief A callback function for mouse movement events. + * @param[in] x The horizontal mouse position. + * @param[in] y The vertical mouse position. + */ + void mouseMoveCallback(double x, double y); + + /** + * @brief A callback function for mouse button events. + * @param[in] button The mouse button. + * @param[in] action The button action. + * @param[in] mods The modifier bits. + */ void mouseButtonCallback(int button, int action, int mods); + + /** + * @brief A callback function for handling the window resizing event. Each existing camera is resized in respect + * of the window size. + * @param[in] width The new width of the window. + * @param[in] height The new height of the window. + */ void resizeCallback(int width, int height); + + /** + * @brief Gets a camera controller object of specified @p controllerType. + * @param[in] controllerType The type of the camera controller. + * @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: - CameraManager(Window &window, float width, float height, glm::vec3 up = glm::vec3(0.0f,-1.0f,0.0f), glm::vec3 position = glm::vec3(0.0f,0.0f,0.0f)); - Camera &getCamera(); + /** + * @brief The constructor of the #CameraManager. + * @param[in] window The window. + * @param[in] width The width of the window. + * @param[in] height The height of the window. + */ + CameraManager(Window &window, float width, float height); + + /** + * @brief The destructor of the #CameraManager. Destroying the #CameraManager leads to deletion of all stored + * camera objects and camera controller objects. + */ + ~CameraManager(); + + /** + * @brief Adds a new camera object to the #CameraManager and binds it to a camera controller object of specified + * @p controllerType. + * @param[in] controllerType The type of the camera controller. + * @return The index of the newly created camera object. + */ + uint32_t addCamera(ControllerType controllerType = ControllerType::NONE); + + /** + * @brief Adds a new camera object to the #CameraManager and binds it to a camera controller object of specified + * @p controllerType. + * @param[in] controllerType The type of the camera controller. + * @param[in] camera The new camera object. + * @return The index of the newly bound camera object. + */ + uint32_t addCamera(ControllerType controllerType, const Camera& camera); + + /** + * @brief Gets the stored camera object located at @p cameraIndex. + * @param[in] cameraIndex The camera index. + * @return The camera object at @p cameraIndex. + * @throws std::runtime_error If @p cameraIndex is not a valid camera index. + */ + Camera& getCamera(uint32_t cameraIndex); + + /** + * @brief Gets the stored camera object set as the active camera. + * @return The active camera. + */ + Camera& getActiveCamera(); + + /** + * @brief Sets the stored camera object located at @p cameraIndex as the active camera. + * @param[in] cameraIndex The camera index. + * @throws std::runtime_error If @p cameraIndex is not a valid camera index. + */ + void setActiveCamera(uint32_t cameraIndex); + + /** + * @brief Gets the index of the stored active camera object. + * @return The active camera index. + */ + uint32_t getActiveCameraIndex() const; + + /** + * @brief Binds a stored camera object located at @p cameraIndex to a camera controller of specified + * @p controllerType. + * @param[in] cameraIndex The camera index. + * @param[in] controllerType The type of the camera controller. + * @throws std::runtime_error If @p cameraIndex is not a valid camera index. + */ + void setControllerType(uint32_t cameraIndex, ControllerType controllerType); + + /** + * @brief Gets the currently bound camera controller type of the stored camera object located at @p cameraIndex. + * @param[in] cameraIndex The camera index. + * @return The type of the camera controller of the specified camera object. + * @throws std::runtime_error If @p cameraIndex is not a valid camera index. + */ + ControllerType getControllerType(uint32_t cameraIndex); + + /** + * @brief Updates all stored camera controllers in respect to @p deltaTime. + * @param[in] deltaTime The time that has passed since last update. + */ + void update(double deltaTime); }; } diff --git a/modules/camera/include/vkcv/camera/PilotCameraController.hpp b/modules/camera/include/vkcv/camera/PilotCameraController.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c6a9f7c7ffa9a3be77f12c29e456291fb8f6b845 --- /dev/null +++ b/modules/camera/include/vkcv/camera/PilotCameraController.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include <vkcv/camera/CameraController.hpp> + +namespace vkcv::camera { + + /** + * @brief Used to move around a camera object in world space. + */ + class PilotCameraController final : public CameraController { + private: + // camera movement indicators + bool m_forward; + bool m_backward; + bool m_upward; + bool m_downward; + bool m_left; + bool m_right; + + bool m_rotationActive; + + float m_cameraSpeed; + + int m_fov_nsteps; + float m_fov_min; + float m_fov_max; + + /** + * @brief Indicates forward movement of the camera depending on the performed @p action. + * @param[in] action The performed action. + */ + void moveForward(int action); + + /** + * @brief Indicates backward movement of the camera depending on the performed @p action. + * @param[in] action The performed action. + */ + void moveBackward(int action); + + /** + * @brief Indicates left movement of the camera depending on the performed @p action. + * @param[in] action The performed action. + */ + void moveLeft(int action); + + /** + * @brief Indicates right movement of the camera depending on the performed @p action. + * @param[in] action The performed action. + */ + void moveRight(int action); + + /** + * @brief Indicates upward movement of the camera depending on the performed @p action. + * @param[in] action The performed action. + */ + void moveUpward(int action); + + /** + * @brief Indicates downward movement of the camera depending on the performed @p action. + * @param[in] action The performed action. + */ + void moveDownward(int action); + + public: + + /** + * @brief The default constructor of the #PilotCameraController. + */ + PilotCameraController(); + + /** + * @brief The destructor of the #PilotCameraController (default behavior). + */ + ~PilotCameraController() = default; + + /** + * @brief Changes the field of view of @p camera with an @p offset in degrees. + * @param[in] offset The offset in degrees. + * @param[in] camera The camera object. + */ + void changeFov(double offset, Camera &camera); + + /** + * @brief Pans the view of @p camera according to the pitch and yaw values and additional offsets @p xOffset + * and @p yOffset. + * @param[in] xOffset The offset added to the yaw value. + * @param[in] yOffset The offset added to the pitch value. + * @param[in] camera The camera object. + */ + void panView(double xOffset, double yOffset, Camera &camera); + + /** + * @brief Updates @p camera in respect to @p deltaTime. + * @param[in] deltaTime The time that has passed since last update. + * @param[in] camera The camera object. + */ + void updateCamera(double deltaTime, Camera &camera); + + /** + * @brief A callback function for key events. Currently, 3D camera movement via W, A, S, D, E, Q are supported. + * @param[in] key The keyboard key. + * @param[in] scancode The platform-specific scancode. + * @param[in] action The key action. + * @param[in] mods The modifier bits. + * @param[in] camera The camera object. + */ + void keyCallback(int key, int scancode, int action, int mods, Camera &camera); + + /** + * @brief A callback function for mouse scrolling events. Currently, this leads to changes in the field of view + * of @p camera. + * @param[in] offsetX The offset in horizontal direction. + * @param[in] offsetY The offset in vertical direction. + * @param[in] camera The camera object. + */ + void scrollCallback(double offsetX, double offsetY, Camera &camera); + + /** + * @brief A callback function for mouse movement events. Currently, this leads to panning the view of the camera, + * if #mouseButtonCallback(int button, int action, int mods) enabled panning. + * @param[in] x The horizontal mouse position + * @param[in] y The vertical mouse position + * @param[in] camera The camera object. + */ + void mouseMoveCallback(double x, double y, Camera &camera); + + /** + * @brief A callback function for mouse button events. Currently, the right mouse button enables panning the + * view of the camera as long as it is pressed. + * @param[in] button The mouse button + * @param[in] action The button action + * @param[in] mods The modifier bits + * @param[in] camera The camera object. + */ + void mouseButtonCallback(int button, int action, int mods, Camera &camera); + }; + +} \ No newline at end of file diff --git a/modules/camera/include/vkcv/camera/TrackballCamera.hpp b/modules/camera/include/vkcv/camera/TrackballCamera.hpp deleted file mode 100644 index c9e269e9f7ad708c68158d5b358efbf37c5bb7a9..0000000000000000000000000000000000000000 --- a/modules/camera/include/vkcv/camera/TrackballCamera.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "Camera.hpp" - -namespace vkcv { - - class TrackballCamera : public vkcv::Camera { - public: - - TrackballCamera( int width, int height, glm::mat4 projection); - - TrackballCamera(int width, int height); - - ~TrackballCamera(); - - float getSensitivity() const; - - void setSensitivity(float sensitivity); - - float getStepSize() const; - - void setStepSize(float stepSize); - - float getTheta() const; - - void setTheta(float theta); - - float getPhi() const; - - void setPhi(float phi); - - float getRadius() const; - - void setRadius(float radius); - - const glm::vec3& getCenter() const; - - void setCenter(const glm::vec3 ¢er); - - private: - float m_sensitivity; - float m_stepSize, m_theta, m_phi, m_radius; - glm::vec3 m_center; - - float m_oldX; - float m_oldY; - }; - -} \ No newline at end of file diff --git a/modules/camera/include/vkcv/camera/TrackballCameraController.hpp b/modules/camera/include/vkcv/camera/TrackballCameraController.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0211043a9c6b862df8e500af190ad1f75a3c78aa --- /dev/null +++ b/modules/camera/include/vkcv/camera/TrackballCameraController.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include "CameraController.hpp" + +namespace vkcv::camera { + + /** + * @brief Used to orbit a camera around its center point. + */ + class TrackballCameraController final : public CameraController { + private: + bool m_rotationActive; + + float m_cameraSpeed; + float m_scrollSensitivity; + float m_radius; + + /** + * @brief Updates the current radius of @p camera in respect to the @p offset. + * @param[in] offset The offset between the old and new radius. + * @param[in] camera The camera object. + */ + void updateRadius(double offset, Camera &camera); + + public: + + /** + * @brief The default constructor of the #TrackballCameraController. + */ + TrackballCameraController(); + + /** + * @brief The destructor of the #TrackballCameraController (default behavior). + */ + ~TrackballCameraController() = default; + + /** + * @brief Sets @p radius as the new radius for orbiting around the camera's center point. + * @param[in] radius The new radius. + */ + void setRadius(const float radius); + + /** + * @brief Pans the view of @p camera according to the pitch and yaw values and additional offsets @p xOffset + * and @p yOffset. + * @param[in] xOffset The offset added to the yaw value. + * @param[in] yOffset The offset added to the pitch value. + * @param[in] camera The camera object. + */ + void panView(double xOffset, double yOffset, Camera &camera); + + /** + * @brief Updates @p camera in respect to @p deltaTime. + * @param[in] deltaTime The time that has passed since last update. + * @param[in] camera The camera object + */ + void updateCamera(double deltaTime, Camera &camera); + + /** + * @brief A callback function for key events. Currently, the trackball camera does not support camera movement. + * It can only orbit around its center point. + * @param[in] key The keyboard key. + * @param[in] scancode The platform-specific scancode. + * @param[in] action The key action. + * @param[in] mods The modifier bits. + * @param[in] camera The camera object. + */ + void keyCallback(int key, int scancode, int action, int mods, Camera &camera); + + /** + * @brief A callback function for mouse scrolling events. Currently, this leads to changes in the field of view + * of the camera object. + * @param[in] offsetX The offset in horizontal direction. + * @param[in] offsetY The offset in vertical direction. + * @param[in] camera The camera object. + */ + void scrollCallback(double offsetX, double offsetY, Camera &camera); + + /** + * @brief A callback function for mouse movement events. Currently, this leads to panning the view of the + * camera, if #mouseButtonCallback(int button, int action, int mods) enabled panning. + * @param[in] xoffset The horizontal mouse position. + * @param[in] yoffset The vertical mouse position. + * @param[in] camera The camera object. + */ + void mouseMoveCallback(double xoffset, double yoffset, Camera &camera); + + /** + * @brief A callback function for mouse button events. Currently, the right mouse button enables panning the + * view of the camera as long as it is pressed. + * @param[in] button The mouse button. + * @param[in] action The button action. + * @param[in] mods The modifier bits. + * @param[in] camera The camera object. + */ + void mouseButtonCallback(int button, int action, int mods, Camera &camera); + + }; + +} \ No newline at end of file diff --git a/modules/camera/src/vkcv/camera/Camera.cpp b/modules/camera/src/vkcv/camera/Camera.cpp index af89ed86881acc8b754a041d32599a78caac57b4..eb1857968b2284287691c6ed41ba168db30d3f84 100644 --- a/modules/camera/src/vkcv/camera/Camera.cpp +++ b/modules/camera/src/vkcv/camera/Camera.cpp @@ -1,44 +1,28 @@ #include "vkcv/camera/Camera.hpp" -#include <iostream> -namespace vkcv { +#define _USE_MATH_DEFINES +#include <math.h> - Camera::Camera(){ - m_up = glm::vec3(0.0f, -1.0f, 0.0f); - m_position = glm::vec3(0.0f, 0.0f, 0.0f); - m_cameraSpeed = 2.f; - // front - m_pitch = 0.0; - m_yaw = 180.0; +namespace vkcv::camera { - m_fov_nsteps = 100; - m_fov_min = 10; - m_fov_max = 120; - - m_forward = false; - m_backward = false; - m_left = false; - m_right = false; + Camera::Camera() { + lookAt( + glm::vec3(0.0f, 0.0f, -1.0f), + glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(0.0f, 1.0f, 0.0f) + ); + + setFront(glm::normalize(m_center - m_position)); } Camera::~Camera() = default; - void Camera::lookAt(glm::vec3 position, glm::vec3 center, glm::vec3 up){ - m_view = glm::lookAt(position, center, up); - } - - glm::mat4 Camera::updateView(double deltatime){ - updatePosition(deltatime); - return m_view = glm::lookAt(m_position, m_position + getFront() , m_up); - } - - void Camera::getView(glm::vec3 &x, glm::vec3 &y, glm::vec3 &z, glm::vec3 &pos){ - x = glm::vec3( glm::row(m_view, 0)); - y = glm::vec3( glm::row(m_view, 1)); - z = glm::vec3( glm::row(m_view, 2)); - pos = glm::vec3( glm::column(m_view, 3)); - glm::mat3 mat_inv = glm::inverse( glm::mat3(m_view)); - pos = -mat_inv * pos; + void Camera::lookAt(const glm::vec3& position, const glm::vec3& center, const glm::vec3& up) { + m_position = position; + m_center = center; + m_up = up; + + setView(glm::lookAt(position, center, up)); } void Camera::getNearFar( float &near, float &far) const { @@ -46,98 +30,111 @@ namespace vkcv { far = m_far; } - - const glm::mat4 Camera::getView() const { + const glm::mat4& Camera::getView() const { return m_view; } + + void Camera::setView(const glm::mat4 &view) { + m_view = view; + } const glm::mat4& Camera::getProjection() const { return m_projection; } - void Camera::setProjection(const glm::mat4 projection){ - m_projection = projection; + void Camera::setProjection(const glm::mat4& projection) { + m_projection = projection; } - float Camera::getFov() const { - return m_fov; + glm::mat4 Camera::getMVP() const { + const glm::mat4 y_correction ( + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + + return y_correction * m_projection * m_view; } - void Camera::setFov( float fov){ - m_fov = fov; - setPerspective( m_fov, m_ratio, m_near, m_far); + float Camera::getFov() const { + const float tanHalfFovy = 1.0f / m_projection[1][1]; + float halfFovy = std::atan(tanHalfFovy); + + if (halfFovy < 0) { + halfFovy += static_cast<float>(M_PI); + } + + return halfFovy * 2.0f; } - void Camera::changeFov(double offset){ - float fov = m_fov; - float fov_range = m_fov_max - m_fov_min; - float fov_stepsize = glm::radians(fov_range)/m_fov_nsteps; - fov -= (float) offset*fov_stepsize; - if (fov < glm::radians(m_fov_min)) { - fov = glm::radians(m_fov_min); - } - if (fov > glm::radians(m_fov_max)) { - fov = glm::radians(m_fov_max); - } - setFov(fov); + void Camera::setFov( float fov){ + setPerspective(fov, getRatio(), m_near, m_far); } - void Camera::updateRatio( int width, int height){ - m_width = width; - m_height = height; - m_ratio = static_cast<float>(width)/glm::max(height, 1); - setPerspective( m_fov, m_ratio, m_near, m_far); + float Camera::getRatio() const { + const float aspectProduct = 1.0f / m_projection[0][0]; + const float tanHalfFovy = 1.0f / m_projection[1][1]; + + return aspectProduct / tanHalfFovy; } - float Camera::getRatio() const { - return m_ratio; + void Camera::setRatio(float ratio){ + setPerspective( getFov(), ratio, m_near, m_far); } - void Camera::setNearFar( float near, float far){ - m_near = near; - m_far = far; - setPerspective(m_fov, m_ratio, m_near, m_far); + void Camera::setNearFar(float near, float far){ + setPerspective(getFov(), getRatio(), near, far); } - void Camera::setPerspective(float fov, float ratio, float near, float far){ - m_fov = fov; - m_ratio = ratio; - m_near = near; - m_far = far; - m_projection = glm::perspective( m_fov, ratio, m_near, m_far); + void Camera::setPerspective(float fov, float ratio, float near, float far) { + m_near = near; + m_far = far; + setProjection(glm::perspective(fov, ratio, near, far)); } glm::vec3 Camera::getFront() const { glm::vec3 direction; - direction.x = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch)); - direction.y = sin(glm::radians(m_pitch)); - direction.z = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch)); + direction.x = std::sin(glm::radians(m_yaw)) * std::cos(glm::radians(m_pitch)); + direction.y = std::sin(glm::radians(m_pitch)); + direction.z = std::cos(glm::radians(m_yaw)) * std::cos(glm::radians(m_pitch)); return glm::normalize(direction); } + + void Camera::setFront(const glm::vec3 &front) { + m_pitch = std::atan2(front.y, std::sqrt(front.x * front.x + front.z * front.z)); + m_yaw = std::atan2(front.x, front.z); + } - glm::vec3 Camera::getPosition() const { + const glm::vec3& Camera::getPosition() const { return m_position; } - void Camera::setPosition( glm::vec3 position ){ - m_position = position; + void Camera::setPosition( const glm::vec3& position ){ + lookAt(position, m_center, m_up); } - void Camera::setUp(const glm::vec3 &up) { - m_up = up; + const glm::vec3& Camera::getCenter() const { + return m_center; } + void Camera::setCenter(const glm::vec3& center) { + lookAt(m_position, center, m_up); + } + + const glm::vec3& Camera::getUp() const { + return m_up; + } + + void Camera::setUp(const glm::vec3 &up) { + lookAt(m_position, m_center, up); + } + float Camera::getPitch() const { return m_pitch; } void Camera::setPitch(float pitch) { - if (pitch > 89.0f) { - pitch = 89.0f; - } - if (pitch < -89.0f) { - pitch = -89.0f; - } m_pitch = pitch; } @@ -149,31 +146,4 @@ namespace vkcv { m_yaw = yaw; } - void Camera::panView(double xOffset, double yOffset) { - m_yaw += xOffset; - m_pitch += yOffset; - } - - void Camera::updatePosition(double deltatime ){ - m_position += (m_cameraSpeed * getFront() * static_cast<float> (m_forward) * static_cast<float>(deltatime)); - m_position -= (m_cameraSpeed * getFront() * static_cast<float> (m_backward) * static_cast<float>(deltatime)); - m_position -= (glm::normalize(glm::cross(getFront(), m_up)) * m_cameraSpeed * static_cast<float> (m_left) * static_cast<float>(deltatime)); - m_position += (glm::normalize(glm::cross(getFront(), m_up)) * m_cameraSpeed * static_cast<float> (m_right) * static_cast<float>(deltatime)); - } - - void Camera::moveForward(int action){ - m_forward = static_cast<bool>(action); - } - - void Camera::moveBackward(int action){ - m_backward = static_cast<bool>(action); - } - - void Camera::moveLeft(int action){ - m_left = static_cast<bool>(action); - } - - void Camera::moveRight(int action){ - m_right = static_cast<bool>(action); - } } \ No newline at end of file diff --git a/modules/camera/src/vkcv/camera/CameraManager.cpp b/modules/camera/src/vkcv/camera/CameraManager.cpp index 2631890d646fbf27a4fbb14cfeef706678d8918c..977c61d03dac51598281262acf9609540063a9e4 100644 --- a/modules/camera/src/vkcv/camera/CameraManager.cpp +++ b/modules/camera/src/vkcv/camera/CameraManager.cpp @@ -1,88 +1,156 @@ -#include <iostream> + #include "vkcv/camera/CameraManager.hpp" -namespace vkcv{ +#include <vkcv/Logger.hpp> + +namespace vkcv::camera { - CameraManager::CameraManager(Window &window, float width, float height, glm::vec3 up, glm::vec3 position): - m_window(window), m_width(width), m_height(height) + CameraManager::CameraManager(Window &window, float width, float height) + : m_window(window) { - m_camera.setUp(up); - m_camera.setPosition(position); - m_camera.setPerspective( glm::radians(60.0f), m_width / m_height, 0.1f, 10.f); - m_lastX = width/2.0; - m_lastY = height/2.0; - bindCamera(); + bindCameraToEvents(); + m_activeCameraIndex = 0; + m_lastX = static_cast<float>(window.getWidth()) / 2.0f; + m_lastY = static_cast<float>(window.getHeight()) / 2.0f; } - void CameraManager::bindCamera(){ - e_keyHandle = m_window.e_key.add( [&](int key, int scancode, int action, int mods) { this->keyCallback(key, scancode, action, mods); }); - e_mouseMoveHandle = m_window.e_mouseMove.add( [&]( double offsetX, double offsetY) {this->mouseMoveCallback( offsetX, offsetY);} ); - e_mouseScrollHandle = m_window.e_mouseScroll.add([&](double offsetX, double offsetY) {this->scrollCallback( offsetX, offsetY);} ); - e_mouseButtonHandle = m_window.e_mouseButton.add([&] (int button, int action, int mods) {this->mouseButtonCallback( button, action, mods);}); - e_resizeHandle = m_window.e_resize.add([&] (int width, int height) {this->resizeCallback( width, height);}); + CameraManager::~CameraManager() {} + + void CameraManager::bindCameraToEvents() { + m_keyHandle = m_window.e_key.add( [&](int key, int scancode, int action, int mods) { this->keyCallback(key, scancode, action, mods); }); + m_mouseMoveHandle = m_window.e_mouseMove.add( [&]( double offsetX, double offsetY) {this->mouseMoveCallback( offsetX, offsetY);} ); + m_mouseScrollHandle = m_window.e_mouseScroll.add([&](double offsetX, double offsetY) {this->scrollCallback( offsetX, offsetY);} ); + m_mouseButtonHandle = m_window.e_mouseButton.add([&] (int button, int action, int mods) {this->mouseButtonCallback( button, action, mods);}); + m_resizeHandle = m_window.e_resize.add([&](int width, int height) {this->resizeCallback(width, height);}); + } + + void CameraManager::resizeCallback(int width, int height) { + for (size_t i = 0; i < m_cameras.size(); i++) { + getCamera(i).setRatio(static_cast<float>(width) / static_cast<float>(height));; + } } void CameraManager::mouseButtonCallback(int button, int action, int mods){ - if(button == GLFW_MOUSE_BUTTON_2 && m_roationActive == false && action == GLFW_PRESS){ + if(button == GLFW_MOUSE_BUTTON_2 && action == GLFW_PRESS){ glfwSetInputMode(m_window.getWindow(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); - m_roationActive = true; - }else if(button == GLFW_MOUSE_BUTTON_2 && m_roationActive == true && action == GLFW_RELEASE){ + } + else if(button == GLFW_MOUSE_BUTTON_2 && action == GLFW_RELEASE){ glfwSetInputMode(m_window.getWindow(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); - m_roationActive = false; } + getActiveController().mouseButtonCallback(button, action, mods, getActiveCamera()); } void CameraManager::mouseMoveCallback(double x, double y){ - - float xoffset = x - m_lastX; - float yoffset = m_lastY - y; + auto xoffset = static_cast<float>(x - m_lastX); + auto yoffset = static_cast<float>(y - m_lastY); m_lastX = x; m_lastY = y; + getActiveController().mouseMoveCallback(xoffset, yoffset, getActiveCamera()); + } - if(!m_roationActive){ - return; + void CameraManager::scrollCallback(double offsetX, double offsetY) { + getActiveController().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; } + } + + CameraController& CameraManager::getActiveController() { + const ControllerType type = getControllerType(getActiveCameraIndex()); + return getControllerByType(type); + } + + uint32_t CameraManager::addCamera(ControllerType controllerType) { + Camera camera; + camera.setPerspective(glm::radians(60.0f), m_window.getWidth() / m_window.getHeight(), 0.1f, 10.0f); + return addCamera(controllerType, camera); + } + + uint32_t CameraManager::addCamera(ControllerType controllerType, const Camera &camera) { + const uint32_t index = static_cast<uint32_t>(m_cameras.size()); + m_cameras.push_back(camera); + m_cameraControllerTypes.push_back(controllerType); + return index; + } - float sensitivity = 0.05f; - xoffset *= sensitivity; - yoffset *= sensitivity; + Camera& CameraManager::getCamera(uint32_t cameraIndex) { + if (cameraIndex < 0 || cameraIndex > m_cameras.size() - 1) { + vkcv_log(LogLevel::ERROR, "Invalid camera index: The index must range from 0 to %lu", m_cameras.size()); + return getActiveCamera(); + } + + return m_cameras[cameraIndex]; + } - m_camera.panView( xoffset , yoffset ); + Camera& CameraManager::getActiveCamera() { + return m_cameras[getActiveCameraIndex()]; } - void CameraManager::scrollCallback(double offsetX, double offsetY) { - m_camera.changeFov(offsetY); + void CameraManager::setActiveCamera(uint32_t cameraIndex) { + if (cameraIndex < 0 || cameraIndex > m_cameras.size() - 1) { + vkcv_log(LogLevel::ERROR, "Invalid camera index: The index must range from 0 to %lu", m_cameras.size()); + return; + } + + m_activeCameraIndex = cameraIndex; } - void CameraManager::keyCallback(int key, int scancode, int action, int mods) { + uint32_t CameraManager::getActiveCameraIndex() const { + return m_activeCameraIndex; + } - switch (key) { - case GLFW_KEY_W: - m_camera.moveForward(action); - break; - case GLFW_KEY_S: - m_camera.moveBackward(action); - break; - case GLFW_KEY_A: - m_camera.moveLeft(action); - break; - case GLFW_KEY_D: - m_camera.moveRight(action); - break; - case GLFW_KEY_ESCAPE: - glfwSetWindowShouldClose(m_window.getWindow(), 1); - break; - default: - break; + void CameraManager::setControllerType(uint32_t cameraIndex, ControllerType controllerType) { + if (cameraIndex < 0 || cameraIndex > m_cameras.size() - 1) { + vkcv_log(LogLevel::ERROR, "Invalid camera index: The index must range from 0 to %lu", m_cameras.size()); + return; } + + m_cameraControllerTypes[cameraIndex] = controllerType; } - void CameraManager::resizeCallback(int width, int height){ - m_camera.updateRatio(width, height); + ControllerType CameraManager::getControllerType(uint32_t cameraIndex) { + if (cameraIndex < 0 || cameraIndex > m_cameras.size() - 1) { + vkcv_log(LogLevel::ERROR, "Invalid camera index: The index must range from 0 to %lu", m_cameras.size()); + return ControllerType::NONE; + } + + return m_cameraControllerTypes[cameraIndex]; } - Camera &CameraManager::getCamera(){ - return m_camera; + CameraController& CameraManager::getControllerByType(ControllerType controllerType) { + switch(controllerType) { + case ControllerType::PILOT: + return m_pilotController; + case ControllerType::TRACKBALL: + return m_trackController; + default: + return m_pilotController; + } } + void CameraManager::update(double deltaTime) { + getActiveController().updateCamera(deltaTime, getActiveCamera()); + } + } \ No newline at end of file diff --git a/modules/camera/src/vkcv/camera/PilotCameraController.cpp b/modules/camera/src/vkcv/camera/PilotCameraController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a50a0efa4b4e75adb81ce869d6b927bd0046758 --- /dev/null +++ b/modules/camera/src/vkcv/camera/PilotCameraController.cpp @@ -0,0 +1,155 @@ +#include "vkcv/camera/PilotCameraController.hpp" + +#include <GLFW/glfw3.h> + +namespace vkcv::camera { + + PilotCameraController::PilotCameraController() { + m_forward = false; + m_backward = false; + m_upward = false; + m_downward = false; + m_left = false; + m_right = false; + + m_rotationActive = false; + + m_cameraSpeed = 2.0f; + + m_fov_nsteps = 100; + m_fov_min = 10; + m_fov_max = 120; + } + + void PilotCameraController::changeFov(double offset, Camera &camera){ + float fov = camera.getFov(); + float fov_range = m_fov_max - m_fov_min; + float fov_stepsize = glm::radians(fov_range) / static_cast<float>(m_fov_nsteps); + fov -= (float) offset*fov_stepsize; + if (fov < glm::radians(m_fov_min)) { + fov = glm::radians(m_fov_min); + } + if (fov > glm::radians(m_fov_max)) { + fov = glm::radians(m_fov_max); + } + camera.setFov(fov); + } + + void PilotCameraController::panView(double xOffset, double yOffset, Camera &camera) { + // handle yaw rotation + float yaw = camera.getYaw() + xOffset; + if (yaw < -180.0f) { + yaw += 360.0f; + } + else if (yaw > 180.0f) { + yaw -= 360.0f; + } + camera.setYaw(yaw); + + // handle pitch rotation + float pitch = camera.getPitch() - yOffset; + if (pitch > 89.0f) { + pitch = 89.0f; + } + if (pitch < -89.0f) { + pitch = -89.0f; + } + camera.setPitch(pitch); + } + + constexpr float getDirectionFactor(bool positive, bool negative) { + return static_cast<float>(positive) - static_cast<float>(negative); + } + + void PilotCameraController::updateCamera(double deltaTime, Camera &camera) { + glm::vec3 position = camera.getPosition(); + + const glm::vec3 front = camera.getFront(); + const glm::vec3 up = camera.getUp(); + const glm::vec3 left = glm::normalize(glm::cross(front, up)); + + const float distance = m_cameraSpeed * static_cast<float>(deltaTime); + + position += distance * getDirectionFactor(m_forward, m_backward) * front; + position += distance * getDirectionFactor(m_left, m_right) * left; + position += distance * getDirectionFactor(m_upward, m_downward) * up; + + camera.lookAt(position, position + front, up); + } + + void PilotCameraController::keyCallback(int key, int scancode, int action, int mods, Camera &camera) { + switch (key) { + case GLFW_KEY_W: + moveForward(action); + break; + case GLFW_KEY_S: + moveBackward(action); + break; + case GLFW_KEY_A: + moveLeft(action); + break; + case GLFW_KEY_D: + moveRight(action); + break; + case GLFW_KEY_E: + moveUpward(action); + break; + case GLFW_KEY_Q: + moveDownward(action); + break; + default: + break; + } + } + + void PilotCameraController::scrollCallback(double offsetX, double offsetY, Camera &camera) { + changeFov(offsetY, camera); + } + + void PilotCameraController::mouseMoveCallback(double xoffset, double yoffset, Camera &camera) { + if(!m_rotationActive){ + return; + } + + float sensitivity = 0.05f; + xoffset *= sensitivity; + yoffset *= sensitivity; + + panView(xoffset , yoffset, camera); + } + + void PilotCameraController::mouseButtonCallback(int button, int action, int mods, Camera &camera) { + if(button == GLFW_MOUSE_BUTTON_2 && m_rotationActive == false && action == GLFW_PRESS){ + m_rotationActive = true; + } + else if(button == GLFW_MOUSE_BUTTON_2 && m_rotationActive == true && action == GLFW_RELEASE){ + m_rotationActive = false; + } + } + + + void PilotCameraController::moveForward(int action){ + m_forward = static_cast<bool>(action); + } + + void PilotCameraController::moveBackward(int action){ + m_backward = static_cast<bool>(action); + } + + void PilotCameraController::moveLeft(int action){ + m_left = static_cast<bool>(action); + } + + void PilotCameraController::moveRight(int action){ + m_right = static_cast<bool>(action); + } + + void PilotCameraController::moveUpward(int action){ + m_upward = static_cast<bool>(action); + } + + void PilotCameraController::moveDownward(int action){ + m_downward = static_cast<bool>(action); + } + +} \ No newline at end of file diff --git a/modules/camera/src/vkcv/camera/TrackballCamera.cpp b/modules/camera/src/vkcv/camera/TrackballCamera.cpp deleted file mode 100644 index 3bbb8611dd234499fb9ba08ba87009c8c76660f6..0000000000000000000000000000000000000000 --- a/modules/camera/src/vkcv/camera/TrackballCamera.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "vkcv/camera/TrackballCamera.hpp" - -namespace vkcv{ - - TrackballCamera::TrackballCamera( int width, int height, glm::mat4 projection) - { - setPosition( glm::vec3(0.0f, 0.0f, 5.0) ); - m_center = glm::vec3( 0.0f, 0.0f, 0.0f); - m_up = glm::vec3(0.0f, 1.0f, 0.0f); - - m_width = width; - m_height = height; - - m_sensitivity = 0.010f; - m_stepSize = 0.1f; - m_theta = glm::pi<float>() / 2.0f; - m_phi = 0.f; - m_radius = 1.5; - - m_view = glm::lookAt( m_center + getPosition(), m_center, m_up); - - m_oldX = width/2.f; - m_oldY = height/2.f; - - setProjection(projection); - } - - - TrackballCamera::TrackballCamera(int width, int height) - { - setPosition( glm::vec3(0.0f, 0.0f, 5.0)); - m_center = glm::vec3( 0.0f, 0.0f, 0.0f); - m_up = glm::vec3(0.0f, 1.0f, 0.0f); - - m_width = width; - m_height = height; - - m_sensitivity = 0.010f; - m_stepSize = 0.1f; - m_theta = glm::pi<float>() / 2.0f; - m_phi = 0.f; - m_radius = 1.5; - - m_view = glm::lookAt( m_center + getPosition(), m_center, m_up); - - m_oldX = width/2.f; - m_oldY = height/2.f; - - m_fov = glm::radians(60.f); - m_ratio = m_width / (float) m_height; - m_near = 0.001f; - m_far = 10.f; - glm::mat4 projection = glm::perspective(m_fov, m_ratio, m_near, m_far); - - setProjection(projection); - } - - TrackballCamera::~TrackballCamera() - { - } - - // TODO: Can be done as events... (mouseMove, mouseDown, mouseUp) - /*void TrackballCamera::update( GLFWwindow* window) { - - double x, y; - - glfwGetCursorPos( window, &x, &y); - if (glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) - { - float changeX = ((float) x - m_oldX) * m_sensitivity; - float changeY = ((float) y - m_oldY) * m_sensitivity; - - m_theta -= changeY; - if (m_theta < 0.01f) m_theta = 0.01f; - else if (m_theta > glm::pi<float>() - 0.01f) m_theta = glm::pi<float>() - 0.01f; - - m_phi -= changeX; - if (m_phi < 0) m_phi += 2*glm::pi<float>(); - else if (m_phi > 2*glm::pi<float>()) m_phi -= 2*glm::pi<float>(); - } - - m_oldX = (float) x; - m_oldY = (float) y; - - if (glfwGetKey( window, GLFW_KEY_UP) == GLFW_PRESS) - m_radius -= m_stepSize; - if (glfwGetKey( window, GLFW_KEY_DOWN) == GLFW_PRESS) - m_radius += m_stepSize; - if (m_radius < 0.1f) m_radius = 0.1f; - - m_position.x = m_center.x + m_radius * sin(m_theta) * sin(m_phi); - m_position.y = m_center.y + m_radius * cos(m_theta); - m_position.z = m_center.z + m_radius * sin(m_theta) * cos(m_phi); - - m_view = glm::lookAt( m_position, m_center, m_up); - - }*/ - - float TrackballCamera::getSensitivity() const { - return m_sensitivity; - } - - void TrackballCamera::setSensitivity(float sensitivity) { - m_sensitivity = sensitivity; - } - - float TrackballCamera::getStepSize() const { - return m_stepSize; - } - - void TrackballCamera::setStepSize(float stepSize) { - m_stepSize = stepSize; - } - - float TrackballCamera::getTheta() const { - return m_theta; - } - - void TrackballCamera::setTheta(float theta) { - m_theta = theta; - } - - float TrackballCamera::getPhi() const { - return m_phi; - } - - void TrackballCamera::setPhi(float phi) { - m_phi = phi; - } - - float TrackballCamera::getRadius() const { - return m_radius; - } - - void TrackballCamera::setRadius(float radius) { - m_radius = radius; - } - - const glm::vec3& TrackballCamera::getCenter() const { - return m_center; - } - - void TrackballCamera::setCenter(const glm::vec3 ¢er) { - m_center = center; - } -} \ No newline at end of file diff --git a/modules/camera/src/vkcv/camera/TrackballCameraController.cpp b/modules/camera/src/vkcv/camera/TrackballCameraController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..201c6ecdc1c703dbcd53b7dc4b179c86576f2312 --- /dev/null +++ b/modules/camera/src/vkcv/camera/TrackballCameraController.cpp @@ -0,0 +1,100 @@ +#include "vkcv/camera/TrackballCameraController.hpp" + +#include <GLFW/glfw3.h> + +namespace vkcv::camera { + + TrackballCameraController::TrackballCameraController() { + m_rotationActive = false; + m_radius = 3.0f; + m_cameraSpeed = 2.5f; + m_scrollSensitivity = 0.2f; + } + + void TrackballCameraController::setRadius(const float radius) { + if (radius < 0.1f) { + m_radius = 0.1f; + } + else { + m_radius = radius; + } + } + + void TrackballCameraController::panView(double xOffset, double yOffset, Camera &camera) { + // handle yaw rotation + float yaw = camera.getYaw() + xOffset * m_cameraSpeed; + if (yaw < 0.0f) { + yaw += 360.0f; + } + else if (yaw > 360.0f) { + yaw -= 360.0f; + } + camera.setYaw(yaw); + + // handle pitch rotation + float pitch = camera.getPitch() + yOffset * m_cameraSpeed; + if (pitch < 0.0f) { + pitch += 360.0f; + } + else if (pitch > 360.0f) { + pitch -= 360.0f; + } + camera.setPitch(pitch); + } + + void TrackballCameraController::updateRadius(double offset, Camera &camera) { + glm::vec3 cameraPosition = camera.getPosition(); + glm::vec3 cameraCenter = camera.getCenter(); + float radius = glm::length(cameraCenter - cameraPosition); // get current camera radius + setRadius(radius - offset * m_scrollSensitivity); + } + + void TrackballCameraController::updateCamera(double deltaTime, Camera &camera) { + float yaw = camera.getYaw(); + float pitch = camera.getPitch(); + + const glm::vec3 yAxis = glm::vec3(0.0f, 1.0f, 0.0f); + const glm::vec3 xAxis = glm::vec3(1.0f, 0.0f, 0.0f); + + const glm::mat4 rotationY = glm::rotate(glm::mat4(1.0f), glm::radians(yaw), yAxis); + const glm::mat4 rotationX = glm::rotate(rotationY, -glm::radians(pitch), xAxis); + const glm::vec3 translation = glm::vec3( + rotationX * glm::vec4(0.0f, 0.0f, m_radius, 0.0f) + ); + + const glm::vec3 center = camera.getCenter(); + const glm::vec3 position = center + translation; + const glm::vec3 up = glm::vec3( + rotationX * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f) + ); + + camera.lookAt(position, center, up); + } + + void TrackballCameraController::keyCallback(int key, int scancode, int action, int mods, Camera &camera) {} + + void TrackballCameraController::scrollCallback(double offsetX, double offsetY, Camera &camera) { + updateRadius(offsetY, camera); + } + + void TrackballCameraController::mouseMoveCallback(double xoffset, double yoffset, Camera &camera) { + if(!m_rotationActive){ + return; + } + + float sensitivity = 0.05f; + xoffset *= sensitivity; + yoffset *= sensitivity; + + panView(xoffset , yoffset, camera); + } + + void TrackballCameraController::mouseButtonCallback(int button, int action, int mods, Camera &camera) { + if(button == GLFW_MOUSE_BUTTON_2 && m_rotationActive == false && action == GLFW_PRESS){ + m_rotationActive = true; + } + else if(button == GLFW_MOUSE_BUTTON_2 && m_rotationActive == true && action == GLFW_RELEASE){ + m_rotationActive = false; + } + } +} \ No newline at end of file diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp index 426cc3a56033cea1e468c5612f4e32981d18f8c1..a02c4542c7608e520e5ed33e746b5a9c836fc09f 100644 --- a/projects/cmd_sync_test/src/main.cpp +++ b/projects/cmd_sync_test/src/main.cpp @@ -18,9 +18,15 @@ int main(int argc, const char** argv) { true ); - vkcv::CameraManager cameraManager(window, windowWidth, windowHeight); - cameraManager.getCamera().setPosition(glm::vec3(0.f, 0.f, 3.f)); - cameraManager.getCamera().setNearFar(0.1, 30); + vkcv::camera::CameraManager cameraManager(window, windowWidth, windowHeight); + uint32_t camIndex = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex2 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex).setPosition(glm::vec3(0.f, 0.f, 3.f)); + cameraManager.getCamera(camIndex).setNearFar(0.1f, 30.0f); + cameraManager.getCamera(camIndex).setYaw(180.0f); + + cameraManager.getCamera(camIndex2).setNearFar(0.1f, 30.0f); window.initEvents(); @@ -233,10 +239,13 @@ int main(int argc, const char** argv) { auto end = std::chrono::system_clock::now(); auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + start = end; - cameraManager.getCamera().updateView(deltatime.count() * 0.000001); + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); - const float sunTheta = std::chrono::duration_cast<std::chrono::milliseconds>(end - appStartTime).count() * 0.001f; + auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - appStartTime); + + const float sunTheta = 0.001f * static_cast<float>(duration.count()); lightInfo.direction = glm::normalize(glm::vec3(std::cos(sunTheta), 1, std::sin(sunTheta))); const float shadowProjectionSize = 5.f; @@ -258,7 +267,7 @@ int main(int argc, const char** argv) { lightInfo.lightMatrix = projectionLight * viewLight; lightBuffer.fill({ lightInfo }); - const glm::mat4 viewProjectionCamera = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); + const glm::mat4 viewProjectionCamera = cameraManager.getActiveCamera().getMVP(); mainPassMatrices.clear(); mvpLight.clear(); diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 8f461512e315d902032cd5a82ee7bdcb624d7a36..42b1f595dc9f36f8cfb9816a1508980aefb52a83 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -18,8 +18,6 @@ int main(int argc, const char** argv) { true ); - vkcv::CameraManager cameraManager(window, static_cast<float>(window.getWidth()), static_cast<float>(window.getHeight())); - window.initEvents(); vkcv::Core core = vkcv::Core::create( @@ -148,7 +146,14 @@ int main(int argc, const char** argv) { vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle); vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage }); - auto start = std::chrono::system_clock::now(); + vkcv::camera::CameraManager cameraManager(window, windowWidth, windowHeight); + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -3)); + + auto start = std::chrono::system_clock::now(); + while (window.isWindowOpen()) { vkcv::Window::pollEvents(); @@ -168,10 +173,11 @@ int main(int argc, const char** argv) { } auto end = std::chrono::system_clock::now(); - auto deltatime = end - start; + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + start = end; - cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count()); - const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); vkcv::PushConstantData pushConstantData((void*)&mvp, sizeof(glm::mat4)); diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index b6b75bca82a8479f3d6b09577337503424ce7a83..8ecea2b69906b017b321e3ca6002761fb8ffdd7d 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -16,8 +16,6 @@ int main(int argc, const char** argv) { false ); - vkcv::CameraManager cameraManager(window, windowWidth, windowHeight); - window.initEvents(); vkcv::Core core = vkcv::Core::create( @@ -160,6 +158,12 @@ int main(int argc, const char** argv) { vkcv::DrawcallInfo drawcall(renderMesh, {}); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + vkcv::camera::CameraManager cameraManager(window, windowWidth, windowHeight); + uint32_t camIndex = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex2 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex).setPosition(glm::vec3(0, 0, -2)); while (window.isWindowOpen()) { @@ -171,10 +175,11 @@ int main(int argc, const char** argv) { } auto end = std::chrono::system_clock::now(); - auto deltatime = end - start; + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); start = end; - cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count()); - const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); + + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); vkcv::PushConstantData pushConstantData((void*)&mvp, sizeof(glm::mat4)); auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);