Search Unity

Entity disappears when material is changed in RenderMesh

Discussion in 'Graphics for ECS' started by Init33, Jul 16, 2019.

  1. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    Hi,

    I am trying to change an entities material from a script but currently the entity disappears when the material is changed.

    The object is a based cube with a convert to entity script. The material is a standard shader with GPU instancing enabled.

    I get my material like so:
     outlineMat = (Material)Resources.Load("_testMat", typeof(Material));


    and update my entity like so:
    Code (CSharp):
    1. var r = EntityManager.GetSharedComponentData<RenderMesh>(selected[0]);
    2. RenderMesh newR = r;
    3. newR.material = outlineMat;
    4. EntityManager.SetSharedComponentData<RenderMesh>(selected[0], newR);
    As soon as this code runs, the object disappears but I can still see the entity in the same position:


    Any ideas why the object seems to disappear?
     
    addent likes this.
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,769
    Try replace materiał renderer without custom shader.
    See if it works.
     
  3. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    Do you mean replace the material with a standard shader material? Thats what I'm already doing.
     
  4. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    35
    I'm having a similar issue, not sure if it's related.

    I have an entity with a RenderMesh which get rebuilt every frame using the standard shader, but it disappears if I move the camera ahead along the z axis at a certain point. Actually, once I get away from the origin point (0, 0, 0) it seems to disappear depending on the camera position and orientation. I always see the mesh in the Scene view however. No clue what's going on, but sounds similar to the issue @Init33 is having.

    I'll also note, that it DOES render properly if I never rebuild the mesh after startup. So it seems to be some combination of rebuilding the mesh + camera position/orientation.

    RenderMeshDisappears.jpg
     
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    RenderBounds is only generated for you once so if you make changes to the mesh you need to update the RenderBounds yourself otherwise it will be culled at the wrong time.
     
    addent likes this.
  6. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    I should note that I cannot see the object in either game or scene view.

    Any other recommendations?
     
  7. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    Yeah I'm not sure about your issue, was just replying to addent.

    The only thing i can think of is, outlineMat is definitely not null right?
     
  8. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    It was null, silly me thought it would throw an error if it couldnt find the resource. I had to put the material in a /Assets/Resources folder and it worked fine.
     
    addent likes this.
  9. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    35
    Thanks! I was not calling calling mesh.RecalculateBounds(). This fixed my issue in 99% of cases, but I still have disappearing geo in some rare instances.

    Just a quick follow up question: I still don't see it changing the RenderBounds, just the WorldRenderBounds. Is that the expected behavior?

    RenderMeshDisappears2.jpg
     
  10. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    35
    Nevermind, this is just the Inspector not updating. I printed the mesh.bounds in a debug statement and everything is working just fine and as expected. Thanks very much for the help!

    DebugLog.jpg
     
  11. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    Look at RenderBoundsUpdateSystem

    Basically when you change your mesh, you need to also do a

    Code (CSharp):
    1. SetComponentData(entity, new RenderBounds { value = new RenderBounds { Value = mesh.bounds.ToAABB() }.})
    or a less performant version

    Code (CSharp):
    1. RemoveComponent<RenderBounds>(entity)
    and unity will add it back updated.
     
  12. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    35
    Yes! Thank-you... I now see the RenderBounds updating too and everything is working perfectly!

    I used your first suggestion:
    Code (CSharp):
    1. SetComponentData(entity, new RenderBounds
    2. {
    3.     Value = mesh.bounds.ToAABB(),
    4. });
    There's so much to learn about how all of this works, I really appreciate it. Thanks again @tertle
     
    Last edited: Jul 18, 2019
    tarahugger likes this.
  13. surits14

    surits14

    Joined:
    Jan 22, 2018
    Posts:
    22
    Following all the comments from above
    - I am not changing the mesh's material
    - My issue is also because of camera orientation
    - From the camera's Y-axis - 65deg onwards the entities disappear every time

    What I did was first created 1600 entities and added them to a list of entities and called every 400 entities from that list time to time and changed the entity's transform value and nonuniform scale value.
    After reading few comments here I tried rather created 40,000 entities to avoid changing the RenderMeshBounds and still when the camera moves in a Z direction and changes orientation along y-axis beyond 65degs the entities disappear during the play mode

    @tertle @addent please help...! much needed. thank you
     
    Last edited: Nov 29, 2019
  14. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    35
    Hi @surits14! For my particular case, I had to do 3 things (note the code below is just example code, but you'll get the idea):

    1) Make sure my entity had a RenderBounds component on it.
    Code (CSharp):
    1. EntityArchetype myArchetype = entityManager.CreateArchetype(
    2.     typeof(TeleportArc),
    3.     typeof(RenderMesh),
    4.     typeof(RenderBounds),
    5.     typeof(LocalToWorld),
    6.     typeof(Translation)
    7. );
    8. Entity myEntity = entityManager.CreateEntity(myArchetype);
    2) When the mesh is created, call the RecalculateBounds() method on it.

    Code (CSharp):
    1. private Mesh CreateQuad(float3 point, float size)
    2. {
    3.     var mesh = new Mesh();
    4.  
    5.     mesh.vertices = new Vector3[] {
    6.         new Vector3(point.x - size, point.y - size, point.z),
    7.         new Vector3(point.x - size, point.y + size, point.z),
    8.         new Vector3(point.x + size, point.y - size, point.z),
    9.         new Vector3(point.x + size, point.y + size, point.z),
    10.     };
    11.  
    12.     mesh.triangles = new int[] {
    13.         0, 1, 2,
    14.         2, 1, 3
    15.     };
    16.  
    17.     mesh.RecalculateNormals();
    18.     mesh.RecalculateTangents();
    19.     mesh.RecalculateBounds();  // Needed this here!
    20.     return mesh;
    21. }
    3) And finally, after the RenderMesh component was set to use the new mesh, the RenderBounds component also needed to be set again.

    Code (CSharp):
    1. protected override void OnUpdate()
    2. {
    3.     ...
    4.     Mesh mesh = CreateQuad(myPoint, mySize);
    5.    
    6.     entityManager.SetSharedComponentData<RenderMesh>(myEntity, new RenderMesh
    7.     {
    8.         mesh = mesh,
    9.         material = hit ? hitMaterial : missMaterial,
    10.         subMesh = 0,
    11.         layer = 0,
    12.         castShadows = ShadowCastingMode.Off,
    13.         receiveShadows = false,
    14.     });
    15.    
    16.     // Need to update the render bounds on the entity too.
    17.     entityManager.SetComponentData(myEntity, new RenderBounds
    18.     {
    19.         Value = mesh.bounds.ToAABB(),
    20.     });
    21.     ...
    22. }
     
  15. surits14

    surits14

    Joined:
    Jan 22, 2018
    Posts:
    22
    From your reply
    1) - Yes, this was done.
    2) - In my case, I am using a mesh from an import model. eg- Sphere mesh
    - Still, I added RecalculateBounds() before entityManager.SetSharedComponentData(entity, new RenderMesh
    - See code below
    3) - Yes, Did the same way you mentioned.

    My code which I run using a signal emitter in the timeline (called only once)

    Code (CSharp):
    1. public void generateInitialCluster()
    2. {
    3.         for (int i = 0; i < 100; i++)
    4.         {
    5.             NativeArray<Entity> entityArray = new NativeArray<Entity>(400, Allocator.Temp);
    6.             entityManager.CreateEntity(entityArchetype, entityArray);
    7.  
    8.             for (int j = 0; j < 400; j++)
    9.             {
    10.                 Entity entity = entityArray[j];
    11.                 entityManager.SetComponentData(entity, new NonUniformScale
    12.                 {
    13.                     Value = new float3(UnityEngine.Random.Range(2, 7.0f), UnityEngine.Random.Range(4, 8.0f), UnityEngine.Random.Range(3, 7.0f)),
    14.                 });
    15.                 entityManager.SetComponentData(entity, new Translation
    16.                 {
    17.                     Value = vPosition[j] //a List<Vector3>
    18.                 });
    19.  
    20.                 mesh.RecalculateBounds();
    21.                 mesh.MarkDynamic();
    22.  
    23.                 entityManager.SetSharedComponentData(entity, new RenderMesh
    24.                 {
    25.                     mesh = mesh,
    26.                     material = material,
    27.                 });
    28.                 entityManager.SetComponentData(entity, new RenderBounds
    29.                 {
    30.                     Value = mesh.bounds.ToAABB(),
    31.                 });
    32.  
    33.                 //entityList.Add(entity); //Adding all the entities to a List<Entity>
    34.             }
    35.             entityArray.Dispose();
    36.         }
    37. }
    Note - The above code is called only once. Still the problem occurs.
     
  16. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    35

    Not sure about this one. I don't think you need the mesh.RecalculateBounds() inside the for loops though. If the mesh is moving/animating/deforming every frame then I'm not sure how that plays into everything either. Sorry, hopefully someone with more experience will help out!
     
  17. surits14

    surits14

    Joined:
    Jan 22, 2018
    Posts:
    22
    Thanks anyways
     
  18. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    35
    I just had a thought... when your set your bounds, is there any chance that it has zero volume due to scaling?

    I have a vague memory that I was trying to set the bounds on a quad and it didn't work when it was aligned with the xy-plane because the bounds had zero depth. I fixed it by forcing the bounds to have at least some volume in each direction.

    Code (CSharp):
    1. minPos = minPos + new Vector3(1.0f, 1.0f, 1.0f);
    2. maxPos = maxPos - new Vector3(1.0f, 1.0f, 1.0f);
    3. bounds.SetMinMax(minPos, maxPos);
    4.  
     
  19. surits14

    surits14

    Joined:
    Jan 22, 2018
    Posts:
    22
    Do I need to set bounds even though it is an imported Mesh?

    This (page) is exactly my problem. (On camera rotation the entities disappear).