How to rotate a btCollisionShape?

Post Reply
b0gd4n
Posts: 14
Joined: Thu Nov 07, 2013 2:38 am

How to rotate a btCollisionShape?

Post by b0gd4n »

I have created a bullet vehicle with a compound as the chassis and the compound is formed of 2 bodies, a chassis and a turret.

I can obtain the turret transform and opengl matrix like this:

Code: Select all

// get chassis and turret transforms
btTransform chassisTransform = m_vehicle->getChassisWorldTransform();
btTransform turretTransform = compound->getChildTransform(1);
// multiply transforms to get updated turret transform
turretTransform *= chassisTransform;

// get turret matrix
btScalar turretMatrix[16];
turretTransform.getOpenGLMatrix(turretMatrix);
The turretTransform is the transform of a btCollisionShape object (turretShape).

I am now trying to rotate this turret around it's Y axis.
I have tried this:

Code: Select all

turretTransform.setRotation(btQuaternion(btVector3(0, 1, 0), angle));
Where angle is a float, but nothing happens.

I'm definitely missing something, but do not fully understand how these rotations work.
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: How to rotate a btCollisionShape?

Post by Flix »

b0gd4n wrote:I'm definitely missing something, but do not fully understand how these rotations work.
Hehe :) , you're definitely missing something...

There are some differencies between collision objects and collision shapes: if you use a single compound shape for both a chassis and a turret you have to face 2 problems:
1) if you want to rotate the turret only, the only way you can do it is to update the child transform of your collision shape (and furthermore, according to the Bullet "official" guide, you should remove/readd the "parent" rigidbody to apply the changes). The way you're making it:

Code: Select all

btTransform turretTransform = compound->getChildTransform(1);
turretTransform *= chassisTransform;
is obviously wrong: you might get the matrix you want, but you don't update the child transform with it.
2) You can't reuse the same collision shape for other bodies.

The correct way to handle moving parts in your objects, is to create different rigid bodies (one per moving part) and connect them with constraints (a chassis rigid body + a turret rigid body +a btHingeConstraint should work in your case, but if you want the turret's cannon to rotate up and down you should create an additional cannon rigid body connected to the turret rigid body with another btHingeConstraint: hope you can understand what I mean).

In short: your approach is completely wrong as far as I can understand :cry:. (And sorry for being a bit rude...). However I suggest you keep on trying to update the turret matrix (and optionally refresh your rigid body), to check if the transform you're applying is correct: remember that in compound shapes child transforms are relative to the parent rigid body transform, that angles are in radians and that you should use: compoundShape->updateChildTransform(...).

P.S. Take a look at the Bullet constraintDemo for further hints about constraints.
b0gd4n
Posts: 14
Joined: Thu Nov 07, 2013 2:38 am

Re: How to rotate a btCollisionShape?

Post by b0gd4n »

Flix wrote:
b0gd4n wrote:I'm definitely missing something, but do not fully understand how these rotations work.
Hehe :) , you're definitely missing something...

There are some differencies between collision objects and collision shapes: if you use a single compound shape for both a chassis and a turret you have to face 2 problems:
1) if you want to rotate the turret only, the only way you can do it is to update the child transform of your collision shape (and furthermore, according to the Bullet "official" guide, you should remove/readd the "parent" rigidbody to apply the changes). The way you're making it:

Code: Select all

btTransform turretTransform = compound->getChildTransform(1);
turretTransform *= chassisTransform;
is obviously wrong: you might get the matrix you want, but you don't update the child transform with it.
2) You can't reuse the same collision shape for other bodies.

The correct way to handle moving parts in your objects, is to create different rigid bodies (one per moving part) and connect them with constraints (a chassis rigid body + a turret rigid body +a btHingeConstraint should work in your case, but if you want the turret's cannon to rotate up and down you should create an additional cannon rigid body connected to the turret rigid body with another btHingeConstraint: hope you can understand what I mean).

In short: your approach is completely wrong as far as I can understand :cry:. (And sorry for being a bit rude...). However I suggest you keep on trying to update the turret matrix (and optionally refresh your rigid body), to check if the transform you're applying is correct: remember that in compound shapes child transforms are relative to the parent rigid body transform, that angles are in radians and that you should use: compoundShape->updateChildTransform(...).

P.S. Take a look at the Bullet constraintDemo for further hints about constraints.
Hey there!

Thanks for the info! It helped A LOT!

I followed your advice and created a separate rigid body for the turret. So now I have 2 different rigid bodies, the car and the turret.

After going through the ConstraintDemo I came out with this:

Code: Select all

// create constraint
	btVector3 axisA(0.f, 1.f, 0.f);
	btVector3 axisB(0.f, 0.f, 0.f);
	btVector3 pivotA(0.f, 1.f, 0.f);
	btVector3 pivotB(0.f, 0.f, 0.f);
	hinge = new btHingeConstraint(*m_carChassis, *turretBody, pivotA, pivotB, axisA, axisB);

	// add constraint to world
	bt_dynamicsWorld->addConstraint(hinge, true);
OK, so the turret is now stuck to the chassis. The chassis is being spawned a few meters above the ground and as it hits the ground the turret starts slowly spinning.

I am now having difficulty figuring out these constraints as I want to make the turret fixed until I want to rotate it.

How do I fix the turret rotation on the hinge and then how do I apply rotation?



EDIT:

ok, I 'THINK' I found something.

I use

Code: Select all

hinge->enableAngularMotor(true, 0, 1);
to stop the rotation.

And I assume I could use the same method to rotate it.

Please let me know if I am doing this the wrong way or something!
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: How to rotate a btCollisionShape?

Post by Flix »

b0gd4n wrote:I use
Code:
hinge->enableAngularMotor(true, 0, 1);
to stop the rotation.

And I assume I could use the same method to rotate it.

Please let me know if I am doing this the wrong way or something!
Yes, all the constaints have limits and motors.

1) Limits are used to limit the constraint (in your case you have a lower and an upper angular limit). In some constraints (like the btHingeConstraint) you can set the axis free by setting the upper limit smaller than the lower limit. You can lock all the constraints by setting the lower limit equal to the upper limit, and you can limit the constraint range by setting the lower limit smaller than the upper limit.
So, by using limits only, you should be able to lock and release the angular motion of your turret.

2) Motors are used to move the constraint: the direction and velocity of the move are determined by the sign and the absolute value of the motor "target velocity". The max motor force is the force needed to apply the target velocity to the constraint (I sometimes make it proportional to the object mass): if it's too low, no move will happen because the body is too heavy to move; if too big, the movement can be too rough, as the target velocity will be applied instantaneously. When both limits and motors are used, the constraint will eventually "stop" at the limit (lower or upper depending on the sign of the target velocity), but the motor will still be active. Last thing: please remember that the bodies can still go to sleep, even if there are constraints or motors applied to them (sleeping depends on the properties you apply to the rigid bodies: you can use btRigidBody->activate() to wake up a sleeping body).

Please note that there are 2 ways to lock a constraint in a particular position:
a) Don't use motors and set the two limits equal to your locked position (pro: no motor used (performance?); cons: you have to remember the true limits and re-set them before applying a motor).
b) Using a motor with a target velocity of 0 (but a max motor force >0). This way you can set the constraint limits once (if you don't need to change them).

In your case I suggest for example:
1) You leave the btHingeConstraint free to rotate (lowerLimit>upperLimit), or set the correct lower and upper limit according to your needs.
2) You apply a motor with 0 target velocity to lock the turret (choose a good max motor force and never change it).
3) when the right or left keys are down, you change the sign and modulo of the target velocity.
4) when the right or left keys are up, you set the target velocity to zero to lock the rotation again.

Please note that in some constraints you have access to single motor variables individually, but in other you must call something like: enableMotor(true,velocity,force), even if you just want to update the target velocity only.
b0gd4n
Posts: 14
Joined: Thu Nov 07, 2013 2:38 am

Re: How to rotate a btCollisionShape?

Post by b0gd4n »

Flix wrote:
b0gd4n wrote:I use
Code:
hinge->enableAngularMotor(true, 0, 1);
to stop the rotation.

And I assume I could use the same method to rotate it.

Please let me know if I am doing this the wrong way or something!
Yes, all the constaints have limits and motors.

1) Limits are used to limit the constraint (in your case you have a lower and an upper angular limit). In some constraints (like the btHingeConstraint) you can set the axis free by setting the upper limit smaller than the lower limit. You can lock all the constraints by setting the lower limit equal to the upper limit, and you can limit the constraint range by setting the lower limit smaller than the upper limit.
So, by using limits only, you should be able to lock and release the angular motion of your turret.

2) Motors are used to move the constraint: the direction and velocity of the move are determined by the sign and the absolute value of the motor "target velocity". The max motor force is the force needed to apply the target velocity to the constraint (I sometimes make it proportional to the object mass): if it's too low, no move will happen because the body is too heavy to move; if too big, the movement can be too rough, as the target velocity will be applied instantaneously. When both limits and motors are used, the constraint will eventually "stop" at the limit (lower or upper depending on the sign of the target velocity), but the motor will still be active. Last thing: please remember that the bodies can still go to sleep, even if there are constraints or motors applied to them (sleeping depends on the properties you apply to the rigid bodies: you can use btRigidBody->activate() to wake up a sleeping body).

Please note that there are 2 ways to lock a constraint in a particular position:
a) Don't use motors and set the two limits equal to your locked position (pro: no motor used (performance?); cons: you have to remember the true limits and re-set them before applying a motor).
b) Using a motor with a target velocity of 0 (but a max motor force >0). This way you can set the constraint limits once (if you don't need to change them).

In your case I suggest for example:
1) You leave the btHingeConstraint free to rotate (lowerLimit>upperLimit), or set the correct lower and upper limit according to your needs.
2) You apply a motor with 0 target velocity to lock the turret (choose a good max motor force and never change it).
3) when the right or left keys are down, you change the sign and modulo of the target velocity.
4) when the right or left keys are up, you set the target velocity to zero to lock the rotation again.

Please note that in some constraints you have access to single motor variables individually, but in other you must call something like: enableMotor(true,velocity,force), even if you just want to update the target velocity only.

Again, I want to thank you for these great replies!

Helped a lot!
Kirity
Posts: 7
Joined: Wed May 13, 2015 10:57 am

Re: How to rotate a btCollisionShape?

Post by Kirity »

After going through this post,,am posting my question hope you guys have touched this part too.

"Hello,
I am not able to understand how does parameters in raAFrame,rbBFrame are used in creating the btHingeConstraint.
btHingeConstraint(btRigidBody& rbA,
btRigidBody& rbB,
const btTransform& rbAFrame,
const btTransform& rbBFrame,
bool useReferenceFrameA = false)

Especially I am struck with understanding of "raAFrame.getBasis().setEulerZYX(XX , XX, XX) "

Also the name is showing as "setEulerZYX()" but the actual code is taking it as "X Y Z" parameters - This is also confusing.

What does setting the Euler's angles means in the context of rigidBody,btTransform and btHingeConstraint ??

To be precise I am refering to ForkLiftDemo example.

Any help is much appreciated."

Thanks
Post Reply