OpenGL 4. 变换
/** 优化说明:* 1. 增加了详细的注释说明每个步骤* 2. 将纹理加载封装为函数* 3. 优化了矩阵变换逻辑* 4. 分离了渲染逻辑* 5. 添加了错误检查*/#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <tool/shader.h>#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>#include <iostream>#define STB_IMAGE_IMPLEMENTATION
#include <tool/stb_image.h>// 函数声明
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void processInput(GLFWwindow *window);
unsigned int loadTexture(const char *path, bool flipY = true, bool alpha = false);
void renderScene(Shader &shader, unsigned int VAO, unsigned int texture1, unsigned int texture2);std::string Shader::dirName;int main(int argc, char *argv[])
{// 1. 初始化GLFW和创建窗口// =============================================Shader::dirName = argv[1];glfwInit();// 设置OpenGL版本和模式glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建窗口GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cerr << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);// 2. 初始化GLAD// =============================================if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cerr << "Failed to initialize GLAD" << std::endl;return -1;}// 3. 基本配置// =============================================glViewport(0, 0, 800, 600);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 启用点大小控制和混合glEnable(GL_PROGRAM_POINT_SIZE);glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);// 4. 创建和编译着色器// =============================================Shader ourShader("./shader/vertex.glsl", "./shader/fragment.glsl");// 5. 设置顶点数据和缓冲区// =============================================// 顶点数据:位置(3) + 颜色(3) + 纹理坐标(2)float vertices[] = {// 位置 // 颜色 // 纹理坐标0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上};// 索引数据unsigned int indices[] = {0, 1, 3, // 第一个三角形1, 2, 3 // 第二个三角形};// 创建VAO、VBO和EBOunsigned int VAO, VBO, EBO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);// 绑定VAO(之后的所有顶点属性设置都会存储在这个VAO中)glBindVertexArray(VAO);// 绑定并填充VBOglBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 绑定并填充EBOglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);// 设置顶点属性指针// 位置属性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);glEnableVertexAttribArray(0);// 颜色属性glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));glEnableVertexAttribArray(1);// 纹理坐标属性glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));glEnableVertexAttribArray(2);// 解绑VAO(不是必须的,但可以防止意外修改)glBindVertexArray(0);// 6. 加载纹理// =============================================unsigned int texture1 = loadTexture("./static/texture/container.jpg");unsigned int texture2 = loadTexture("./static/texture/awesomeface.png", true, true);// 告诉着色器采样器对应的纹理单元ourShader.use();ourShader.setInt("texture1", 0);ourShader.setInt("texture2", 1);// 7. 主渲染循环// =============================================while (!glfwWindowShouldClose(window)){// 处理输入processInput(window);// 清空屏幕glClearColor(0.1f, 0.1f, 0.1f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 渲染场景renderScene(ourShader, VAO, texture1, texture2);// 交换缓冲区和轮询IO事件glfwSwapBuffers(window);glfwPollEvents();}// 8. 清理资源// =============================================glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glDeleteTextures(1, &texture1);glDeleteTextures(1, &texture2);glfwTerminate();return 0;
}// 加载纹理函数
unsigned int loadTexture(const char *path, bool flipY, bool alpha)
{unsigned int textureID;glGenTextures(1, &textureID);glBindTexture(GL_TEXTURE_2D, textureID);// 设置纹理参数glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);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(flipY);// 加载图像int width, height, nrChannels;unsigned char *data = stbi_load(path, &width, &height, &nrChannels, 0);if (data){GLenum format = alpha ? GL_RGBA : GL_RGB;glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cerr << "Failed to load texture: " << path << std::endl;}stbi_image_free(data);return textureID;
}// 渲染场景函数
void renderScene(Shader &shader, unsigned int VAO, unsigned int texture1, unsigned int texture2)
{shader.use();// 绑定纹理glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, texture1);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texture2);// 获取当前时间用于动画float time = glfwGetTime();shader.setFloat("factor", -time);// 绑定VAOglBindVertexArray(VAO);// 第一个物体:旋转+缩放glm::mat4 trans = glm::mat4(1.0f);trans = glm::translate(trans, glm::vec3(-0.5f, 0.0f, 0.0f));trans = glm::rotate(trans, time, glm::vec3(0.0f, 0.0f, 1.0f));trans = glm::scale(trans, glm::vec3(0.5f));shader.setMat4("transform", trans);// 绘制第一个物体glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glDrawElements(GL_POINTS, 6, GL_UNSIGNED_INT, 0);// 第二个物体:脉动效果trans = glm::mat4(1.0f);trans = glm::translate(trans, glm::vec3(0.5f, 0.0f, 0.0f));float scale = sin(time) * 0.5f + 0.5f; // 在0.0-1.0之间变化trans = glm::scale(trans, glm::vec3(scale));shader.setMat4("transform", trans);// 绘制第二个物体glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glDrawElements(GL_POINTS, 6, GL_UNSIGNED_INT, 0);
}// 窗口大小改变回调函数
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{glViewport(0, 0, width, height);
}// 输入处理函数
void processInput(GLFWwindow *window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){glfwSetWindowShouldClose(window, true);}
}
变换 - LearnOpenGL CN