OpenGL使用相同MVP矩阵绘制两个立方体出现拉伸变形问题
问题描述
基于OpenGL开发简易3D空间场景,计划绘制橙色、绿色两个立方体,为两个立方体传入完全相同的model、view、projection矩阵,预期两立方体处于同一位置、显示效果完全一致,但实际渲染出现拉伸变形异常,线框模式下效果如下:
最初怀疑异常由两个立方体使用相同model矩阵导致,附项目相关代码如下。
问题原因
变形和共用model矩阵没有任何关系,是代码中三个基础错误导致:
view矩阵未初始化:glm::mat4 view;声明的是栈上局部变量,GLM不会默认将其初始化为单位矩阵,内存中存储的是随机垃圾值,基于这个未初始化矩阵做平移变换,结果完全不可控。- 投影矩阵宽高比计算错误:
float(window_width / window_height)的写法是先对两个int类型值做整数除法,800/600的整数运算结果为1,转为float后仍然是1.0f,不是正确的4:3宽高比,直接导致透视投影结果拉伸。 - 未开启深度测试、未清除深度缓冲:代码仅调用
glClear(GL_COLOR_BUFFER_BIT)清除颜色缓冲,没有清除深度缓冲,也没有启用GL_DEPTH_TEST,就算矩阵修正后也会出现面绘制顺序错乱的问题。
修正方法
- 初始化view矩阵为单位矩阵,修改对应代码为:
glm::mat4 view(1.0f); view = glm::translate(view, glm::vec3(0.f, 0.f, -5.f));
- 修正宽高比计算逻辑,先将宽高转为浮点数再做除法:
projection = glm::perspective(glm::radians(45.f), (float)window_width / (float)window_height, 0.1f, 100.f);
- 在GLAD加载完成后添加代码开启深度测试:
glEnable(GL_DEPTH_TEST);
- 修改渲染循环中的清屏逻辑,同时清除颜色缓冲和深度缓冲:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
原项目代码
main.cpp
#include "src/Program.hpp" #include <GLFW/glfw3.h> // functions void framebufferResizeCallback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } void errorCallback(int error, const char* description) { std::cout << "error :" << description << std::endl; } //variables int window_width = 800; int window_height = 600; int main() { glfwInit(); glfwWindowHint(GLFW_VERSION_MAJOR, 3); glfwWindowHint(GLFW_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwSetErrorCallback(errorCallback); GLFWwindow* window = glfwCreateWindow(window_width, window_height, "Opengl_triangle", NULL, NULL); glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebufferResizeCallback); gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); Program light("src/vertex.glsl", "src/fragment.glsl"); Program object("src/vertex.glsl", "src/fragment_green.glsl"); /// going 3D // calculations glm::mat4 model(1.f); model = glm::rotate(model,glm::radians(20.f), glm::vec3(1.f, 0.f, 0.6f)); glm::mat4 view; view = glm::translate(view, glm::vec3(0.f, 0.f, -5.f)); glm::mat4 projection; projection = glm::perspective(glm::radians(45.f), float(window_width / window_height), 0.1f, 100.f); // sending it to the shaders LIGHT light.use(); light.uniformMatrix4(model, "model"); light.uniformMatrix4(view, "view"); light.uniformMatrix4(projection, "projection"); // sending it to the shaders OBJECT object.use(); object.uniformMatrix4(model, "model"); object.uniformMatrix4(view, "view"); object.uniformMatrix4(projection, "projection"); //fun stuff float vertices[] = { -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, }; unsigned int VBO, VAO_light, VAO_object ; glGenVertexArrays(1, &VAO_light); glGenVertexArrays(1, &VAO_object); glGenBuffers(1, &VBO); glBindVertexArray(VAO_light); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); glEnableVertexAttribArray(0); glBindVertexArray(VAO_object); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); glEnableVertexAttribArray(0); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); while (!glfwWindowShouldClose(window)) { glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); light.use(); glBindVertexArray(VAO_light); glDrawArrays(GL_TRIANGLES, 0, 36); object.use(); glBindVertexArray(VAO_object); glDrawArrays(GL_TRIANGLES, 0, 36); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; }
片段着色器
#version 330 core out vec4 fragColor; void main() { fragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); }
顶点着色器
#version 330 core layout (location = 0) in vec3 aPos; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(aPos , 1.0f); }
Shader与Program封装类
class Program { Shader vertex; Shader fragment; GLuint ID; public: // essential methods Program() : ID(0) { std::cout << "program default constructor" << std::endl; } Program(const char* vertexShader_path, const char * fragmentShader_path) { // recreate shaders vertex = Shader(vertexShader_path, GL_VERTEX_SHADER); fragment = Shader(fragmentShader_path, GL_FRAGMENT_SHADER); // create shader program ID = glCreateProgram(); glAttachShader(ID, vertex.getID()); glAttachShader(ID, fragment.getID()); glLinkProgram(ID); checkProgramLinking(ID); } /// usage methods void use() { glUseProgram(ID); } GLuint getID() { return ID; } // accesing uniforms methods void uniformMatrix4(glm::mat4 matrix, const char* matrixName) { GLuint uniformLocation = glGetUniformLocation(ID, matrixName); glUniformMatrix4fv(uniformLocation, 1, GL_FALSE, glm::value_ptr(matrix)); } private: void checkProgramLinking(unsigned int& program) { int success; char log[512]; glGetProgramiv(program, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(program, 512, NULL, log); std::cout << "error linking program : " << log << std::endl; } } } class Shader { GLuint ID; public: // essential methods Shader() : ID(0) { std::cout << "default shader constructor" << std::endl; } Shader(const char* path, GLenum type) { // converting shader code from file std::string shaderCodeS; std::ifstream shaderFile; shaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { shaderFile.open(path); std::stringstream shaderStream; shaderStream << shaderFile.rdbuf(); shaderFile.close(); shaderCodeS = shaderStream.str(); } catch (std::ifstream::failure& e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ: " << e.what() << std::endl; } const char* shaderCode = shaderCodeS.c_str(); // shader creation ID = glCreateShader(type); glShaderSource(ID, 1, &shaderCode, NULL); glCompileShader(ID); checkShaderCompilation(ID); std::cout << "shader argumented constructor" << std::endl; } // methods for usage GLuint getID() { return ID; } private: void checkShaderCompilation(unsigned int& shader) { int success; char log[512]; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 512, NULL, log); std::cout << "error compiling shader:" << log << std::endl; } } };
内容的提问来源于stack exchange,提问作者Jakkkub
相关产品推荐
相关产品推荐

