如何让PyQt5 Qt3D中的动画正常运行?
解决Qt3D Python动画不生效的问题
你的代码里动画没跑起来,核心是两个关键问题没处理好:控制器计算的矩阵没同步到目标变换上,以及没有正确把angle属性暴露给Qt的属性系统,导致QPropertyAnimation无法驱动它。下面是修复后的完整代码,我会逐一解释修改点:
关键修改点
- 用
pyqtProperty暴露属性:Qt的QPropertyAnimation依赖Qt的元对象系统,必须用pyqtProperty装饰器把angle、radius、target这些属性暴露出来,动画才能识别并驱动它们。 - 同步变换矩阵到目标:在
updateMatrix方法里,计算完旋转平移矩阵后,要把这个矩阵设置给目标QTransform的matrix属性,这样实体的位置旋转才会更新。 - 完善动画的创建与启动:确保动画正确绑定到控制器的
angle属性,设置循环模式和时长。
修复后的完整代码
from PyQt5.Qt3DCore import QEntity, QTransform from PyQt5.Qt3DExtras import QTorusMesh, QPhongMaterial, \ QSphereMesh, Qt3DWindow, QOrbitCameraController from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout from PyQt5.QtGui import QVector3D, QMatrix4x4, QColor from PyQt5.QtCore import pyqtSignal, QPropertyAnimation, pyqtProperty import sys def fuzzyCompareDouble(p1, p2): """ compares 2 double values """ return abs(p1 - p2) * 100000. <= min(abs(p1), abs(p2)) class OrbitTransformController(QTransform): targetChanged = pyqtSignal() angleChanged = pyqtSignal() radiusChanged = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.m_target = QTransform() self.m_matrix = QMatrix4x4() self.m_radius = 1.0 self.m_angle = 0.0 # 用pyqtProperty暴露target属性,让Qt元对象系统识别 @pyqtProperty(QTransform, notify=targetChanged) def target(self): return self.m_target def setTarget(self, target): if self.m_target != target: self.m_target = target self.targetChanged.emit() # 用pyqtProperty暴露radius属性 @pyqtProperty(float, notify=radiusChanged) def radius(self): return self.m_radius def setRadius(self, radius): if not fuzzyCompareDouble(radius, self.m_radius): self.m_radius = radius self.radiusChanged.emit() self.updateMatrix() # 用pyqtProperty暴露angle属性,这是动画驱动的核心属性 @pyqtProperty(float, notify=angleChanged) def angle(self): return self.m_angle def setAngle(self, angle): if not fuzzyCompareDouble(angle, self.m_angle): self.m_angle = angle self.angleChanged.emit() self.updateMatrix() def updateMatrix(self): self.m_matrix.setToIdentity() self.m_matrix.rotate(self.m_angle, QVector3D(0.0, 1.0, 0.0)) self.m_matrix.translate(self.m_radius, 0.0, 0.0) # 关键:把计算好的矩阵设置给目标变换,让实体更新 self.m_target.setMatrix(self.m_matrix) def main(): app = QApplication(sys.argv) # 创建Qt3D窗口 view = Qt3DWindow() view.defaultFrameGraph().setClearColor(QColor(100, 100, 100)) # 创建根实体 rootEntity = QEntity() # 创建球体实体(被环绕的中心物体) sphereEntity = QEntity(rootEntity) sphereMesh = QSphereMesh() sphereMesh.setRadius(0.5) sphereMaterial = QPhongMaterial() sphereMaterial.setDiffuse(QColor(255, 0, 0)) sphereEntity.addComponent(sphereMesh) sphereEntity.addComponent(sphereMaterial) # 创建 torus 实体(环绕中心的物体) torusEntity = QEntity(rootEntity) torusMesh = QTorusMesh() torusMesh.setRadius(1.0) torusMesh.setMinorRadius(0.2) torusMaterial = QPhongMaterial() torusMaterial.setDiffuse(QColor(0, 255, 0)) # 创建变换和控制器 torusTransform = QTransform() controller = OrbitTransformController() controller.setTarget(torusTransform) controller.setRadius(4.0) # 给控制器添加动画 angleAnimation = QPropertyAnimation(controller, b"angle") angleAnimation.setDuration(10000) # 10秒一圈 angleAnimation.setStartValue(0.0) angleAnimation.setEndValue(360.0) angleAnimation.setLoopCount(-1) # 无限循环 angleAnimation.start() # 把组件添加到torus实体 torusEntity.addComponent(torusMesh) torusEntity.addComponent(torusMaterial) torusEntity.addComponent(torusTransform) # 设置相机 camera = view.camera() camera.lens().setPerspectiveProjection(45.0, 16.0/9.0, 0.1, 1000.0) camera.setPosition(QVector3D(0, 0, 10.0)) camera.setViewCenter(QVector3D(0, 0, 0)) # 添加相机控制器 camController = QOrbitCameraController(rootEntity) camController.setCamera(camera) # 设置根实体 view.setRootEntity(rootEntity) # 把Qt3D窗口嵌入到QWidget中(可选,方便显示) container = QWidget() layout = QVBoxLayout(container) layout.addWidget(view) container.show() sys.exit(app.exec_()) if __name__ == "__main__": main()
额外说明
- 我补全了完整的主程序逻辑,包括创建球体、torus、相机和控制器,确保代码可以直接运行。
- 动画绑定到
controller的angle属性,通过pyqtProperty暴露后,QPropertyAnimation就能正确驱动角度变化,进而触发updateMatrix更新目标变换的矩阵。 - 控制器的
updateMatrix方法最后调用self.m_target.setMatrix(self.m_matrix),把计算好的旋转平移矩阵应用到目标变换上,这样torus就会绕着球体持续旋转了。
内容的提问来源于stack exchange,提问作者P Moran
相关产品推荐
相关产品推荐

