【问题标题】:QT Rotating object problemsQT 旋转物体问题
【发布时间】:2021-07-14 00:02:40
【问题描述】:

我目前正在做一个有旋转物体的项目。对象的旋转速度发生变化,其旋转方向也发生变化(向前/向后)。在做了一些研究之后,我在QT documentation 上遇到了RotationAnimator,它似乎拥有我需要的一切,我可以轻松地反转方向。唯一的问题是在 QML 中。我的程序完全是 Qt 的 C++。

我尝试过使用QVariantAnimation(文档here),但我尝试过的每一种方法总是有一些问题。更改速度相对容易,只需fooAnimation->setLoop(-1)(无限循环)并更改动画的持续时间。我遇到的问题是向前和向后循环。或者换句话说,改变方向。我尝试使用fooAnimation->setDirection(<Direction goes here>) 更改动画的方向,但是如果我反向运行动画足够长的时间,它将完全停止动画。它只会向前循环。这是问题的关键部分。

所以我尝试了其他方法来改变方向。一个想法是在我想反转时使用fooAnimation->setEndValue(<value goes here>)endValue 从360 度更改为-360,但这会产生不利影响。如果我要交换方向,当前的旋转:假设它是 110,将被反转。所以现在它突然跳到 -110 并从那里开始。这会导致非常抖动的旋转,因为每次发生方向交换时,它都会传送对象的旋转。

这似乎是一件很容易实现的事情,旋转一个可以改变其旋转速度和方向的对象,但我就是不知道如何用动画来实现它。

这里需要注意的是,所有这些都是在 Qt 3D 中完成的,因此我可以从旋转对象(或者在本例中为 QTransform)获取旋转和其他属性

【问题讨论】:

    标签: c++ qt qt3d


    【解决方案1】:

    有多种方法可以实现此效果。在这个 Qt/QML 演示中,我使用了一种基于 NumberAnimation 的方法来旋转立方体。

    这些是它背后的关键思想:

    • 立方体有一个Transform 组件,它定义了Qt3D 用来使用预定义的旋转和缩放值将立方体放置在世界中的4x4 矩阵。 NumberAnimation 只是改变了这个变换使用的旋转角度,使立方体在屏幕上旋转;
    • 旋转速度由NumberAnimationduration 属性定义:值越小,立方体旋转得越快。立方体从 0 度旋转到 360 度需要 5 秒;
    • 更改旋转速度意味着根据当前旋转角度距 0 度的距离重新计算动画的duration。每当我们更改任何NumberAnimation 属性时,动画都需要重新启动;
    • 当旋转方向改变时,我们将当前的旋转角度存储在cubeTransform.startAngle中,并更新NumberAnimationtofrom属性以及duration,这样立方体就可以在一个从当前角度开始的新方向。

    我在 UI 中添加了几个按钮来改变运行时的方向和速度:

    ma​​in.qml

    import QtQuick 2.12 as QQ2
    import QtQuick.Controls 2.12
    import QtQuick.Scene3D 2.12
    
    import Qt3D.Core 2.0
    import Qt3D.Render 2.0
    import Qt3D.Input 2.0
    import Qt3D.Extras 2.0
    import Qt3D.Logic 2.0
    
    QQ2.Item {
        id: windowId
        width: 800
        height: 800
    
        property real cubeScale: 100.0
        property int rotationSpeed: 5000
        property real speedFactor: 1.0
        property bool clockwiseRotation: true
    
        Scene3D {
            id: scene3D
            anchors.fill: parent
            aspects: ["input", "logic"]
            focus: true
            cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
    
            Entity {
                id: rootEntity
    
                Camera {
                    id: camera
                    projectionType: CameraLens.PerspectiveProjection
                    fieldOfView: 45
                    nearPlane : 0.1
                    farPlane : 100000.0
                    position: Qt.vector3d(0.0, 0.0, 500.0)
                    viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
                    upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
                }
    
                components: [
                    RenderSettings {
                        activeFrameGraph: ForwardRenderer {
                            camera: camera
                            clearColor: "silver"
                        }
                    },
                    InputSettings { }
                ]
    
                Entity {
                    id: lightEntity
                    enabled: true
    
                    DirectionalLight {
                        id: infiniteLight
                        color: "white"
                        intensity: 1.0
                        worldDirection: Qt.vector3d(0, 0, 0)
                    }
    
                    Transform {
                        id: infiniteLightTransform
                        translation: Qt.vector3d(0.0, 0.0, 500.0)
                    }
    
                    components: [ infiniteLight, infiniteLightTransform ]
                }
    
                Entity {
                    id: cubeEntity
    
                    CuboidMesh {
                        id: cubeMesh
                    }
    
                    PhongMaterial {
                        id: cubeMaterial
                        ambient: "red"
                        diffuse: Qt.rgba(1.0, 1.0, 1.0, 1.0)
                    }
    
                    Transform {
                        id: cubeTransform
    
                        property real angle: 0.0
                        property real startAngle: 0.0
    
                        matrix: {
                            var m = Qt.matrix4x4();
                            m.rotate(cubeTransform.angle, Qt.vector3d(0, 1, 0));
                            m.translate(Qt.vector3d(0, 0, 0));
                            m.scale(windowId.cubeScale, windowId.cubeScale, windowId.cubeScale);
                            return m;
                        }
                    }
    
                    components: [ cubeMesh, cubeMaterial, cubeTransform ]
                }
    
                QQ2.NumberAnimation {
                    id: cubeAnimation
    
                    property int startPos: {
                        if (cubeTransform.startAngle === 0)
                        {
                            if (windowId.clockwiseRotation === true)
                                return 0;
    
                            return 360;
                        }
    
                        return cubeTransform.startAngle;
                    }
    
                    property int endPos: (windowId.clockwiseRotation === true) ? 360 : 0
    
                    target: cubeTransform
                    property: "angle"
                    duration: windowId.rotationSpeed / windowId.speedFactor
                    from: cubeAnimation.startPos
                    to: cubeAnimation.endPos
                    loops: 1
                    running: true
    
                    onStarted: {
                        console.log("onStarted");
                    }
    
                    onFinished: {
                        console.log("onFinished");
                        // reset the starting angle
                        cubeTransform.startAngle = 0;
    
                        // reset the duration of the animation
                        cubeAnimation.duration = windowId.rotationSpeed / windowId.speedFactor;
    
                        // the animation is currently stopped, run it again
                        cubeAnimation.running = true;
                    }
                }
            }
        }
    
        QQ2.Row {
            anchors.fill: parent
    
            Button {
                text: "Change Direction"
    
                onClicked: {
                    // pause the animation
                    cubeAnimation.pause();
    
                    // invert rotation
                    windowId.clockwiseRotation = !windowId.clockwiseRotation;
    
                    // store current angle as the starting angle for the rotation
                    cubeTransform.startAngle = cubeTransform.angle;
    
                    // update the remaining time to avoid changing the rotation speed
                    let progressPercentage = cubeTransform.startAngle / 360.0;
                    if (windowId.clockwiseRotation)
                        progressPercentage = 1.0 - progressPercentage;
    
                    cubeAnimation.duration = (windowId.rotationSpeed / windowId.speedFactor) * progressPercentage;
    
                    // restart the animation from this angle using a new direction
                    cubeAnimation.restart();
                }
            }
    
            Button {
                text: "1x"
                highlighted: (windowId.speedFactor === 1.0)
    
                onClicked: changeSpeed(1.0)
            }
    
            Button {
                text: "2x"
                highlighted: (windowId.speedFactor === 2.0)
    
                onClicked: changeSpeed(2.0)
            }
        }
    
        function changeSpeed(newSpeed) {
            windowId.speedFactor = newSpeed;
    
            // pause the animation
            cubeAnimation.pause();
    
            // store current angle as the starting angle for the rotation
            cubeTransform.startAngle = cubeTransform.angle;
    
            // update the remaining time to avoid changing the rotation speed
            let progressPercentage = cubeTransform.startAngle / 360.0;
            if (windowId.clockwiseRotation)
                progressPercentage = 1.0 - progressPercentage;
    
            cubeAnimation.duration = (windowId.rotationSpeed / windowId.speedFactor) * progressPercentage;
    
            // restart the animation from this angle using a new direction
            cubeAnimation.restart();
        }
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-18
      • 2011-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多