This code isn't pretty, but it works for my test cases. Improvements are welcome.
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;
}