我在 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())
解决了。 我设法让它工作。 技巧是将 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 库的文档记录如此之少......