Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug Strange behaviour when setting renderer colour of instantiated objects.

Discussion in 'Editor & General Support' started by Miss_Maae, Aug 7, 2023.

  1. Miss_Maae

    Miss_Maae

    Joined:
    May 3, 2021
    Posts:
    4
    I have a system in unity where theres a data class (called melt data) which is a scriptable object. The scriptable object will save and load data from a different class (called melt save) for each scriptable object. My scriptable object will be placed in a list and for each item in the list, it is to spawn a game object (called a meowmelt) which stores the scriptable object (melt data). Upon the meowmelt storing the melt data, the scriptable object is to load the save data and store that so that the meowmelt class can read from the scriptableobject data and the save data.

    I have an issue where each meowmelt's colour is to be loaded from the melt save data. Upon the data being loaded, it SHOULD set the renderer component to this colour, however this is not the case. I store the R, G, B and A values rather than an instance of colour as it doesn't seem to be serializable, so a new instance of colour is made upon loading the data.

    To make a meowmelt, I have a template melt that is set to inactive, as I said, for each melt data, this template is instantiated and set active, the data it reads from is set and then the script is started. After the data is loaded correctly, the melt colour should be set. I am aware that the line of code should set the colour correctly in theory, but what happens is they retain their default colour. I am also aware that the data loads correctly and before the colour is set as I can see a variable that shows the intended colour in the inspector

    Stranger still, if I was to run the script with the template meowmelt set to active and with data, it will set all the other melts' colours to that which is saved by the melt data of the template melt, but the template melt would remain white.

    I think that there may be something fishy going on with the instances of the material, but I don't fully understand it. Please could anyone help and provide any suggestions as to why this doesn't seem to work?
    Thank you

    (this is where I set the colour, you can see that it stores the intended colour so that it can be seen in the inspector for debugging purposes.)
    image_2023-08-07_141523775.png
    (With no template melt active, the colours are all default, they aren't just white)
    image_2023-08-07_141431807.png
    (With the template melt active, they all read from this melt's intended colour. It is set before the other melts are active. Note how it is not shown on the template melt itsself.)
    image_2023-08-07_141856479.png
    This shows that the intended colour is correct, however the actual colour is not correct.
    image_2023-08-07_141417212.png
    This is my code for spawning a melt.
    image_2023-08-07_141948231.png


    Thank you, any help is much appreciated. I am relatively new to unity, I do not fully understand the intricacies of how it works yet.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    The most likely thing tripping you up is how Materials will be instanced if you access them via the .material property.

    It's in the docs but it's still kinda subtle.

    To get it right, I find it simplest to copy the material out (which instances it), change its color, and assign it back.

    Code (csharp):
    1. Material temp = MyRenderer.material;
    2.  
    3. temp.SetColor()...etc.etc.etc.etc
    4.  
    5. MyRenderer.material = temp;
    ALSO: photographs of code are not a thing. If you post a code snippet, ALWAYS USE CODE TAGS:

    How to use code tags: https://forum.unity.com/threads/using-code-tags-properly.143875/
     
  3. Miss_Maae

    Miss_Maae

    Joined:
    May 3, 2021
    Posts:
    4
    Hi there,
    thanks for the suggestion but this doesn't seem to change what is happening.
    I have implemented it as follows
    Code (csharp):
    1.  
    2. public void SetColour(Color x)
    3.     {
    4.        
    5.         lastSetColour = x;
    6.         Material temp = meltRenderer.material;
    7.  
    8.         temp.SetColor("_Color", lastSetColour);
    9.  
    10.  
    11.         meltRenderer.material = temp;
    12. }
    13.  
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    If your problem is with OnCollision-type functions, print the name of what is passed in!

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    "When in doubt, print it out!(tm)" - Kurt Dekker (and many others)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
    Miss_Maae likes this.
  5. Miss_Maae

    Miss_Maae

    Joined:
    May 3, 2021
    Posts:
    4

    Hi, I have been doing this already, I've been working on debugging this using Debug.Log for hours testing many theories. First I thought the colour wasn't loading correctly, which was incorrect, I tested by exposing the intended colour to the inspector which is loaded from the file. I thought perhaps the data wasn't loading or was loading from the wrong file, but no. I tried setting the colour outside of the script when the melts were being spawned or setting it just for one melt, didn't work. I set the colour to green during update to test if perhaps it was an issue with the files loading too slowly, or somehow the renderer reference was being accessed too early, I still didn't see any results. I went to chatGPT to check if it could spot any errors, I followed all its instructions and no. I even tried different variations of using new instances of color or modifying old ones, this didn't work. All I can discern is that
    The correct melt is setting their own colour, the set colour method does indeed set the colour, as in its not an issue with setting the _Color property of the shader but the colour will not show up correctly. As long as the template is active, everything else is set to the colour of the template and then template is set to default colour or if it is inactive, everything is default white.
    If I am to set the colour of the template while it is inactive before the other melts are spawned, the other melts only follow the colour set to the template, despite them attempting to change their colour and that code that does explicitly being run with the correct colour, this is why i'm out of theories due to my lack of experience in this aspect of unity (using materials and instances).

    Posting to the forum was really a last resort for me and I appreciate your suggestion, but its not often helpful to tell people to debug when that is why they are here in the first place. More suggestions for me to test would also be very appreciated if you have any more ideas?
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    Actually, I beg to differ. Your thoroughness is a massive outlier here in the forums. Most people have never written a single Debug.Log() statement, let alone gone through the rigorous steps you have!

    So next steps to take are what I call the "replace it with a duck" steps.

    Set your current prefab(s) aside one by one and replace them with simpler ones.

    Try a cube with a simple default diffuse material.

    The idea is that until you get THAT to work, no sense in digging through more unknowns.

    One common way to end up with white when you want an actual color is misusing Color vs Color32
     
    Miss_Maae likes this.
  7. Miss_Maae

    Miss_Maae

    Joined:
    May 3, 2021
    Posts:
    4
    I've solved it, there was an animator component on the thing I was trying to change the colour of. It for some reason stopped the modifying of its textures. Sometimes you think the solution has to be a myriad of different things and its just because you accidentally put a component on something a long time ago and didn't notice :/