3

I am building a free real color mixer for 3 colors. To feel real I first convert hex or rgb to hsl and calculate with h, s, l values. I figured out to mix 2 colors:

function hslMixer2c(hsl10,hsl11,hsl12,hsl20,hsl21,hsl22,amount1,amount2) { // read hsl10 as hsl1[0], 1st value from hsl string
    var amountTot = amount1 + amount2;
    if (Math.abs(hsl10 - hsl20) > 0.5) { hsl10 += 1; } // > 179.5 is shorter part from wheel to 359
    var h = (amount1 / amountTot) * hsl10 + (amount2 / amountTot) * hsl20;  
    var s = (amount1 / amountTot) * hsl11 + (amount2 / amountTot) * hsl21; 
    var l = (amount1 / amountTot) * hsl12 + (amount2 / amountTot) * hsl22; 
    if (h > 1) { h -= 1; } 

    return [h, s, l];
}

HSL Color Wheel

So far, so good...

But I want to add a 3th color to mix. I tried several calculations but the results are different when changing the order of the used colors.

function hslMixer3c(hsl10,hsl11,hsl12,hsl20,hsl21,hsl22,hsl30,hsl31,hsl32,amount1,amount2,amount3) { // read hsl10 as hsl1[0], 1st value from hsl string
    var amountTot = amount1 + amount2 + amount3;
    if (Math.abs(hsl10 - hsl20) > 0.5) { hsl10 += 1; } // > 179.5 is andere kant naar 359 korter)
    var hsl90 = (amount1 / amountTot) * hsl10 + (amount2 / amountTot) * hsl20;  // hsl9x is sub mix
    var hsl91 = (amount1 / amountTot) * hsl11 + (amount2 / amountTot) * hsl21; 
    var hsl92 = (amount1 / amountTot) * hsl12 + (amount2 / amountTot) * hsl22; 
    if (hsl90 > 1) { hsl90 -= 1; } 
    if (Math.abs(hsl90 - hsl30) > 0.5) { hsl90 += 1; } // > 179.5 is andere kant naar 359 korter)
    var h = hsl90 + (amount3 / amountTot) * hsl30;  
    var s = hsl91 + (amount3 / amountTot) * hsl31; 
    var l = hsl92 + (amount3 / amountTot) * hsl32; 
    if (h > 1) { h -= 1; } 

    return [h, s, l];
}

Set color 1st at 90, 2nd at 180, 3rd at 300 the calculation is first for color 1 and 2 and additional 3 gives 190. But when I take 3 and 1 as first, the color goes to the upper side of the wheel and gives with addition color 3 a whole other result off course.

Can anyone help me pointing to the right direction, maybe with a sample?

Harry
  • 786
  • 1
  • 8
  • 27
  • How did you add a third color? By running this code twice, or by writing separate code whith an additional `amount3`? – Jongware Mar 05 '16 at 15:58
  • I write a separate code with additional amount 3. I will edit my question by adding that code. Sorry, I forgot. – Harry Mar 05 '16 at 16:03
  • Equations can be found on Wikipedia/hsl – Arif Burhan Mar 05 '16 at 16:08
  • Your 3rd component code essentially comes down to running the 2-component code twice. Do you get another result if you do the calculations only once - amount1 * hsl1 + amount2 *hsl2 + amount3*hsl3? – Jongware Mar 05 '16 at 17:14
  • @RadLexus but I have to check if the difference between 2 colors is more or less then 179,5 for the exact calculation at the right side of the color wheel. This can't be done with 3 colors at once. – Harry Mar 05 '16 at 22:05
  • You need to think of what you want to achieve. Suppose, in your two-color model, the 2 colors are 180° apart - what does "mixing" them result in? Similarly, for a mix of 3 colors: if mixing *a* and *b*, then mixing *ab* and *c* results in a different color than *ac* and *b* or *bc* and *a*, your model is not stable. I'm beginning to wonder if moving from RGB to HSL was such a good move. – Jongware Mar 05 '16 at 23:00

1 Answers1

5

One approach might be to convert each of the colors hue angles into a vector format:

  x = Math.cos(hue / 180 * Math.PI) * saturation
  y = Math.sin(hue / 180 * Math.PI) * saturation
  z = lightness

and then simply sum up these vectors (axis by axis) and divide by the number of colors.

If you would like some colors to contribute more towards the final color than others you could multiply each vector by a weight (where the sums of all weights = 1) prior to adding the vectors.

Finally convert back to hue and saturation:

        h = Math.atan2(y, x) * 180 / Math.PI
        s = Math.sqrt(x * x + y * y)
        l = z
Bjorn Reppen
  • 22,007
  • 9
  • 64
  • 88