Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Question Physics.BakeMesh question

Discussion in '2019.3 Beta' started by Peter77, Sep 7, 2019.

  1. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,471
    In Unity 2019.3, there is the new Physics.BakeMesh API:
    https://docs.unity3d.com/2019.3/Documentation/ScriptReference/Physics.BakeMesh.html

    If I bake a mesh at runtime and assign it to a MeshCollider, do the cookingOptions in the MeshCollider have any affect? Do I need to set the MeshCollider.cookingOptions to None if I assign a baked mesh?

    There seem to be no cookingOptions for Physics.BakeMesh?

    The documentation reads:
    I don't understand this. When I assign a physics-baked mesh to a MeshCollider, what is being instantiated? I'm dynamically switching MeshCollider meshes at runtime, like through a flipbook. Would this cause any issues?
     
    Last edited: Sep 8, 2019
    Prodigga and Grizmu like this.
  2. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    Thanks for the great in-depth questions.

    Let me go through some of the aspects of interaction with MeshCollider.

    In practical terms, the most expensive function of MeshCollider is its sharedMesh property (MeshCollider::SetSharedMesh in the native lands if you examined the callstacks).

    Changing sharedMesh might cause an expensive cooking/baking run. Whenever the sharedMesh property is changed, we will only reuse the PhysX mesh pointer stored in the Mesh instance if:
    - this MeshCollider's cookingOptions are exactly the default ones, AND
    - the MeshCollider's transform is good (*), AND
    - the Mesh instance hasn't been changed since the last time cooking was ran.

    (*) Here, MeshCollider's transform is good when
    - it's scaling is not negative and not skewed, OR
    - it's scaling can be negative but only when MeshCollider is not convex

    (Keep in mind that cooking requires the readable property of the Mesh set)

    The cookingOptions are not stored in the Mesh instance, they belong to the MeshCollider instance currently. For that reason we will only write the PhysX mesh pointer back to Mesh if the cookingOptions are default.

    Getting back to Physics.BakeMesh - it's supposed to be used in conjunction with MeshColliders that have the default cooking options, as otherwise the PhysX mesh pointer won't be shared.

    Does this help?
     
    Peter77 and Prodigga like this.
  3. Carpet_Head

    Carpet_Head

    Joined:
    Nov 27, 2014
    Posts:
    254
    I think there may actually be a bug in the code that performs the check related to this:
    - the Mesh instance hasn't been changed since the last time cooking was ran.

    From my experience, the actual behaviour is that the cooking/baking will be performed if the mesh was ever changed after it's initial baking pass, regardless of whether it has changed since the last good bake.

    For example:

    Modify Mesh
    Modify Mesh
    Assign sharedmesh
    Move collider (bake)
    Move collider (no bake)
    Move collider (no bake)
    Modify Mesh
    Move collider (bake) - expected
    Move collider (bake) - unexpected
     
  4. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    Interesting. Could you file a bug report for easier tracking?
     
  5. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    686
    Having a similar issue on some procedural meshes..

    I'm doing..

    // creating or refreshing mesh verts in job system
    gameObject.SetActive(false);
    collider.sharedMesh = null;
    // creating or rebuilding mesh with new data
    // setting mesh filter's sharedmesh
    gameObject.SetActive(true);
    // Physics.BakeMesh( meshID ); in job system
    collider.sharedMesh = mesh;

    This seems to result in the following errors:

    [Physics.PhysX] Foundation: Invalid deregistration detected. // on the null set
    [Physics.PhysX] Foundation: Invalid registration detected. // on the refreshed mesh set

    And to top it off, it seems to be rebaking the mesh anyways when setting the sharedMesh ;_;
     
  6. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    May I kindly ask you to file a bug using Unity's Bugreporter? You'd get a tracking link for this issue, and everyone will be able to track progress on it. Thanks!
     
  7. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    686
    Unfortunately, after restarting Unity this problem seems to have vanished, so now I cannot duplicate it to file a bug report..
     
  8. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    686
    @yant However, the double bake does still happen for me. I made a repro, here's the case: #1197040
     
    LeonhardP likes this.
  9. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    Super cool, I'll take a look. Thanks.
     
  10. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    686
    Ever get a chance to look at this? I just updated to 2019.3.0f3 hoping it would be fixed, but I'm still seeing the bake show up in both the job system and the main thread.. (schedules a job to bake a bunch of meshes, then next frame completes the job and sets the meshes to the sharedMesh parameter of their mesh colliders)

    upload_2019-12-11_21-41-58.png

    upload_2019-12-11_21-42-37.png
     
  11. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    Yes, I took a look. I think to make the current code work well, it is required:
    - Use a new Mesh every time you modify it
    - Make sure you actually set the baked mesh to some mesh collider (otherwise it may leak)

    ^ those issues are getting addressed as we speak, but I have no dates share unfortunately.
     
  12. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    686
    Oh, is the issue that a single mesh class instance being rebaked multiple times is not yet supported? I suppose I can work around this, although it does seem like a waste of heap space, in my case it may be acceptable as a workaround. I'll try it, thanks!
     
  13. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    It's not exactly like it's not supported, just that a bug makes it broken. Debugging it I find this may be a viable workaround in the meantime.
     
  14. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    I can confirm that currently it only seems to bake on fresh meshes. Can't await the fix, i run a procedural Terrain-Generator on mobile:

    I use custom meshes paired with Terrains that are only used for their TerrainColliders. Terrain Colliders can be updated about 10 times quicker than an equivalent CookingOption.None-meshcollider
    (~1ms vs 10ms, cant be threaded -> lags).

    I already do threading on everything else, so finally having the option to thread mesh-collider generation is the best news ever! If this is fixed i can consider any mesh for my terrain, not just heightmapped terrains.

    Question: are there any plans to expose the collider-data for a more direct tinkering? E.g. i could use the Terrain-Collider generation speed but with some flipped quads (for polystyle)
     
    Last edited: Dec 16, 2019
  15. Lynxed

    Lynxed

    Joined:
    Dec 9, 2012
    Posts:
    121
    My game is all procedural, so i am really interested in this.
    Can you please give a link to the issue tracker page, so i can vote on this?
     
  16. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,471
    Is there any indication in the profiler if the mesh pointer can't be shared with PhysX? I'm currently writing an import pipeline to create "physics meshes", which are regular meshes ran through Physics.BakeMesh and saved as asset. I then assign these physics meshes to a MeshCollider at runtime and would like to know whether this works without overhead.
     
    Last edited: Dec 14, 2019
  17. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    686
    When you do get a chance to look deeper at this and work on fixing it, can you ensure that the previously baked collision mesh is still somehow valid until we swap to the new one? Or is it writing to the same buffer, so this is not possible? I may need to make a new mesh anyways (or I suppose, in the future just keep two and swap between them on update) to ensure collision is still valid while the new one is being baked..
     
  18. Lynxed

    Lynxed

    Joined:
    Dec 9, 2012
    Posts:
    121
    I use transformations (including non-uniform scales) of a set of primitive MeshCollider objects to construct collision shape. I get colliders from pools). Needless to say, i'm getting a lot of Physics.Bake now left and right. It would be nice, if we could Physics.Bake(meshID, convex, transform) or Physics.Bake(meshID, convex, pos, rot, scale) if it has to be blittable.

    Also - this fix can't come fast enough. Creating new Mesh instances just because we need to change the mesh is insane.
     
    funkyCoty likes this.
  19. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    There is only one thing i want for christmas, it's Physics.BakeMesh.
     
    Lynxed likes this.
  20. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    Did anyone do this yet?
     
  21. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    686
    Marrt, LeonhardP and Lynxed like this.
  22. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
  23. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    I'm really sorry, but have to inform everybody on this thread that the issue has not yet been addressed, unfortunately. anthony
     
    Marrt likes this.
  24. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    Thanks for the Update!

    So what is the current Workaround?
    I tried creating new meshes each time but i still wasn't able to trigger the threaded meshbaking in a way that the mesh didn't need also trigger baking in the main loop.
     
  25. Lynxed

    Lynxed

    Joined:
    Dec 9, 2012
    Posts:
    121
    What is the time estimate for the fix? Proc gen stuff uses 2019.3 features heavily (like setting NativeCollections to Mesh), falling back to earlier versions is not an option. GC traps are everywhere.
     
    ImpossibleRobert likes this.
  26. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    864
    It doesn't work for me. I see a Mesh.Bake PhysX collisionData on the main thread anyway every time I instantiate a prefab containing meshcollider that references a previously baked mesh using Physics.Bake Mesh. Is there any way to determine was the bake successful or not? May be it is because I am using PhysicsScenes?
     
    Marrt likes this.
  27. Hyp-X

    Hyp-X

    Joined:
    Jun 24, 2015
    Posts:
    421
    We get a lot of this type of errors (in the player 2019.3.0f6 Win64 Mono):

    Couldn't create a Convex Mesh from source mesh "p_BigRock_01_b_N" within the maximum polygons limit (256). The partial hull will be used. Consider simplifying your mesh.


    After a few (not always the same amount) of reloading the scene, we start get these:

    Code (CSharp):
    1. [Physics.PhysX] Foundation: Invalid registration detected.
    2. (Filename: C:\buildslave\physx\build\physx/source/foundation/src/PsFoundation.cpp Line: 201)
    3.  
    4. [Physics.PhysX] Foundation: Invalid deregistration detected.
    5. (Filename: C:\buildslave\physx\build\physx/source/foundation/src/PsFoundation.cpp Line: 216)
    And after that we get a crash on exit. Can these be related? (The errors and the crash)
     
  28. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    299
    I don't think it is. TerrainCollider internally uses Heightfield, while MeshCollider uses either TriangleMesh or ConvexMesh (depending on convex setting). I'd prefer Unity to decouple TerrainCollider from TerrainData and expose methods for direct update of heightmap (which PhysX supports).
     
  29. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    Hi,

    Can you guys help trying out this custom build please? https://beta.unity3d.com/download/5ef4e2647b21/public_download.html

    It's based on some 20.1 alpha, and we can have this change in all Unity versions 19.3 to trunk provided that we see it's improving on the issues discussed above.

    The main changes are:
    • When the MeshCollider is activated (or .sharedMesh is set), we check for actual default flags present before making the decision to bake another physx mesh instance. Priorly, we compared to an int directly, and that apparently is not great as you can get input flags == -1 in some cases (Editor's "Everything" sets that for instance). Didn't work well with deprecated flags (=convex inflation) either.
    • Addressed a problem in Physics.BakeMesh() where it checked if a Mesh had already been baked and early out if yes. This broke the pipeline where you wanted to keep modifying the same mesh and bake it over and over again. New logics:
      • Physics.BakeMesh() will always bake a new instance of physx mesh and store it on the Mesh
      • If this Mesh has already been baked (Mesh holds a pointer to the binary blob for mem management purposes), decrease the ref count of this physx mesh
      • If ref count == 0, we know nothing is using it any more, and will release memory (happens off the main thread)
      • If ref count > 0, we know something is using this instance still, it will get released when the last MeshCollider using it is deactivated (or .sharedMesh is set, replacing it with another one, possibly baked with BakeMesh on another thread).
    I expect that the intended workflow is:
    1. Modify mesh
    2. Bake it with Physics.BakeMesh() on any thread
    3. Call MeshCollider.sharedMesh with the mesh on the main thread
    Note that (3) is consistent with the classic pipeline of editing Mesh geometry and then calling MeshCollider.sharedMesh to have it applied. Also avoids destroying PhysX and Unity shapes on another thread.

    Please do let me know what you think.

    Thanks for all your help.

    Anthony
     
    Marrt likes this.
  30. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    Did not work for me. I wasn't able to avoid rebaking on assignment in the main thread.
    Do cooking options break it? Can we in any way verify if the bake was performed on the thread?

    Anyway, we should wait for a second person to test this, my code got messy because i had only an hour to test this, so it might just be me.


    EDIT: Was my fault, the custom build works!
    https://forum.unity.com/threads/physics-bakemesh-question.741257/#post-5545537
     
    Last edited: Mar 3, 2020
  31. Carpet_Head

    Carpet_Head

    Joined:
    Nov 27, 2014
    Posts:
    254
    cooking options break it, I believe intentionally
     
  32. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    In 2019.3 it was designed to work with default cooking options only (and then it actually broke if you set "Everything" which is logical to be default, but it wasn't because of an issue in comparison). If you specify non-default cooking options, the mesh will be baked for the second time.
     
  33. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    This is what the Editor uses per defaul:
    upload_2020-3-2_20-22-11.png

    I created my MeshColliderComponent via script without touching the default cooking options. And after that failed, i tried to set it manually to this state. Same behavior. Has anyone else tried so far?
     
    Last edited: Mar 3, 2020
  34. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    I've just created this simple project to set common grounds what we're speaking about.

    There's just one scene with a script that creates everything procedurally.

    It adds renderer, filter, MeshColllider, spawn a single Mesh instance and will generate new vertices every Update(). It's baked every Update(), but then used only in FixedUpdate() to demonstrate that there are no bakes happening inside FixedUpdate.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CreateTriangle : MonoBehaviour
    6. {
    7.     private Mesh mesh;
    8.     private MeshCollider collider;
    9.     private MeshFilter filter;
    10.     private MeshRenderer renderer;
    11.  
    12.     public float elevation = 0;
    13.     public float size = 1;
    14.     public float speed = 0.2f;
    15.     public float spawnDelay = 2f;
    16.     public GameObject testProto;
    17.  
    18.     public IEnumerator Start()
    19.     {
    20.         mesh = new Mesh();
    21.         collider = gameObject.AddComponent<MeshCollider>();
    22.         filter = gameObject.AddComponent<MeshFilter>();
    23.         renderer = gameObject.AddComponent<MeshRenderer>();
    24.         filter.sharedMesh = mesh;
    25.  
    26.         while (true)
    27.         {
    28.             // this is to drop something from atop and make sure collision is working as the thing bounces off the triangle
    29.             var g = GameObject.Instantiate(testProto, Vector3.up * (elevation + 10), Quaternion.identity);
    30.             yield return new WaitForSeconds(spawnDelay);
    31.         }
    32.     }
    33.  
    34.     private void Generate()
    35.     {
    36.         mesh.vertices = new Vector3[] {
    37.             new Vector3(0, elevation, size),
    38.             new Vector3(size, elevation, 0),
    39.             new Vector3(0, elevation, 0),
    40.         };
    41.         mesh.triangles = new int[] {0, 1, 2};
    42.         mesh.RecalculateNormals();
    43.     }
    44.  
    45.     public void Update()
    46.     {
    47.         elevation += Time.deltaTime * speed;
    48.         Generate();
    49.         Physics.BakeMesh(mesh.GetInstanceID(), false);
    50.     }
    51.  
    52.     public void FixedUpdate()
    53.     {
    54.         // there will be no bake here because we baked in Update() before
    55.         collider.sharedMesh = mesh;
    56.     }
    57. }
    58.  
     

    Attached Files:

  35. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    Thank you for looking into this! I checked your script, it seems that Physics.Bake() will still only happen once for the lifetime of the mesh.
    EDIT: Oops, I used the old Editor on my first tests, in 2020.1.0a24.3012 it works as expected! (in the current version 2019.3.03f it doesn't)

    Thank You! Can we expect this in the next stable release? I need to test this on an Android device :D


    I adapted your script to include Threading (see below). Just paste it, needed objects are created procedurally. I also used a larger mesh so that the baking should take some milliseconds. So you can see in the console-messages if assignments cause baking:

    Controls:
    Press 1: Update the mesh and Bake it in Update, the assignment in FixedUpdate should not take long
    Press 2: Update the mesh without baking it, the assignment in FixedUpdate should take long
    Press 3: Update the mesh and bake it in a second thread, the assignment in the callback should not take long
    Space: Drop a test collider

    Here is the script:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. using System.Threading;
    6. using BakeThreads;
    7.  
    8. public class CreateTriangle : MonoBehaviour
    9. {
    10.     private Mesh mesh;
    11.     private MeshCollider collider;
    12.     private MeshFilter filter;
    13.     private MeshRenderer renderer;
    14.     private GameObject    lagIndicator    = null;
    15.     private    GameObject    dropCloneSource    = null;
    16.     private    float        spawnDelay        = 2.8f;
    17.     private    GameObject    curClone        = null;
    18.  
    19.     private BakeThreadHandle bakeHandle = null;
    20.  
    21.     //counter for better console messages
    22.     public static int jobCounter;
    23.  
    24.     public void Start()//public IEnumerator Start()
    25.     {
    26.         //Target mesh
    27.             mesh = new Mesh();
    28.             collider = gameObject.AddComponent<MeshCollider>();
    29.             filter = gameObject.AddComponent<MeshFilter>();
    30.             renderer = gameObject.AddComponent<MeshRenderer>();
    31.             filter.sharedMesh = mesh;
    32.         //LagIndicator
    33.             lagIndicator = GameObject.CreatePrimitive(PrimitiveType.Cube);
    34.             lagIndicator.transform.position = new Vector3(-5F, 0F, 0F);
    35.  
    36.         //LagIndicator
    37.             dropCloneSource = GameObject.CreatePrimitive(PrimitiveType.Cube);
    38.             dropCloneSource.transform.position = new Vector3(-5F, 5F, 0F);
    39.             dropCloneSource.AddComponent<Rigidbody>();
    40.  
    41.         //borrow material from primitve
    42.             renderer.sharedMaterial = lagIndicator.GetComponent<MeshRenderer>().sharedMaterial;
    43.  
    44.         //init our bakehandle for threading (see bottom of this script)
    45.             bakeHandle = new BakeThreadHandle( OnFinishedThreadedMeshBake );
    46.     }
    47.     private static void Generate( Mesh targetMesh, float timeMod )
    48.     {
    49.  
    50.         //generate array (COULD BE THREADED)
    51.  
    52.             //https://www.patrykgalach.com/2019/07/29/procedural-terrain-pt1-plane/
    53.             int width = 180;
    54.             int depth = 180;
    55.             float scale = 0.05F;
    56.             // Defining vertices.
    57.             Vector3[] vertices = new Vector3[(width + 1) * (depth + 1)];
    58.             int i = 0;
    59.             float y = Random.Range(-15F,15F);
    60.             for (int d = 0; d <= depth; d++){
    61.             for (int w = 0; w <= width; w++){
    62.                 vertices[i] = ( new Vector3(w, y, d) - new Vector3(width / 2f, 0, depth / 2f) )*scale;
    63.                 i++;
    64.             }}
    65.             // Defining triangles.
    66.             int[] triangles = new int[width * depth * 2 * 3]; // 2 - polygon per quad, 3 - corners per polygon
    67.             for (int d = 0; d < depth; d++){
    68.             for (int w = 0; w < width; w++){
    69.                 // quad triangles index.
    70.                 int ti = (d * (width) + w) * 6; // 6 - polygons per quad * corners per polygon
    71.                 // First tringle
    72.                 triangles[ti] = (d * (width + 1)) + w;
    73.                 triangles[ti + 1] = ((d + 1) * (width + 1)) + w;
    74.                 triangles[ti + 2] = ((d + 1) * (width + 1)) + w + 1;
    75.                 // Second triangle
    76.                 triangles[ti + 3] = (d * (width + 1)) + w;
    77.                 triangles[ti + 4] = ((d + 1) * (width + 1)) + w + 1;
    78.                 triangles[ti + 5] = (d * (width + 1)) + w + 1;
    79.             }}
    80.  
    81.         //assign to mesh (CANNOT BE THREADED)
    82.             targetMesh.vertices = vertices;
    83.             targetMesh.triangles = triangles;
    84.             targetMesh.RecalculateNormals();
    85.     }
    86.     public void Update()
    87.     {
    88.  
    89.         lagIndicator.transform.Rotate(0F,0F,60F*Time.unscaledDeltaTime);
    90.  
    91.         //BAKE in Update
    92.         if(Input.GetKeyDown(KeyCode.Alpha1)){    jobCounter++;
    93.             Debug.Log("═════Key 1═════════\nBAKING IN UPDATE, assignment should NOT take long [ job:"+jobCounter.ToString().PadLeft(4,'.')+" ]");
    94.  
    95.             Generate( mesh, Time.time );//Generating vertex arrays etc. could be threaded too, but assigning .vertices|.triangles etc. to mesh, cannot be threaded
    96.  
    97.             float start = Time.realtimeSinceStartup;
    98.             BakeMeshCollider( mesh );
    99.             print("[ job:"+jobCounter.ToString().PadLeft(4,'.')+" ] Meshcollider Baking in Main thread took:\n"+BakeThreadQueue.GetMS(Time.realtimeSinceStartup -start)+"" );
    100.  
    101.             assignmentPending = true;
    102.         }
    103.  
    104.         //Don't Bake
    105.         if(Input.GetKeyDown(KeyCode.Alpha2)){    jobCounter++;
    106.             Debug.Log("═════Key 2═════════\nDON'T BAKE assignment should take long [ job:"+jobCounter.ToString().PadLeft(4,'.')+" ]");
    107.  
    108.             Generate( mesh, Time.time );//Generating vertex arrays etc. could be threaded too, but assigning .vertices|.triangles etc. to mesh, cannot be threaded
    109.  
    110.             assignmentPending = true;
    111.         }
    112.  
    113.         //Bake in Thread
    114.         if(Input.GetKeyDown(KeyCode.Alpha3)){    jobCounter++;
    115.  
    116.             Debug.Log("═════Key 3═════════\nBAKING IN THREAD, assignment should NOT take long [ job:"+jobCounter.ToString().PadLeft(4,'.')+" ]");
    117.  
    118.             if( bakeHandle.occupied ){
    119.                 print("One Thread is already active");//for simplicity, only  threadhandle allowed in this example
    120.             }else{
    121.  
    122.                 Generate( mesh, Time.time );//Generate could be threaded too
    123.  
    124.                 int meshID = mesh.GetInstanceID();//caching because 'targetMesh.GetInstanceID()' cant be called in worker thread!
    125.  
    126.                 //prepare & start thread (long version)
    127.                 //ThreadStart threadstart = delegate {  MeshUpdate_Threadable( meshID, bakeHandle ); };
    128.                 //Thread t = new Thread( threadstart );
    129.                 //t.Start();
    130.  
    131.                 //prepare & start thread (one line version)
    132.                 new Thread( new ThreadStart( delegate { BakeMeshCollider_Threaded( meshID, bakeHandle );})).Start();
    133.                 bakeHandle.startTime = Time.realtimeSinceStartup;
    134.                 bakeHandle.occupied = true;
    135.             }
    136.         }
    137.  
    138.         //Collison Test Object
    139.         if(Input.GetKeyDown(KeyCode.Space)){
    140.             if(curClone!= null){ Destroy(curClone); }
    141.             curClone = GameObject.Instantiate(dropCloneSource, Vector3.up *10, Quaternion.identity);
    142.         }
    143.  
    144.         BakeThreadQueue.CheckFinishedThreads();
    145.     }
    146.     private bool assignmentPending = false;
    147.     public void FixedUpdate()
    148.     {
    149.         if( assignmentPending ){
    150.  
    151.             float start = Time.realtimeSinceStartup;
    152.             // there will be no bake here because we baked in Update() before
    153.             collider.sharedMesh = mesh;
    154.             assignmentPending = false;
    155.             print("[ job:"+jobCounter.ToString().PadLeft(4,'.')+" ] Meshcollider assignment in FixedUpdate took:\n"+BakeThreadQueue.GetMS(Time.realtimeSinceStartup -start)+"" );
    156.         }
    157.     }
    158.  
    159.     //NO THREADING
    160.     private static void BakeMeshCollider( Mesh targetMesh  )
    161.     {
    162.         Physics.BakeMesh( targetMesh.GetInstanceID(), false);
    163.     }
    164.  
    165.  
    166.     //THREADING
    167.     private static void BakeMeshCollider_Threaded( int targetMeshInstanceID, BakeThreadHandle bakeHandle  )
    168.     {
    169.         Physics.BakeMesh( targetMeshInstanceID, false);
    170.  
    171.         //report that the bake has finished
    172.         lock( BakeThreadQueue.bakeFinishedQueue ){    //threads need to lock things that may be accessed by multiple threads at once
    173.             BakeThreadQueue.bakeFinishedQueue.Enqueue( bakeHandle );
    174.         }
    175.     }
    176.  
    177.     //used as callback on our handle
    178.     private void OnFinishedThreadedMeshBake(){
    179.         float start = Time.realtimeSinceStartup;
    180.         collider.sharedMesh = mesh;
    181.         print("[ job:"+jobCounter.ToString().PadLeft(4,'.')+" ] Meshcollider assignment after threaded baking took:\n"+BakeThreadQueue.GetMS(Time.realtimeSinceStartup -start)+"" );
    182.     }
    183. }
    184.  
    185.  
    186.  
    187.  
    188.  
    189.  
    190. namespace BakeThreads{
    191.  
    192.     public class BakeThreadHandle
    193.     {
    194.         public    readonly System.Action    callback;
    195.         public    bool    occupied;
    196.         public    float    startTime;
    197.         public BakeThreadHandle( System.Action callback){
    198.             this.callback = callback;
    199.         }
    200.     }
    201.  
    202.     public static class BakeThreadQueue
    203.     {
    204.         public static Queue<BakeThreadHandle> bakeFinishedQueue = new Queue<BakeThreadHandle>();
    205.         public static bool    allowMultipleDequeues = false;
    206.  
    207.         //check every Update if thread is ready
    208.         public static void CheckFinishedThreads(){
    209.  
    210.             for(int i=0; i<bakeFinishedQueue.Count; i++){
    211.  
    212.                 BakeThreadHandle handle    = bakeFinishedQueue.Dequeue();        //get finished task handle
    213.                 Debug.Log(  "[ job:"+CreateTriangle.jobCounter.ToString().PadLeft(4,'.')+" ] Finished baking in another Thread!" +
    214.                             "BakeThread took about \n"+GetMS(Time.realtimeSinceStartup -handle.startTime)+" to complete" );    //measure time it took
    215.  
    216.                 //do what must be done after baking has finsihed
    217.                 handle.callback();
    218.                 handle.occupied = false;
    219.  
    220.                 //early exit if we only want one dequeue per frame, e.g. if the callback is a large non threadable function and performing multiple might cause lag
    221.                 if(!allowMultipleDequeues){ break; }
    222.             }
    223.         }
    224.  
    225.         public    static string GetMS( float seconds, string msDecimalPlaces = "F6" ){
    226.             return ""+(1000F *seconds).ToString( msDecimalPlaces ) +"ms";
    227.         }
    228.     }
    229. }
    230.  
    231.  
     
    Last edited: Mar 3, 2020
    yant likes this.
  36. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    Thanks for your input Marrt. I'll let it sit here for a few days just in case. Afterwards there's going to be a PR to 20.2, 20.1 and 19.3. I'll keep you posted here on the thread. Sorry it's taken a while. Anthony.
     
    iamarugin and Marrt like this.
  37. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    @Peter77 -- speaking of the profiler entries, there are two:

    "Mesh.Bake PhysX CollisionData" -- indicated when baking a non-scaled mesh
    "Mesh.Bake Scaled Mesh PhysX CollisionData" -- indicated when baking a scaled mesh

    Clearly, it would be nice to have an API that tells you whether the mesh will be baked or not, but it's not there at the moment.

    Currently, we run baking when either one is true: cooking options are not default, scaling is non-uniform, shared mesh is dirty.

    Hope that helps.
     
    Peter77 likes this.
  38. Andresmonte

    Andresmonte

    Joined:
    Nov 22, 2014
    Posts:
    37
    i tested on version 2020.1.0a25.3171 and Physics.Bake() is only working once, then Mesh.Bake PhysX moves to the mesh assignment.
    when we can get the fix in a public version.
    Constantly moving the heavy calculation out of the main thread would be very useful for me.
     
  39. Andresmonte

    Andresmonte

    Joined:
    Nov 22, 2014
    Posts:
    37
    I could not edit my post...So.
    Mesh.Clear() does Not work, only work around I found is to create a new Mesh every time.
     
  40. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    Try the script in this post: https://forum.unity.com/threads/physics-bakemesh-question.741257/#post-5545537

    - Create a new 3D project in 2020.1.0a24.3012 (https://beta.unity3d.com/download/5...429.93567035.1583100738-1295778461.1543368316) not 2020.1.0a25.3171
    - Insert the scipt into the asset folder and put it onto an object in your scene
    - press 1,2,3 or Space and watch console
     
  41. Andresmonte

    Andresmonte

    Joined:
    Nov 22, 2014
    Posts:
    37
    It worked on 2020.1.0a24.3012, I just thought that 2020.1.0a25.3171 being more recent was going to work as well, my bad.
     
  42. ImpossibleRobert

    ImpossibleRobert

    Joined:
    Oct 10, 2013
    Posts:
    512
    @yant not sure if my physics bug is somehow related to baking but there seems to be something really off when instantiating an object, scaling it and doing a raycast against it, all in the same frame. The raycast will still act on the unscaled size. I have to put in a "yield" to let one frame pass in order to fix this behavior. Is this intended? What worries me: QA is going to simply close it now since I cannot supply my 20Gb project that easily. Not sure if it ever reached you: Bug 1222033
     
  43. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    If you don't have Auto Sync On in the physics settings (which all the new projects don't have for perf reasons) - then you need to sync manually before operations that require the latest state to be written to physx. See Physics.SyncTransforms()
     
    Marrt and ImpossibleRobert like this.
  44. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    The fix that the custom build above illustrates is not yet available in any official builds. It will take some time to propagate it to all the releases affected, I'll be posting here as I have dates/versions.
     
    Andresmonte likes this.
  45. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    FWIW - this fix is part of 2020.2.0a5. Back-ports are following on.
     
    Andresmonte and Marrt like this.
  46. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    Yet another note to update you that the fix has been approved for 2020.1.0b4.

    2019.3 is fair to expect to take a lot longer (there is a ton of fixes waiting to land, and only a fixed amount is allowed per release in order to spend more time verifying each case).

    A
     
    Andresmonte likes this.
  47. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    864
    Thanks for info, can't wait these fixes for 19.3
     
  48. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    578
    A heads up that the fix will be available as part of 2019.3.10f1. That's it, abandon this thread, I guess ;-) Thanks everyone!
     
    coidevoid and Marrt like this.
  49. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    864
    Wow, this is great, thanks!
     
  50. coidevoid

    coidevoid

    Joined:
    Oct 26, 2017
    Posts:
    55
    I tried with the 2019.3.10f but I still get the "Foundation: Invalid deregistration / registration detected."...
    My mesh colliders all have the default cooking options. Weirdly, appart from that error that pops every frame it does work as expected.
    Any idea what I could have done wrong ?

    Here's my code if that can help :)

    Code (CSharp):
    1. //public Dictionary<Mesh, MeshCollider> meshesToBake;
    2.  
    3. NativeArray<int> meshIds = new NativeArray<int>(meshesToBake.Count, Allocator.TempJob);
    4. int j = 0;
    5. foreach (Mesh mesh in meshesToBake.Keys)
    6. {
    7.     meshIds[j] = mesh.GetInstanceID();
    8.     j++;
    9. }
    10. BakeJob bakeJob = new BakeJob(meshIds);
    11. bakeJob.Schedule(meshIds.Length, 1).Complete();
    12. meshIds.Dispose();
    13. foreach (Mesh mesh in meshesToBake.Keys)
    14. {
    15.     meshesToBake[mesh].sharedMesh = mesh;
    16. }
    17. meshesToBake.Clear();
     
    Last edited: Apr 16, 2020
    Andresmonte likes this.