This is possible using GL 1.x and here's how.
So as you've found using vertex colors, a smooth transition is where it blends the two colors. This is a called a linear interpolation, or a "lerp" for short. It can be generalized to any dimension by operating on the elements of the vector individually and indeed colors are treated like a lerp in 3D -- blend R1 with R2, G1 with G2, B1 with B2.
The lerp() function has an "alpha" parameter, such that alpha = 0.0 yields fully color 1 and alpha of 1.0 yields fully color 2, and somewhere in-between creates a mixture. So you'll see then that if you have color 1 (C1) and color 2 (C2) and some alpha value (A), then would do it as: lerp(C1,C2,A) = A*C1 + (1.0-A)*C2
. As many people will tell you, you can simplify this formula, but keeping it as is will help you understand how to do this with GL 1.x.
To do this with two textures using GL 1.x, you will be drawing two rectangles on top of each other, one with texture 1, one with texture 2. However, you will be adding the two colors. If you do this as-is you'll end up with a final texture that looks like
final = C1 + C2
If you look at the lerp() function, you'll see that we're missing the multiplication by A
and 1.0-A
. So to do this, we're going to using colors.
In OpenGL 1.x, the default way that colors and textures are combined is like so:
C' = Ccolor * Ctexel
This is done by glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_TEXTURE_ENV_MODE)
. Again, this is the default mode, so you shouldn't need to do this.
If we specify a color of { 1, 1, 1, 1} (pure white) on side of the rectangle in the vertex data, and then { 1, 1, , 0} (transparent) on the other side, the colors will be smoothly interpolated by OpenGL as you've already noticed. Generalize that to alpha, which isn't "visible" per se, but can be used in graphics techniques such as this. So in effect, you'll end up with the alpha value of the color varying from 0..1 smoothly as desired. Now we have to use this value. Simply having the alpha value varying across the rectangle doesn't do anything, because alpha itself is not visible like red, green, or blue. So we have to somehow multiply this alpha value with each color.
Enter blending. Blending in the GL 1.x fixed function does just that. It takes the incoming pixel (call the source) and blends it with the destination pixel (i.e. what is already in the framebuffer) by some function, so you can look at mathematically as: Cblended = blend(Csrc, Cdest)
First, you must enable it: glEnable(GL_BLEND)
.
Then, you must give it the function glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
for the first rectangle.
The first parameter to glBlendFunc()
is what gets multiplied with the source color. We're saying the alpha value of the color. The second parameter is what is multiplied with whatever is already in the framebuffer. We're saying 1.0-alpha. This effectively means we're doing a lerp().
When drawing the second rectangle, you must give it the function glBlendFunc(GL_SRC_ALPHA, GL_ONE)
. This preserves the previously calculated value (GL_ONE meaning multiply old value by 1.0) and then blends the incoming (new rectangle) value by its alpha, performing the lerp().
Let's go other all of this, mostly so you can appreciate shaders.
- Enable blending, possibly set up texture environment.
- Set up the blending function
- Draw rectangle 1 with left vertices having alpha of 1, right side alpha of 0
- Switch blend function to GL_SRC_ALPHA / GL_ONE (thanks Trevor)
- Draw rectangle 2 with right vertices having alpha of 1, left side alpha of 0
- Turn off blending and do other stuff.
This works because:
- When you specify vertex colors, the alpha value is smoothly interpolated across the rectangle.
- Using blending, we can multiply the color by that alpha value
- Since we swap 1.0/0.0 alpha values depending on which rectangle we're drawing, for each pixel where alpha is some value
K
for rectangle 1, it will be 1-K
for rectangle 2.
glBegin
and multi-texturing or shaders. \$\endgroup\$