0

I'm trying do some 3D animation in GraphicsScene, for example, to rotate pictures in GraphicsScene (using class, subclassed from qPixmapItem and QObject, if it matters) with Animation framework.

Everything works fine, until i want to rotate pictures around vertical axis. There is no way doing so via item.rotate(), so i'm using QTranform.

The problem is that doing so does not animate anything at all. What am i doing wrong?

P.S. I do not want use OpenGl for this.

Here is the way i'm doing it. This way works for animating simpler properties like pos, rotation(via rotation, setRotation)

My code :

// hybrid graphicsSceneItem, supporting animation 
class ScenePixmap : public QObject, public QGraphicsPixmapItem
{
    Q_OBJECT
    Q_PROPERTY(QTransform transform READ transform WRITE setTransform)
public:
    ScenePixmap(const QPixmap &pixmap, QObject* parent = NULL, QGraphicsItem* parentItem = NULL):
        QObject(parent),
        QGraphicsPixmapItem(pixmap, parentItem)

    {}
};

Here is how I setup scene and animation:

//setup scene
//Unrelated stuff, loading pictures, etc.
            scene = new QGraphicsScene(this);
        foreach(const QPixmap& image, images)
        {
            ScenePixmap* item = new ScenePixmap(image);
            item->moveBy(70*i, 0);
            i++;
            this->images.append(item);
            scene->addItem(item);
        }
    }

    ui->graphicsView->setBackgroundBrush(QBrush(Qt::black, Qt::SolidPattern));
    ui->graphicsView->setScene(scene);

    //setup animation
QTransform getTransform()
{
    QTransform transform;
    transform.rotate(-30, Qt::ZAxis);//also tried transform = transform.rotate(...)

    return transform;
}

QAbstractAnimation* SetupRotationAnimation(ScenePixmap* pixmapItem)
{
    QPropertyAnimation* animation = new QPropertyAnimation(pixmapItem, "transform");
    animation->setDuration(1400);
    animation->setStartValue( pixmapItem->transform());
    animation->setEndValue(getTransform());//here i tried to multiply with default transform , this does not work either
    return animation;
}

here is the way i start animation:

void MainWindow::keyPressEvent ( QKeyEvent * event )
{

    if((event->modifiers() & Qt::ControlModifier))
    {
        QAnimationGroup* groupAnimation = new QParallelAnimationGroup();


        foreach(ScenePixmap* image, images)
        {
            groupAnimation->addAnimation( SetupRotationAnimation(image));

        }

        groupAnimation->start(QAbstractAnimation::DeleteWhenStopped);

    }
}

EDIT[Solved] thx to Darko Maksimovic:

Here is the code that worked out for me:

QGraphicsRotation* getGraphicRotation()
{
    QGraphicsRotation* transform = new QGraphicsRotation(this);

    transform->setAxis(Qt::YAxis);

    return transform;
}

QAbstractAnimation* SetupRotationAnimation(ScenePixmap* pixmapItem)
{
    QGraphicsRotation* rotation = getGraphicRotation();

    QPropertyAnimation* animation = new QPropertyAnimation(rotation, "angle");
    animation->setDuration(1400);
    animation->setStartValue( 0);
    animation->setEndValue(45);

    pixmapItem->setTransformOriginPoint(pixmapItem->boundingRect().center());

    QList<QGraphicsTransform*> transfromations = pixmapItem->transformations();
    transfromations.append(rotation);
    pixmapItem->setTransformations(transfromations);

    return animation;
}
undefined
  • 1,354
  • 1
  • 8
  • 19
  • Where are you calling `SetupRotationAnimation`? – Stefan Majewsky May 14 '12 at 11:24
  • You know, I _honestly_ can't decide whether "`transfromations`" is a clever pun (for the list of existing **transformations** you're loading **from** the pixmap)... or just the same typo repeated three times. – FeRD Mar 20 '20 at 22:09

2 Answers2

2

I see you use QTransform. If you want only one rotation, and simple rotation that is, it is better that you use setRotation [don't forget about setTransformOriginPoint].

If you, however, want to remember many rotations, around different transform points for example, then you should use QGraphicsTransform, i.e. its specialised derived class, QGraphicsRotation, which you apply by calling setTransformations on a graphics object (you should first fetch the existing transformations by calling o.transformations(), append to this, then call setTransformations; if you keep the pointer to the added transformation you can also change it later directly).

From the code you posted I can't see where your error is coming from, but by using specialised functions you can avoid some of frequent problems.

P.S. I also see you didn't use prepareGeometryChange in the code you posted, so please be advised that this is necessary when transforming objects.

Darko Maksimovic
  • 1,155
  • 12
  • 14
0

The problem is very simple. QVariantAnimation and QPropertyAnimation don't support QTransform. Heck, they don't even support unsigned integers at the moment. That's all there's to it. Per Qt documentation:

If you need to interpolate other variant types, including custom types, you have to implement interpolation for these yourself. To do this, you can register an interpolator function for a given type. This function takes 3 parameters: the start value, the end value and the current progress.

It'd might not be all that trivial to generate such an interpolator. Remember that you have to "blend" between two matrices, while maintaining the orthonormality of the matrix, and the visual effect. You'd need to decompose the matrix into separate rotation-along-axis, scaling, skew, etc. sub-matrices, and then interpolate each of them separately. No wonder the Qt folks didn't do it. It's probably much easier to do the inverse problem: generate the needed transformation matrix as a function of some parameter t, by composing the necessary rotations, translations, etc., all given as (perhaps constant) functions of t.

Just because a QVariant can carry a type doesn't mean it's supported by the default interpolator. There probably should be a runtime warning issued to this effect.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313