Search Unity

[Unity.Physics.MeshCollider.Create] Slow : More parameters to disable internal checks

Discussion in 'Physics for ECS' started by dyox, Nov 12, 2019.

  1. dyox

    dyox

    Joined:
    Aug 19, 2011
    Posts:
    619
    Hello,

    Actually the use of Unity.Physics.MeshCollider.Create to create/modify procedural meshes in realtime is slow, even with Burst, due to many checks inside :
    -indices referencing outside vertex array
    -MeshConnectivityBuilder.WeldVertices
    - Build bounding volume hierarchy
    -etc

    Is it possible to provide a function with more parameters to disable all this checks, if users have already made them on other systems/jobs before, this may increase speed.

    Also it could be interesting to have access to MeshConnectivityBuilder ,MeshBuilder to build/provide mesh directly to MeshCollider or at least decompose the creation process into multiple functions to dispatch over frames. (BoundingVolumeHierarchy,TempSection,AABB).

    Thanks.
     
    Last edited: Nov 12, 2019
    andywatts, Occuros, Nothke and 3 others like this.
  2. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    I've logged this request. How comfortable are you (and folk in general reading this) with making Unity Physics a local package, trying to do this yourself and sharing your implementation here?
     
  3. dyox

    dyox

    Joined:
    Aug 19, 2011
    Posts:
    619
    Yes.

    This is my Implementation of Physics_MeshCollider.cs with CookingOptions parameters :

    Code (CSharp):
    1. using System;
    2. using System;
    3. using System.ComponentModel;
    4. using Unity.Collections;
    5. using Unity.Collections.LowLevel.Unsafe;
    6. using Unity.Mathematics;
    7. using Unity.Entities;
    8.  
    9. namespace Unity.Physics
    10. {
    11.     // A collider representing a mesh comprised of triangles and quads.
    12.     // Warning: This is just the header, it is followed by variable sized data in memory.
    13.     // Therefore this struct must always be passed by reference, never by value.
    14.     public struct MeshCollider : ICompositeCollider
    15.     {
    16.         public enum MeshCookingOptions
    17.         {
    18.             None = 0,
    19.             EnableMeshCleaning = 1,
    20.             WeldColocatedVertices = 2,
    21.         }
    22.      
    23.         ColliderHeader m_Header;
    24.         Aabb m_Aabb;
    25.         internal Mesh Mesh;
    26.  
    27.         // followed by variable sized mesh data
    28.  
    29.         #region Construction
    30.  
    31.         // Create a mesh collider asset from a set of triangles
    32.         public static BlobAssetReference<Collider> Create(NativeArray<float3> vertices, NativeArray<int> indices, MeshCookingOptions cookingOptions = MeshCookingOptions.EnableMeshCleaning | MeshCookingOptions.WeldColocatedVertices) =>
    33.             Create(vertices, indices, CollisionFilter.Default, Material.Default, cookingOptions);
    34.  
    35.         public static BlobAssetReference<Collider> Create(NativeArray<float3> vertices, NativeArray<int> indices, CollisionFilter filter, MeshCookingOptions cookingOptions = MeshCookingOptions.EnableMeshCleaning | MeshCookingOptions.WeldColocatedVertices) =>
    36.             Create(vertices, indices, filter, Material.Default, cookingOptions);
    37.  
    38.         public static unsafe BlobAssetReference<Collider> Create(NativeArray<float3> vertices, NativeArray<int> indices, CollisionFilter filter, Material material, MeshCookingOptions cookingOptions = MeshCookingOptions.EnableMeshCleaning | MeshCookingOptions.WeldColocatedVertices)
    39.         {
    40.             int numIndices = indices.Length;
    41.             int numTriangles = numIndices / 3;
    42.  
    43.             // Copy vertices
    44.             var tempVertices = vertices;
    45.  
    46.             // Copy indices
    47.             NativeArray<int> tempIndices;
    48.  
    49.             if ((cookingOptions & MeshCookingOptions.EnableMeshCleaning) == MeshCookingOptions.EnableMeshCleaning)
    50.             {
    51.                 tempIndices = new NativeArray<int>(numIndices, Allocator.Temp);
    52.              
    53.                 for (int iTriangle = 0; iTriangle < numTriangles; iTriangle++)
    54.                 {
    55.                     int iIndex0 = iTriangle * 3;
    56.                     int iIndex1 = iIndex0 + 1;
    57.                     int iIndex2 = iIndex0 + 2;
    58.  
    59.                     if (indices[iIndex0] >= 0 && indices[iIndex0] < vertices.Length
    60.                         && indices[iIndex1] >= 0 && indices[iIndex1] < vertices.Length
    61.                         && indices[iIndex2] >= 0 && indices[iIndex2] < vertices.Length)
    62.                     {
    63.                         tempIndices[iIndex0] = indices[iIndex0];
    64.                         tempIndices[iIndex1] = indices[iIndex1];
    65.                         tempIndices[iIndex2] = indices[iIndex2];
    66.                     }
    67.                     else
    68.                     {
    69.                         throw new ArgumentException("Tried to create a MeshCollider with indices referencing outside vertex array");
    70.                     }
    71.                 }
    72.             }
    73.             else
    74.             {
    75.                 tempIndices = new NativeArray<int>(indices, Allocator.Temp);
    76.             }
    77.  
    78.             // Build connectivity and primitives
    79.  
    80.             NativeList<float3> uniqueVertices;
    81.  
    82.             if ((cookingOptions & MeshCookingOptions.WeldColocatedVertices) == MeshCookingOptions.WeldColocatedVertices)
    83.             {
    84.                 uniqueVertices = MeshConnectivityBuilder.WeldVertices(tempIndices, tempVertices);
    85.             }
    86.             else
    87.             {
    88.                 uniqueVertices = new NativeList<float3>(tempVertices.Length, Allocator.Temp);
    89.                 uniqueVertices.AddRange(tempVertices);
    90.             }
    91.  
    92.  
    93.             var connectivity = new MeshConnectivityBuilder(tempIndices, uniqueVertices);
    94.             NativeList<MeshConnectivityBuilder.Primitive> primitives = connectivity.EnumerateQuadDominantGeometry(tempIndices, uniqueVertices);
    95.  
    96.             int primitivesLength = primitives.Length;
    97.  
    98.             // Build bounding volume hierarchy
    99.             int nodeCount = math.max(primitivesLength * 2 + 1, 2); // We need at least two nodes - an "invalid" node and a root node.
    100.             var nodes = new NativeArray<BoundingVolumeHierarchy.Node>(nodeCount, Allocator.Temp);
    101.             int numNodes = 0;
    102.  
    103.             {
    104.                 // Prepare data for BVH
    105.                 var points = new NativeList<BoundingVolumeHierarchy.PointAndIndex>(primitivesLength, Allocator.Temp);
    106.                 var aabbs = new NativeArray<Aabb>(primitivesLength, Allocator.Temp);
    107.  
    108.                 for (int i = 0; i < primitives.Length; i++)
    109.                 {
    110.                     MeshConnectivityBuilder.Primitive p = primitives[i];
    111.  
    112.                     // Skip degenerate triangles
    113.                     if (MeshConnectivityBuilder.IsTriangleDegenerate(p.Vertices[0], p.Vertices[1], p.Vertices[2]))
    114.                     {
    115.                         continue;
    116.                     }
    117.  
    118.                     aabbs[i] = Aabb.CreateFromPoints(p.Vertices);
    119.                     points.Add(new BoundingVolumeHierarchy.PointAndIndex
    120.                     {
    121.                         Position = aabbs[i].Center,
    122.                         Index = i
    123.                     });
    124.                 }
    125.  
    126.                 var bvh = new BoundingVolumeHierarchy(nodes);
    127.  
    128.                 bvh.Build(points.AsArray(), aabbs, out numNodes, useSah: true);
    129.             }
    130.  
    131.             // Build mesh sections
    132.             BoundingVolumeHierarchy.Node* nodesPtr = (BoundingVolumeHierarchy.Node*)nodes.GetUnsafePtr();
    133.             MeshBuilder.TempSection sections = MeshBuilder.BuildSections(nodesPtr, numNodes, primitives);
    134.  
    135.             // Allocate collider
    136.             int meshDataSize = Mesh.CalculateMeshDataSize(numNodes, sections.Ranges);
    137.             int totalColliderSize = Math.NextMultipleOf(sizeof(MeshCollider), 16) + meshDataSize;
    138.          
    139.             MeshCollider* meshCollider = (MeshCollider*)UnsafeUtility.Malloc(totalColliderSize, 16, Allocator.Temp);
    140.  
    141.             // Initialize it
    142.             {
    143.                 UnsafeUtility.MemClear(meshCollider, totalColliderSize);
    144.                 meshCollider->MemorySize = totalColliderSize;
    145.  
    146.                 meshCollider->m_Header.Type = ColliderType.Mesh;
    147.                 meshCollider->m_Header.CollisionType = CollisionType.Composite;
    148.                 meshCollider->m_Header.Version += 1;
    149.                 meshCollider->m_Header.Magic = 0xff;
    150.  
    151.                 ref var mesh = ref meshCollider->Mesh;
    152.  
    153.                 mesh.Init(nodesPtr, numNodes, sections, filter, material);
    154.  
    155.                 // Calculate combined filter
    156.                 meshCollider->m_Header.Filter = mesh.Sections.Length > 0 ? mesh.Sections[0].Filters[0] : CollisionFilter.Default;
    157.                 for (int i = 0; i < mesh.Sections.Length; ++i)
    158.                 {
    159.                     for (var j = 0; j < mesh.Sections[i].Filters.Length; ++j)
    160.                     {
    161.                         var f = mesh.Sections[i].Filters[j];
    162.                         meshCollider->m_Header.Filter = CollisionFilter.CreateUnion(meshCollider->m_Header.Filter, f);
    163.                     }
    164.                 }
    165.  
    166.                 meshCollider->m_Aabb = meshCollider->Mesh.BoundingVolumeHierarchy.Domain;
    167.                 meshCollider->NumColliderKeyBits = meshCollider->Mesh.NumColliderKeyBits;
    168.             }
    169.  
    170.             // Copy collider into blob
    171.             var blob = BlobAssetReference<Collider>.Create(meshCollider, totalColliderSize);
    172.             UnsafeUtility.Free(meshCollider, Allocator.Temp);
    173.             return blob;
    174.         }
    175.  
    176.         #endregion
    177.  
    178.         #region ICompositeCollider
    179.  
    180.         public ColliderType Type => m_Header.Type;
    181.         public CollisionType CollisionType => m_Header.CollisionType;
    182.         public int MemorySize { get; private set; }
    183.  
    184.         public CollisionFilter Filter => m_Header.Filter;
    185.  
    186.         public MassProperties MassProperties
    187.         {
    188.             get
    189.             {
    190.                 // Rough approximation based on AABB
    191.                 float3 size = m_Aabb.Extents;
    192.                 return new MassProperties
    193.                 {
    194.                     MassDistribution = new MassDistribution
    195.                     {
    196.                         Transform = new RigidTransform(quaternion.identity, m_Aabb.Center),
    197.                         InertiaTensor = new float3(
    198.                             (size.y * size.y + size.z * size.z) / 12.0f,
    199.                             (size.x * size.x + size.z * size.z) / 12.0f,
    200.                             (size.x * size.x + size.y * size.y) / 12.0f)
    201.                     },
    202.                     Volume = 0,
    203.                     AngularExpansionFactor = math.length(m_Aabb.Extents) * 0.5f
    204.                 };
    205.             }
    206.         }
    207.  
    208.         public Aabb CalculateAabb()
    209.         {
    210.             return m_Aabb;
    211.         }
    212.  
    213.         public Aabb CalculateAabb(RigidTransform transform)
    214.         {
    215.             // TODO: Store a convex hull wrapping the mesh, and use that to calculate tighter AABBs?
    216.             return Math.TransformAabb(transform, m_Aabb);
    217.         }
    218.  
    219.         // Cast a ray against this collider.
    220.         public bool CastRay(RaycastInput input) => QueryWrappers.RayCast(ref this, input);
    221.         public bool CastRay(RaycastInput input, out RaycastHit closestHit) => QueryWrappers.RayCast(ref this, input, out closestHit);
    222.         public bool CastRay(RaycastInput input, ref NativeList<RaycastHit> allHits) => QueryWrappers.RayCast(ref this, input, ref allHits);
    223.         public unsafe bool CastRay<T>(RaycastInput input, ref T collector) where T : struct, ICollector<RaycastHit>
    224.         {
    225.             fixed (MeshCollider* target = &this)
    226.             {
    227.                 return RaycastQueries.RayCollider(input, (Collider*)target, ref collector);
    228.             }
    229.         }
    230.  
    231.         // Cast another collider against this one.
    232.         public bool CastCollider(ColliderCastInput input) => QueryWrappers.ColliderCast(ref this, input);
    233.         public bool CastCollider(ColliderCastInput input, out ColliderCastHit closestHit) => QueryWrappers.ColliderCast(ref this, input, out closestHit);
    234.         public bool CastCollider(ColliderCastInput input, ref NativeList<ColliderCastHit> allHits) => QueryWrappers.ColliderCast(ref this, input, ref allHits);
    235.         public unsafe bool CastCollider<T>(ColliderCastInput input, ref T collector) where T : struct, ICollector<ColliderCastHit>
    236.         {
    237.             fixed (MeshCollider* target = &this)
    238.             {
    239.                 return ColliderCastQueries.ColliderCollider(input, (Collider*)target, ref collector);
    240.             }
    241.         }
    242.  
    243.         // Calculate the distance from a point to this collider.
    244.         public bool CalculateDistance(PointDistanceInput input) => QueryWrappers.CalculateDistance(ref this, input);
    245.         public bool CalculateDistance(PointDistanceInput input, out DistanceHit closestHit) => QueryWrappers.CalculateDistance(ref this, input, out closestHit);
    246.         public bool CalculateDistance(PointDistanceInput input, ref NativeList<DistanceHit> allHits) => QueryWrappers.CalculateDistance(ref this, input, ref allHits);
    247.         public unsafe bool CalculateDistance<T>(PointDistanceInput input, ref T collector) where T : struct, ICollector<DistanceHit>
    248.         {
    249.             fixed (MeshCollider* target = &this)
    250.             {
    251.                 return DistanceQueries.PointCollider(input, (Collider*)target, ref collector);
    252.             }
    253.         }
    254.  
    255.         // Calculate the distance from another collider to this one.
    256.         public bool CalculateDistance(ColliderDistanceInput input) => QueryWrappers.CalculateDistance(ref this, input);
    257.         public bool CalculateDistance(ColliderDistanceInput input, out DistanceHit closestHit) => QueryWrappers.CalculateDistance(ref this, input, out closestHit);
    258.         public bool CalculateDistance(ColliderDistanceInput input, ref NativeList<DistanceHit> allHits) => QueryWrappers.CalculateDistance(ref this, input, ref allHits);
    259.         public unsafe bool CalculateDistance<T>(ColliderDistanceInput input, ref T collector) where T : struct, ICollector<DistanceHit>
    260.         {
    261.             fixed (MeshCollider* target = &this)
    262.             {
    263.                 return DistanceQueries.ColliderCollider(input, (Collider*)target, ref collector);
    264.             }
    265.         }
    266.  
    267.         public uint NumColliderKeyBits { get; private set; }
    268.  
    269.         public bool GetChild(ref ColliderKey key, out ChildCollider child)
    270.         {
    271.             if (key.PopSubKey(NumColliderKeyBits, out uint subKey))
    272.             {
    273.                 int primitiveKey = (int)(subKey >> 1);
    274.                 int polygonIndex = (int)(subKey & 1);
    275.  
    276.                 Mesh.GetPrimitive(primitiveKey, out float3x4 vertices, out Mesh.PrimitiveFlags flags, out CollisionFilter filter, out Material material);
    277.  
    278.                 if (Mesh.IsPrimitveFlagSet(flags, Mesh.PrimitiveFlags.IsQuad))
    279.                 {
    280.                     child = new ChildCollider(vertices[0], vertices[1], vertices[2], vertices[3], filter, material);
    281.                 }
    282.                 else
    283.                 {
    284.                     child = new ChildCollider(vertices[0], vertices[1 + polygonIndex], vertices[2 + polygonIndex], filter, material);
    285.                 }
    286.  
    287.                 return true;
    288.             }
    289.  
    290.             child = new ChildCollider();
    291.             return false;
    292.         }
    293.  
    294.         public bool GetLeaf(ColliderKey key, out ChildCollider leaf)
    295.         {
    296.             return GetChild(ref key, out leaf);
    297.         }
    298.  
    299.         public unsafe void GetLeaves<T>(ref T collector) where T : struct, ILeafColliderCollector
    300.         {
    301.             var polygon = new PolygonCollider();
    302.             polygon.InitEmpty();
    303.             if (Mesh.GetFirstPolygon(out uint meshKey, ref polygon))
    304.             {
    305.                 do
    306.                 {
    307.                     var leaf = new ChildCollider((Collider*)&polygon, RigidTransform.identity);
    308.                     collector.AddLeaf(new ColliderKey(NumColliderKeyBits, meshKey), ref leaf);
    309.                 }
    310.                 while (Mesh.GetNextPolygon(meshKey, out meshKey, ref polygon));
    311.             }
    312.         }
    313.  
    314.         #endregion
    315.  
    316.         #region Obsolete
    317.         [EditorBrowsable(EditorBrowsableState.Never)]
    318.         [Obsolete("This signature has been deprecated. Use a signature passing native containers instead. (RemovedAfter 2019-10-25)")]
    319.         public static unsafe BlobAssetReference<Collider> Create(float3[] vertices, int[] indices, CollisionFilter? filter = null, Material? material = null)
    320.         {
    321.             var v = new NativeArray<float3>(vertices, Allocator.Temp);
    322.             var i = new NativeArray<int>(indices, Allocator.Temp);
    323.             return Create(v, i, filter ?? CollisionFilter.Default, material ?? Material.Default);
    324.         }
    325.         #endregion
    326.     }
    327. }
    328.  
    I've added MeshCookingOptions with Default to EnableMeshCleaning | WeldColocatedVertices .
    Also avoided 2 Unnecessary Temp Copy of Vertices And Indices.

    Code (csharp):
    1.  
    2. public enum MeshCookingOptions
    3.         {
    4.             None = 0,
    5.             EnableMeshCleaning = 1,
    6.             WeldColocatedVertices = 2,
    7.         }
    8.  
    Performances :

    Default : 10-13 ms
    MeshColliderDefault.png
    MeshColliderAfter.png


    Optimized : 2-5ms
    MeshColliderOptimization.png
    MeshColliderBefore.png


    Result :


    I will post other possible changes if there are any
     
    Last edited: Nov 13, 2019
    Chipboard, andywatts, bb8_1 and 6 others like this.
  4. dyox

    dyox

    Joined:
    Aug 19, 2011
    Posts:
    619
     
    bb8_1 likes this.
  5. dyox

    dyox

    Joined:
    Aug 19, 2011
    Posts:
    619
    UnityPhysics need some cache system, colliders are almost all the same at (+/- 0.01f scale..).
    Baked Colliders is the main problem actually, but for vegetation, i've something interesting in work.
     
  6. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    You can use the binary serialization from the entities package to bake stuff at design time. Raw pointer data that's fast to load no collider creation per say necessary. Combine that with the batch api's for actually creating the entities and it's all extremely fast.


    Edit:

    For runtime updates you can just reserialize the new collider. So next time the player loads the same scene/area you don't have to do that work over again, just stream it right in.
     
    Last edited: Nov 19, 2019
  7. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Also you can reuse the same collider between a lot of entities if it's the same size.
     
    dyox likes this.
  8. vildauget

    vildauget

    Joined:
    Mar 10, 2014
    Posts:
    121
    Any news/update on this? Can we expect cooking options and more optimized creation to show up in the official package, or should we look into customized solutions? Thank you.
     
  9. sietse85

    sietse85

    Joined:
    Feb 22, 2019
    Posts:
    99
    Hello i am generating terrain chunks procedural and as such also mesh colliders. The game freezes up when the mesh colliders are being generated. So possibly because of all of the internal checks? Hope to hear a solution. Thanks!
     
  10. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    It usually freezes because of synchronous Burst compilation on mesh collider creation, that part is not due to the performance of the internal checks.
     
  11. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Is there a way to do this asynchronously?
     
  12. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    At the moment, not if you don't want to change the physics package. You can go to Edit/Project Settings, and in the editor tab scroll all the way down to Enter Play Mode Settings and enable the experimental feature. That should cache Burst compilation results so you would get the synchronous compilation only once if nothing has changed in the meantime.
     
    vildauget likes this.
  13. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Nah, I mean can you call some equivalent of `MeshCollider.Create` from a job/worker thread?
     
  14. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Oh, of course, if you have points and triangles buffer you can create it from your own job for sure.
     
  15. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    723
    @petarmHavok are there any news/updates planned for the performance improvements for procedural MeshColliders via MeshCollider.Create?

    I understand this is not cheap, but I really struggle a lot with the performance cost of this method.



    Edit: While not the solution to all of my problems I want to highlight how huge the difference with a BurstedJob as suggested by @petarmHavok (even without parallelization) is:
    MeshCollider.Create took 6s instead of 30s from a BurstedJob.

    Next step will be to parallize this. It will still be in the "many seconds" with this, but it could bring this conversion down from multiple hours to many minutes.
     
    Last edited: Apr 12, 2022
  16. maciejgorski

    maciejgorski

    Joined:
    Oct 7, 2015
    Posts:
    8
    Hey. Great job. But how does force Unity to use other implementation of this class than built-in? How make unity.physics a local package?
     
    Last edited: May 5, 2022
  17. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    723
    @maciejgorski copy it to your scripts folder and remove it from the package manager. You loose update support and need to redo all changes on any new version.
     
  18. maciejgorski

    maciejgorski

    Joined:
    Oct 7, 2015
    Posts:
    8
    Thanks for reply. But how to disbale the old one unity.physics package? Im filtering packages in manager but the only place I see is Disable button while listing Built-in packages in Physics. I'am ubanble to use it cause of dependencies.
    Did You mean that Disable button?
     
  19. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    723
    @maci0jkamo2 ... interesting. Which version of Unity?
    upload_2022-5-6_9-16-9.png
    I have a "Remove" button for Unity.Physics
     
  20. maciejgorski

    maciejgorski

    Joined:
    Oct 7, 2015
    Posts:
    8
    Its 2020.3.22f1. It looks like playing with packages caused this issue. Anyway I was able finnaly to remove unity physics package and put its code to my scripts. Still strugling with havoc those packages are dependant and probably I have to move them both. Did You also do that?
     
  21. mk1987

    mk1987

    Joined:
    Mar 18, 2019
    Posts:
    53
    I have been having some issues with this function in general myself. I am creating a collider which in this case has approx 60,000 Tri's converting a procedurally generated gameobject into a entity (since the 'creation' tool in my game is all legacy in gameobjects and the 'gameplay' aspect is entity DOTS).

    Whilst i can get it to work it appears to take around 1.4s non-burst and 0.3s burst creating a noticeable stutter which in VR can be nasty and seizure inducing. What i had tried to do was schedule it in a IJob and in my conversion code wait for that job to finish, it gives the impression its worked and im stutter free as im not blocking the main thread but the blobassetreference<Physics.Collider> created using MeshColider.Create() is seemingly invalid since it doesn't collide with anything. If i pause it at time of scheduling for a couple seconds or tell it complete at schedule. the collider produced is correct and working, the same as if left to run on the main thread.

    Am i right in thinking that MeshCollider.Create() and/or blobassetreferences cannot be run over multiple frames, behaving as if its using Allocation.Temp/TempJob and not persistant? The ideal solution is for it to run faster of course and should be the focus, but it is frustrating that i cant put that function into the background.

    For ref im using Entities 0.50 with 2020.3.33.
     
  22. davidus2010

    davidus2010

    Joined:
    Dec 4, 2017
    Posts:
    72
    Is there any update on this with the 1.0.0-exp15 release? It seems like all the required classes are still internal-only, so we can't use a version with cooking options ourselves, and they still haven't been added to unity physics. So we still still are forced to do all the checks mentioned in the initial post.
     
  23. Spemble

    Spemble

    Joined:
    Mar 20, 2016
    Posts:
    7
    Did anyone make progress on this? Any tips on what to do? This feature would be very helpful for me.

    Would you be able to share the code you have to do this? I tried putting the function call in a job and the collider doesn't work anymore.