Download

[PHYSICS] Center of mass needs a rework

I have two major criticisms to say : Why do we set an offset to the calculated center of mass and not directly the center of mass ?
Why is GetCenterOfMass relative to the parent component ? In my opinion, it should be relative to the origin of the component.

Please change it, it’s counter intuitive and written nowhere.

EDIT : GetCenterOfMass is in world space.

GetCenterOfMass is in world space as far as I know.

It’s still a weird choice.

Not sure what you mean by “I tried with World Space” - there is no choice. Component needs to simulate physics to return non-zero COM and if it’s a part of welded body then COM of a complete welded body is returned.

Components physics are not even replicated, only the parent actor can be replicated so, not sure what are you doing but probably its another note to take in account.

That’s another problem, but that is feasible.

In my testings, the center of mass is not relative to the origin of the component which is being simulated, and don’t worry, I am simulating it.

The point is that we need to get the COM that is in world space (as you say), then transform it in local space, then use your wanted COM - that to set the wanted center of mass that is in local space.

As you keep mentioning relative vs local coordinate I assume that you are trying to set center of mass on a child component. But the thing is, if you are simulating it then it’s not connected to its parent and there is no reason for COM to be relative to anything. If you are not simulating it then child component is welded to its parent and the top of the hierarchy defines the origin in basis of which COM is set. Technically its not even like that as there are separate “physics bodies” created and components have pointers to them. So multiple welded components are in fact a single physics body (afaik).
Another thing is that there is no way to set center of mass without making a custom c++ function that changes it on physics body level. Default nodes/functions set only an offset of COM, which is calculated when you add collision body to the object.

Anyway, there might be a bug in the code introduced by one of the engine updates. Can you list steps to re-produce this issue?

I don’t think there is a bug, I might just be confused by my actor between World Transform and Relative Transform. I actually just tested that, and it is indeed world space.
I am indeed trying to set the center of mass on a child RuntimeMeshComponent being simulated.
The COM could be relative to the origin of the component, such as if the component was a mesh, setting the COM somewhere would use the same coordinate system as the mesh’s. Since all welded components are child of this component, they would only have to get the center of mass relative to the simulating component, so I see why the COM is returned in world space.

BUT, and that is why I’m complaining, the COM is only being set using an offset as you mentioned, and doesn’t override the default COM, meaning that at any change of the geometry, the COM is being recalculated which adds a lot of overhead for nothing.

The solution that I am proposing is that GetCenterOfMass stays the same, but that SetCenterOfMass gets a OverrideCOM just like Mass does, in such that it doesn’t rely on the calculated PhysX COM.

And, I really appreciate you responding to my criticisms.

I hear you. Yeah, agree with that, would be very useful option to set COM directly. I’m not sure why devs added offset instead of override, perhaps something related to how code is structured or how it’s fed to PhysX. Don’t know exactly.

If you are in dire need of such change, this is the code for c++ function to set InertiaTensor:



void UMMTBPFunctionLibrary::MMTSetInertiaTensor(UPrimitiveComponent * Target, const FVector& InertiaTensor)
{
	FBodyInstance* BodyInstance = GetBodyInstance(Target);
	if (BodyInstance != NULL) {

		PxRigidBody* PRigidBody = BodyInstance->GetPxRigidBody_AssumesLocked();

		if (PRigidBody != NULL) {

			PRigidBody->setMassSpaceInertiaTensor(U2PVector(InertiaTensor));
		}
	}
}


For center of mass you can replace “PRigidBody->setMassSpaceInertiaTensor(U2PVector(InertiaTensor));” with this line:
PRigidBody->setCMassLocalPose( [NewCenterOfMassTransform] );

Transform here is not FTransform but PxTransform of Physx. Haven’t tested it but should work.

Can’t I just disable PhysX-calculated COM to make it so that the offset is always what I want ? If it’s always disabled, it should do just fine.

Actually, I know why I was getting weird results : You can’t get the center of mass of an object for which you just set the collision, it returns (0;0;0). So, the physics engine just comes after you set you collision offset and screws it up by setting the PhysX offset.