Blending of paint colours - Algorithm Required


This is really a general rather than OpenGL question I suppose, but I’m sure someone here can help me.

What I’m trying to do is blend colours in my application in the same way that real paints do. So, for example Blue(RGB=0,0,1) blends with Yellow(RGB=1,1,0) to make Green(RGB=0,1,0). At the moment the OpenGL blending that I’m using gives white(RGB=1,1,1) when blending blue and yellow.

Is there a blending mode in OpenGL that I can use to achieve ‘paint’ blending? Otherwise, does anyone know an algorithm for this so that I can do it the hard way?

Many thanks


Colour mixing should work similarly to the CMY colour model, which is simply (1,1,1)-(R,G,B). In this model, it’s not actually blue and yellow that give green, but cyan and yellow. Cyan = RGB(0,1,1) = CMY(1,0,0) and yellow = RGB(1,1,0) = CMY(0,0,1). Green = CMY(cyan+yellow) = CMY(1,0,1) = RGB(0,1,0).

Doing the math for the conversions in the general case, all this results in a very simple formula: the “mixture” of (r1,g1,b1) and (r2,g2,b2) is (r1+r2-1, g1+g2-1, b1+b2-1). That is, you only have to subtract 1 to get the right colour.

Two things to note: 1. Pure blue and yellow give black in this model (which could be a good approximation to real life, as you never really use pure blue and yellow); 2. I haven’t given clamping enough thought.

I just wanted to add that the reason for this is that CMY is subtractive (like paint) and RGB is additive (like light). Color spaces really is a very interesting topic, the way you represent colors really makes a difference, usability, compression and interpolation are just a few that come to mind. If you have “Computer Graphics: Principles and Practice.”, read the chapter on colour, it has really good coverage on these kind of things.

On monitors and TV’s we use additive color, where we start with a black surface (your monitor) and add color to it (R,G, and B, in correct quantities) until we get the desired color. So adding red & green to black gets us yellow.

For most other things in the world (including all paints & inks) we use subtractive color. In this case, we start out with white light reflecting off of a surface (so the surface should be white). However, pigments in the material (and/or in the paint applied to the surface) absorb some of the components of this white light. Whatever proportions of the light components (RGB) that arent absorbed are reflects, and that determines the color that we perceive the surface to be. So a white light emits RGB(1,1,1), and a red object contains pigments that absorb RGB(0,1,1) (ie: Green and Blue), and the reflected color we see is…
White - (Green + Blue) =
White - Green - Blue =
RGB(1,1,1) - RGB(0,1,0) - RGB(0,0,1) =
RGB(1-0-0, 1-1-0, 1-0-1) =
RGB(1,0,0) =

Thus to clarify ET3D’s formula
(r1+r2-1, g1+g2-1, b1+b2-1)
isnt exactly correct. It should be
(1-r1-r2, 1-g1-g2, 1-b1-b2)

And on another note, as additive color saturates to white, subtactive color saturates to black (because you cant remove more light than was originally)

[This message has been edited by LordKronos (edited 05-09-2001).]

Thanks for your help guys, I’m going to give this a go. I’m a bit worried about pure yellow and blue making black, I guess if the results are OK for most colours then I can put a fiddle factor in somewhere to take account of the results I don’t like.

I’ll post what I did once I’ve messed about with it.


LordKronos, you “fixed” my correct formula with an error

First the example (that I gave before): cyan - RGB(0,1,1), and yellow - RGB(1,1,0) give:

In my forumla: (0+1-1, 1+1-1, 1+0-1) = (0,1,0) = green
In your forumla: (1-0-1, 1-1-1, 1-0-1) = (0,-1,0) = (0,0,0) (when clamped)

The proof:

RGB(r1,g1,b1) and RGB(r2,g2,b2) are CMY(1-r1,1-g1,1-b1) and CMY(1-r2,1-g2,1-b2).

The mixture of these two colours is their addition in CMY, which is (2-r1-r2,2-g1-g2,2-b1-b2). Converting back to RGB gives (1-(2-r1-r2),1-(2-g1-g2),1-(2-b1-b2)) = (r1+r2-1,g1+g2-1,b1+b2-1).

Your example is wrong, because mixing green and blue never gives red. It should give black (as green absorbs RGB(1,0,1) and blue absorbs RGB(1,1,0), and therefore all components are absorbed). In my case, it will give

(0+0-1, 0+1-1, 1+0-1) = (-1,0,0) = (0,0,0) (when clamped), which is the correct answer.

Actually, I wasnt really wrong, just speaking differently. If you read my message agian, you will see that I was talking in terms of colors absorbed, whereas you were talking in terms of colors reflected. Thats why I thought your formula was incorrect…I was looking at it the opposite way.

So we were both right. With my method, mixing green and red would mean starting with RGB(1,1,1), green absorbs RGB(1,0,1), and blue absorbs RGB(1,1,0), resulting in RGB(1-1-1, 1-0-1, 1-1-0) = RGB(-1,0,0) which saturates to RGB(0,0,0) which is the same as you got.

Ah, right, I see now. You simply didn’t answer the question