For a school assignment, I need to do something like this: The 500x500 rectangle should show the different hue, saturation, and brightness of whatever color the mouse is pointing at, kind of like a Color Picker.
But since I suck at coding so much, I don't know what to do. I don't understand HSB very much. Here is my code and a picture of what I have right now.
void setup() {
size(500,550);
}
void draw() {
noStroke();
colorMode(HSB, 100);
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 50; j++) {
int h = i-200;
int s = j+500;
int b = 500 + j;
stroke(h,s,b);
point(i, j);
}
}
noStroke();
fill(mouseX, mouseY);
rect(0,50,500,500);
}
Any help would be appreciated. Thank you very much!
You're already doing great using colorMode(HSB)
to render the rainbow.
I'd move nested for loop to setup to make it more efficient: it would rendered once and stay there since you're not calling background()
and rect(0,50,500,500);
is bellow the rainbow gradient.
HSB is actually easier to use than RGB. Here's a diagram from Wikipedia: SharkD, CC BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0, via Wikimedia Commons
Value is the same a Brightness. Hue is typically in a 0-360 degrees range so picture going around in a rainbow circle, starting at red and ending at red. Let's say you start at red, at 0 degrees hue and you know yellow is at 60 degrees hue. Intuitively you'd find orange halfway between red and yellow at 30 degrees. In fact, if you go every 60 degrees you'll go through red, yellow, green, cyan, blue, magenta and back to red at 360/0.
Saturation and brightnesses typically go between 0-100%. Notice in the diagram above saturation increases away from the centre: 0 saturation = gray, 100% saturation = full tint.
Brightess increases from bottom to top in the diagram.
It's a bit strange you're mapping to 0-100 range for hue, saturation and brightness. Perhaps the intention was to simplify things by treating the hue as a percentage too.
One thing that could make things easier is the map()
function.
It maps a number from one range to another.
For example this bit of code is trying to remap i, j positions to hue and saturation.
i, j
are in in 0-500, 0-50 range (x, y positions)i
from 0-499
range to 0-100
to map into hueFor example:
void setup() {
size(500, 550);
colorMode(HSB, 100);
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 50; j++) {
// remap i (x -> width) to 0 - 100 range for hue
// since map returns a float, round helps make that an int
int h = round(map(i, 0, 499, 0, 100));
int s = 100;
int b = 100;
stroke(h, s, b);
point(i, j);
}
}
noStroke();
}
void draw() {
fill(map(mouseX, 0, width, 0, 100), map(mouseY, 0, height, 0, 100), 100);
rect(0, 50, 500, 500);
}
In this particular case the 0-500 to 0-50 range is trivial: 500 / 100 = 5, therefore:
int h = i / 5;
will get you the same result as int h = round(map(i, 0, 499, 0, 100));
,
just don't have to think of the arithmetic too much.
In the nested for loop you're setting HSB colours.
For the next part you'll need to get / read HSB colours
and luckily Processing already provides hue(), saturation() and brightness() for you. For the color picker you'll only need hue()
.
To get the color under the cursor location on you simply call get(x, y)
which returns a color a those coordinates.
If you look at the gradient image you notice:
If you read the hue()
when the mouse is clicked on the top rainbow gradient you can then make the larger gradient bellow by simply mapping x,y coordinates to saturation and brightness:
float hue;
void setup() {
size(500, 550);
colorMode(HSB, 100);
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 50; j++) {
// remap i (x -> width) to 0 - 100 range for hue
// since map returns a float, round helps make that an int
int h = round(map(i, 0, 499, 0, 100));
int s = 100;
int b = 100;
stroke(h, s, b);
point(i, j);
}
}
noStroke();
}
void draw() {
// pick colour (hue)
if(mousePressed){
// check if the mouse was pressed on the top side only
if((mouseX >= 0 && mouseX <= 500) &&
(mouseY >= 0 && mouseY <= 50)){
hue = hue(get(mouseX, mouseY));
}
}
// render saturation , brightness mapping
for (int i = 0; i < 500; i++) {
for (int j = 50; j < 550; j++) {
int saturation = round(map(i, 0, 500, 100, 0));
// swap output mapping range: brightness goes up when y decreases
int brightness = round(map(j, 50, 550, 100, 0));
stroke(hue, saturation, brightness);
point(i, j);
}
}
}
You'll notice this runs a bit slow. It can be much faster using the pixels[]
.
However there are a few curve balls:
loadPixels()
before you can read pixelsindex = x + y * width
updatePixels()
after setting values to pixels[]
to updateThis will run much faster:
float hue;
void setup() {
size(500, 550);
colorMode(HSB, 100);
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 50; j++) {
// remap i (x -> width) to 0 - 100 range for hue
// since map returns a float, round helps make that an int
int h = round(map(i, 0, 499, 0, 100));
int s = 100;
int b = 100;
stroke(h, s, b);
point(i, j);
}
}
noStroke();
}
void draw() {
// make latest pixels[] data available
loadPixels();
// pick colour (hue)
if(mousePressed){
// check if the mouse was pressed on the top side only
if((mouseX >= 0 && mouseX <= 500) &&
(mouseY >= 0 && mouseY <= 50)){
//hue = hue(get(mouseX, mouseY));
hue = hue(pixels[mouseX + mouseY * width]);
}
}
// render saturation , brightness mapping
for (int i = 0; i < 500; i++) {
for (int j = 50; j < 550; j++) {
int saturation = round(map(i, 0, 500, 100, 0));
// swap output mapping range: brightness goes up when y decreases
int brightness = round(map(j, 50, 550, 100, 0));
//stroke(hue, saturation, brightness);
//point(i, j);
pixels[i + j * width] = color(hue, saturation, brightness);
}
}
// update
updatePixels();
}