Rotating to face a point

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
SimRex
Posts: 6
Joined: Wed Feb 04, 2004 11:54 pm
Location: England
Contact:

Rotating to face a point

Post by SimRex »

Based on numerous forum searches, rotation seems to be a fairly common newbie problem, and it looks like I'm no different...

My problem is, I want to rotate a node to face another node.

The problem is, it doesn't seem to work - the node just keeps facing forwards, and even if I press the "rotate node 10 degrees left" key, it stays facing forwards. Therefore, it's fair to assume the problem is in the functions I've written to calculate the change in angles needed. So here they are:

Code: Select all

void MyObject::AdjustHeading(vector3df vDestination)
{      
    vector3df start = NodePtr->getPosition();
    vector3df diff = vector3df(vDestination.X-start.X, vDestination.Y-start.Y, vDestination.Z-start.Z);
    vector3df diffAngles = AsAngles(diff);
    NodePtr->setRotation(diffAngles);
NodePtr is, as one might expect, a pointer to the appropriate node. The AsAngles function is:

Code: Select all

vector3df AsAngles(vector3df v3d)
{
    float xRot,yRot,zRot;
    float x = v3d.X;
    float y = v3d.Y;
    float z = v3d.Z;
    xRot = atanf(y/x);
    yRot = 0;
    zRot = atanf(y/z);
    vector3df retval(xRot,yRot,zRot);
    return retval;
    
}

So, anyone see anything small and foolish, or am I barking up entirely the wrong tree with this?
keless
Posts: 805
Joined: Mon Dec 15, 2003 10:37 pm
Location: Los Angeles, California, USA

Post by keless »

open up the IrrLicht source code, and look at ICamera::setTarget(ISceneNode)
a screen cap is worth 0x100000 DWORDS
Guest
Posts: 35
Joined: Mon Feb 02, 2004 7:17 pm
Location: Russia, Saint-Petersburg

Post by Guest »

actually you don't need such complex calculations :)

as far as I see, you have two nodes (node1 and node2), and you want to rotate them to look at each other... so you can do the following:

Code: Select all

node2->setRotation(-node1->getRotation());
but this code requires that you nodes are initially "look" in one direction. Otherwise you have to consider initial difference in rotations. Try it if you'd like and tell me if it works :)
SimRex
Posts: 6
Joined: Wed Feb 04, 2004 11:54 pm
Location: England
Contact:

Post by SimRex »

Well, thank you both for your help, it is appreciated :)

I've decided, after looking more closely at the source code, that a SceneNodeAnimator is what I'm looking for. It will probably require me to cannibalise the Camera class, as keless kind of suggested, to get some of the transformation stuff out of there. That seems to be the best way to create the effect I'm after.

To the guest, the main drawback with your method is, in the future I'm going to need to be able to tell a node toturn and face a specific point in 3d space, which it needs to do smoothly over a couple of seconds.
SimRex
Posts: 6
Joined: Wed Feb 04, 2004 11:54 pm
Location: England
Contact:

Post by SimRex »

Thought I'd post back a few potentially useful things I've found out while trying to solve my problem...

This is probably the wrong place to post it, but I don't know where would be the right place...

Item1 - node->setRotation(xRot,yRot, zRot)

xRot = Rotation about the X axis. Rotation is measured from the +ve Z axis. If xRot is 90, the node will have rotated between the +ve Z axis and the -ve Y axis.

yRot = Rotation about the Y axis. Measures from the +ve Z axis. If yRot is 90, the node will have rotated between the +ve Z axis and the +ve X axis.

zRot = Rotation about the Z axis. Rotation is measured from the +ve Y axis. If zRot is 90, the node will have rotated between the +ve Y axis and the -ve X axis.

Item2 - Getting a forward unit vector so you can move forwards...

Code: Select all

	// Create a vector to store the current rotation in degrees
	vector3df facing = node->getRotation();

	// Create a unit vector pointing "forwards"
	// ie the direction of the +ve Z axis, angle(0,0,0)
	vector3df unitDirection(0,0,1);

	// Rotate in each plane by the angle between the plane
	// and the axis perpendicular to the plane                       
	unitDirection.rotateXZBy(facing.Y, vector3df(0,0,0));
	unitDirection.rotateYZBy(facing.X, vector3df(0,0,0));
	unitDirection.rotateXYBy(facing.Z, vector3df(0,0,0));

	// Flip the rotation about X and Y.
	// Probably better to negate the angles higher up but
	// this works
	unitDirection.set(-unitDirection.X, -unitDirection.Y, unitDirection.Z);

	// Move forward 1 unit.
	node->setPosition(node->getPosition() + unitDirection);
The code seems to work perfectly for me, although I'd love to know if there's a better way to do this.

Hope that this will help some newbie...
NecromanX
Posts: 16
Joined: Sat Jan 24, 2004 6:01 pm

Post by NecromanX »

the moving forward part can be done a lot smaller :)

try this one:

Code: Select all

vector3df forward = ( sin( (Node->getRotation().Y+90)*PI/180.0f ), 0, cos( (Node->getRotation().Y+90)*PI/180.0f ) ); 
			Node->setPosition( Node->getPosition() + forward*0.25f ); 
if your node isnt a md2 model remove the "+90" for x and z
SimRex
Posts: 6
Joined: Wed Feb 04, 2004 11:54 pm
Location: England
Contact:

Post by SimRex »

NecromanX wrote:the moving forward part can be done a lot smaller :)

try this one:

Code: Select all

vector3df forward = ( sin( (Node->getRotation().Y+90)*PI/180.0f ), 0, cos( (Node->getRotation().Y+90)*PI/180.0f ) ); 
			Node->setPosition( Node->getPosition() + forward*0.25f ); 
if your node isnt a md2 model remove the "+90" for x and z
That looks like it would work fine for 2-dimensional movement, but I need some nodes to be able to move freely in 3-dimensional space, so I have to have something in there to take account for the change in X and Z angles too... The easiest way I could find to make that work was the method above - it all got too confusing when I was trying to use sin and cos to get the same effect :(

Thanks for bringing that one to my attention though :)
Maureen

Post by Maureen »

And heres a way to calculate the angles to build a look at function

Code: Select all

void faceTarget(irr::scene::ISceneNode& target){
  irr::core::vector3df pos=getPosition(); // myposition
  irr::core::vector3df targetPos=target.getPosition();
  irr::core::matrix4 transform.
                         buildCameraLookAtMatrixLH(pos,targetPos,up);
  irr::core::vector3df rot=Math::MatrixToEulerAngles(transform);
  transform.transformVect(forward,curforward);
  transform.transformVect(up,curup);
  this->setRotation(rot);
}
Matrix to Euler conversion isn't provided in the matrix class so here's a conversion from www.flipcode.com

Code: Select all

/*
*	convert an irrlicht matrix4 to eulerangles
*/
irr::core::vector3df MatrixToEulerAngles(irr::core::matrix4& mat)
{
  irr::f32 angle_y,D,C,angle_x,angle_z,frx,fry;
  angle_y = D = -asin( mat(0,2) );
  C           =  cos( angle_y );
  angle_y    *= (f32)irr::core::GRAD_PI;
  if ( fabs( C ) > 0.005 )             /* Gimball lock? */
  {
    frx      =  mat(2,2) / C;          
    fry      = -mat(1,2)  / C;
    angle_x  = atan2( fry, frx ) * (f32)irr::core::GRAD_PI;
    frx      =  mat(0,0) / C;           
    fry      = -mat(0,1) / C;	
    angle_z  = atan2( fry, frx ) * (f32)irr::core::GRAD_PI;
  }
  else                                 /* Gimball lock has occurred */
  {
    angle_x  = 0;                      
    frx      = mat(1,1);              
    fry      = mat(1,0);
    angle_z  = atan2( fry, frx ) * (f32)irr::core::GRAD_PI;
  }
  angle_x = angle_x<0 ? angle_x+360.0f : angle_x;
  angle_y = angle_y<0 ? angle_y+360.0f : angle_y;
  angle_z = angle_z<0 ? angle_z+360.0f : angle_z;
  return irr::core::vector3df(angle_x,angle_y,angle_z);
}
hope this helps. it would be nice if someone could veryfie the correctness of the above code :)

Maureen
Maureen

Post by Maureen »

Ahhh, just found a thread in the Advanced Forum which is about matrix to euler conversion.... sorry for this spam
Maureen
jox
Bug Slayer
Posts: 726
Joined: Thu Apr 22, 2004 6:55 pm
Location: Germany

Post by jox »

@Maureen: I verifed the correctness of the above code. Result: correctness == false ;)

You can find correct code here:

http://irrlicht.sourceforge.net/phpBB2/ ... php?t=2234

grease,
jox
Post Reply