Commit 26f44f6f authored by cutealien's avatar cutealien

quaternion conversions to and from matrix4 no longer invert rotations. Define...

quaternion conversions to and from matrix4 no longer invert rotations. Define IRR_TEST_BROKEN_QUATERNION_USE in quaternion.h allows compile-tests to find affected code (see changes.txt for more info). Loaders for b3d, ms3d, ogre and .X just use transposed matrixes now for downward compatibility - meaning if it worked before it still works - if it was broken before it's still broken. Same for CSkinnedMesh. For collada (.dae) loader this fixed previously wrong rotations.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4276 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 1cc1271e
Changes in 1.8 (??.??.2011) Changes in 1.8 (??.??.2011)
- quaternion conversions to and from matrix4 no longer invert rotations.
To test if your code was affected by this you can set IRR_TEST_BROKEN_QUATERNION_USE in quaternion.h and try to compile your application.
Then on all compile-errors when you pass the matrix to the quaternion you can replace the matrix transposed matrix.
For all errors you get on getMatrix() you can use quaternion::getMatrix_transposed instead.
- CGUIEnvironment::loadGui - loading a gui into a target-element no longer messes up when the gui-file contained guienvironment serialization. - CGUIEnvironment::loadGui - loading a gui into a target-element no longer messes up when the gui-file contained guienvironment serialization.
- Colladawriter now exports materials per node when those are used in Irrlicht - Colladawriter now exports materials per node when those are used in Irrlicht
......
...@@ -166,10 +166,6 @@ namespace scene ...@@ -166,10 +166,6 @@ namespace scene
SMD3QuaternionTag( const core::stringc& name ) SMD3QuaternionTag( const core::stringc& name )
: Name ( name ) {} : Name ( name ) {}
// construct from a matrix
SMD3QuaternionTag ( const core::stringc& name, const core::matrix4 &m )
: Name(name), position(m.getTranslation()), rotation(m) {}
// construct from a position and euler angles in degrees // construct from a position and euler angles in degrees
SMD3QuaternionTag ( const core::vector3df &pos, const core::vector3df &angle ) SMD3QuaternionTag ( const core::vector3df &pos, const core::vector3df &angle )
: position(pos), rotation(angle * core::DEGTORAD) {} : position(pos), rotation(angle * core::DEGTORAD) {}
......
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
#include "matrix4.h" #include "matrix4.h"
#include "vector3d.h" #include "vector3d.h"
// Between Irrlicht 1.7 and Irrlicht 1.8 the quaternion-matrix conversions got fixed.
// This define disables all involved functions completely to allow finding all places
// where the wrong conversions had been in use.
#define IRR_TEST_BROKEN_QUATERNION_USE 0
namespace irr namespace irr
{ {
namespace core namespace core
...@@ -34,8 +39,10 @@ class quaternion ...@@ -34,8 +39,10 @@ class quaternion
//! Constructor which converts euler angles (radians) to a quaternion //! Constructor which converts euler angles (radians) to a quaternion
quaternion(const vector3df& vec); quaternion(const vector3df& vec);
#if !IRR_TEST_BROKEN_QUATERNION_USE
//! Constructor which converts a matrix to a quaternion //! Constructor which converts a matrix to a quaternion
quaternion(const matrix4& mat); quaternion(const matrix4& mat);
#endif
//! Equalilty operator //! Equalilty operator
bool operator==(const quaternion& other) const; bool operator==(const quaternion& other) const;
...@@ -46,8 +53,10 @@ class quaternion ...@@ -46,8 +53,10 @@ class quaternion
//! Assignment operator //! Assignment operator
inline quaternion& operator=(const quaternion& other); inline quaternion& operator=(const quaternion& other);
#if !IRR_TEST_BROKEN_QUATERNION_USE
//! Matrix assignment operator //! Matrix assignment operator
inline quaternion& operator=(const matrix4& other); inline quaternion& operator=(const matrix4& other);
#endif
//! Add operator //! Add operator
quaternion operator+(const quaternion& other) const; quaternion operator+(const quaternion& other) const;
...@@ -89,8 +98,10 @@ class quaternion ...@@ -89,8 +98,10 @@ class quaternion
//! Normalizes the quaternion //! Normalizes the quaternion
inline quaternion& normalize(); inline quaternion& normalize();
#if !IRR_TEST_BROKEN_QUATERNION_USE
//! Creates a matrix from this quaternion //! Creates a matrix from this quaternion
matrix4 getMatrix() const; matrix4 getMatrix() const;
#endif
//! Creates a matrix from this quaternion //! Creates a matrix from this quaternion
void getMatrix( matrix4 &dest, const core::vector3df &translation ) const; void getMatrix( matrix4 &dest, const core::vector3df &translation ) const;
...@@ -185,13 +196,13 @@ inline quaternion::quaternion(const vector3df& vec) ...@@ -185,13 +196,13 @@ inline quaternion::quaternion(const vector3df& vec)
set(vec.X,vec.Y,vec.Z); set(vec.X,vec.Y,vec.Z);
} }
#if !IRR_TEST_BROKEN_QUATERNION_USE
// Constructor which converts a matrix to a quaternion // Constructor which converts a matrix to a quaternion
inline quaternion::quaternion(const matrix4& mat) inline quaternion::quaternion(const matrix4& mat)
{ {
(*this) = mat; (*this) = mat;
} }
#endif
// equal operator // equal operator
inline bool quaternion::operator==(const quaternion& other) const inline bool quaternion::operator==(const quaternion& other) const
...@@ -218,7 +229,7 @@ inline quaternion& quaternion::operator=(const quaternion& other) ...@@ -218,7 +229,7 @@ inline quaternion& quaternion::operator=(const quaternion& other)
return *this; return *this;
} }
#if !IRR_TEST_BROKEN_QUATERNION_USE
// matrix assignment operator // matrix assignment operator
inline quaternion& quaternion::operator=(const matrix4& m) inline quaternion& quaternion::operator=(const matrix4& m)
{ {
...@@ -229,9 +240,9 @@ inline quaternion& quaternion::operator=(const matrix4& m) ...@@ -229,9 +240,9 @@ inline quaternion& quaternion::operator=(const matrix4& m)
const f32 scale = sqrtf(diag) * 2.0f; // get scale from diagonal const f32 scale = sqrtf(diag) * 2.0f; // get scale from diagonal
// TODO: speed this up // TODO: speed this up
X = ( m(2,1) - m(1,2)) / scale; X = ( m(1,2) - m(2,1)) / scale;
Y = ( m(0,2) - m(2,0)) / scale; Y = ( m(2,0) - m(0,2)) / scale;
Z = ( m(1,0) - m(0,1)) / scale; Z = ( m(0,1) - m(1,0)) / scale;
W = 0.25f * scale; W = 0.25f * scale;
} }
else else
...@@ -244,9 +255,9 @@ inline quaternion& quaternion::operator=(const matrix4& m) ...@@ -244,9 +255,9 @@ inline quaternion& quaternion::operator=(const matrix4& m)
// TODO: speed this up // TODO: speed this up
X = 0.25f * scale; X = 0.25f * scale;
Y = (m(0,1) + m(1,0)) / scale; Y = (m(1,0) + m(0,1)) / scale;
Z = (m(2,0) + m(0,2)) / scale; Z = (m(0,2) + m(2,0)) / scale;
W = (m(2,1) - m(1,2)) / scale; W = (m(1,2) - m(2,1)) / scale;
} }
else if ( m(1,1) > m(2,2)) else if ( m(1,1) > m(2,2))
{ {
...@@ -255,10 +266,10 @@ inline quaternion& quaternion::operator=(const matrix4& m) ...@@ -255,10 +266,10 @@ inline quaternion& quaternion::operator=(const matrix4& m)
const f32 scale = sqrtf( 1.0f + m(1,1) - m(0,0) - m(2,2)) * 2.0f; const f32 scale = sqrtf( 1.0f + m(1,1) - m(0,0) - m(2,2)) * 2.0f;
// TODO: speed this up // TODO: speed this up
X = (m(0,1) + m(1,0) ) / scale; X = (m(1,0) + m(0,1) ) / scale;
Y = 0.25f * scale; Y = 0.25f * scale;
Z = (m(1,2) + m(2,1) ) / scale; Z = (m(2,1) + m(1,2) ) / scale;
W = (m(0,2) - m(2,0) ) / scale; W = (m(2,0) - m(0,2) ) / scale;
} }
else else
{ {
...@@ -267,16 +278,16 @@ inline quaternion& quaternion::operator=(const matrix4& m) ...@@ -267,16 +278,16 @@ inline quaternion& quaternion::operator=(const matrix4& m)
const f32 scale = sqrtf( 1.0f + m(2,2) - m(0,0) - m(1,1)) * 2.0f; const f32 scale = sqrtf( 1.0f + m(2,2) - m(0,0) - m(1,1)) * 2.0f;
// TODO: speed this up // TODO: speed this up
X = (m(0,2) + m(2,0)) / scale; X = (m(2,0) + m(0,2)) / scale;
Y = (m(1,2) + m(2,1)) / scale; Y = (m(2,1) + m(1,2)) / scale;
Z = 0.25f * scale; Z = 0.25f * scale;
W = (m(1,0) - m(0,1)) / scale; W = (m(0,1) - m(1,0)) / scale;
} }
} }
return normalize(); return normalize();
} }
#endif
// multiplication operator // multiplication operator
inline quaternion quaternion::operator*(const quaternion& other) const inline quaternion quaternion::operator*(const quaternion& other) const
...@@ -320,15 +331,15 @@ inline quaternion quaternion::operator+(const quaternion& b) const ...@@ -320,15 +331,15 @@ inline quaternion quaternion::operator+(const quaternion& b) const
return quaternion(X+b.X, Y+b.Y, Z+b.Z, W+b.W); return quaternion(X+b.X, Y+b.Y, Z+b.Z, W+b.W);
} }
#if !IRR_TEST_BROKEN_QUATERNION_USE
// Creates a matrix from this quaternion // Creates a matrix from this quaternion
inline matrix4 quaternion::getMatrix() const inline matrix4 quaternion::getMatrix() const
{ {
core::matrix4 m; core::matrix4 m;
getMatrix_transposed(m); getMatrix(m, core::vector3df(0,0,0));
return m; return m;
} }
#endif
/*! /*!
Creates a matrix from this quaternion Creates a matrix from this quaternion
......
...@@ -177,7 +177,8 @@ bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint) ...@@ -177,7 +177,8 @@ bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint)
positionMatrix.setTranslation( joint->Animatedposition ); positionMatrix.setTranslation( joint->Animatedposition );
core::matrix4 scaleMatrix; core::matrix4 scaleMatrix;
scaleMatrix.setScale( joint->Animatedscale ); scaleMatrix.setScale( joint->Animatedscale );
core::matrix4 rotationMatrix = joint->Animatedrotation.getMatrix(); core::matrix4 rotationMatrix;
joint->Animatedrotation.getMatrix_transposed(rotationMatrix);
joint->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix; joint->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix;
......
...@@ -501,7 +501,9 @@ bool CMS3DMeshFileLoader::load(io::IReadFile* file) ...@@ -501,7 +501,9 @@ bool CMS3DMeshFileLoader::load(io::IReadFile* file)
tmpMatrix=jnt->LocalMatrix*tmpMatrix; tmpMatrix=jnt->LocalMatrix*tmpMatrix;
k->rotation = core::quaternion(tmpMatrix); // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from tmpMatrix to tmpMatrix.getTransposed() for downward compatibility.
// Not tested so far if this was correct or wrong before quaternion fix!
k->rotation = core::quaternion(tmpMatrix.getTransposed());
} }
// get translation keyframes // get translation keyframes
......
...@@ -773,7 +773,10 @@ void COgreMeshFileLoader::composeObject(void) ...@@ -773,7 +773,10 @@ void COgreMeshFileLoader::composeObject(void)
ISkinnedMesh::SJoint* joint = m->addJoint(); ISkinnedMesh::SJoint* joint = m->addJoint();
joint->Name=Skeleton.Bones[i].Name; joint->Name=Skeleton.Bones[i].Name;
joint->LocalMatrix = Skeleton.Bones[i].Orientation.getMatrix(); // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility.
// Not tested so far if this was correct or wrong before quaternion fix!
Skeleton.Bones[i].Orientation.getMatrix_transposed(joint->LocalMatrix);
if (Skeleton.Bones[i].Scale != core::vector3df(1,1,1)) if (Skeleton.Bones[i].Scale != core::vector3df(1,1,1))
{ {
core::matrix4 scaleMatrix; core::matrix4 scaleMatrix;
...@@ -823,7 +826,11 @@ void COgreMeshFileLoader::composeObject(void) ...@@ -823,7 +826,11 @@ void COgreMeshFileLoader::composeObject(void)
poskey->position=keyjoint->LocalMatrix.getTranslation()+frame.Position; poskey->position=keyjoint->LocalMatrix.getTranslation()+frame.Position;
ISkinnedMesh::SRotationKey* rotkey = m->addRotationKey(keyjoint); ISkinnedMesh::SRotationKey* rotkey = m->addRotationKey(keyjoint);
rotkey->frame=frame.Time*25; rotkey->frame=frame.Time*25;
rotkey->rotation=core::quaternion(keyjoint->LocalMatrix)*frame.Orientation;
// IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from keyjoint->LocalMatrix to keyjoint->LocalMatrix.getTransposed() for downward compatibility.
// Not tested so far if this was correct or wrong before quaternion fix!
rotkey->rotation=core::quaternion(keyjoint->LocalMatrix.getTransposed())*frame.Orientation;
ISkinnedMesh::SScaleKey* scalekey = m->addScaleKey(keyjoint); ISkinnedMesh::SScaleKey* scalekey = m->addScaleKey(keyjoint);
scalekey->frame=frame.Time*25; scalekey->frame=frame.Time*25;
scalekey->scale=frame.Scale; scalekey->scale=frame.Scale;
......
...@@ -167,7 +167,9 @@ void CSkinnedMesh::buildAllLocalAnimatedMatrices() ...@@ -167,7 +167,9 @@ void CSkinnedMesh::buildAllLocalAnimatedMatrices()
{ {
joint->GlobalSkinningSpace=false; joint->GlobalSkinningSpace=false;
joint->LocalAnimatedMatrix=joint->Animatedrotation.getMatrix(); // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility.
// Not tested so far if this was correct or wrong before quaternion fix!
joint->Animatedrotation.getMatrix_transposed(joint->LocalAnimatedMatrix);
// --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() --- // --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() ---
f32 *m1 = joint->LocalAnimatedMatrix.pointer(); f32 *m1 = joint->LocalAnimatedMatrix.pointer();
......
...@@ -1877,8 +1877,10 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) ...@@ -1877,8 +1877,10 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint)
ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->addRotationKey(joint); ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->addRotationKey(joint);
keyR->frame=time; keyR->frame=time;
keyR->rotation= core::quaternion(mat);
// IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility.
// Not tested so far if this was correct or wrong before quaternion fix!
keyR->rotation= core::quaternion(mat.getTransposed());
ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->addPositionKey(joint); ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->addPositionKey(joint);
keyP->frame=time; keyP->frame=time;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment