Add camera movement

- Add camera API
- Add mouse event
- Add member
This commit is contained in:
Linloir 2022-12-13 16:30:49 +08:00
parent f5f2247274
commit 069aca1cf2
No known key found for this signature in database
GPG Key ID: 58EEB209A0F2C366
4 changed files with 146 additions and 34 deletions

View File

@ -3,6 +3,9 @@
#include <GLM/glm.hpp>
#include <GLM/ext/matrix_transform.hpp>
#define CAMERA_MAX_ZOOM 90.0f
#define CAMERA_MIN_ZOOM 1.0f
class Camera {
public:
inline glm::vec3 defaultOrigin() { return glm::vec3(1.0f, 1.0f, 1.0f); }
@ -16,11 +19,7 @@ private:
glm::vec3 _up;
float _yaw = 0.0f;
float _pitch = 0.0f;
float _zoom = 90.0f;
private:
// Camera settings
float _moveStep = 1.0f;
float _zoom = 45.0f;
private:
// World settings
@ -33,27 +32,31 @@ public:
Camera(glm::vec3 position, float yaw, float pitch);
public:
inline float zoom() const { return _zoom; }
inline float zoomVal() const { return _zoom; }
inline glm::mat4 viewMatrix();
public:
inline void move(glm::vec3 direction, float step);
inline void move(glm::vec2 offset);
inline void setPosition(glm::vec3 position);
inline void pitch(float deltaAngle);
inline void setPitch(float angle);
inline void yaw(float deltaAngle);
inline void setYaw(float angle);
inline void rotate(float deltaPitchAngle, float deltaYawAngle);
inline void setRotation(float pitchAngle, float yawAngle);
inline void zoom(float deltaZoom);
inline void setZoom(float zoom);
inline void push(float distance);
private:
void updateCameraState();
};
inline glm::mat4 Camera::viewMatrix() {
return glm::lookAt(_position, _position + _front, _up);
}
inline void Camera::move(glm::vec3 direction, float step) {
_position += direction * step;
inline void Camera::move(glm::vec2 offset) {
// Offset describe the movement on the xy plane in the camera's coordinate system
// Should convert to the movement of position vector in world coordinate system
glm::vec3 worldSpaceOffset = offset.x * _right + offset.y * _up;
_position += worldSpaceOffset;
updateCameraState();
}
@ -81,3 +84,46 @@ inline void Camera::setYaw(float angle) {
_yaw = angle;
updateCameraState();
}
inline void Camera::rotate(float deltaPitchAngle, float deltaYawAngle) {
_pitch += deltaPitchAngle;
_yaw += deltaYawAngle;
updateCameraState();
}
inline void Camera::setRotation(float pitchAngle, float yawAngle) {
_pitch = pitchAngle;
_yaw = yawAngle;
updateCameraState();
}
inline void Camera::zoom(float deltaZoom) {
_zoom += deltaZoom;
if (_zoom > CAMERA_MAX_ZOOM) {
_zoom = CAMERA_MAX_ZOOM;
}
else if (_zoom < CAMERA_MIN_ZOOM) {
_zoom = CAMERA_MIN_ZOOM;
}
updateCameraState();
}
inline void Camera::setZoom(float zoom) {
_zoom = zoom;
if (_zoom > CAMERA_MAX_ZOOM) {
_zoom = CAMERA_MAX_ZOOM;
}
else if (_zoom < CAMERA_MIN_ZOOM) {
_zoom = CAMERA_MIN_ZOOM;
}
updateCameraState();
}
inline void Camera::push(float distance) {
_position += distance * _front;
updateCameraState();
}
inline glm::mat4 Camera::viewMatrix() {
return glm::lookAt(_position, _position + _front, _up);
}

View File

@ -55,22 +55,6 @@ void SceneViewer::initializeGL() {
Logger::info("Currently running on OpenGL version: " + std::string((const char*)glGetString(GL_VERSION)));
_vao.ensureInitialized();
Logger::info("Vertex Array Object initialized");
vector<Vertex> vertices = {
{ { -0.5f, -0.5f, 0.0f } },
{ { 0.5f, -0.5f, 0.0f } },
{ { 0.0f, 0.5f, 0.0f } }
};
VertexBufferObject vbo(vertices);
Logger::info("Vertex Buffer Object initialized");
_vao.bindVertexBufferObject(vbo);
_vao.setVertexAttributePointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
_vao.enableVertexAttribute(0);
Logger::info("Vertex Buffer Object bound to Vertex Array Object");
_shaderProgram.ensureInitialized();
Logger::info("Shader Program initialized");
@ -83,8 +67,8 @@ void SceneViewer::initializeGL() {
Model* backpackModel = new Model("E:\\Repositories\\CollegeProjects\\CGAssignments\\FinalProject\\Models\\backpack\\backpack.obj");
Logger::info("Model loaded");
Renderable renderable(backpackModel);
_objects.push_back(backpackModel);
Renderable backpack(backpackModel);
_objects.push_back(backpack);
_camera.setPosition(glm::vec3(0.0f, 0.0f, 3.0f));
_camera.setYaw(-90.0f);
@ -102,11 +86,75 @@ void SceneViewer::paintGL() {
// Set view and projection matrices
glm::mat4 view = _camera.viewMatrix();
glm::mat4 projection = glm::perspective(glm::radians(_camera.zoom()), (float)width() / (float)height(), 0.1f, 100.0f);
glm::mat4 projection = glm::perspective(glm::radians(_camera.zoomVal()), (float)width() / (float)height(), 0.1f, 100.0f);
_shaderProgram.setUniform("view", view);
_shaderProgram.setUniform("projection", projection);
for (auto object : _objects) {
object.render(_shaderProgram);
}
}
}
void SceneViewer::mousePressEvent(QMouseEvent* event) {
Logger::debug("Mouse pressed at: " + std::to_string(event->x()) + ", " + std::to_string(event->y()));
if (event->button() == Qt::LeftButton) {
// TODO: Hit test on objects
}
else {
_lastMousePosition = event->pos();
}
}
void SceneViewer::mouseMoveEvent(QMouseEvent* event) {
Logger::debug("Mouse moved with offset: " + std::to_string(event->x() - _lastMousePosition.x()) + ", " + std::to_string(event->y() - _lastMousePosition.y()));
// Check the type of button pressed
switch (event->buttons()) {
case Qt::LeftButton: {
// Move the selected object
if (_selectedObject != nullptr) {
// TODO: move the selected object
}
break;
}
case Qt::RightButton: {
// Move the camera
float xoffset = event->x() - _lastMousePosition.x();
float yoffset = _lastMousePosition.y() - event->y(); // reversed since y-coordinates go from bottom to top
float xmovement = xoffset * _cameraMovementSpeed;
float ymovement = yoffset * _cameraMovementSpeed;
Logger::debug("Camera movement: " + std::to_string(xmovement) + ", " + std::to_string(ymovement));
_camera.move({ -xmovement, -ymovement });
break;
}
case Qt::MiddleButton: {
// Rotate the camera
float xoffset = event->x() - _lastMousePosition.x();
float yoffset = _lastMousePosition.y() - event->y(); // reversed since y-coordinates go from bottom to top
// Calculate pitch angle
float pitch = yoffset * _cameraRotationSpeed;
// Calculate yaw angle
float yaw = xoffset * _cameraRotationSpeed;
Logger::debug("Camera rotation: " + std::to_string(pitch) + ", " + std::to_string(yaw));
_camera.rotate(pitch, yaw);
break;
}
default: {
Logger::warning("Unknown mouse button input");
Logger::warning("Mouse button: " + std::to_string(event->buttons()));
break;
}
}
// Update the last mouse position
_lastMousePosition = event->pos();
// Update the view
update();
}
void SceneViewer::wheelEvent(QWheelEvent* event) {
// Zoom in or out
float wheelOffset = event->angleDelta().y();
Logger::debug("Wheel offset: " + std::to_string(wheelOffset));
_camera.push(wheelOffset * _cameraPushSpeed);
// Update the view
update();
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <qwidget.h>
#include <qevent.h>
#include <qopenglfunctions.h>
#include <QtOpenGLWidgets/qopenglwidget.h>
@ -17,17 +18,34 @@ class SceneViewer : public QOpenGLWidget, protected QOpenGLFunctions
Q_OBJECT
private:
// OpenGL section-------------------------------------
// List of objects currently in the scene
std::vector<Renderable> _objects;
// Shader program for objects
ShaderProgram _shaderProgram = ShaderProgram::empty();
VertexArrayObject _vao = VertexArrayObject::empty();
// Main camera
Camera _camera;
float _cameraMovementSpeed = 0.02f;
float _cameraRotationSpeed = 0.3f;
float _cameraPushSpeed = 0.02f;
// User Interaction flags section---------------------
QPoint _lastMousePosition;
Renderable* _selectedObject = nullptr;
public:
SceneViewer(QWidget* parent = 0);
~SceneViewer();
protected:
// OpenGL functions
virtual void initializeGL() override;
virtual void paintGL() override;
virtual void resizeGL(int w, int h) override;
// Mouse events
virtual void mousePressEvent(QMouseEvent* event) override;
virtual void mouseMoveEvent(QMouseEvent* event) override;
virtual void wheelEvent(QWheelEvent* event) override;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 MiB

After

Width:  |  Height:  |  Size: 5.2 MiB