Как я могу загрузить и визуализировать файл OBJ, который может включать в себя треугольники, четырехугольники или N-Gons в OpenGL? - PullRequest
1 голос
/ 12 марта 2020

У меня есть следующий код c ++ для загрузки объектного файла, по крайней мере, вершин и индексов вершин.

 bool ObjMeshImporter::from_file(const std::string& filepath, nelems::Mesh* pMesh)
  {
    std::ifstream in(filepath, std::ios::in);
    if (!in)
    {
      return false;
    }

    std::vector<glm::vec3> t_vert;

    std::string line;
    while (std::getline(in, line))
    {
      if (line.substr(0, 2) == "v ")
      {
        // read vertices
        std::istringstream s(line.substr(2));
        glm::vec3 v; s >> v.x; s >> v.y; s >> v.z;

        // Add to temporary vertices before indexing
        t_vert.push_back(v);
      }
      else if (line.substr(0, 2) == "f ")
      {
        // TODO: Store UVs and Normals
        unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
        int count_found = sscanf_s(line.substr(2).c_str(), 
          "%d/%d/%d %d/%d/%d %d/%d/%d\n", 
          &vertexIndex[0], &uvIndex[0], &normalIndex[0], 
          &vertexIndex[1], &uvIndex[1], &normalIndex[1], 
          &vertexIndex[2], &uvIndex[2], &normalIndex[2]);

        if (count_found != 9) {
          return false;
        }

        pMesh->add_vertex_index(vertexIndex[0]-1);
        pMesh->add_vertex_index(vertexIndex[1]-1);
        pMesh->add_vertex_index(vertexIndex[2]-1);

      }
    }

    // Now use the indices to create the concrete vertices for the mesh
    for (auto v_idx : pMesh->GetVertexIndices())
    {
      glm::vec3 vertex = t_vert[v_idx];
      pMesh->add_vertex(vertex);
    }
    return true;
  }

Он работает довольно хорошо для такого объекта, как этот (икосфера Блендера):

enter image description here

Эта модель состоит из треугольников.

Но когда я загружаю тот, у которого есть четырехугольники, он не работает:

enter image description here

конечно, потому что это мой метод рендеринга лица:

glDrawArrays(GL_TRIANGLES, 0, (GLsizei)mVertexIndices.size());

Итак, я знаю, мне нужно расширить парсер и для каждой строки в «f» проверить, сколько у меня есть индексов, и лучше всего было бы хранить VFace-класс, который знает, сколько вершин сделано из лица - хорошо.

Так что я бы рендерил лица с трисом как GL_TRIANGLE и лица с квадрами как GL_QUADS ... но как насчет NGONS? А также как отрисовать линии?

РЕДАКТИРОВАТЬ: я видел, что есть GL_POLYGON. Но нужно ли для них создавать отдельные вершинные буферы?

1 Ответ

0 голосов
/ 15 марта 2020

Нет, я хочу визуализировать лица с треугольниками, квадратами или нгонами.

Я считаю, что этот вопрос не имеет разумного решения. Современное графическое оборудование отображает только 3 типа примитивов: точек , линий сегментов и треугольников . Таким образом, прямой ответ заключается в том, что вы должны сгенерировать триангуляцию из любого супа с не треугольной геометрией ( квадратов , n-полигонов , B-Spline поверхностей, аналитические поверхности и др. c.). Это может быть сделано вашим собственным кодом или с использованием существующей библиотеки (последняя является предпочтительной, поскольку разбиение полигонов не так уж тривиально - я видел несколько реализаций, работающих в целом, но с ошибками в том или ином случае использования в некоторых файлах OBJ).

Существуют веские причины, по которым современное оборудование работает только на треугольниках - их можно использовать для рендеринга любой другой геометрии, они идеально распараллелены (по сравнению с геометрией, имеющей переменное количество узлов в элементе), и это упрощает аппаратное обеспечение.

Вот несколько подходов для рендеринга не треугольников в OpenGL с комментариями:

  • GL_QUADS. Устаревший , начиная с OpenGL 3.0. Следует отметить, однако, что согласно различным публикациям и дискуссиям, по крайней мере, аппаратные средства NVIDIA и, вероятно, AMD все еще на самом деле поддерживают аппаратно-ускоренную поддержку этих примитивов. Вам понадобятся два разных прохода отрисовки для рендеринга треугольников, смешанных с квадратами (например, индексы разделения для каждого типа примитива, хотя у вас все еще может быть общий буфер вершин). Если вы когда-либо использовали GL_QUADS в приложении, вы также можете заметить, что неплоский четырехугольник, передаваемый графическому оборудованию, разбивается на треугольники, и разные производители графических процессоров делают это в разном порядке (например, создают разные пары треугольников).

  • GL_POLYGON. Также Устаревший , начиная с OpenGL 3.0. Этот примитив существовал в OpenGL в те дни, когда обработка вершин выполнялась не графическим оборудованием, а процессором. Так что у этого, вероятно, никогда не было реального аппаратного ускорения - драйвер OpenGL просто разделял полигоны на треугольники медленным и неэффективным способом. Существует еще одна причина, по которой GL_POLYGON практически бесполезен для файлов OBJ - GL_POLYGON предназначен только для выпуклых полигонов (тривиально разбиваемых на треугольники), тогда как файлы OBJ часто содержат вогнутых полигонов. Вы можете найти некоторые спецификации OBJ для inte rnet, требующие выпуклости многоугольников, в то время как другие вообще не указывают детали многоугольника - но практически вы не можете игнорировать это, так как в реальном файле OBJ есть сложные многоугольники (если вы заботитесь о чтении) произвольные файлы).

  • GL_PATCHES для Тесселяционные шейдеры . Они предназначены для аппаратно-ускоренной триангуляции патчей фиксированного размера, что является мощным механизмом для отображения сглаживаемых поверхностей. Однако они не имеют ничего общего с n-полигонами в файле OBJ, так как для определения геометрии шейдерного тесселяции требуются следующие очень разные шаблоны.

  • Примитивы смежности для Геометрия шейдеры . Примитивы типа GL_TRIANGLES_ADJACENCY предоставляют дополнительную информацию об окружении треугольника, но они также не имеют прямого отношения к n-полигонам в файле OBJ. В отличие от шейдеров Tesselation, Geometry Shader позволяет вызывать переменное количество новых треугольников с произвольно заданными позициями узлов. Технически это позволяет генерировать произвольный n-многоугольник, разбитый на треугольники в Geometry Shader. Хотя для этого необходимо предоставлять данные геометрии не внутри данных основных вершин, а с помощью дополнительных структур (таких как TBO или аналогичных). Практически, этот подход не имеет смысла для реализации (если вы не проводите некоторые исследования), поскольку Geometry Shaders оказались очень неэффективными для задач, похожих на тесселяцию, что приводит к очень низкой производительности .

  • Вычислительные шейдеры . Их можно использовать для произвольных задач, включая разбиение многоугольников на треугольники с использованием пользовательских структур данных и / или их рендеринг, но это маловероятный надежный способ рендеринга многоугольников - также предмет исследования, а не практического решения.

...