Assigning Havok Body Tags For Contact Welding at runtime

How do you go about tagging an entity programmatically at runtime for Contact Welding the same way you can assign a “Custom Tag” on a PhysicsBody authoring component attached to a GameObject in the inspector?

I have entities which RenderMesh and all other components are created at runtime. I would like to use the Contact Point Welding feature which Havok physics provides, but I cannot find how to use the feature without a PhysicsBody GameObject authoring component. Is there a way to enable the feature for or tag certain entities/colliders using SystemBase or some other static method?

You need to define tags that will enable welding before simulation runs (in HavokConfiguration). Then, if you want to opt in or opt out bodies, you just need to wait for BuildPhysicsWorld system to finish, get an appropriate RigidBody on the PhysicsWorld, and set its CustomTags field. That will do the trick for you.

I seem to be having trouble converting what you told me into code. A code example of your explaination would be greatly appreciated. I’m gonna try to break down my thought process:

Initial setup:

  • Define tags using the HavokConfiguration GameObject component - my selections for the dropdown on the “Body Tags For Contact Welding” field on the component are: “None”, “Everything”, “0: CheckGhostCollisions”, and a bunch of “1: (Undefined…)”, “2: (Undefined…)”, … etc.
  • Set the PhysicsStep SimulationType to Havok Physics - self-explanatory

In code:

  • Wait for BuildPhysicsWorld system to finish - I think I am supposed to do this by adding a tag above my SystemBase class:
  [UpdateBefore(typeof(Unity.Physics.Systems.BuildPhysicsWorld))]
  public class ControllableSystem : SystemBase
  • Get an appropriate RigidBody on the PhysicsWorld - now I believe I am supposed to gather the RigidBody of the triangulated surface, correct? Or am I supposed to gather the RigidBody of the dynamic/moving body? Both? I did some testing in the Physics examples that led me to believe I need to gather the RigidBody of the surface(s). Within a ForEach Entities block, gathering the surface Entities, I gather a RigidBody using this code:
          var rb_index = physicsWorldSystem.PhysicsWorld.GetRigidBodyIndex(entity);
          if (rb_index > -1)
          {
            var rb = physicsWorldSystem.PhysicsWorld.Bodies[rb_index];
  • Set the RigidBody’s CustomTags field - this is the part I am stuck at. I see that the field is accessible, however, when I write to the field, it does not seem to affect the RigidBody. It is a byte, do I simply assign a variable? rb.CustomTags = 1; The change does not seem to stick. I have a Debug.Log running each onUpdate for the entity, printing the CustomTags field and its change. Each time the field is logged, it shows that is does indeed change. However, on the next onUpdate call, the CustomTags field is back to 0. “PhysicsWorld.Bodies” seems to be readonly; am I doing this wrong?

“Full” code (trimmed):

[UpdateBefore(typeof(Unity.Physics.Systems.BuildPhysicsWorld))]
public class ControllableSystem : SystemBase
{
    protected override void OnCreate()
    ...

    protected override void OnDestroy()
    ...

    protected override void OnUpdate()
    {
      // Gather physics world
      var physicsWorldSystem = World.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>();

      // Append custom physics tag for contact welding
      Entities
        .ForEach((Entity entity, in VoxelChunkEntity chunk) =>
        {
          var rb_index = physicsWorldSystem.PhysicsWorld.GetRigidBodyIndex(entity);
          if (rb_index > -1)
          {
            var rb = physicsWorldSystem.PhysicsWorld.Bodies[rb_index];
            if (rb.CustomTags == 0)
            {
              var value_old = rb.CustomTags;
              rb.CustomTags = 1;
              Debug.Log($"{rb_index}: {value_old} .. {rb.CustomTags}");
            }
          }
        })
        .WithoutBurst()
        .Run();
    }
   
}

The code above is used for debugging purposes. Once I get this figured out, the CustomTags will not be assigned to each frame unless needed.

I think I’ve solved it.

Ignore all of the code above, the solution is much simpler.

Attach a PhysicsCustomTags component to the entity like so:

          EntityManager.AddComponentData(entity, new PhysicsCustomTags() { Value = 1 });

The above code assigns the PhysicsCustomTags Value to 1, which sets it to the 1st custom physics body tag found in the Havok Physics Configuration GameObject component “Body Tags For Welding” list (marked index 0). The value is a byte so I’m sure there’s a proper way to assign the value other than mine.

The movement of my dynamic body is now very smooth!

Update: After some testing, it looks like you can put the PhysicsCustomTags component on the surface or the dynamic body entities, it does not seem to matter. However, maybe it’s better to put the component on the terrain, the dynamic bodies, or both; maybe whichever you have less of? Anyone knows?

Just to add to the initial solution you had, you would need UpdateAfter BuildPhysicsWorld, and also when you set rb.CustomTags you need to write back the rb to the Bodies array.

But yeah, your second solution is more neat. And regarding the question, you should put the tag on bodies that are of high importance for your game, if you put it on terrain for example then every dynamic body that ends up on that terrain will have welding enabled, and that costs performance.

Thanks, that makes sense.

As for the initial solution, I attempted to do something like this before:

var rb = physicsWorldSystem.PhysicsWorld.Bodies[rb_index];
rb.CustomTags = 1;
physicsWorldSystem.PhysicsWorld.Bodies[rb_index] = rb;

However, this produces a compilation error as PhysicsWorld.Bodies is readonly. What is the proper way to write back to the Bodies array?

Yeah you need something like

var bodies = physicsWorldSystem.PhysicsWorld.Bodies;
var rb = bodies[rb_index];
rb.CustomTags = 1;
bodies[rb_index] = rb;

That works! Thanks

1 Like