I am trying to perform continuous raycasting in pyside6. I mostly followed example with fixes from this question, but translated it to python.
My enviroment params: Windows 10, Python 3.11, PySide6 6.6.0.
For raycasting I tried both PySide6.Qt3DRender.Qt3DRender.QScreenRayCaster
and PySide6.Qt3DRender.Qt3DRender.QRayCaster
.
When connecting to the signal PySide6.Qt3DRender.Qt3DRender.QAbstractRayCaster.hitsChanged, I get message repeatedly printed to standard output by PySide itself:
TypeError: Can't call meta function because I have no idea how to handle Qt3DRender::QAbstractRayCaster::Hits
If I don't connect to the signal, nothing is printed.
The question is how to make signal PySide6.Qt3DRender.Qt3DRender.QAbstractRayCaster.hitsChanged
work as expected.
The minimal reproducible example as follows. There camera is pointed directly onto the sphere and ray is casted exactly from window center:
import sys
from PySide6.QtCore import Slot, QPoint
from PySide6.QtGui import QVector3D
from PySide6.Qt3DCore import (Qt3DCore)
from PySide6.Qt3DExtras import (Qt3DExtras)
from PySide6.Qt3DRender import Qt3DRender
from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout, QApplication, QSizePolicy
class Window(Qt3DExtras.Qt3DWindow):
def __init__(self):
super().__init__()
# Camera
self.camera().lens().setPerspectiveProjection(60, 16 / 9, 0.1, 1000)
self.camera().setPosition(QVector3D(0, 0, 1.5))
self.camera().setViewCenter(QVector3D(0, 0, 0))
# root
self.rootEntity = Qt3DCore.QEntity()
self.setRootEntity(self.rootEntity)
# Sphere
self.material = Qt3DExtras.QPhongMaterial(self.rootEntity)
self.sphereEntity = Qt3DCore.QEntity(self.rootEntity)
self.sphereMesh = Qt3DExtras.QSphereMesh()
self.sphereMesh.setRadius(1)
self.sphereTransform = Qt3DCore.QTransform()
self.sphereEntity.addComponent(self.sphereMesh)
self.sphereEntity.addComponent(self.sphereTransform)
self.sphereEntity.addComponent(self.material)
# camera controls
self.camController = Qt3DExtras.QFirstPersonCameraController(self.rootEntity)
self.camController.setLinearSpeed(5)
self.camController.setLookSpeed(120)
self.camController.setCamera(self.camera())
# ray casting
self.rays_caster = Qt3DRender.QScreenRayCaster()
Qt3DRender.QRayCaster
self.rays_caster.setPosition(QPoint(150, 150))
self.rays_caster.setEnabled(True)
self.rays_caster.setRunMode(Qt3DRender.QAbstractRayCaster.RunMode.Continuous)
self.rootEntity.addComponent(self.rays_caster)
self.rays_caster.hitsChanged.connect(self.hits_changed)
# configure picking
self.pickable_layer = Qt3DRender.QLayer(self.rootEntity)
self.pickable_layer.setRecursive(True)
self.rootEntity.addComponent(self.pickable_layer)
self.rays_caster.addLayer(self.pickable_layer)
def hits_changed(self, hits):
print(hits)
class MainWidget(QWidget):
def __init__(self) -> None:
super().__init__()
vbox = QVBoxLayout()
label = QLabel('Это окно для рендера')
vbox.addWidget(label)
self.view = Window()
widg = QWidget()
widg.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.MinimumExpanding)
self.view_wind = QWidget.createWindowContainer(self.view, parent=widg)
self.view_wind.setMinimumSize(300, 300)
vbox2 = QVBoxLayout()
vbox2.addWidget(self.view_wind)
widg.setLayout(vbox2)
vbox.addWidget(widg)
self.setLayout(vbox)
if __name__ == '__main__':
app = QApplication(sys.argv)
widg = MainWidget()
widg.show()
sys.exit(app.exec())