使用 VTK 渲染网格 api

Rendering a mesh with VTK api

我正在制作一个更简单的查看器来读取和可视化网格。

VTK 对我来说是新手,我首先尝试找出 best/most 为查看器设置网格数据的有效方法。我看到有很多使用 C++ 的 VTK 示例,但是其中很多都是转换为 vtk 格式或渲染原语。

我对转换为 vtk 格式不感兴趣,我只是想将我的网格数据设置为 vtk 非结构化网格vtk 多边形数据集 并渲染它。

我做了一个小测试。下面的代码正确呈现,但这是设置数据集的最有效方法吗?如果我将 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);

您示例中的代码可能由于多种原因而变慢

  • 您正在 j 循环中构造和销毁 2 个 vtkTriangle 实例。这很昂贵,并且可能是速度缓慢的最大原因。
  • 既然你构建了 polydata,最好完全避免使用 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);.

  • 您的示例没有重复使用多个方块共享的点。这使得 nodestriangles 都消耗了比必要更多的内存。
  • 对于中等大小的网格(适合单台计算机的内存),您可以使用线程来准备 nodestriangles 数组。对于大型网格,VTK 被构建为跨多台计算机工作,其中每台计算机仅包含网格的一部分(分布式内存并行性)。
  • 如果您已经在内存中拥有网格,最新版本的 VTK 允许您编写特殊的 类 将网格暴露给 VTK 而无需任何副本,但这超出了本问题的范围。但是,它会将给定网格消耗的内存量减半,因此根据网格和计算机的内存,它可能很重要。
  • 根据您制作的大小 N_SQUARES,您可能会导致计算机使用交换文件或分区。在那种情况下,您应该减小网格的大小或使用分布式内存并行性。