Can anyone help, cube sides not always transparent

Hi,

In the process of learning OpenGL I decided I would give myself a variation on some existing examples I have looked at (such as NeHe lesson 8). Running the code I see a rotating cube with transparent textures, except they aren’t always transparent or the faces at the back seem to be missing when looking through the transparency. I just can’t work out what is happening. Follows is the code:


public class CubeChase extends Panel implements GLEventListener, Runnable {

  GLU glu = new GLU();
  GLCanvas canvas;
  Cube cube;
  float x = 0.0f;
  
  private int[] textures = new int[3];          // Storage For 3 Textures
  
  private float[] lightAmbient = {0.5f, 0.5f, 0.5f, 1.0f};
  private float[] lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
  private float[] lightPosition = {0.0f, 0.0f, 0.0f, -6.0f};
  
  public CubeChase() {
    GLCapabilities capabilities = new GLCapabilities();
            
    canvas =
        GLDrawableFactory.getFactory().createGLCanvas(capabilities);
    
    canvas.addGLEventListener(this);    
    
    setLayout(new BorderLayout());
    add(canvas); 
    
    Point3D centerPoint = new Point3D(0,0,0);
    //create a cube around center point
    cube = new Cube(centerPoint,2.0);
    
  }
  

  private boolean loadGLTextures(GLAutoDrawable gldrawable) {
      TextureReader.Texture texture = null;
      try {
          texture = TextureReader.readTexture("data/glass.png");
      } catch (IOException e) {
          return false;
      }

      GL gl = gldrawable.getGL();
      
      //Create Nearest Filtered Texture
      gl.glGenTextures(3, textures,0); /* * */
      gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]);

      gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
      gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);

      gl.glTexImage2D(GL.GL_TEXTURE_2D,
              0,
              3,
              texture.getWidth(),
              texture.getHeight(),
              0,
              GL.GL_RGB,
              GL.GL_UNSIGNED_BYTE,
              texture.getPixels());          

      return true;
  }

  
  public void init(GLAutoDrawable drawable) {
    if (!loadGLTextures(drawable)) {
      System.out.println("Unable to load textures,Bailing!");
      System.exit(0);
    }
    
    GL gl = drawable.getGL();
    
    gl.glEnable(GL.GL_BLEND);
    gl.glDisable(GL.GL_DEPTH_TEST);
    gl.glEnable(GL.GL_LIGHTING);
    gl.glEnable(GL.GL_TEXTURE_2D);                          // Enable Texture Mapping
    gl.glShadeModel(GL.GL_SMOOTH);                            //Enables Smooth Color Shading
    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);               //This Will Clear The Background Color To Black
    gl.glClearDepth(1.0);                                  //Enables Clearing Of The Depth Buffer
    gl.glEnable(GL.GL_DEPTH_TEST);                            //Enables Depth Testing
    gl.glDepthFunc(GL.GL_LEQUAL);                             //The Type Of Depth Test To Do
    gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);  // Really Nice Perspective Calculations
    gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, lightAmbient,0);      // Setup The Ambient Light
    gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, lightDiffuse,0);      // Setup The Diffuse Light
    gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, lightPosition,0);    // Position The Light
    gl.glEnable(GL.GL_LIGHT1);                              // Enable Light One

    gl.glColor4f(1.0f, 1.0f, 1.0f, 0.5f);                   // Full Brightness.  50% Alpha (new )
    gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);                 // Set The Blending Function For Translucency (new )
    
  }

  
  public void display(GLAutoDrawable drawable) {

    GL gl = drawable.getGL();
    
    gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);            // Clear Screen And Depth Buffer
    gl.glLoadIdentity();           
    
    gl.glTranslatef(0.0f,0.0f,-5.0f);

    gl.glRotatef(x, 1.0f, 1.0f, 0.0f);
    
    gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]);
    
    Rectangle3D[] faces = cube.getFaces();
    for ( int i=0; i<faces.length; i++) {     
      gl.glBegin(GL.GL_QUADS);    
      
      Point3D p1 = faces[i].getP1();
      Point3D p2 = faces[i].getP2();
      Point3D p3 = faces[i].getP3();
      Point3D p4 = faces[i].getP4();
      
      Point3D normal = findNormal(p3,p1);
      
      gl.glNormal3d(normal.x,normal.y,normal.z);
      
      gl.glTexCoord2f(1.0f, 1.0f);
      gl.glVertex3d(p1.x,p1.y,p1.z);
      
      gl.glTexCoord2f(1.0f, 0.0f);
      gl.glVertex3d(p2.x,p2.y,p2.z);
      
      gl.glTexCoord2f(0.0f, 0.0f);
      gl.glVertex3d(p3.x,p3.y,p3.z);
      
      gl.glTexCoord2f(0.0f, 1.0f);
      gl.glVertex3d(p4.x,p4.y,p4.z);
      
      gl.glEnd();
    }
    
  }
  
  public static double dotProduct(Point3D p1, Point3D p2) {
    return (p1.x*p2.x)+(p1.y*p2.y)+(p1.y*p2.y); 
  }
  
  public static Point3D findNormal (Point3D p1, Point3D p2) {
    
    double x = (p1.y * p2.z) - (p2.y * p1.z);
    double y = (p1.z * p2.x) - (p2.z * p1.x);
    double z = (p1.x * p2.y) - (p2.x * p1.y);
    return new Point3D(x,y,z);
  }

  public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
    GL gl = drawable.getGL(); ; 
    
    if (height == 0) height = 1;
    gl.glViewport(0, 0, width, height);                       // Reset The Current Viewport And Perspective Transformation
    gl.glMatrixMode(GL.GL_PROJECTION);                           // Select The Projection Matrix
    gl.glLoadIdentity();                                      // Reset The Projection Matrix
    glu.gluPerspective(45.0f, width / (height*1.0f), 0.1f, 100.0f);  // Calculate The Aspect Ratio Of The Window
    gl.glMatrixMode(GL.GL_MODELVIEW);                            // Select The Modelview Matrix
    gl.glLoadIdentity();       
  }

  public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
    // TODO Auto-generated method stub
    
  }
  
  public void run () {
    while (true) {      
      try {
        Thread.sleep(5);
      } catch (InterruptedException e) {
      }
      x+=0.05f;    
      canvas.repaint(0);
    }
  }
  
  public static void main ( String[] args ) {
     CubeChase cubeChase = new CubeChase();
     
     Frame f = new Frame();
     f.add(cubeChase);
     f.setBounds(50,50,400,300);
     f.setVisible(true);
     (new Thread(cubeChase)).run();
  }  
  
}

When drawing with transparency, you need to sort transparent shapes back to front. If you draw a triangle that contains transparency which is infront of another shape, and that shape is drawn later, the second shape will not appear because it will fail the depth test.

Usually one will separate their scene objects into opaque and transparent. One will then render their opaque objects from front to back, and then the transparent objects from back to front (also known as the painter’s algorithm). Transparent objects need to be drawn back to front because semitransparent foreground pixels will cause any further pixels which are behind them to fail their depth test. On the other hand, opaque is drawn front to back because since the pixels are opaque there is no need to care about the appearance of pixels behind them, and when the distant sahpes are drawn, it is faster to throw away a pixel which fails the depth test than to overwrite an existing pixel with a pixel that is closer to the viewer.