Entity disappears when material is changed in RenderMesh

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:

var r = EntityManager.GetSharedComponentData<RenderMesh>(selected[0]);
RenderMesh newR = r;
newR.material = outlineMat;
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?

1 Like

Try replace materiał renderer without custom shader.
See if it works.

Do you mean replace the material with a standard shader material? Thats what I’m already doing.

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.

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.

1 Like

I should note that I cannot see the object in either game or scene view.

Any other recommendations?

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?

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.

1 Like

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?

4759652--452270--RenderMeshDisappears2.jpg

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!

4759688--452273--DebugLog.jpg

Look at RenderBoundsUpdateSystem

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

SetComponentData(entity, new RenderBounds { value = new RenderBounds { Value = mesh.bounds.ToAABB() }.})

or a less performant version

RemoveComponent<RenderBounds>(entity)

and unity will add it back updated.

4 Likes

Yes! Thank-you… I now see the RenderBounds updating too and everything is working perfectly!

I used your first suggestion:

SetComponentData(entity, new RenderBounds
{
    Value = mesh.bounds.ToAABB(),
});

There’s so much to learn about how all of this works, I really appreciate it. Thanks again @tertle

1 Like

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

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.
EntityArchetype myArchetype = entityManager.CreateArchetype(
    typeof(TeleportArc),
    typeof(RenderMesh),
    typeof(RenderBounds),
    typeof(LocalToWorld),
    typeof(Translation)
);
Entity myEntity = entityManager.CreateEntity(myArchetype);
  1. When the mesh is created, call the RecalculateBounds() method on it.
private Mesh CreateQuad(float3 point, float size)
{
    var mesh = new Mesh();

    mesh.vertices = new Vector3[] {
        new Vector3(point.x - size, point.y - size, point.z),
        new Vector3(point.x - size, point.y + size, point.z),
        new Vector3(point.x + size, point.y - size, point.z),
        new Vector3(point.x + size, point.y + size, point.z),
    };

    mesh.triangles = new int[] {
        0, 1, 2,
        2, 1, 3
    };

    mesh.RecalculateNormals();
    mesh.RecalculateTangents();
    mesh.RecalculateBounds();  // Needed this here! 
    return mesh;
}
  1. And finally, after the RenderMesh component was set to use the new mesh, the RenderBounds component also needed to be set again.
protected override void OnUpdate()
{
    ...
    Mesh mesh = CreateQuad(myPoint, mySize);
   
    entityManager.SetSharedComponentData<RenderMesh>(myEntity, new RenderMesh
    {
        mesh = mesh,
        material = hit ? hitMaterial : missMaterial,
        subMesh = 0,
        layer = 0,
        castShadows = ShadowCastingMode.Off,
        receiveShadows = false,
    });
   
    // Need to update the render bounds on the entity too.
    entityManager.SetComponentData(myEntity, new RenderBounds
    {
        Value = mesh.bounds.ToAABB(),
    });
    ...
}

From your reply

    • Yes, this was done.
    • 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
    • Yes, Did the same way you mentioned.

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

public void generateInitialCluster()
{
        for (int i = 0; i < 100; i++)
        {
            NativeArray<Entity> entityArray = new NativeArray<Entity>(400, Allocator.Temp);
            entityManager.CreateEntity(entityArchetype, entityArray);

            for (int j = 0; j < 400; j++)
            {
                Entity entity = entityArray[j];
                entityManager.SetComponentData(entity, new NonUniformScale
                {
                    Value = new float3(UnityEngine.Random.Range(2, 7.0f), UnityEngine.Random.Range(4, 8.0f), UnityEngine.Random.Range(3, 7.0f)),
                });
                entityManager.SetComponentData(entity, new Translation
                {
                    Value = vPosition[j] //a List<Vector3>
                });

                mesh.RecalculateBounds();
                mesh.MarkDynamic();

                entityManager.SetSharedComponentData(entity, new RenderMesh
                {
                    mesh = mesh,
                    material = material,
                });
                entityManager.SetComponentData(entity, new RenderBounds
                {
                    Value = mesh.bounds.ToAABB(),
                });

                //entityList.Add(entity); //Adding all the entities to a List<Entity>
            }
            entityArray.Dispose();
        }
}

Note - The above code is called only once. Still the problem occurs.

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!

Thanks anyways

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.

minPos = minPos + new Vector3(1.0f, 1.0f, 1.0f);
maxPos = maxPos - new Vector3(1.0f, 1.0f, 1.0f);
bounds.SetMinMax(minPos, maxPos);

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).