Update camera in trame vtkLocalView

Hi,

I have been trying back and forward but cannot figure out why this camera update in VtkLocalView does not work.
Any input would be appreciated, thanks!


from trame.app import get_server
from trame.ui.vuetify3 import SinglePageLayout
from trame.widgets import vtk as vtk_widgets
from trame.widgets import vuetify3 as vuetify

# VTK imports
from vtkmodules.vtkFiltersSources import vtkConeSource
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
)

# -----------------------------------------------------------------------------
# VTK setup
# -----------------------------------------------------------------------------

renderer = vtkRenderer()
renderWindow = vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindow.OffScreenRenderingOn()

renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)

cone_source = vtkConeSource()
mapper = vtkPolyDataMapper()
actor = vtkActor()
mapper.SetInputConnection(cone_source.GetOutputPort())
actor.SetMapper(mapper)
renderer.AddActor(actor)
renderer.ResetCamera()
renderWindow.Render()

# -----------------------------------------------------------------------------
# Trame setup
# -----------------------------------------------------------------------------

server = get_server(client_type="vue3")
state, ctrl = server.state, server.controller

# -----------------------------------------------------------------------------
# Callbacks
# -----------------------------------------------------------------------------


@ctrl.set("view_x")
def set_camera_view_x():
    camera = renderer.GetActiveCamera()
    camera.SetPosition(1, 0, 0)
    camera.SetFocalPoint(0, 0, 0)
    camera.SetViewUp(0, 0, 1)
    renderer.ResetCamera()
    renderer.ResetCameraClippingRange()
    renderer.UpdateLightsGeometryToFollowCamera()
    renderWindow.Render()
    ctrl.view_update()


@ctrl.set("view_y")
def set_camera_view_y():
    camera = renderer.GetActiveCamera()
    camera.SetPosition(0, 1, 0)
    camera.SetFocalPoint(0, 0, 0)
    camera.SetViewUp(0, 0, 1)
    renderer.ResetCamera()
    renderer.ResetCameraClippingRange()
    renderer.UpdateLightsGeometryToFollowCamera()
    renderWindow.Render()
    ctrl.view_update()


@ctrl.set("view_z")
def set_camera_view_z():
    camera = renderer.GetActiveCamera()
    camera.SetPosition(0, 0, 1)
    camera.SetFocalPoint(0, 0, 0)
    camera.SetViewUp(0, 1, 0)
    renderer.ResetCamera()
    renderer.ResetCameraClippingRange()
    renderer.UpdateLightsGeometryToFollowCamera()
    renderWindow.Render()
    ctrl.view_update()


# -----------------------------------------------------------------------------
# GUI
# -----------------------------------------------------------------------------

with SinglePageLayout(server) as layout:
    layout.title.set_text("VTK Cone Geometry - Camera Views")

    with layout.toolbar:
        vuetify.VSpacer()
        vuetify.VBtn("X View", click=ctrl.view_x)
        vuetify.VBtn("Y View", click=ctrl.view_y)
        vuetify.VBtn("Z View", click=ctrl.view_z)

    with layout.content:
        with vuetify.VContainer(
            fluid=True,
            classes="pa-0 fill-height",
        ):
            view = vtk_widgets.VtkLocalView(renderWindow)
            ctrl.view_update = view.update
            ctrl.view_reset_camera = view.reset_camera

#
# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------

if __name__ == "__main__":
    server.start()

I assume it has to do with the fact that the camera is updated server side, but the update is not pushed to the local renderer?

Not sure why it doesn’t work with VtkLocalView @Sebastien_Jourdain

For a quick and easy fix, you can replace VtkLocalView with LocalView

First install trame-vtklocal using pip:

pip install trame-vtklocal

Then, update relevant parts of your code:

from trame_vtklocal.widgets import vtklocal
...
...
view = vtklocal.LocalView(renderWindow) # instead of vtk_widgets.VtkLocalView

I tested this change in your code and the view buttons work.

The difference is that VtkLocalView uses VTK.js in the client. OTOH, trame_vtklocal.widgets.LocalView uses VTK C++ in the browser through webassembly tech.

Hi, thanks for the suggestion. I have been keeping an eye on WASM but am wondering whether it’s still under development or stable enough for production purposes. I would mostly use it for volume and mesh rendering.

mesh rendering should be stable. volume rendering not yet.

So local rendering (vtk.js and wasm) have special handling for camera. Meaning the camera is handle on the client side independently from the server. Which means when you update the scene you do not always want to push the server camera which can be out of sync with the client.

So we need to be explicit on when such push needs to happen.

For trame-vtk / vtk.js

You need to call widget.push_camera().
See code here

For trame-vtklocal / VTK.wasm

You need to call widget.update(push_camera=True).
See code here

Thanks Sebastien, that did the trick!