OpenGL更新模型Uniform为相同值时出现闪烁问题
OpenGL静态模型Uniform导致画面闪烁问题
我查遍了几乎所有OpenGL闪烁相关的问题,大多都和Z缓冲或透视投影有关,但我现在的情况不一样:我只渲染一个四边形,而且没开深度测试。每帧把模型Uniform设为同一个值时画面会闪烁,但如果让模型随Uniform更新在屏幕上移动,一切就正常了。
主渲染代码
mat4 model = mat4_identity(); model = mat4_translatev(make_vec3(100.0f, 200.0f, 0.0f)); vec4 color = make_vec4(1.0f, 0.8f, 0.7f, 1.0f); mat4 projection = mat4_ortho(0.0f, 800.0f, 600.0f, 0.0f, -1.0f, 1.0f); Shader shader("generic_shader.vs", "generic_shader.fs"); shader.use(); //shader.set_vec4("color", &color); shader.set_mat4("model", &model); shader.set_mat4("projection", &projection); float vertices[] = { 0.0f, 0.0f, 0.0f, 200.0f, 200.0f, 0.0f, 200.0f, 200.0f, }; unsigned int indices[] = { 0, 1, 2, 2, 1, 3, }; unsigned int vao, vbo, ebo; glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glGenBuffers(1, &ebo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glBindVertexArray(0); while (!glfwWindowShouldClose(window)) { float currentFrame = static_cast<f32>(glfwGetTime()); deltaTime = currentFrame - lastFrame; while(deltaTime < REQUIRED_FRAME_TIME) { currentFrame = static_cast<f32>(glfwGetTime()); deltaTime = currentFrame - lastFrame; } deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; processInput(window); glDisable(GL_DEPTH_TEST); glClearColor(1.0f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); shader.use(); //model = mat4_translatev(make_vec3(16.0f * currentFrame, 12.0f * currentFrame, 0.0f)); // <- 取消注释后就不会闪烁 shader.set_mat4("model", &model); glBindVertexArray(vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); glfwPollEvents(); glfwSwapBuffers(window); }
Shader::use() 实现
void Shader::use() { glUseProgram(this->program_id); }
矩阵Uniform设置函数实现
void Shader::set_mat4(const char* uniform_name, mat4* value) { *value = mat4_transpose(*value); glUniformMatrix4fv(glGetUniformLocation(this->program_id, uniform_name), 1, GL_TRUE, &value->E[0][0]); }
processInput()为空函数,使用自定义数学库处理向量和矩阵运算。
问题根源
问题出在set_mat4函数里的矩阵转置操作:每次调用都会直接修改传入的model矩阵本身。第一帧调用时矩阵被转置,第二帧调用时又把已经转置过的矩阵再转置一次(相当于还原成原矩阵),如此反复交替,导致模型矩阵每帧在正确和错误状态之间切换,最终表现为画面闪烁。
而当让模型随时间移动时,每帧都会重新生成新的model矩阵,转置操作只会作用于当前新矩阵,不会有前一帧的残留影响,因此不会闪烁。
修复方案
方案1:使用临时变量存储转置结果,不修改原矩阵
void Shader::set_mat4(const char* uniform_name, mat4* value) { mat4 transposed = mat4_transpose(*value); // 用临时变量保存转置后的矩阵 glUniformMatrix4fv(glGetUniformLocation(this->program_id, uniform_name), 1, GL_TRUE, &transposed.E[0][0]); }
方案2:利用OpenGL的矩阵存储参数避免手动转置
由于你的矩阵是列主序,可以将glUniformMatrix4fv的第三个参数改为GL_FALSE(OpenGL默认按列主序读取矩阵),这样无需手动转置:
void Shader::set_mat4(const char* uniform_name, mat4* value) { glUniformMatrix4fv(glGetUniformLocation(this->program_id, uniform_name), 1, GL_FALSE, &value->E[0][0]); }
内容的提问来源于stack exchange,提问作者Monu Yadav
相关产品推荐
相关产品推荐

