QVTKRenderWindowInteractor PySide2 Resize Issue

I am trying to embed a QVTKRenderWindowInteractor in a QT app using PySide2 and VTK 9.0

I’ve done so successfully with PyQt5, but now with PySide2 the rendering area doesn’t update properly upon resizing.

Initial render and after resizing:

The sphere scales and translates to account for the new window size, but the actual rendering frame doesn’t update.

In a slightly more complex case I’ve tried capturing the resize event of the QVTKRenderWindowInteractor and injecting all kinds of update/render calls but to no avail.

Any ideas? I’m happy to provide more information a la vtk.vtkRenderWindow.ReportCapabilities or something similar.

A minimal (hopefully) reproducible example:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#import PyQt5
#from PyQt5.QtWidgets import QApplication

import PySide2
from PySide2.QtWidgets import QApplication

import vtk
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor

def add_sphere(ren):
    # Create source
    source = vtk.vtkSphereSource()
    source.SetCenter(0, 0, 0)
    source.SetRadius(5.0)
    # Create a mapper
    mapper = vtk.vtkPolyDataMapper()
    mapper.SetInputConnection(source.GetOutputPort())
    # Create an actor
    actor = vtk.vtkActor()
    actor.SetMapper(mapper)
    # Add actor
    ren.AddActor(actor)
    ren.ResetCamera()

app = QApplication([])

widget = QVTKRenderWindowInteractor()
ren = vtk.vtkRenderer()
widget.GetRenderWindow().AddRenderer(ren)

widget.show()
widget.Initialize()
widget.Start()

add_sphere(ren)
ren.SetBackground([1.0, 0.5, 0.5])

app.exec_()

Are you using a hi-dpi screen? By that I mean to ask if you configured the display with a scaling factor > 100% in the windows display settings.

Indeed I am. My main monitor is 4K with a scale factor of 150%.
I changed the scale to 100% but still have the same issue.
And the issue also persists on my secondary monitor that is always at 100%.

I know there are various QT environment variables to handle scaling and hi-dpi displays, perhaps I should investigate them anyway.

Can you try a more recent version of VTK? Try vtk 9.3.0. The X logo makes me think you’re running it throug WSL? VTK doesn’t really support such configurations, maybe WSL-gui thinks your display resolution is something else.

I’m not running through WSL. I’m running off a Linux server and using a Xserver to display on my local Windows client.

But indeed I’ll try with the latest VTK and let you know what happens. Thanks

Oh and I should add that this issue doesn’t exist when run directly on my Windows machine. Same versions of all packages.

Update: Same issue with VTK 9.2 and 9.3

I’ve discovered that the issue is actually independent of QT.
So using PyQt5 actually solves the issue.
Maybe the question is: What is PyQt5 doing differently from PySide2? Which I understand is not necessarily for this forum then.

This pure-VTK example has the exact same troublesome behavior:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import vtk

def add_sphere(ren):
    # Create source
    source = vtk.vtkSphereSource()
    source.SetCenter(0, 0, 0)
    source.SetRadius(5.0)
    # Create a mapper
    mapper = vtk.vtkPolyDataMapper()
    mapper.SetInputConnection(source.GetOutputPort())
    # Create an actor
    actor = vtk.vtkActor()
    actor.SetMapper(mapper)
    # Add actor
    ren.AddActor(actor)
    ren.ResetCamera()

ren = vtk.vtkRenderer()
renwin = vtk.vtkRenderWindow()
renwin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renwin)

add_sphere(ren)
ren.SetBackground([1.0, 0.5, 0.5])

iren.Initialize()
renwin.Render()
iren.Start()

After some experimenting I’ve found that in my actual project with a proper PySide2.QtWidgets.QMainWindow, if I override the resizeEvent method like this then the issue is resolved.

def resizeEvent(self, *args):
    picker = vtk.vtkPropPicker()
    picker.Pick(0, 0, 0, self.ren)

    super().resizeEvent(*args)

where self.ren is a reference to a vtk.vtkRenderer instance.

Any idea why the Pick method forces a proper redraw?
I looked through the source code for vtk.vtkPropPicker but didn’t see anything obvious.

Hmm that’s strange. The pick method eventually triggers a framebuffer capture to read pixels. I guess this had an effect of resizing the framebuffer to the actual size? It could be a bug in pyside2 that occurs in remote X sessions.