Unable to make use of QBoundingVolume
-
I am learning the basics of PySide6 with the goal of creating a basic 3D model viewer. Now stuck on the challenge of calculating a bounding volume.
OS: Windows 10 Pro, 64-bit
IDE: PyCharm Community.
Python 3.8.10The QBoundingVolume instances I create always display the following behavior:
- "areImplicitPointsValid" is always set to False
- maxPoint and minPoint always start out set to (0, 0, 0).
- Explicitly setting maxPoint and minPoint does not change the behavior of my app.
For my test I have a line with five vertices. The current default camera perspective when loading the app is this:
My hope is to get a functional bounding volume so that the initial camera view will show the entirety of this five-point line. Like so:
Most likely my error lies in some fundamental misunderstanding of how PySide6 and its 3D modules work. Days of research have made me familiar with the official Qt wiki but the solution still is beyond me. Any help is deeply appreciated!
The code:
from PySide6.QtCore import QTimer, QByteArray, QObject from PySide6.QtGui import QVector3D, QColor, QAction, QKeySequence from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QHBoxLayout, QStatusBar, QFileDialog, QLabel) from PySide6.Qt3DCore import Qt3DCore from PySide6.Qt3DExtras import Qt3DExtras from PySide6.Qt3DRender import Qt3DRender import struct import os os.environ['QT3D_RENDERER'] = 'opengl' class MainWindow(QMainWindow): def __init__(self): super().__init__() horizontal_layout = QHBoxLayout() # Set up the 3D view self.view = Qt3DExtras.Qt3DWindow() self.view.defaultFrameGraph().setClearColor(QColor(230,230,230)) self.container = QWidget.createWindowContainer(self.view) self.container.setMinimumSize(300, 200) self.placeholder_label = QLabel("Placeholder Widget Label") self.placeholder_label.setMinimumSize(200, 200) widget = QWidget() horizontal_layout.addWidget(self.container) horizontal_layout.addWidget(self.placeholder_label) widget.setLayout(horizontal_layout) self.setCentralWidget(widget) open_mapid_action = QAction("&Open File", self) open_mapid_action.setStatusTip("Open mapid file and display the walkmesh") open_mapid_action.setShortcut(QKeySequence(0x04000000 + 0x4F)) #Ctrl+O open_mapid_action.triggered.connect(self.open_file_dialog) self.setStatusBar(QStatusBar(self)) menu = self.menuBar() file_menu = menu.addMenu("&File") file_menu.addAction(open_mapid_action) # Set up the 3D scene self.rootEntity = Qt3DCore.QEntity() # Create a 3D entity for the line self.line_entity = Qt3DCore.QEntity(self.rootEntity) line_geometry = Qt3DCore.QGeometry(self.line_entity) # Create a custom line geometry vertex_data = \ [QVector3D(-5.0, -5.0, 0.0), QVector3D(0.0, 0.0, 0.0), QVector3D(1.0, 0.0, 0.0), QVector3D(1.0, 1.0, 0.0), QVector3D(0.0, 5.0, 5.0),] vertex_byteArray = QByteArray() for vector in vertex_data: vertex_byteArray.append(struct.pack('fff', vector.x(), vector.y(), vector.z())) vertex_buffer = Qt3DCore.QBuffer(line_geometry) vertex_buffer.setData(vertex_byteArray) print(vertex_buffer.data()) # Create a QAttribute to store the vertex data vertex_attribute = Qt3DCore.QAttribute(line_geometry) vertex_attribute.setName(Qt3DCore.QAttribute.defaultPositionAttributeName()) vertex_attribute.setAttributeType(Qt3DCore.QAttribute.AttributeType.VertexAttribute) vertex_attribute.setVertexBaseType(Qt3DCore.QAttribute.VertexBaseType.Float) vertex_attribute.setBuffer(vertex_buffer) vertex_attribute.setVertexSize(3) # 3 components (X, Y, Z) per vertex vertex_attribute.setByteOffset(0) vertex_attribute.setByteStride(3 * 4) # 3 components * 4 bytes for float vertex_attribute.setCount(3) line_geometry.addAttribute(vertex_attribute) # Create a line material self.line_material = Qt3DExtras.QPhongMaterial(self.rootEntity) self.line_material.setAmbient(QColor(0,255,0)) # Create a line renderer self.line_renderer = Qt3DRender.QGeometryRenderer(self.rootEntity) self.line_renderer.setPrimitiveType(Qt3DRender.QGeometryRenderer.LineStrip) #See qt63drender_metatypes.json self.line_renderer.setGeometry(line_geometry) self.line_renderer.setVertexCount(len(vertex_data)) self.line_entity.addComponent(self.line_renderer) self.line_entity.addComponent(self.line_material) self.bounding_instance = Qt3DCore.QBoundingVolume(self.rootEntity) self.geometry_view_instance = Qt3DCore.QGeometryView(self.rootEntity) self.geometry_view_instance.setGeometry(line_geometry) self.bounding_instance.setView(self.geometry_view_instance) self.bounding_instance.setMaxPoint(QVector3D(5, 5, 5)) self.bounding_instance.setMinPoint(QVector3D(-5, -5, -5)) self.line_entity.addComponent(self.bounding_instance) # Set up camera self.camera_entity = self.view.camera() self.camera_entity.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 2000.0) self.camera_entity.setPosition(QVector3D(1, 1, 1)) self.camera_entity.setViewCenter(QVector3D(0, 0, 0)) #self.camera_entity.viewSphere(QVector3D(0, 0, 0), 5) # Set up orbit controller self.orbit_controller = Qt3DExtras.QOrbitCameraController(self.rootEntity) self.orbit_controller.setLinearSpeed(15.0) self.orbit_controller.setLookSpeed(500.0) self.orbit_controller.setCamera(self.camera_entity) self.view.setRootEntity(self.rootEntity) self.show() def open_file_dialog(self): # Open file dialog to select a file file, _ = QFileDialog.getOpenFileName(self, "Open File", "", "rfd files (*.rfd;*.raw);;All Files (*)") if file: print(f"Selected file: {file}") if __name__ == "__main__": app = QApplication([]) window = MainWindow() app.exec()