Quaternion changes rotation when initializing

Post Reply
Zaladen
Posts: 25
Joined: Thu May 14, 2015 10:21 am

Quaternion changes rotation when initializing

Post by Zaladen »

I create a body and initialize with a rotation like so:

Code: Select all

btRigidBody* Bullet::CreateBoxBody(const btVector3 &scale, btVector3 &rot, btScalar mass, const btVector3 &pos)
{
	btCollisionShape *shape = new btBoxShape(btVector3(1, 1, 1));
	shape->setLocalScaling(scale);

	btQuaternion rotQuat;
	rotQuat = rotQuat.getIdentity();
	rotQuat.setX(rot.getX());
	rotQuat.setY(rot.getY());
	rotQuat.setZ(rot.getZ());
	rotQuat.setW(1.0f);

	btDefaultMotionState *motionState =
		new btDefaultMotionState(btTransform(rotQuat, pos));

	btVector3 fallInertia(0, 0, 0);
	shape->calculateLocalInertia(mass, fallInertia);

	btRigidBody::btRigidBodyConstructionInfo
		bodyCl(mass, motionState, shape, fallInertia);
	btRigidBody *body = new btRigidBody(bodyCl);

	dynamicsWorld->addRigidBody(body);
	dynamicsWorld->updateSingleAabb(body);

	btTransform trans;
	body->getMotionState()->getWorldTransform(trans);
	std::cout << trans.getRotation().getX() << std::endl;

	return body;
}
When I do this the resulting rotation printed by the cout command is slightly different than the input variable rot, for example if I input 0.0026 the result will be something like 0.00245 or something. This obviously creates problems if I try to save the state of the objects and the rotation changes each time I try to load it. Any suggestions?
teh_ballerer
Posts: 9
Joined: Fri Sep 26, 2014 3:31 am

Re: Quaternion changes rotation when initializing

Post by teh_ballerer »

This is due to how floating point values are represented in C++. Long story short, it's not possible to represent every possible decimal value using the IEEE floating point model, so only discrete values are used (e.g. 0.0001, 0.0002, 0.0003, 0.0005, 0.0006) notice how I skipped 0.0004, it's just an example.

To get exact values you would need to use arbitrary precision arithmetic, which is a lot more involved and might be more than what you want to do. You would need a separate library for this, unless you implement it yourself, and you would need to integrate it with Bullet.

Please read this for more information:
http://floating-point-gui.de/

Hope this is helpful.
Zaladen
Posts: 25
Joined: Thu May 14, 2015 10:21 am

Re: Quaternion changes rotation when initializing

Post by Zaladen »

Oh I see, that's certainly problematic! I'll look into it and check out the link, thanks for your help!
anthrax11
Posts: 72
Joined: Wed Feb 24, 2010 9:49 pm

Re: Quaternion changes rotation when initializing

Post by anthrax11 »

You can also try switching to double precision (see BT_USE_DOUBLE_PRECISION).
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Quaternion changes rotation when initializing

Post by drleviathan »

Actually, I think the problem is that you're creating an non-normalized quaternion. In order for a quaternion to represent a rotation it must lie on the unit hypersphere, which means its length (sqrt(x^2 + y^2 + z^2 + w^2)) must be 1.0. Meanwhile this code...

Code: Select all

   rotQuat.setX(rot.getX());
   rotQuat.setY(rot.getY());
   rotQuat.setZ(rot.getZ());
   rotQuat.setW(1.0f);
...appears to be stuffing some vector rot into the imaginary parts of the quaternion rotQuat and then setting the real part to 1.0. Since the real component is already 1.0 it is impossible for the quaternion to be normalized unless rot has all zeros.

I could tell you how to do it correctly... if I just knew what rot is supposed to be. Is it euler angles? Is it an axis of rotation, perhaps with a length that is significant in some way?
Zaladen
Posts: 25
Joined: Thu May 14, 2015 10:21 am

Re: Quaternion changes rotation when initializing

Post by Zaladen »

Oh I see, unfortunately I don't know much about how quaternions work. :/ I wanted to use euler angles initially but that didn't work correctly so I ended up using the constructor that uses scalars (x, y, z, w), I don't completely know how that works though, how is that different from euler angles?
Zaladen
Posts: 25
Joined: Thu May 14, 2015 10:21 am

Re: Quaternion changes rotation when initializing

Post by Zaladen »

Ok I tried to initialize with the w component also, which fixed the problem with the angles changing, but instead I get this error outputted at every frame in the console:

sepAxis=(undef,undef,undef), squaredDistance = undef, shapeTypeA=10,shapeTypeB=0
btGjkPairDetector maxIter exceeded:1002

shapeTypeA and shapeTypeB are also different for each output.

Edit:

Ok an update, I searched the forums and found out that if you set rotation to (0,0,0,0) it causes this problem, and in some places i had set the rotation to just that, so changing that to (1,0,0,0) fixed the problem!
Last edited by Zaladen on Sat May 21, 2016 2:08 am, edited 1 time in total.
kermado
Posts: 20
Joined: Tue Jan 12, 2016 11:20 am

Re: Quaternion changes rotation when initializing

Post by kermado »

Use btQuaternion::setEuler, btQuaternion::setRotation, or the two corresponding constructors to properly initialize your quaternion. As drleviathan said, only unit quaternions represent rotations. The vector part of the quaternion (x, y, z), also referred to as the imaginary part, are not the Euler angles. I very much doubt that this is a floating point precision issue. This is more likely caused when Bullet attempts to convert the non-unit quaternion to a 3x3 matrix which is then stored in the btTransform.

For example, use:

Code: Select all

btQuaternion rotation(M_PI/4, 0, 0); // 45 degrees rotation about x-axis.
Remember that angles should be supplied in radians rather than the archaic base 60 Babylonian unit of degrees.
Post Reply