From 2b6518a20f794f05c94b0acb416c49389f93544c Mon Sep 17 00:00:00 2001 From: iridiumR Date: Mon, 29 May 2023 00:53:51 +0800 Subject: [PATCH] feat(OpenGL): lab2 camera --- OpenGL/lab2/include/camera.h | 154 +++++++++++++++++++++++++++++++++++ OpenGL/lab2/src/main.cpp | 93 ++++++++++++++++----- OpenGL/lab2/src/tex.vs | 5 +- 3 files changed, 229 insertions(+), 23 deletions(-) create mode 100644 OpenGL/lab2/include/camera.h diff --git a/OpenGL/lab2/include/camera.h b/OpenGL/lab2/include/camera.h new file mode 100644 index 0000000..120863e --- /dev/null +++ b/OpenGL/lab2/include/camera.h @@ -0,0 +1,154 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include "glad/glad.h" +#include +#include +#include +#include + +// Defines several possible options for camera movement. Used as abstraction to +// stay away from window-system specific input methods +enum Camera_Movement { FORWARD, BACKWARD, LEFT, RIGHT, UP, DOWN }; + +// Default camera values +const float YAW = -90.0f; +const float PITCH = 0.0f; +const float SPEED = 2.5f; +const float SENSITIVITY = 0.1f; +const float ZOOM = 45.0f; + +// An abstract camera class that processes input and calculates the +// corresponding Euler Angles, Vectors and Matrices for use in OpenGL +class Camera { +public: + // camera Attributes + glm::vec3 Position; + glm::vec3 Front; + glm::vec3 Up; + glm::vec3 Right; + glm::vec3 WorldUp; + // euler Angles + float Yaw; + float Pitch; + // camera options + float MovementSpeed; + float MouseSensitivity; + float Zoom; + + bool firstMouse; + float lastX, lastY; + + // constructor with vectors + Camera(float X, float Y, glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.4f), + glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, + float pitch = PITCH) + : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), + MouseSensitivity(SENSITIVITY), Zoom(ZOOM) { + lastX = X; + lastY = Y; + Position = position; + WorldUp = up; + Yaw = yaw; + Pitch = pitch; + updateCameraVectors(); + } + // constructor with scalar values + Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, + float yaw, float pitch) + : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), + MouseSensitivity(SENSITIVITY), Zoom(ZOOM) { + Position = glm::vec3(posX, posY, posZ); + WorldUp = glm::vec3(upX, upY, upZ); + Yaw = yaw; + Pitch = pitch; + updateCameraVectors(); + } + + // returns the view matrix calculated using Euler Angles and the LookAt Matrix + glm::mat4 GetViewMatrix() { + return glm::lookAt(Position, Position + Front, Up); + } + + // processes input received from any keyboard-like input system. Accepts input + // parameter in the form of camera defined ENUM (to abstract it from windowing + // systems) + void ProcessKeyboard(Camera_Movement direction, float deltaTime) { + float velocity = MovementSpeed * deltaTime; + if (direction == FORWARD) + Position += Front * velocity; + if (direction == BACKWARD) + Position -= Front * velocity; + if (direction == LEFT) + Position -= Right * velocity; + if (direction == RIGHT) + Position += Right * velocity; + if (direction == UP) { + Position += Up * velocity; + if (direction == DOWN) + Position -= Up * velocity; + } + + } + + // processes input received from a mouse input system. Expects the offset + // value in both the x and y direction. + void ProcessMouseMovement(float xpos, float ypos, + GLboolean constrainPitch = true) { + if (firstMouse) { + lastX = xpos; + lastY = ypos; + firstMouse = false; + } + + float xoffset = xpos - lastX; + float yoffset = lastY - ypos; + lastX = xpos; + lastY = ypos; + + xoffset *= MouseSensitivity; + yoffset *= MouseSensitivity; + + Yaw += xoffset; + Pitch += yoffset; + + // make sure that when pitch is out of bounds, screen doesn't get flipped + if (constrainPitch) { + if (Pitch > 89.0f) + Pitch = 89.0f; + if (Pitch < -89.0f) + Pitch = -89.0f; + } + + // update Front, Right and Up Vectors using the updated Euler angles + updateCameraVectors(); + } + + // processes input received from a mouse scroll-wheel event. Only requires + // input on the vertical wheel-axis + void ProcessMouseScroll(float yoffset) { + Zoom -= (float)yoffset; + if (Zoom < 1.0f) + Zoom = 1.0f; + if (Zoom > 45.0f) + Zoom = 45.0f; + } + +private: + // calculates the front vector from the Camera's (updated) Euler Angles + void updateCameraVectors() { + // calculate the new Front vector + glm::vec3 front; + front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch)); + front.y = sin(glm::radians(Pitch)); + front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch)); + Front = glm::normalize(front); + // also re-calculate the Right and Up vector + Right = glm::normalize(glm::cross( + Front, WorldUp)); // normalize the vectors, because their length gets + // closer to 0 the more you look up or down which + // results in slower movement. + Up = glm::normalize(glm::cross(Right, Front)); + } +}; +#endif \ No newline at end of file diff --git a/OpenGL/lab2/src/main.cpp b/OpenGL/lab2/src/main.cpp index 35558cb..a0b84d4 100644 --- a/OpenGL/lab2/src/main.cpp +++ b/OpenGL/lab2/src/main.cpp @@ -1,12 +1,18 @@ +#include "camera.h" #include "glad/glad.h" #include "shader.h" #include "stb_image.h" #include #include -#include #include #include #include +#include + +// settings +const unsigned int SCR_WIDTH = 600; +const unsigned int SCR_HEIGHT = 600; + // 四边形顶点 float vertices[] = { @@ -23,12 +29,13 @@ unsigned int indices[] = { 1, 2, 3 // 第二个三角形 }; +float deltaTime, lastTime; +Camera camera = Camera(SCR_HEIGHT / 2.0f, SCR_HEIGHT / 2.0f); + void framebuffer_size_callback(GLFWwindow *window, int width, int height); void processInput(GLFWwindow *window); - -// settings -const unsigned int SCR_WIDTH = 600; -const unsigned int SCR_HEIGHT = 600; +void mouse_callback(GLFWwindow *window, double xpos, double ypos); +void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); int main() { @@ -40,7 +47,8 @@ int main() { // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 创建窗口 - GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); + GLFWwindow *window = + glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); @@ -55,7 +63,10 @@ int main() { } // 设置视口 + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetCursorPosCallback(window, mouse_callback); + glfwSetScrollCallback(window, scroll_callback); // 创建着色器程序 Shader shader = Shader("src/tex.vs", "src/tex.fs"); @@ -99,11 +110,11 @@ int main() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // 加载并生成纹理 + + // 加载并生成纹理 // 图片翻转y轴 stbi_set_flip_vertically_on_load(true); - int width, height, nrChannels; + int width, height, nrChannels; unsigned char *data = stbi_load("resources/bf-half.png", &width, &height, &nrChannels, 0); if (data) { @@ -123,38 +134,55 @@ int main() { // 绑定纹理 shader.setInt("tex", 0); - // 设置变换矩阵 + // 开启深度测试 + glEnable(GL_DEPTH_TEST); // 循环渲染 while (!glfwWindowShouldClose(window)) { + + // 计算帧时间差 + float currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastTime; + lastTime = currentFrame; + // 处理输入 processInput(window); - // 设置为白色 - glClearColor(1.0f, 1.0f, 1.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); + // 初始化 + glClearColor(0.3f, 0.3f, 0.3f, 0.3f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 绑定纹理 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); + glm::mat4 view = camera.GetViewMatrix(); + glm::mat4 projection = + glm::perspective(glm::radians(camera.Zoom), + (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); + // 绘制三角形 shader.use(); glBindVertexArray(VAO); + shader.setMat4("view", view); + shader.setMat4("projection", projection); + glm::mat4 trans(1.0f); - trans = glm::rotate(trans, float(-sin((float)glfwGetTime())), glm::vec3(0.0, 1.0, 0.0)); - trans = glm::translate(trans,glm::vec3(-0.2,0.0,0.0)); - shader.setMat4("trans",trans); + trans = glm::rotate(trans, float(-sin((float)glfwGetTime())), + glm::vec3(0.0, 1.0, 0.0)); + trans = glm::translate(trans, glm::vec3(-0.2, 0.0, 0.0)); + shader.setMat4("trans", trans); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); trans = glm::mat4(1.0f); - trans = glm::rotate(trans, float(-sin((float)glfwGetTime())), glm::vec3(0.0, 1.0, 0.0)); - trans = glm::translate(trans,glm::vec3(0.2,0.0,0.0)); - trans = glm::rotate(trans,glm::radians(180.0f), glm::vec3(0.0, 1.0, 0.0)); - // trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0, 0.5, 0.5)); - // trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5)); - shader.setMat4("trans",trans); + trans = glm::rotate(trans, float(sin((float)glfwGetTime())), + glm::vec3(0.0, 1.0, 0.0)); + trans = glm::translate(trans, glm::vec3(0.2, 0.0, 0.0)); + trans = glm::rotate(trans, glm::radians(180.0f), glm::vec3(0.0, 1.0, 0.0)); + // trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0, 0.5, + // 0.5)); trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5)); + shader.setMat4("trans", trans); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 检查并调用事件,交换缓冲 @@ -171,9 +199,30 @@ int main() { void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + camera.ProcessKeyboard(FORWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + camera.ProcessKeyboard(BACKWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + camera.ProcessKeyboard(LEFT, deltaTime); + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + camera.ProcessKeyboard(RIGHT, deltaTime); + if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) + camera.ProcessKeyboard(UP, deltaTime); + if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) + camera.ProcessKeyboard(DOWN, deltaTime); } + // 窗口大小改变时回调该函数 void framebuffer_size_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height); +} + +void mouse_callback(GLFWwindow *window, double xpos, double ypos) { + camera.ProcessMouseMovement(xpos, ypos); +} + +void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) { + camera.ProcessMouseScroll(yoffset); } \ No newline at end of file diff --git a/OpenGL/lab2/src/tex.vs b/OpenGL/lab2/src/tex.vs index 9d1251e..d2437c7 100644 --- a/OpenGL/lab2/src/tex.vs +++ b/OpenGL/lab2/src/tex.vs @@ -7,10 +7,13 @@ out vec3 ourColor; out vec2 TexCoord; uniform mat4 trans; +uniform mat4 view; +uniform mat4 projection; void main() { - gl_Position = trans * vec4(aPos, 1.0); + gl_Position = projection * view * trans * vec4(aPos, 1.0); + // gl_Position = trans * vec4(aPos, 1.0); ourColor = aColor; TexCoord = aTexCoord; }