Question

Hard to describe what I'm trying to do. I basically want to create a discrete rainbow gradient so that for any line of i number of JButtons, the colour gradient across them will look rainbow.

I have done the following but it only really creates a red gradient followed by green gradient followed by blue gradient:

Color[] c = new Color[i];
    for(int n = 0; n < i; n++) {
        if(n < i/3) {
            c[n] = new Color(255, 255/(n+1), 255/(n+1));
        } else if(n < 2*i/3) {
            c[n] = new Color(255/(n-(i/3)), 255, 255/(n-(i/3)));
        } else {
            c[n] = new Color(255/(n+1), 255/(n+1), 255);
        }
    }

Any Idea how I would be able to get some type of rainbow effect?

Thanks

EDIT:

Used a Sine function which seems to work slightly better, but not sure how to define it so I get one "rainbow wave" in the region I want:

for(int n = 0; n < i; n++) {
        c[n] = new Color((int)(Math.sin(n) * 127 + 128), (int)(Math.sin(n + Math.PI/2) * 127 + 128), (int)(Math.sin(n + Math.PI) * 127 + 128));
    }
Was it helpful?

Solution

Your code has the right idea, but you need to run through your colors a little bit differently.

Let's say you're starting with green:

Color(  0, 255,   0)

Slowly start adding in some red to get to yellow:

Color( 51, 255,   0)
Color(102, 255,   0)
Color(153, 255,   0)
Color(204, 255,   0)
Color(255, 255,   0)

Then, take out the green to get to red:

Color(255, 204,   0)
Color(255, 153,   0)
Color(255, 102,   0)
Color(255,  51,   0)
Color(255,   0,   0)

Now, add blue to get to purple:

Color(255,   0,  51)
Color(255,   0, 102)
Color(255,   0, 153)
Color(255,   0, 204)
Color(255,   0, 255)

Then, remove red to get to blue:

Color(204,   0, 255)
Color(153,   0, 255)
Color(102,   0, 255)
Color( 51,   0, 255)
Color(  0,   0, 255)

Add the green back in to get to cyan:

Color(  0,  51, 255)
Color(  0, 102, 255)
Color(  0, 153, 255)
Color(  0, 204, 255)
Color(  0, 255, 255)

And finally remove the blue to get back to green:

Color(  0, 255, 204)
Color(  0, 255, 153)
Color(  0, 255, 102)
Color(  0, 255,  51)
Color(  0, 255,   0)

In this circle, of course, you can start anywhere and go in either direction.

In code, it could look as simple as this:

List<Color> colors = new ArrayList<Color>();
for (int r=0; r<100; r++) colors.add(new Color(r*255/100,       255,         0));
for (int g=100; g>0; g--) colors.add(new Color(      255, g*255/100,         0));
for (int b=0; b<100; b++) colors.add(new Color(      255,         0, b*255/100));
for (int r=100; r>0; r--) colors.add(new Color(r*255/100,         0,       255));
for (int g=0; g<100; g++) colors.add(new Color(        0, g*255/100,       255));
for (int b=100; b>0; b--) colors.add(new Color(        0,       255, b*255/100));
                          colors.add(new Color(        0,       255,         0));

Here, the 100's are the number of steps for each fade, which you can adjust.

If you need the colors in an array instead, do this at the end:

Color[] c = colors.toArray(new Color[colors.size()]);

One thing to note: The human eye is MUCH more sensitive to green than to red and blue. So you might want to add and remove green with smaller steps than you would with red and blue. Just play with the different step-sizes until you get something that looks even.

PS: For what I've used it for, linear fading as described above is perfectly sufficient and looks as expected. I personally don't think you need to complicate things by using sin and cos or other math.

OTHER TIPS

You can use the HSV (hue, saturation, value) Instead of a RGB. In HSV, the color range is affected by only one variable (hue). if you run from 0 to 360 you cover the entire range of colors.

HSV scheme

Example of code:

final int ARRAY_SIZE = 100;
double jump = 360.0 / (ARRAY_SIZE*1.0);
int[] colors = new int[ARRAY_SIZE];
for (int i = 0; i < colors.length; i++) {
    colors[i] = Color.HSVToColor(new float[]{(float) (jump*i), 1.0f, 1.0f});
}

If you want to cover only part of the color table (Use the picture I attached below). An example of an array of turquoise color for a red color:

final int ARRAY_SIZE = 100;
final int MAX_COLOR = 360;
final int MIN_COLOR = 160;
double jump = (MAX_COLOR-MIN_COLOR) / (ARRAY_SIZE*1.0);
int[] colors = new int[ARRAY_SIZE];
for (int i = 0; i < colors.length; i++) {
    colors[i] = Color.HSVToColor(new float[]{(float) (MIN_COLOR + (jump*i)), 1.0f, 1.0f});
}

HSV color scheme

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top