What you want is to “slide” the positions of your start/end colors.
Unfortunately, the normal Lerp
function won’t do this for you, so you will need to write your own. Instead of “sliding” the colors themselves, you can “slide” your lerp parameter instead. Here is some pseudocode for what your new lerp might look like.
Color slidingLerp(startColor, endColor, time, parameter) {
return Color.Lerp(startColor, endColor, parameter + (time - 0.5) * 2);
}
In the above pseudocode, time
is the time in your diagram, and parameter
is the t
that you use with the normal Lerp
.
To see what this function does with time
and parameter
, plug in values for time
.
When time == 0
, the expression parameter + (time - 0.5) * 2
evaluates to parameter - 1
. Assuming parameter
is clamped between 0 and 1, expression will be less than or equal to 0, which will be clamped to 0 by Color.Lerp
. A similar situation happens when time == 1
. When time == 0.5
, the same expression evaluates to just parameter
, so the function behaves like the normal Lerp
.
Edit:
It is possible to avoid using textures to draw a radial gradient if you use a specialized shader.
Let’s say you have a quad that looks like this, where the red is the UVs of the quad:
This just so happens to be the UV layout of the quad primitive in Unity (maybe with diagonal switched, but that won’t matter). The UV coordinate at the center of the quad is simply (0.5, 0.5). Given a pixel on the quad, you can calculate its distance from the center point using the distance formula:
float t = length(UV - float2(0.5, 0.5));
Note that the range of t
is between 0 and sqrt(2)/2
for a pixel in the quad. It would be nice to normalize it, so we take t and multiply it by sqrt(2)
:
float t = length(UV - float2(0.5, 0.5)) * 1.41421356237;
Now, using the normalized value of t
, we can just plug it into the special lerp that I mentioned originally and return the color:
return lerp(colorA, colorB, t + (slide - 0.5) * 2);
Putting this concept in a shader program, you’ll get something like this:
//RadialGradientQuad.shader
Shader "Custom/RadialGradientQuad" {
Properties {
_ColorA ("Color A", Color) = (1, 1, 1, 1)
_ColorB ("Color B", Color) = (0, 0, 0, 1)
_Slide ("Slide", Range(0, 1)) = 0.5
}
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType" = "Plane"}
LOD 100
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata_t {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
half2 texcoord : TEXCOORD0;
};
v2f vert (appdata_t v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.texcoord = v.texcoord;
return o;
}
fixed4 _ColorA, _ColorB;
float _Slide;
fixed4 frag (v2f i) : SV_Target
{
float t = length(i.texcoord - float2(0.5, 0.5)) * 1.41421356237; // 1.141... = sqrt(2)
return lerp(_ColorA, _ColorB, t + (_Slide - 0.5) * 2);
}
ENDCG
}
}
}
Given this shader, I assume that you know how to create a material and put it on a quad. You should see something like this: