Setting the center of mass does nothing except translate the model

Post Reply
User avatar
Andrei Despinoiu
Posts: 3
Joined: Thu Mar 23, 2023 8:58 pm

Setting the center of mass does nothing except translate the model

Post by Andrei Despinoiu »

The way I understand it, the center of mass is the point where you can balance the thing.

I imagine it can be used with a vehicle, for example, set somewhere underneath the visual representation (geometry), so that it never flips upside-down, or at least greatly reduces the chances of it happening.
Or if it's set somewhere above a chair, for example, it should easily tip over, right?

I set it to -10000 on the .y axis (in OpenGL +Y is up), thinking the thing will always stay upright, like a buoy (device floating on water), but nope. It just teleported it. What am I missing? It just seems to translate my entire entity downwards, or in whatever direction I set the center of mass. Capsule collider, very thin box collider, doesn't matter, even if I drop it from any height, it just rolls on the floor... Of if I set it to +/- 10000 on the X axis, I would expect the capsule to prefer rolling on that side only, but it just doesn't work.

I set it like this:

Code: Select all

rigidbody.rb->activate(); // Wake it up in case it's sleeping
btTransform transf = rigidbody.rb->getCenterOfMassTransform(); // Same thing as "getWorldTransform()"
const btVector3 pos = transf * rigidbody.centerOfMass; // Rotate this point so it's local to it and not in world-space somewhere near the center of the scene
transf.setOrigin(pos);
rigidbody.rb->setCenterOfMassTransform(transf);
"rigidbody" is an instance of a struct called "RigidbodyComponent".
"rigidbody.rb" is the "btRigidBody*" pointer.
"rigidbody.centerOfMass" is a btVector3 that I change the values to in the editor GUI (default is 0,0,0).
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Setting the center of mass does nothing except translate the model

Post by drleviathan »

Yeah you don't want to use btRigidBody::setCenterOfMassTransform(). That sets the world_transform of the object's center of mass and doesn't change the center of mass in the object's local-frame.

The center of mass in the object's local-frame is, by definition, the origin of the shape geometry.

Consider a unit mesh cube with eight corners. The mesh vertices would be with the origin at their center would be:

< 0.5, 0.5, 0.5 >
< 0.5, 0.5, -0.5 >
< 0.5, -0.5, 0.5 >
< 0.5, -0.5, -0.5 >
< -0.5, 0.5, 0.5 >
< -0.5, 0.5, -0.5 >
< -0.5, -0.5, 0.5 >
< -0.5, -0.5, -0.5 >


By symmetry the center of mass is at the origin: < 0.0, 0.0, 0.0 >

In order to move the center of mass you must move the point. For example, if we add < 0.5, 0.5, 0.5 > to all the points we would produce a cube with the origin (and hence its center-of-mass) is at one corner:

< 1.0, 1.0, 1.0 >
< 1.0, 1.0, 0.0 >
< 1.0, 0.0, 1.0 >
< 1.0, 0.0, 0.0 >
< 0.0, 1.0, 1.0 >
< 0.0, 1.0, 0.0 >
< 0.0, 0.0, 1.0 >
< 0.0, 0.0, 0.0 >


That works fine for mesh shapes and convex hulls...but what about for implicit shapes like btSphereShape and btBoxShape? For those you must wrap them in a btCompoundShape and supply the offset transform.
User avatar
Andrei Despinoiu
Posts: 3
Joined: Thu Mar 23, 2023 8:58 pm

Re: Setting the center of mass does nothing except translate the model

Post by Andrei Despinoiu »

I do have compound shapes working. It was a bit of a pain to set up, but they are working...

But you should be able to shift the vertices of a collision up or down, for example a capsule surrounding a character that has its origin at its feet, so it's not only covering the upper part of its body. This is like... basic stuff. And it's completely missing from Bullet. FOR YEARS! Why do you have to translate the geometry down? I think all animations will also have to be edited to be translated down, to match it.

So the center of mass is in world space. That is... unbelievable. It should be in local space (local to the collision). It's absurd to have it in world space for something that moves around the scene. It means you have to set it every frame, and currently, if you set it every frame it shoots up if the center of mass btVector3 is "0, 0.15, 0", because it just directly sets the world transform.

WORST OF ALL, setting the center of mass doesn't do what you think it does!

For example, how do I do this in Bullet (at 5:11)?
https://youtu.be/LG1CtlFRmpU?t=311
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Setting the center of mass does nothing except translate the model

Post by drleviathan »

Yes, the center of mass (COM) defines the local-frame origin which means: in order to shift the COM relative to the geometry you must shift the geometry instead. For this reason: btRigidBody::setCenterOfMassTransform() can only be understood to mean "set the COM transform in the world-frame".

The way to give a vehicle a COM outside of its own geometry is to use the aforementioned btCompoundShape trick.

That youtube video talks about how they move the COM back into the bounds of the vehicle when it dies, to allow it to tumble more realistically. It is is possible to do this in Bullet. You would first have to make sure every potentially shifted object is already using a btCompoundShape. This because implicit shapes (btSphereShape, btBoxShape, etc) don't have a COM-relative transform feature and thus cannot be shifted in this way. Then, you could write a custom utility to "shift the world-frame COM transform while keeping the collision geometry's world-frame transform invariant" that could operate on such an object.

Hard core game devs will often employ "shape sharing" where they use one shape instance to provide the collision info for multiple bodies. This is an optimization because it reduces memory footprint and hence improves CPU cache performance. In such a paradigm shifting the COM of a shape would affect ALL of the bodies, so COM-shfting a single body would require giving it a different shape... iff it was sharing. This is why general-purpose COM-shift technology cannot be part of the default Bullet tool set: it could only be implemented as a feature of a sufficiently intelligent "shape management" system.
User avatar
Andrei Despinoiu
Posts: 3
Joined: Thu Mar 23, 2023 8:58 pm

Re: Setting the center of mass does nothing except translate the model

Post by Andrei Despinoiu »

drleviathan wrote: Fri Mar 24, 2023 3:03 pm Then, you could write a custom utility to "shift the world-frame COM transform while keeping the collision geometry's world-frame transform invariant" that could operate on such an object.
I'm sorry but what is the purpose of Bullet's "setCenterOfMassTransform()" function if I need to write such a custom utility?

This is so weird... What I was hoping to add was a small red sphere, for debug purposes, to see where its center of mass was and how it behaved if I changed its position, how it can tip over, or not. Instead, I get this "always in the middle", simply because that's where the model's origin (or "pivot" point) is.

Let's say I have one of those adjustable fitness weights (example here). I unscrew one of the sides, so all that's left is the bar that was holding them, and the opposite side. The center of mass is no longer in the center, but according to Bullet, it is. Doesn't mater how heavy the opposite side is, it can be 800 kg, the bar 1 kg, and Bullet is like "yeah, center".

I guess you could treat them as separate models... and have the one with all the weights "attached" be positioned so that its pivot is in the middle, while the one with only one weight attached has the pivot where you would think the center of mass would be. Same with an axe or a hammer, for example. Or an (opened) umbrella.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Setting the center of mass does nothing except translate the model

Post by drleviathan »

Alas, physics simulations require approximation and abstraction in order to run in real-time on real-life hardware. The discrepancy between how you think it should work, and how it actually works, is a manifestation of that truth.

The fact of the matter is: it is possible to get the effect you want, but you have to do it the right way. For maximum flexibility for how the physics library can be used I believe shape-manager and COM-shifter utilities really do belong outside the domain of the physics engine itself. Not everyone needs either one of them, and those who do will want full control.

Somewhat unrelated to your particular frustration: I do find this question interesting:
What is the purpose of Bullet's "setCenterOfMassTransform()" function?
btRigidBody::getCenterOfMassTransform() is identical to the btCollisionBody::getWorldTransform() of the base class, which is odd. So I went and examined the implementations of the setters to see if they were also identical. No, they are different! Each one sets btCollisionObject::m_worldTransform, however they have distinct side effects and the btRigidBody method doesn't call the the other on btCollisionObject and therefore it lacks that one's side effect. Meanwhile, I have always used setWorldTransform(), which means I wasn't getting the side effects of setCenterOfMassTransform(). Should I have been calling both? My spidey sense tells me there is a bug here, but it AFAIK it has never bitten me and it doesn't look serious so I didn't bother to track it down. If I were to write a fresh game engine today using Bullet I would probably take the time to understand it better.
Post Reply