
Two-color Gradients
If the gradient stop list has two colors, which have positions of 0% and 100% respectively, then we use a fairly complicated interpolation strategy, where we blend each (r,g,b) color channel independently, using a gamma interpolation function, that is oriented so that the brighter of the two values dominates the area between the two colors.
Here's C++ pseudocode to describe this interpolation, using C runtime 'pow' power function, which is to be called for each RGB color channel.
// t: expresses a linear ratio beween color1 (value 0.0) and color2 (value 1.0) // rampUp: true if a color channel is growing lighter from color1 to color2, or false if it is growing darker. float ColorChannelVal(float t, bool rampUp) { if(rampUp) return 1.0f - pow( 1.0f - t, 1.875); return pow(t, 1.875); }
This function is used to convert the "linear" distance between colors to a "gamma" value for each RGB channel independently. Then we interpolate the actual color channel value by using the gamma values as a ratio between val1 and val2, rather than the original linear value. For the alpha channel, we perform a linear interpolation between the colors, rather than using the gamma function.
Note that we only apply this special algorithm when there are 2 colors, and one has a position of 0.0 and the other has a position of 1.0 across the gradient. If the gradient has two colors but one has a position like, say, 0.2, then we default back to linear interpolation.
This sample shows a two-color gradient where color channels are interpolated in different directions.
This is what the same example looks like with a normal linear gradient applied (achieved by nudging the position of the right-most color stop from 100% to 99%). It is noticeably less bright:
Here is a visualization of the separate red, green, and blue components. Note how the red and blue components are oriented in opposite directions because the gamma function is applied to maximize the brightness along the width of the gradient range. The green channel is oriented the same direction as the red, but has much less variation between the opposite colors in the range.
Three-color Gradients
If the gradient stop list has three colors, and the first and last color have the same color values, and are at positions 0% and 100%, respectively, then the colors are not linearly interpolated between the positions. Instead, we use the same per-channel interpolation logic as with the two-color gradient. The difference is that, in the 3-color case of S0, S1, S2, where S0.pos < S1.pos < S2.pos, and S0.color == S2.color, the 2-color interpolation is applied twice: once from S0 to S1, and a second time from S2 to S1.
Below is a sample rendering with two 2-color gradients (shorter strips) drawn next to two 3-color gradients (longer strips). It is easy to see the colors line up perfectly when the middle stop of the 3-color gradient lines up with the end of the 2-color gradient.
Below is a 3-color gradient example with black and yellow gradient stops:
This is what the same gradient would look like with a simpler linear interpolation. Note there is a 'crease' in the middle of the range.
We do not, but maybe we should, have any way to enable this per-channel gamma interpolation for 4+ gradient stops. That future feature would produce brighter and smoother gradients for more complex collections of colors.