Рендеринг сетки с помощью VTK api

Я делаю более простой просмотрщик для чтения и визуализации меша.

VTK для меня новичок, и я сначала пытаюсь найти лучший/наиболее эффективный способ настроить данные сетки для средства просмотра. Я вижу, что есть много примеров VTK с C++, но многие из них предназначены для преобразования в формат vtk или примитивов рендеринга.

Меня не интересует преобразование в формат vtk, я просто хочу настроить данные сетки на неструктурированную сетку vtk или набор данных vtk poly и визуализировать их.

Я провел небольшой тест. Приведенный ниже код отображается правильно, но является ли это наиболее эффективным способом настройки набора данных? Если я установлю N_SQUARES на 1 000 000, это сработает, но треугольный цикл кажется очень медленным.

    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();


    //TEST MESH
    int N_SQUARES = 100;

    //This creates node coordinates for N_SQUARES amount of squares. (Nodal data would be read from a file later on)
    vtkSmartPointer<vtkPoints> nodes = vtkSmartPointer<vtkPoints>::New();   

    for (int i = 0; i < N_SQUARES; i++){
        nodes->InsertNextPoint(0.0, 0.0, 0.0 + 0.2f*float(i));
        nodes->InsertNextPoint(1.0, 0.0, 0.0 + 0.2f*float(i));
        nodes->InsertNextPoint(1.0, 1.0, 0.0 + 0.2f*float(i));
        nodes->InsertNextPoint(0.0, 1.0, 0.2 + 0.2f*float(i));
    }

    //Here two triangles are created for each square. (these indices would later on be read from FEM element data)
    vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New();

    for (int j = 0; j < N_SQUARES; j++){
        vtkSmartPointer<vtkTriangle> triangle1 = vtkSmartPointer<vtkTriangle>::New();
        triangle1->GetPointIds()->SetId(0, 0 + j);
        triangle1->GetPointIds()->SetId(1, 1 + j);
        triangle1->GetPointIds()->SetId(2, 2 + j);

        vtkSmartPointer<vtkTriangle> triangle2 = vtkSmartPointer<vtkTriangle>::New();
        triangle2->GetPointIds()->SetId(0, 2 + j);
        triangle2->GetPointIds()->SetId(1, 3 + j);
        triangle2->GetPointIds()->SetId(2, 0 + j);


        triangles->InsertNextCell(triangle1);
        triangles->InsertNextCell(triangle2);
    }

    vtkSmartPointer<vtkPolyData> meshData = vtkSmartPointer<vtkPolyData>::New();
    meshData->SetPoints(nodes);
    meshData->SetPolys(triangles);

    vtkSmartPointer<vtkPolyDataMapper> meshMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    meshMapper->SetInputData(meshData);

    vtkSmartPointer<vtkActor> meshActor = vtkSmartPointer<vtkActor>::New();
    meshActor->SetMapper(meshMapper);

    renderer->AddActor(meshActor);


    ui.qvtkWidget->GetRenderWindow()->AddRenderer(renderer);

person remi    schedule 28.06.2017    source источник


Ответы (1)


Код в вашем примере может быть медленным по любой из нескольких причин.

  • Вы создаете и уничтожаете 2 экземпляра vtkTriangle внутри вашего j-цикла. Это дорого и, вероятно, самая большая причина медлительности.
  • Поскольку вы строите полиданные, лучше вообще не использовать vtkTriangle. Вместо этого сделайте что-то вроде

    for (int j = 0; j < N_SQUARES; ++j)
    {
      vtkIdType triangle1[3] = {j, j+1, j+2};
      vtkIdType triangle2[3] = {j+2, j+3, j};
      triangles->InsertNextCell(3, triangle1);
      triangles->InsertNextCell(3, triangle2);
      // ... or better yet, create a single quad:
      vtkIdType quad[4] = {j, j+1, j+2, j+3};
      triangles->InsertNextCell(4, quad);
    }
    
  • Вы не сообщаете VTK, насколько большими будут массивы (координаты точек или связность) заранее. Это означает, что VTK должен перераспределять и копировать массивы по мере увеличения их размера. Попробуйте добавить nodes->GetData()->Allocate(4 * N_SQUARES); перед первым циклом (над i). Точно так же вы можете сказать vtkCellArray заранее выделить нужный объем памяти (немного сложно, это массив целых чисел, отформатированный следующим образом: nptsPerPoly0 ptId0Poly0 ptId1Poly0 ... ptIdNPoly0 nPtsPerPoly1 ...). Для треугольников вы бы назвали triangles->Allocate((1 + 3) * 2 * N_SQUARES);. Для квадроциклов, как в предыдущем примере, это будет triangles->Allocate((1 + 4) * N_SQUARES);.

  • В вашем примере не используются точки, которые являются общими для нескольких квадратов. Это приводит к тому, что и nodes, и triangles потребляют гораздо больше памяти, чем необходимо.
  • Для сеток среднего размера (умещающихся в памяти одного компьютера) можно использовать многопоточность для подготовки массивов nodes и triangles. Для больших сеток VTK предназначен для работы на нескольких компьютерах, каждый из которых содержит только часть сетки (параллелизм с распределенной памятью).
  • Если у вас уже есть сетка в памяти, последние версии VTK позволяют вам писать специальные классы, которые открывают сетку для VTK, не требуя каких-либо копий, но это выходит за рамки этого вопроса. Однако это уменьшит вдвое объем памяти, потребляемой данной сеткой, поэтому это может быть важно в зависимости от сетки и памяти вашего компьютера.
  • В зависимости от того, насколько большим вы сделаете N_SQUARES, вы можете заставить свой компьютер использовать файл подкачки или раздел. В этом случае вам следует уменьшить размер сетки или использовать параллелизм с распределенной памятью.
person Drone2537    schedule 01.07.2017
comment
Благодарю вас! Вот такой ответ мне был нужен. Изменю мой код и протестирую его. У меня есть некоторый опыт работы с OpenGL и использованием буфера и т. д. для рендеринга. Я считаю, что под капотом VTK использует это. Есть ли обзор того, как VTK вызывает различные методы OpenGL? - person remi; 01.07.2017
comment
@ remi000 Все вызовы VTK OpenGL ограничены классами в каталогах VTK/Rendering/OpenGL или VTK/Rendering/OpenGL2 (в зависимости от того, используете ли вы старый или новый бэкэнд OpenGL. Внутри директора вызовы OpenGL разделены по многим классам. Например, vtkOpenGLPolyDataMapper.cxx заполняет экземпляры vtkOpenGLVertexBufferObject данными; вызовы, которые связывают/загружают объекты буфера, находятся в vtkOpenGLBufferObject (надкласс vtkOpenGLVertexBufferObject). - person Drone2537; 01.07.2017