Fixing the unstable camera up vector when rotating horizontally

When rotating the camera around a scene with vtkInteractorStyleTrackballCamera, there is a unsatisfying swinging effect that I would like to avoid. I mainly want to know if you agree with the solution before starting to implement it.

Unsatisfying behaviour

I can start a VTK view with a camera standing horizontally, having an up vector toward the Z axis :

vtkCamera0

When I start to drag mouse on the left or right, the camera is rotating around the focal point as expected, but also has its up vector oscillating a little on the right then left like the mast of a boat on the sea.

Despite one can continue rotating to get back to a fully horizontal view, I want to avoid this :

Expected behaviour

Another 3D framework - Jzy3D - does not have this behaviour with its camera mouse controller


The axis always look horizontal whatever the camera rotations.

Reason

My understanding is that this VTK behaviour could be due to the recomputation of the camera up vector when rotating, which is the only difference I found with Jzy3D camera rotation (limited to azimuth and elevation increments).

I presume that in VTK, the up vector is updated to allow complete rotation around the object and allow an up-side-down camera (?). In Jzy3D, the up vector is always kept to (0,0,1) (toward increading Z), as elevation increment can not go above the top or bottom position (looking to the ground from the sky or vice versa). OpenGL has always been fine with this, even if a top position may deserve more relevant up vectors like (1, 0, 0) or (0, 1, 0).

Proposal for a fix

I’d like to get your opinion on the appropriate improvements to get a stable camera

  • Add a OrthogonalyzeCameraUpVector setting to allow disabling the recomputation of the up vector.
  • Add a hook to let the user program this.

I would choose the first solution mainly because I work with Python and Java and that I can not easily override vtk classes from Python or Java (if you know way, please tell me!).

I however fear that this may let the camera in an inconsistent setting and that would not allow such a contribution to be merged in VTK. Not having my solution merged in VTK would require to keep my own build of VTK which I would like to avoid.

What would you suggest?

I’ve noticed this, too, when viewing complex scenes with a long rendering time. It seemed to me that the problem was that Modified event was invoked right after changing the camera orientation and then again after orthogonalization. This can be fixed very easily, by reorganizing the code so that Modifed event is only invoked once, after orthogonalization.

Thank you Andras for your suggestion. I don’t think that it comes from a race condition on my side as I don’t have long rendering, and also it occurs for all scenes.

Your suggestion about ModifiedEvent led me to read more about observables in VTK and I found a workaround that avoid modifying vtkCamera (which answers my second question!) :

renderWindowInteractor.AddObserver('InteractionEvent', CameraObserver(renderer.GetActiveCamera()))

class CameraObserver(object):
    def __init__(self, cam):
        self.cam = cam

    def __call__(self, caller, ev):
        self.cam.SetViewUp(0, 0, 1)

The swing effect is not visible that much when not using an axis cube, which may be the reason why the camera movement have been accepted as is up to now.

Thank you for puting on the good track :slight_smile:

Martin,

I ran into the same issue and used the same solution earlier.
Issue with constantly setting the up vector of the camera to 0,0,1 is that it results in strange movement when looking (nearly) top-down or bottom up.

In the end I wrote a whole interactor class in python: DAVE/vtkBlenderLikeInteractionStyle.py at bf2acc90d707dd07a82747eb097537bbcfcaab68 · RubendeBruin/DAVE · GitHub

I think it includes the camera-behavior you’re looking for.

1 Like

Thank you Ruben!

I did not know one can override a native vtk class in Python, this is a very good news. I’ll see if I can do the same in Java.

I tried your example which starts without problem. Only one thing to suggest : the middle click that you attached to camera rotation does not exist on macOS trackpad (although one can install software to map specific gestures to the middle click event).

Hi @rdbrn ,

Would you be interested in putting that interactor in VTK ? It would need to be reimplemented in C++ though.

I think trackpads usually come without a middle button. In the interactor you can use “m” or “space” as replacement for the middle-mouse button

hi @mwestphal , would love to. I’m currently on a vessel (work) but when I’m back home I’ll do I c++ implementation and MR.

Are you talking about the whole interactor or just the camera rotation behavior?

Creating just an actor with the camera control behavior would be just as easy as deriving from trackballinteractor and overriding the camera rotation, I could definitely do that.

If we would be aiming for all of the functionality (zoom, select, measure, etc) I will need some guidance on how to efficiently implement it. The interactor in python is basically an uber-interactor with bits and pieces grabbed and copied from all the other interactors. So implementing it in c++ would quickly turn into a copy-paste nightmare or struggling with multiple inheritance (which I’m not too familiar with in c++).

The more the better I’d say :slight_smile: I’ll be happy to help.