Search Unity

Resolved Unity Physics runtime mesh collider creation and modification

Discussion in 'DOTS Dev Blitz Day 2022 - Q&A' started by pbhogan, Dec 8, 2022.

  1. pbhogan

    pbhogan

    Joined:
    Aug 17, 2012
    Posts:
    384
    Unity Entities Graphics has some great convenience features to enable runtime mesh creation / modification:
    1. RenderMeshUtility.AddComponents for runtime mesh creation
    2. MaterialMeshInfo (and RegisterMesh / RegisterMaterial calls) for efficiently changing meshes at runtime
    Are there any plans to add similar helpers and concepts for DOTS Physics?

    Procedural terrain is a good use case. There is the need to create meshes at runtime and, if the terrain is modifiable at runtime, then there is a need to efficiently update mesh colliders at runtime.

    I've rolled my own "PhysicsUtility.AddComponents"-style helpers for creating a mesh collider at runtime by looking at the physics internals, but this is obviously quite fragile. Specifically, taking a Mesh (or MeshDataArray), ColliderFilter and (physics) Material and building a BlobAssetReference<Collider>. It sure would be nice to have a supported helper API to rely on for this. I have no idea if it's possible to change a collider efficiently at runtime without building a whole new collider, but I'd love if there was a way to build the collider asynchronously and do a MaterialMeshInfo-style ID swap efficiently.
     
    scottjdaley likes this.
  2. IsaacsUnity

    IsaacsUnity

    Unity Technologies

    Joined:
    Mar 1, 2022
    Posts:
    94
    Thanks for the question! We currently can't modify a compound collider after creation as it is read-only, although we understand this feature can be valuable in some cases. Aside from this feedback, if this feature and use case is important to you, do share more on our public roadmap.
     
    daniel-holz likes this.
  3. daniel-holz

    daniel-holz

    Unity Technologies

    Joined:
    Sep 17, 2021
    Posts:
    278
    Did you have a look at Physics.MeshCollider.Create()?

    Code (CSharp):
    1. public static BlobAssetReference<Collider> Create(NativeArray<float3> vertices, NativeArray<int3> triangles, CollisionFilter filter, Material material)
    If it's creation of a mesh you are looking for, this function should do the job. It doesn't take a Mesh as input directly but it's used in the MeshBlobsJob (in BaseShapeBakingSystem.cs) for asynchronous creation of BlobAssetReference<Collider>'s.
    This job extracts the vertices and triangles for each mesh in a MeshDataArray in parallel and creates a BlobAssetReference<Collider> for them.

    If I understand correctly, for starters you would like an officially supported API in some utilities class which does exactly that, but for a single Mesh.

    Please let me know if my understanding is correct.
     
  4. pbhogan

    pbhogan

    Joined:
    Aug 17, 2012
    Posts:
    384
    Yes, that's correct.

    My own implementation uses Physics.MeshCollider.Create() under the hood, and it pretty much does what you describe... it gets the MeshData and builds the vertices and triangles NativeArrays in a job and passes it to Physics.MeshCollider.Create() in another job.

    It's not that any of that is particularly difficult, but there are some fiddly bits dealing with the correct index format of the MeshData to build the triangles, handle all the sub-meshes, wrap it in jobs, etc. I definitely had to go dig into the physics codebase to figure out exactly what to do. It just seems like there should be something in the general public API that takes a Mesh, MeshData or MeshDataArray (along with the CollisionFilter and Material) and spits out a BlobAssetReference<Collider> and just abstracts away the internal complexity of these fairly common operations.

    My wishlist would be to add:

    Code (CSharp):
    1.  
    2. public static BlobAssetReference<Collider> Create( Mesh mesh, CollisionFilter filter, Material material );
    3. public static BlobAssetReference<Collider> Create( MeshData meshData, CollisionFilter filter, Material material );
    4. public static BlobAssetReference<Collider> Create( MeshDataArray meshDataArray, CollisionFilter filter, Material material );
    5.  
    ... maybe along with some simple jobs to wrap the three burst-able calls (NativeArrays, MeshData and MeshDataArray). Again, something that is trivial to write, but is just another thing that many people will have to do.

    Finally, in my PhysicsUtility class, I have it all wrapped in a call that has RenderMeshUtility.AddComponents() vibes, taking an Entity and EntityManager and adding the correct components. But, that's just gravy. :)
     
    daniel-holz likes this.
  5. daniel-holz

    daniel-holz

    Unity Technologies

    Joined:
    Sep 17, 2021
    Posts:
    278
    That sounds good. I agree.
    I will relay that request internally.
     
  6. daniel-holz

    daniel-holz

    Unity Technologies

    Joined:
    Sep 17, 2021
    Posts:
    278
    @pbhogan Hi again!
    We are starting to look into the solution for this and have some more questions.
    If I understand the use case correctly here, you are taking the Mesh object from some collider, and then you create another collider from it.
    Is there a reason why you don't just clone the current collider? Is it because you would like to make modifications to the Mesh?
     
  7. pbhogan

    pbhogan

    Joined:
    Aug 17, 2012
    Posts:
    384
    Hi @daniel-holz

    No, I'm creating an entirely new collider given a procedurally generated Mesh (or MeshData / MeshDataArray). Think colliders for procedurally generated terrain chunks.

    In my case, the terrain is not only procedurally generated at runtime, but can also be modified at runtime (something like No Man's Sky or Astroneer). So, I not only need to create the mesh colliders for each terrain chunk at runtime but also modify them at runtime given a new mesh. I understand modification is it's own can of worms so just replacing works too.

    Again, Physics.MeshCollider.Create() is fine—it's just lower level than what is typically needed, and requires unpacking the mesh data into arrays, building the triangle list, etc. Most developers are just thinking: I have a mesh and I want a collider, where's the mesh-to-collider function.

    Also, the more that can be done asynchronously in a job, the better.
     
  8. daniel-holz

    daniel-holz

    Unity Technologies

    Joined:
    Sep 17, 2021
    Posts:
    278
    @pbhogan
    This added context is very helpful in understanding your use case better. Thank you!
    Now that I am better informed about what you are trying to do here, to avoid any misunderstanding before we advance on this, I would just like to confirm that the
    Mesh
    ,
    MeshData
    and
    MeshDataArray
    types you are talking about are indeed the following
    UnityEngine
    types.
    I am asking, because there is also an internal
    Unity.Physics.Mesh
    type that is used in the Unity Physics
    MeshCollider
    .
     
    tmonestudio likes this.
  9. pbhogan

    pbhogan

    Joined:
    Aug 17, 2012
    Posts:
    384
    @daniel-holz

    Yes, those are the types I'm referring to.

    If it's helpful, here's a gist of my current utility code related to this. It doesn't handle every case, there's some default behavior specific to my current prototyping and it isn't optimized but should give you an idea of what I'm doing.

    https://gist.github.com/pbhogan/d9170ff611eff23229274bec9207a633

    CreateColliderForMesh() is most applicable to the discussion here, but AddComponentsForMesh() is also worth noting as a similarity to Unity's RenderMeshUtility.AddComponents()
     
    daniel-holz likes this.
  10. daniel-holz

    daniel-holz

    Unity Technologies

    Joined:
    Sep 17, 2021
    Posts:
    278
    Fantastic. Thanks!
     
    filod likes this.
  11. Ziddon

    Ziddon

    Joined:
    Feb 6, 2015
    Posts:
    27
    Hey, I just wanted to chime in here as I'm working on a similar project and would really love a solution for this as well. Being able to create a mesh collider at runtime using the job system would be super cool.

    It would be ideal to be able to create multiple mesh blob/object in a burst compiled job, since multiple chunks are sometimes created simultaneously (world initial creation or lod change).

    Please let me know if this gets put on the roadmap as I'd be happy to vote on it.
     
    daniel-holz likes this.
  12. daniel-holz

    daniel-holz

    Unity Technologies

    Joined:
    Sep 17, 2021
    Posts:
    278
    Quick update here. We've completed implementing
    MeshCollider
    creation functions which work for the proposed
    UnityEngine
    mesh data types and these are already available in the current experimental 1.1 release. See here.
    These are burstable and have been tested to work within Burst-compiled jobs as part of our automatic tests.
     
    andywatts, bzor, JesOb and 1 other person like this.
  13. filod

    filod

    Joined:
    Oct 3, 2015
    Posts:
    224
    it will be even greater if the samples project can also be updated :D
     
    daniel-holz likes this.
  14. daniel-holz

    daniel-holz

    Unity Technologies

    Joined:
    Sep 17, 2021
    Posts:
    278
    Agreed!
    This is in the making. The samples project will only be updated to the latest version once the latest version is out of experimental and out of prerelease. It's gonna happen!
     
  15. filod

    filod

    Joined:
    Oct 3, 2015
    Posts:
    224
    sounds great, i already managed use this in my tilemap system just now, it's so simple and works like a charm:

    Code (CSharp):
    1.  
    2.             // create any mesh/entity you like (use RenderMeshUtility.AddComponents)
    3.             state.EntityManager.AddComponentData(entity, new PhysicsCollider()
    4.             {
    5.                 Value = MeshCollider.Create(mesh, extraInfo.PhysicsInfo.CollisionFilter,
    6.                     extraInfo.PhysicsInfo.Material)
    7.             });
    8.             state.EntityManager.AddSharedComponent(entity, new PhysicsWorldIndex());
    for physics material, you can use PhysicsMaterialTemplate and create like this:
    Code (CSharp):
    1. new TilePhysicsInfo()
    2.             {
    3.                 Material = new Unity.Physics.Material
    4.                 {
    5.                     Friction = PhsicsMaterialTemplate.Friction.Value,
    6.                     FrictionCombinePolicy = PhsicsMaterialTemplate.Friction.CombineMode,
    7.                     Restitution = PhsicsMaterialTemplate.Restitution.Value,
    8.                     RestitutionCombinePolicy = PhsicsMaterialTemplate.Restitution.CombineMode,
    9.                     CollisionResponse = PhsicsMaterialTemplate.CollisionResponse,
    10.                     CustomTags = PhsicsMaterialTemplate.CustomTags.Value
    11.                 },
    12.                 CollisionFilter = new CollisionFilter()
    13.                 {
    14.                     BelongsTo = PhsicsMaterialTemplate.BelongsTo.Value,
    15.                     CollidesWith = PhsicsMaterialTemplate.CollidesWith.Value
    16.                 }
    17.             }
    i do have a question, how to dispose/free this generated mesh/collider memory? since it can be generate quite frequently, can i just call blob.Dispose() ?
     
    Last edited: Nov 8, 2023
    daniel-holz likes this.
  16. daniel-holz

    daniel-holz

    Unity Technologies

    Joined:
    Sep 17, 2021
    Posts:
    278
    Great to hear it works fine for you!

    Dispose: yes, just call blob.Dispose().
    You should dispose of these when you don't need them anymore. That lifetime management can either be done using a manually created array / list of your blobs that you release at the very end of your game.
    Or, if you want to dispose of the blobs when entities get deleted, you can use the cleanup component approach documented here.
     
    filod likes this.
  17. pbhogan

    pbhogan

    Joined:
    Aug 17, 2012
    Posts:
    384
    Thanks for this @daniel-holz
    I'm excited to try this out when I get a chance1
     
    daniel-holz likes this.
  18. VinylStar

    VinylStar

    Joined:
    Apr 15, 2022
    Posts:
    3
    Thanks for this, it's very interesting work.

    I'm attempting to transition my code from using normal GameObjects to store procedural meshes to the ECS paradigm. I'm having some large performance regressions compared to the PhysX bake pathway. For me, the Physics.Create method is somewhere between 5-10x slower than the PhysX bake job. Do you guys have any benchmarking data to confirm if this is expected or if it's something I'm doing wrong? I really like the convenience of this new API as I am wanting to move to only one physics system rather than using both the traditional one and the new Entities Physics.

    I moved away from using Create(MeshData, CollisionFilter, Material) towards the direct Create(NativeArray<float3>, NativeArray<int3>) as the Create that uses MeshData has some extra checks in there (the call to
    MeshUtilities.AppendMeshPropertiesToNativeBuffers). This has made it somewhat faster, but still its 5x+ worse than the PhysX version.

    Other ideas I have is somehow calling without the SafetyChecks.CheckTriangleIndicesInRangeAndThrow check, or allow me to directly pass in the tempIndices. Any other tips would be appreciated. Thanks again.
     
    Last edited: Apr 26, 2024 at 1:34 AM