DEPARTMENT OF COMPUTING

CS 3005: Programming in C++

Color Gradients

A color gradient is a range of colors that smoothly transition from a starting color to an ending color, with some number of intermediate steps. Below is an example gradient of 300 colors that starts with ( 104, 151, 155 ) and ends with ( 85, 40, 0 ).

GradientExample

Notice the smooth, slow transition from the light blue to the deep brown. The gradient shown is a linear color gradient. Each color is the same (color)-distance from each of its neighboring colors. This is what makes it a linear gradient, instead of some other kind of gradient.

Calculating Gradient Colors

If we want to construct a linear gradient of n colors starting with c1 and ending with c2, we can easily figure out the color of the first and last colors. Color 0 (the first one) is c1. Color n-1 (the last one) is c2.

The rest of the colors need a little more work. Let’s figure out the color next to c1.

For a linear gradient, the color change between any two colors is the same amount. With n colors, there are n-1 color changes. So, the color next to c1 will be 1/(n-1) part of the way from c1 to c2. The color after that will be 2 steps or 2/(n-1) of the way. In fact, the ith color after c1 will be i/(n-1) of the way from c1 to c2.

How far do we need to go? In other words, what is the color distance? Let’s consider the red channel first. c1 and c2 both have a red component. The distance we need to go is c2.red - c1.red. Each step away from c1 will add another (c2.red - c1.red)/(n-1) to the red value of the gradient color.

If we put this all together, we get a formula for the red channel of the ith color in the gradient.

`red_i = c1.red + i * ( c2.red - c1.red ) / ( n - 1 )`

We usually don’t want to calculate the same values repeatedly, so it would be wise to calculate

`red_step = ( c2.red - c1.red ) / ( n - 1 )`

once, and use it in a simplified version of the formula:

`red_i = c1.red + i * red_step`

A similar set of formulas are representative of how to calculate the green and blue channels for the colors.

Finally, there really is no need to assign the first and last colors specially. These formulas will work correctly for them as well. By calculating the *_step values up front and constructing a simple loop, we can fill in all colors of the gradient.

On Floating Point vs Integer Types

When calculating the *_step values, we want to be sure that the division is calculated as a floating point value, particularly the division. Then, the result needs to be stored in a floating point variable, so that the fractional part is preserved. If not, our gradient will be close, but incorrect, particularly the colors later in the gradient.

Since we’re working in a strongly typed language, be sure to use the correct types for values. For example, red_i, c1.red, c2.red, i, and n are all integers. However, red_step should be floating point for best results. This means that you want the division to happen as a floating point operation. Use a casting technique to make the division to be floating point. For example:

`( (double)c2.red - c1.red ) / ( n - 1 )`

This will cause a copy of c2.red to be converted to double, which causes a copy of c1.red to be promoted to double before subtraction. This will cause the result of n-1 to be promoted to double before the division. If red_step is a double, it will be able to receive this value correctly. If you run into problems with unit tests that show colors off slightly, this is a good place to debug.

Disclaimer

This description is intentionally separated from details of any particular programming assignment. Use the information here, and the functions or methods available to you to implement this algorithm in your code.

Last Updated 03/17/2021