Suggested addition: vector3d<T>::rotationToDirection()

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Suggested addition: vector3d<T>::rotationToDirection()

Post by rogerborg »

One of the FAQs is "how do I create a direction (vector) from a rotation?"

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. */
Test app, that demonstrates that the method produces the same result as performing the rotation via matrix4.

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
}

Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

You're the best!

Can you explain please why didn't you use matrix4? I assumed from the other thread it would be as simple as those 3-4 lines using matrix::rotateVect() but it seems you did something else (similar ?). Is it more efficient?

Thanks! Another great addition by you.
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

matrix4<T> uses vector3d<T>, and they both inline all their functionality in their headers. To use matrix4 from a vector3d method, we'd have to introduce a vector3d.cpp file.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

rogerborg wrote:matrix4<T> uses vector3d<T>, and they both inline all their functionality in their headers. To use matrix4 from a vector3d method, we'd have to introduce a vector3d.cpp file.
:shock: Didn't had a clue that was the problem. Wow..

Cool - Thanks.
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Post Reply