Changing rotation order to permit rotation on all axis[SOLVE

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
robertgarand
Posts: 69
Joined: Fri Feb 22, 2008 6:47 pm
Location: montreal
Contact:

Changing rotation order to permit rotation on all axis[SOLVE

Post by robertgarand »

Hi all,
I have been trying to make a apollo like sim.
I realize that the order of rotation being x,y,z. All rotation made on the X axis get totally cancelled by a Y rotation at 90 or 270, rotation possibility increase toward 0 and 180.

Try to make a node rotate on X axis when there is a 90 rotation on Y.
You just can't have the slightest inclination on the X.
It's impossible :!:

That is if you want a certain facing direction from your object. like a car, a boat, a spaceship, a player, etc.
The only way is to keep the camera at its back or to rotate the whole world, can't work with huge map or world.

The workaround would be to modify the matrix routines, but I don't know the engine enough to be sure of the side effect.
I would spend the time if needed, it would be worthwhile. with new order (Y,X,Z) any rotation would be possible. Am I lost or right ?

Any comment, warning, or suggestion would be welcome.
Any helping hand (and neurons) would be welcome :)
[EDIT]
To make rotation possible in all direction using matrix, one must NOT try to call rotation routine with a final rotation, rotation must be made in increasing steps, and for the node's rotation to cross the 90 & 270 degrees border, one of X or Z axis rotation must be other then zero. I don't completly understand the reason, but it works. I'm using a variable to keep track of the actual node's rotation because if you log the rotation it gives the relative rotation in the order they're made to get the final rotation. here's my code (brief version, ask if you need complete)

Code: Select all

//Update of events action on rotation of vaissel
 irr::core::vector3df rolls(0.f,0.f,0.f);
 ...
switch (key)
{
...
///acitvate attitude controls
    case KEY_LEFT: {log_str.append(L"thrustinL",15);
    rolls.Z+=roll_speed;
    actual_rot.Z+=roll_speed;
    rotate(rolls,vaisseau);
    make_thrust(ps[1]);break;}
...other keys

//to make actual rotation on vaissel node
void vaissel::rotate(irr::core::vector3df &rotation, scene::ISceneNode * node)
{    irr::core::matrix4 m;
    m.setRotationDegrees(node->getRotation());
    irr::core::matrix4 n;
    n.setRotationDegrees(rotation);
    m *= n;
    node->setRotation( m.getRotationDegrees() );
    node->updateAbsolutePosition();
}
HUGE thanks goes to bitplane, my project still lives :D
[EDIT]
Regards,
Robert
Last edited by robertgarand on Wed Jan 14, 2009 12:16 am, edited 1 time in total.
If it can't be writen, it can't exist
Dark_Kilauea
Posts: 368
Joined: Tue Aug 21, 2007 1:43 am
Location: The Middle of Nowhere

Post by Dark_Kilauea »

You are suffering from what is called Gimbal Lock (look it up for details).

Using quaternions for your transformations is one way to fix this problem.
rogerborg wrote:Every time someone learns to use a debugger, an angel gets their wings.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Actually, just using quaternions won't eliminate it. You need to stop using Euler angles to do your rotation calculations. i.e., no setRotation()...
robertgarand
Posts: 69
Joined: Fri Feb 22, 2008 6:47 pm
Location: montreal
Contact:

already using quaternions...

Post by robertgarand »

Hi,
Dark, I'm already using quaternions, it don't eliminate this problem,
cos when the rotation have to be done in X, it is done first,
then Y rot is done, cancelling the X rotation.
Quaternions only prevents mix-up of axis passed the 90 deg.

Vitek, how else then setrotation can I change rotation of a node ?At the render pass,
Illricht will still use its routine to update absolute transformation, no?

Can you give me a clue to follow ?
Tia,
Regards,
Robert
If it can't be writen, it can't exist
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

The problem is that you're treating three separate rotations as a single unit, if you start rotating around Y, you can't just change the X value because it also now affects the other axes. At 90 degrees it even becomes another axis.
Use separate rotation matrices/quaternions for pitch, roll and yaw and you'll be okay.. I think.
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
robertgarand
Posts: 69
Joined: Fri Feb 22, 2008 6:47 pm
Location: montreal
Contact:

Maybe I use quaternion wrong way...

Post by robertgarand »

Hi bitplane,
This is the code I'm using, as you see, on key press, I increase/decrease the rotation around corresponding axis, then, rotate it of current_rotation degrees by quaternion, the result is always that at 90 or 270 Y rotation, I can not rotate around X axis. It would be solve if the order be Y,X then Z.

Does my rotate routine okay ?

Thanks a lot for taking a few minutes for me, I am at the point of
dropping the project, after many, many hours of search and tests.

regards,
Robert

Code: Select all

void vaissel::rotate(irr::core::vector3df &vector,irr::core::vector3df &around, irr::f32 rotation_angle)
{
    quaternion rotating_quaternion;
    matrix4 matrix;
    rotating_quaternion.fromAngleAxis(rotation_angle, around);
    rotating_quaternion.getMatrix(matrix);
    matrix.rotateVect(vector);

}


void vaissel::set_gage_color()
{
    ///color of fuel gage
        if(fuel > data_level[current_level].fuel_for_level*0.5f)//50% yellow
         { fuel_color = green_fuel;return;}
        if(fuel <data_level[current_level].fuel_for_level*0.2f)//20% red
         { fuel_color = red_fuel;return;}
        else { fuel_color = yellow_fuel;return;}
}

void vaissel::roll(irr::scene::ISceneNode* node , irr::core::vector3df to)
{}
///add current thrust power to velocity
void vaissel::thrusting(irr::EKEY_CODE key)
{
    irr::f32 lapse;
    irr::f32 nows;
    nows = timer->getTime();
    lapse = nows-last_time_key;
    irr::core::vector3df rotation;//,Z(0.f,0.f,1.f),X(1.f,0.f,0.f);
    irr::core::vector3df boost,rolls(0.f,0.f,0.f);
    if(lapse > 90) {lapse =20;}
    vector3df Z=(Device->getSceneManager()->getActiveCamera()->getTarget() - 
	Device->getSceneManager()->getActiveCamera()->getAbsolutePosition()).normalize();
    vector3df up =Device->getSceneManager()->getActiveCamera()->getUpVector();
    vector3df X =Z.crossProduct(up);
    rotation=vaisseau->getRotation();
    actual_rot=rotation.Y;
switch (key)
{


    case KEY_SPACE:{log_str.append(L"boosting",15);
        irr::core::matrix4 m,n;
        //rotate(rotation,up,(actual_rot)*DEGTORAD);
        boost.X -=(booster_thrust*lapse)*sinf ( core::DEGTORAD * rotation.Z);
        boost.Z +=(booster_thrust*lapse)*sinf ( core::DEGTORAD * rotation.X);
        boost.Y= (1-( abs(boost.X) + abs(boost.Z) ))*booster_thrust*lapse;
        //rotate(boost,up,actual_rot*DEGTORAD);
        velocity+=boost; fuel-=lapse /fuel_factor;make_booster();break;}
//change pitch and roll
    case KEY_LEFT: {log_str.append(L"thrustinL",15);
    rolls.Z+=roll_speed;
    rotation+=rolls;
    rotate(rotation,up, actual_rot*DEGTORAD);
    make_thrust(ps[1]);break;}

    case KEY_RIGHT:{log_str.append(L"thrustinR",15);
    rolls.Z-=roll_speed;
    rotation+=rolls;
    rotate(rotation,up, actual_rot*DEGTORAD);
    make_thrust(ps[3]);break;}

    case KEY_DOWN: {log_str.append(L"thrustinD",15);
    rolls.X-=roll_speed;
    rotation+=rolls;
    rotate(rotation,up, actual_rot*DEGTORAD);
    make_thrust(ps[2]);break;}

    case KEY_UP:   {log_str.append(L"thrustinU",15);
    rolls.X+=roll_speed;
    rotation+=rolls;
    rotate(rotation, up, rotation.Y*DEGTORAD);
    make_thrust(ps[0]);break;}
}
rotation.Y=actual_rot;
vaisseau->setRotation(rotation);
vaisseau->updateAbsolutePosition();
}

///update vaissel
void vaissel::update(irr::u32 now)
{   core::triangle3df triangle;
	core::line3d<f32> line;
	core::vector3df end(0,-500,0);
	core::vector3df start,up(0.f,1.f,0.f);
	core::vector3df movement,turn_amount,rotx,rotz,roty;
///for rotation
    irr::core::matrix4 m,n;
    irr::core::vector3df direction_y,rotation(0.f,0.f,0.f), this_rotation;
    rotation=vaisseau->getRotation();
    irr::f32 delta;
    irr::core::vector3df direction = velocity;
///update position
    u32 lapse = now - last_time;
    if (lapse > 90)
        {lapse=20;//did a pause
        }
    velocity+= data_level[current_level].gravityc*lapse;
    movement = velocity*lapse;
    move(vaisseau, movement);
    last_time = now;
///update  rotation
if(camera_is_orbit)
{   direction_y = velocity.getHorizontalAngle();
    delta = direction_y.Y-rotation.Y;
    if(delta > 179.f)
        delta -= 360.f;
    else if(delta < -179.f)
        delta += 360.f;
if(delta < -1.40f)
        {
        rotation.Y-=turn_speed*lapse;
        rotate(rotation,up, (-turn_speed*lapse)*DEGTORAD);
        }
if(delta > 1.40f)
        {
        //actual_rot+=turn_speed*lapse;
        rotation.Y+=turn_speed*lapse;
        rotate(rotation,up, (turn_speed*lapse)*DEGTORAD);
        }

if(rotation.Y<0)rotation.Y+=360;
if(rotation.Y>360)rotation.Y-=360;
actual_rot = rotation.Y;
vaisseau->setRotation(rotation);
vaisseau->updateAbsolutePosition();

}
};


void vaissel::update_camera(irr::scene::ICameraSceneNode *camera,//current cam
                irr::scene::ISceneNode *node,//the vaisseau position
                irr::core::vector3df offset)//offset from cam to vaisseau
{
    irr::core::vector3df direction = velocity;
    direction.Y=0;
    irr::core::vector3df rotation;
    rotation.Y = vaisseau->getRotation().Y;
    rotation.X = 0.f;
    rotation.Z = 0.f;
    //rotation.Y-= 180.f;
    //direction.Y = 0.0f;
    irr::core::matrix4 m;
///if cam is orbiting, get new pos & angle
    if(camera_is_orbit)   m.setRotationDegrees(rotation);
    irr::core::vector3df frv = irr::core::vector3df (0.0f, 0.0f, 1.0f);
    m.transformVect(frv);
    irr::core::vector3df upv = irr::core::vector3df (0.0f, 1.0f, 0.0f);
    m.transformVect(upv);

    m.transformVect(offset);
    offset += node->getPosition();
    camera->setPosition(offset);
    offset += frv;
    ///we let camera at level
    camera->setUpVector(upv);
    camera->setTarget(offset);
    camera->updateAbsolutePosition();
}

If it can't be writen, it can't exist
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

Ah sorry I was wrong. Apply a small change in node space and it won't ever reach 90 degrees-

Code: Select all

		core::matrix4 change;
		change.makeIdentity();
		change.setRotationDegrees( core::vector3df(rotation.X, rotation.Y, rotation.Z));
		change = node->getAbsoluteTransformation()*change;
		core::vector3df currentRotation = change.getRotationDegrees();
		node->setRotation(currentRotation);
The movement example with extra keys for rotation-
http://irrlichtirc.g0dsoft.com/paste/301
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
robertgarand
Posts: 69
Joined: Fri Feb 22, 2008 6:47 pm
Location: montreal
Contact:

It think I get it

Post by robertgarand »

Thx a lot Bitplane, :D

I'll dig into this and let you know how it worked out.
I still don't understand why it works with matrices...
I'll burn a few neurons on this.

Regards,
Robert
If it can't be writen, it can't exist
Post Reply