remi
remi

Reputation: 1047

Rendering a mesh with VTK api

I'm making a simpler viewer to read and visualize a mesh.

VTK is new to me and I'm first trying to figure out the best/most efficient way to set up the mesh data for the viewer. I see there are many examples of VTK with c++, but a lot of them are to convert to vtk format or rendering primitives.

I'm not interested in converting to vtk format, I just what to set up my mesh data to a vtk unstructured grid or vtk poly data set and render it.

I've done a little test. The code bellow correctly renders, but is this the most efficient way to set up the dataset? If I set N_SQUARES to 1 000 000, it works, but the triangle loop seems very slow.

    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);

Upvotes: 1

Views: 2249

Answers (1)

Drone2537
Drone2537

Reputation: 545

The code in your example could be slow for any of several reasons

  • You are constructing and destroying 2 vtkTriangle instances inside your j-loop. This is expensive and probably the largest cause of slowness.
  • Since you build polydata, it would be best to avoid using vtkTriangle at all. Instead, do something like

    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);
    }
    
  • You don't tell VTK how big the arrays (point coordinates or connectivity) are going to be ahead of time. This means VTK must reallocate and copy the arrays as you increase their size. Try adding nodes->GetData()->Allocate(4 * N_SQUARES); before your first loop (over i). Similarly, you can tell the vtkCellArray to allocate the right amount of memory ahead of time (a little tricky; it is an array of integers formatted like so: nptsPerPoly0 ptId0Poly0 ptId1Poly0 ... ptIdNPoly0 nPtsPerPoly1 ...). For triangles, you would call triangles->Allocate((1 + 3) * 2 * N_SQUARES);. For quads as in the previous example, it would be triangles->Allocate((1 + 4) * N_SQUARES);.

  • Your example doesn't re-use points that are shared by multiple squares. That makes both nodes and triangles consume much more memory than necessary.
  • For medium-sized meshes (fit in memory on a single computer), you can use threading to prepare the nodes and triangles arrays. For large meshes, VTK is built to work across multiple computers where each one holds only part of the mesh (distributed-memory parallelism).
  • If you already have the mesh in memory, recent versions of VTK allow you to write special classes that expose the mesh to VTK without requiring any copies, but that's beyond the scope of this question. However, it would halve the amount of memory a given mesh consumes so it could be important depending on the mesh and your computer's memory.
  • Depending on how big you make N_SQUARES, you could be causing your computer to use a swap file or partition. In that case you should reduce the size of your mesh or use distributed-memory parallelism.

Upvotes: 3

Related Questions