diff --git a/base/camera.hpp b/base/camera.hpp new file mode 100644 index 00000000..d00a7b22 --- /dev/null +++ b/base/camera.hpp @@ -0,0 +1,136 @@ +/* +* Basic camera class +* +* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + + +#define GLM_FORCE_RADIANS +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include +#include +#include + +class Camera +{ +private: + float fov; + float znear, zfar; + + void updateViewMatrix() + { + glm::mat4 rotM = glm::mat4(); + glm::mat4 transM; + + rotM = glm::rotate(rotM, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); + rotM = glm::rotate(rotM, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); + rotM = glm::rotate(rotM, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); + + transM = glm::translate(glm::mat4(), position); + + if (type == CameraType::firtsperson) + { + matrices.view = rotM * transM; + } + else + { + matrices.view = transM * rotM; + } + }; +public: + enum CameraType { lookat, firtsperson }; + CameraType type = CameraType::lookat; + + glm::vec3 rotation = glm::vec3(); + glm::vec3 position = glm::vec3(); + + float rotationSpeed = 1.0f; + float movementSpeed = 1.0f; + + struct + { + glm::mat4 perspective; + glm::mat4 view; + } matrices; + + struct + { + bool left = false; + bool right = false; + bool up = false; + bool down = false; + } keys; + + bool moving() + { + return keys.left || keys.right || keys.up || keys.down; + } + + void setPerspective(float fov, float aspect, float znear, float zfar) + { + this->fov = fov; + this->znear = znear; + this->zfar = zfar; + matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar); + }; + + void updateAspectRatio(float aspect) + { + matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar); + } + + void setRotation(glm::vec3 rotation) + { + this->rotation = rotation; + updateViewMatrix(); + }; + + void rotate(glm::vec3 delta) + { + this->rotation += delta; + updateViewMatrix(); + } + + void setTranslation(glm::vec3 translation) + { + this->position = translation; + updateViewMatrix(); + }; + + void translate(glm::vec3 delta) + { + this->position += delta; + updateViewMatrix(); + } + + void update(float deltaTime) + { + if (type == CameraType::firtsperson) + { + if (moving()) + { + glm::vec3 camFront; + camFront.x = -cos(glm::radians(rotation.x)) * sin(glm::radians(rotation.y)); + camFront.y = sin(glm::radians(rotation.x)); + camFront.z = cos(glm::radians(rotation.x)) * cos(glm::radians(rotation.y)); + camFront = glm::normalize(camFront); + + float moveSpeed = deltaTime * movementSpeed; + + if (keys.up) + position += camFront * moveSpeed; + if (keys.down) + position -= camFront * moveSpeed; + if (keys.left) + position -= glm::normalize(glm::cross(camFront, glm::vec3(0.0f, 1.0f, 0.0f))) * moveSpeed; + if (keys.right) + position += glm::normalize(glm::cross(camFront, glm::vec3(0.0f, 1.0f, 0.0f))) * moveSpeed; + + updateViewMatrix(); + } + } + }; + +}; \ No newline at end of file diff --git a/base/vulkanexamplebase.cpp b/base/vulkanexamplebase.cpp index 86b4a877..43ab4881 100644 --- a/base/vulkanexamplebase.cpp +++ b/base/vulkanexamplebase.cpp @@ -426,6 +426,11 @@ void VulkanExampleBase::renderLoop() auto tEnd = std::chrono::high_resolution_clock::now(); auto tDiff = std::chrono::duration(tEnd - tStart).count(); frameTimer = (float)tDiff / 1000.0f; + camera.update(frameTimer); + if (camera.moving()) + { + viewChanged(); + } // Convert to clamped timer value if (!paused) { @@ -489,6 +494,7 @@ void VulkanExampleBase::renderLoop() auto tEnd = std::chrono::high_resolution_clock::now(); auto tDiff = std::chrono::duration(tEnd - tStart).count(); frameTimer = tDiff / 1000.0f; + camera.update(frameTimer); // Convert to clamped timer value if (!paused) { @@ -515,11 +521,13 @@ void VulkanExampleBase::renderLoop() if (std::abs(gamePadState.axes.x) > deadZone) { rotation.y += gamePadState.axes.x * 0.5f * rotationSpeed; + camera.rotate(glm::vec3(0.0f, gamePadState.axes.x * 0.5f, 0.0f)); updateView = true; } if (std::abs(gamePadState.axes.y) > deadZone) { rotation.x -= gamePadState.axes.y * 0.5f * rotationSpeed; + camera.rotate(glm::vec3(gamePadState.axes.y * 0.5f, 0.0f, 0.0f)); updateView = true; } // Zoom @@ -553,6 +561,7 @@ void VulkanExampleBase::renderLoop() auto tEnd = std::chrono::high_resolution_clock::now(); auto tDiff = std::chrono::duration(tEnd - tStart).count(); frameTimer = tDiff / 1000.0f; + camera.update(frameTimer); // Convert to clamped timer value if (!paused) { @@ -1114,8 +1123,48 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR PostQuitMessage(0); break; } + + if (camera.firtsperson) + { + switch (wParam) + { + case 0x57: + camera.keys.up = true; + break; + case 0x53: + camera.keys.down = true; + break; + case 0x41: + camera.keys.left = true; + break; + case 0x44: + camera.keys.right = true; + break; + } + } + keyPressed((uint32_t)wParam); break; + case WM_KEYUP: + if (camera.firtsperson) + { + switch (wParam) + { + case 0x57: + camera.keys.up = false; + break; + case 0x53: + camera.keys.down = false; + break; + case 0x41: + camera.keys.left = false; + break; + case 0x44: + camera.keys.right = false; + break; + } + } + break; case WM_RBUTTONDOWN: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: @@ -1126,6 +1175,7 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR { short wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam); zoom += (float)wheelDelta * 0.005f * zoomSpeed; + camera.translate(glm::vec3(0.0f, 0.0f, (float)wheelDelta * 0.005f * zoomSpeed)); viewChanged(); break; } @@ -1135,6 +1185,7 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR int32_t posx = LOWORD(lParam); int32_t posy = HIWORD(lParam); zoom += (mousePos.y - (float)posy) * .005f * zoomSpeed; + camera.translate(glm::vec3(-0.0f, 0.0f, (mousePos.y - (float)posy) * .005f * zoomSpeed)); mousePos = glm::vec2((float)posx, (float)posy); viewChanged(); } @@ -1144,6 +1195,7 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR int32_t posy = HIWORD(lParam); rotation.x += (mousePos.y - (float)posy) * 1.25f * rotationSpeed; rotation.y -= (mousePos.x - (float)posx) * 1.25f * rotationSpeed; + camera.rotate(glm::vec3((mousePos.y - (float)posy), -(mousePos.x - (float)posx), 0.0f)); mousePos = glm::vec2((float)posx, (float)posy); viewChanged(); } @@ -1153,6 +1205,7 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR int32_t posy = HIWORD(lParam); cameraPos.x -= (mousePos.x - (float)posx) * 0.01f; cameraPos.y -= (mousePos.y - (float)posy) * 0.01f; + camera.translate(glm::vec3(-(mousePos.x - (float)posx) * 0.01f, -(mousePos.y - (float)posy) * 0.01f, 0.0f)); viewChanged(); mousePos.x = (float)posx; mousePos.y = (float)posy; @@ -1673,6 +1726,8 @@ void VulkanExampleBase::windowResize() updateTextOverlay(); } + camera.updateAspectRatio((float)width / (float)height); + // Notify derived class windowResized(); viewChanged(); @@ -1700,4 +1755,3 @@ void VulkanExampleBase::setupSwapChain() { swapChain.create(setupCmdBuffer, &width, &height); } - diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index 4ae432a6..61d288e2 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -40,6 +40,7 @@ #include "vulkanTextureLoader.hpp" #include "vulkanMeshLoader.hpp" #include "vulkantextoverlay.hpp" +#include "camera.hpp" #define GAMEPAD_BUTTON_A 0x1000 #define GAMEPAD_BUTTON_B 0x1001 @@ -160,6 +161,8 @@ public: // Use to adjust mouse zoom speed float zoomSpeed = 1.0f; + Camera camera; + glm::vec3 rotation = glm::vec3(); glm::vec3 cameraPos = glm::vec3(); glm::vec2 mousePos;