Local to World Coordinates and Vice Versa

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
BoingBoing
Posts: 18
Joined: Fri Sep 11, 2009 4:31 am

Local to World Coordinates and Vice Versa

Post by BoingBoing »

SceneNode->GetWorldPosition(0,10,0);
Would return a global position.
SceneNode->GetWorldAngles(0,90,0);
Would return a global angle.
BoingBoing
Posts: 18
Joined: Fri Sep 11, 2009 4:31 am

Post by BoingBoing »

Paid a trip to geometry-land.

Code: Select all

vector3df toWorldPos(IAnimatedMeshSceneNode* scene, vector3df vec)
{
	vector3df pos = scene->getPosition();
	vector3df ang = scene->getRotation().rotationToDirection(vec);

	return pos+ang;
}

vector3df toLocalPos(IAnimatedMeshSceneNode* scene, vector3df vec)
{
	vector3df pos = scene->getPosition();
	vector3df ang = (-scene->getRotation()).rotationToDirection(vec-pos);

	return ang;
}

vector3df toWorldAng(IAnimatedMeshSceneNode* scene, vector3df vec)
{
	return scene->getRotation()+vec;
}

vector3df toLocalAng(IAnimatedMeshSceneNode* scene, vector3df vec)
{
	return scene->getRotation()-vec;
}
Is there any default code in Irrlicht I could use instead of this messy coding? :D
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

I'm almost certain that your code is incorrect.
BoingBoing
Posts: 18
Joined: Fri Sep 11, 2009 4:31 am

Post by BoingBoing »

It is absolutely incorrect.

I tried to make an entity follow the camera but I failed miserably.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

To transform from the nodes local coordinate system to the world coordinate system, you use the nodes absolute transformation matrix.

Code: Select all

core::vector3df toWorldPos(scene::ISceneNode* node, const core::vector3df pos_in_node_space)
{
  core::vector3df pos_in_world_space(pos_in_node_space);
  node->getAbsoluteTransformation().transformVect(pos_in_world_space);
  return pos_in_world_space;
}

core::vector3df toLocalPos(scene::ISceneNode* node, const core::vector3df pos_in_world_space)
{
  core::vector3df pos_in_node_space(pos_in_world_space);

  core::matrix4 world_to_local = node->getAbsoluteTransformation();
  world_to_local.makeInverse();

  world_to_local.transformVect(pos_in_world_space);
  return pos_in_world_space;
}
Rotations are handled similarly.

Travis
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Re: Local to World Coordinates and Vice Versa

Post by christianclavet »

Hi, I tried this to convert a node world space angle to a local space angle:

Code: Select all

vector3df toLocalAng(IAnimatedMeshSceneNode* scene, vector3df vec)
{
   return scene->getRotation()-vec;
}
It seem logical that this work for the rotations... But it doesnt give me the correct angle.
For testing this I have put 2 object: 1 using the local angle (parented) and 1 that is using the world angle (not parented)). The object matches their position but not their angle (update at every frame). For the node positionning the code Vitek provided worked perfectly.

I used this to set the node:

Code: Select all

node->setRotation(Mylocalangle); 
and this to retrieve it:

Code: Select all

Mylocalangle = node->getRotation()
Here is the output that I have on the console:
- gameobject is the object rotation after it was set with the "local angle"
- Parent angle is the parent object current rotation values
- Combined angle is the parent object angle + local angle check if it match the world angle
World angle is: 272.629272,269.999969,0.000000
Local angle is: 272.629272,87.370682,-182.629288
Game object: 272.629272,87.370682,-182.629288
Parent angle: 0.000000,182.629288,182.629288
Combined Angle:272.629272,269.999969,0.000000
Last edited by christianclavet on Thu Jul 14, 2011 6:28 pm, edited 1 time in total.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Local to World Coordinates and Vice Versa

Post by mongoose7 »

Are you adding Euler angles component-wise? How can this possibly work?

Doesn't "adding" angles mean "multiplying" the rotation matrices?
blAaarg
Posts: 94
Joined: Tue Mar 02, 2010 9:11 pm
Location: SoCal

Re: Local to World Coordinates and Vice Versa

Post by blAaarg »

I'm not sure if I understand you correctly, but if by "node world space angle" you mean the "world rotation of a node" then I think what you need to do is "un-rotate" a node when given its world transformation (matrix). :?: Or at least get a tool that will tranform some 3D element back into the node's local space? That way you could have something that will change any object in world space into the local space of a node. Is that right?

If so, you need to 1) get the scene node's absolute transformation (as represented by a ) matrix: getAbsoluteTransformation().

2) Use that matrix to create an inverse matrix that represents the transformation back into local space: getInverse().

3) Then use that matrix to apply a transformation to whatever vector/element you want to have local coordinates: transformVect(), transformBox(), transformPlane(), etc.

Although setInverseRotationDegrees() might be quicker for steps 2 and 3.

Also, you may need to update the scene node's transformation first, before doing all this.
"Computers don't make mistakes! What they do they do on purpose!!"

-Dale Gribble
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Re: Local to World Coordinates and Vice Versa

Post by christianclavet »

Hi, Thanks for the replies... Still it doesnt work.

What I want to achieve is to send the WORLD rotation value and get the LOCAL rotation for a node. So I'll be able to match a WORLD rotation, from a parented node.

I tried the same matrix transformation used to get the local coordinate (position), (vitek post) but this doesnt work (the parented node rotation seem to turn at every frame instead of matching the object in world coordinates), using the setInverseRotationDegrees did not do better.

Actually im using this (getting the parented node the proper local angle to match another object world angle):

Code: Select all

core::vector3df localangle = worldangle - parentednode->getRotation();
Then this for getting back later the world angle (the angle value return the previous good value):

Code: Select all

core::vector3df worldangle = parentednode->getRotation()+localangle;
Sometimes, it can match, sometimes not (depend of the angle of the world object), but the object is at least not continually rotating from frame to frame. With a lot of testing, I found out that if I'm rotating only the Y axis, I got it matched all the time. If I'm trying another axe or doing a combination, the match doesnt work all the time.

I really don't know what I'm missing. My local object (object parented) don't match the rotation of the object that is world space)

Can this be a problem with gimbal lock? (I think the local angle is good, but perhaps the parented node can't set at the desired angle?)
All the angles are in degrees. The object I'm rotating in world space is rotated in all 3 axes (xyz) by a rotate animator.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Local to World Coordinates and Vice Versa

Post by mongoose7 »

Can I tell you once again that you CANNOT ADD EULER ANGLES COMPONENT-WISE? It only works, as you have said, if only one component is non-zero.

I would suggest you convert the angles to quaternions, multiply them together, then convert the result back to Euler angles.
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Re: Local to World Coordinates and Vice Versa

Post by christianclavet »

Thanks! That would finally make sense! I never worked with quaternion before.. Following what you proposed I wrote that and tested it. The angle seem to get wrong again. Can you correct me?
Is that the proper way to multiply a quaternion? Do you have a link to a place that explain why I must multiply the quaternion in order to get the local angle?

Code: Select all

core::vector3df ConvertToLocal (scene::ISceneNode, core::vector3df worldtoangle)
{
       // Create first quaternion from the current "worldangle"
       core::quaternion quat=core::quaternion(core::DEGTORAD*worldangle);
       // Create the second quaternion from the parent node reference
       core::quaternion quat2=core::quaternion(core::DEGTORAD*Node->getRotation());
       // Multiply the quaternion?
       quat=quat*quat2;
       core::vector3df radianLocal = core::vector3df(0,0,0);
       quat.toEuler(radianLocal);
       return core::vector3df(radianLocal*core::RADTODEG);
}
What do I do to get the reverse? (A local angle to a world angle)
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Local to World Coordinates and Vice Versa

Post by mongoose7 »

I haven't done a lot of transformation work. But looking at your line of code

Code: Select all

core::vector3df worldangle = parentednode->getRotation()+localangle;
if this is "nearly" correct, then what you would need to do is

Code: Select all

quaternion q1(DEGTORAD*parentednode->getRotation());
quaternion q2(DEGTORAD*localangle);
This gives you the two angles as quaternion rotations. Two combine them, you need to apply the first rotation (quaternion) followed by the second. If they're in the order written, this should be

Code: Select all

q2 *= q1;
(I think Irrlicht multiplies them "backwards".)

So, I don't really understand what you are trying to do, but this, I believe, is how you need to combine transformations. In Irrlicht we have quaternions, in OpenGL you would need to use matrices.

You can get the inverse of a quaternion by changing the direction of the "vector" part:

Code: Select all

q.X = -q.X;
q.Y = -q.Y;
q.Z = -q.Z;
(X, Y, Z) is the axis of rotation of the quaternion and W is the cosine of the half-angle. Reversing the vector results in a rotation in the other direction (or, same direction but upside-down).
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Re: Local to World Coordinates and Vice Versa

Post by christianclavet »

Thanks a lot for your efforts... I started to read more about the quaternion. Since the only way I see to rotate a node is to use node->setRotation(); it will surely not work as it will produce the same problem (now I'm pretty sure the problem is a gimbal lock problem).

I know we can retrieve the transformation matrix from the node, but can we modify it. Perhaps the "irr::scene::IDummyTransformationSceneNode " could do the trick if we can modify the reference to the matrix... I don't know. But the node will not be able to get the proper rotation until there is a way to bypass it. I don't see anywere we could change the rotation of a node based on quaternions.

This is now getting beyond my current knowledge (not C++ but my shitty math knowledge). My brain is going to explode! :shock:

So working with parented nodes is really not suggested for me at the moment, because of gimbal lock problems and no easy way to get it working.

Thanks to you (mongoose) and Travis that provided me with a working solution for positions (that is working 100%). If someone find a way to reposition a node to a local rotation based on a world rotation, then theses should be added to IRRlicht as it would provide an easy way to support "dynamic parenting" of nodes.
Xaryl
Posts: 90
Joined: Sat Apr 30, 2011 11:54 pm

Re: Local to World Coordinates and Vice Versa

Post by Xaryl »

To do transformation related to rotation try:

Code: Select all

core::matrix4 m;
m.setRotationDegrees(...);
multiply it with the needed transformation, and get the angle back with:

Code: Select all

m.getRotationDegrees();
By "dynamic parenting", do you mean this?

Code: Select all

void parentAndKeepTransformation(scene::ISceneNode* child, scene::ISceneNode* parent){
    core::matrix4 m(core::matrix4::EM4CONST_NOTHING);
    parent->getAbsoluteTransformation().getInverse(m); 
    m *= child->getAbsoluteTransformation();
    child->setPosition(m.getTranslation());
    child->setRotation(m.getRotationDegrees());
    child->setScale(m.getScale());
    child->setParent(parent);
}
(You might want to updateAbsolutePosition() first.)
Post Reply