These aren't the Gamuts You're Looking For...
Or are they...?
I'm re-writing my answer in part because there are valid reasons for mixing colors in linear as I first wrote, but using perception adjusted colors does have some advantages depending on needs, as are other methods, so it's not an absolute "do this not that."
There are some cases when you might want to use linear math on gamma encoded color data, particularly if you are looking for a perceptually linear result. For instance in one example, averaging the RGB components between two colors will give a different result depending on if you are using linearized color values, or gamma/perceptually encoded ones, or are using some other color difference method. Which is better? Depends on your application.
Working with VFX in films, normally we model light as it is in the real world, and light in the real world behaves linearly, so linear math on a linear light model is the means to do that. But if you are generating a set of gradient colors for use in web design? Well, it could be better to generate those using the gamma encoded color values, or perceptually uniform values (L*).
CIELAB is used for applications where you need to model the nonlinear perception of human vision. Since you mentioned it, I am assuming that is your intent. But you might also look into iCAM and CIECAM02.
But you say you want to mix colors that represent virtual lights in a virtual environment ( i.e. 3D rendering or laying images in a composite, etc) usually that means we want to mix colors using a linear light (linear colorspace) model. This could be linearized RGB, or it could be CIEXYZ or xyY, which are linear colorspaces.
BACKGROUND
CIELAB is nonlinear. The L* (from L*a*b*
)is perceptual lightness, approximating the human eye's gamma of photopic vision. The intention is to be perceptually uniform.
CIEXYZ is a linear representation of light. Luminance (the Y in XYZ) varies linearly just as light does in the real world. The intention is that when you apply simple linear math, the results mirror real light.
XYZ and LAB serve two very different purposes. If you are working with light values, such as with adding together multiple colors, then linear spaces such as XYZ or xyY are your ideal choice as the math to do so is simple.
But if you are working with perceptual quantities, such as how would this apple look if it was perceived as half as brightness, then L*a*b*
may give you an easier answer.
The usual example is middle grey. in CIELAB, the middle grey that most people identify as "half way" between black (0.0) and white (100.0) is a value of 50.0 in L*a*b*
.
However in XYZ, with black (0.0) and white (100.0), that same middle grey is 18.4.
In XYZ, if you double the quantity of light, such as $ 18.4 * 2 = 36.8 $, the result in L*a*b*
would be only a mild increase from 50.0 to 67.1. Indeed, when you double the number of photons in a scene, our human vision only perceives a small increase, not a literal doubling of light.
Mixing Colors For Fun and Profit
When I first read the question where you say you want to mix colors, I assumed you meant you want to mix light values to come up with a final mixture of light. This is probably the bias of my VFX/Film background.
But I re-read the question recently and realized my answer was partially off point, so I've expanded is for clarity and additional related methods.
I'm still assuming you want to blend colors of an additive model like RGB, not a subtractive model (i.e. paint and pigments). Totally different set of transforms !!
LIGHT? Or PERCEPTION?
The Linear/NonLinear Choices
Perception is non-linear, so modeling it usually requires a non-linear, perceptually uniform approach. CIELAB, ICAM, CIECAM02 are some non-linear methods. And in fact, sRGB, Rec709 and other gamma curves "approach" the curve of perception to differing degrees.
Since light is linear, to model it use linear math and a linear colorspace. You could use CIEXYZ, or xyY, or you can just linearize the RGB colorspace you are using, for discussion I'll assume we're linearizing sRGB as it's the common standard for computers and the web.
LINEARIZING sRGB
Step one is linearizing the sRGB values. You can use a simple power curve applying an exponent of 2.2, or use the correct sRGB curve — Here's a code snippet from my OpenOffice Calc (spreadsheet) for converting an sRGB color value to linear RGB using the proper sRGB math.
For this discussion, we'll assume a HEX value of #009CC3
in cell A1 of the spreadsheet.
First, split apart the HEX values of each channel of sRGB
```lang-none
=DEC2HEX(HEX2DEC(A1)/65536) // R of #00 in cell B1
=DEC2HEX(MOD(HEX2DEC(A1);65536)/256) // G of #9C in cell C1
=DEC2HEX(MOD(HEX2DEC(A1);256)) // B of #C3 in cell D1
// Normalize the sRGB values from 8bit to float, dividing by 255
=B1/255 //R in cell B2
=C1/255 //G in cell C2
=D1/255 //B in cell D2
Then linearize each color separately. Only red (Cell B3) is shown here:
=IF( B2 <= 0.04045 ; B2 / 12.92 ; POWER(((B2 + 0.055) / 1.055) ; 2.4))
Spectral weighting is probably not important for what we are going to do in this example, simple adding/averaging. However we might want to if we are doing a multiply operation or other more complex tasks.
MIX IT UP
With R, G and B are linear, we can use simple math to mix and average them. The math to add two colors in a linear colorspace can be as trivial as an average:
$$
\large C_{result} = (C_{1LinearValue} + C_{2LinearValue}) / 2
$$
It's simple — but is it accurate enough for what you need?
You might need perceptually encoded values for doing, say, creating a gradient between two or more colors.
So let's say we have these two sRGB gamma encoded hex values to mix in equal proportions: C1 = #009CC3
sRGB Cerulean Blue, and C2 = #FFFE00
sRGB Yellow
The linearized RGB values of those colors:
$ C_1 = 0.0_R, 0.334_G, 0.548_B $ (Cerulean Blue)
$ C_2 = 1.0_R, 0.995_G, 0.0_B $ (Yellow)
Then add each channel, and divide each channel by 2:
$ R_1 + R_2 = 1.0 $ and $ 1.0 / 2 = 0.5_R $
$ G_1 + G_2 = 1.3294 $ and $ 1.3294 / 2 = 66.47_G $
$ B_1 + B_2 = 0.5478 $ and $ 0.5478 / 2 = 27.39_B $
To display on an sRGB monitor, the sRGB gamma needs to be applied. The spreadsheet math to encode the sRGB curve is (only red in cell B3 shown):
=IF( B2 <= 0.0031308 ; B2 * 12.92 ; (POWER(B2 ; (1/2.4)) * 1.055) - 0.055 )
If you want to use the "simple sRGB" curve instead, which is widely done when accuracy is less important than performance, then just raise each channel to the power of 0.455:
$ 0.5^{0.455} = 0.735_R´ $ which rounds to 8bit 188 or #BC
$ 66.47^{0.455} = 0.835_G´ $ which rounds to 8bit 213 or #D5
$ 27.39^{0.455} = 0.560_B´ $ which rounds to 8bit 143 or #8F
Thus, equal quantities of #FFFE00 and #009CC3 results in #BCD58F when using linearized math. This should accurately model the real-world behavior of light.
When To Use Linear
Linear light math is great for doing compositing operations, such as overlying images, adding light effects like glows, blurs, simulating real environments, etc. When I originally wrote this post, that's what I had in mind.
But there are things it is better to do in a perceptually encoded space.
NON-LINEAR and PERCEPTUALLY UNIFORM
If instead you used the sRGB encoded values (or some perceptually encoded values) and averaged them without going to linear first, the resultant color would be #80CD62 — substantially different from the linear result of #BCD58F. Which is better? Depends on your application! But let's talk GRADIENTS.
Here are some examples of four gradients. All the gradients were created by averaging the middle color with the start and end color, and then averaging the color between the middle color and either the start or end, etc.
- The left most gradient was just done directly to sRGB value without
going to linear.
- Second from the left, the start and end values were
linearized first, then averaged, then re-encoded with the sRGB gamma.
- The next, darker gradient, the values were linearized then averaged,
but never re-gamma encoded - i.e. that's what a linear value looks
like when you send it to the monitor without applying inverse gamma.
- And the right gradient was "done" in L* (CIELAB perceptual lightness)
the values were first linearized from sRGB, then encoded with the L*
curve, then averaged, then linearized FROM L* to Y, and finally
re-encoded with sRGB for display.]
Here we'll go around the color hitting opponent colors (180° opposite)



While I'm not going to get into opponent vision theory, I'll just mention that we can't see blue and yellow at the same time in the same location, nor red and green. And look at the gradients: smack in the middle is a neutral middle grey.
That's also what is directly between blue and yellow in CIELAB: neutral grey. CIELAB is partly based on color opponents.
These gradients weren't made with CIELAB math (except the one on the right which uses the L* part of L*a*b*
)

And finally a set of gradients from adjacent "primaries", these three sets basically define the limits of a a computer monitor, at least at the primaries.
BUT ALSO: again, looking at the middle row, notice that the sRGB & L* pretty much are a "straight line" between each primary, and notice the Y and L for each patch: the luminance or lightness DECREASES in between for the sRGB and L* versions of the gradient, and the linear second from the left is actually closer to what we'd want to see, with Y or L* increasing more in the middle, especially for the red to green gradient - the linear version gives us the nice oranges.



And herein lies one of the problems with using simple math to blend colors — results degrade and become less accurate when color channels are closeer to or at 0.
So, as it turns out there are a number of ways to mix and predict colors, and some are more and some are less accurate or useful, depending on the specific application and purpose.
MULTI COLORS
But what about multiple colors, multiple size stimuli, and different distributions? As I hope the simple demonstration above shows, you can use fairly simple math fo some tasks.
Related: The Wikipedia page on CIEXYZ has useful math for mixing multiple colors in CIE xyY colorspace: CIEXYZ and Mixing Math for xyY xyY is a linear colorspace derived from XYZ.
Still, if you are modeling light then: If you have four colors and you want to weight each one differently, such as 31% for color $C_1$, 35% for $C_2$, 15% for $C_3$, and 19% for $C_4$, then using linear RGB values:
$ RGB_1 * 0.31 + RGB_2 * 0.35 + RGB_3 * 0.15 + RGB_3 * 0.19 = RGB_{result} $
And of course, apply the sRGB transfer curve back to $ RGB_{result} $
BUT WAIT THERE'S MORE
There are other, more complex maths for working with non-linear and perceptually uniform spaces. In which case we really need to know the motivation/need and application/desired results.
CIELAB is perceptually uniform and most used as a color difference model, that is, "how much does color sample A vary from color sample B?" This has much utility in industry for determining color variations from different production runs or different manufacturing facilities for instance.