OpenGL绘制旋转立方体
概要
主要介绍使用OpenGL绘制一个立方体,并给立方体的六个面赋予不同的颜色,并使立方体可以自动旋转,也可以通过键盘按键A、D、W、S进行左、右、上、下移动。
1.使用GLM函数库(OpenGL Mathematics)进行立方体举矩阵的变换运算;
2.使用PVM矩阵进行坐标系变换。PVM矩阵即 P:projection;V:view;M:model。model矩阵对应从局部坐标系到世界坐标系的变换;view矩阵对应从世界坐标系到观察坐标系的变换;projection 矩阵对应从观察坐标系到剪裁空间的变换。
3.通过注册鼠标和键盘控制函数,使立方体可以通过设备控制。
效果
主要实现代码
main.cpp
#include "glad.c" #include <glad/glad.h> #include <GLFW/glfw3.h> #include <stb_image.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <learnopengl/shader_m.h> #include <learnopengl/camera.h> #include <learnopengl/model.h> #include <iostream> #include <GL/gl.h> #include <GL/glu.h> //鼠标键盘响应函数 void framebuffer_size_callback(GLFWwindow* window, int width, int height); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void processInput(GLFWwindow *window); const char *vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "layout (location = 1) in vec3 PosColor;\n" "out vec3 positionColor;\n" "uniform mat4 model;\n" "uniform mat4 view;\n" "uniform mat4 projection;\n" "void main()\n" "{\n" " gl_Position = projection * view * model * vec4(aPos, 1.0);\n" " positionColor=PosColor;\n" "}\0"; const char *fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "in vec3 positionColor;\n" "void main()\n" "{\n" " FragColor = vec4(positionColor,1.0);\n" "}\n\0"; const float vertices[] = { //立方体数组 -0.5f, -0.5f, -0.5f, 1.0f,0.0f,0.0f, 0.5f, -0.5f, -0.5f, 1.0f,0.0f,0.0f, 0.5f, 0.5f, -0.5f, 1.0f,0.0f,0.0f, 0.5f, 0.5f, -0.5f, 1.0f,0.0f,0.0f, -0.5f, 0.5f, -0.5f, 1.0f,0.0f,0.0f, -0.5f, -0.5f, -0.5f, 1.0f,0.0f,0.0f, -0.5f, -0.5f, 0.5f, 0.0f,1.0f,0.0f, 0.5f, -0.5f, 0.5f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, 0.5f, 0.0f,1.0f,0.0f, 0.5f, 0.5f, 0.5f, 0.0f,1.0f,0.0f, -0.5f, 0.5f, 0.5f, 0.0f,1.0f,0.0f, -0.5f, -0.5f, 0.5f, 0.0f,1.0f,0.0f, -0.5f, 0.5f, 0.5f, 0.0f,0.0f,1.0f, -0.5f, 0.5f, -0.5f, 0.0f,0.0f,1.0f, -0.5f, -0.5f, -0.5f, 0.0f,0.0f,1.0f, -0.5f, -0.5f, -0.5f, 0.0f,0.0f,1.0f, -0.5f, -0.5f, 0.5f, 0.0f,0.0f,1.0f, -0.5f, 0.5f, 0.5f, 0.0f,0.0f,1.0f, 0.5f, 0.5f, 0.5f, 0.5f,0.0f,0.0f, 0.5f, 0.5f, -0.5f, 0.5f,0.0f,0.0f, 0.5f, -0.5f, -0.5f, 0.5f,0.0f,0.0f, 0.5f, -0.5f, -0.5f, 0.5f,0.0f,0.0f, 0.5f, -0.5f, 0.5f, 0.5f,0.0f,0.0f, 0.5f, 0.5f, 0.5f, 0.5f,0.0f,0.0f, -0.5f, -0.5f, -0.5f, 0.0f,0.5f,0.0f, 0.5f, -0.5f, -0.5f, 0.0f,0.5f,0.0f, 0.5f, -0.5f, 0.5f, 0.0f,0.5f,0.0f, 0.5f, -0.5f, 0.5f, 0.0f,0.5f,0.0f, -0.5f, -0.5f, 0.5f, 0.0f,0.5f,0.0f, -0.5f, -0.5f, -0.5f, 0.0f,0.5f,0.0f, -0.5f, 0.5f, -0.5f, 0.0f,0.0f,0.5f, 0.5f, 0.5f, -0.5f, 0.0f,0.0f,0.5f, 0.5f, 0.5f, 0.5f, 0.0f,0.0f,0.5f, 0.5f, 0.5f, 0.5f, 0.0f,0.0f,0.5f, -0.5f, 0.5f, 0.5f, 0.0f,0.0f,0.5f, -0.5f, 0.5f, -0.5f, 0.0f,0.0f,0.5f }; float screen_width = 1920.0f; //窗口宽度 float screen_height = 1080.0f; //窗口高度 //相机参数 glm::vec3 camera_position = glm::vec3(0.0f, 0.0f, 3.0f); //摄像机位置 glm::vec3 camera_front = glm::vec3(0.0f, 0.0f, -1.0f); //摄像机方向 glm::vec3 camera_up = glm::vec3(0.0f, 1.0f, 0.0f); //摄像机上向量 //视野 float fov = 45.0f; Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); float lastX = screen_width / 2.0f; float lastY = screen_height / 2.0f; bool firstMouse = true; float deltaTime = 0.0f; float lastFrame = 0.0f; int main() { // 初始化GLFW glfwInit(); // 初始化GLFW glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // OpenGL版本为3.3,主次版本号均设为3 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用核心模式(无需向后兼容性) glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 如果使用的是Mac OS X系统,需加上这行 glfwWindowHint(GLFW_RESIZABLE, FALSE); // 不可改变窗口大小 // 创建窗口(宽、高、窗口名称) auto window = glfwCreateWindow(screen_width, screen_height, "Cube", nullptr, nullptr); if (window == nullptr) { // 如果窗口创建失败,输出Failed to Create OpenGL Context std::cout << "Failed to Create OpenGL Context" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); // 将窗口的上下文设置为当前线程的主上下文 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // 初始化GLAD,加载OpenGL函数指针地址的函数 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // 指定当前视口尺寸(前两个参数为左下角位置,后两个参数是渲染窗口宽、高) glViewport(0, 0, screen_width, screen_height); ////////////////////////////////////////////////////////////////////////// // build and compile our shader program // ------------------------------------ // vertex shader unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); // check for shader compile errors int success; char infoLog[512]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; } // fragment shader unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader); // check for shader compile errors glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; } // link shaders unsigned int shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); // check for linking errors glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); ////////////////////////////////////////////////////////////////////////// //Shader shader("../debug/shader/task-cube.vs", "../debug/shader/task-cube.fs");//加载着色器 // 生成并绑定VAO和VBO GLuint vertex_array_object; // == VAO glGenVertexArrays(1, &vertex_array_object); glBindVertexArray(vertex_array_object); GLuint vertex_buffer_object; // == VBO glGenBuffers(1, &vertex_buffer_object); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object); // 将顶点数据绑定至当前默认的缓冲中 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 设置顶点属性指针 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); glEnable(GL_DEPTH_TEST); // Render loop主循环 while (!glfwWindowShouldClose(window)) { //计算每帧的时间差 float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; processInput(window); //进入主循环,清理颜色缓冲深度缓冲 glClearColor(0.0f, 0.34f, 0.57f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清理颜色缓冲和深度缓冲 //shader.use(); glUseProgram(shaderProgram); // Transform坐标变换矩阵 glm::mat4 model(1);//model矩阵,局部坐标变换至世界坐标 model = glm::translate(model, glm::vec3(0.0,0.0,0.0)); model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.5f, 1.0f, 0.0f)); model = glm::scale(model, glm::vec3(1.0f,1.0f,1.0f)); glm::mat4 view(1);//view矩阵,世界坐标变换至观察坐标系 view = camera.GetViewMatrix(); glm::mat4 projection(1);//projection矩阵,投影矩阵 projection = glm::perspective(glm::radians(camera.Zoom), screen_width / screen_height, 0.1f, 100.0f); // 向着色器中传入参数 std::string strModel = "model"; std::string strView = "view"; std::string strProjection = "projection"; glUniformMatrix4fv(glGetUniformLocation(shaderProgram, strModel.c_str()), 1, GL_FALSE, &model[0][0]); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, strView.c_str()), 1, GL_FALSE, &view[0][0]); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, strProjection.c_str()), 1, GL_FALSE, &projection[0][0]); //绘制 glBindVertexArray(vertex_array_object); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); glfwSwapBuffers(window); glfwPollEvents(); } //释放VAOVBO glDeleteVertexArrays(1, &vertex_array_object); glDeleteBuffers(1, &vertex_buffer_object); // 清理所有的资源并正确退出程序 glfwTerminate(); return 0; } 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); } } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } void mouse_callback(GLFWwindow* window, double xpos, double ypos) { if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; lastX = xpos; lastY = ypos; camera.ProcessMouseMovement(xoffset, yoffset); } void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { camera.ProcessMouseScroll(yoffset); }
完整的项目代码
链接:https://pan.baidu.com/s/1GH_3Yqe4FJt6ivZ1DZkhSA
提取码:u8gs
参考资料
One thought on “OpenGL绘制旋转立方体”
赞