This post was written with AI assistance. But I’m still human
Hi,
I’m new to 3D Slicer and VTK. I am trying to build a “virtual window” effect using a custom stereo display that gives me real-time viewDistance and eyeSeparation.
My goal is to let the user interact normally with the 3D volume using standard mouse controls (rotate, pan, zoom). From my understanding, to achieve this “virtual window” effect while preserving standard mouse interactions, the physical screen coordinates must dynamically track the camera: the screen center should sit exactly at the camera position, and the EyePosition should be placed behind it (camera.GetPosition() - viewDist * dop).
However, as soon as camera.SetUseOffAxisProjection(True) is invoked, it feels like ViewUp is locked, and the user can no longer rotate the camera, only translate it. This leads to broken math on my side during mouse movements.
Here is how I’m updating the frustrum :
layoutManager = slicer.app.layoutManager()
threeDWidget = layoutManager.threeDWidget(0)
renderWindow = threeDWidget.threeDView().renderWindow()
renderer = renderWindow.GetRenderers().GetFirstRenderer()
camera = renderer.GetActiveCamera()
p = self.stereoParams
pixelPitch = p['pixelPitch'] # unit : meter
viewDist = p['viewDistance'] # Distance User to screen (m)
eyeSeparation = p['eyeSeparation'] # IPD (m)
viewportSizePx = renderWindow.GetSize()
if viewportSizePx[0] <= 0 or viewportSizePx[1] <= 0:
return # Window minimized or invalid
viewportWidth = viewportSizePx[0] * pixelPitch # viewport width (m)
viewportHeight = viewportSizePx[1] * pixelPitch # viewport height (m)
halfW = viewportWidth / 2.0
halfH = viewportHeight / 2.0
up = np.array(camera.GetViewUp())
dop = np.array(camera.GetDirectionOfProjection())
cam = np.array(camera.GetPosition())
right = np.cross(dop, up)
rMag = np.linalg.norm(right)
right /= rMag
bl = cam - halfW * right - halfH * up
br = cam + halfW * right - halfH * up
tr = cam + halfW * right + halfH * up
camera.SetUseOffAxisProjection(True)
camera.SetScreenBottomLeft(bl)
camera.SetScreenBottomRight(br)
camera.SetScreenTopRight(tr)
camera.SetEyePosition(camera.GetPosition()- viewDist * dop)
camera.SetEyeSeparation(eyeSeparation)
It seems that I’m not doing things right.
Is there any documentation or existing examples on implementing off-axis projection with dynamic screen coordinates within Slicer?
Thanks for any help!