Search Unity

Should be simple but I just can't do it! Changing texture by script.

Discussion in 'Scripting' started by tre4bax, Apr 20, 2020.

  1. tre4bax

    tre4bax

    Joined:
    Aug 31, 2013
    Posts:
    22
    I'm just getting back into Unity3d having spent some time away.

    I can replicate my issue by boiling this down pretty basic.

    I have an Empty that contains a single upright plane on which I have put a texture. I want to be able to change that texture via script however I just cannot figure out how. This is because I decided to update to using HDRP/Lit and it does not appear to work the same.

    So far I have tried

    renderer.material.mainTexture = newTexture;

    renderer.material.SetTexture("_MainTex",newTexture);

    renderer.material.SetTexture("_BaseMap",newTexture);

    The best I have managed is to create a new material and apply that which then just gives me a grey square that I cannot change the texture on either.

    Feels like this should be a really easy normal operation and yet two days of trying and hitting the internet has got me nowhere so now I am asking the question here. How in heck do you change texture from the initial one to one stored in the resources? Doing the above does change the material internally, it just does not render the new information provided.

    Trev
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Show a screenshot of how this renderer is configured?
     
  3. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    You need to use a material property block:
    Code (CSharp):
    1. MaterialPropertyBlock block = new MaterialPropertyBlock();
    2. renderer.GetPropertyBlock(block);
    3. block.SetTexture("_BaseMap",newTexture);
    4. renderer.SetPropertyBlock(block);
     
    anihilnine likes this.
  4. tre4bax

    tre4bax

    Joined:
    Aug 31, 2013
    Posts:
    22
    Thanks so much for your replies. I've continued to bang me head on this since it posted.

    I really have a totally basic setup created to have just the basics of what I want to do so no other logic is interferring. I have created a Plane, tipped it so it is vertical then added a material to it by dropping that texture on the plane. All shows fine in the editor it is using the out HDPR/Lit shader and the BaseMap shows the texture I drop onto it.

    To test changing it I have then attached a script to the plane that is just intended to change the texture for a new one when the game runs. I just modified this using PraetorBlue's advice from above to this.

    public class JustChangeTexture : MonoBehaviour
    {
    // Start is called before the first frame update
    void Start()
    {
    Renderer renderer = GetComponent<Renderer>();

    MaterialPropertyBlock block = new MaterialPropertyBlock();
    //renderer.GetPropertyBlock(block);
    block.SetTexture("_BaseMap", (Texture2D)Resources.Load("MyNewTexture"));
    renderer.SetPropertyBlock(block);
    }

    // Update is called once per frame
    void Update()
    {

    }
    }

    I have experimented with moving the content of start into update so that it is called every frame but that changes nothing. Am I suppose to use an EnableKeyword somewhere. I don't think so as I can't find one that would correspond to changing the BaseMap but could be missing something. I did have a look through the shader file but can find no reference to the baseMap there at all.

    Really banging my head and yet convinced that it is actually so simple and I will be kicking myself.
     
  5. tre4bax

    tre4bax

    Joined:
    Aug 31, 2013
    Posts:
    22
    Well I am rapidly coming to the opinion that it is not possible to change the texture on a Material that is already in use. I have no idea why as I used to do this happily with older versions of Unity, I just cannot make it happen here whatever I do.

    Challenge for me is to do what I want will mean me having to create many many customised panels that I then swap in and out rather than just changing the texture on one. I know my familiarity with Unity is limited, I just thought this would be a no brainer as it was before.

    Feels like the object is pre-compiling the material and then not changing it once it is running. The fact that I can change the name of Texture that is looked at suggests I am making a change, it is just that when rendering that change is completely ignored.
     
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Something is definitely off in your project. This exact line is working for me right now in 2019.3.10f, with dozens of such renderers in my scene:

    Code (CSharp):
    1. BackgroundRenderer?.material.SetTexture("_BaseMap", (Texture)TextureReference.Asset);
    What kind of renderer is it?
     
  7. tre4bax

    tre4bax

    Joined:
    Aug 31, 2013
    Posts:
    22
    Hi @PraetorBlue

    I really isn't much of a project right now as I have created a brand new HDRP project and then one scene with one plane in it. I just added a texture to that which shows. Then I added the code above with and without the block stuff in the hope it would change the texture. I have even added something to just increment the z so the plane moves incase it was because it was not refreshing.

    For me the equivalent of BackgroundRenderer.material will show the name of the new texture just not the texture. The only difference from your code is that I am using a texture from the resource folder. Did just notice I was using Texture2D and you are using Texture so I changed that and it still did not change.

    It is a Mesh Renderer using an HDRP/Lit shader. If I change the base map option in the GUI the texture changes. I just cannot seem to change this value through scripting. When I look at the renderer.material there is no property BaseMap or anything similar. There is a mainTexture and that still has the old texture name in it unless I use "_MainTex" which will change it, however that still does not change what is rendered.

    I find the renderer by doing this (stuck it in a function so I can call from start and update).

    void setTexture()
    {
    Transform image = transform.Find("Image"); //find the image component

    Renderer renderer = image.GetComponent<Renderer>();

    Texture tex = Resources.Load<Texture>("Gallery\\picture1");
    renderer.material.SetTexture("_BaseMap", tex);

    }

    Image is the name I have given to the plane in the GUI. Only thing I am wondering is if I am looking at the right renderer.
     
  8. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    My example is using URP Lit Shader instead of HDRP Lit Shader. Maybe the texture name is different - I'm having trouble finding the docs for the names of the textures on these shaders. Best I can tell it might be "_MainTex", but in your OP you said you tried that... "_BaseColorMap" maybe??
     
  9. PyotrRomanov

    PyotrRomanov

    Joined:
    Apr 28, 2018
    Posts:
    1
    I am having the same issue as OP, I believe. In my case I am using a ShaderGraph shader which has a property that I named "_BaseMap" (although I have tried many other names as well). If I export my texture to png and drag that onto the material it shows up fine, but SetTexture does not work no matter how many times I ensure the same spelling on the property name. I have used the Block method as well, but nothing changes.
    The material and renderer are dragged into their respective references through the editor so I am sure they are correct. The texture, again, can be exported and imported manually and works, so it has no problems. Dropping it onto the material during runtime forms no problems so I am sure that's not it either. It's just the SetTexture method that simply does not do its job for me.
     
  10. lgh_unity820

    lgh_unity820

    Joined:
    Jul 5, 2022
    Posts:
    6
    @PyotrRomanov I exactly have same issue. I tried using property, I tried to use material.mainTexture and nothing changed. And thing that freaks me more is i even dont get any error or warning message!
    And my unity version is 2020.3.30f1
     
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,736
    But did you try copying the Material out to a temporary variable, setting the texture, then assigning it back the way the documentation suggests?
     
  12. lgh_unity820

    lgh_unity820

    Joined:
    Jul 5, 2022
    Posts:
    6
    Ah, it was just my mistake. i figured it out. i didnt know i shouldnt write file extension after its name when i use resources.load. But thanks anyway.
     
  13. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,736
  14. lgh_unity820

    lgh_unity820

    Joined:
    Jul 5, 2022
    Posts:
    6
    So even i cannot write file extension as parameter in resource.load(), But i can write unity object type in angle bracket in <T> in Resource.Load.
    Did i understand right?
     
  15. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,736
    If you had this file:

    Assets/Resources/Textures/Kurt.png


    You would always load it with:

    Code (csharp):
    1. Texture2D Kurt = Resources.Load<Texture2D>( "Textures/Kurt");
     
  16. lgh_unity820

    lgh_unity820

    Joined:
    Jul 5, 2022
    Posts:
    6
    Thanks. That makes me understand more clear for using Resources.Load
     
    Kurt-Dekker likes this.