vtkGlyph3DMapper with double precision as vtkGlyph3D?

Hi there,

My team has been trying to replace the filter vtkGlyph3D by its GPU version vtkGlyph3DMapper, but seems like the mapper version does not support large coordinates very well as the filter do. Since in our project the point coordinates are frequently above 6000000, I would like to know if we are missing any additional configuration; if its a limitation of this mapper or a mere lack of understanding. Thank you!
(I suspect this topic from @cobo might be related: Struggling with geographic coordinates, but I’m not sure how that could apply for mappers)

Follow a simple code example comparing the two approaches given the same input data:

Bug%20demo%20of%20Glyph3dMapper%20against%20Glyph3d

Glyph3dMapper vs Glyph3d

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType);

#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCubeSource.h>
#include <vtkFloatArray.h>
#include <vtkGlyph3DMapper.h>
#include <vtkNamedColors.h>
#include <vtkPointData.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkUnsignedCharArray.h>

int main(int, char*[]) {
  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
  points->SetDataTypeToDouble();
  points->InsertNextPoint(6000000, 6000000, 6000000);
  points->InsertNextPoint(6000001, 6000001, 6000001);
  points->InsertNextPoint(6000002, 6000002, 6000002);

  vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
  polydata->SetPoints(points);

  vtkSmartPointer<vtkCubeSource> cubeSource = vtkSmartPointer<vtkCubeSource>::New();

  // ### Glyph3d
  vtkSmartPointer<vtkGlyph3D> glyph3D = vtkSmartPointer<vtkGlyph3D>::New();
  glyph3D->SetSourceConnection(cubeSource->GetOutputPort());
  glyph3D->SetInputData(polydata);
  glyph3D->Update();

  vtkSmartPointer<vtkPolyDataMapper> glyph_mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
  glyph_mapper->SetInputConnection(glyph3D->GetOutputPort());

  vtkSmartPointer<vtkActor> actor_glyph = vtkSmartPointer<vtkActor>::New();
  actor_glyph->SetMapper(glyph_mapper);

  // ### Glyph3dMapper
  vtkSmartPointer<vtkGlyph3DMapper> glyph3Dmapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
  glyph3Dmapper->SetSourceConnection(cubeSource->GetOutputPort());
  glyph3Dmapper->SetInputData(polydata);
  glyph3Dmapper->Update();

  vtkSmartPointer<vtkActor> actor_glyph_3dmapper = vtkSmartPointer<vtkActor>::New();
  actor_glyph_3dmapper->SetMapper(glyph3Dmapper);

  // Create a renderer, render window, and interactor
  // Define viewport ranges
  // (xmin, ymin, xmax, ymax)
  double leftViewport[4] = {0.0, 0.0, 0.5, 1.0};
  double rightViewport[4] = {0.5, 0.0, 1.0, 1.0};

  // Setup both renderers
  vtkSmartPointer<vtkRenderer> leftRenderer = vtkSmartPointer<vtkRenderer>::New();
  leftRenderer->SetViewport(leftViewport);
  leftRenderer->SetBackground(.6, .5, .4);

  vtkSmartPointer<vtkRenderer> rightRenderer = vtkSmartPointer<vtkRenderer>::New();
  rightRenderer->SetViewport(rightViewport);
  rightRenderer->SetBackground(.4, .5, .6);

  vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->AddRenderer(leftRenderer);
  renderWindow->AddRenderer(rightRenderer);

  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
      vtkSmartPointer<vtkRenderWindowInteractor>::New();
  renderWindowInteractor->SetRenderWindow(renderWindow);

  // Add the actor to the scene
  leftRenderer->AddActor(actor_glyph_3dmapper);
  rightRenderer->AddActor(actor_glyph);

  // Position the camera
  leftRenderer->GetActiveCamera()->SetPosition(5999990, 6000000, 6000000);
  leftRenderer->GetActiveCamera()->SetFocalPoint(6000000, 6000000, 6000000);

  rightRenderer->GetActiveCamera()->SetPosition(5999990, 6000000, 6000000);
  rightRenderer->GetActiveCamera()->SetFocalPoint(6000000, 6000000, 6000000);

  // Render and interact
  renderWindow->Render();
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}

Thank you for your time,
Rodrigo Figueiredo.

You can try replacing all float types by double in vtkOpenGLGlyph3DMapper and vtkOpenGLGlyph3DHelper.

Alternatively, you can address numerical instability by normalizing your coordinates (subtract mean position from all coordinates, divide all coordinates by the bounding box diameter).

1 Like

Hello Andras,

So just to be clear: besides doing our own vtk fixed compilation, currently we are not able to configure that from a user’s perspective? And if so, are there any scheduled version where those double precision options will be generally reviewed?

This alternative was considered, but we are reticent due to the fairly diverse types of data we need to mix together in a consistent way, as well as the the I/O of the user that would have to be fixed everywhere… so, unless you know of something that could potentially solve this kind of general coordinate system shift, we are holding back to do that.

Thank you!
Rodrigo F. Figueiredo.

Automatic coordinate normalization is available already in some mappers in VTK, but not vtkGlyph3DMapper. Hence, the behavior that you are seeing. It’s not the vtkGlyph3D filter that handles the point coordinates correctly, it is the vtkOpenGLPolyDataMapper.

Changing to doubles won’t help anything. All the graphics math will be computed with floats anyway once the data gets to the graphics card and you’ll see the same problem.

This (optional) rescaling is done in the vtkOpenGLVertexBufferObject. See the documentation for the vtkOpenGLVertexBufferObject::ShiftScaleMethod. The shift and scaling is accounted for in the final camera transformation matrix so that you need not do anything to your input data or change the data type to double (OpenGL is going to use floats for transformation anyway).

The ideal solution is to make vtkOpenGLGlyph3DMapper handle the rescaling automatically.

1 Like

Hi Cory!
I see… so judging by the fact that the vtkOpenGLGlyph3DMapper doesn’t seem to have a vtkOpenGLVertexBufferObject, I suppose it’s not a matter of doing a small fix or change in configuration. Instead one would have to review the algorithm to include this behavior, is that it?

If that is so, I guess we have no other choice but to stick with the vtkGlyph3D filter for a while…

Thank you!

It is a little more complex than that, yes. If you would like to accelerate the implementation of point rescaling in vtkOpenGLGlyph3DMapper, Kitware offers support services.

1 Like