No interaction for vtkCameraOrientationWidget in QtQuick

I am developing a 3D application based on VTK and QtQuick. I am trying to use vtkCameraOrientationWidget and followed example here (https://kitware.github.io/vtk-examples/site/Cxx/PolyData/Curvatures/). To use vtkCameraOrientationWidget, it is basically three lines of code:

  vtkNew<vtkCameraOrientationWidget> camOrientManipulator;
  camOrientManipulator->SetParentRenderer(renderer);
  // Enable the widget.
  camOrientManipulator->On();

But there is no interaction (i.e., mouse click on the handle to change camera view). I can confirm that my vtkstyle get all the mouse events passed from QEvent. Any help is appreciated!

Thanks,
Cam

Hi,

I don’t use vtkCameraOrientationWidget, but something else from the same family. I setup my VTK widget with a code like this (the last four lines of code are the ones that make the thing work):

    //----------------------adding the orientation axes-------------------------
    vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
    _vtkAxesWidget = vtkSmartPointer<vtkOrientationMarkerWidget>::New();
    _vtkAxesWidget->SetOutlineColor(0.9300, 0.5700, 0.1300);
    _vtkAxesWidget->SetOrientationMarker(axes);
    _vtkAxesWidget->SetInteractor(_vtkwidget->GetRenderWindow()->GetInteractor());
    _vtkAxesWidget->SetViewport(0.0, 0.0, 0.2, 0.2);
    _vtkAxesWidget->SetEnabled(1);
    _vtkAxesWidget->InteractiveOn();
    //--------------------------------------------------------------------------

In the code above, _vtkwidget is a QVTKOpenGLWidget in my case. IMO, it’s missing a call to SetInteractor().

I hope this helps somehow.

regards,

Paulo

Hi Paulo,

Thanks for your reply. vtkOrientationMarkerWidget use a different design than vtkCameraOrientationWidget.
For vtkCameraOrientationWidget, SetInteractor() actually happens inside SetParentRenderer()
What I need to do is just to have a widget where I can click on a set of handles to actively change the camera view in my renderer. This is exactly what vtkCameraOrientationWidget does. Now in my codebase, I can get it work except for handle interactions. For some reasons, vtkCameraOrientationWidget doesn’t receive my mouse events.
Now I am trying vtkOrientationMarkerWidget which can receive my events but I have to implement the control by myself (i.e., click on the widget, pick the corresponding cell, then do something).

Did you try this:

?

I don’t have a _vtkwidget as QVTKOpenGLWidget.
What is _vtkwidget for?
In your example, if I do
_vtkAxesWidget->SetInteractor(_myRenderWindow->GetInteractor()); rather than
_vtkAxesWidget->SetInteractor(_vtkwidget->GetRenderWindow()->GetInteractor());. Isn’t it the same thing?

If _myRenderWindow points to the window you’re rendering the scene and receiving user input events, then yes.

That’s correct. I also tested some other widgets such as vtkImplicitPlaneWidget2
using standard boilerplate code:

vtkNew<vtkImplicitPlaneRepresentation> rep;
vtkNew<vtkImplicitPlaneWidget2> planeWidget;
planeWidget->SetRepresentation(rep);
auto iren = ren->GetRenderWindow()->GetInteractor();
planeWidget->SetInteractor(iren);
planeWidget->SetCurrentRenderer(ren);
planeWidget->SetEnabled(true);
planeWidget->SetProcessEvents(true);

And it works fine. I suspect that my issue with vtkCameraOrientationWidget is from SetParentRender() design which is different than other widgets.

For other widgets, the workflow is 1) setup widget representation. 2) setup widget interactor which is the interactor in my renderwindow. 3) enable widget. So there is only one renderer and one layer in renderwindow and the widget is rendered in this renderer.

For vtkCameraOrientationWidget, it is a little bit different as it creates a second renderer which is overlaid on my main renderer. So my renderwindow has two layers: layer 0 for my main renderer and layer 1 for a new renderer which renders vtkCameraOrientationWidget. Per instruction, I just have to do

  vtkNew<vtkCameraOrientationWidget> camOrientManipulator;
  camOrientManipulator->SetParentRenderer(renderer);
  // Enable the widget.
  camOrientManipulator->On();

Everything that I described above just happened inside SetParentRenderer(renderer). But there is no interaction. This particular design doesn’t fit my QtQuick framework or at least I am missing something. I am really confused.

I also have two renderers in my program (the main one called _rendererMainScene and another for always-on-top actors such as labels called _rendererForeground). Here’s how I set everthing up (before adding actors):

    _vtkwidget = new QVTKOpenGLWidget();

    _rendererMainScene = vtkSmartPointer<vtkRenderer>::New();

    // Create the renderer for always-on-top objects
    // It attaches to the same camera of the main renderer
    _rendererForeground = vtkSmartPointer<vtkRenderer>::New();
    _rendererForeground->SetActiveCamera( _rendererMainScene->GetActiveCamera() );
    _rendererForeground->SetLayer( 1 ); //layers greater than zero have no background and are rendered last.

    _vtkwidget->SetRenderWindow(vtkGenericOpenGLRenderWindow::New());
    _vtkwidget->GetRenderWindow()->AddRenderer(_rendererMainScene);
    _vtkwidget->GetRenderWindow()->AddRenderer(_rendererForeground);
    _vtkwidget->setFocusPolicy(Qt::StrongFocus);

    //----------------------adding the orientation axes-------------------------
    vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
    _vtkAxesWidget = vtkSmartPointer<vtkOrientationMarkerWidget>::New();
    _vtkAxesWidget->SetOutlineColor(0.9300, 0.5700, 0.1300);
    _vtkAxesWidget->SetOrientationMarker(axes);
    _vtkAxesWidget->SetInteractor(_vtkwidget->GetRenderWindow()->GetInteractor());
    _vtkAxesWidget->SetViewport(0.0, 0.0, 0.2, 0.2);
    _vtkAxesWidget->SetEnabled(1);
    _vtkAxesWidget->InteractiveOn();
    //--------------------------------------------------------------------------

    // Customize event handling through a subclass of vtkInteractorStyleTrackballCamera.
    // This allows picking and probing by clicking on objects in the scene, for example.
    m_myInteractor = vtkSmartPointer<v3dMouseInteractor>::New();
    m_myInteractor->setParentView3DWidget( this );
    m_myInteractor->SetDefaultRenderer(_rendererMainScene);
    _vtkwidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle( m_myInteractor );

    // Set callback for any event
    vtkSmartPointer<vtkCallbackCommand> callBackCommand = vtkSmartPointer<vtkCallbackCommand>::New();
    callBackCommand->SetCallback( rendererCallback );
    callBackCommand->SetClientData((void*)this);
    _rendererMainScene->AddObserver( vtkCommand::AnyEvent , callBackCommand );   // mp_ren is the vtkRenderer object.

    // adjusts view so everything fits in the screen
    _rendererMainScene->ResetCamera();

    // add the VTK widget the layout
    ui->frmViewer->layout()->addWidget(_vtkwidget);

Maybe this helps to pinpoint the problem with your code.

Anything amiss with how the objects are wired you’ll end up with the mouse events not going to where they are supposed to.

SetParentRenderer() is supposed to wire everything for you, that is, to send mouse events to the target renderer so whenever you manipulate the vtkCameraOrientationWidget, the scene updates accordingly. Maybe the problem is on how two renderers coexist in the same render window. See the code I posted above on how two renderers can coexist so the can both display things and receive user input events through the same window.

Hi Cam,

I am the author of vtkCameraOrientationWidget and it’s representation. I’ll be honest, I haven’t tested it in a QtQuick window yet. As a matter of fact I have never done any QtQuick development besides the basics in QtCreator.

Could you help me by answering these questions?

  1. When you try to rotate the camera interactively in the main renderer (the viewport with your dataset (s)), does the camera rotate like usual?
  2. When you do the above, does the widget also rotate and does it show some sort of synchronization with the main renderer’s camera?
  3. When you move mouse on top of the widget, do you see any of these visual changes in the widget?
    a. A transparent greyish disk enclosing the widget
    b. The color of the text (x or y or z) on the hovered grabber changes from black to white

I want to know if the widget is at least hot. Basically, for any interaction, it needs to get activated by hovering, which makes it hot.

It would be great if you could call Print on the widget and the interactor on any mouse click, move, release events. I would like to see the event flow.

Hi jaswantp,

Thanks for your reply.

  1. Yes, the camera rotates like usual in my main renderer.
  2. The camera in vtkCameraOrientationWidget is synchronized with the main renderer.
  3. I don’t see any kind of change. The widget is not hot. It doesn’t receive any mouse events including the mouse hovering.

I think the problem comes from QtQuick wrapper layer (VTK/GUISupport/QtQuick at master · Kitware/VTK · GitHub).
One thing I would look out for is in QQuickVTKRenderWindow.cxx, on line 129 ~ 132, it creates a dummy renderer in m_renderWindow and sets the number of layers to 2, which could mess up with the renderer which renders vtkCameraOrientationWidget .
The other thing is QQuickVTKInteractiveWidget.cxx where sync function is defined.

I have no intention to change the source. I am kind of switching my main application back to QtWidget. I realized that I can inject QML element into my main QtWidget application.

and sets the number of layers to 2, which could mess up with the renderer which renders vtkCameraOrientationWidget .

Hmm, I think there is no need to worry about this because I safely preserve/increase the number of layers. See 83 - 84 and 100 - 101

I’ve seen this widget work in ParaView which already uses 2 layers (base layer +1 for the older pvAxes orientation widget) so it should not be an issue with layers afaik.

This comment notes that the dummy renderer spans the entire viewport. QQuickVTKRenderWindow.cxx:127

I assume because both the renderers QQuickVTKRenderWindow::m_dummyRenderer and vtkCameraOrientationWidget::DefaultRenderer live in the same layer and one overlaps the other, the events are not propagated to my widget. I have to investigate this…

In ParaView, it might have worked because the old pvAxes orientation widget occupied a smaller viewport rectangle and did not overlap the widget renderer’s viewport.