Stencil Buffer - long code clip

Started by psiegel, June 11, 2003, 14:53:33

Previous topic - Next topic

psiegel

Has anyone had any luck using the stencil buffer in LWJGL?  I've tried whipping up a sample using NeHe's tutorials and my red book, but it just doesn't seem to work.  In the code below, I'm drawing a simple spinning colored cube.  I create my stencil buffer by drawing a small plane in front of the cube.  I expect my cube to have its edges cut to the area of the little plane.  But instead, I always see the full cube.  

Oh, and this code is based on the examples that come with LWJGL, so  the class it extends (BaseWindow) is defined there.   Can anyone spot what's wrong with this code?

public class StencilTest extends BaseWindow {
  private float xrot;
  private float yrot;
  private float zrot;
  
  //* Creates a new instance of Lesson 
  public StencilTest() { 
  }
  
  protected void initGL() throws Exception {
    try {  
      gl.enable(GL.STENCIL_TEST);
      gl.clearStencil(0);

      // Call parent to finish setting up GL 
      super.initGL();
    }
    catch (Exception e) {
      throw new Exception("Problem initialising GL", e);
    }
  }
  
  protected boolean drawGLScene(float frameTime) {
    // Clear The Screen And The Depth Buffer 
    gl.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT | GL.STENCIL_BUFFER_BIT);
    
    // Reset The Current Modelview Matrix 
    gl.loadIdentity();

    //  Build the stencil
    buildStencil();
    
    drawCube();
        
    // rotate 15pps on the X Axis 
    xrot += frameTime * 30f ;
    // rotate 20pps on the Y Axis 
    yrot += frameTime * 20f;
    // rotate 10pps on the Z Axis 
    zrot += frameTime * 40f;
    
    return true;
  }
  
  public void drawCube() {
    gl.pushMatrix();
    
    gl.translatef(0.0f,0.0f,-5.0f);
    gl.rotatef(xrot,1.0f,0.0f,0.0f);
    gl.rotatef(yrot,0.0f,1.0f,0.0f);
    gl.rotatef(zrot,0.0f,0.0f,1.0f);

    gl.begin(GL.QUADS);

    // Front Face 
    gl.color4f(0.0f, 0.0f, 1.0f, 1.0f);
    //  Bottom Left
    gl.vertex3f(-1.0f, -1.0f,  1.0f);
    // Bottom Right  
    gl.vertex3f( 1.0f, -1.0f,  1.0f);
    // Top Right  
    gl.vertex3f( 1.0f,  1.0f,  1.0f);
    // Top Left  
    gl.vertex3f(-1.0f,  1.0f,  1.0f);
    
    // Back Face 
    gl.color4f(0.0f, 1.0f, 0.0f, 1.0f);
    // Bottom Right  
    gl.vertex3f(-1.0f, -1.0f, -1.0f);
    // Top Right  
    gl.vertex3f(-1.0f,  1.0f, -1.0f);
    // Top Left  
    gl.vertex3f( 1.0f,  1.0f, -1.0f);
    // Bottom Left  
    gl.vertex3f( 1.0f, -1.0f, -1.0f);
    
    // Top Face 
    // Top Left  
    gl.vertex3f(-1.0f,  1.0f, -1.0f);
    // Bottom Left  
    gl.vertex3f(-1.0f,  1.0f,  1.0f);
    // Bottom Right  
    gl.vertex3f( 1.0f,  1.0f,  1.0f);
    // Top Right  
    gl.vertex3f( 1.0f,  1.0f, -1.0f);
    
    // Bottom Face 
    gl.color4f(1.0f, 0.0f, 0.0f, 1.0f);
    // Top Right  
    gl.vertex3f(-1.0f, -1.0f, -1.0f);
    // Top Left  
    gl.vertex3f( 1.0f, -1.0f, -1.0f);
    // Bottom Left  
    gl.vertex3f( 1.0f, -1.0f,  1.0f);
    // Bottom Right  
    gl.vertex3f(-1.0f, -1.0f,  1.0f);
    
    // Right face 
    gl.color4f(1.0f, 1.0f, 0.0f, 1.0f);
    // Bottom Right  
    gl.vertex3f( 1.0f, -1.0f, -1.0f);
    // Top Right  
    gl.vertex3f( 1.0f,  1.0f, -1.0f);
    // Top Left  
    gl.vertex3f( 1.0f,  1.0f,  1.0f);
    // Bottom Left  
    gl.vertex3f( 1.0f, -1.0f,  1.0f);
    
    // Left Face 
    gl.color4f(1.0f, 0.0f, 1.0f, 1.0f);
    // Bottom Left  
    gl.vertex3f(-1.0f, -1.0f, -1.0f);
    // Bottom Right  
    gl.vertex3f(-1.0f, -1.0f,  1.0f);
    // Top Right  
    gl.vertex3f(-1.0f,  1.0f,  1.0f);
    // Top Left  
    gl.vertex3f(-1.0f,  1.0f, -1.0f);
    gl.end();

    gl.popMatrix();
  }
  
  public void buildStencil() {

    // Set our stencil func and op to fill up the buffer
    gl.stencilFunc(GL.ALWAYS, 1, 1);
    gl.stencilOp(GL.REPLACE, GL.REPLACE, GL.REPLACE);

    //  Disable color and depth, so we don't actually draw to the screen.
    gl.colorMask(false, false, false, false);
    gl.disable(GL.DEPTH_TEST);
    
    //  Draw the stencil object
    gl.pushMatrix();
    gl.color4f(1.0f, 1.0f, 1.0f,  1.0f);
    gl.translatef(0.0f,0.0f,-3.0f);

    gl.begin(GL.QUADS);
    // Bottom Left  
    gl.texCoord2f(0.0f, 0.0f); gl.vertex3f(-0.5f, -0.5f,  0.0f);
    // Bottom Right  
    gl.texCoord2f(1.0f, 0.0f); gl.vertex3f( 0.5f, -0.5f,  0.0f);
    // Top Right  
    gl.texCoord2f(1.0f, 1.0f); gl.vertex3f( 0.5f,  0.5f,  0.0f);
    // Top Left  
    gl.texCoord2f(0.0f, 1.0f); gl.vertex3f(-0.5f,  0.5f,  0.0f);
    gl.end();
    gl.popMatrix();
    
    //  Re-enable depth and color
    gl.enable(GL.DEPTH_TEST);
    gl.colorMask(true, true, true, true);

    //  Set the stencil func and op and use the buffer but not overwrite it.
    gl.stencilFunc(GL.EQUAL, 1, 1);
    gl.stencilOp(GL.KEEP, GL.KEEP, GL.KEEP);
  }
  
  public static void main(String[] arguments) {
    int err = 0;
    StencilTest test = new StencilTest();
    try {
      test.start(640, 480, 16, false);
    }
    catch (Exception e) {
      err = 1;
      e.printStackTrace();
    }
    System.exit(err);
  }
}


Paul

elias

I'm not at home right now, but I would take a look at BaseWindow.java and see if it isn't specifying 0 for stencil depth.

- elias

psiegel

BaseWindow mentions nothing about stencil anything.  However, I'm curious what this "stencil depth" is.  I don't see it mentioned in NeHe's tutorial or my red book.  Perhaps this is something I need to set somewhere?

cfmdobbie

The size of the stencil buffer will be passed into the GL constructor.

Nope, it's nothing to do with OpenGL, merely the context in which OpenGL renders - it's a windowing-system feature.  Redbook won't tell you anything about it - take a look at the Javadoc for GL.java.
ellomynameis Charlie Dobbie.

psiegel

Ah, excellent.  I changed the last parameter in the GL constructor from 0 to 1 and it works.  While I am pleased to know this, it does lead to some more questions:

What are the last three parameters in the GL constructor?  I know they are named depth, alpha, and stencil, but I have no idea what they represent.  Is 1 the correct value to be passing here?  It works in this example, but would I ever want to pass a value that's neither 0 nor 1?

What happens if I call the GL constructor with a value of 1 for stencil and the hardware doesn't support a stencil buffer?  Does it throw an exception?  Does it simply ignore it?  If so, is there a way I can query whether the hardware does support the stencil buffer?

Thanks for all the help guys!

Paul

[Edit]: Spelling and grammar were just too horrible to not edit.

cfmdobbie

Those three are the sizes of the depth, alpha and stencil buffers in bits.

You'll want to use a depth buffer when you want to start Z-buffering your objects.  If you give it a depth buffer and perform the right incantations, OpenGL will draw your objects so that nearer ones aren't obscured by farther ones.  The alpha buffer is pretty exotic - it's to allow an alpha component on the rendering surface (i.e. the window).  Not that not having an alpha buffer doesn't affect being able to perform alpha blending!  The stencil buffer you know about!

If you only want a 1-bit stencil buffer, passing 1 is great.  For a depth buffer 1 bit would be next to useless; most people would use an 8- or a 16-bit depth buffer.

The OpenGL drivers are allowed to provide any GL context that at least meets your requirements - it may give you more than you ask for but never less.  If you ask for 1 bit of stencil and the hardware doesn't support it, you'll get an exception.

You should be able to query current settings via the Display class, or there are methods to do so in OpenGL as well (glGetIntegerv etc).
ellomynameis Charlie Dobbie.

princec

Actually the gl driver is allowed to give you a bit less but we reckoned that was crap and enforce the minimums that you ask for for consistency between platforms and drivers. Works a treat.

Cas :)

cfmdobbie

Quote from: "princec"Actually the gl driver is allowed to give you a bit less but we reckoned that was crap and enforce the minimums that you ask for for consistency between platforms and drivers. Works a treat.

Fascinating - I never realised that!  I've learned something new - I'm off to bed.  G'night! :wink:
ellomynameis Charlie Dobbie.

psiegel

Does anyone have any stats on what buffers are supported by what hardware?  Is it safe to just use the stencil buffer, or does it only work on the latest of graphics cards?  What about auxiliary color buffers?

cfmdobbie

A good question, and a hard one to get an answer to.  I'd just like to point out that (a) I rock, and (b) the Web is my bitch.

Take a look at this page:

http://web.archive.org/web/20020211010329/http://www.reactorcritical.com/chips/summary-full.shtml

That should give you a good start!
ellomynameis Charlie Dobbie.

princec

Stencil and alpha are supported on TNT class cards and above, albeit slowly, and with some caveats. Auxiliary buffers aren't supporte on general hardware at all, only on stuff like 3dlabs Wildcats.

Cas :)

psiegel

Charlie, you rock.  The web is your bitch.

Thanks a lot!

Paul