Ray casting issues with PySide6 and Qt3D

50 views Asked by At

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())
0

There are 0 answers