help with basic vector motion and rotation

Started by
6 comments, last by Inf_229 14 years ago
Hi all. There's something not right with the way I'm doing rotations with OpenGL. I'm trying to make a little buggy drive around some terrain. I'm fine with getting the terrain height but looks like I'm just not understanding something with rotations. Help, anybody. Please :) My approach is something like:


class vec3f
{
    ...
    public:
    float x, y, z;
    void Normalize();  //norm to 1
    void RotateBy(float fltAngle, float _x, float _y, float _z); //rot by an arbitrary axis
};

class Buggy
{
    ...
    public:
    vec3f position;
    vec3f heading;
    float velocity;
    void Draw() 
    {
        glPushMatrix();
        glTranslatef(position.x, position.y, position.z);
        glRotatef(heading.x, 0, 1, 0);
        glRotatef(heading.y, 1, 0, 0);
        glRotatef(heading.z, 0, 0, 1);

        //draw the object
        ...

        glPopMatrix();
     }

     void UpdatePosition()
     {
         if (velocity > GROUND_FRICTION)
         {
            velocity-=GROUND_FRICTION;    //Slow the buggy with friction
         }

         //Now update its position
         heading.Normalize();
         position += heading * velocity;

         //And find position.y using interpolated heightmap data...
         //this bit works.  trust me.
         ...
     }


};

//And in the keyboard callback
...
//hit some key to make it turn
TheBuggy->heading.RotateBy(amount, 0, 1, 0);  //rotate around the y axis




Am I missing steps somewhere, or does it look like the problem might be in my vec3f.RotateBy() func?
Advertisement
I don't know what your RotateBy() function does, but yeah, that looks wrong. It looks like in one place you're interpreting your 'heading' vector as a set of three Euler angles, but in another place you're interpreting it as a direction vector, which doesn't really make any sense.
I'm using it as both a heading and direction because I'm only using a single float for velocity, which moves the object in whatever direction it's currently facing. I'm now switching this to a vec3f.

My RotateBy() is based on a tutorial I found at Rotation About an Arbitrary Axis , and looks something like:

void vec::RotateBy(float fltAngle, float fltX, float fltY, float fltZ){float theta = fltAngle * PI/180.0f;/* Multiply this vector { this.x, this.y, this.z, 1.0f }bytX^2+c    tXY+sZ  tXZ-sY  0tXY-sZ    tY^2+c  tYZ+sX  0tXY+sY    tYZ-sX  tZ^2+c  00         0       0       1where XYZ are fltX, fltY, fltZ - the axis to rotate about*///Calculate the perpendicular component: multiply this by the cosine of the rotation anglevec vecPerp = vec( this->x, this->y, this->z) * cos(theta);//Calculate the cross-product between the rotation axis and this vector//vec operator*(vec other) has been overloaded to cross product.vec vecCross = vec(fltX, fltY, fltZ)*vecPerp;//Add the two togethervec r = vecPerp + vecCross;//Add the component of the vector we're about to rotate that is parallel to the rotation vector//TODO - unsure about this step.float c = cos(theta);float s = sin(theta);float t = 1.0f-cos(theta);//for readability's sake.float X2 = fltX * fltX;float Y2 = fltY * fltY;float Z2 = fltZ * fltZ;float XY = fltX*fltY;float XZ = fltX*fltZ;float YZ = fltY*fltZ;vec rot;rot.x =  (r.x * (t*X2)+c)+(r.y * (t*XY ) + s*fltZ )+(r.z * (t*XZ) - s*fltY);rot.y = (r.x * (t*XY)-s*fltZ)+(r.y * (t*Y2)+c)+(r.z * (t*YZ) + s*fltX);rot.z = (r.x * (t*XY)+s*fltY)+(r.y * (t*YZ) - s*fltX )+(r.z * (t*Z2) + c);//All done, now apply the rotation to this.this->x = rot.x;this->y = rot.y;this->z = rot.z;}


I'm also not sure about the last step I should do before I multiply my heading vector by the matrix. All I have to go on is

Quote:Add the component of the vector you are trying to rotate that is parallel to the vector you are rotating about

But as all I'm trying is to rotate about the Y axis, I don't think it should matter yet?

[Edited by - Inf_229 on May 2, 2010 2:13:53 AM]
What is your code doing or not doing that you want it to do / not do?

Just as a stab in the dark, have you tried swapping the order of when you perform the rotation/translation operations?

for example, change this:
        glTranslatef(position.x, position.y, position.z);        glRotatef(heading.x, 0, 1, 0);        glRotatef(heading.y, 1, 0, 0);        glRotatef(heading.z, 0, 0, 1);

to this:
        glRotatef(heading.x, 0, 1, 0);        glRotatef(heading.y, 1, 0, 0);        glRotatef(heading.z, 0, 0, 1);        glTranslatef(position.x, position.y, position.z);

--- "A penny saved never boils."
Yes, I've tried swapping the order around, but no luck. Anyway, I got it banged into my head fairly well that you should always translate and then rotate your objects.

What my code is (not) doing:

If I initialise my Buggy with an orientation of {0.0, 0.0, 1.0}, and call orientation.RotateBy(1.0f, 0.0f, 1.0f, 0.0f) - that is "one degree rotation about the y-axis", orientation ends up as {0.982395, 1.0, 1.0173}.

On subsequent calls this value sticks - further 1 degree rotations on the same orientation vector give the same result. And clearly {0.982395, 1.0, 1.0173} is not one degree from {0, 0, 1}.

ring any bells?
Quote:Original post by Inf_229
I'm using it as both a heading and direction because I'm only using a single float for velocity, which moves the object in whatever direction it's currently facing. I'm now switching this to a vec3f.
So does that mean you're no longer using the 'heading' vector as a 'direction' vector? Maybe you could post your new code so we can see what you're doing currently.

In any case, using the heading vector as a direction vector as in your previous code is incorrect. Also, using a float for your velocity vector is incorrect (in anything but a 1-d game, velocity should be a vector).
Quote:Original post by Whatz
Just as a stab in the dark, have you tried swapping the order of when you perform the rotation/translation operations?

for example, change this:
        glTranslatef(position.x, position.y, position.z);        glRotatef(heading.x, 0, 1, 0);        glRotatef(heading.y, 1, 0, 0);        glRotatef(heading.z, 0, 0, 1);

to this:
        glRotatef(heading.x, 0, 1, 0);        glRotatef(heading.y, 1, 0, 0);        glRotatef(heading.z, 0, 0, 1);        glTranslatef(position.x, position.y, position.z);
That part of the code is almost certainly correct as is, and should not be changed.
Quote:Original post by Inf_229
Yes, I've tried swapping the order around, but no luck. Anyway, I got it banged into my head fairly well that you should always translate and then rotate your objects.
To be a little more accurate, you generally want to rotate first, then translate. However, because of the way the OpenGL API works, when using OpenGL convenience functions such as glTranslate() and glRotate(), the order in which the transforms appear in your code will be translate->rotate.
Quote:Original post by Inf_229
Yes, I've tried swapping the order around, but no luck. Anyway, I got it banged into my head fairly well that you should always translate and then rotate your objects.

What my code is (not) doing:

If I initialise my Buggy with an orientation of {0.0, 0.0, 1.0}, and call orientation.RotateBy(1.0f, 0.0f, 1.0f, 0.0f) - that is "one degree rotation about the y-axis", orientation ends up as {0.982395, 1.0, 1.0173}.

On subsequent calls this value sticks - further 1 degree rotations on the same orientation vector give the same result. And clearly {0.982395, 1.0, 1.0173} is not one degree from {0, 0, 1}.

ring any bells?


Dang - I guess I don't know the math well enough to help, but I have another suggestion. I like to simulate problem code on paper first, then step through with a debugger and match my expected values to the actual values for every step.
--- "A penny saved never boils."
Hrm. Well right now I'm not bothering with velocity and position updates at all until I'm happy the rotation is working OK. I need to do more reading before I tackle this again, I think. Wish me luck :)

This topic is closed to new replies.

Advertisement