使用rapidobj加载OBJ文件到游戏中模型扭曲的问题排查
问题:使用rapidobj加载OBJ模型出现扭曲异常
我尝试用rapidobj库把OBJ文件加载到游戏里,但每次加载模型都会扭曲显示异常(见附图)。哪怕把索引循环起始值改成OBJ规定的1,还是没法正确读取模型。
加载代码
// public domain, cc by sa is bad auto objFile = rapidobj::ParseFile(location); for(unsigned int i = 0; i < objFile.attributes.positions.size(); i+=3) this->bufferVertices.push_back(glm::vec3(objFile.attributes.positions[i], objFile.attributes.positions[i + 1], objFile.attributes.positions[i + 2])); for(unsigned int i = 0; i < objFile.shapes.size(); i++) { for(unsigned e = 0; e < objFile.shapes[i].mesh.indices.size(); e++) this->indices.push_back(objFile.shapes[i].mesh.indices[e].position_index); } for(unsigned i = 0; i < indices.size(); i++) this->vertices.push_back(this->bufferVertices[this -> indices [i]]);
我的思路是先把顶点加载到数组,再通过索引把正确顶点复制到主顶点数组,之前这个逻辑是能用的,但第一次用rapidobj就不行。用RenderDoc查看发现模型部分加载正确,但有无效重复值导致模型损坏。
缓冲区代码
// public domain cc by sa is awful glGenVertexArrays(1, &(this->vao)); glBindVertexArray(this->vao); glEnableVertexAttribArray(0); glGenBuffers(1, &(this->vbo[0])); glBindBuffer(GL_ARRAY_BUFFER, this->vbo[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(this->vertices.data())*sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); glEnableVertexAttribArray(1); glGenBuffers(1, &(this->vbo[1])); glBindBuffer(GL_ARRAY_BUFFER, this->vbo[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(this->position.data()) * sizeof(glm::vec3), position.data(), GL_DYNAMIC_DRAW); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); glVertexAttribDivisor(1, 1);
请问我哪里出错了?
错误分析与修复方案
1. 索引与顶点数组的映射完全错误
rapidobj返回的position_index是指向原始positions数组的单float元素索引(0基),但你把positions每3个元素打包成glm::vec3存入bufferVertices后,直接用position_index作为bufferVertices的索引取值,这会导致顶点完全对应错误。
比如position_index=1属于第一个顶点(对应bufferVertices[0]),但你会取bufferVertices[1],直接导致顶点错乱,这是模型扭曲的核心原因。
修复代码:
把索引处理逻辑改成:
for(unsigned int i = 0; i < objFile.shapes.size(); i++) { for(unsigned e = 0; e < objFile.shapes[i].mesh.indices.size(); e++) { // 将单float索引转换为vec3顶点数组的索引 unsigned int vertex_idx = objFile.shapes[i].mesh.indices[e].position_index / 3; this->indices.push_back(vertex_idx); } }
2. 缓冲区数据大小计算错误
你用sizeof(this->vertices.data())计算缓冲区大小,而data()返回的是指针,64位系统下指针大小固定为8字节,这会导致实际写入GPU的数据量远小于需求,剩下的内存都是垃圾值,进一步加剧模型显示异常。
修复代码:
将glBufferData的大小参数改为元素个数乘以单个元素大小:
// 修复顶点缓冲区大小 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW); // 修复position缓冲区大小 glBufferData(GL_ARRAY_BUFFER, position.size() * sizeof(glm::vec3), position.data(), GL_DYNAMIC_DRAW);
3. 冗余的顶点复制逻辑(可选优化)
你当前把索引展开为顶点的逻辑完全没必要,直接使用索引绘制(EBO)更高效且不易出错:
// 生成并绑定EBO unsigned int ebo; glGenBuffers(1, &ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW); // 绘制时使用glDrawElements替代glDrawArrays glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
内容的提问来源于stack exchange,提问作者drk1
相关产品推荐
相关产品推荐

