2017-06-28 3 views
0

Ich mache einen einfacheren Viewer, um ein Mesh zu lesen und zu visualisieren.Rendern eines Gitters mit VTK api

VTK ist neu für mich und ich versuche zuerst herauszufinden, die beste/effizienteste Möglichkeit zum Einrichten der Maschendaten für den Betrachter. Ich sehe, es gibt viele Beispiele für VTK mit C++, aber viele von ihnen sind in Vtk-Format oder Rendering-Primitiven zu konvertieren.

Ich bin nicht interessiert an VTK-Format bei der Umwandlung, ich, was nur meine Netzdaten zu einem VTK unstrukturierten Gitter oder VTK Poly Daten gesetzt einzurichten und sie machen.

Ich habe einen kleinen Test gemacht. Der folgende Code wird richtig wiedergegeben, aber ist dies die effizienteste Methode zum Einrichten des Datasets? Wenn ich N_SQUARES auf 1 000 000 setze, funktioniert es, aber die Dreiecksschleife scheint sehr langsam zu sein.

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

Antwort

1

Der Code in Ihrem Beispiel könnte aus einem von mehreren Gründen

  • Sie bauen und zu zerstören 2 vtkTriangle Instanzen in Ihrem j -loop langsam sein. Dies ist teuer und wahrscheinlich die größte Ursache für Langsamkeit.
  • Da Sie Polydata erstellen, wäre es am besten zu vermeiden, vtkTriangle überhaupt zu verwenden. Stattdessen tun so etwas wie

    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); 
    } 
    
  • Sie nicht VTK sagen, wie groß die Arrays (Punktkoordinaten oder Konnektivität) vor der Zeit sein werden. Dies bedeutet, dass VTK die Arrays neu zuweisen und kopieren muss, wenn Sie ihre Größe erhöhen. Versuchen Sie, vor Ihrer ersten Schleife nodes->GetData()->Allocate(4 * N_SQUARES); hinzuzufügen (über i). In ähnlicher Weise können Sie dem vtkCellArray mitteilen, dass es im Voraus die richtige Menge an Speicher reservieren soll (etwas kompliziert; es ist ein Array von Ganzzahlen, die wie folgt formatiert sind: nptsPerPoly0 ptId0Poly0 ptId1Poly0 ... ptIdNPoly0 nPtsPerPoly1 ...). Für Dreiecke würden Sie triangles->Allocate((1 + 3) * 2 * N_SQUARES); anrufen. Für Quads wie im vorherigen Beispiel wäre es triangles->Allocate((1 + 4) * N_SQUARES);.

  • Ihr Beispiel verwendet keine Punkte, die von mehreren Quadraten gemeinsam verwendet werden. Das macht nodes und triangles verbrauchen viel mehr Speicher als nötig.
  • Für mittelgroße Netze (passen in Arbeitsspeicher auf einem einzelnen Computer), können Sie Threading verwenden, um die nodes und triangles Arrays vorzubereiten. Bei großen Netzen ist VTK so konzipiert, dass es auf mehreren Computern ausgeführt werden kann, auf denen jeweils nur ein Teil des Netzes (verteilte Speicherparallelität) vorhanden ist.
  • Wenn Sie das Mesh bereits im Speicher haben, können Sie in neueren Versionen von VTK spezielle Klassen schreiben, die das Mesh VTK zugänglich machen, ohne dass Kopien erforderlich sind. Dies würde jedoch den Rahmen dieser Frage sprengen. Es würde jedoch die Speichermenge, die ein bestimmtes Mesh verbraucht, halbieren, was abhängig vom Mesh und dem Speicher Ihres Computers wichtig sein könnte.
  • Abhängig davon, wie groß Sie N_SQUARES machen, können Sie Ihren Computer veranlassen, eine Auslagerungsdatei oder Partition zu verwenden. In diesem Fall sollten Sie die Größe Ihres Netzes reduzieren oder die Parallelität des verteilten Speichers verwenden.
+0

Vielen Dank! Das ist die Art von Antwort, die ich brauchte. Ändere meinen Code und teste ihn aus. Ich habe einige Erfahrung mit OpenGL und die Verwendung von Puffer und so weiter zum Rendern. Ich glaube "unter die Haube" VTK nutzt dies. Gibt es einen Überblick darüber, wie VTK die verschiedenen OpenGL-Methoden aufruft? – remi000

+0

@ remi000 Alle OpenGL-Aufrufe von VTK beschränken sich auf Klassen in den Verzeichnissen 'VTK/Rendering/OpenGL' oder' VTK/Rendering/OpenGL2' (je nachdem, ob Sie das alte oder das neue OpenGL-Backend verwenden. Im Director, dem Aufrufe von OpenGL sind auf viele Klassen verteilt, zum Beispiel 'vtkOpenGLPolyDataMapper.cxx' füllt' vtkOpenGLVertexBufferObject'-Instanzen mit Daten, Aufrufe, die die Pufferobjekte binden/hochladen, befinden sich in 'vtkOpenGLBufferObject' (die Oberklasse von' vtkOpenGLVertexBufferObject'). – Drone2537