adjust model to vectors

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
Timm
Posts: 4
Joined: Sun Oct 05, 2008 6:51 pm

adjust model to vectors

Post by Timm »

Hello there,
i've got a problem adjusting a model to three given vectors(right vector, up vector and view vector). I'm able to compute them properly and the look in the direction i want them to look. I also changed the Irrlicht Code to override the relative Transformation routine to change the matrix by hand.
I came up integrating my 3 vectors directly into the matrix like the gluLookAt routine does.

The solution i wanted to achieve is to bypass the gimbal lock problem. But obviously it seems that i reprogrammed the normal rotation routine.
This is kinda ridiculous as the routines I used obviously worked for me in my engine's camera class.

Perhaps there is an easier solution than the one i'm going. If so, could someone tell me?

Thanks :)
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

From your post i can't understand what your problem is....

The closest i can get is something to do with normal rotation routine..?
Image Image Image
Timm
Posts: 4
Joined: Sun Oct 05, 2008 6:51 pm

Post by Timm »

Okay, i try to explain what i want to achieve.

I got an object that has a precomputed direction vector, right vector and an up vector. Now I want to rotate that object(it's an IMeshSceneNode) around till it faces in the direction of the direction vector. I hope you understand it now :).

Thanks :)
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

right and up are perpendicular, and right is just 90 degree rotated front? Which would mean that you want to align the front vector with the direction vector, keeping up in hte same hemisphere? Is that the task?
Timm
Posts: 4
Joined: Sun Oct 05, 2008 6:51 pm

Post by Timm »

No, I want to rotate the the mesh so that the mesh is looking in the direction of the direction vector.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yeah, but who knows where the mesh is looking? Assuming your mesh is a cube (for testing purposes), I cannot guarantee any "looking" direction. You have to define "front" somehow.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

OK, first stab:

Calculate the Euler rotations that will produce given direction and up vectors (the right vector is just the cross product of those, so we can ignore it).

You can then interpolate between the current rotation and this calculated rotation, although I can't guarantee that it'll be free of gimbal lock.

If that doesn't do what you want, then I can take another stab at it. Perhaps a hack, conceivably even a slash as well.

Sample app:

Code: Select all

#include <irrlicht.h>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#pragma comment(lib, "Irrlicht.lib")

vector3df calculateRotations(vector3df const & direction,
                             vector3df const & up)
{
   vector3df masterDirection(direction);
   masterDirection.normalize();

   vector3df masterUp(up);
   masterUp.normalize();

   // project the up vector onto a vector that's orthogonal to the direction
   vector3df realUp = masterDirection.crossProduct(masterUp).normalize();
   realUp = realUp.crossProduct(masterDirection);

   // Get the quaternion to rotate to the required direction
   quaternion quatDirection;
   quatDirection.rotationFromTo(vector3df(0, 0, 1), masterDirection);

   // Apply that rotation to the world up vector
   vector3df worldUp(0, 1, 0);
   matrix4 mat;
   quatDirection.getMatrix(mat);
   mat.rotateVect(worldUp);

   // Get the quaternion to rotate to the required up
   quaternion quatUp;
   quatUp.rotationFromTo(worldUp, realUp);

   // Concatenate them to get a total rotation
   quaternion quat = quatDirection * quatUp;

   // Convert to euler rotations
   vector3df eulers;
   quat.toEuler(eulers); //... in radians
   eulers *= RADTODEG;   //... and now in degrees
   // This is the euler rotations required.

   return eulers;
}

void makeRandomTargets(vector3df & targetDirection,
                       vector3df & targetUp)
{
    do
    {
        targetDirection.set((f32)(rand() % 2000 - 1000), 
                            (f32)(rand() % 2000 - 1000), 
                            (f32)(rand() % 2000 - 1000));
        targetUp.set((f32)(rand() % 2000 - 1000), 
                     (f32)(rand() % 2000 - 1000), 
                     (f32)(rand() % 2000 - 1000));
    } while(equals(targetDirection.getLengthSQ(), 0.f) ||
            equals(targetUp.getLengthSQ(), 0.f) || 
            targetDirection == targetUp);

    targetDirection.normalize();
    targetUp.normalize();
}

bool rotateNode(ISceneNode * node, const vector3df & targetRotations, f32 delta)
{
    vector3df rotation = node->getRotation();
    vector3df deltaRotation = targetRotations - rotation;

    if(equals(deltaRotation.getLengthSQ(), 0.f))
        return false; // reached target

    const f32 availableRotationMagnitude = delta * 45.f; // degrees per second
    // You could also scale the speeds by the largest difference

    if(deltaRotation.X < - availableRotationMagnitude)
        deltaRotation.X = -availableRotationMagnitude;
    else if(deltaRotation.X > availableRotationMagnitude)
        deltaRotation.X = availableRotationMagnitude;

    if(deltaRotation.Y < - availableRotationMagnitude)
        deltaRotation.Y = -availableRotationMagnitude;
    else if(deltaRotation.Y > availableRotationMagnitude)
        deltaRotation.Y = availableRotationMagnitude;

    if(deltaRotation.Z < - availableRotationMagnitude)
        deltaRotation.Z = -availableRotationMagnitude;
    else if(deltaRotation.Z > availableRotationMagnitude)
        deltaRotation.Z = availableRotationMagnitude;

    rotation += deltaRotation;
    node->setRotation(rotation);
    return true;
}



int main()
{
	IrrlichtDevice *device =
		createDevice( video::EDT_OPENGL, dimension2d<s32>(640, 480), 16,
			false, false, false, 0);
	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();

    ISceneNode * MrCubey = smgr->addCubeSceneNode();
    MrCubey->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
	MrCubey->setMaterialFlag(video::EMF_LIGHTING, false);

    (void)smgr->addCameraSceneNode(0, vector3df(0, 0, -30));

    vector3df targetDirection;
    vector3df targetUp;

    makeRandomTargets(targetDirection, targetUp);
    vector3df targetRotations = calculateRotations(targetDirection, targetUp);

    SMaterial material;
	material.setTexture(0, 0);
	material.Lighting = false;


    u32 then = device->getTimer()->getTime();
	while(device->run())
	{
        const u32 now = device->getTimer()->getTime();
        const f32 delta = (f32)(now - then) * 0.001f;
        then = now;

        if(!rotateNode(MrCubey, targetRotations, delta))
        {
            makeRandomTargets(targetDirection, targetUp);
            targetRotations = calculateRotations(targetDirection, targetUp);
        }

		driver->beginScene(true, true, SColor(255,100,101,140));
		smgr->drawAll();

        driver->setTransform(video::ETS_WORLD, core::matrix4());
        driver->setMaterial(material);

        driver->draw3DLine(MrCubey->getAbsolutePosition(),
                           MrCubey->getAbsolutePosition() + 50.f * targetDirection,
                           SColor(255, 255, 0, 0));

        driver->draw3DLine(MrCubey->getAbsolutePosition(),
                           MrCubey->getAbsolutePosition() + 50.f * targetUp,
                           SColor(255, 0, 255, 0));

		driver->endScene();
	}

	device->drop();

	return 0;
}
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Timm
Posts: 4
Joined: Sun Oct 05, 2008 6:51 pm

Post by Timm »

Yeah, but who knows where the mesh is looking? Assuming your mesh is a cube (for testing purposes), I cannot guarantee any "looking" direction. You have to define "front" somehow.
The front was (0,0,1). But nevermind now.

Thanks rogerborg the second was the function I was looking for.
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

i know this is a pretty old post, but tried out the code, and worked, except if the direction is vector3df(0,0,-1). then it wants to rotate vector3df(180, -5.0089557e-006, 180). what no matter how we see, not right. it should only rotate on Y axis.
after a lot of debugging, i got it, that the rotationFromTo function changed since 1.6
there is a block what wasnt there before

Code: Select all

else if (d <= -1.0f) // exactly opposite
	{
		core::vector3df axis(1.0f, 0.f, 0.f);
		axis = axis.crossProduct(core::vector3df(X,Y,Z));
		if (axis.getLength()==0)
		{
			axis.set(0.f,1.f,0.f);
			axis.crossProduct(core::vector3df(X,Y,Z));
		}
		return this->fromAngleAxis(core::PI, axis);
	}
this returns the bad angle. is it irrlicht bug, or just the old code doesnt work, and should use somethign else?

Edit: OK tryed out the old code, and its even worse... XD (it tries to divide by zero, so the values becomes garbage to protect the world from apocalypse) what should i do?
Image
Image
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

hmmm, I don't know if this may help,
but for OpenSteer I had to deal with rotation from forward verctor and vice versa...
so I made this 2 little functions:

Code: Select all

  //! convert rotation vector to forward vector
  static Vec3 getForwardFromRotation(Vec3 r) {
    irr::core::matrix4 mat;
    mat.setRotationDegrees(r.vector3df());
    Vec3 ff;
    ff.set(mat(2,0), mat(2,1), mat(2,2));
    ff.normalize();
    return ff;
  }

  //! convert forward vector to rotation vector
  static Vec3 getRotationFromForward(Vec3 r) {
    Vec3 ff = r.vector3df().getHorizontalAngle();
    return ff;
  }
remember that Vec3 is an OpenSteer vector and I added a vector3df() function to it for easy conversion between OpenSteer and Irrlicht...

for pure Irrlicht it should be like this (I guess :lol: ):

Code: Select all

  static irr::core::vector3df getForwardFromRotation(irr::core::vector3df r) {
    irr::core::matrix4 mat;
    mat.setRotationDegrees(r);
    irr::core::vector3df ff(mat(2,0), mat(2,1), mat(2,2));
    ff.normalize();
    return ff;
  }

  //! convert forward vector to rotation vector
  static irr::core::vector3df getRotationFromForward(irr::core::vector3df r) {
    irr::core::vector3df ff = r.getHorizontalAngle();
    return ff;
  }
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

thanks, but i need interpolation. and whats the most important, is i need to get the nearest rotation.
so from 20 to 270, it has to rotate down etc.
Image
Image
anirul
Posts: 30
Joined: Wed Oct 07, 2009 6:03 am
Location: Geneva
Contact:

Post by anirul »

I advise you to forget matrix and use quaternion they are free of gimbal lock and pretty easy to use! If you have a look in the irr::core::quaternion you'll be pleased! quaternion can be multiply just like matrix do and can be computed from 2 vectors. The only issue is they will take the shortest rotation between 2 vectors so won't care about your up vector. but in normal case you can rotate back the camera to suit your needs.
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

as i see this code above uses quaternions, except for upvector. quaternions works good, except when the target rotation is the opposite of the current. then it gets stuck.
Image
Image
Post Reply