btMatrix3x3 getEuler returning nan

Post Reply
conormcc
Posts: 6
Joined: Thu Apr 09, 2009 9:25 am

btMatrix3x3 getEuler returning nan

Post by conormcc »

Hey all,

I am trying to get the rotation/origin of my btRigidBodies in order to save game state.

Code: Select all

        btTransform transform;
        sBoxBodies[i]->getMotionState()->getWorldTransform(transform);
        
        btScalar yaw, pitch, roll;
        
        btMatrix3x3 mat = btMatrix3x3(transform.getRotation());
        mat.getEulerYPR(yaw, pitch, roll);

        NSLog(@"cube %d origin:%f,%f,%f rotation:%f,%f,%f", i, transform.getOrigin().getX(),transform.getOrigin().getY(),transform.getOrigin().getZ(),yaw,pitch,roll);
        
It seems to work fine mostly but every now and again I get a nan, usually in the pitch:

cube 4 origin:3.762772,-6.667145,5.960001 rotation:-1.631328,nan,-1.025141

Does anyone else get this? Is there a better way to store the details of a quaternion?

Thanks,
Conor
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: btMatrix3x3 getEuler returning nan

Post by Erwin Coumans »

Does it happen when you use

Code: Select all

const btMatrix3x3 mat& = transform.getBasis();
instead of convertion back/forward between matrix/quaternion?

btMatrix3x3::getEulerYPR might have issues.
Can you provide a small reproduction testbed, starting from one of the Bullet/Demos?

You can attach zip-files to this forum topic.
Thanks,
Erwin
conormcc
Posts: 6
Joined: Thu Apr 09, 2009 9:25 am

Re: btMatrix3x3 getEuler returning nan

Post by conormcc »

Thanks Erwin,

I will give transform.getBasis() a go and let you know. I will send you a test program when i get the chance to.

I had started to work around it by converting the matrix to an OpenGL float[] array (instead of getting the YPR) and just storing it in an NSData object.

Cheers,
Conor
conormcc
Posts: 6
Joined: Thu Apr 09, 2009 9:25 am

Re: btMatrix3x3 getEuler returning nan

Post by conormcc »

I thought using getBasis() solved the problem but I eventually got a nan, though it seems to have been a lot less common than before.

I've changed my implementation to:

Code: Select all

btScalar mat[15];
transform.getOpenGLMatrix(mat);
NSData *orientation = [NSData dataWithBytes:mat length:(sizeof(btScalar)*15)];
[defaults setObject: orientation forKey: orientationKey];
So far it seems to be working fine.

Cheers,
Conor
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: btMatrix3x3 getEuler returning nan

Post by Flix »

I recently got a problem with btMatrix3x3::setEuler(...). I know it's not exactly the argument of this thread, but maybe it's a part of the same topic.

Basically I've found out that with this code:
const btScalar yaw = btRadians(-145.0);
const btScalar pitch = btRadians(85.0);
const btScalar roll = btRadians(0.);

btMatrix3x3 m1,m2,m3;
m1.setEulerYPR(yaw,pitch,roll);
btQuaternion q = btQuaternion(yaw,pitch,roll); // ctr that calls btQuaternion::setEuler(...)
m2.setRotation(q);
m3.setEulerZYX(pitch,yaw,roll);
if we display the three matrices, we can notice that m1!=(m2==m3).
I discovered that m2 is the correct matrix (at list for my usage of it...): so
btMatrix3x3::setEulerYPR(...) must be wrong, while btQuaternion::setEuler(...) is correct. Also it's very strange that m2==m3, but it happens only when roll==0, so it's not advisable to replace the code inside btMatrix3x3::setEulerYPR(...) with this setEulerZYX(pitch,yaw,roll);.

I know, my contribution is very poor since it does not solve anything, but maybe sharing my experience can be useful to other.
secondwish
Posts: 11
Joined: Tue Sep 16, 2008 9:34 am

Re: btMatrix3x3 getEuler returning nan

Post by secondwish »

With Euler angle definition with Yaw Pitch And Roll is unfortunately dependent on your coordinate system setup. Actually there are about 8 or even more (32 i think) possibilities to define the euler angles (see wikipedia). It doesnt matter how, you just have to set it uop consitently in your system: I have once tried to figure this out for the bullet coordinate system - though this might be different from the one of you application -

The assumption is that the we are using tradiditional aerospace Yaw Pitch Roll (see http://de.wikipedia.org/w/index.php?tit ... 1231174938)

This means that setEulerZYX(r, p, y) is correct, assuming that btMatrix3x3::setEulerZYX is correct which is not for some angles (0 as mentioned by flix). It needs some rework on the 0 Angle I guess..





BTW: How is the opengl camera setup usually?
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: btMatrix3x3 getEuler returning nan

Post by Flix »

Here are some methods that can be used as an alternative to btMatrix3x3::getEulerYPR(...) and btMatrix3x3::setEulerYPR(...).
I'm not saying that they are better, they're just an alternative.

I've ported them Bullet from <OgreMatrix3.cpp> (these are for yaw around Y, pitch around X and roll around Z, normally used in both OpenGL and Ogre):

Code: Select all

// In my (single) test, this method created the same matrix than this Bullet code:
// btQuaternion q(fYAngle,fPAngle,fRAngle);	
// btMatrix3x3 m; m.setRotation(q);
// Maybe the code above is faster.
// P.S. btMatrix3x3::setEulerYPR(fYAngle,fPAngle,fRAngle) did not give me the same result (but I made only a single test)
SIMD_FORCE_INLINE static void FromEulerYXZ(btMatrix3x3& m,btScalar fYAngle,btScalar fPAngle,btScalar fRAngle) {      
      	btScalar fCos, fSin;

        fCos = btCos(fYAngle);
        fSin = btSin(fYAngle);
        btMatrix3x3 kYMat(fCos,0.0,fSin,0.0,1.0,0.0,-fSin,0.0,fCos);

        fCos = btCos(fPAngle);
        fSin = btSin(fPAngle);
        btMatrix3x3 kXMat(1.0,0.0,0.0,0.0,fCos,-fSin,0.0,fSin,fCos);

        fCos = btCos(fRAngle);
        fSin = btSin(fRAngle);
        btMatrix3x3 kZMat(fCos,-fSin,0.0,fSin,fCos,0.0,0.0,0.0,1.0);

        m = kYMat*(kXMat*kZMat);		
	}
// This method returns true if the result is unique, otherwise it returns false and returns a 
// solution in which roll is zero (which is good for me).
SIMD_FORCE_INLINE static bool ToEulerYXZ(const btMatrix3x3& m,btScalar& rfYAngle,btScalar& rfPAngle,btScalar& rfRAngle) {
        // rot =  cy*cz+sx*sy*sz  cz*sx*sy-cy*sz  cx*sy
        //        cx*sz           cx*cz          -sx
        //       -cz*sy+cy*sx*sz  cy*cz*sx+sy*sz  cx*cy

        rfPAngle = btAsin(-m[1][2]);
        if ( rfPAngle < btRadians(SIMD_HALF_PI) )
        {
            if ( rfPAngle > btRadians(-SIMD_HALF_PI) )
            {
                rfYAngle = btAtan2(m[0][2],m[2][2]);
                rfRAngle = btAtan2(m[1][0],m[1][1]);
                return true;
            }
            else
            {
                // WARNING.  Not a unique solution.
                btScalar fRmY = btAtan2(-m[0][1],m[0][0]);
                rfRAngle = btScalar(0.0);  // any angle works
                rfYAngle = rfRAngle - fRmY;
                return false;
            }
        }
        else
        {
            // WARNING.  Not a unique solution.
            btScalar fRpY = btAtan2(-m[0][1],m[0][0]);
            rfRAngle = btScalar(0.0);  // any angle works
            rfYAngle = fRpY - rfRAngle;
            return false;
        }
}
I hope that m[j] are the same for Ogre::Matrix3 and btMatrix3x3, because I just copied them as they are (I didn't swap the indices, I made a super easy porting).
These methods still need some testing to ensure everything is OK, but they seem to work, although they're probably slower than the Bullet alternatives.

There's a little problem with the license: Ogre is licensed LGPL, so I don't think that these methods (in <OgreMatrix3.cpp> there are plenty of other methods for all the possible axis combinations) can be useful for people looking for free code (and can't enter the main Bullet branch of course), but in the original file there's a line saying that:

Taken from <OgreMatrix3.cpp>:
// Adapted from Matrix math by Wild Magic http://www.geometrictools.com/

And taken from <OgreMatrix3.h>:
// NB All code adapted from Wild Magic 0.2 Matrix math (free source code)
// http://www.geometrictools.com/

So maybe they can be used freely ?!? :?
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: btMatrix3x3 getEuler returning nan

Post by Flix »

I'm sorry, in the code I provided in my last post there were two errors in the method ToEulerYXZ(...):

btRadians(SIMD_HALF_PI) and btRadians(-SIMD_HALF_PI)
are wrong in Bullet: they should simply be SIMD_HALF_PI and -SIMD_HALF_PI.

With these corrections, these methods seem to work well in the following ranges (according to my cross tests between the two methods):

yaw free
pitch in (-SIMD_HALF_PI,SIMD_HALF_PI)
roll in (-SIMD_HALF_PI,SIMD_HALF_PI)
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: btMatrix3x3 getEuler returning nan

Post by Flix »

I'm sorry for having resurrected this old thread again (and furthermore for answering to myself), but I wrote:
There's a little problem with the license: Ogre is licensed LGPL, so I don't think that these methods (in <OgreMatrix3.cpp> there are plenty of other methods for all the possible axis combinations) can be useful for people looking for free code (and can't enter the main Bullet branch of course), but in the original file there's a line saying that:

Taken from <OgreMatrix3.cpp>:
// Adapted from Matrix math by Wild Magic http://www.geometrictools.com/

And taken from <OgreMatrix3.h>:
// NB All code adapted from Wild Magic 0.2 Matrix math (free source code)
// http://www.geometrictools.com/

So maybe they can be used freely ?!? :?


Well, I'm just discovering that the Ogre library from the (current SVN and) upcaming version 1.7 will switch to the MIT license (please read here: http://www.ogre3d.org/2009/09/15/ogre-w ... e-from-1-7).

So probably all the useful code in <OgreMatrix3.cpp> can freely be converted to Bullet and happily used.

I just wanted the Bullet community to be aware of it, because I think it's an important opportunity and I guess many more developers will start using Ogre + Bullet mixed solutions because of the license change.

P.S: maybe the methods that I posted could be added (side by side to the old ones) to the Bullet btTransform class, because at the present moment it seems that btMatrix3x3::setEulerYPR(fYAngle,fPAngle,fRAngle) gives different results than: btQuaternion q(fYAngle,fPAngle,fRAngle);btMatrix3x3 m; m.setRotation(q);
(At least this is what I experimented...)
Post Reply