Best way to rotate a btRigidBody

Post Reply
paokakis
Posts: 29
Joined: Mon Jan 04, 2021 10:31 am

Best way to rotate a btRigidBody

Post by paokakis »

Hello to the group,

I am creating a 3D space shooter game using OpenGL and Bullet Physics. I have stumbled upon a problem that might be easy for some but is a real challenge for me. So any help is deeply appreciated.
I have a callback function that is passing in the mouse position on the screen as a vector2. I want to take the mouse input and convert it to rotations for the player object (a spaceship). It should rotate to the right when I move the mouse to the right, to the left when I move to the left, up when I move down and down when I move up. All the moves should be relative to the current rotation of the object so if, for example, it is rotated 90 degrees to the right (roll) then when I move the mouse down , the front part of the spaceship should move towards the screen.
I tried to use quaternion rotations to avoid using torques for simplicity and as a first approach with the following code :

Code: Select all

void SpaceShip::onHover(const glm::vec2& pos)
{
	static float yaw = 0.f;
	static float roll = 0.f;
	static float pitch = 0.f;
	static float xOffset = 0.f;
	static float yOffset = 0.f;
	static float move = 0.005f;
	static float restore = 0.001f;

	xOffset = (prevPos.x == pos.x) ? 0.f : (prevPos.x > pos.x) ? -move : move;
	yOffset = (prevPos.y == pos.y) ? 0.f : (prevPos.y > pos.y) ? move : -move;

	roll += (xOffset * sensitivity);
	pitch += (yOffset * sensitivity);

	this->PhysicsSetRotation(yaw, pitch, roll);

	prevPos = pos;
}
The PhysicsSetRotation function is the following :

Code: Select all

btTransform transform = body->getCenterOfMassTransform();
btQuaternion rotation;
rotation.setEuler(glm::radians(yaw), glm::radians(pitch), glm::radians(roll));
transform.setRotation(rotation);
body->setCenterOfMassTransform(transform);
The problem that I have with this method is that the rotation is not relative to the spaceship object. For example, when I rotate to the right 90 degrees and then I drag my mouse down the left part of the spaceship is moving to the screen instead of the front.
So I think I should change the yaw also depending on the roll but I don't know what value should I put there.
Another thing that I would like to ask is for some suggestions to do the rotation with torque and how to calculate this. If my description is not clear I can add some video or GIF to show what is happening.

Thanks in advance.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Best way to rotate a btRigidBody

Post by drleviathan »

Your description is not clear to me. A diagram or video would be helpful.

That said, I think I can offer some advice already. It would go like this:

Avoid representing full rotations with Euler angles. Use pure rotation math when possible. It is ok to use Euler angles (roll, pitch, yaw) to compute rotations but it is almost always a bad idea to decompose a rotation back into Euler angles.

I will assume your game is something like the old game called "Descent" where there is no true "up" direction and I will outline how I would do it. Note when flying an airplane over ground then there would be an implicit "up" then you would want to "steer differently".

Consider this pseudo-code. It might not compile and may very well have bugs. I'm writing this fresh and did not test it:

Code: Select all

// use mouse position to compute a delta-rotation in spaceship local-frame
btScalar yaw = 0.0;
btScalar roll = xOffset * sensitivity;
btScalar pitch = yOffset * sensitivity;
btQuaternion deltaLocalRotation(yaw, pitch, roll);

// get old ship rotation
btTransform transform = body->getWorldTransform();
btQuaternion oldBodyRotation = transform.getRotation();

// newBodyRotation is a combination of oldBodyRotation and deltaLocalRotation,
// but in general: rotations don't commute (their order matters) so...
// what is the their order?
//
// This is how you do it: always imagine the rotations as operating FROM THE LEFT
// on hypothetical vectors at the far RIGHT.
//
// Specifically, if we know the localForward direction
// (probably along a cardinal axis like <0,0,-1> or something)
// and we wanted to compute that axis in the world-frame we would:
//
// worldForward = bodyRotation * localForward
//
// Now that we've got that down, let us consider how to apply a deltaLocalRotation
// to get newBodyRotation.
//
// Since deltaLocalRotation is in the local-frame it must operate on a local-frame vector
// and therefore must be ordered on the RIGHT side:
//
// newWorldForward = newBodyRotation * localForward
// newWorldForward = (oldBodyRotation * deltaLocalRotation) * localForward
//
// See the order inside the parentheses there?  The local delta must be on the RIGHT
// so it can operate on the hypothetical localForward first.
//
btQuaternion newBodyRotation = oldBodyRotation * deltaLocalRotation;
transform.setRotation(newBodyRotation);
body->setTransform(transform);
paokakis
Posts: 29
Joined: Mon Jan 04, 2021 10:31 am

Re: Best way to rotate a btRigidBody

Post by paokakis »

Hello,

Thanks for the reply. I'll try to implement your suggestion. In the meantime you can take a look here : https://youtu.be/dFPNO_yQNZs.
You can see in the first part I roll to the right and at 90 degrees I pitch down expecting the point of the spaceship to come up but instead it is rotating the left side of the spaceship like you correctly suggested with your code that the up is wrong...
paokakis
Posts: 29
Joined: Mon Jan 04, 2021 10:31 am

Re: Best way to rotate a btRigidBody

Post by paokakis »

Thanks man, I tested your code and the rotation is object relative as I wanted. Once more thanks!
Post Reply