0
\$\begingroup\$

I am doing frame based animation for 300 frames in opengl es 2.0

I want a rectangle to translate by +200 pixels in X axis and also scaled up by double (2 units) in the first 100 frames

Then, the animated rectangle has to stay there for the next 100 frames.

Then, I want the same animated rectangle to translate by +200 pixels in X axis and also scaled down by half (0.5 units) in the last 100 frames.

I am using simple linear interpolation to calculate the delta-animation value for each frame.

Pseudo code:

The below drawFrame() is executed for 300 times (300 frames) in a loop.

float RectMVMatrix[4][4] = {1, 0, 0, 0,
                            0, 1, 0, 0,
                            0, 0, 1, 0,
                            0, 0, 0, 1
                           };   // identity matrix
int totalframes = 300;
float translate-delta;  // interpolated translation value for each frame
float scale-delta;  // interpolated scale value for each frame

// The usual code for draw is:
void drawFrame(int iCurrentFrame)
{
 // mySetIdentity(RectMVMatrix); // comment this line to retain the animated position.
  mytranslate(RectMVMatrix, translate-delta, X_AXIS); // to translate the mv matrix in x axis by translate-delta value
  myscale(RectMVMatrix, scale-delta); // to scale the mv matrix  by scale-delta value
  ... // opengl calls 
  glDrawArrays(...);
  eglswapbuffers(...);
}

The above code will work fine for first 100 frames. in order to retain the animated rectangle during the frames 101 to 200, i removed the "mySetIdentity(RectMVMatrix);" in the above drawFrame().

Now on entering the drawFrame() for the 2nd frame, the RectMVMatrix will have the animated value of first frame

e.g. RectMVMatrix[4][4] = { 1.01, 0, 0, 2,
                            0,    1, 0, 0,
                            0,    0, 1, 0,
                            0,    0, 0, 1
                           };// 2 pixels translation and 1.01 units scaling after first frame

This RectMVMatrix is used for mytranslate() in 2nd frame. The translate function will affect the value of "RectMVMatrix[0][0]". Thus translation affects the scaling values also.

Eventually output is getting wrong.

How to retain the animated position without affecting the current ModelView matrix?


I got the solution... Thanks to Sergio.

I created separate matrices for translation and scaling. e.g.CurrentTranslateMatrix[4][4], CurrentScaleMatrix[4][4].

Then for every frame,

I reset 'CurrentTranslateMatrix' to identity and call mytranslate( CurrentTranslateMatrix, translate-delta, X_AXIS) function.

I reset 'CurrentScaleMatrix' to identity and call myscale(CurrentScaleMatrix, scale-delta) function.

Then, I multiplied these 'CurrentTranslateMatrix' and 'CurrentScaleMatrix' to get the final 'RectMVMatrix' Matrix for the frame.

Pseudo Code:

    float RectMVMatrix[4][4] = {0};
    float CurrentTranslateMatrix[4][4] = {0};
    float CurrentScaleMatrix[4][4] = {0};
    int iTotalFrames = 300;
    int iAnimationFrames = 100;

    int iTranslate_X = 200.0f; // in pixels
    float fScale_X = 2.0f;
    float scaleDelta;
    float translateDelta_X;
    void DrawRect(int iTotalFrames)
    {
        mySetIdentity(RectMVMatrix);
        for (int i = 0; i< iTotalFrames; i++)
        {
            DrawFrame(int iCurrentFrame);
        }
    }
    void getInterpolatedValue(int iStartFrame, int iEndFrame, int iTotalFrame, int iCurrentFrame, float *scaleDelta, float *translateDelta_X)
    {
        float fDelta = float ( (iCurrentFrame - iStartFrame) / (iEndFrame - iStartFrame))

        float fStartX = 0.0f;
        float fEndX = ConvertPixelsToOpenGLUnit(iTranslate_X);
        *translateDelta_X = fStartX + fDelta * (fEndX - fStartX);

        float fStartScaleX = 1.0f;
        float fEndScaleX   = fScale_X;
        *scaleDelta  = fStartScaleX + fDelta * (fEndScaleX - fStartScaleX);
    }

    void DrawFrame(int iCurrentFrame)
    {
        getInterpolatedValue(0, iAnimationFrames, iTotalFrames, iCurrentFrame, &scaleDelta, &translateDelta_X)
        mySetIdentity(CurrentTranslateMatrix);
        myTranslate(RectMVMatrix, translateDelta_X, X_AXIS); // to translate the mv matrix in x axis by translate-delta value
        mySetIdentity(CurrentScaleMatrix);
        myScale(RectMVMatrix, scaleDelta); // to scale the mv matrix  by scale-delta value
        myMultiplyMatrix(RectMVMatrix, CurrentTranslateMatrix, CurrentScaleMatrix);// RectMVMatrix = CurrentTranslateMatrix*CurrentScaleMatrix;
        ... // opengl calls 
        glDrawArrays(...);
        eglswapbuffers(...);
    }

I maintained this "RectMVMatrix" value, if there is no animation for the current frame (e.g. 101th frame onwards).

\$\endgroup\$
1
\$\begingroup\$

First, keep in mind that the order in which you apply the transformations is important. This is because matrix multiplication is not transitive: A*B != B*A

I'm guessing your intent is to scale the rectangle first, then translate it to the right position. If you do it the other way around the distance translated will be scaled as well, which is probably not what you want.

So let's say you have your transformation (X), as a multiplication of a translation (T) and a scale (S): X = T*S

If you combine them in the same way, after frame two you'll have: X = (T1*S1)*(T2*S2), which is why you're having problems.

What you need to do is group them like this: X = T2*(T1*S1)*S2 In this way, the translations accumulate on one side, the scales accumulate on the other side and the end result is what you'd expect.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.