Reputation: 23803
I have this function that takes two arguments. They are arrays in the [r, g, b]
format.
function mix(color1, color2)
{
var r = Math.round((color1[0] + color2[0])/2);
var g = Math.round((color1[1] + color2[1])/2);
var b = Math.round((color1[2] + color2[2])/2);
return [r, g, b];
}
If I try to mix red (255, 0, 0) and blue (0, 0, 255), tt gives me [128,0,128]
, which is purple. But if I try mixing blue (0, 0, 255) and yellow (255, 255, 0)
console.log(mix([255,0,0], [0,0,255]));
console.log(mix([255,255,0], [0,0,255]));
it gives me gray [128, 128, 128]
, instead of green. Why is this happening?
Upvotes: 0
Views: 2543
Reputation: 339927
You need to convert your colours into either HSL or HSV color models (plenty of samples here or on Google, e.g. like this page).
You then do the averaging with the resulting numbers, and then convert back to RGB.
This will ensure that the saturation and brightness remain consistent, and give you the correct hue that's half way between the two original colours.
Using the library linked above:
function mix(color1, color2, amount)
{
if (typeof amount === "undefined") {
amount = 0.5;
}
var hsl1 = rgbToHsl.apply(this, color1);
var hsl2 = rgbToHsl.apply(this, color2);
var h = amount * hsl1[0] + (1 - amount) * hsl2[0];
var s = amount * hsl1[1] + (1 - amount) * hsl2[1];
var l = amount * hsl1[2] + (1 - amount) * hsl2[2];
return hslToRgb(h, s, l);
}
NB: this is untested code (the algorithm is correct, I just didn't actually throw it at an interpreter yet), and the results may need to be rounded. However for bonus points it also allows you to specify a mix proportion other than 50/50.
Upvotes: 4
Reputation: 21
2 main issues here:
additive versus subtractive mixing - that's easy to read about
But I think, the main issue was that blue and yellow paint do not make green. The type of blue you would be thinking of is in fact not blue: more of a cyan or at least a blue with some green shift.
A pure "blue" is neither warm (towards red) or cool (towards yellow/green) and in paint would be something like ultramarine red shade - a pure blue but you would consider quite a dark (almost navy) blue.
When mixed in paint with yellow you would not get a bright green, more of a dull grey. In paint to get paint colors which are bright from mixes it is essential to use colors which are not across from each other on the color wheel , but in fact as close as possible ideally, so a bright green can in fact be only obtained in paint from mixing a greeny blue with a greeny yellow - ie. they are neighbours.
The green will still not be as bright as a pure green. That cannot be done in subtractive (paint mixing) - to combine colors and get new pure colors can only be done with colored lights - ie. additive mixing , like you see in the theatre.
However be aware that additive mixing is somewhat counter-intuitive - instead of your subtractive paint blue/yellow mix giving a neutral gray (black in theory) in fact with lights you would get white .... (still not green!).
It is a very complex field because there is also some psychology and physiology involved - our brains cheat or mistake color perception on a regular basis. eg. you mix black with yellow you get a dark green - that is related to the sensitivity or the red / green cones as the brightness decreases - it is in fact dark yellow but we see green.
Upvotes: 2
Reputation: 10117
I think your formula works fine, it is what, say, photoshop would do if you put blue next to yellow and apply a blur...you'd get gray right in the middle. Blue and yellow don't mix to make green. Red, green, and blue are primaries on computer monitors, camera film and the human eye.
Yellow, meanwhile, is a mixture of red and green light, that is, the red and green sensitive cones in your eyes are stimulated when you see yellow. It may not seem intuitive, but it's true. Look at a yellow area of your screen under a magnifying glass and you'll see it is composed of red and green dots.
This is in contrast to what you may have learned in elementary school, and sometimes mixing paints or inks may end up with blue and yellow making a (typically muddy) green. So, I don't suggest you change your algorithm, that is a standard way of blending two colors together. Just change your expectations. :)
Upvotes: 0
Reputation: 113974
To get what you expect you need to work in CMY space instead of RGB space.
Here's a simple RGB to CMY converter:
function rgb2cmy (r, g, b) {
var c = 255-r;
var m = 255-g;
var y = 255-b;
return [c,m,y];
}
And simply reverse the process to convert back to RGB:
function cmy2rgb (c, m, y) {
var r = 255-c;
var g = 255-m;
var b = 255-y;
return [r,g,b];
}
(if you've been paying attention you'll realize that both functions do the same thing)
Upvotes: 1
Reputation: 137420
Because you are calculating resulting color as the arythmetic average of two base colors.
Colors work in a different way depending on what you mix. If you would mix paints of many different colors, the result would be dark, nearly black. But if you would mix lights of different colors, the result would be nearly white. First define the process you want to simulate - I bet it is the one that is similar to mixing paints, correct?
Two basic methods of mixing colors are:
subtractive mixing, which looks like that:
additive mixing, which looks like that:
What you need is subtractive color mixing, whose output should be in RGB
notation.
Upvotes: 2