提高网格几何序列化性能

Improve mesh geometry serialization performance

提问人:StudenteChamp 提问时间:8/27/2023 最后编辑:StudenteChamp 更新时间:9/3/2023 访问量:45

问:

我想缩短 3D 应用程序的序列化时间。 我使用以下场景进行测试: https://www.dropbox.com/scl/fi/j8ays9phm2xs45icla4bo/TestScene.zip?rlkey=qy8jpwgz3s8b95mz62l8axcug&dl=0

我用 Blender 和 3DS Max 进行了性能比较。
搅拌机:1 秒 3DS 最大:2 秒 我的应用程序:15 秒

为了序列化网格,我使用 OBJ 文件格式和 Assimp。
Assimp 序列化时间过长。 我应该编写自己的格式吗?有什么我应该知道的技巧吗?

谢谢。为了方便起见,我的序列化代码如下:

    aiScene* scene = new aiScene();

    // Allocate materials memory
    scene->mNumMaterials = 1;
    scene->mMaterials = new aiMaterial*[scene->mNumMaterials];
    
    // Allocate mesh memory
    scene->mNumMeshes = (unsigned)m_flatMeshContainer.size();
    scene->mMeshes = new aiMesh*[m_flatMeshContainer.size()];

    scene->mRootNode = new aiNode();
    scene->mRootNode->mNumMeshes = 0;

    // Create materials
    for (Uint32 i = 0u; i < scene->mNumMaterials; ++i)
    {
        scene->mMaterials[i] = new aiMaterial();
    }

    // Create meshes
    std::mutex mtx;
    tbb::parallel_for(size_t(0), m_meshGroupIdentifiers.size(), [&](size_t idx) {

        const auto& groupId = m_meshGroupIdentifiers[idx];
        const auto group = getMeshGroupPtr_FromEntity(groupId);

        // Create meshes
        const auto nbMeshes = (unsigned)group->m_meshes.size();
        aiNode* node = new aiNode();
        node->mMeshes = new unsigned int[nbMeshes];
        node->mNumMeshes = nbMeshes;

        for (Uint32 i = 0u; i < nbMeshes; ++i)
        {
            // Init mesh
            const Mesh* nativeMesh = group->m_meshes[i];
            const auto flatMeshIdx = nativeMesh->getFlatId();
            scene->mMeshes[flatMeshIdx] = new aiMesh();
            node->mMeshes[i] = flatMeshIdx;

            aiMesh* mesh = scene->mMeshes[flatMeshIdx];
            mesh->mName = group->getName();
            mesh->mMaterialIndex = 0;

            // Build vertices
            const auto& vertices = nativeMesh->getRealVertices();
            const auto nbVertex = (unsigned)vertices.size();

            mesh->mVertices = new aiVector3D[nbVertex];
            mesh->mNormals = new aiVector3D[nbVertex];
            mesh->mNumVertices = nbVertex;

            mesh->mTextureCoords[0] = new aiVector3D[nbVertex];
            mesh->mNumUVComponents[0] = nbVertex;

            for (Uint32 j = 0u; j < nbVertex; ++j)
            {
                const auto& vtx = vertices[j];

                mesh->mVertices[j] = aiVector3D(vtx.position.x, vtx.position.y, vtx.position.z);
                mesh->mNormals[j] = aiVector3D(vtx.normal.x, vtx.normal.y, vtx.normal.z);
                mesh->mTextureCoords[0][j] = aiVector3D(vtx.texCoord.x, vtx.texCoord.y, 0);
            }

            // Build faces
            const auto& indices = nativeMesh->getRealIndices();
            mesh->mNumFaces = (unsigned)indices.size() / PRIMITIVE_NB_VTX;
            mesh->mFaces = new aiFace[mesh->mNumFaces];

            for (Uint32 j = 0u; j < indices.size(); j += PRIMITIVE_NB_VTX)
            {
                aiFace &face = mesh->mFaces[j / PRIMITIVE_NB_VTX];
                face.mIndices = new unsigned int[PRIMITIVE_NB_VTX];
                face.mNumIndices = PRIMITIVE_NB_VTX;

                for (Uint32 k = 0; k < PRIMITIVE_NB_VTX; ++k)
                {
                    face.mIndices[k] = indices[k + j];
                }
            }
        }

        std::lock_guard<std::mutex> lock(mtx);
        scene->mRootNode->addChildren(1, &node);
    });


    const auto objPath = m_serializationFullPath.string();
    Assimp::Exporter exporter;
    // HERE : SLOW  --------------------------------------------------------------------------------------------
    exporter.Export(scene, "obj", objPath);
    // ---------------------------------------------------------------------------------------------------------

    delete scene;
图形 3D 网格 Assimp

评论

0赞 leandro 8/28/2023
您是否正在构建版本?根据我的经验,调试和发布之间存在巨大的性能差异。可能就是这样
1赞 StudenteChamp 8/29/2023
我正在构建发布,谢谢:)

答:

0赞 leandro 8/29/2023 #1

我会尽量避免在循环中调用任何构造函数或内存分配。这段代码如下所示

 mesh->mVertices = new aiVector3D[nbVertex]();
 mesh->mNormals = new aiVector3D[nbVertex]();
 mesh->mNumVertices = nbVertex;

 mesh->mTextureCoords[0] = new aiVector3D[nbVertex]();
 mesh->mNumUVComponents[0] = nbVertex;

 for (Uint32 j = 0u; j < nbVertex; ++j)
 {
    const auto& vtx = vertices[j];

    mesh->mVertices[j].x = vtx.position.x;
    mesh->mVertices[j].y = vtx.position.y;
    mesh->mVertices[j].z = vtx.position.z;

    mesh->mNormals[j].x = vtx.normal.x;
    mesh->mNormals[j].y = vtx.normal.y;
    mesh->mNormals[j].z = vtx.normal.z;

    mesh->mTextureCoords[0][j].x = vtx.texCoord.x;
    mesh->mTextureCoords[0][j].y = vtx.texCoord.y;
    mesh->mTextureCoords[0][j].z = vtx.texCoord.z;
 }

评论

0赞 StudenteChamp 8/30/2023
循环本身很快。慢代码是:exporter。导出(scene, “obj”, objPath);
0赞 StudenteChamp 9/3/2023 #2

我通过实现自己的二进制文件格式解决了它。
为了写入我使用的文件:

    std::ofstream fileStream(filePath, std::ios::out | std::ios::binary)

阅读:

    std::ifstream fileStream(filePath, std::ios::out | std::ios::binary);

这里有很好的例子:https://www.tutorialspoint.com/reading-and-writing-binary-file-in-c-cplusplus#:~:text=To%20write%20a%20binary%20file,the%20end%20of%20the%20file