Упрощение сетки с помощью Assimp и OpenMesh

Несколько дней назад я задал вопрос о том, как использовать свертывание краев с помощью Assimp. Сглаживание объекта и удаление повторяющихся вершин в программном обеспечении являются основной проблемой, которая может заставить работать схлопывание краев, я имею в виду, что это работает, потому что MeshLab может упростить это следующим образом: упрощенная сетка

Это выглядит хорошо в MeshLab, но затем я делаю это в своем движке, который использует Assimp и OpenMesh. Проблема в том, что Assimp импортировал указанные вершины и индексы, что могло привести к тому, что полуребро пропустило противоположную пару (это называется не многообразие?). Снимок результата использует Quadric Decimation OpenMesh:

Прореживание OpenMesh

Чтобы очистить и найти проблему, я делаю это без децимации и напрямую анализирую структуру данных 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;
}

Также предоставьте объект дерева, который я тестировал, и данные лица, сгенерированные Assimp, я извлек из отладчика Visual Studio, что показывает проблему, заключающуюся в том, что некоторые индексы не могут найти пару индексов.


person Tokenyet    schedule 04.12.2016    source источник
comment
Вы убедились, что это не потому, что вы не рисуете лица сзади? т.е. нормали отсутствующих граней указывают внутрь дерева.   -  person Anders Schou    schedule 05.12.2016


Ответы (1)


Несколько недель думал об этом и терпел неудачу. Я подумал, что мне нужно какое-то академическое/математическое решение для автоматического создания этих прореженных сеток, но теперь я пытаюсь найти простой способ реализовать это, то, как я могу сделать, это изменить структуру для загрузки многообъектов (file.obj) в один пользовательский объект (класс obj) и переключить объект, когда это необходимо. Преимущество этого в том, что я могу управлять тем, что должно быть представлено, и игнорировать любые проблемы алгоритма.

Кстати, я перечисляю некоторые препятствия, которые толкают меня обратно на простой путь.

  1. Assimp Unique Indices and Vertices, в этом нет ничего плохого, но для алгоритма нет возможности сделать для этого полуреберную структуру смежности.
  2. OpenMesh для чтения только объектного файла (*.obj), это можно сделать при использовании функции read_mesh, но недостатком является отсутствие примера документа и сложность использования в моем движке.
  3. Написать собственный импортер 3D-моделей для любого формата сложно.

В заключение, есть два способа заставить уровень детализации работать в движке: один использует алгоритм упрощения сетки и дополнительные тесты для обеспечения качества, другой - просто переключить 3D-модель, созданную с помощью программного обеспечения для 3D. Это не автоматический, но стабильный. Я использую второй метод, и я показываю результат здесь :)

эта работа!

Однако это не настоящее решение моего вопроса, поэтому я не буду давать мне ответ.

person Tokenyet    schedule 06.12.2016