Turn around origin in 3D

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

Turn around origin in 3D

Post by arras »

This code shows two methods by which to turn node around origin. First use absolute rotation and works around XY axes and second use relative rotation around XYZ axes.

Code: Select all

/*!-----------------------------------------------------------------------------
| Turn around origin tutorial                                                  |
| author: arras                                                                |
| date:   01.12.2009                                                           |
|                                                                              |
| use arrow keys (X,Y axis) and Q W (Z axis) to rotate node around origin      |
------------------------------------------------------------------------------*/

#include <iostream>
using namespace std;

#include <irrlicht.h>
using namespace irr;

// this one will rotate node around absolute X and Y axis
// if you try to rotate around Z (Q,W keys) strange things will happen
void rotateAround1(scene::ISceneNode *node, const core::vector3df &origin,
   const core::vector3df &angle)
{
   // current relative position of node against origin
   core::vector3df pos = node->getPosition() - origin;

   // new rotation of node
   core::vector3df newRot = node->getRotation() + angle;

   // position were node is when unrotated
   f32 distance = pos.getLength();
   core::vector3df newPos(0,0,distance); // this assumes Z axis points "forward"

   // now rotate position vector with new rotation
   // to find out new position of node
   core::matrix4 m;
   m.setRotationDegrees(newRot);
   m.rotateVect(newPos);
   // get it absolute
   newPos += origin;

   // position node
   node->setPosition(newPos);

   // rotate node
   node->setRotation(newRot);

   cout << "X: " << newRot.X << ", Y: " << newRot.Y << ", Z: " << newRot.Z
      <<endl;
}

// this one allows rotation around all 3 axes, but rotation will be relative
void rotateAround2(scene::ISceneNode *node, const core::vector3df &origin,
   const core::vector3df &angle)
{
   // current relative position of node against origin
   core::vector3df pos = node->getPosition() - origin;

   // current rotation of node
   core::vector3df rot = node->getRotation();

   // position were node is when unrotated
   f32 distance = pos.getLength();
   core::vector3df newPos(0,0,distance); // this assumes Z axis points "forward"

   // to calculate new rotation, we need to use 2 matrices
   core::matrix4 m, n;
   m.setRotationDegrees(rot); // current rotation
   n.setRotationDegrees(angle); // rotation to add
   m *= n;
   // find out new position
   m.rotateVect(newPos);
   // get it absolute
   newPos += origin;

   // get new rotation of node
   core::vector3df newRot = m.getRotationDegrees();

   // set position
   node->setPosition(newPos);

   // set rotation
   node->setRotation(newRot);

   cout << "X: " << newRot.X << ", Y: " << newRot.Y << ", Z: " << newRot.Z
      <<endl;
}

// receiver for key imput
class MEventReceiver : public IEventReceiver
{
public:

   bool Left;
   bool Right;
   bool Up;
   bool Down;
   bool RollLeft;
   bool RollRight;

   MEventReceiver()
   {
      Left = false;
      Right = false;
      Up = false;
      Down = false;
      RollLeft = false;
      RollRight = 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: Up = event.KeyInput.PressedDown; break;
            case KEY_DOWN: Down = event.KeyInput.PressedDown; break;

            case KEY_KEY_Q: RollLeft = event.KeyInput.PressedDown; break;
            case KEY_KEY_W: RollRight = event.KeyInput.PressedDown; break;

            default: break;
         }

         return true;
		}
		return false;
	}

}Receiver;

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

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

   // node to rotate
   scene::ISceneNode *node = smgr->addCubeSceneNode();
   node->getMaterial(0).setFlag(video::EMF_LIGHTING, false);
   node->getMaterial(0).setFlag(video::EMF_WIREFRAME, true);

   // node to show origin
   scene::ISceneNode *origin = smgr->addSphereSceneNode(1.0f);
   origin->getMaterial(0).setFlag(video::EMF_LIGHTING, false);
   origin->getMaterial(0).setFlag(video::EMF_WIREFRAME, true);

   // place node and origin in such a way that node lies in front of origin
   // that is on Z axis
   // this is what this tutorial considers as default rotation 0,0,0
   node->setPosition(core::vector3df(10,0,50));
   origin->setPosition(core::vector3df(10,0,0));

   smgr->addCameraSceneNode(0, core::vector3df(10,70,-70),
      core::vector3df(10,0,0));

   f32 speed = 0.1; // rotation speed

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

      // get imput and rotate
      
      // replace it with rotateAround2 function to see difference
      if(Receiver.Left)
         rotateAround1(node, origin->getPosition(), core::vector3df(0,speed,0));

      if(Receiver.Right)
         rotateAround1(node, origin->getPosition(),core::vector3df(0,-speed,0));

      if(Receiver.Up)
         rotateAround1(node, origin->getPosition(),core::vector3df(-speed,0,0));

      if(Receiver.Down)
         rotateAround1(node, origin->getPosition(), core::vector3df(speed,0,0));

      if(Receiver.RollLeft)
         rotateAround1(node, origin->getPosition(),core::vector3df(0,0,-speed));

      if(Receiver.RollRight)
         rotateAround1(node, origin->getPosition(), core::vector3df(0,0,speed));

      smgr->drawAll();

      driver->endScene();
   }

   device->drop();

   return 0;
}
happilylazy
Posts: 53
Joined: Sun Aug 31, 2008 3:16 pm
Location: Split, Croatia

Post by happilylazy »

Awesome thread.
Comment the code a little more extensively and put this into irrLicht tutorial!
What now??? =_=''
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Post by arras »

There may be case where you need to rotate node around origin but rotation of node itself should be independent. For example you need to rotate moon around planet or planet around star. Principle is the same, only main difference is we need to store rotation somewhere as we will not be able to store it in node itself (it have its own independent rotation). I will store it in global variable but you can do it different. I will post only functions itself, rest of the code will be the same:

Code: Select all

core::vector3df Rotation;

// this one will rotate node around absolute X and Y axis
// if you try to rotate around Z (Q,W keys) strange things will happen
void rotateAround1B(scene::ISceneNode *node, const core::vector3df &origin,
   const core::vector3df &angle)
{
   // current relative position of node against origin
   core::vector3df pos = node->getPosition() - origin;

   // new rotation of node
   Rotation += angle;

   // position were node is when unrotated
   f32 distance = pos.getLength();
   core::vector3df newPos(0,0,distance); // this assumes Z axis points "forward"

   // now rotate position vector with new rotation
   // to find out new position of node
   core::matrix4 m;
   m.setRotationDegrees(Rotation);
   m.rotateVect(newPos);
   // get it absolute
   newPos += origin;

   // position node
   node->setPosition(newPos);

   cout << "X: " << Rotation.X << ", Y: " << Rotation.Y << ", Z: " << Rotation.Z
      <<endl;
}

// this one allows rotation around all 3 axes, but rotation will be relative
void rotateAround2B(scene::ISceneNode *node, const core::vector3df &origin,
   const core::vector3df &angle)
{
   // current relative position of node against origin
   core::vector3df pos = node->getPosition() - origin;

   // position were node is when unrotated
   f32 distance = pos.getLength();
   core::vector3df newPos(0,0,distance); // this assumes Z axis points "forward"

   // to calculate new rotation, we need to use 2 matrices
   core::matrix4 m, n;
   m.setRotationDegrees(Rotation); // current rotation
   n.setRotationDegrees(angle); // rotation to add
   m *= n;
   // find out new position
   m.rotateVect(newPos);
   // get it absolute
   newPos += origin;

   // get new rotation
   Rotation = m.getRotationDegrees();

   // set position
   node->setPosition(newPos);

   cout << "X: " << Rotation.X << ", Y: " << Rotation.Y << ", Z: " << Rotation.Z
      <<endl;
}
kamikaze942
Posts: 52
Joined: Wed Mar 03, 2010 7:11 pm

still rotates relative

Post by kamikaze942 »

I've implemented the first code for this, and my model still rotates arbitrarily. Am I missing something? Or is it supposed to move relative. here is my code.

[code]
if (GetAsyncKeyState(VK_F3))
{
f32 speed = 0.5;
vector3df myorigin(boyhero->getPosition());
boyhero->setRotate(myorigin, core::vector3df(0,speed,0));
}

other page

void character::setRotate(const core::vector3df origin, const core::vector3df angle)
{

core::vector3df pos = node->getAbsolutePosition() - origin;
core::vector3df newRot = node->getRotation() + angle;
f32 distance = pos.getLength();
core::vector3df newPos(0,0,distance);
core::matrix4 m;
m.setRotationDegrees(newRot);
m.rotateVect(newPos);
newPos += origin;
node->setPosition(newPos);
node->setRotation(newRot);

}

[/code]
Kamikaze
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Post by arras »

What exactly do you expect your model to do, what do you mean by "arbitrarily"? You code seems to be exact copy of one of those functions I posted. Does it something different than it does in my example?
kamikaze942
Posts: 52
Joined: Wed Mar 03, 2010 7:11 pm

arbitrary

Post by kamikaze942 »

what i mean by arbitrary is the character i have rotates around himself. Right now with the code, the character's whole body is rotating in a sort of loop. I've learned in 2d rotations that you have to multiply

matrix [current position] * matrix [rotation matrix] * matrix[inverse position]

I know the concept is similar in and i've gone through tutorials, but everything i've seen just rotates him from a position other than himself. Your code looks correct as you change the origin and do the multiplication, but I'm wondering why my character doesn't rotate around himself. Do I need to find a center for the node? I am calling my node from

IAnimatedscenemesh

[/img]
Kamikaze
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Post by arras »

Now to me this seems like contradiction:
...and my model still rotates arbitrarily

...what i mean by arbitrary is the character i have rotates around himself

...but I'm wondering why my character doesn't rotate around himself

but everything i've seen just rotates him from a position other than himself
But that is exactly what this code is intended to do. To turn node around some point in space. Mostly other than itself. You can see it if you compile my code.

If what you want is to rotate node around itself, that is around origin (set in modeling program while creating mesh) than you need to look here: Free Flight (space flight) functions
There are function which rotate node around its origin relative to its own rotation.
kamikaze942
Posts: 52
Joined: Wed Mar 03, 2010 7:11 pm

Post by kamikaze942 »

(set in modeling program while creating mesh)
how so?
Kamikaze
kamikaze942
Posts: 52
Joined: Wed Mar 03, 2010 7:11 pm

scaling problem

Post by kamikaze942 »

ok, i've seen your code work. Sorry for the mis-trust. I believe why i 'think' he is moving relative. I had to scale my .X animation to show up in irrlicht by 300 on the x,y,z. I believe this is the cause of this, as I brought in the ninja from movement example and he is rotating just fine. Anyone know a way to correct this?
Kamikaze
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Post by arras »

You have two possibilities I know about:

You can edit your model in modelling/animating application. There are dozens out there. 3DMax, Maya, Blender, Milkshape3D, CharacterFX just to name few in range from hi cost professional to freeware.

If you don't have experience with using them than you can try to do it in Irrlicht code. After loading your mesh and before creating node, you can change origin or mesh by changing position of each vertex. I newer did it with animated mesh so I can't give you more details on that.

You can also ask somebody to edit model for you. Somebody who is skilled with modelling.
zillion42
Posts: 324
Joined: Wed Aug 29, 2007 12:32 am
Location: Hamburg, Germany

Post by zillion42 »

arras has made it simple and short, hope this is what your talking about:

Code: Select all

void rotateAroundCentre(core::vector3df &point, core::vector3df center, core::vector3df rotation)
{
	point -= center;
	core::matrix4 m;
	m.setRotationDegrees(rotation);
	m.rotateVect(point);
	point += center;
}
This one is from Rogerborg:

Code: Select all

void rotateVectorAroundAxis(core::vector3df & vector, const core::vector3df & axis, f64 radians)
{
	core::quaternion MrQuaternion;
	core::matrix4 MrMatrix;
	(void)MrQuaternion.fromAngleAxis(radians, axis);
	MrQuaternion.getMatrix(MrMatrix,core::vector3df(0,0,0));
	MrMatrix.rotateVect(vector);
}
EDIT:
oops, didnt see arras actually started the thread... :oops: well, I remembered my own problem a while ago:
http://irrlicht.sourceforge.net/phpBB2/ ... ght=rotate
Post Reply