Search code examples
c#unity-game-engineshader

Unity : How do I change a Shader Graph's property (float) over time?


As seen below, I created a shader effect and added a Vector1 property called "Visibility", where if set to 1 nothing happens but as it progresses to 0 the shader effect comes into play and becomes visible.

enter image description here

enter image description here

My issue is finding a way to reduce the Visibility property from 1 to 0 over time, in the span of 2 seconds it should go from 1 to 0. I know how to change the value of the "Visibility" property through code using SetFloat, like this:

 if (door.GetComponent<MeshRenderer>().material = changeDisolve)
     {
         changeDisolve.SetFloat("Visibility", 0.0f);
     }

But i want the value to progress to 0 via a 'duration', so i tried using Mathf.Lerp as seen below-which did not work either:

 if (door.GetComponent<MeshRenderer>().material = changeDisolve)
     {
         float changeVisibility = Mathf.Lerp(1f, 0f, 3f);
         changeDisolve.SetFloat("Visibility", changeVisibility);
     }

Does anyone know what i am doing wrong or how to go about this? Thanks in advance.


Solution

  • If you want to change the code to be called each X Seconds you should use InvokeRepeating. You could also start InvokeRepeating the moment you enter a BoxCollider with OnTriggerEnter() or the moment you leave a BoxCollider with OnTriggerExit() etc, but you can't use Update.

    You can use CancelInvoke(); to stop all InvokeRepeating calls. In this case after your shaderValue has reached 0 or less.

    // Starting at the start of the game after Awake()
    // the shader will be changed every 0.2 seconds
    
    public class ExampleScript : MonoBehaviour
    {
        private shaderValue = 1f;
        private float change = 0.1f;
    
        void Start()
        {
            InvokeRepeating("ChangeShader", 0.1f, 0.2f);
        }
    
        void Changeshader()
        {
             if (shaderValue <= 0f) {
                 CancelInvoke();
             }
    
             else if (door.GetComponent<MeshRenderer>().material = changeDisolve) {
                 shaderValue -= change;
                 changeDisolve.SetFloat("Visibility", shaderValue);
             }
        }
    }
    

    You could also use an IEnumerator, which makes it possible to call WaitForSeconds which will then wait that amount and after the specified delay has been finished continue with the rest of the code.

    You could also use OnTriggerEnter() or OnTriggerExit() instead of Start().

    // Starting in Update
    // the shader will be changed every 0.2 seconds
    
    public class ExampleScript : MonoBehaviour
    {
        private shaderValue = 1f;
        private float change = 0.1f;
        private float delay = 0.2f;
    
        void Start()
        {
             StartCouroutine(ChangeShader());
        }
    
        IEnumerator Changeshader()
        {
             while (shaderValue > 0f){
    
                 yield return new WaitForSeconds(delay);             
    
                 if (door.GetComponent<MeshRenderer>().material = changeDisolve) {
                     shaderValue -= change;
                     changeDisolve.SetFloat("Visibility", shaderValue);
                 }
             }
        }
    }