It's simple enough to do it with a matrix, but how about a vector3d<T> method to do it on one operation? Ease of use, and all that.
The proposed solution basically cribs the set/perform rotation code from matrix4. It assumes that "direction" is relative to (0, 0, 1), but can be given a different "forwards" if required.
Code: Select all
Index: include/vector3d.h
===================================================================
--- include/vector3d.h (revision 1306)
+++ include/vector3d.h (working copy)
@@ -255,6 +255,58 @@
return angle;
}
+ //! Builds a direction vector from (this) rotation vector.
+ //! This vector is assumed to hold 3 Euler angle rotations, in degrees.
+ /**
+ \param[in] forwards The direction representing "forwards" which will be
+ rotated by this vector. If you do not provide a
+ direction, then the positive Z axis (0, 0, 1) will
+ be assumed to be fowards.
+ \return A vector calculated by rotating the forwards direction by
+ the 3 Euler angles that this vector is assumed to represent.
+ */
+ vector3d<T> rotationToDirection(const vector3d<T> & forwards = vector3d<T>(0, 0, 1))
+ {
+ // This implementation performs the same calculations as using a
+ // matrix to do the rotation.
+ f64 pseudoMatrix[9];
+
+ f64 cr = cos( core::DEGTORAD * X );
+ f64 sr = sin( core::DEGTORAD * X );
+ f64 cp = cos( core::DEGTORAD * Y );
+ f64 sp = sin( core::DEGTORAD * Y );
+ f64 cy = cos( core::DEGTORAD * Z );
+ f64 sy = sin( core::DEGTORAD * Z );
+
+ pseudoMatrix[0] = ( cp*cy );
+ pseudoMatrix[1] = ( cp*sy );
+ pseudoMatrix[2] = ( -sp );
+
+ f64 srsp = sr*sp;
+ f64 crsp = cr*sp;
+
+ pseudoMatrix[3] = ( srsp*cy-cr*sy );
+ pseudoMatrix[4] = ( srsp*sy+cr*cy );
+ pseudoMatrix[5] = ( sr*cp );
+
+ pseudoMatrix[6] = ( crsp*cy+sr*sy );
+ pseudoMatrix[7] = ( crsp*sy-sr*cy );
+ pseudoMatrix[8] = ( cr*cp );
+
+ vector3d<T> result;
+ result.X = (T)(forwards.X * pseudoMatrix[0] +
+ forwards.Y * pseudoMatrix[3] +
+ forwards.Z * pseudoMatrix[6]);
+ result.Y = (T)(forwards.X * pseudoMatrix[1] +
+ forwards.Y * pseudoMatrix[4] +
+ forwards.Z * pseudoMatrix[7]);
+ result.Z = (T)(forwards.X * pseudoMatrix[2] +
+ forwards.Y * pseudoMatrix[5] +
+ forwards.Z * pseudoMatrix[8]);
+
+ return result;
+ }
+
//! Fills an array of 4 values with the vector data (usually floats).
/** Useful for setting in shader constants for example. The fourth value
will always be 0. */
Code: Select all
#include <irrlicht.h>
#include <iostream>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
void testRotation(f32 X, f32 Y, f32 Z)
{
core::vector3df rotations(X, Y, Z);
core::vector3df direction = rotations.rotationToDirection();
(void)printf("%f %f %f == ", direction.X, direction.Y, direction.Z);
direction.set(0, 0, 1);
core::matrix4 matrix;
matrix.setRotationDegrees(rotations);
matrix.rotateVect(direction);
(void)printf("%f %f %f\n", direction.X, direction.Y, direction.Z);
core::vector3df forwards(1, 2, 3);
// Don't normalise the vector, as it should still work
direction = rotations.rotationToDirection(forwards);
(void)printf("%f %f %f == ", direction.X, direction.Y, direction.Z);
direction = forwards;
matrix.rotateVect(direction);
(void)printf("%f %f %f\n", direction.X, direction.Y, direction.Z);
}
int main()
{
testRotation(0, 0, 0);
testRotation(90, 0, 0);
testRotation(0, 90, 0);
testRotation(0, 0, 90);
testRotation(45, 45, 0);
testRotation(45, -45, 0);
testRotation(123, 132, 312);
return 0
}