From 79c1fb531dfea4a745090c8b5a21401350eccc72 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 12 Dec 2001 15:09:11 +0000 Subject: [PATCH] Fixed problems with osg::Matrix::makeRot(from,to) and osg::Quat::makeRot(from,to) so that they both use the same implementation (the Quat code now) and the code has been corrected to work from and to vectors which directly opposite to one another. --- src/osg/Matrix.cpp | 78 +++++++++------------------------------------- src/osg/Quat.cpp | 46 ++++++++++++++------------- 2 files changed, 38 insertions(+), 86 deletions(-) diff --git a/src/osg/Matrix.cpp b/src/osg/Matrix.cpp index 8c501c63d..0d26b48e6 100644 --- a/src/osg/Matrix.cpp +++ b/src/osg/Matrix.cpp @@ -159,79 +159,28 @@ void Matrix::makeTrans( float x, float y, float z ) void Matrix::makeRot( const Vec3& from, const Vec3& to ) { - double d = from * to; // dot product == cos( angle between from & to ) - if( d < 0.9999 ) { - double angle = acos(d); - // For right-handed rotations, cross product must be from x to, not - // to x from - //Vec3 axis = to ^ from; //we know ((to) x (from)) is perpendicular to both - Vec3 axis = from ^ to; //we know ((from) x (to)) is perpendicular to both - makeRot( inRadians(angle) , axis ); - } - else - makeIdent(); + Quat quat; + quat.makeRot(from,to); + quat.get(*this); } void Matrix::makeRot( float angle, const Vec3& axis ) { - makeRot( angle, axis.x(), axis.y(), axis.z() ); + Quat quat; + quat.makeRot( angle, axis); + quat.get(*this); } void Matrix::makeRot( float angle, float x, float y, float z ) { - float d = sqrt( x*x + y*y + z*z ); - if( d == 0 ) - return; - -#ifdef USE_DEGREES_INTERNALLY - angle = DEG2RAD(angle); -#endif - -#if 0 - float sin_half = sin( angle/2 ); - float cos_half = cos( angle/2 ); - - Quat q( sin_half * (x/d), - sin_half * (y/d), - sin_half * (z/d), - cos_half );//NOTE: original used a private quaternion made of doubles -#endif - Quat q; - q.makeRot( angle, x, y, z); - makeRot( q ); // but Quat stores the values in a Vec4 made of floats. + Quat quat; + quat.makeRot( angle, x, y, z); + quat.get(*this); } -void Matrix::makeRot( const Quat& q ) { - // taken from Shoemake/ACM SIGGRAPH 89 - Vec4 v = q.asVec4(); - - double xs = 2 * v.x(); //assume q is already normalized? assert? - double ys = 2 * v.y(); // if not, xs = 2 * v.x() / d, ys = 2 * v.y() / d - double zs = 2 * v.z(); // and zs = 2 * v.z() /d where d = v.length2() - - double xx = xs * v.x(); - double xy = ys * v.x(); - double xz = zs * v.x(); - double yy = ys * v.y(); - double yz = zs * v.y(); - double zz = zs * v.z(); - double wx = xs * v.w(); - double wy = ys * v.w(); - double wz = zs * v.w(); - -/* - * This is inverted - Don Burns - SET_ROW(0, 1.0-(yy+zz), xy - wz, xz + wy, 0.0 ) - SET_ROW(1, xy + wz, 1.0-(xx+zz),yz - wx, 0.0 ) - SET_ROW(2, xz - wy, yz + wx, 1.0-(xx+yy),0.0 ) - SET_ROW(3, 0.0, 0.0, 0.0, 1.0 ) - */ - - SET_ROW(0, 1.0-(yy+zz), xy + wz, xz - wy, 0.0 ) - SET_ROW(1, xy - wz, 1.0-(xx+zz),yz + wx, 0.0 ) - SET_ROW(2, xz + wy, yz - wx, 1.0-(xx+yy),0.0 ) - SET_ROW(3, 0.0, 0.0, 0.0, 1.0 ) - +void Matrix::makeRot( const Quat& q ) +{ + q.get(*this); fully_realized = true; } @@ -256,7 +205,8 @@ void Matrix::makeRot( float yaw, float pitch, float roll) cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); - makeRot( q ); + + q.get(*this); } void Matrix::mult( const Matrix& lhs, const Matrix& rhs ) diff --git a/src/osg/Quat.cpp b/src/osg/Quat.cpp index 4e13bfded..073b8f84b 100644 --- a/src/osg/Quat.cpp +++ b/src/osg/Quat.cpp @@ -42,15 +42,15 @@ void Quat::makeRot( const float angle, const Vec3& vec ) // and then use a cross product to get the rotation axis // Watch out for the two special cases of when the vectors // are co-incident or opposite in direction. -void Quat::makeRot( const Vec3& vec1, const Vec3& vec2 ) +void Quat::makeRot( const Vec3& from, const Vec3& to ) { const float epsilon = 0.00001f; - float length1 = vec1.length(); - float length2 = vec2.length(); + float length1 = from.length(); + float length2 = to.length(); // dot product vec1*vec2 - float cosangle = vec1*vec2/(length1*length2); + float cosangle = from*to/(length1*length2); if ( fabs(cosangle - 1) < epsilon ) { @@ -60,30 +60,32 @@ void Quat::makeRot( const Vec3& vec1, const Vec3& vec2 ) makeRot( 0.0, 1.0, 0.0, 0.0 ); } else -#if 0 /// This is broken and entirely unecessary. - Don Burns. - if ( fabs(cosangle + 1) < epsilon ) + if ( fabs(cosangle + 1.0) < epsilon ) { + // vectors are close to being opposite, so will need to find a + // vector orthongonal to from to rotate about. + osg::Vec3 tmp; + if (fabs(from.x()) biggest ) { biggest=fabs(vec1[1]); bigposn = 1; } - if ( fabs(vec1[2]) > biggest ) { biggest=fabs(vec1[2]); bigposn = 2; } - Vec3 temp = Vec3( 1.0, 1.0, 1.0 ); - temp[bigposn] = 0.0; - Vec3 axis = vec1^temp; // this is a cross-product to generate the - // axis around which to rotate - makeRot( (float)M_PI, axis ); } else -#endif { // This is the usual situation - take a cross-product of vec1 and vec2 // and that is the axis around which to rotate. - Vec3 axis = vec1^vec2; + Vec3 axis(from^to); float angle = acos( cosangle ); makeRot( angle, axis ); } @@ -224,7 +226,7 @@ void Quat::get( Matrix& m ) const // //http://www.gamasutra.com/features/programming/19980703/quaternions_01.htm - float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; + double wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; // calculate coefficients x2 = QX + QX;