c++qtqt3d

Rotating a 3D object at a (fast) constant rate in QT


This seems like a pretty simple problem, but I have tried a implementation of what I think would work and it works "kind of".

What I expect: To be able to rotate an object about an axis at a constant rate that is rather fast. (Roughly around 120 *RPM or 2 *RPS.)

What I have tried: My basic implementation was a QTimer that would timeout (emit timeout signal as well) after a certain amount of milliseconds. The timeout would rotate the 3D object a set amount, like 0.1 degrees.

Sample code that could do the following would be something like this:

//Setup timer and 3d object (Q3DObject is just an example and may not even exist, doesn't matter)

QTimer *rotationTimer = new QTimer();
Q3DObject *object = new Q3DObject(...)

void main() 
{
    //Connect signal and slot
    connect(rotationTimer, SIGNAL(timeout()), this, SLOT(updateRotation()))
    rotationTimer->start(10); //Timeout every 10 ms
}

//This is a slot
void updateRotation()
{
    //Get current rotation from object then "add" a quaternion rotation about the -x axis of 0.1 degree.
    object->setRotation(object->rotation * QQuaternion::fromAxisAndAngle(-1.0f,0.0f,0.0f,0.1f));
}

Problem with this though implementation is that even with a timeout of 1ms, it is very slow, since its increasing it by 0.1 every 1ms. That would mean its MAX change in angle is 100 angle every 1s. This is far too slow. Changing the 0.1 degree increase to something bigger does help the speed, but at the performance of how smooth the transition from each increase, higher numbers result in a jittery looking rotation.

I feel that there is a far better way of achieving my goal here but I just cant think of anything. I also think this approach is not the most computationally efficient way of rotating an object either.

Does anyone know a better way of achieving this effect? I'll keep researching to see if I can find a better solution in the mean time.


Solution

  • It seems that what you want is to make an animation of the rotation so in that case it is better to use a QVariantAnimation, that class will interpolate the values between the ranges that are established so it is no longer necessary to define a minimum change (the 0.1 degrees that you use).

    Q3DFoo foo;
    
    QVariantAnimation animation;
    animation.setStartValue(QVariant(0.0));
    animation.setEndValue(QVariant(360.0));
    animation.setDuration(5 * 1000);
    animation.setLoopCount(-1);
    
    QObject::connect(&animation, &QVariantAnimation::valueChanged, &foo, [&foo](const QVariant & value){
        foo.setRotation(QQuaternion::fromAxisAndAngle(-1.0f, 0.0f, 0.0f, value.toFloat()));
    });
    
    animation.start():