Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Question Noob: Lerp Shader property in if else toggle?

Discussion in 'Scripting' started by pillowww, Sep 4, 2020.

  1. pillowww

    pillowww

    Joined:
    Aug 18, 2020
    Posts:
    8
    Hi everyone!
    I'm an absolute novice in coding and I'd hope to get a little help here.

    I'm trying to change textures of a shader, based on a button press. Here is the code for that:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ShaderFader : MonoBehaviour
    6. {
    7.     public void fader()
    8.     {
    9.         if (gameObject.GetComponent<Renderer>().sharedMaterial.GetFloat("_Blend") == 1)
    10.         {
    11.             gameObject.GetComponent<Renderer>().sharedMaterial.SetFloat("_Blend", 0);
    12.         }
    13.         else
    14.         {
    15.             gameObject.GetComponent<Renderer>().sharedMaterial.SetFloat("_Blend", 1);
    16.         }
    17.        
    18.     }
    19. }
    20.  
    This works as expected. I call the function and the texture switches instantly!
    I'm trying to have it fade between the textures, the property I'm calling is a range slider between 0 and 1.
    I've looked into Mathf.Lerp but it's really confusion and I don't know where to add it in the code.
    Any help would be greatly appreciated!
     
  2. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    Hey dude,

    this should sort you out...
    Code (CSharp):
    1. Slider slider;
    2. Renderer renderer;
    3. float fadeSpeed;
    4.  
    5. void Update()
    6. {
    7.     float currentValue = renderer.sharedMaterial.GetFloat("_Blend");
    8.     if (currentValue != slider.value))
    9.     {
    10.         float newPos = MathF.MoveTowards(currentValue, slider.value, fadeSpeed * Time.DeltaTime);
    11.         sharedMaterial.SetFloat("_Blend", newPos);
    12.     }
    13. }
     
  3. Zer0Cool

    Zer0Cool

    Joined:
    Oct 24, 2014
    Posts:
    203
    Here's some code that fades the material each time you press space.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using System.Collections;
    4.  
    5. public class Fade : MonoBehaviour {
    6.  
    7.     public float fadeSpeed = 1.0f;
    8.  
    9.     private Material material;
    10.  
    11.     private bool toggle = true;
    12.  
    13.     public void Start()
    14.     {
    15.         // better use the material property here!
    16.         material = GetComponent<Renderer>().sharedMaterial;
    17.     }
    18.  
    19.     void Update()
    20.     {
    21.         if (Input.GetKeyDown("space"))
    22.         {
    23.            StartCoroutine(FadeMaterial(toggle));
    24.            toggle = !toggle; // toggles at each click
    25.         }
    26.     }
    27.  
    28.     IEnumerator FadeMaterial(bool fadeAway)
    29.     {
    30.         // fade from 1.0 to 0
    31.         if (fadeAway)
    32.         {
    33.             // loop over 1/fadeSpeed seconds backwards
    34.             for (float i = 1; i >= 0; i -= fadeSpeed * Time.deltaTime)
    35.             {
    36.                 material.SetFloat("_Blend", i);
    37.                 yield return null;
    38.             }
    39.         }
    40.         // fade from 0 to 1.0
    41.         else
    42.         {
    43.             // loop over 1/fadeSpeed seconds
    44.             for (float i = 0; i <= 1; i += fadeSpeed * Time.deltaTime)
    45.             {
    46.                 material.SetFloat("_Blend", i);    
    47.                 yield return null;
    48.             }
    49.         }
    50.     }
    51. }
    52.  
    Byside:
    It is not recommended to modify materials returned by sharedMaterial. If you want to modify the material of a renderer use material instead.
     
    Last edited: Sep 4, 2020
    pillowww likes this.
  4. pillowww

    pillowww

    Joined:
    Aug 18, 2020
    Posts:
    8
    Hey thanks! Could you elaborate on this? When I add it to my script it wont compile and I can't enter playmode. I get errors on Slider and renderer in your first 2 lines in VS.
     
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,947
    You need to make them public or
    SerializeField
    and assign the appropriate values in the inspector.
     
    pillowww likes this.
  6. pillowww

    pillowww

    Joined:
    Aug 18, 2020
    Posts:
    8
    Thank you! This works! I've changed it a little bit to work with my button, also I had to add a 'float' to fadeSpeed, don't know if this is good practice, but it wouldn't compile otherwise. Thanks again!
    Here is the updated script for anyone interested, finding this thread:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using System.Collections;
    4.  
    5. public class ShaderFader : MonoBehaviour
    6. {
    7.  
    8.     public float fadeSpeed = 1.0f;
    9.    
    10.     private Material material;
    11.  
    12.     private bool toggle = true;
    13.  
    14.     public void Start()
    15.     {
    16.         material = GetComponent<Renderer>().sharedMaterial;
    17.     }
    18.  
    19.     public void Faded()
    20.     {
    21.         StartCoroutine(FadeMaterial(toggle));
    22.         toggle = !toggle; // toggles at each click
    23.     }
    24.  
    25.  
    26.     IEnumerator FadeMaterial(bool fadeAway)
    27.     {
    28.         // fade from 1.0 to 0
    29.         if (fadeAway)
    30.         {
    31.             // loop over fadeSpeed seconds backwards
    32.             for (float i = 1; i >= 0; i -= fadeSpeed * Time.deltaTime)
    33.             {
    34.                 material.SetFloat("_Blend", i);
    35.                 yield return null;
    36.             }
    37.         }
    38.         // fade from 0 to 1.0
    39.         else
    40.         {
    41.             // loop over fadeSpeed seconds
    42.             for (float i = 0; i <= 1; i += fadeSpeed * Time.deltaTime)
    43.             {
    44.                 material.SetFloat("_Blend", i);
    45.                 yield return null;
    46.             }
    47.         }
    48.     }
    49. }
    50.  
    51.  
     
  7. Zer0Cool

    Zer0Cool

    Joined:
    Oct 24, 2014
    Posts:
    203
    Yeah, i havnt tested the code so add float to fadeSpeed is absolutely right. But i assume you should use .material here and not .sharedMaterial because this changes your material asset too and therefore influences all instances of your material asset.
    But nice that I could help :)
     
    pillowww likes this.
  8. pillowww

    pillowww

    Joined:
    Aug 18, 2020
    Posts:
    8
    Thanks, yeah I'll do that! Great name btw:) need to re-watch!
     
    Zer0Cool likes this.
  9. pillowww

    pillowww

    Joined:
    Aug 18, 2020
    Posts:
    8
    Hey everyone!
    I'm having another little issue:
    The code is working, but somehow fades between 0.001 and 0.998.
    Is there a way to force it to reach 1? I don't get why it's not reaching the full value.
     
  10. pillowww

    pillowww

    Joined:
    Aug 18, 2020
    Posts:
    8
    As in, to clarify:
    Code (CSharp):
    1. IEnumerator FadeMaterial(bool fadeAway)
    2.     {
    3.         // fade from 1.0 to 0
    4.         if (fadeAway)
    5.         {
    6.             // loop over fadeSpeed seconds backwards
    7.             for (float i = 1; i >= 0; i -= fadeSpeed * Time.deltaTime)
    8.             {
    9.                 material.SetFloat("_Blend", i);
    10.                 yield return null;
    11.             }
    12.         }
    13.         // fade from 0 to 1.0
    14.         else
    15.         {
    16.             // loop over fadeSpeed seconds
    17.             for (float i = 0; i <= 1; i += fadeSpeed * Time.deltaTime)
    18.             {
    19.                 material.SetFloat("_Blend", i);
    20.                 yield return null;
    21.             }
    22.         }
    23.     }
    Does not result in 0 and 1, but in values just above 0 and below 1. I'm guessing this has to do with framerate maybe? is there a way to force it to reach == 1 and == 0 ? Sadly the fade only works when 100% complete. Thanks for any input!
     
  11. pillowww

    pillowww

    Joined:
    Aug 18, 2020
    Posts:
    8
    Actually, after some research, I think I found that deltaTime will never truly reach 1 or 0, but I don't understand why. I had no luck getting the value to truly reach 1 and 0, any help would be appreciated.

    I've also tried using Mathf.MoveTowards * deltatime, but it results in the same value, that is 0.999 but never reaching 1, causing artifacts.
     
    Last edited: Sep 5, 2020
  12. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,947
    Time.deltaTime is simply the number of seconds that has passed since the previous frame. Since games usually run around 60 FPS (or faster), it is usually a small number like 0.0167

    If you start at 0, and keep adding 0.0167, what happens? Well, after 59 frames (59 * 0.0167) you will end up with 0.9853. If you add 0.0167 again you will end up with 1.002. Your for loop is checking that
    i <= 1
    , so 1.002 will not satisfy that condition. Therefore the last iteration of your for loop is when i is 0.9853.

    Obviously it depends on what your fadeSpeed is and what your exact framerate is. But the point is that you will never get to EXACTLY 1 by adding small floating point numbers together. One quick thing you could do is simply force it to be exactly one at the end like this:

    Code (CSharp):
    1.             for (float i = 0; i <= 1; i += fadeSpeed * Time.deltaTime)
    2.             {
    3.                 material.SetFloat("_Blend", i);
    4.                 yield return null;
    5.             }
    6.  
    7.             material.SetFloat("_Blend", 1);
    A common way to do this would be to use a while loop:
    Code (CSharp):
    1. float time = 0;
    2.  
    3. while (time < 1) {
    4.   time += Time.deltaTime * fadeSpeed;
    5.   material.SetFloat("_Blend", Mathf.Clamp01(time));
    6. }
     
    Last edited: Sep 5, 2020
    Zer0Cool and pillowww like this.
  13. pillowww

    pillowww

    Joined:
    Aug 18, 2020
    Posts:
    8
    Thank you very much, that explains it! It's quite hard getting into this, I'm glad for the help. I've updated it and it works as I intended!
     
    Zer0Cool likes this.