How do I properly combine the colors of different lights?

Let's say I have 4 light colors:

(0.6,0.0,0.0), (0.0,0.6,0.0), (0.1,0.1,0.1), (0.1,0.1,0.1)


And now I want to combine them properly. I can't add them together, because if I add for example 3rd color and 4th color I will receive (0.2,0.2,0.2), while I would expect it to be (0.1,0.1,0.1). So what is the way to mix colors together and receive final light color?

I tried something like this (Pseudo-code example for color 3 and 4):

color3 - color4 = (0.0,0.0,0.0)
finalColor = subtraction result (0.0,0.0,0.0) + color3


But sometimes it doesn't work.

• What's the context? What do you want to do with these colours? – Alexandre Vaillancourt Feb 11 '16 at 18:37
• I'm creating multiple lights in my game engine. – skprime Feb 11 '16 at 18:40
• Why should it be (0.1,0.1,0.1)? If you shine two flashlights on the same area it will be brighter than if you shine only one flashlight, right? – amitp Feb 12 '16 at 0:06

Your question makes it clear what you don't want, i.e. a combination of a color like (0.1,0.1,0.1) with itself to result in pure addition, giving (0.2,0.2,0.2), when you would expect it to result to stay the same (0.1,0.1,0.1). However, you never made it clear what you want in other cases, such as when combining your first color, (0.6,0.0,0.0) with your second color (0.0,0.6,0.0). I guess that in this case you are expecting the result to be a pure plain addition, giving (0.6,0.6,0.0).

Here are the visual representations of the 4 colors you gave as example in the second line of your question:

So, here it is a visualization of what you get when purely adding (0.6,0.0,0.0) and (0.0,0.6,0.0), which is equal to (0.6,0.6,0.0):

Now, when summing two lights of the same color, like (0.1,0.1,0.1) plus (0.1,0.1,0.1), as @amitp has accuratelly pointed out in the comments, there is no reason why you should expect that two hlights overlapping would NOT result in a brighter version of that original color. Thus, this is what you got, i.e. (0.2,0.2,0.2):

In other words, that is perfectly correct and "realistic": two lights of different color result in a brighter light of composed color, while two lights of the same color result in a brighter light of that original color.

That only works well because of something that @Draco18s correctly pointed out in her/his answer: any values above 1 (i.e. 255) will be clamped to 1 (i.e. 255). It means, in a rough and imprecise way to put it, that when a light color is in its brightest RGB version, then of course the overlap of two such lights just cannot result in any brigther versions of themselves. Thus, summing (1,0,0) with itself still results in (1,0,0), which looks like the following:

So, to sum up, there is nothing wrong there that you need fixing. However, maybe what you are looking for is something that is not exaclty what one can see in the picture you posted in your question. For instance, think of the averaging of two colors instead of their addition (I mean, literally the sum of the two colors divided by 2).

The average of (0.6,0.0,0.0) and (0.0,0.6,0.0) is (0.3,0.3,0.0). Which looks like the following:

Now, in that case, the averaging combination of the colors results in a new color that looks similar to both the original colors. Instead of red and green resulting in yellow, now you have red and green resulting in something that looks, in a perception sense of the word, like a mix of the red and green. However, the downside is that due to the nature of the average, it also looks a bit darker than the original two colors that compose the third. Therefore, this may or may not work for your particular situation, depending on what you prefer.

But of course, in this case, averaging (0.1,0.1,0.1) with itself will now result in (0.1,0.1,0.1):

Whether averaging or pure addition (or any other formula) works best for you, it is you who can decide. However, within the RGB color space alone, you can't easily get the result of averaging for (0.1,0.1,0.1) plus (0.1,0.1,0.1) AND the result of pure addition between (0.6,0.0,0.0) and (0.0,0.6,0.0). Unless you just hard code if-else exceptions, passing different formulas for each types of cases. But of course, that wouldn't keep consistency, would probably look less natural or could result in pretty unpredictable results.

PS: For a fairly detailed explanation on color mixing and related discussions, see Manipulating colors in .NET - Part 1.

Define "properly." There are multiple ways of blending color. Additive blending works as you describe, 0.1 + 0.1 = 0.2 because we don't care if this value goes over 1 (as the values are clamped [0-1]). If you want to account for High Dynamic Range color, then you have to perform an additional step: rescaling.

HDR works by saving the largest value produced across the standard render (letting per-pixel values exceed 1), then dividing every pixel by that value, or some value close to it, so that the whitest whites stay white, the darkest black stay black, and everything else in between scales. This is how our eyes work, and why going into a dark room you can't see (until your eyes adjust) only to have the sun dazzle you when you come out again.