diff --git a/changes.txt b/changes.txt index f6fbfc03..daa16e6c 100644 --- a/changes.txt +++ b/changes.txt @@ -1,5 +1,10 @@ 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. - Colladawriter now exports materials per node when those are used in Irrlicht diff --git a/include/IAnimatedMeshMD3.h b/include/IAnimatedMeshMD3.h index 0ff544a8..a9937620 100644 --- a/include/IAnimatedMeshMD3.h +++ b/include/IAnimatedMeshMD3.h @@ -166,10 +166,6 @@ namespace scene SMD3QuaternionTag( const core::stringc& 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 SMD3QuaternionTag ( const core::vector3df &pos, const core::vector3df &angle ) : position(pos), rotation(angle * core::DEGTORAD) {} diff --git a/include/quaternion.h b/include/quaternion.h index 76902f8c..5a0fed11 100644 --- a/include/quaternion.h +++ b/include/quaternion.h @@ -10,6 +10,11 @@ #include "matrix4.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 core @@ -34,8 +39,10 @@ class quaternion //! Constructor which converts euler angles (radians) to a quaternion quaternion(const vector3df& vec); +#if !IRR_TEST_BROKEN_QUATERNION_USE //! Constructor which converts a matrix to a quaternion quaternion(const matrix4& mat); +#endif //! Equalilty operator bool operator==(const quaternion& other) const; @@ -46,8 +53,10 @@ class quaternion //! Assignment operator inline quaternion& operator=(const quaternion& other); +#if !IRR_TEST_BROKEN_QUATERNION_USE //! Matrix assignment operator inline quaternion& operator=(const matrix4& other); +#endif //! Add operator quaternion operator+(const quaternion& other) const; @@ -89,8 +98,10 @@ class quaternion //! Normalizes the quaternion inline quaternion& normalize(); +#if !IRR_TEST_BROKEN_QUATERNION_USE //! Creates a matrix from this quaternion matrix4 getMatrix() const; +#endif //! Creates a matrix from this quaternion void getMatrix( matrix4 &dest, const core::vector3df &translation ) const; @@ -185,13 +196,13 @@ inline quaternion::quaternion(const vector3df& vec) set(vec.X,vec.Y,vec.Z); } - +#if !IRR_TEST_BROKEN_QUATERNION_USE // Constructor which converts a matrix to a quaternion inline quaternion::quaternion(const matrix4& mat) { (*this) = mat; } - +#endif // equal operator inline bool quaternion::operator==(const quaternion& other) const @@ -218,7 +229,7 @@ inline quaternion& quaternion::operator=(const quaternion& other) return *this; } - +#if !IRR_TEST_BROKEN_QUATERNION_USE // matrix assignment operator 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 // TODO: speed this up - X = ( m(2,1) - m(1,2)) / scale; - Y = ( m(0,2) - m(2,0)) / scale; - Z = ( m(1,0) - m(0,1)) / scale; + X = ( m(1,2) - m(2,1)) / scale; + Y = ( m(2,0) - m(0,2)) / scale; + Z = ( m(0,1) - m(1,0)) / scale; W = 0.25f * scale; } else @@ -244,9 +255,9 @@ inline quaternion& quaternion::operator=(const matrix4& m) // TODO: speed this up X = 0.25f * scale; - Y = (m(0,1) + m(1,0)) / scale; - Z = (m(2,0) + m(0,2)) / scale; - W = (m(2,1) - m(1,2)) / scale; + Y = (m(1,0) + m(0,1)) / scale; + Z = (m(0,2) + m(2,0)) / scale; + W = (m(1,2) - m(2,1)) / scale; } else if ( m(1,1) > m(2,2)) { @@ -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; // TODO: speed this up - X = (m(0,1) + m(1,0) ) / scale; + X = (m(1,0) + m(0,1) ) / scale; Y = 0.25f * scale; - Z = (m(1,2) + m(2,1) ) / scale; - W = (m(0,2) - m(2,0) ) / scale; + Z = (m(2,1) + m(1,2) ) / scale; + W = (m(2,0) - m(0,2) ) / scale; } else { @@ -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; // TODO: speed this up - X = (m(0,2) + m(2,0)) / scale; - Y = (m(1,2) + m(2,1)) / scale; + X = (m(2,0) + m(0,2)) / scale; + Y = (m(2,1) + m(1,2)) / scale; Z = 0.25f * scale; - W = (m(1,0) - m(0,1)) / scale; + W = (m(0,1) - m(1,0)) / scale; } } return normalize(); } - +#endif // multiplication operator inline quaternion quaternion::operator*(const quaternion& other) 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); } - +#if !IRR_TEST_BROKEN_QUATERNION_USE // Creates a matrix from this quaternion inline matrix4 quaternion::getMatrix() const { core::matrix4 m; - getMatrix_transposed(m); + getMatrix(m, core::vector3df(0,0,0)); return m; } - +#endif /*! Creates a matrix from this quaternion diff --git a/source/Irrlicht/CB3DMeshFileLoader.cpp b/source/Irrlicht/CB3DMeshFileLoader.cpp index c1798161..fd4df43a 100644 --- a/source/Irrlicht/CB3DMeshFileLoader.cpp +++ b/source/Irrlicht/CB3DMeshFileLoader.cpp @@ -177,7 +177,8 @@ bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint) positionMatrix.setTranslation( joint->Animatedposition ); core::matrix4 scaleMatrix; scaleMatrix.setScale( joint->Animatedscale ); - core::matrix4 rotationMatrix = joint->Animatedrotation.getMatrix(); + core::matrix4 rotationMatrix; + joint->Animatedrotation.getMatrix_transposed(rotationMatrix); joint->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix; diff --git a/source/Irrlicht/CMS3DMeshFileLoader.cpp b/source/Irrlicht/CMS3DMeshFileLoader.cpp index ed112073..558c4bfa 100644 --- a/source/Irrlicht/CMS3DMeshFileLoader.cpp +++ b/source/Irrlicht/CMS3DMeshFileLoader.cpp @@ -501,7 +501,9 @@ bool CMS3DMeshFileLoader::load(io::IReadFile* file) 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 diff --git a/source/Irrlicht/COgreMeshFileLoader.cpp b/source/Irrlicht/COgreMeshFileLoader.cpp index 063d67a7..97bf7504 100644 --- a/source/Irrlicht/COgreMeshFileLoader.cpp +++ b/source/Irrlicht/COgreMeshFileLoader.cpp @@ -773,7 +773,10 @@ void COgreMeshFileLoader::composeObject(void) ISkinnedMesh::SJoint* joint = m->addJoint(); 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)) { core::matrix4 scaleMatrix; @@ -823,7 +826,11 @@ void COgreMeshFileLoader::composeObject(void) poskey->position=keyjoint->LocalMatrix.getTranslation()+frame.Position; ISkinnedMesh::SRotationKey* rotkey = m->addRotationKey(keyjoint); 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); scalekey->frame=frame.Time*25; scalekey->scale=frame.Scale; diff --git a/source/Irrlicht/CSkinnedMesh.cpp b/source/Irrlicht/CSkinnedMesh.cpp index 915fcbf8..98b92108 100644 --- a/source/Irrlicht/CSkinnedMesh.cpp +++ b/source/Irrlicht/CSkinnedMesh.cpp @@ -167,7 +167,9 @@ void CSkinnedMesh::buildAllLocalAnimatedMatrices() { 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() --- f32 *m1 = joint->LocalAnimatedMatrix.pointer(); diff --git a/source/Irrlicht/CXMeshFileLoader.cpp b/source/Irrlicht/CXMeshFileLoader.cpp index 0629cbd6..a40bb677 100644 --- a/source/Irrlicht/CXMeshFileLoader.cpp +++ b/source/Irrlicht/CXMeshFileLoader.cpp @@ -1877,8 +1877,10 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->addRotationKey(joint); 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); keyP->frame=time;