Page 1 of 1

calculate angle from 2 vectors for object rotation

Posted: Thu Jul 10, 2008 8:23 am
by HydroNom
Hello,

It seems that I'm currently mathematical disabled a little bit. I have load a 3D object and can show it. Additionally I have 2 vectors (normalized) which defines the rotation of this object. The first vector is the direction of the objects X axis, the second is it's normale vector (matches the direction of the Y axis) For example: v1(-1.0,0,0) v2(0,1.0,0) which defines the objects x axis directs into the opposite to the world x axis

How can I calculate the angles for setRotation function of a scene node object from this?

Re: calculate angle from 2 vectors for object rotation

Posted: Thu Jul 10, 2008 9:55 am
by rogerborg
HydroNom wrote:It seems that I'm currently mathematical disabled a little bit. I have load a 3D object and can show it. Additionally I have 2 vectors (normalized) which defines the rotation of this object. The first vector is the direction of the objects X axis, the second is it's normale vector (matches the direction of the Y axis) For example: v1(-1.0,0,0) v2(0,1.0,0) which defines the objects x axis directs into the opposite to the world x axis

How can I calculate the angles for setRotation function of a scene node object from this?
It's not massively intuitive, but vector3df::getHorizontalAngle() will get you the required Y and X rotations.

Code: Select all

	vector3df const masterVector(vector3df(-1, -2, -3).normalize());
	vector3df const rotations = masterVector.getHorizontalAngle();

	matrix4 mat;
	mat.setRotationDegrees(rotations);

	vector3df slaveVector(0, 0, 1);
	mat.rotateVect(slaveVector);

	assert(masterVector == slaveVector);
Some things to note:

Irrlicht maths uses the common idiom that +Z is forwards, i.e. rotations are relative to (0, 0, 1).

The up vector (what you called the "normale") has no part in this calculation, since a direction vector can be defined by only two rotations (Y then X in this case).

Posted: Thu Jul 10, 2008 12:16 pm
by HydroNom
Unitl the getHorizontalAngle() I can follow you. With the Up-vector I have a problem to understand. What do you mean with "The up vector has no part in this calculation"? How can it be a part?

Posted: Thu Jul 10, 2008 12:36 pm
by rogerborg
Urgh, I'm sorry. I pulled a JP and didn't read your question fully. Of course you need X, Y and Z rotations. To get those, you just have to... uh... wait... I know this...

EPIC FAIL.

OK, hopefully someone else will know this or figure it out, but I don't see a general solution. I'm going to continue to assume that "direction" is based on +Z, not +X.

The X (pitch) and Y (yaw) rotations are sufficient to express the direction vector. That leaves the Z (roll) rotation to express the required up vector. However, there's no guarantee that the up vector is perpendicular to the direction vector, so there's no Z rotation that's guaranteed to produce it. I therefore can't solve for Z. I'm a Scotsman, not a mathematician, dammit!

Posted: Thu Jul 10, 2008 1:16 pm
by JP
Hey! F*** you buddy! xD

Epic fail indeed! :lol:

Posted: Thu Jul 10, 2008 3:44 pm
by rogerborg
Oh my SHATNER, I think I sprained my brain.

If I project the up vector so that it's always orthogonal to the direction, then I can get Eulers from it. It's... not pretty.

Code: Select all

#include <irrlicht.h>
#include <assert.h>

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

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;


void createRotations(vector3df const & fromDirection,
					 vector3df const & fromUp,
					 ISceneNode * testNode)
{
	vector3df masterDirection(fromDirection);
	masterDirection.normalize();

	vector3df masterUp(fromUp);
	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.  
	
	// Now let's test them.	
	testNode->setRotation(eulers);
	testNode->updateAbsolutePosition();
	mat = testNode->getAbsoluteTransformation();

	vector3df slaveDirection(0, 0, 1);
	mat.rotateVect(slaveDirection);

	vector3df slaveUp(0, 1, 0);
	mat.rotateVect(slaveUp);

	(void)printf("\nEulers %.2f %.2f %.2f\n",
		eulers.X, eulers.Y, eulers.Z);
	(void)printf("From dir %.2f %.2f %.2f, up %.2f %.2f %.2f\n",
		masterDirection.X, masterDirection.Y, masterDirection.Z, 
		realUp.X, realUp.Y, realUp.Z);
	(void)printf("  to dir %.2f %.2f %.2f, up %.2f %.2f %.2f\n",
		slaveDirection.X, slaveDirection.Y, slaveDirection.Z, 
		slaveUp.X, slaveUp.Y, slaveUp.Z);

	(void)printf("           %s                      %s\n",
			masterDirection == slaveDirection ? "PASS" : "FAIL",
			realUp == slaveUp ? "PASS" : "FAIL");
}

int main()
{
	IrrlichtDevice* device = createDevice(EDT_NULL);
	ISceneManager* smgr = device->getSceneManager();
	ISceneNode * node = smgr->addEmptySceneNode();

	createRotations(vector3df(0, 0, 1), vector3df(0, 1, 1), node);
	createRotations(vector3df(1, 0, 0), vector3df(0, 1, 0), node);
	createRotations(vector3df(1, 0, 1), vector3df(0, 1, 1), node);
	createRotations(vector3df(1, 0, 1), vector3df(1, 0, -1), node);
	createRotations(vector3df(-1, 0, -1), vector3df(-1, -2, -3), node);
	createRotations(vector3df(0, 1, 1), vector3df(1, 0, 0), node);
	createRotations(vector3df(0, 1, 1), vector3df(0, 1, 0), node);
	createRotations(vector3df(1, 1, 1), vector3df(-1, 1, -1), node);
	createRotations(vector3df(3, 4, 5), vector3df(-2, 4, -6), node);

	device->drop();
    return 0;
} 
Seriously, I need to go and have a lie down.

In the meantime, doubtless hybrid or Vitek will rewrite the above in 3 lines, find a degenerate case, or point out that I misunderstood the problem (again).

Going to a dark room now.

Dumped in code snippets.