You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

渲染输出(应为黑色立方体)

渲染输出(应为黑色立方体)


问题分析与解决方案

核心错误点

  1. 顶点大小计算错误:代码中使用meshtmp.layout().getSize(1)获取顶点大小,而bgfx的VertexLayout::getSize(uint32_t _attrIdx)方法传入参数1时,是获取属性索引为1的属性字节大小,而非单个顶点的总字节大小。由于Attrib::Position的属性索引是0,这会导致vertex_size值错误,进而使顶点偏移计算混乱,缓冲区内存溢出或数据覆盖。
  2. 顶点内存预分配错误:预分配顶点缓冲区时同样使用了错误的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 04:18:10