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:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShaderFader : MonoBehaviour
{
public void fader()
{
if (gameObject.GetComponent<Renderer>().sharedMaterial.GetFloat("_Blend") == 1)
{
gameObject.GetComponent<Renderer>().sharedMaterial.SetFloat("_Blend", 0);
}
else
{
gameObject.GetComponent<Renderer>().sharedMaterial.SetFloat("_Blend", 1);
}
}
}
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!
Here’s some code that fades the material each time you press space.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Fade : MonoBehaviour {
public float fadeSpeed = 1.0f;
private Material material;
private bool toggle = true;
public void Start()
{
// better use the material property here!
material = GetComponent<Renderer>().sharedMaterial;
}
void Update()
{
if (Input.GetKeyDown("space"))
{
StartCoroutine(FadeMaterial(toggle));
toggle = !toggle; // toggles at each click
}
}
IEnumerator FadeMaterial(bool fadeAway)
{
// fade from 1.0 to 0
if (fadeAway)
{
// loop over 1/fadeSpeed seconds backwards
for (float i = 1; i >= 0; i -= fadeSpeed * Time.deltaTime)
{
material.SetFloat("_Blend", i);
yield return null;
}
}
// fade from 0 to 1.0
else
{
// loop over 1/fadeSpeed seconds
for (float i = 0; i <= 1; i += fadeSpeed * Time.deltaTime)
{
material.SetFloat("_Blend", i);
yield return null;
}
}
}
}
Byside:
It is not recommended to modify materials returned by sharedMaterial. If you want to modify the material of a renderer use material instead.
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.
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:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class ShaderFader : MonoBehaviour
{
public float fadeSpeed = 1.0f;
private Material material;
private bool toggle = true;
public void Start()
{
material = GetComponent<Renderer>().sharedMaterial;
}
public void Faded()
{
StartCoroutine(FadeMaterial(toggle));
toggle = !toggle; // toggles at each click
}
IEnumerator FadeMaterial(bool fadeAway)
{
// fade from 1.0 to 0
if (fadeAway)
{
// loop over fadeSpeed seconds backwards
for (float i = 1; i >= 0; i -= fadeSpeed * Time.deltaTime)
{
material.SetFloat("_Blend", i);
yield return null;
}
}
// fade from 0 to 1.0
else
{
// loop over fadeSpeed seconds
for (float i = 0; i <= 1; i += fadeSpeed * Time.deltaTime)
{
material.SetFloat("_Blend", i);
yield return null;
}
}
}
}
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
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.
IEnumerator FadeMaterial(bool fadeAway)
{
// fade from 1.0 to 0
if (fadeAway)
{
// loop over fadeSpeed seconds backwards
for (float i = 1; i >= 0; i -= fadeSpeed * Time.deltaTime)
{
material.SetFloat("_Blend", i);
yield return null;
}
}
// fade from 0 to 1.0
else
{
// loop over fadeSpeed seconds
for (float i = 0; i <= 1; i += fadeSpeed * Time.deltaTime)
{
material.SetFloat("_Blend", i);
yield return null;
}
}
}
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!
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.
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:
for (float i = 0; i <= 1; i += fadeSpeed * Time.deltaTime)
{
material.SetFloat("_Blend", i);
yield return null;
}
material.SetFloat("_Blend", 1);
A common way to do this would be to use a while loop:
float time = 0;
while (time < 1) {
time += Time.deltaTime * fadeSpeed;
material.SetFloat("_Blend", Mathf.Clamp01(time));
}