Quaternion rotation of polygon vertices (SLERP)

Started by
9 comments, last by alvaro 10 years, 3 months ago

I tried using a quaternion SLERP to update the vertices of a polygon and the problem I ran into is that as the polygon tries to rotate a full 360 it stretches along an axis, I think its the y-axis actually.

This is the polygon initially.

[attachment=19541:image2.png]

and this is what happens at about 45 degrees into the rotation (notice the polygon stretches towards the edge and actually escapes to the

corner).

[attachment=19540:image1.png]

I can post the code on pastebin if needed.

Here's an excerpt from the program, its the main call that updates the vertices which calls the SLERP function to interpolate 2 quaternions.


CVec3 RotatePoint( float t, CVec3 P1,
                  float angle_i, float angle_f,
                  int x1, int y1, int z1
                  , int x2, int y2, int z2)
{
    CQuat QRot;
    CQuat Q1( angle_i, CVec3( x1, y1, z1)); // Set by axis-angle
    CQuat Q2( angle_f, CVec3( x2, y2, z2));
    //QRot.Slerp( Q1, Q2, t, false);
    QRot.QuaternionSlerp( Q1, Q2, t);

    CMatrix M;
    QRot.ToMatrix( M.mf);
    return M*P1;
}
void calc_quaternion_verts( verts *c_verts, verts *s_verts,
                                    int vertices_count, float t,
                                    float angle_i, float angle_f,
                                    int x1, int y1, int z1,
                                    int x2, int y2, int z2)
{
        CVec3 P1;
        float new_x = 0.0f;
        float new_y = 0.0f;
        float new_z = 0.0f;
        float x_center = (float)SCREEN_X / 2.0f;
        float y_center = (float)SCREEN_Y / 2.0f;

        for( int i = 0; i < vertices_count; i++)
        {
            P1.x = c_verts[i].vx;
            P1.y = c_verts[i].vy;
            P1.z = c_verts[i].vz;

            //P1 = RotatePoint( t, P1, angle_i, angle_f, x1, 0.0f, 0.0f, x2, 0.0f, 0.0f);
            //P1 = RotatePoint( t, P1, angle_i, angle_f, 0.0f, y1, 0.0f, 0.0f, y2, 0.0f);
            //P1 = RotatePoint( t, P1, angle_i, angle_f, 0.0f, 0.0f, z1, 0.0f, 0.0f, z2);
            P1 = RotatePoint( t, P1, angle_i, angle_f, x1, y1, z1, x2, y2, z2);

            new_x = P1.x;
            new_y = P1.y;
            new_z = P1.z;

            s_verts[i].vx = new_x + x_center;
            s_verts[i].vy = new_y + y_center;
            s_verts[i].vz = new_z;
        }
}
Advertisement
I don't see anything wrong with the code at a first glance. But why are you using `int' for axis coordinates? And why are you using three different representations of rotations?

I don't see anything wrong with the code at a first glance. But why are you using `int' for axis coordinates? And why are you using three different representations of rotations?

I use 1 or -1 for all the axes coordinates. I'm not sure if I'm supposed to use 3 different representations for rotations, what line are you looking at?

Here's the whole code, compile and link with Allegro 5.

quaternion_rotation.cpp http://pastebin.com/rtjWb5hf

quat.h http://pastebin.com/34xeJ229

matrix.h http://pastebin.com/k8F47rup

vec3.h http://pastebin.com/VXjxStL8

I use 1 or -1 for all the axes coordinates.

Why limit yourself to coordinate axes? The same code works for arbitrary rotation axes.

I'm not sure if I'm supposed to use 3 different representations for rotations, what line are you looking at?

I was looking at the function `RotatePoint', which takes as input two rotations expressed in angle-axis form, it converts them to quaternions, interpolates between them, then converts them to a matrix, then finally applies the rotation to a point. I would use quaternions for everything, for simplicity.

Also, there is no point in using degrees for angles: Use radians everywhere. It's much too easy to make mistakes when there are too many representations available for the same thing.

I use 1 or -1 for all the axes coordinates.

Why limit yourself to coordinate axes? The same code works for arbitrary rotation axes.

I'm not sure if I'm supposed to use 3 different representations for rotations, what line are you looking at?

I was looking at the function `RotatePoint', which takes as input two rotations expressed in angle-axis form, it converts them to quaternions, interpolates between them, then converts them to a matrix, then finally applies the rotation to a point. I would use quaternions for everything, for simplicity.

Also, there is no point in using degrees for angles: Use radians everywhere. It's much too easy to make mistakes when there are too many representations available for the same thing.

I would use quaternions for everything although I'm not sure how I would do that. Right now I'm converting angles to quaternions (as you said) in:


CQuat Q1( angle_i, CVec3( x1, y1, z1)); // Set by axis-angle
    CQuat Q2( angle_f, CVec3( x2, y2, z2));

I suppose I could create a quaternion initially without this although I would have trouble understanding the quaternion orientation to begin with. Using degrees is easier to understand. I would like to maybe try radians but I'm not sure if the code has that, that would also be nothing more than converting from degrees to radians. How would I setup quaternions without radians or degrees by the way?

I use 1 or -1 for all the axes coordinates.

Why limit yourself to coordinate axes? The same code works for arbitrary rotation axes.

You're right, I was using 1's because those are unit vectors and they make the most sense when rotating along an axis, or at least that's what I thought.

Did you find anything wrong with the code though, like whether the polygon should stretch.

It took a while to install Allegro 5, cmake and figure out how to compile your program on Mac OS X, but I finally got it to work (or not work ;) ).

The problem is that your axes (x1, y1, z1) and (x2, y2, z2) are not normalized. By the way, since you have a type for vectors, why don't you use it, instead of passing three individual values? Similarly, a lot of your code that manipulates coordinates one by one could be written using vectors, and the code would be easier to read as a result.
Continuing on the theme of representing the same thing in too many ways, why do you need `verts' if you have `CVec3'? And why is `verts' plural? Why do you need the typedef `matrix' if you have `CMatrix'?

It took a while to install Allegro 5, cmake and figure out how to compile your program on Mac OS X, but I finally got it to work (or not work ;) ).

The problem is that your axes (x1, y1, z1) and (x2, y2, z2) are not normalized. By the way, since you have a type for vectors, why don't you use it, instead of passing three individual values? Similarly, a lot of your code that manipulates coordinates one by one could be written using vectors, and the code would be easier to read as a result.

Congrats on running it. Anyways normalizing (x1,y1,z1) and (x2,y2,z2) for 1 or -1 would still be 1 or -1 no? To normalize I would need to make it a unit vector by dividing using the norm, I guess that would be root 3 then?

You're right about passing values, and about cvec and verts, this code was essentially pieced together from two different sources on the internet and I tried to make it work using the "least programming work needed as possible" theorem, sorry! Thanks for helping so far though, how do I normalize though?

You can pass the rotation axes as one CVec3 each, instead of three ints each. You can then normalize them using the method CVec3::Normalize that is already in your code.

You can pass the rotation axes as one CVec3 each, instead of three ints each. You can then normalize them using the method CVec3::Normalize that is already in your code.

I'm guessing I would normalize a CVec3 type before doing this then right?


CQuat Q1( angle_i, CVec3( x1, y1, z1)); // Set by axis-angle
    CQuat Q2( angle_f, CVec3( x2, y2, z2));

Thanks for your help so far!

This topic is closed to new replies.

Advertisement