[cairo] Colorized transparency
Hugues De Keyzer
hugues at depinxi.be
Fri Oct 20 08:53:29 PDT 2006
I'm new to cairo so I don't really know its features. I'm used to work with interactive computer graphics for my job (mainly OpenGL). I have a concern about color, opacity (or transparency) and blending.
In OpenGL, when a pixel is going to be drawn to the frame buffer at a particular position, it can be blended with the current color present in the frame buffer at that position. Blending is done through a configurable blending function that takes 2 factors, one for the source color (our new pixel), and one for the destination color (the current color in the frame buffer). Many factors are available, including GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA,... The most common factor combination is:
this results in the following computation:
final_color = source_color * source_alpha + dest_color * (1 - source_alpha)
This is the most common use of alpha blending. It is the "Normal" mode for Photoshop layers. It is a linear interpolation from the destination color to the source color based on the alpha value.
OK, now, what is the purpose of my message?
In OpenGL, a color can have only red, green, blue and alpha components. Why am I saying "only"? Because having alpha as a single value is very limitating.
In RenderMan, a surface has an opacity and a color. The color and the opacity have both the same type: color. They have the same number of components. In RGB color mode (RenderMan can use several color spaces), color and opacity are thus both defined as 3 values: red, green and blue.
The RenderMan Companion says (// indicates italic):
"Cs and Os represent the current surface color and opacity, respectively, as declared in RiColor() and RiOpacity() and bound to the surface being shaded when it was created.
Cs and Os are used as filter values. The color of reflected light from a surface with surface color Cs under incident light with color Cl is often taken to be Cl * Cs. In other words, each component of Cs scales the corresponding component of the incoming light according to the absorbtion of the surface. Os has the same effect on light passing /through/ the surface."
That is, the blending equation is:
final_color = source_color + destination_color * (1 - source_opacity)
With only this equation and a 3 component opacity, any type of useful blending can be done.
If we need the same result as the equation with one component opacity, we just need to set all opacity components to the same value and premultiply the color by the opacity.
If we want to add the colors together, just set opacity to (0, 0, 0).
If we want to multiply the colors together, just set source_color to (0, 0, 0) and source_opacity to 1 - source_color.
In OpenGL, such behavior can be done in 2 passes. First with (GL_ZERO, GL_ONE_MINUS_SRC_COLOR) with the color set to the opacity, then with (GL_ONE, GL_ONE) with the color set to the source color.
I don't know if we can define a 3 component opacity for cairo surfaces, but I think it should be really useful and should be the default way, not just an option. This would open the door for really high-quality rendering.
Having a one component opacity (alpha) is a limitation due to the early graphics cards that could blend pictures together (like the Truevision Targa). Why should we stay with such a limitation?
Hugues De Keyzer
More information about the cairo