使用Assimp、BGFX和C++时顶点与索引匹配异常问题排查
基于BGFX的通用模型类顶点索引匹配异常问题
我正在用C++编写适配任意底层数据类型的BGFX通用模型类,使用Assimp导入模型数据时,发现顶点与索引匹配异常,已定位到处理顶点和索引的函数存在问题。即便仅导入位置数据且无偏移,问题依然存在,无法确定导入过程中的错误点。目标Mesh类通过源数据的void*指针、网格缓冲区字节偏移、待复制数据字节大小完成数据复制。
存在问题的函数
void ProcessVerticesAndIndices(const aiMesh* mesh, SGModel::Mesh& meshtmp) { using namespace bgfx; using namespace SGModel; //Preallocate memory meshtmp.reserveVerticesData(mesh->mNumVertices * meshtmp.layout().getSize(1)); meshtmp.reserveIndicesData(mesh->mNumFaces * TRIANGULATED_VERTEX_COUNT * sizeof(Indice)); size_t vertex_size = meshtmp.layout().getSize(1); for (size_t i = 0; i < mesh->mNumVertices; ++i) { //Process vertices if (mesh->HasPositions()) { //Type sizes are the size of the primitive type of the attribute (e.g. sizeof(float), sizeof(int32_t) etc) uint8_t pos_type_size = GetBGFXAttributeTypeSize(GetBGFXAttributeType(Attrib::Position)); meshtmp.copyVertices(&mesh->mVertices[i].x, i * vertex_size, pos_type_size); meshtmp.copyVertices(&mesh->mVertices[i].y, i * vertex_size + pos_type_size, pos_type_size); meshtmp.copyVertices(&mesh->mVertices[i].z, i * vertex_size + 2 * pos_type_size, pos_type_size); } } size_t indices_index = 0; for(size_t i = 0; i < mesh->mNumFaces; ++i) { auto face = mesh->mFaces[i]; for (size_t j = 0; j < face.mNumIndices; ++j) { meshtmp.copyIndices(&face.mIndices[j], indices_index * sizeof(Indice), sizeof(Indice)); indices_index++; } }
控制台输出的立方体顶点与索引
VERTICES (in buffer order): Index: 0 POS: 4 4 4 Index: 1 POS: -4 4 4 Index: 2 POS: -4 -4 4 Index: 3 POS: 4 -4 4 Index: 4 POS: 4 -4 -4 Index: 5 POS: 4 -4 4 Index: 6 POS: -4 -4 4 Index: 7 POS: -4 -4 -4 Index: 8 POS: -4 -4 -4 Index: 9 POS: -4 -4 4 Index: 10 POS: -4 4 4 Index: 11 POS: -4 4 -4 Index: 12 POS: -4 4 -4 Index: 13 POS: 4 4 -4 Index: 14 POS: 4 -4 -4 Index: 15 POS: -4 -4 -4 Index: 16 POS: 4 4 -4 Index: 17 POS: 4 4 4 Index: 18 POS: 4 -4 4 Index: 19 POS: 4 -4 -4 Index: 20 POS: -4 4 -4 Index: 21 POS: -4 4 4 Index: 22 POS: 4 4 4 Index: 23 POS: 4 4 -4 INDICES (in buffer order): 0 1 2 0 2 3 4 5 6 4 6 7 8 9 10 8 10 11 12 13 14 12 14 15 16 17 18 16 18 19 20 21 22 20 22 23
渲染输出(应为黑色立方体)

问题分析与解决方案
核心错误点
- 顶点大小计算错误:代码中使用
meshtmp.layout().getSize(1)获取顶点大小,而bgfx的VertexLayout::getSize(uint32_t _attrIdx)方法传入参数1时,是获取属性索引为1的属性字节大小,而非单个顶点的总字节大小。由于Attrib::Position的属性索引是0,这会导致vertex_size值错误,进而使顶点偏移计算混乱,缓冲区内存溢出或数据覆盖。 - 顶点内存预分配错误:预分配顶点缓冲区时同样使用了错误的
getSize(1),导致缓冲区容量不足,后续写入的顶点数据会覆盖已有数据。
修复后的代码
void ProcessVerticesAndIndices(const aiMesh* mesh, SGModel::Mesh& meshtmp) { using namespace bgfx; using namespace SGModel; // 获取单个顶点的总字节大小 size_t vertex_size = meshtmp.layout().getSize(); // 预分配正确大小的顶点缓冲区 meshtmp.reserveVerticesData(mesh->mNumVertices * vertex_size); meshtmp.reserveIndicesData(mesh->mNumFaces * TRIANGULATED_VERTEX_COUNT * sizeof(Indice)); if (mesh->HasPositions()) { uint8_t pos_type_size = GetBGFXAttributeTypeSize(GetBGFXAttributeType(Attrib::Position)); // 单个Position属性的总字节数 size_t pos_total_size = 3 * pos_type_size; for (size_t i = 0; i < mesh->mNumVertices; ++i) { // 直接复制整个aiVector3D,避免分三次复制的繁琐与错误 meshtmp.copyVertices(&mesh->mVertices[i], i * vertex_size, pos_total_size); } } size_t indices_index = 0; for(size_t i = 0; i < mesh->mNumFaces; ++i) { auto face = mesh->mFaces[i]; for (size_t j = 0; j < face.mNumIndices; ++j) { meshtmp.copyIndices(&face.mIndices[j], indices_index * sizeof(Indice), sizeof(Indice)); indices_index++; } }
补充说明
- 修复后通过
meshtmp.layout().getSize()(无参数)获取单个顶点的总字节大小,确保顶点偏移计算正确。 - 直接复制整个
aiVector3D内存块,既简化代码,也避免了分分量复制可能带来的偏移计算错误。 - 若后续需要添加其他顶点属性(如法线、UV),只需按同样逻辑扩展即可,无需修改核心偏移计算逻辑。
内容的提问来源于stack exchange,提问作者will martin
相关产品推荐
相关产品推荐

