OpenGL实例化绘制异常:气泡球体显示怪异形状求助
OpenGL实例化绘制气泡显示异常问题
我用OpenGL开发简单游戏,场景里包含玩家球体和多个气泡球体,但气泡的实例化功能未按预期工作,显示效果怪异。作为OpenGL实例化新手,无法定位问题根源。
预期效果:两个气泡与正常显示的玩家球体外观完全一致;当前显示效果:气泡出现扭曲、形态异常的怪异画面。
相关代码
玩家类绘制方法
void Player::draw(glm::mat4 ViewMat, GLfloat aspect, glm::vec3 light, GLfloat zoom) { bindProgram(); bindBuffers(); glm::mat4 Projection = glm::perspective(zoom, aspect, 0.1f, 100.0f); glm::mat4 Model = glm::mat4(1.0f); glm::mat4 MVP = Projection * ViewMat * Model; glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "MVP"), 1, GL_FALSE, &MVP[0][0]); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "M"), 1, GL_FALSE, &Model[0][0]); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "V"), 1, GL_FALSE, &ViewMat[0][0]); glUniform3f(glGetUniformLocation(shaderProgram, "origin"), origin.x, origin.y, origin.z); glUniform3f(glGetUniformLocation(shaderProgram, "lightPosWorld"), light.x, light.y, light.z); glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size() / 3); }
气泡类静态绘制方法
void Bubble::drawAll(glm::mat4 ViewMat, GLfloat aspect, glm::vec3 light, GLfloat zoom, std::vector<Bubble *> allInstances) { std::vector<float> origins; uint count = 0; for (auto b : allInstances) { origins.push_back(b->origin.x); origins.push_back(b->origin.y); origins.push_back(b->origin.z); count++; } allInstances[0]->bindProgram(); allInstances[0]->bindBuffers(); glBufferData(GL_ARRAY_BUFFER, origins.size() * sizeof(origins), origins.data(), GL_STATIC_DRAW); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, originsBuffer); glVertexAttribPointer(1, // attribute. No particular reason for 0, but must match the layout in the shader. 3, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void *)0 // array buffer offset ); glm::mat4 Projection = glm::perspective(zoom, aspect, 0.1f, 100.0f); glm::mat4 Model = glm::mat4(1.0f); glm::mat4 MVP = Projection * ViewMat * Model; GLuint programID = allInstances[0]->shaderProgram; glVertexAttribDivisor(0, 0); glVertexAttribDivisor(1, 1); glUniformMatrix4fv(glGetUniformLocation(programID, "MVP"), 1, GL_FALSE, &MVP[0][0]); glUniformMatrix4fv(glGetUniformLocation(programID, "M"), 1, GL_FALSE, &Model[0][0]); glUniformMatrix4fv(glGetUniformLocation(programID, "V"), 1, GL_FALSE, &ViewMat[0][0]); glUniform3f(glGetUniformLocation(programID, "lightPosWorld"), light.x, light.y, light.z); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, allInstances[0]->vertices.size() / 3, count); }
玩家顶点着色器
#version 330 core layout(location = 0) in vec3 vertexPosition_modelspace; uniform mat4 MVP; uniform mat4 M; uniform mat4 V; uniform vec3 origin; uniform vec3 lightPosWorld; uniform vec3 cameraPos; out vec3 vertexPosWorld; out vec3 vertexNormal; out vec3 eyeDirectionCamera; out vec3 lightDirectionCamera; void main() { gl_Position = MVP * vec4(vertexPosition_modelspace + origin,1); vertexPosWorld = (M * vec4(vertexPosition_modelspace + origin,1)).xyz; vertexNormal = normalize(vertexPosWorld - origin); }
气泡顶点着色器
#version 330 core layout(location = 0) in vec3 vertexPosition_modelspace; layout(location = 1) in vec3 origin; uniform mat4 MVP; uniform mat4 M; uniform mat4 V; uniform vec3 lightPosWorld; uniform vec3 cameraPos; out vec3 vertexPosWorld; out vec3 vertexNormal; out vec3 eyeDirectionCamera; out vec3 lightDirectionCamera; void main() { gl_Position = MVP * vec4(vertexPosition_modelspace + origin,1); vertexPosWorld = (M * vec4(vertexPosition_modelspace + origin,1)).xyz; vertexNormal = normalize(vertexPosWorld - origin); }
问题定位与修复
你的气泡实例化代码存在3个关键错误:
缓冲区操作顺序与参数错误
- 你先调用
glBufferData但未绑定originsBuffer,导致实例化数据被写入到模型顶点缓冲区,直接覆盖了气泡的模型顶点数据,这是显示异常的核心原因。 sizeof(origins)参数错误:origins是vector<float>对象,sizeof(origins)获取的是容器本身的大小,而非单个元素的大小,应该替换为sizeof(float)。
修复后的缓冲区操作代码:
// 先绑定实例化数据缓冲区 glBindBuffer(GL_ARRAY_BUFFER, originsBuffer); // 写入实例化数据,使用正确的元素大小 glBufferData(GL_ARRAY_BUFFER, origins.size() * sizeof(float), origins.data(), GL_STATIC_DRAW); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);- 你先调用
顶点属性除数设置时机错误
glVertexAttribDivisor应该在glVertexAttribPointer之后调用,确保属性配置完成后,再设置实例化步进规则。
冗余代码优化
count变量可以直接用allInstances.size()替代,无需循环统计。
修正后的Bubble::drawAll核心片段:
std::vector<float> origins; uint count = allInstances.size(); for (auto b : allInstances) { origins.push_back(b->origin.x); origins.push_back(b->origin.y); origins.push_back(b->origin.z); } allInstances[0]->bindProgram(); allInstances[0]->bindBuffers(); // 处理实例化数据缓冲区 glBindBuffer(GL_ARRAY_BUFFER, originsBuffer); glBufferData(GL_ARRAY_BUFFER, origins.size() * sizeof(float), origins.data(), GL_STATIC_DRAW); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); // 配置实例化步进规则 glVertexAttribDivisor(0, 0); glVertexAttribDivisor(1, 1); // 矩阵与Uniform设置 glm::mat4 Projection = glm::perspective(zoom, aspect, 0.1f, 100.0f); glm::mat4 Model = glm::mat4(1.0f); glm::mat4 MVP = Projection * ViewMat * Model; GLuint programID = allInstances[0]->shaderProgram; glUniformMatrix4fv(glGetUniformLocation(programID, "MVP"), 1, GL_FALSE, &MVP[0][0]); glUniformMatrix4fv(glGetUniformLocation(programID, "M"), 1, GL_FALSE, &Model[0][0]); glUniformMatrix4fv(glGetUniformLocation(programID, "V"), 1, GL_FALSE, &ViewMat[0][0]); glUniform3f(glGetUniformLocation(programID, "lightPosWorld"), light.x, light.y, light.z); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, allInstances[0]->vertices.size() / 3, count);
额外建议:将originsBuffer的创建(glGenBuffers)放到类的初始化方法中,避免每次绘制都重复创建缓冲区,提升性能。
内容的提问来源于stack exchange,提问作者cptkidd
相关产品推荐
相关产品推荐

