- Home /
Color.lerp not working properly
I looked around to see if anyone had a similar issue but nothing like i had... when i run the script the color does change but it just goes to white and then gets whiter, also seems like the intensity increases but that might just be my eyes playing tricks on me
public Camera gameCamera;
public Camera menuCamera;
public Light mainLight;
public Material pipe;
public Material pipeWall;
private float[,,] colorPalette = new float[4, 5, 3]
{
{ {166, 212, 159}, {156, 179, 128}, {82, 42, 39}, {199, 62, 29}, {197, 152, 73} },
{ {20, 49, 9}, {170, 174, 127}, {208, 214, 179}, {247, 247, 247}, {239, 239, 239} },
{ {202, 207, 214}, {214, 229, 227}, {159, 216, 203}, {81, 118, 100}, {45, 51, 25} },
{ {255, 204, 51}, {102, 102, 102}, {255, 153, 0}, {255, 255, 255}, {166, 38, 57} }
};
private int palette;
public float colorChangeReset = 10;
private float colorTimer;
private void Awake()
{
palette = Random.Range(0, colorPalette.GetLength(0) - 1);
ChangeColor(palette);
colorTimer = colorChangeReset;
}
private void Update()
{
colorTimer -= Time.deltaTime;
if (colorTimer <= 0)
{
ChangeColor(palette);
colorTimer = colorChangeReset;
}
}
private void ChangeColor(int palette)
{
gameCamera.backgroundColor = menuCamera.backgroundColor = RenderSettings.fogColor =
Color.Lerp(gameCamera.backgroundColor, new Color
(colorPalette[palette, 0, 0], colorPalette[palette, 0, 1], colorPalette[palette, 0, 2]), Time.deltaTime * 2);
mainLight.color = Color.Lerp(mainLight.color, new Color
(colorPalette[palette, 1, 0], colorPalette[palette, 1, 1], colorPalette[palette, 1, 2]), Time.deltaTime * 2);
pipe.color = Color.Lerp(pipe.color, new Color
(colorPalette[palette, 2, 0], colorPalette[palette, 2, 1], colorPalette[palette, 2, 2]), Time.deltaTime * 2);
RenderSettings.ambientLight = Color.Lerp(RenderSettings.ambientLight, new Color
(colorPalette[palette, 3, 0], colorPalette[palette, 3, 1], colorPalette[palette, 3, 2]), Time.deltaTime * 2);
pipeWall.color = Color.Lerp(pipeWall.color, new Color
(colorPalette[palette, 4, 0], colorPalette[palette, 4, 1], colorPalette[palette, 4, 2]), Time.deltaTime * 2);
palette++;
if (palette >= colorPalette.GetLength(0) - 1)
{
palette = 0;
}
}
Answer by Bunny83 · May 17, 2016 at 05:00 PM
You have several problems with your code. First of all Random.Range
with int parameters has the upper limit exclusive, so don't subtract 1 from the Lenght. Random.Range(0, 3)
will return a number between 0 and 2 inclusive (0,1 or 2).
The next problem which is your actual problem is that the Color struct uses float value in the range of 0f - 1f. You seem to want to use value in the range of 0 -255 (byte values). Unity has another struct called Color32 which does use bytes instead of floats. So you either have to divide your current values by "255f" or turn the float array into a byte array and use the Color32 struct instead.
Finally you should be aware that you use Lerp not as a linear interpolating function but as a smoothing function which is not entirely framerate independend and is not linear at all. The way you use it it has an asymptotic behaviour and will mathematically never reach it's target, it just gets closer and closer.
Lerp always does the same and it does work as it should. Lerp simply does this:
Color Lerp(Color a, Color b, float t)
{
return a + (b-a)*t;
}
edit
Finally using a multidimensional array like this is a bit cryptic. You might want to use a small custom class for that and directly use Color values.
[System.Serializable]
public class ColorSettings
{
public Color gameBackground;
public Color mainLight;
public Color ambientLight;
public Color pipe;
public Color pipeWall;
}
public ColorSettings[] colorPalette;
This way you could set your color settings in the inspector and it's easier to use and more clear what the code does.
If you really want to hardcode those settings in your code you can still do this:
public ColorSettings[] colorPalette = new ColorSettings[] {
new ColorSettings {
gameBackground = new Color32(166, 212, 159, 255),
mainLight = new Color32(156, 179, 128, 255),
pipe = new Color32(82, 42, 39, 255),
ambientLight = new Color32(199, 62, 29, 255),
pipeWall = new Color32(197, 152, 73, 255)
},
new ColorSettings {
gameBackground = new Color32(20, 49, 9, 255),
mainLight = new Color32(170, 174, 127, 255),
pipe = new Color32(208, 214, 179, 255),
ambientLight = new Color32(247, 247, 247, 255),
pipeWall = new Color32(239, 239, 239, 255)
},
new ColorSettings {
gameBackground = new Color32(202, 207, 214, 255),
mainLight = new Color32(214, 229, 227, 255),
pipe = new Color32(159, 216, 203, 255),
ambientLight = new Color32(81, 118, 100, 255),
pipeWall = new Color32(45, 51, 25, 255)
},
new ColorSettings {
gameBackground = new Color32(255, 204, 51, 255),
mainLight = new Color32(102, 102, 102, 255),
pipe = new Color32(255, 153, 0, 255),
ambientLight = new Color32(255, 255, 255, 255),
pipeWall = new Color32(166, 38, 57, 255)
},
};
As long as the "colorPalette" array is public it will still use the values you set in the inspector. If you only want to hardcode the values you might want to use the NonSerialized attribute or make the variable private.
Note: i quickly "copied & pasted" your values over. There might be some errors so check your values. I used the same order as you used so it should be correct.
second edit
I just discovered that you call your "ChangeColor" method only once every 10 seconds. That won't work with Lerp at all, no matter if you use it "correctly" or as a smoothing function. Since you only call ChangeColor once every 10 seconds you only update your colors once every 10 seconds. If that's actually want you want, using Time.deltaTime is completely wrong here. DeltaTime is only used for things that are executed once a frame since deltaTime is the time difference between two frames. Using it in a method that isn't called every frame makes no sense at all.
From your code it's not clear what behaviour you're after. If you want more information, you should tell us what exact behaviour you want to achieve.
also to clarify im trying to change the color every few seconds according to the variable i have set, colorChangeReset, and have a smooth transition in 1-2 seconds. This is more for testing purposes and seeing how everything looks in the final version colorChangeReset will be 30 seconds or so, but the transition/lerp itself with happen in the same amount of time.
@Bunny83 thanks a bunch i used your corrections as well as removing the multidimensional array and adding a small custom class. Ive attached an edited script, it does change colors now but it doesn't do it smoothly it just flickers into the next color
@JoshDangit that article was really helpful thanks a lot, i added a float that i increase separately now and use that to control the percentage.
edit i fixed the problem... was a stupid mistake, kept changing the color palette without realizing it, ive attached the working script below:
private int palette;
private bool startChange = false;
float t = 0;
public float colorChangeReset = 10;
private float colorTimer;
private void Awake()
{
colorTimer = colorChangeReset;
palette = Random.Range(0, colorPalette.Length);
}
private void Update()
{
if(!startChange)
colorTimer -= Time.deltaTime;
if (colorTimer <= 0)
{
SetLerpFromColors();
startChange = true;
colorTimer = colorChangeReset;
palette++;
if (palette >= colorPalette.GetLength(0))
{
palette = 0;
}
}
ChangeColor();
}
private void ChangeColor()
{
if (startChange)
{
gameCamera.backgroundColor = menuCamera.backgroundColor = RenderSettings.fogColor =
Color.Lerp(lerpFromColors[0], colorPalette[palette].gameBackground, t);
mainLight.color = Color.Lerp(lerpFromColors[1], colorPalette[palette].mainLight, t);
pipe.color = Color.Lerp(lerpFromColors[2], colorPalette[palette].pipe, t);
RenderSettings.ambientLight = Color.Lerp(lerpFromColors[3], colorPalette[palette].ambientLight, t);
pipeWall.color = Color.Lerp(lerpFromColors[4], colorPalette[palette].pipeWall, t);
t += 0.5f * Time.deltaTime;
if(t >= 1)
{
startChange = false;
t = 0;
}
}
}
private void SetLerpFromColors()
{
lerpFromColors = new Color[5];
lerpFromColors[0] = gameCamera.backgroundColor;
lerpFromColors[1] = mainLight.color;
lerpFromColors[2] = pipe.color;
lerpFromColors[3] = RenderSettings.ambientLight;
lerpFromColors[4] = pipeWall.color;
}
Answer by JoshDangIt · May 17, 2016 at 04:15 PM
Unity's docs doesn't explain Lerping well. Read this tutorial instead: http://www.blueraja.com/blog/404/how-to-use-unity-3ds-linear-interpolation-vector3-lerp-correctly
The guide is on Vector3.Lerp but it's the same principle. The third variable is not the speed to move toward the 2nd color but a percentage between the two colors.