Blending

We start with no blending. We draw 2 quads, a red one with a corner at 0,0,0 and a blue one 0.5 further 'back' . We see:

1

The camera is at 0,0,5. The blue quad is partially obscured by the red quad, even though we draw the blue quad after:

gl.glLoadIdentity();// Reset The View
glu.gluLookAt(..
redQuad(gl);
blueQuad(gl);

This is because we have depth testing enabled. If we comment that out in init:

        //gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glClearDepth(1.0f);                      // Depth Buffer Setup
        gl.glDepthFunc(GL.GL_LEQUAL);
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);

We see:

2

Blending - translucent surface

We need to have depth test off, enable blending, and use glBlendFunc to control how fragments and pixels are blended (blent?).

The Red Book describes how glBendFunc works. You have 2 factors which multiply the source pixel (the new one) with the destination pixel (what has already been drawn). Each factor has RGBA parts. The results are added together to give the final pixel. In other words you get

source factor X source pixel + dest factor X dest pixel

where each factor and pixel has RGBA parts. If any part is over 1, it is clamped to 1.

For example, this in display..

glu.gluLookAt(..
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
redQuad(gl);
blueQuad(gl);

where the quads are drawn by

private void redQuad(GL gl) {
        gl.glBegin(GL.GL_QUADS);
        gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
        gl.glVertex3d(0, 0, 0);
        gl.glVertex3d(0, 1, 0);
        gl.glVertex3d(1, 1, 0);
        gl.glVertex3d(1, 0, 0);
        gl.glEnd();
    }

    private void blueQuad(GL gl) {
        gl.glBegin(GL.GL_QUADS);
        gl.glColor4f(0.0f, 0.0f, 1.0f, 0.6f);
        gl.glVertex3d(0.5, 0.5, -1);
        gl.glVertex3d(0.5, 1.5, -1);
        gl.glVertex3d(1.5, 1.5, -1);
        gl.glVertex3d(1.5, 0.5, -1);
        gl.glEnd();
    }

produces 3
The red quad has alpha 1. So when we draw it over the black background,

gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

means in effect that we get

1 X red + (1-1) X black

in other words all red. But the blue has alpha of 0.6, so for this we get

0.6 X blue + (1-0.6) X red

where the blue and red overlap similarly for the blue on black.

If we draw the blue first, we get

4

The blue mixes 0.6 with the black, but the red with an alpha of 1 completely replaces the blue and black.

Drawing arbitrary opaque and translucent images

The last example suggests we have a problem drawing translucent images - we have to draw them after the opaque ones. But a distant transulcent object would appear on top of a near opaque one, if depth testing is off.

The Red Book tells you how to do it:

1. Enable depth testing

2. Draw all opaque objects

3. Make the depth buffer read only (but depth testing still enabled)

4. Enable blending

5. Draw the translucent objects

If we try to draw a translucent object more distant than an opaque one, the frozen depth buffer will hide it. If it is nearer, it will still be drawn, and blent to appear translucent.

To show this, we could draw quads at random positions. It is useful to have a RedQuad class:

class RedQuad {
    private double x,y,z;
     
        public RedQuad()
        {  // make one with random positions      
        x=-5 + Math.random() * 10;
        y = -5 + Math.random() * 10;
        z = -Math.random() * 10;
    }

    public void draw(GL gl) {
        gl.glBegin(GL.GL_QUADS); // draw one
        gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
        gl.glVertex3d(x, y, z);
        gl.glVertex3d(x, y + 1, z);
        gl.glVertex3d(x + 1, y + 1, z);
        gl.glVertex3d(x + 1, y, z);
        gl.glEnd();
    }
}

and the BlueQuad class is the same, except that it is blue and has an alpha of 0.5. Then we declare vectors of these:

    
private Vector<RedQuad> redQuads = new Vector<RedQuad>();
private Vector<BlueQuad> blueQuads = new Vector<BlueQuad>();

Make them in init:

for (int i = 0; i < 20; i++) {
            redQuads.add(new RedQuad());
            blueQuads.add(new BlueQuad());
        }

and draw them like this

 glu.gluLookAt(.. 
 gl.glEnable(GL.GL_DEPTH_TEST);
 for (int i = 0; i < redQuads.size(); i++) {
            redQuads.elementAt(i).draw(gl);
        }
// make depth buffer read-only
gl.glDepthMask(false); // not GL.GL_FALSE); - Java has boolean type, unlike old C

gl.glEnable(GL.GL_BLEND); // blending on
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
for (int i = 0; i < blueQuads.size(); i++) {
            blueQuads.elementAt(i).draw(gl);
        }
gl.glDepthMask(true); // depth buffer read-write, for next time around

This produces..5