【问题标题】:Mesh Simplification with Assimp and OpenMesh使用 Assimp 和 OpenMesh 简化网格
【发布时间】:2017-04-19 02:09:17
【问题描述】:

几天前,我问了一个关于如何使用edge collapse with Assimp 的问题。平滑 obj 并删除软件中的重复顶点解决了可能使边缘塌陷工作的基本问题,我的意思是它可以工作,因为它可以通过 MeshLab 进行简化,如下所示:

它在 MeshLab 中看起来不错,但我随后在使用 Assimp 和 OpenMesh 的引擎中执行此操作。问题是Assimp 导入了指定的顶点和索引,这可能会让半边错过对面的对(这叫非流形吗?)。 结果快照使用 OpenMesh 的 Quadric Decimation:

为了明确找到问题,我没有抽取并直接解析 OpenMesh 数据结构。一切都按预期工作正常(我的意思是没有抽取的结果)。

我用来抽取网格的代码:

Loader::BasicData Loader::TestEdgeCollapse(float vertices[], int vertexLength, int indices[], int indexLength, float texCoords[], int texCoordLength, float normals[], int normalLength)
{
    // Mesh type
    typedef OpenMesh::TriMesh_ArrayKernelT<>   OPMesh;
    // Decimater type
    typedef OpenMesh::Decimater::DecimaterT< OPMesh > OPDecimater;
    // Decimation Module Handle type
    typedef OpenMesh::Decimater::ModQuadricT< OPMesh >::Handle HModQuadric;

    OPMesh mesh;
    std::vector<OPMesh::VertexHandle> vhandles;
    int iteration = 0;
    for (int i = 0; i < vertexLength; i += 3)
    {
        vhandles.push_back(mesh.add_vertex(OpenMesh::Vec3f(vertices[i], vertices[i + 1], vertices[i + 2])));
        if (texCoords != nullptr)
            mesh.set_texcoord2D(vhandles.back(),OpenMesh::Vec2f(texCoords[iteration * 2], texCoords[iteration * 2 + 1]));
        if (normals != nullptr)
            mesh.set_normal(vhandles.back(), OpenMesh::Vec3f(normals[i], normals[i + 1], normals[i + 2]));
        iteration++;
    }

    for (int i = 0; i < indexLength; i += 3)
        mesh.add_face(vhandles[indices[i]], vhandles[indices[i + 1]], vhandles[indices[i + 2]]);

    OPDecimater decimater(mesh);
    HModQuadric hModQuadric;
    decimater.add(hModQuadric);
    decimater.module(hModQuadric).unset_max_err();
    decimater.initialize();
    //decimater.decimate(); // without this, everything is fine as expect.
    mesh.garbage_collection();

    int verticesSize = mesh.n_vertices() * 3;
    float* newVertices = new float[verticesSize];
    int indicesSize = mesh.n_faces() * 3;
    int* newIndices = new int[indicesSize];
    float* newTexCoords = nullptr;
    int texCoordSize = mesh.n_vertices() * 2;
    if(mesh.has_vertex_texcoords2D())
        newTexCoords = new float[texCoordSize];
    float* newNormals = nullptr;
    int normalSize = mesh.n_vertices() * 3;
    if(mesh.has_vertex_normals())
        newNormals = new float[normalSize];

    Loader::BasicData data;

    int index = 0;
    for (v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it)
    {
        OpenMesh::Vec3f &point = mesh.point(*v_it);
        newVertices[index * 3] = point[0];
        newVertices[index * 3 + 1] = point[1];
        newVertices[index * 3 + 2] = point[2];
        if (mesh.has_vertex_texcoords2D())
        {
            auto &tex = mesh.texcoord2D(*v_it);
            newTexCoords[index * 2] = tex[0];
            newTexCoords[index * 2 + 1] = tex[1];
        }
        if (mesh.has_vertex_normals())
        {
            auto &normal = mesh.normal(*v_it);
            newNormals[index * 3] = normal[0];
            newNormals[index * 3 + 1] = normal[1];
            newNormals[index * 3 + 2] = normal[2];
        }
        index++;
    }
    index = 0;

    for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it)
        for (fv_it = mesh.fv_ccwiter(*f_it); fv_it.is_valid(); ++fv_it)
        {
            int id = fv_it->idx();
            newIndices[index] = id;
            index++;
        }

    data.Indices = newIndices;
    data.IndicesLength = indicesSize;
    data.Vertices = newVertices;
    data.VerticesLength = verticesSize;
    data.TexCoords = nullptr;
    data.TexCoordLength = -1;
    data.Normals = nullptr;
    data.NormalLength = -1;
    if (mesh.has_vertex_texcoords2D())
    {
        data.TexCoords = newTexCoords;
        data.TexCoordLength = texCoordSize;
    }
    if (mesh.has_vertex_normals())
    {
        data.Normals = newNormals;
        data.NormalLength = normalSize;
    }
    return data;
}

还提供我测试过的the tree obj,和Assimp生成的the face data,我从visual studio调试器中取出,显示部分索引找不到索引对的问题。

【问题讨论】:

  • 你确认不是因为你没有画出人脸的“背面”吗? IE。缺失面的法线指向树的内部。

标签: algorithm computational-geometry mesh assimp openmesh


【解决方案1】:

考虑了几周但失败了,我想我想要一些学术/数学解决方案来自动生成这些抽取的网格,但现在我试图找到简单的方法 为了实现这一点,我能够做的就是改变在单个自定义对象(类 obj)中加载 多对象(file.obj)的结构,并在需要时切换对象.这样做的好处是我可以管理应该呈现的内容并忽略任何算法问题。

顺便说一下,我列出了一些让我回到简单方式的障碍。

  1. Assimp Unique Indices and Vertices,这并没有错,但是对于算法来说,没有办法为此做邻接半边结构。
  2. OpenMesh 用于只读取目标文件(*.obj),使用read_mesh 函数可以做到这一点,但缺点是缺少文档示例,在我的引擎中难以使用。
  3. 为任何格式编写自定义 3d 模型导入器都很难。

总之,在引擎中实现细节层次有两种方法,一种是使用网格简化算法和更多的测试来保证质量,另一种只是切换3d软件制作的3dmodel,它不是自动的但稳定。我使用第二种方法,我在这里展示结果:)

但是,这不是我的问题的真正解决方案,所以我不会给我一个答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    • 2015-03-17
    • 2020-11-30
    • 2021-12-27
    • 1970-01-01
    • 2022-11-28
    • 2014-07-12
    相关资源
    最近更新 更多