Search Unity

In-Editor real time mesh modification. Forced to use what doesn't work. What do I do?

Discussion in 'Editor & General Support' started by MrDude, Sep 25, 2018.

  1. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Hi all.

    Okay, so I am trying to create a prefab that I can scale during design time and have it's texture be modified to scale with the object rather than being stretched. You can see the final effect here

    Now the issue I am facing is that I read in the documentation years ago that you mustn't change the sharedMaterial on a mesh since that will update all instances of the mesh. Since the name does say SHARED material that makes perfect sense, so I try to do what I want to do using the mesh's material instead. Unfortunately, when I try to scale the mesh in the editor it works just fine but I get errors about memory leaks telling me that I should rather use sharedMaterial instead.

    So I do that and as you can see in the video I provided above, that works beautifully.... It does exactly what I want and all is well with the world. And then I add the second mesh to the scene and now each time I update one mesh, all meshes share the same scale value, thus breaking every mesh i work with.

    This leaves me in a catch22 situation... I know what to do but the Editor tells me "Nope, you are not allowed to do that cause it might cause memory leaks. Use that thing we tell you NOT to use, instead" but when I follow that advice the editor is saying "See? No more errors. Too bad now it doesn't work at all any more. Hey, we TOLD you not to use that, didn't we?"

    So what do I do?

    All I want to do is say this:
    Code (csharp):
    1. void Update() {
    2. myRenderer.material.mainTextureScale =  new Vector2(transform.localScale.x, transform.localScale.y);
    3. }
    Real simple, right? But with ExecuteInEditMode set on the script I get the memory leak error mentioned above so... what do I do? :(

    Any advice would be greatly appreciated.
    Thanks :)
     
    Last edited: Sep 25, 2018
  2. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    P.s. The actual error I am receiving when using the material directly is this:
    Code (csharp):
    1. Instantiating material due to calling renderer.material during edit mode. This will leak materials into the scene. You most likely want to use renderer.sharedMaterial instead.
    2. UnityEngine.Renderer:get_material()
    Full code for a mesh with 6 separate materials:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. [ExecuteInEditMode]
    5. public class WallTiler : MonoBehaviour {
    6.  
    7.     [SerializeField] bool scale_east_and_west = false;
    8.     [SerializeField] Renderer South;
    9.     [SerializeField] Renderer North;
    10.     [SerializeField] Renderer East;
    11.     [SerializeField] Renderer West;
    12.  
    13.     Vector2 XScale => new Vector2( transform.localScale.x, transform.localScale.y );
    14.     Vector2 ZScale => new Vector2( transform.localScale.z, transform.localScale.y );
    15.     Vector2 YScale => new Vector2( 1f, transform.localScale.y);
    16.  
    17.     void SetUV( Renderer r, Vector2 s ) => r.material.mainTextureScale = s;
    18.    
    19.     void Update () {
    20.         SetUV( North, XScale );
    21.         SetUV( South, XScale );
    22.         if ( scale_east_and_west )
    23.         {
    24.             SetUV( East, ZScale );
    25.             SetUV( West, ZScale );
    26.         }
    27.         else
    28.         {
    29.             SetUV( East, YScale );
    30.             SetUV( West, YScale );
    31.         }
    32.     }
    33. }
    34.  
     
    Last edited: Sep 25, 2018
  3. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Does nobody have any suggestions regarding this? This is kind of a big deal for what I'm doing and errors about memory leaks are really not welcome :(

    Anybody have any ideas or is this simply me trying to do something that Unity was not designed to be able to do and I just have to live with the consequences of me trying to do something I shouldn't be able to do?
     
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    The .material error shows up because exactly what it says is happening. The material you're creating gets added to the scene file. Now, from basic checking it seems like Unity actually cleans out those materials from the scene file when you stop referencing them, so the error might not be necessary.
    It might be that there's corner-cases where Unity can't figure that out, and the material file gets left in the scene, so you get an actual leak. I don't know. The error is probably there because the behaviour when setting .material is confusing? Idk.

    If you know what you're doing, you can kinda notify Unity that you do by doing this the hard way:

    Code (csharp):
    1. renderer.sharedMaterial = new Material(renderer.sharedMaterial); //creates a clone of the original, assigned material
    2. // edit shared material
    This does exactly the same thing as editing .material (the created material is saved in the scene), but you don't get any errors.
     
    MrDude likes this.
  5. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    Interesting.... I was wondering if there would be an easy way to actually create an instance that I then just assign to the mesh and avoid having that issue.

    What I couldn't figure out was how to create an instance during design time that would automatically be cleared when Unity needs to clear it (again, due to it being at design time). If this code of yours works this will be a super simple solution indeed! Thanks man!

    Gonna give this a go right now! Touch wood! :D
     
    Last edited: Oct 2, 2018
  6. MrDude

    MrDude

    Joined:
    Sep 21, 2006
    Posts:
    2,569
    As expected, too easy to possibly be the right answer :(

    The first mesh's scaling works as expected but it's new scaling is applied to the child object also. The child object, on the other hand, when I scale that it doesn't do the UV scaling at all. Instead it just scales the mesh. I am assuming this is do to the first mesh's Update loop setting the scale for all instances.

    ....buuuuuuut.... Doing THIS works 100% perfectly!
    Code (csharp):
    1. South.material = new Material( South.sharedMaterial );
    Thanks a bunch, mate!
    I never would have imagined the solution would be so glaringly obvious that I would look right past it!
    You da man! :D