You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让PyQt5 Qt3D中的动画正常运行?

解决Qt3D Python动画不生效的问题

你的代码里动画没跑起来,核心是两个关键问题没处理好:控制器计算的矩阵没同步到目标变换上,以及没有正确把angle属性暴露给Qt的属性系统,导致QPropertyAnimation无法驱动它。下面是修复后的完整代码,我会逐一解释修改点:

关键修改点

  1. 用pyqtProperty暴露属性:Qt的QPropertyAnimation依赖Qt的元对象系统,必须用pyqtProperty装饰器把angle、radius、target这些属性暴露出来,动画才能识别并驱动它们。
  2. 同步变换矩阵到目标:在updateMatrix方法里,计算完旋转平移矩阵后,要把这个矩阵设置给目标QTransform的matrix属性,这样实体的位置旋转才会更新。
  3. 完善动画的创建与启动:确保动画正确绑定到控制器的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:24:25