将 Qt3DWindow 的视图渲染为图像

问题描述 投票:0回答:1

我在 QWidget 容器内有一个 Qt3DWindow,并添加了一个 QSphere(以及材质、照明、相机)。当我启动它并且我可以看到球体时,这一切都很好。我现在想“捕获”/“渲染”此视图并将其保存为图像。我花了一整天的时间试图弄清楚如何完成这个看似非常简单的任务,但到目前为止一切都失败了。 我尝试过一些常见AI工具推荐的QRenderCapture()、grab()和QOffscreenSurface(),但没有效果。 这是窗口和查看器的工作代码。

import sys
from PyQt6.QtWidgets import QApplication, QHBoxLayout, QWidget, QPushButton, 
from PyQt6.QtWidgets import QMainWindow, QWidget
from PyQt6.QtGui import QIcon, QPixmap, QPainter, QImage, QMatrix4x4, QQuaternion, QVector3D, QColor, QGuiApplication, QPageLayout
from PyQt6.QtCore import QTimer
from PyQt6.Qt3DCore import QEntity, QTransform
from PyQt6 import Qt3DRender
from PyQt6.Qt3DExtras import QForwardRenderer, QPhongMaterial, Qt3DWindow, QOrbitCameraController, QDiffuseSpecularMaterial, QTextureMaterial, QNormalDiffuseMapMaterial, QDiffuseMapMaterial 
from PyQt6.Qt3DExtras import QSphereMesh
from PyQt6.Qt3DRender import QRenderCapture, QRenderCaptureReply
from PyQt6.QtCore import QTimer

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.view = Qt3DWindow()
        self.container = QWidget.createWindowContainer(self.view)
        self.setCentralWidget(self.container)

        # Create & set layouts
        main_layout = QHBoxLayout()
        main_layout.addWidget(self.container)
        
        main_widget = QWidget()
        main_widget.setLayout(main_layout)
        self.setCentralWidget(main_widget)
       
        # Root entity
        self.rootEntity = QEntity()

        # Load mesh
        sphere_mesh = QSphereMesh()
        sphere_mesh.setRadius(20)

        mesh_entity = QEntity(self.rootEntity)
        mesh_entity.addComponent(sphere_mesh)
        
        # Load/create textures
        diffuse_material = QPhongMaterial(self.rootEntity)
        diffuse_material.setDiffuse(QColor.fromRgbF(0.1, 0.9, 0.7, 0.6))
        mesh_entity.addComponent(diffuse_material)

        # Add material components to entity
        mesh_entity.addComponent(diffuse_material)

        # Camera
        self.camera = self.view.camera()
        self.camera.lens().setPerspectiveProjection(60.0, 16.0 / 9.0, 1, 1000.0)
        self.camera.setPosition(QVector3D(0.0, 0, 120.0))
        self.camera.setViewCenter(QVector3D(0.0, 0.0, 0.0))
        
        # camera controls
        self.camController = QOrbitCameraController(self.rootEntity)
        self.camController.setLinearSpeed(200.0)
        self.camController.setLookSpeed(280.0)
        self.camController.setCamera(self.camera)
        
        # Light
        light_entity = QEntity(self.rootEntity)
        light = Qt3DRender.QPointLight(light_entity)
        light.setConstantAttenuation(0)
        light_entity.addComponent(light)
        light_transform = QTransform()
        light_transform.setTranslation(QVector3D(350, 100, 200))
        light_entity.addComponent(light_transform)
        
        self.view.setRootEntity(self.rootEntity)

        self.capture_btn = QPushButton('Capture', self)
        self.capture_btn.clicked.connect(self.capture_image)
        main_layout.addWidget(self.capture_btn)

    def capture_image(self):
        pass

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setGeometry(100, 100, 800, 600)
    window.setWindowTitle("3D Object Viewer")
    window.show()
    sys.exit(app.exec())
python render qt3d
1个回答
0
投票

解决了。 我设法让它工作。 技巧是将 FrameGraph 链接到 QRenderCapture 实例。这是添加到 init()

的代码
self.render_capture = QRenderCapture()
self.view.activeFrameGraph().setParent(self.render_capture)
self.view.setActiveFrameGraph(self.render_capture)

另一个问题是等待渲染完成。这是我的实现方式。

def capture_image(self):
   self.reply = self.render_capture.requestCapture()
   loop = QEventLoop()
   self.reply.completed.connect(loop.quit)
   QTimer.singleShot(200, loop.quit)  # Timeout after 1 second
   loop.exec()
        
   image = self.reply.image()
   image.save("capture_output.jpg", "JPG")

我简直不敢相信这个 Qt3D 库的文档记录如此之少......

© www.soinside.com 2019 - 2024. All rights reserved.