Turn to target in 3D

A forum to store posts deemed exceptionally wise and useful
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Turn to target in 3D

Post by arras »

This tutorial shows how to turn node towards target given node rotation and position.

Code: Select all

/*!-----------------------------------------------------------------------------
| Turn to target tutorial                                                      |
| author: arras                                                                |
| date:   06.02.2009                                                           |
|                                                                              |
| use arrow keys + PgUp/PgDn or A,D,S,W,E,C keys to move target around         |
------------------------------------------------------------------------------*/

#include <irrlicht.h>
using namespace irr;

// return relative position of target given origin and rotation
core::vector3d<f32> getRelativePosition(const core::vector3d<f32> &origin, const core::vector3d<f32> &rotation, const core::vector3d<f32> &target)
{
   core::matrix4 m;
   m.setRotationDegrees(rotation);

   core::vector3d<f32> relative = target - origin;
   m.inverseRotateVect(relative);

   return relative;
}

// return relative position of target given node position and rotation
core::vector3d<f32> getRelativePosition(scene::ISceneNode *node, const core::vector3d<f32> &target)
{
   node->updateAbsolutePosition(); //this will update AbsoluteTransformation of node
   core::matrix4 m = node->getAbsoluteTransformation();

   core::vector3d<f32> relative = target - node->getPosition();
   m.inverseRotateVect(relative);

   return relative;
}

// use above functions to rotate node towards target
// rotation is done around local X and Y axis of node not global axis, if you want
//    different behavior you need to code it yourself
// code is susceptible to gimbal lock
void rotateTo(scene::ISceneNode *node, f32 speed, const core::vector3df &target)
{
   core::vector3df pos = getRelativePosition(node, target);
   core::vector3df rot = pos.getHorizontalAngle();

   if(rot.X <= 180 && rot.X > speed) rot.X = speed;
   if(rot.X > 180 && rot.X < 360 - speed) rot.X = -speed;

   if(rot.Y <= 180 && rot.Y > speed) rot.Y = speed;
   if(rot.Y > 180 && rot.Y < 360 - speed) rot.Y = -speed;

   core::matrix4 m;
   m.setRotationDegrees( node->getRotation() );

   core::matrix4 m2;
   m2.setRotationDegrees(rot);

   m *= m2;

   node->setRotation( m.getRotationDegrees() );
}

// just detects keyboard input
class MEventReceiver : public IEventReceiver
{
   bool Left;
   bool Right;
   bool Up;
   bool Down;
   bool Forward;
   bool Back;

public:

   MEventReceiver()
   {
      Left = false;
      Right = false;
      Up = false;
      Down = false;
      Forward = false;
      Back = false;
   }

   virtual bool OnEvent(const SEvent &event)
	{
		if(event.EventType == irr::EET_KEY_INPUT_EVENT)
      {
         switch(event.KeyInput.Key)
         {
            case KEY_RIGHT: Right = event.KeyInput.PressedDown; break;
            case KEY_LEFT: Left = event.KeyInput.PressedDown; break;

            case KEY_UP: Forward = event.KeyInput.PressedDown; break;
            case KEY_DOWN: Back = event.KeyInput.PressedDown; break;

            case KEY_PRIOR: Up = event.KeyInput.PressedDown; break;
            case KEY_NEXT: Down = event.KeyInput.PressedDown; break;

            case KEY_KEY_D: Right = event.KeyInput.PressedDown; break;
            case KEY_KEY_A: Left = event.KeyInput.PressedDown; break;

            case KEY_KEY_W: Forward = event.KeyInput.PressedDown; break;
            case KEY_KEY_S: Back = event.KeyInput.PressedDown; break;

            case KEY_KEY_E: Up = event.KeyInput.PressedDown; break;
            case KEY_KEY_C: Down = event.KeyInput.PressedDown; break;

            default: break;
         }

         return true;
		}
		return false;
	}

	bool leftPressed(){return Left;}
	bool rightPressed(){return Right;}

	bool forwardPressed(){return Forward;}
	bool backPressed(){return Back;}

	bool upPressed(){return Up;}
	bool downPressed(){return Down;}

} Receiver;


// moves node around scene given commands detected by receiver
void control(scene::ISceneNode *node, f32 speed)
{
   if(Receiver.leftPressed()) node->setPosition(node->getPosition() + core::vector3df(0,0,-speed));
   if(Receiver.rightPressed()) node->setPosition(node->getPosition() + core::vector3df(0,0,speed));

   if(Receiver.forwardPressed()) node->setPosition(node->getPosition() + core::vector3df(-speed,0,0));
   if(Receiver.backPressed()) node->setPosition(node->getPosition() + core::vector3df(speed,0,0));

   if(Receiver.upPressed()) node->setPosition(node->getPosition() + core::vector3df(0,speed,0));
   if(Receiver.downPressed()) node->setPosition(node->getPosition() + core::vector3df(0,-speed,0));
}

int main()
{
   IrrlichtDevice *device = createDevice(video::EDT_OPENGL,
      core::dimension2d<s32>(640, 480), 16, false, false, false, &Receiver);

   device->setWindowCaption(L"Irrlicht Vzor");

   video::IVideoDriver* driver = device->getVideoDriver();
   scene::ISceneManager* smgr = device->getSceneManager();

   // add arrow to the scene which will represent object rotating towards target
   scene::IMesh *mesh = smgr->addArrowMesh("arrow", video::SColor(180,255,0,0),
      video::SColor(180,0,0,255), 4,8, 20,15, 0.5f,1 )->getMesh(0);
   // arrow mesh points along Y axis originaly we have to change that
   core::matrix4 m;
   m.setRotationDegrees(core::vector3df(90,0,0));
   smgr->getMeshManipulator()->transformMesh(mesh, m);
   scene::ISceneNode *node = smgr->addMeshSceneNode(mesh);
   node->setMaterialFlag(video::EMF_LIGHTING, false);
   node->setPosition(core::vector3df(0,0,10));

   // target marker
   mesh = smgr->addSphereMesh("sphere", 1)->getMesh(0);
   smgr->getMeshManipulator()->setVertexColors(mesh, video::SColor(255,255,0,0));
   scene::ISceneNode *target = smgr->addMeshSceneNode(mesh);
   target->setPosition(core::vector3df(0,10,30));
   target->setMaterialFlag(video::EMF_LIGHTING, false);

   // camera
   smgr->addCameraSceneNode(0, node->getPosition()+core::vector3df(20,20,-20),node->getPosition());

   while(device->run())
   {
      driver->beginScene(true, true, video::SColor(0,200,200,200));

      control(target, 0.01f); // set diferent speed if its too fast/slow
      rotateTo(node, 0.01f, target->getPosition()); // set diferent speed if its too fast/slow

      smgr->drawAll();

      driver->endScene();
   }

   device->drop();

   return 0;
}
Vandrick
Posts: 13
Joined: Sat Feb 21, 2009 5:37 am

Post by Vandrick »

ArcTan does it for you and its fast.


core::vector3df LookAt(core::vector3df Pos1, core::vector3df Pos2)
{
core::vector3df Rot;
float X; float Y;
X = Pos1.X - Pos2.X ;
Y = Pos1.Z - Pos2.Z ;
Rot.Y = (irr::f32)((atan2(X, Y) * 180 / PI2) + 180);
return Rot;
}
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Post by arras »

Your function returns rotation only in horizontal plane. You still need vertical. Besides getHorizontalAngle() use atan2() to compute that. Look at the sources: vector3d<T> getHorizontalAngle() const
Vandrick
Posts: 13
Joined: Sat Feb 21, 2009 5:37 am

Post by Vandrick »

Ah thats good to know. Sorry for the miss help.

The reason my Rotation only returns a 2d Rotation is because I use it to have one npc chase another. If they start looking up and down with a 3rd Rotation it would look silly.
trivtn
Posts: 132
Joined: Tue Jan 17, 2006 12:30 pm
Location: Viet Nam
Contact:

Post by trivtn »

I've used it in control my Character, It worked wonderful. Thank!
There's something is fantastic, there's nothing is absolute.
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Post by arras »

I am glad it helps :)
trivtn
Posts: 132
Joined: Tue Jan 17, 2006 12:30 pm
Location: Viet Nam
Contact:

Post by trivtn »

Yes ! Here my result. Thanks!
http://www.youtube.com/watch?v=WN75hv00MFE
There's something is fantastic, there's nothing is absolute.
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Post by arras »

Hey, looks great :) Good luck.
Virion
Competition winner
Posts: 2148
Joined: Mon Dec 18, 2006 5:04 am

Post by Virion »

the video looks cool hehe
trivtn
Posts: 132
Joined: Tue Jan 17, 2006 12:30 pm
Location: Viet Nam
Contact:

Post by trivtn »

Thank you !, I've improved my game project more. Thank arras! :lol: . And my next video :
http://www.youtube.com/watch?v=63bOrEp6KXE
There's something is fantastic, there's nothing is absolute.
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Post by arras »

Nice progress trivtn. Why didn't I see your project in Project Announcements? :)
trivtn
Posts: 132
Joined: Tue Jan 17, 2006 12:30 pm
Location: Viet Nam
Contact:

Post by trivtn »

Yes! After I've fininshed the my "Saving and Loading level ", I'll send it in Project Announcements. I'm trying this.
Thanks arras ! :lol:
There's something is fantastic, there's nothing is absolute.
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Is your project in D3D or OGL? I think I can fix that lighting problem, you need to adjust the light's attenuation after you create it.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
trivtn
Posts: 132
Joined: Tue Jan 17, 2006 12:30 pm
Location: Viet Nam
Contact:

Post by trivtn »

Thank BlindSide!. I've download your Shadow Map. I like it :lol:
-My game does't use any addin effect. I'll use it in Funture.
There's something is fantastic, there's nothing is absolute.
tonic
Posts: 69
Joined: Mon Dec 10, 2007 6:18 pm
Contact:

Post by tonic »

Here's one version of finding rotation degrees to look at or face another node. Just posting here in case somebody has problems with the lookat /facing stuff and wants to try different solutions.

Code: Select all

irr::core::vector3df gIrrGetLookAtRotationDegreesLH(const irr::core::vector3df &from, const irr::core::vector3df &target)
{
    const core::vector3df upVector(0, 1, 0);
    core::matrix4 m, m2;
    m.buildCameraLookAtMatrixLH(from, target, upVector);
    if (m.getInverse(m2))
        return m2.getRotationDegrees();
    else
    {
        core::vector3df v = target - from;
        if (v.Y < 0)
            return core::vector3df(90, 0, 0);
        else
            return core::vector3df(-90, 0, 0);
    }
}
Post Reply