diff --git a/include/Camera.h b/include/Camera.h new file mode 100644 index 0000000..087c4ce --- /dev/null +++ b/include/Camera.h @@ -0,0 +1,93 @@ +//----------------------------------------------------------------------------- +// Basic camera class including derived orbit-style and first person +// shooter (FPS) style camera support +//----------------------------------------------------------------------------- +#ifndef CAMERA_H +#define CAMERA_H + +#include "glm/glm.hpp" +#include "glm/gtc/constants.hpp" + + +//-------------------------------------------------------------- +// Abstract Camera Class +//-------------------------------------------------------------- +class Camera +{ +public: + glm::mat4 getViewMatrix() const; + + virtual void setPosition(const glm::vec3& position) {} + virtual void rotate(float yaw, float pitch) {} // in degrees + virtual void move(const glm::vec3& offsetPos) {} + + const glm::vec3& getLook() const; + const glm::vec3& getRight() const; + const glm::vec3& getUp() const; + const glm::vec3& getPosition() const; + + float getFOV() const { return mFOV; } + void setFOV(float fov) { mFOV = fov; } // in degrees + +protected: + Camera(); + + virtual void updateCameraVectors() {} + + glm::vec3 mPosition; + glm::vec3 mTargetPos; + glm::vec3 mLook; + glm::vec3 mUp; + glm::vec3 mRight; + const glm::vec3 WORLD_UP; + + // Euler Angles (in radians) + float mYaw; + float mPitch; + + // Camera parameters + float mFOV; // degrees +}; + +//-------------------------------------------------------------- +// FPS Camera Class +//-------------------------------------------------------------- +class FPSCamera : public Camera +{ +public: + + FPSCamera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), float yaw = glm::pi(), float pitch = 0.0f); // (yaw) initial angle faces -Z + + virtual void setPosition(const glm::vec3& position); + virtual void rotate(float yaw, float pitch); // in degrees + virtual void move(const glm::vec3& offsetPos); + +private: + + void updateCameraVectors(); +}; + + +//-------------------------------------------------------------- +// Orbit Camera Class +//-------------------------------------------------------------- +class OrbitCamera : public Camera +{ +public: + + OrbitCamera(); + + virtual void rotate(float yaw, float pitch); // in degrees + + // Camera Controls + void setLookAt(const glm::vec3& target); + void setRadius(float radius); + +private: + + void updateCameraVectors(); + + // Camera parameters + float mRadius; +}; +#endif //CAMERA_H diff --git a/include/engine.h b/include/engine.h index e96017d..820aea3 100644 --- a/include/engine.h +++ b/include/engine.h @@ -3,6 +3,7 @@ #include #include +#include "Camera.h" #include "ShaderProgram.h" #include #include @@ -29,24 +30,35 @@ namespace djalim { public: void start(); + OpenGlEngine(); OpenGlEngine( const char* title, int width, int height); ~OpenGlEngine(); GLFWwindow* window; + + int windowWidth; + int windowHeight; + + const double ZOOM_SENSITIVITY = -3.0; + const float MOVE_SPEED = 5.0; // units per second + const float MOUSE_SENSITIVITY = 0.1f; + double previousSeconds = 0.0; double elapsedSeconds; int frameCount = 0; ShaderProgram shaderProgram; + FPSCamera Camera = FPSCamera(glm::vec3(0.0f, 2.0f, 10.0f)); Objects3D objects; - + unsigned int VBO; unsigned int VAO; - + bool gWireframe = false; void onUpdate(); void loadHints(); + void cameraUpdate(); void createObject(std::string name, std::string textures, std::string filepath); void createObject(std::string name, std::string textures, std::string filepath, glm::vec3 position, glm::vec3 rotation, glm::vec3 scale); void loadCallbacks(); @@ -57,4 +69,6 @@ namespace djalim { }; } + + #endif // ENGINE_H diff --git a/src/Camera.cpp b/src/Camera.cpp new file mode 100644 index 0000000..cd21e4d --- /dev/null +++ b/src/Camera.cpp @@ -0,0 +1,182 @@ +//----------------------------------------------------------------------------- +// Basic camera class including derived orbit-style and first person +// shooter (FPS) style camera support +//----------------------------------------------------------------------------- +#include "Camera.h" +#include "glm/gtc/matrix_transform.hpp" + +// Default camera values +const float DEF_FOV = 45.0f; // degrees + +//------------------------------------------------------------ +// Base Camera class constructor +//------------------------------------------------------------ +Camera::Camera() +: mPosition(glm::vec3(0.0f, 0.0f, 0.0f)), + mTargetPos(glm::vec3(0.0f, 0.0f, 0.0f)), + mUp(glm::vec3(0.0f, 1.0f, 0.0f)), + mRight(1.0f, 0.0f, 0.0f), + WORLD_UP(0.0f, 1.0f, 0.0f), + mYaw(glm::pi()), + mPitch(0.0f), + mFOV(DEF_FOV) +{ +} + +//------------------------------------------------------------ +// Base Camera - Returns view matrix +//------------------------------------------------------------ +glm::mat4 Camera::getViewMatrix()const +{ + return glm::lookAt(mPosition, mTargetPos, mUp); +} + +//------------------------------------------------------------ +// Base Camera - Returns camera's local look vector +//------------------------------------------------------------ +const glm::vec3& Camera::getLook() const +{ + return mLook; +} + +//------------------------------------------------------------ +// Base Camera - Returns camera's local right vector +//------------------------------------------------------------ +const glm::vec3& Camera::getRight() const +{ + return mRight; +} + +//------------------------------------------------------------ +// Base Camera - Returns camera's local up vector +//------------------------------------------------------------ +const glm::vec3& Camera::getUp() const +{ + return mUp; +} + +//------------------------------------------------------------ +// Base Camera - Returns camera's position +//------------------------------------------------------------ +const glm::vec3& Camera::getPosition() const +{ + return mPosition; +} + +//----------------------------------------------------------------------------- +// FPSCamera - Constructor +//----------------------------------------------------------------------------- +FPSCamera::FPSCamera(glm::vec3 position, float yaw, float pitch) +{ + mPosition = position; + mYaw = yaw; + mPitch = pitch; +} + +//----------------------------------------------------------------------------- +// FPSCamera - Sets the camera position in world space +//----------------------------------------------------------------------------- +void FPSCamera::setPosition(const glm::vec3& position) +{ + mPosition = position; +} + +//----------------------------------------------------------------------------- +// FPSCamera - Sets the incremental position of the camera in world space +//----------------------------------------------------------------------------- +void FPSCamera::move(const glm::vec3& offsetPos) +{ + mPosition += offsetPos; + updateCameraVectors(); +} + +//----------------------------------------------------------------------------- +// FPSCamera - Sets the incremental orientation of the camera +//----------------------------------------------------------------------------- +void FPSCamera::rotate(float yaw, float pitch) +{ + mYaw += glm::radians(yaw); + mPitch += glm::radians(pitch); + + // Constrain the pitch + mPitch = glm::clamp(mPitch, -glm::pi() / 2.0f + 0.1f, glm::pi() / 2.0f - 0.1f); + updateCameraVectors(); +} + +//----------------------------------------------------------------------------- +// FPSCamera - Calculates the front vector from the Camera's (updated) Euler Angles +//----------------------------------------------------------------------------- +void FPSCamera::updateCameraVectors() +{ + // Spherical to Cartesian coordinates + // https://en.wikipedia.org/wiki/Spherical_coordinate_system (NOTE: Our coordinate sys has Y up not Z) + + // Calculate the view direction vector based on yaw and pitch angles (roll not considered) + // radius is 1 for normalized length + glm::vec3 look; + look.x = cosf(mPitch) * sinf(mYaw); + look.y = sinf(mPitch); + look.z = cosf(mPitch) * cosf(mYaw); + + mLook = glm::normalize(look); + + // Re-calculate the Right and Up vector. For simplicity the Right vector will + // be assumed horizontal w.r.t. the world's Up vector. + mRight = glm::normalize(glm::cross(mLook, WORLD_UP)); + mUp = glm::normalize(glm::cross(mRight, mLook)); + + mTargetPos = mPosition + mLook; +} + + +//------------------------------------------------------------ +// OrbitCamera - constructor +//------------------------------------------------------------ +OrbitCamera::OrbitCamera() + : mRadius(10.0f) +{} + +//------------------------------------------------------------ +// OrbitCamera - Sets the target to look at +//------------------------------------------------------------ +void OrbitCamera::setLookAt(const glm::vec3& target) +{ + mTargetPos = target; +} + +//------------------------------------------------------------ +// OrbitCamera - Sets the radius of camera to target distance +//------------------------------------------------------------ +void OrbitCamera::setRadius(float radius) +{ + // Clamp the radius + mRadius = glm::clamp(radius, 2.0f, 80.0f); +} + +//------------------------------------------------------------ +// OrbitCamera - Rotates the camera around the target look +// at position given yaw and pitch in degrees. +//------------------------------------------------------------ +void OrbitCamera::rotate(float yaw, float pitch) +{ + mYaw = glm::radians(yaw); + mPitch = glm::radians(pitch); + + mPitch = glm::clamp(mPitch, -glm::pi() / 2.0f + 0.1f, glm::pi() / 2.0f - 0.1f); + + // Update Front, Right and Up Vectors using the updated Euler angles + updateCameraVectors(); +} + +//------------------------------------------------------------ +// OrbitCamera - Calculates the front vector from the Camera's +// (updated) Euler Angles +//------------------------------------------------------------ +void OrbitCamera::updateCameraVectors() +{ + // Spherical to Cartesian coordinates + // https://en.wikipedia.org/wiki/Spherical_coordinate_system (NOTE: Our coordinate sys has Y up not Z) + mPosition.x = mTargetPos.x + mRadius * cosf(mPitch) * sinf(mYaw); + mPosition.y = mTargetPos.y + mRadius * sinf(mPitch); + mPosition.z = mTargetPos.z + mRadius * cosf(mPitch) * cosf(mYaw); +} diff --git a/src/core/Mesh3D.cpp b/src/core/Mesh3D.cpp index 5248d34..821fe95 100644 --- a/src/core/Mesh3D.cpp +++ b/src/core/Mesh3D.cpp @@ -1,12 +1,10 @@ #include "Mesh3D.h" #include #include -#include #include #include #include - struct objVertex { float x, y, z; }; @@ -23,8 +21,6 @@ struct objFace { objFaceIndice vertices[3]; }; - - djalim::Mesh3D::Mesh3D(){} djalim::Mesh3D::Mesh3D(const std::string& filepath) { @@ -122,5 +118,3 @@ void djalim::Mesh3D::loadOBJFile(const std::string& filepath) { } } } - - diff --git a/src/core/callbacks.cpp b/src/core/callbacks.cpp index a83c5b2..97ea5a2 100644 --- a/src/core/callbacks.cpp +++ b/src/core/callbacks.cpp @@ -24,6 +24,38 @@ void mainCallback(GLFWwindow* window, int key, int scancode, int action, int mod } +void glfw_onFramebufferSize(GLFWwindow* window, int width, int height) +{ + auto* engine = static_cast(glfwGetWindowUserPointer(window)); + + engine->windowWidth = width; + engine->windowHeight = height; + + + // Define the viewport dimensions + int w, h; + glfwGetFramebufferSize( engine->window, &w, &h); // For retina display + glViewport(0, 0, w, h); + // glViewport(0, 0, gWindowWidth, gWindowHeight); + +} + +//----------------------------------------------------------------------------- +// Called by GLFW when the mouse wheel is rotated +//----------------------------------------------------------------------------- +void glfw_onMouseScroll(GLFWwindow* window, double deltaX, double deltaY) +{ + auto* engine = static_cast(glfwGetWindowUserPointer(window)); + double fov = engine->Camera.getFOV() + deltaY * engine->ZOOM_SENSITIVITY; + + fov = glm::clamp(fov, 1.0, 120.0); + + engine->Camera.setFOV((float)fov); +} + + void djalim::OpenGlEngine::loadCallbacks(){ glfwSetKeyCallback(window, mainCallback); + glfwSetFramebufferSizeCallback(window, glfw_onFramebufferSize); + glfwSetScrollCallback(window, glfw_onMouseScroll); } diff --git a/src/core/engine.cpp b/src/core/engine.cpp index d820bef..9425807 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -1,5 +1,6 @@ #include "engine.h" #include "Mesh3D.h" +#include #include #include #include @@ -9,6 +10,8 @@ #include #include +djalim::OpenGlEngine::OpenGlEngine(){} + djalim::OpenGlEngine::OpenGlEngine(const char* title, int width, int height) { // initialize GLFW if (!glfwInit()) { @@ -25,7 +28,12 @@ djalim::OpenGlEngine::OpenGlEngine(const char* title, int width, int height) { exit(1); } + windowWidth = width; + windowHeight = height; + glfwMakeContextCurrent(this->window); + glfwSetWindowUserPointer(this->window, this); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // initialize GLEW glewExperimental = GL_TRUE; @@ -53,8 +61,6 @@ void djalim::OpenGlEngine::createObject(std::string name, std::string textures, (objects[name])->scale = scale; } - - void djalim::OpenGlEngine::createObject(std::string name, std::string textures, std::string filepath){ // Load the mesh from the file @@ -62,7 +68,7 @@ void djalim::OpenGlEngine::createObject(std::string name, std::string textures, bool textureLoaded = objects[name]->texture.loadTexture(textures); - std::cout << &(objects[name]) << std::endl; + std::cout << &(objects[name]) << std::endl; if (!textureLoaded) { std::cerr << "Failed to load " << name << " texture!" << std::endl; @@ -114,6 +120,7 @@ void djalim::OpenGlEngine::start(){ //glClearColor(0, 0.5, 0.5, 1.0f); onUpdate(); + cameraUpdate(); glfwSwapBuffers(this->window); @@ -136,3 +143,40 @@ void djalim::OpenGlEngine::draw(djalim::Mesh3D* object){ glBindVertexArray(object->VAO); glDrawArrays(GL_TRIANGLES, 0, object->numFaces * 3); } + + +void djalim::OpenGlEngine::cameraUpdate(){ + + // Camera orientation + double mouseX, mouseY; + + // Get the current mouse cursor position delta + glfwGetCursorPos(window, &mouseX, &mouseY); + + // Rotate the camera the difference in mouse distance from the center screen. Multiply this delta by a speed scaler + Camera.rotate((float)(windowWidth / 2.0 - mouseX) * MOUSE_SENSITIVITY, (float)(windowHeight / 2.0 - mouseY) * MOUSE_SENSITIVITY); + + // Clamp mouse cursor to center of screen + glfwSetCursorPos(window, windowWidth / 2.0, windowHeight / 2.0); + + // Camera FPS movement + + // Forward/backward + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + Camera.move(MOVE_SPEED * (float)elapsedSeconds * Camera.getLook()); + else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + Camera.move(MOVE_SPEED * (float)elapsedSeconds * -Camera.getLook()); + + // Strafe left/right + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + Camera.move(MOVE_SPEED * (float)elapsedSeconds * -Camera.getRight()); + else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + Camera.move(MOVE_SPEED * (float)elapsedSeconds * Camera.getRight()); + + // Up/down + if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) + Camera.move(MOVE_SPEED * (float)elapsedSeconds * glm::vec3(0.0f, 1.0f, 0.0f)); + else if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) + Camera.move(MOVE_SPEED * (float)elapsedSeconds * -glm::vec3(0.0f, 1.0f, 0.0f)); + +} diff --git a/src/loops/cube.cpp b/src/loops/cube.cpp deleted file mode 100644 index 8b13789..0000000 --- a/src/loops/cube.cpp +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/loops/rainbowWindow.cpp b/src/loops/rainbowWindow.cpp deleted file mode 100644 index 02e3e44..0000000 --- a/src/loops/rainbowWindow.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "engine.h" -#include "loops.h" -#include "iostream" -#include - - -void djalim::rainbowWindow(double elapsedSeconds){ - static double red = 0.0; - static double green= 0.0; - static double blue = 0.0; - static double thresh = 0.0; - - thresh += elapsedSeconds; - - if (thresh >0.1){ - thresh = 0.0; - red += 0.1; - if( red > 1.0 ) { - red = 0.0; - green += 0.1; - if( green > 1.0 ) { - green = 0.0; - blue += 0.1; - if( blue > 1.0 ) { - blue = 0.0; - } - } - } - } - std::cout << "red: " << red << ", green: " << green << ", blue: " << blue << " \r"; - glClearColor(red, green, blue, 1.0f); -} diff --git a/src/loops/rbgTriangle.cpp b/src/loops/rbgTriangle.cpp deleted file mode 100644 index 9c8a686..0000000 --- a/src/loops/rbgTriangle.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "engine.h" -#include "loops.h" - -void djalim::rgbTriangle(djalim::ShaderProgram shaderProgram, unsigned int VAO){ - // Dessiner le triangle - shaderProgram.use(); - glBindVertexArray(VAO); - glDrawArrays(GL_TRIANGLES, 0, 3); - - glClearColor(0, 0.5, 0.5, 1.0f); - -} diff --git a/src/main.cpp b/src/main.cpp index a1ec38f..9443b40 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ #include "engine.h" int main() { - djalim::OpenGlEngine engine = djalim::OpenGlEngine("Mon app", 800, 600); - engine.start(); - return 0; + djalim::OpenGlEngine engine = djalim::OpenGlEngine("Mon app", 800, 600); + engine.start(); + return 0; } diff --git a/src/onCreate.cpp b/src/onCreate.cpp index 6bf639e..6d6ab79 100644 --- a/src/onCreate.cpp +++ b/src/onCreate.cpp @@ -2,12 +2,18 @@ #include "Texture2D.h" void djalim::OpenGlEngine::onCreate(){ - glEnable(GL_DEPTH_TEST); + glEnable(GL_DEPTH_TEST); stbi_set_flip_vertically_on_load(true); - createObject("cube", "../assets/textures/prof.png", "../assets/models/L.obj"); createObject("mimikyu", + "../assets/textures/crate.jpg", + "../assets/models/destiny island.obj", + glm::vec3(0.0,0.0,0.0), + glm::vec3(0.0,0.0,0.0), + glm::vec3(.1,.1,.1) + ); + createObject("cube", "../assets/textures/crate.jpg", "../assets/models/crate.obj", glm::vec3(1.0,1.0,1.0), diff --git a/src/onUpdate.cpp b/src/onUpdate.cpp index 199b497..cb3c0e7 100644 --- a/src/onUpdate.cpp +++ b/src/onUpdate.cpp @@ -4,23 +4,25 @@ #include void djalim::OpenGlEngine::onUpdate(){ - showFps(); + showFps(); - shaderProgram.use(); - shaderProgram.setUniform("ourTexture", 0); + shaderProgram.use(); + shaderProgram.setUniform("ourTexture", 0); - // Matrice de Projection - glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); - shaderProgram.setUniform("projection", projection); + glm::mat4 model(1.0), view(1.0), projection(1.0); - // Matrice de Vue - glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 10.0f), // Position caméra - glm::vec3(0.0f, 0.0f, 0.0f), // Cible - glm::vec3(0.0f, 1.0f, 0.0f)); // Axe Haut - shaderProgram.setUniform("view", view); + // Create the View matrix + view = Camera.getViewMatrix(); - draw((objects["cube"]).get()); - draw((objects["mimikyu"]).get()); + // Create the projection matrix + projection = glm::perspective(glm::radians(Camera.getFOV()), (float)windowWidth / (float)windowHeight, 0.1f, 200.0f); + + // Matrice de Projection + shaderProgram.setUniform("projection", projection); + shaderProgram.setUniform("view", view); + + draw((objects["cube"]).get()); + draw((objects["mimikyu"]).get()); }