Component collisions without auto-weld

I try to create an Actor using physics with a precise position for the center of mass.

I create a first prototype with 2 cubes:

  • A StaticMeshComponent as root with physic enabled and mass scale at 1 and no gravity.
  • A StaticMeshComponent as child with physic disabled, mass scale at 0 and “auto weld” enabled. The child cube is placed next to the root cube.

At BeginPlay event, i set an angular velocity to 180°/s to the root cube.

My goal is to have the 2 cubes rotating around the center of the root cube with the collisions working for the 2 cubes.

The problems is that the 2 cubes are rotating around a point between the 2 cube, as if the 2 cubes had the same mass. In fact, the mass scale of the child is totally ignored because the “auto weld” settings seam to override the mass settings. In this case, the collisions are correct.

I try to disable the “auto weld” setting on the child cube. This solve the center position problem but the child cube no longer have any collision with others objects in the world.

How can I have both mass control (or no mass at all) by component and collisions for all components ?

I don’t want to use Physics Constraint because it may work for 2 cube, but not for a big static assembly with a lot of component.

Thanks.

When autoweld is on we take the geometry of the child body and add it to the root body so that it can be simulated as a single body. When doing this we will update mass to get the correct mass distribution. I think in the common case this is what you would expect as welding an object should affect center of mass because you’re building a compound object.

Have you tried modifying Center Of Mass Offset? We are planning to make center of mass a bit easier to visualize in upcoming release so we could probably add some way for you to set this directly instead of just an offset.

Hope that helps, I can give you more info on the code if you’d like to make some modifications to set it to be exactly where the root is.

I tried to modify the Center Of Mass offset for the root and the system act like if the root cube is shifted but it will be difficult to find the right offset to compensate all the child.

Maybe if i modify the Center Of Mass offset of all the child to set it on the center of the root, i will have the right rotation center. However, the moment of inertia will be very wrong and i don’t find how to correct it.

The problem is that the auto weld weld both collision shape and physic settings. It should be too hard to have a weld mode that keep the collision shape weld bue instead of use the same mass scale for all welded component, compute the centroid of all individual mass and use the sum of the mass as total mass.

changing the center of mass on the child will not do anything right now as we simply inherit the mass settings of the root. What you suggest is certainly possible, though it adds complexity to the code and would require yet another flag. I’m not really against it but I want to think about the use case some more before making this change as auto-welding is already a very intrusive change coming in 4.5

Were you thinking of using mass scale of 0 so that the child would have no affect on the parent?

If you’d like to make this modification locally take a look at FBodyInstance::UpdateMassProperties. Near the bottom you can see the COMNudge is used to set the center of mass.

When welding we call this function after adding new shapes to the root body

Using mass scale to 0 was a limit case but my real use case is the following : a modular spaceshipe forming only one rigid body, each module have its own density.

The COM and moment of inertia calculation for a set of point mass is very simple but there is no way to forcce these value. I just looked the UpdateMassProperties and if i can get the calculated COM, i can fix it with an offset equal to the difference with a value i calculate. However the moment of inertia remain wrong and there is no Inertia Scale.

In the FBodyInstance, i found no reference to the welded components. If i want to use them to calculate the COM and Inertia, i will need the physic properties and not only the shape. Did I miss something ? It’s seem possible or i’d better not to use ue4 physics ?

If you compute the moment of inertia you could set it directly in UpdateMassProperties. Each shape’s userData will tell you what body instance it originally belonged to. If the userData is NULL it means that the root is the original body instance. You can do something like this:

    int32 NumSyncShapes;
    TArray<PxShape*> Shapes = GetAllShapes(NumSyncShapes);
    for(PxShape : Shapes)
    {
        FBodyInstance* BI = FPhysxUserData::Get<FBodyInstance>(PShape->userData);
        if(BI == NULL){ BI = this;}  //in the root case just use this
    
        //you can now get at all the original settings of the body to do proper COM and moment of inertia calculation
    }

I think this would be a good change to make, if you get it working or need help please let me know and then we can integrate it into the engine so you don’t have to maintain it yourself.

Thanks for bringing it up

I begin to inspect the code and i found the following method:

static bool updateMassAndInertia(PxRigidBody& body, const PxReal* shapeDensities, PxU32 shapeDensityCount, const PxVec3* massLocalPose = NULL, bool includeNonSimShapes = false);

It’s the same updateMassAndInertia method than the one used by ue4 for now but taking an array of density instead of an unique density.

I will just have to generate a density array and it should work.

I will also try to correct the velocity if the center of mass position change. If a body change its mass and its COM, the linear velocity will change to keep the same local velocity at each point of the shape before and after the COM change.

In 2 dimensions, the new velocity for the new center of mass is V = V0 + 2.Pi.r.Va / 360 with :

  • V = linear velocity of the new center of mass, in m/s
  • V0 = linear velocity of the initial center of mass, in m/s
  • r = distance between the old and the new center of mass (in m)
  • Va = angular velocity of the body, in °/s

The angular velocity is not impacted by th COM position change.

The best way to visualise the COM velocity change is to imagine a steel beam rotating with no gravity and no linear velocity. The COM is at the middle of the beam.
If you cut the beam in half, the 2 parts of the beam will go in an opposite direction, like sling stones.

If it seem correct to you, I will try to implement this as soon as i have the time.

I create a pull request here for this feature.

https://github.com/EpicGames/UnrealEngine/pull/509