VTK - How to display multiple 3D text objects with a single actor

I am trying to make text using vtk vtkVectorText object. It works great for one three-dimensional location. I need to place 3D text over some 3d points (vtkPoint). I tried to do this with vtkTextActor3d, but each text object requires a separate actor, and I ended up with 10k actors, which is pretty bad and concise when I try to rotate a scene, for example.

I also tried applying some appendFilter to create a vtkVectorText array, getting an unstructured grid from an appendFilter object and then converting it to polydata to display an unstructured grid with my points. It shows nothing, as I cannot figure out what is the best way to do this.

Can someone help me?

Here is my code from the last part:

vtkSmartPointer<vtkAppendFilter> appendFilter = vtkSmartPointer<vtkAppendFilter>::New(); //for each point for (int i = 0; i < N;i++) { vtkSmartPointer<vtkVectorText> vecText = vtkSmartPointer<vtkVectorText>::New(); vecText->SetText("My text, needs to appear multiple times"); vecText->Update(); appendFilter->AddInputData(vecText->GetOutput()); appendFilter->Update(); } vtkSmartPointer<vtkUnstructuredGrid> unstructuredGrid = appendFilter->GetOutput(); unstructuredGrid->Allocate(N); unstructuredGrid->SetPoints(points); vtkSmartPointer<vtkGeometryFilter> geometryFilter = vtkSmartPointer<vtkGeometryFilter>::New(); geometryFilter->SetInputData(unstructuredGrid); geometryFilter->Update(); vtkSmartPointer<vtkPolyDataMapper> textMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); textMapper->SetInputConnection(geometryFilter->GetOutputPort()); vtkSmartPointer<vtkActor> textActor = vtkSmartPointer<vtkActor>::New(); textActor->SetMapper(textMapper); textActor->GetProperty()->SetColor(0, 1, 0); renderer->AddActor(textActor); 
+5
source share
1 answer

If the text for each point is the same, I would suggest using it as a symbol:

 vtkSmartPointer<vtkPolyData> pointsHolder = vtkSmartPointer<vtkPolyData>::New(); pointsHolder->SetPoints(points); // I assume that these are the points where you want the object to be rendered vtkSmartPointer<vtkGlyph3DMapper> glyphMapper = vtkSmartPointer<vtkGlyph3DMapper>::New(); glyphMapper->SetSourceConnection(vecText->GetOutputPort()); // this says WHAT should be rendered glyphMapper->SetInputData(pointsHolder); // this says WHERE textActor->SetMapper(glyphMapper); 

This will display the text at all points in the "points" array (which I assume is an array of vtkPoints with positions where you want the text to be rendered). Thus, you can do all kinds of things that you can’t add to one grid, for example, setting a different size for each glyph, providing an array of scales or turning them on / off interactively, providing a mask, etc. see http://www.vtk.org/doc/nightly/html/classvtkGlyph3DMapper.html

If the text may differ for each point, you will probably have to do this by adding. I see a few errors in your incremental code:

1) First, a little performance - call appendFilter-> Update (); only once, after you have set all the inputs.

2)

 unstructuredGrid->Allocate(N); unstructuredGrid->SetPoints(points); 

By calling Allocate, you just dumped everything that appendfilter did for you. Even without it, the second line will rewrite the positions for all points that were generated for the text. The result of adding a filter is just what you have to directly assign to your cartographer, these two lines should be deleted. Just like vtkGeometryFilter, I see no reason for this (I think you used it to get vtkPolyData instead of vtkUnstructuredGrid - just use vtkAppendPolydata instead of vtkAppendFilter, it will produce polydata directly).

3) However, now the array of "points" is not used, i.e. your text will not be in the correct position. You will need to convert the polydata for each instance of the text before assigning it to the add filter. The simplest would be to use points from your "points" array as translation vectors, so you must add the coordinates of the points to each point vecText-> GetOutput () before sending it to the add filter, so something like this:

 vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New(); //for each point for (int i = 0; i < N;i++) { vtkSmartPointer<vtkVectorText> vecText = vtkSmartPointer<vtkVectorText>::New(); vecText->SetText("My text, needs to appear multiple times"); vecText->Update(); vtkPolyData *output = vecText->GetOutput(); double *location = points->GetPoint(i); for (int j = 0; j < output->GetNumberOfPoints(); j++) { double *point = output->GetPoint(j); output->GetPoints()->SetPoint(j, point[0] + location[0], point[1] + location[1], points[2] + location[2]); } appendFilter->AddInputData(output); } appendFilter->Update(); 

You will need something smarter if you want, for example, to center the text there.

+1
source

Source: https://habr.com/ru/post/1260282/


All Articles