\r
//! Set this matrix to the product of two matrices\r
/** Calculate b*a, no optimization used,\r
- use it if you know you never have a identity matrix */\r
+ use it if you know you never have an identity matrix */\r
CMatrix4<T>& setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );\r
\r
//! Multiply by another matrix.\r
CMatrix4<T> operator*(const CMatrix4<T>& other) const;\r
\r
//! Multiply by another matrix.\r
- /** Calculate and return other*this */\r
+ /** Like calling: (*this) = (*this) * other \r
+ */\r
CMatrix4<T>& operator*=(const CMatrix4<T>& other);\r
\r
//! Multiply by scalar.\r
//! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.\r
CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation );\r
\r
- //! Get the rotation, as set by setRotation() when you already know the scale.\r
- /** If you already know the scale then this function is faster than the other getRotationDegrees overload.\r
- NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.\r
+ //! Get the rotation, as set by setRotation() when you already know the scale used to create the matrix\r
+ /** NOTE: The scale needs to be the correct one used to create this matrix.\r
+ You can _not_ use the result of getScale(), but have to save your scale \r
+ variable in another place (like ISceneNode does).\r
+ NOTE: No scale value can be 0 or the result is undefined.\r
+ NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(), \r
+ but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.\r
+ NOTE: It will (usually) give wrong results when further transformations have been added in the matrix (like shear).\r
+ WARNING: There have been troubles with this function over the years and we may still have missed some corner cases.\r
+ It's generally safer to keep the rotation and scale you used to create the matrix around and work with those.\r
*/\r
core::vector3d<T> getRotationDegrees(const vector3d<T>& scale) const;\r
\r
//! Returns the rotation, as set by setRotation().\r
/** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.\r
+ NOTE: This only works correct if no other matrix operations have been done on the inner 3x3 matrix besides \r
+ setting rotation (so no scale/shear). Thought it (probably) works as long as scale doesn't flip handedness.\r
+ NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(), \r
+ but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.\r
*/\r
core::vector3d<T> getRotationDegrees() const;\r
\r
\r
//! Returns the absolute values of the scales of the matrix.\r
/**\r
- Note that this returns the absolute (positive) values unless only scale is set.\r
- Unfortunately it does not appear to be possible to extract any original negative\r
- values. The best that we could do would be to arbitrarily make one scale\r
- negative if one or three of them were negative.\r
- FIXME - return the original values.\r
+ Note: You only get back original values if the matrix only set the scale.\r
+ Otherwise the result is a scale you can use to normalize the matrix axes,\r
+ but it's usually no longer what you did set with setScale.\r
*/\r
template <class T>\r
inline vector3d<T> CMatrix4<T>::getScale() const\r
}\r
\r
\r
- //! Returns a rotation that is equivalent to that set by setRotationDegrees().\r
- /** This code was sent in by Chev. Note that it does not necessarily return\r
- the *same* Euler angles as those set by setRotationDegrees(), but the rotation will\r
- be equivalent, i.e. will have the same result when used to rotate a vector or node.\r
- This code was originally written by by Chev.\r
+ //! Returns a rotation which (mostly) works in combination with the given scale\r
+ /** \r
+ This code was originally written by by Chev (assuming no scaling back then, \r
+ we can be blamed for all problems added by regarding scale)\r
*/\r
template <class T>\r
inline core::vector3d<T> CMatrix4<T>::getRotationDegrees(const vector3d<T>& scale_) const\r
{\r
const CMatrix4<T> &mat = *this;\r
- core::vector3d<T> scale(scale_);\r
- // we need to check for negative scale on to axes, which would bring up wrong results\r
- if (scale.Y<0 && scale.Z<0)\r
- {\r
- scale.Y =-scale.Y;\r
- scale.Z =-scale.Z;\r
- }\r
- else if (scale.X<0 && scale.Z<0)\r
- {\r
- scale.X =-scale.X;\r
- scale.Z =-scale.Z;\r
- }\r
- else if (scale.X<0 && scale.Y<0)\r
- {\r
- scale.X =-scale.X;\r
- scale.Y =-scale.Y;\r
- }\r
+ const core::vector3d<f64> scale(core::iszero(scale_.X) ? FLT_MAX : scale_.X , core::iszero(scale_.Y) ? FLT_MAX : scale_.Y, core::iszero(scale_.Z) ? FLT_MAX : scale_.Z);\r
const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z));\r
\r
f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0));\r
\r
f64 rotx, roty, X, Z;\r
\r
- if (!core::iszero(C))\r
+ if (!core::iszero((T)C))\r
{\r
const f64 invC = core::reciprocal(C);\r
rotx = mat[10] * invC * invScale.Z;\r
}\r
\r
//! Returns a rotation that is equivalent to that set by setRotationDegrees().\r
- /** This code was sent in by Chev. Note that it does not necessarily return\r
- the *same* Euler angles as those set by setRotationDegrees(), but the rotation will\r
- be equivalent, i.e. will have the same result when used to rotate a vector or node.\r
- This code was originally written by by Chev. */\r
template <class T>\r
inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const\r
{\r
- return getRotationDegrees(getScale());\r
+ // Note: Using getScale() here make it look like it could do matrix decomposition. \r
+ // It can't! It works (or should work) as long as rotation doesn't flip the handedness \r
+ // aka scale swapping 1 or 3 axes. (I think we could catch that as well by comparing \r
+ // crossproduct of first 2 axes to direction of third axis, but TODO)\r
+ // And maybe it should also offer the solution for the simple calculation \r
+ // without regarding scaling as Irrlicht did before 1.7\r
+ core::vector3d<T> scale(getScale());\r
+\r
+ // We assume the matrix uses rotations instead of negative scaling 2 axes.\r
+ // Otherwise it fails even for some simple cases, like rotating around \r
+ // 2 axes by 180° which getScale thinks is a negative scaling.\r
+ if (scale.Y<0 && scale.Z<0)\r
+ {\r
+ scale.Y =-scale.Y;\r
+ scale.Z =-scale.Z;\r
+ }\r
+ else if (scale.X<0 && scale.Z<0)\r
+ {\r
+ scale.X =-scale.X;\r
+ scale.Z =-scale.Z;\r
+ }\r
+ else if (scale.X<0 && scale.Y<0)\r
+ {\r
+ scale.X =-scale.X;\r
+ scale.Y =-scale.Y;\r
+ }\r
+\r
+ return getRotationDegrees(scale);\r
}\r
\r
\r