Compound Dynamic Body is behaving strange

Hello
I have issues with compound bodies, they behave very strange compared to simple box colliders

EXAMPLE:
Compound Body with 10 box colliders

if 2 compound colliders are penetrating each other due to some explosion force they they will both start dancing around and rotate like mad…

Another strange behaviour possibly due to interpolation is that they will jitter on screen when they collide with something

They also look very unstable once they start colliding with lots of objects, they have trouble coming to a rest and usually because some simple box body is penetrating the compound collider

Are there any best practices or known issues with compound bodies?

I can make a video if needed

Let me know!
thanks!

ps i am using havok

Are things the same with Unity Physics as they are with Havok Physics?
My guess is that the collisions between 2 interpenetrating compound bodies are trying to resolve themselves but can’t.
A video or simple repro would help.

here is a video

this compound collider is made of 3 boxes, it loops the movement you see forever…
below is a static floor and around it some other small box bodies

Everything is formed dynamically in runtime ( i make new colliders and bodies if needed)
its a block destruction system

I am also using inertia tensor on X and Y set to zero

This is one of the examples that seems wrongs, i have other cases similar to this


The colliders in debug mode

Since you are doing everything dynamically, what are the mass properties initially (before you set the two axis to 0). Seems like this has spherical mass properties, thus the wobble.

This is object A with a compound collider and dynamic body (no render object)
under object A there are several smaller boxes with no collider or bodies obviously as the physics are controlled by the parent

One thing that is questionable is that the parent has float3(0,0,0) position and i am using the children render/collider position to put them in the right place initially… can that give any problems?


here is a debug photo in the CreateDynamicBody function before i modify the inertia tensor and create the body

I’ve just tried locally what you are doing (setting inverse inertia on a compound to 0 on 2 axis) and everything seems fine. Makes me wonder if something else is wrong here.

You mentioned that your child boxes of the compound don’t have a collider. Is that true? That could be an issue.

The position stuff should be fine, I don’t see a problem with that. Are you making a compound on your own? Maybe share that piece of code as well to verify?

public static void CreateDynamicBody(Entity entity, float mass, float3 startAngularVelocity, float3 startLinearVelocity, float gravityFactor, float linearDamping, float angularDamping, ref PhysicsCollider colliderComponent, bool lockTo2DPhysics = true)
    {
        PhysicsMass physicsMass = PhysicsMass.CreateDynamic(colliderComponent.MassProperties, mass);
        if (lockTo2DPhysics)
        {
            physicsMass.InverseInertia[0] = 0;
            physicsMass.InverseInertia[1] = 0;
            physicsMass.InverseInertia[2] = physicsMass.InverseInertia[2];
        }
        EntityManagerRef.AddComponentData(entity, physicsMass);

        float3 angularVelocityLocal = math.mul(math.inverse(colliderComponent.MassProperties.MassDistribution.Transform.rot), startAngularVelocity);
        EntityManagerRef.AddComponentData(entity, new PhysicsVelocity()
        {
            Linear = startLinearVelocity,
            Angular = angularVelocityLocal
        });

        EntityManagerRef.AddComponentData(entity, new PhysicsDamping()
        {
            Linear = linearDamping,
            Angular = angularDamping
        });

        if (gravityFactor != 1)
        {
            EntityManagerRef.AddComponentData(entity, new PhysicsGravityFactor()
            {
                Value = gravityFactor
            });
        }
    }
   List<int4> colliderBoxes = BuildColliderAssistant.BuildOptimizesColliders(newIndexListFromRootInstance, newInstance.MeshBoxes, newInstance.Width, newInstance.Height);
        NativeArray<Unity.Physics.CompoundCollider.ColliderBlobInstance> Blobs = new NativeArray<Unity.Physics.CompoundCollider.ColliderBlobInstance>(colliderBoxes.Count, Allocator.Temp);

        float massCalculator = 0;
        for (int i = 0; i < colliderBoxes.Count; ++i)
        {
            Vector3 outColliderPosition, outColliderSize;
            PixelMeshData.CreatePositionForBox(colliderBoxes[i], out outColliderPosition, out outColliderSize);
            outColliderSize.z = PixelMeshData.GetPixelZSize(PixelCollisionType.Compound);
            outColliderPosition.z = 0;

            BlobAssetReference<Unity.Physics.Collider> boxCollider = PhysicsAssistant.CreateBoxCollider(float3.zero, outColliderSize, 0, newInstance.PhysicsMaterialTemplate);

            Blobs[i] = new Unity.Physics.CompoundCollider.ColliderBlobInstance()
            {
                Collider = boxCollider,
                CompoundFromChild = new Unity.Mathematics.RigidTransform(
                  Quaternion.identity,
                  outColliderPosition)
            };

            massCalculator += colliderBoxes[i].w * colliderBoxes[i].z;
        }

        massCalculator /= PixelMeshData.MassVolume;

        BlobAssetReference<Unity.Physics.Collider> MyCollider = Unity.Physics.CompoundCollider.Create(Blobs);
        Blobs.Dispose();

        PhysicsCollider physicsCollider;
        PhysicsAssistant.CreateCollider(ref newInstance.EntityRef, ref MyCollider, out physicsCollider);

        PhysicsVelocity existingVelocity = new PhysicsVelocity() { Angular = newInstance.PhysicsBodyTemplate.InitialAngularVelocity, Linear = newInstance.PhysicsBodyTemplate.InitialLinearVelocity };
        if (rootInstance.IsStaticOrDynamic == BlockPhysicsType.Dynamic)
        {
            existingVelocity = Game.Instance.EntityWorld.EntityManager.GetComponentData<PhysicsVelocity>(rootInstance.EntityRef);
        }

        PhysicsAssistant.CreateDynamicBody(newInstance.EntityRef, massCalculator,
           existingVelocity.Angular,
            existingVelocity.Linear,
            newInstance.PhysicsBodyTemplate.GravityFactor,
            newInstance.PhysicsBodyTemplate.LinearDamping,
            newInstance.PhysicsBodyTemplate.AngularDamping,
            ref physicsCollider,
            true);

the create body function, which is similar to the samples and the code i use to create the collider and dynamic body


in my video, the entity that rotates weird, here is a snapshot from the entity debug, the translation/rotation/localtoparent/physicsvelocity data change every frame because of the rotation bug

I just noticed, the entity that behaves strange… i changed its compound collider during the game but i did not update anything in the dynamic body… is that wrong?

What happens is…
Block A is destroyed in half, B and C
B is completely new dynamic body and physics collider
C is actually Entity A but with an updated collider (i remake the compound collider)

PhysicsCollider physicsCollider = new PhysicsCollider() { Value = MyCollider };
                EntityManagerRef.SetComponentData<PhysicsCollider>(existingInstanceEntity, physicsCollider);

Does the same strange behavior happen when you don’t change stuff at runtime like this?

its not as stable as in with normal inertia tensor… but more or less is ok

I fixed it!!! updating just the compound collider is not enough

  public static void UpdateColliderAndPhysicsMass(Entity entity, ref BlobAssetReference<Collider> collider, float mass, bool lockTo2DPhysics)
    {
        PhysicsCollider physicsCollider = new PhysicsCollider() { Value = collider };
        EntityManagerRef.SetComponentData<PhysicsCollider>(entity, physicsCollider);

        PhysicsMass physicsMass = PhysicsMass.CreateDynamic(physicsCollider.MassProperties, mass);
        if (lockTo2DPhysics)
        {
            physicsMass.InverseInertia[0] = 0;
            physicsMass.InverseInertia[1] = 0;
            physicsMass.InverseInertia[2] = physicsMass.InverseInertia[2];
        }

        EntityManagerRef.SetComponentData(entity, physicsMass);
    }

I call this function now to update both collider and the physicsmass!

Oh yeah, if you change the collider mass props need to be recalculated. Glad you solved it!

1 Like