Search Unity

Is there a way to change sharedMaterial without affecting prefabs?

Discussion in 'General Graphics' started by Baalhug, Feb 12, 2020.

  1. Baalhug

    Baalhug

    Joined:
    Aug 12, 2013
    Posts:
    32
    Hi:

    So I have a procedurally made maze with dozens and even hundreds of instances of wall objects sharing same material. When map button is pressed, an ortographic camera renders the current state of the maze from top view, and I'm changing walls and floor textures to black and white to see it more clearly. To avoid hardware stress (important since this is a mobile game), I'm changing sharedMaterial.mainTexture of the walls when in map view, saving original Textures and switching back to them when leaving map view. The problem is, if I exit game while in map view, wall prefab textures have changed forever.

    After reading a lot, some people advice to use a copy of the material but this isn't working for me because I must loop through all wall instances, and I don't want this. If I don't loop I must use sharedMaterial directly, so I change prefabs materials.

    Other people advice to use MaterialPropertyBlocks, but it's the same problem, I must loop through all the intances. I'm not worried about looping through hundreds of objects, the real problem is batching render is gone.

    So, is there a way to change sharedMaterial without affecting the prefab or changing every object material in a loop?

    Code (CSharp):
    1. // This will change prefab if exiting game while in map view mode
    2.  
    3. // when entering map view mode
    4. wallMat = wallObject.GetComponent<MeshRenderer>().sharedMaterial;
    5. backUpTex = wallMat.mainTexture;
    6. wallMat.mainTexture = blackTexture;
    7.  
    8. // when exiting map view mode
    9. wallMat.mainTexture = backUpTex;

    Code (CSharp):
    1. // This will only change wallObject material, not all the other instances sharing material
    2.  
    3. // when entering map view mode
    4. Material copyMat = new Material(wallMat);
    5. wallObject.GetComponent<MeshRenderer>().sharedMaterial = copyMat;
    6. copyMat.mainTexture = blackTexture;
    7.  
    8. // when exiting map view mode
    9. wallObject.GetComponent<MeshRenderer>().sharedMaterial = wallMat;
     
  2. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,639
    I've done the same thing before. Just add some code that runs at the beginning of the scene to set the SharedMaterial texture to what it's supposed to start off as. You could also try setting it back in OnApplicationQuit
    https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnApplicationQuit.html

    I'm pretty sure this only a problem in the editor, though.
     
  3. Baalhug

    Baalhug

    Joined:
    Aug 12, 2013
    Posts:
    32
    Well, switching back textures on OnApplicationQuit event is not working, but if the problem only exists in editor then it should be OK. Anyway I don't understand the point of this behaviour in editor but not in compiled version. It makes no sense to me. I will test in mobile and report back.
     
  4. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    fill a bug report
     
  5. Baalhug

    Baalhug

    Joined:
    Aug 12, 2013
    Posts:
    32
    I almost forgot this. I have tried it in mobile and it's true: SharedMaterial.mainTexture won't change in mobile version.
     
  6. cholleme

    cholleme

    Unity Technologies

    Joined:
    Apr 23, 2019
    Posts:
    31
    sharedMaterial modifies the actual material asset in the project. So if you do access it in the editor or play-in editor it will modify the asset and thus be saved in the project. This is documented behaviour in and not a bug.

    I think the best approach here is really to go via MaterialPropertyBlocks. It should be possible to batch even when using MPB's maybe something specific is preventing the batching?
     
  7. norvinzhang

    norvinzhang

    Joined:
    Feb 18, 2022
    Posts:
    1
    MaterialPropertyBlocks not work with SRPBatch