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 )
.
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 i
th 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 i
th 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