Is this gimbal lock?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
BakeMyCake
Posts: 23
Joined: Sat Jun 15, 2013 3:13 am

Is this gimbal lock?

Post by BakeMyCake »

I have a node that rotates however it likes. A child to this node inherits it's rotation. If I apply additional local rotation to the child using getHorizontalAngle I get correct results only if the parent node is rotating around the Y axis. As soon as the parent starts pitching or rolling the child node rotations get messed up. The farther the parent pitches/rolls the stronger the child rotation is affected. Is this the notorious gimbal lock?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Is this gimbal lock?

Post by CuteAlien »

Maybe :-) Sorry, hard to tell without seeing what you do exactly and what you are trying to reach. Try to describe what exactly you want to do, then we can probably help you to get it working. For example when you say you apply the local rotation - we don't know what you are doing there in code. Or why you are using getHorizontalAngle.

I suspect your problem is not about gimbal lock, but hard to tell from information we have so far.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
BakeMyCake
Posts: 23
Joined: Sat Jun 15, 2013 3:13 am

Re: Is this gimbal lock?

Post by BakeMyCake »

The basic idea is that the parent node travels around the game world in his own agenda, rotating in all 3 possible axes, while the child node called turret is controlled by your cursor. The turret is positioned below relative to parent. The turret is supposed to look where you point on the screen. Well, it doesn't...

Code: Select all

//get mouse to 3d world coordinates
core::line3d<f32> ray = collisionManager->getRayFromScreenCoordinates(cursorControl->getPosition(),camera);
turret->updateAbsolutePosition();
vector3df nodePos = turret->getAbsolutePosition();
vector3df diff = ray.end - nodePos;
 
turret->setRotation(diff.getHorizontalAngle()-ship.getRotation());
 
//for checking purposes
vector3df test2 = diff.getHorizontalAngle().rotationToDirection();
 
driver->beginScene(true, true, SColor(255, 100, 101, 140));
smgr->drawAll();
guienv->drawAll();
driver->draw3DLine(nodePos,nodePos+test2,SColor(255,0,0,0));
driver->endScene();
As you can see I shoot a ray and calculate the horizontal angle between the ray and the position of the turret. Dug that bit of code from snooping around the forums. After that I subtract the parents rotation from the rotation of the child. Without that the turret turns towards the camera when the parent turns.

The turret points at the cursor only in a scenario when the parent is perfectly horizontally aligned (doesn't roll or pitch). In other scenarios the turret starts rotating in weird ways and doesn't point at the cursor. My initial guess was that the angles are calculated incorrectly, so I've made a test2 variable that holds the vector that would be the result of the angle rotation. The line produced by driver->draw3DLine(nodePos,nodePos+test2,SColor(255,0,0,0)); is pointing towards the cursor in a rather precise way, so the horizontal angle calculated is probably the angle I need. Yet rotating the turret node with those angles gives me little success.

I don't know what to think. If I can get a vector derived from the angle, and the vector is correct, then why can't I get the same orientation when I apply the same angle to a node.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Is this gimbal lock?

Post by CuteAlien »

Probably you don't want ray.end - pos, but rather the closest point on the camera-ray to your nodePos (aka: ray. getClosestPoint(pos)) as ray.end is the point at the far-plane while this way you could get one at the same depth as your turret.

I'd have to experiment myself to figure out this specific case, but maybe search the forum some more. If I remember right there had been a thread in the past about orienting a child towards a certain point.
I suspect you can't just subtract the parent euler angles, but maybe have to transform the 'diff' first by the inverse of the parent matrix and then you could use the getHorizontalAngle directly. But no guarantees (my first bet is usually also wrong and I have to experiment a while).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: Is this gimbal lock?

Post by Mel »

I take that the turret is attached to your parent node, so you can do this: get the absolute transformation matrix of the parent, and transform the world point you want to aim at with it. That way, the turret and the point will be on the same frame of reference, then do the same you were doing. More than gimbal lock, it is a matter of uncertain alignment with regard to the parent, which goes when the point is expressed in the same terms of the parent orientation, i hope this helps!
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
BakeMyCake
Posts: 23
Joined: Sat Jun 15, 2013 3:13 am

Re: Is this gimbal lock?

Post by BakeMyCake »

In a fortunate permutation of arbitrary c++ code I've managed to make it work, but it's ugly as hell. I removed the parent status from the ship - all these relationships are weighing my poor turret down. For some reason nothing I do works if the turret is a child, so I just do my stuff and then place the turret in the place where it should be as if it were a child. At the moment the code has a lot of redundant parts. Once I'm done making it less of an embarrassment I will probably share it. Right now I cant figure out if this sequence of actions is actually just building a quaternion, and can be rewritten:

Code: Select all

//Calculate the normalized vector from your object to the target.This is simply normalize(P2 - P1)
vector3df vecTo = (ray.end - nodePos).normalize();
//Take the cross product of T and L(watch the order as the cross product is not commutative).This is the axis of rotation.
vector3df axisRot = vecTo.crossProduct(getIn(ship));
//Calculate arccos(dot(T, L)).This is your angle of rotation.
float angle = acosf(vecTo.dotProduct(getIn(ship)));
float realAngle = angle*RADTODEG;
 
rotateNodeInLocalSpace(turret, -realAngle, axisRot);
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Is this gimbal lock?

Post by mongoose7 »

The problem was, you set the child rotation as if it was absolute. But it is not, it is relative to the parent. So, after calculating the rotation you want, you need to multiply it by the inverse of the rotation of the parent.

Rotation of child = (rotation of parent)* ((relative) rotation of child)
BakeMyCake
Posts: 23
Joined: Sat Jun 15, 2013 3:13 am

Re: Is this gimbal lock?

Post by BakeMyCake »

mongoose7 wrote:The problem was, you set the child rotation as if it was absolute. But it is not, it is relative to the parent. So, after calculating the rotation you want, you need to multiply it by the inverse of the rotation of the parent.

Rotation of child = (rotation of parent)* ((relative) rotation of child)
Oh... This is much better. Well, never mind then... *deletes all his code*

If anyone else ever wonders what needs to be done to make a child node face point here it goes:

Code: Select all

matrix4 matParent = parentNode->getAbsoluteTransformation();
matParent.makeInverse();
 
vector3df difference = (target - childNode->getAbsolutePosition()).normalize();
 
matParent.rotateVect(difference);
 
childNode->setRotation(difference.getHorizontalAngle());
Post Reply