camera refactor

This commit is contained in:
Benjamin Kyd
2023-04-29 22:42:19 +01:00
parent 9ec4536fdf
commit 1d0ec3330c
5 changed files with 194 additions and 189 deletions

View File

@@ -3,56 +3,51 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <memory>
#include <mutex> #include <mutex>
namespace inferno { namespace inferno::graphics {
class Camera { struct _CameraImpl;
public:
Camera();
Camera(int w, int h);
void update(); typedef struct Camera {
bool didUpdate(); glm::mat4 ViewMatrix;
void newFrame(); glm::mat4 ProjectionMatrix;
glm::mat4 LookMatrix;
float MouseSensitivity = 0.4f;
float CameraSpeed = 0.1f;
float Roll, Pitch, Yaw;
float FOV = 45.0f;
glm::vec3 Position = {};
glm::vec3 LookDirection = {};
glm::mat4 getViewMatrix(); std::unique_ptr<_CameraImpl> _impl;
glm::mat4 getProjectionMatrix(); } Camera;
glm::mat4 getCameraLook();
void setRasterViewport(glm::vec2 viewport); std::unique_ptr<Camera> camera_create();
void camera_cleanup(std::unique_ptr<Camera>& camera);
// Keyboard void camera_update(std::unique_ptr<Camera>& camera);
void moveCamera(uint8_t posDelta); void camera_did_update(std::unique_ptr<Camera>& camera);
// Mouse Delta void camera_new_frame(std::unique_ptr<Camera>& camera);
void mouseMoved(glm::vec2 mouseDelta);
void setPosition(glm::vec3 position); glm::mat4 camera_get_view(std::unique_ptr<Camera>& camera);
void setEulerLook(float roll, float pitch, float yaw); glm::mat4 camera_get_projection(std::unique_ptr<Camera>& camera);
void setLook(glm::vec3 lookDirection); glm::mat4 camera_get_look(std::unique_ptr<Camera>& camera);
public: void raster_set_viewport(std::unique_ptr<Camera>& camera, glm::ivec2 viewport);
void setRayViewport(glm::vec2 viewport); glm::ivec2 raster_get_viewport(std::unique_ptr<Camera>& camera);
glm::vec2 getRayViewport();
public: void ray_set_viewport(std::unique_ptr<Camera>& camera, glm::ivec2 viewport);
// necessary evil glm::ivec2 ray_get_viewport(std::unique_ptr<Camera>& camera);
float MouseSensitivity = 0.4f;
float CameraSpeed = 0.1f;
float Roll, Pitch, Yaw;
float FOV = 45.0f;
glm::vec3 Position = {};
glm::vec3 LookDirection = {};
private: void camera_move(std::unique_ptr<Camera>& camera, uint8_t movement_delta);
glm::vec2 mViewport = { 100.0f, 100.0f }; void camera_mouse_move(std::unique_ptr<Camera>& camera, glm::vec2 mouse_delta);
glm::vec2 mRayViewport = { 200.0f, 200.0f };
glm::mat4 mViewMatrix = {};
glm::mat4 mProjMatrix = {};
glm::mat4 mCameraLook = {};
bool mDidUpdate;
std::mutex _mCam; void camera_set_position(std::unique_ptr<Camera>& camera, glm::vec3 position);
}; void camera_set_euler_look(std::unique_ptr<Camera>& camera, float roll,
float pitch, float yaw);
void camera_set_look(std::unique_ptr<Camera>& camera,
glm::vec3 look_direction);
} } // namespace inferno::graphics

View File

@@ -25,20 +25,24 @@
namespace inferno { namespace inferno {
InfernoApp* inferno_create() std::unique_ptr<InfernoApp> inferno_create()
{ {
// MOTD // MOTD
yolo::info("INFERNO HART v" INFERNO_VERSION); yolo::info("INFERNO HART v" INFERNO_VERSION);
InfernoApp* app = new InfernoApp(); std::unique_ptr<InfernoApp> app = std::make_unique<InfernoApp>();
app->Input = std::make_unique<InfernoInput>();
// Create window // Create window
graphics::window_create("Inferno v" INFERNO_VERSION, 1280, 720); graphics::window_create("Inferno v" INFERNO_VERSION, 1280, 720);
return app; return app;
} }
void inferno_cleanup(InfernoApp* app) void inferno_cleanup(std::unique_ptr<InfernoApp>& app)
{ {
graphics::window_cleanup();
app.reset();
} }
static void inferno_gui_help_marker(const char* desc) static void inferno_gui_help_marker(const char* desc)
@@ -53,7 +57,7 @@ static void inferno_gui_help_marker(const char* desc)
} }
} }
void inferno_preset_gui(InfernoApp* app) void inferno_preset_gui(std::unique_ptr<InfernoApp>& app)
{ {
ImGuiID dockspace_id = ImGui::GetID("main"); ImGuiID dockspace_id = ImGui::GetID("main");
@@ -70,7 +74,7 @@ void inferno_preset_gui(InfernoApp* app)
yolo::info("LAYOUT SET TO DEFAULT"); yolo::info("LAYOUT SET TO DEFAULT");
} }
void inferno_move_input(InfernoApp* app) void inferno_move_input(std::unique_ptr<InfernoApp>& app)
{ {
static GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR); static GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
glfwSetCursor(graphics::window_get_glfw_window(), cursor); glfwSetCursor(graphics::window_get_glfw_window(), cursor);
@@ -109,13 +113,13 @@ void inferno_move_input(InfernoApp* app)
app->Input->MovementDelta |= 0b00000100; app->Input->MovementDelta |= 0b00000100;
} }
void inferno_stop_move_input(InfernoApp* app) void inferno_stop_move_input(std::unique_ptr<InfernoApp>& app)
{ {
app->Input->MovementDelta = 0x0; app->Input->MovementDelta = 0x0;
app->Input->MouseDelta = { 0.0f, 0.0f }; app->Input->MouseDelta = { 0.0f, 0.0f };
} }
int inferno_run(InfernoApp* app) int inferno_run(std::unique_ptr<InfernoApp>& app)
{ {
while (true) { while (true) {
@@ -152,25 +156,25 @@ int inferno_run(InfernoApp* app)
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
if (showPreview && ImGui::Begin("Preview", nullptr, ImGuiWindowFlags_NoScrollbar)) if (showPreview && ImGui::Begin("Preview", nullptr, ImGuiWindowFlags_NoScrollbar)) {
{ if (ImGui::IsWindowHovered()) {
if (ImGui::IsWindowHovered())
{
inferno_move_input(app); inferno_move_input(app);
} else } else {
{
inferno_stop_move_input(app); inferno_stop_move_input(app);
} }
if (glm::length(app->Input->MouseDelta) > 0.0f) camera.mouseMoved(mouseDelta); if (glm::length(app->Input->MouseDelta) > 0.0f)
if (movementDelta != 0b00000000) camera.moveCamera(movementDelta); camera.mouseMoved(app->Input->MouseDelta);
if (app->Input->MovementDelta != 0b00000000)
camera.moveCamera(app->Input->MovementDelta);
camera.setRasterViewport({ImGui::GetWindowSize().x, ImGui::GetWindowSize().y}); camera.setRasterViewport({ ImGui::GetWindowSize().x, ImGui::GetWindowSize().y });
mRasterRenderer->setTargetSize({ImGui::GetWindowSize().x, ImGui::GetWindowSize().y}); mRasterRenderer->setTargetSize({ ImGui::GetWindowSize().x, ImGui::GetWindowSize().y });
mRasterRenderer->prepare(); mRasterRenderer->prepare();
mRasterRenderer->draw(); mRasterRenderer->draw();
ImGui::Image((ImTextureID)mRasterRenderer->getRenderedTexture(),
ImGui::Image((ImTextureID)mRasterRenderer->getRenderedTexture(),inderno
{ mRasterRenderer->getTargetSize().x, mRasterRenderer->getTargetSize().y }, { mRasterRenderer->getTargetSize().x, mRasterRenderer->getTargetSize().y },
ImVec2(0,1), ImVec2(1,0)); ImVec2(0, 1), ImVec2(1, 0));
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
ImGui::End(); ImGui::End();
} }

View File

@@ -6,23 +6,20 @@
namespace inferno { namespace inferno {
class Window;
class HHM;
typedef struct InfernoInput { typedef struct InfernoInput {
glm::vec2 MouseDelta; glm::vec2 MouseDelta;
uint8_t MovementDelta; uint8_t MovementDelta;
} InfernoInput; } InfernoInput;
typedef struct InfernoApp { typedef struct InfernoApp {
InfernoInput* Input; std::unique_ptr<InfernoInput> Input;
} InfernoApp; } InfernoApp;
InfernoApp* inferno_create(); std::unique_ptr<InfernoApp> inferno_create();
void inferno_cleanup(InfernoApp* app); void inferno_cleanup(std::unique_ptr<InfernoApp>& app);
void inferno_preset_gui(InfernoApp* app); void inferno_preset_gui(std::unique_ptr<InfernoApp>& app);
void inferno_move_input(InfernoApp* app); void inferno_move_input(std::unique_ptr<InfernoApp>& app);
void inferno_stop_move_input(InfernoApp* app); void inferno_stop_move_input(std::unique_ptr<InfernoApp>& app);
int inferno_run(InfernoApp* app); int inferno_run(std::unique_ptr<InfernoApp>& app);
} }

View File

@@ -5,6 +5,6 @@
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
auto* inferno = inferno::inferno_create(); std::unique_ptr<inferno::InfernoApp> inferno = inferno::inferno_create();
return inferno::inferno_run(inferno); return inferno::inferno_run(inferno);
} }

View File

@@ -1,205 +1,214 @@
#include <scene/camera.hpp> #include <scene/camera.hpp>
using namespace inferno; namespace inferno::graphics {
Camera::Camera() typedef struct _CameraImpl {
glm::ivec2 Viewport = { 100, 100 };
glm::ivec2 RayViewport = { 200, 200 };
bool DidUpdate;
std::mutex CamMutex;
} _CameraImpl;
std::unique_ptr<Camera> camera_create()
{ {
mProjMatrix = glm::perspective( glm::radians(FOV), 1.0f, 0.1f, 1000.0f ); std::unique_ptr<Camera> camera = std::make_unique<Camera>();
camera->_impl = std::make_unique<_CameraImpl>();
Roll = 0.0f; camera->ProjectionMatrix = glm::perspective(
Pitch = 0.0f; glm::radians(camera->FOV),
Yaw = 0.0f; 1.0f,
0.1f,
1000.0f);
camera->ViewMatrix = {};
Position = {}; camera->Roll = 0.0f;
LookDirection = {}; camera->Pitch = 0.0f;
camera->Yaw = 0.0f;
mViewMatrix = {}; camera->Position = {};
camera->LookDirection = {};
update(); camera_update(camera);
return camera;
} }
Camera::Camera(int w, int h) void camera_cleanup(std::unique_ptr<Camera>& camera)
{ {
mProjMatrix = glm::perspective(glm::radians(FOV), (float)w / (float)h, 0.1f, 1000.0f); camera->_impl.reset();
camera.reset();
Roll = 0.0f;
Pitch = 0.0f;
Yaw = 0.0f;
Position = {};
LookDirection = {};
mViewMatrix = {};
update();
} }
void Camera::update() void camera_update(std::unique_ptr<Camera>& camera)
{ {
glm::mat4 matRoll = glm::mat4(1.0f); glm::mat4 matRoll = glm::mat4(1.0f);
glm::mat4 matPitch = glm::mat4(1.0f); glm::mat4 matPitch = glm::mat4(1.0f);
glm::mat4 matYaw = glm::mat4(1.0f); glm::mat4 matYaw = glm::mat4(1.0f);
matRoll = glm::rotate(matRoll, Roll, glm::vec3(0.0f, 0.0f, 1.0f)); matRoll = glm::rotate(matRoll, Roll, glm::vec3(0.0f, 0.0f, 1.0f));
matPitch = glm::rotate(matPitch, Pitch, glm::vec3(1.0f, 0.0f, 0.0f)); matPitch = glm::rotate(matPitch, Pitch, glm::vec3(1.0f, 0.0f, 0.0f));
matYaw = glm::rotate(matYaw, Yaw, glm::vec3( 0.0f, 1.0f, 0.0f)); matYaw = glm::rotate(matYaw, Yaw, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 rotate = matRoll * matPitch * matYaw; glm::mat4 rotate = matRoll * matPitch * matYaw;
mCameraLook = rotate; mCameraLook = rotate;
glm::mat4 translate = glm::mat4(1.0f); glm::mat4 translate = glm::mat4(1.0f);
translate = glm::translate(translate, -Position); translate = glm::translate(translate, -Position);
std::lock_guard<std::mutex> lock(this->_mCam); std::lock_guard<std::mutex> lock(this->_mCam);
mViewMatrix = rotate * translate; mViewMatrix = rotate * translate;
mProjMatrix = glm::perspective(glm::radians(FOV), mViewport.x / mViewport.y, 0.1f, 1000.0f); mProjMatrix = glm::perspective(glm::radians(FOV), mViewport.x / mViewport.y, 0.1f, 1000.0f);
// Work out Look Vector // Work out Look Vector
glm::mat4 inverseView = glm::inverse(mViewMatrix); glm::mat4 inverseView = glm::inverse(mViewMatrix);
LookDirection.x = inverseView[2][0]; LookDirection.x = inverseView[2][0];
LookDirection.y = inverseView[2][1]; LookDirection.y = inverseView[2][1];
LookDirection.z = inverseView[2][2]; LookDirection.z = inverseView[2][2];
mDidUpdate = true; mDidUpdate = true;
} }
bool Camera::didUpdate() bool Camera::didUpdate()
{ {
std::lock_guard<std::mutex> lock(this->_mCam); std::lock_guard<std::mutex> lock(this->_mCam);
return mDidUpdate; return mDidUpdate;
} }
void Camera::newFrame() void Camera::newFrame()
{ {
std::lock_guard<std::mutex> lock(this->_mCam); std::lock_guard<std::mutex> lock(this->_mCam);
mDidUpdate = false; mDidUpdate = false;
} }
glm::mat4 Camera::getViewMatrix() glm::mat4 Camera::getViewMatrix()
{ {
std::lock_guard<std::mutex> lock(this->_mCam); std::lock_guard<std::mutex> lock(this->_mCam);
return mViewMatrix; return mViewMatrix;
} }
glm::mat4 Camera::getProjectionMatrix() glm::mat4 Camera::getProjectionMatrix()
{ {
std::lock_guard<std::mutex> lock(this->_mCam); std::lock_guard<std::mutex> lock(this->_mCam);
return mProjMatrix; return mProjMatrix;
} }
glm::mat4 Camera::getCameraLook() glm::mat4 Camera::getCameraLook()
{ {
std::lock_guard<std::mutex> lock(this->_mCam); std::lock_guard<std::mutex> lock(this->_mCam);
return mCameraLook; return mCameraLook;
} }
void Camera::setRasterViewport(glm::vec2 viewport) void Camera::setRasterViewport(glm::vec2 viewport)
{ {
std::lock_guard<std::mutex> lock(this->_mCam); std::lock_guard<std::mutex> lock(this->_mCam);
mViewport = viewport; mViewport = viewport;
mProjMatrix = glm::perspective(glm::radians(FOV), (float)viewport.x / (float)viewport.y, 0.1f, 1000.0f); mProjMatrix = glm::perspective(glm::radians(FOV), (float)viewport.x / (float)viewport.y, 0.1f, 1000.0f);
} }
void Camera::moveCamera(uint8_t posDelta) void Camera::moveCamera(uint8_t posDelta)
{ {
if (posDelta == 0) return; if (posDelta == 0)
return;
// Rotate by camera direction // Rotate by camera direction
glm::vec3 delta(0.0f); glm::vec3 delta(0.0f);
glm::mat2 rotate {
cos(Yaw), -sin(Yaw),
sin(Yaw), cos(Yaw)
};
glm::vec2 f(0.0, 1.0); glm::mat2 rotate {
f = f * rotate; cos(Yaw), -sin(Yaw),
sin(Yaw), cos(Yaw)
};
if (posDelta & 0x80) { glm::vec2 f(0.0, 1.0);
delta.z -= f.y; f = f * rotate;
delta.x -= f.x;
}
if (posDelta & 0x20) {
delta.z += f.y;
delta.x += f.x;
}
if (posDelta & 0x40) {
delta.z += f.x;
delta.x += -f.y;
}
if (posDelta & 0x10) {
delta.z -= f.x;
delta.x -= -f.y;
}
if (posDelta & 0x8) {
delta.y += 1;
}
if (posDelta & 0x4) {
delta.y -= 1;
}
// get current view matrix if (posDelta & 0x80) {
glm::mat4 mat = getViewMatrix(); delta.z -= f.y;
glm::vec3 forward(mat[0][2], mat[1][2], mat[2][2]); delta.x -= f.x;
glm::vec3 strafe(mat[0][0], mat[1][0], mat[2][0]); }
if (posDelta & 0x20) {
delta.z += f.y;
delta.x += f.x;
}
if (posDelta & 0x40) {
delta.z += f.x;
delta.x += -f.y;
}
if (posDelta & 0x10) {
delta.z -= f.x;
delta.x -= -f.y;
}
if (posDelta & 0x8) {
delta.y += 1;
}
if (posDelta & 0x4) {
delta.y -= 1;
}
// forward vector must be negative to look forward. // get current view matrix
// read :http://in2gpu.com/2015/05/17/view-matrix/ glm::mat4 mat = getViewMatrix();
Position += delta * CameraSpeed; glm::vec3 forward(mat[0][2], mat[1][2], mat[2][2]);
glm::vec3 strafe(mat[0][0], mat[1][0], mat[2][0]);
// update the view matrix // forward vector must be negative to look forward.
update(); // read :http://in2gpu.com/2015/05/17/view-matrix/
Position += delta * CameraSpeed;
// update the view matrix
update();
} }
void Camera::mouseMoved(glm::vec2 mouseDelta) void Camera::mouseMoved(glm::vec2 mouseDelta)
{ {
if (glm::length(mouseDelta) == 0) return; if (glm::length(mouseDelta) == 0)
// note that yaw and pitch must be converted to radians. return;
// this is done in update() by glm::rotate // note that yaw and pitch must be converted to radians.
Yaw += MouseSensitivity * (mouseDelta.x / 100); // this is done in update() by glm::rotate
Pitch += MouseSensitivity * (mouseDelta.y / 100); Yaw += MouseSensitivity * (mouseDelta.x / 100);
Pitch = glm::clamp<float>(Pitch, -M_PI / 2, M_PI / 2); Pitch += MouseSensitivity * (mouseDelta.y / 100);
Pitch = glm::clamp<float>(Pitch, -M_PI / 2, M_PI / 2);
update(); update();
} }
void Camera::setPosition(glm::vec3 position) void Camera::setPosition(glm::vec3 position)
{ {
Position = position; Position = position;
update(); update();
} }
void Camera::setEulerLook(float roll, float pitch, float yaw) void Camera::setEulerLook(float roll, float pitch, float yaw)
{ {
Roll = roll; Pitch = pitch; Yaw = yaw; Roll = roll;
LookDirection.x = cos(Yaw) * cos(Pitch); Pitch = pitch;
LookDirection.y = sin(Yaw) * cos(Pitch); Yaw = yaw;
LookDirection.z = sin(Pitch); LookDirection.x = cos(Yaw) * cos(Pitch);
LookDirection.y = sin(Yaw) * cos(Pitch);
LookDirection.z = sin(Pitch);
update(); update();
} }
void Camera::setLook(glm::vec3 lookDirection) void Camera::setLook(glm::vec3 lookDirection)
{ {
LookDirection = lookDirection; LookDirection = lookDirection;
Pitch = asin(-lookDirection.y); Pitch = asin(-lookDirection.y);
Yaw = atan2(lookDirection.x, lookDirection.z); Yaw = atan2(lookDirection.x, lookDirection.z);
update(); update();
} }
void Camera::setRayViewport(glm::vec2 viewport) void Camera::setRayViewport(glm::vec2 viewport)
{ {
std::lock_guard<std::mutex> lock(this->_mCam); std::lock_guard<std::mutex> lock(this->_mCam);
mRayViewport = viewport; mRayViewport = viewport;
} }
glm::vec2 Camera::getRayViewport() glm::vec2 Camera::getRayViewport()
{ {
std::lock_guard<std::mutex> lock(this->_mCam); std::lock_guard<std::mutex> lock(this->_mCam);
return mRayViewport; return mRayViewport;
} }
}