If you check out this page in the manual.
It says “Color keys of the gradient (maximum 8 color keys).”
You can make your own Gradient object, which isn’t that hard. However, you then need to make your own GradientField control for the IMGUI which is arguably harder.
If you really need this, a hybrid solution would be to make only a custom Gradient object, and ignore the IMGUI tool, and make a list of colors instead.
To implement your own custom Gradient object, you need to understand that it does two things. One is to collect keys which contain { color, alpha } properties, and the other is to evaluate (interpolate) based on some parameter t (typically 0 … 1). Gradient evaluators can be made much more fancy, but you seem to be okay with the basic linear interpolation.
To make this, you have to imagine having keys sitting anywhere between 0 … 1, so this is another property you need to account for: { t, color, alpha }. Then you have to be able to sort the keys based on t (ideally only when the list changes), to have an easier time finding the two neighboring ones for any arbitrary point on this segment.
Imagine a simple diagram of a segment going from 0 to 1, and now imagine 3 keys, positioned at 0%, 75% and 85%
Q1 What should a color at 50% be?
Q2 What should a color at 80% be?
Q3 What should a color at 90% be?
Let’s get you properly introduced to linear interpolation.
On one hand, you want a value that’s some % in between A and B.
You basically mix the two values in some linear proportion.
If you want them 50-50 you add half of A and half of B. You get an average, right? x = (a + b) * 0.5
However, a generalized “mixture” looks like this x = a * (1 - t) + b * t
Let’s check this out, if A was 10, and B was 20
This would make a t of 30% result in 10 * (1 - 0.3) + 20 * 0.3 = 7 + 6 = 13
Interesting right? You end up on a value exactly 3/10ths away from A, and 7/10ths away from B.
This means that t is literally at 30% of this segment between A and B.
An inverse concept is also important. If I told you we have A at 10 and B at 20 and some point X at 16, what’s t equal to? Intuitively you can guess it’s 60%, and it is, but let’s do the actual inversion
a * (1 - t) + b * t = x
b * t + a * (1 - t) = x
b * t + a - a * t = x
t * (b - a) + a = x
t * (b - a) = x - a
t = (x - a) / (b - a)
So if A was 10, and B was 20, and X was 16
(16 - 10) / (20 - 10) = 6 / 10 = 0.6
We can now formally write some code
// lerp is short for linear interpolation
float Lerp(float min, float max, float t) => min * (1f - t) + max * t;
float InverseLerp(float min, float max, float v) => (v - min) / (max - min);
Let’s now return to questions.
For Q1
t (50%) lies between keys 0 (0%) and 1 (75%).
Where would t be if we stretched this from 0 to 100%?
This is answered by InverseLerp(0, 0.75, 0.5) = 0.6666
So what’s the evaluated color here?
This is answered by Lerp(color1, color2, 0.6666) (note that this kind of lerp works with the colors)
This works with alpha as well.
For Q2
t (80%) lies between keys 1 (75%) and 2 (85%).
Where would t be if we stretched this from 0 to 100%?
InverseLerp(0.75, 0.85, 0.8) = 0.5
So what’s the evaluated color here?
This is answered by Lerp(color1, color2, 0.5)
For Q3
t (90%) lies to the right of the rightmost key 2 (85%).
Because there are no other neighbors, we assume that this key’s color is fixed.
This was the hardest part.
To find where input t lands exactly, you simply walk through the sorted keys in order, and accumulate them until the result surpasses it stop once a key’s t surpasses the input t. This key and the previous key are the neighbors. If there are no more keys and input t is still greater, or when there was no previous key, this is a fixed color (non-interpolated).
Code might look something like this (edit: check the next post for getNeighborKeys because I made a mistake)
public Color Evaluate(float t) {
if(_keys.Length == 0) return new Color(0f, 0f, 0f, 0f);
var n = getNeighborKeys(_keys, t);
if(n.l < 0) return _keys[n.r].Color;
else if(n.r < 0) return _keys[n.l].Color;
return Color.Lerp(_keys[n.l].Color, _keys[n.r].Color, n.t);
}
Feel free to ask if you need more detail.