LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: Mattbooth on March 07, 2005, 20:53:45

Title: Gettin depth value's from glReadPixels
Post by: Mattbooth on March 07, 2005, 20:53:45
Hi guys

using the following simple code to get the depth value from glReadPixels, well it doesnt work and the program crashs with the following error

Code
IntBuffer zdepth = ByteBuffer.allocateDirect(1*4).order(ByteOrder.nativeOrder()).asIntBuffer();
       GL11.glReadPixels(x, y, width, height, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, zdepth);
       float z = (float)zdepth.get(0);
       System.out.println(z);


Error
QuoteIntBuffer zdepth = ByteBuffer.allocateDirect(1*4).order(ByteOrder.nativeOrder()).asIntBuffer();
       GL11.glReadPixels(x, y, width, height, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, zdepth);
       float z = (float)zdepth.get(0);
       System.out.println(z);

Any tutorials in the get depth or a pointer in the right direction appreciated :)
Title: Gettin depth value's from glReadPixels
Post by: princec on March 07, 2005, 21:07:45
Ahem... need to post your error message again ;)

Cas :)
Title: Gettin depth value's from glReadPixels
Post by: Mattbooth on March 07, 2005, 21:08:54
DOH lol

QuoteAn unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION (0xc0000005) occurred at PC=0x691303C3
Function=[Unknown.]
Library=C:\WINDOWS\system32\atioglxx.dll

NOTE: We are unable to locate the function name symbol for the error
     just occurred. Please refer to release documentation for possible
     reason and solutions.

there is a lot more but thats most of the readable works ;)
Title: Gettin depth value's from glReadPixels
Post by: napier on March 07, 2005, 21:14:06
I don't think you want an IntBuffer there.   This code works for me:

public static final int SIZE_FLOAT = 4;
public static final int SIZE_BYTE = 1;

public static ByteBuffer allocBytes(int howmany) {
  return ByteBuffer.allocateDirect(howmany * SIZE_BYTE).order(ByteOrder.nativeOrder());
}

public static float getZDepth(int x, int y)
{
  ByteBuffer zdepth = allocBytes(SIZE_FLOAT);
  GL11.glReadPixels(x, y, 1, 1, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, zdepth);
  return ( (float) (zdepth.getFloat(0)));
}


It gets Z depth at one pixel at the given x,y screen position.
Title: Gettin depth value's from glReadPixels
Post by: Mattbooth on March 07, 2005, 21:33:40
Okay that code does work, but only when the width and height are set to 1, and the getFloat() is 0;

same error i think

QuoteAn unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION (0xc0000005) occurred at PC=0x7C911C48
Function=[Unknown.]
Library=C:\WINDOWS\system32\ntdll.dll

NOTE: We are unable to locate the function name symbol for the error
     just occurred. Please refer to release documentation for possible
     reason and solutions.

rather strange, ideally like when gettin the RGB which i have no probs with, i would like to get the width and height of the full window :)

....
Title: Gettin depth value's from glReadPixels
Post by: tomb on March 07, 2005, 22:26:54
The buffer zdepth has to be big enough to hold all the data. In your first code example you create a buffer to hold one float, but you pass in "width" and "height". If width or height is greater than 1 the function will try to write outside the array and you get a access violation. Create a ByteBuffer that is atleast 4*width*height large. In addition there might be padding issues. Try looking up pixel store (or something similar). But you probably know about this if you have used readPixels to get rgb.
Title: Gettin depth value's from glReadPixels
Post by: Mattbooth on March 07, 2005, 23:30:29
Jeez its been a long day

Yep extended the size of the buffer and it works fine now.

However when cycling through the buffer i now get an out of bounds exception, the max is set to 4*width*height.

Is there an explaination anywhere of interpreting hte buffer readings, i know hte reading are bound to [1 / 0].  So i assume 1.0 is there is no object in the buffer, and any other value is a distance away?

Cheers
Title: Gettin depth value's from glReadPixels
Post by: tomb on March 08, 2005, 01:26:43
Quote from: "Mattbooth"Jeez its been a long day
However when cycling through the buffer i now get an out of bounds exception, the max is set to 4*width*height.
So you are reading outside the buffer? Hmmm, well... don't read outside it then :D Seriously, you have to post some code, or I can only guess what you are doing wrong.

Quote from: "Mattbooth"
Is there an explaination anywhere of interpreting hte buffer readings, i know hte reading are bound to [1 / 0].  So i assume 1.0 is there is no object in the buffer, and any other value is a distance away?
0/1 is the normalized value between the front and back clipping plane. However I'm not competely sure if it is a the linear depth value that is store or if there is 1/w or something. Does the opengl docs say anything?
Title: Gettin depth value's from glReadPixels
Post by: Mattbooth on March 08, 2005, 10:23:12
righty ho

code variables
int SIZE_FLOAT = width * height;
   static final int SIZE_BYTE = 3;
   int arraySize = SIZE_FLOAT * SIZE_BYTE;
   int length = width * height * 4;
   private int width = displayMode.getWidth();
   private int height = displayMode.getHeight();

Method detail

int firstElement = length;
       int bufferIndex;
       int bufferArrayIndex = 0;
       int bytesPerRow = width * 4;
               
   ByteBuffer zdepth = allocBytes(SIZE_FLOAT);
   GL11.glReadPixels(x, y, width, height, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, zdepth);
   
   float [][]depthArray = new float [width][height];

   for (int row = 0; row< height; row++) {
           
           // I assume these are here because OpenGL reads data in from the screen upside-down
           firstElement -= bytesPerRow;
           bufferIndex = firstElement;
           
           for(int column = 0; column <width; column ++){
               
               depthArray[column][row] = zdepth.getFloat(bufferIndex ++);
               
           }
   }


All the info i can get about the depth reading is
Quote
Depth values are read from the depth buffer. Each component is converted to floating point such that the minimum depth value maps to 0 and the maximum value maps to 1. Each component is then multiplied by GL_DEPTH_SCALE, added to GL_DEPTH_BIAS, and finally clamped to the range [0,1].

And the red book doesnt have any info on these...

Tar
Title: Gettin depth value's from glReadPixels
Post by: tomb on March 08, 2005, 14:14:46
SIZE_FLOAT should be 4
SIZE_BYTE should be 1 (if it is used)
arraySize should be width * height
length should be arraySize * SIZE_FLOAT

zdepth should be crated like this:
ByteBuffer zdepth = allocBytes(length);
Title: Gettin depth value's from glReadPixels
Post by: Mattbooth on March 08, 2005, 14:32:43
Yep that work now mate thanks :)

Any idea on the interpretation of the z depth?  I've set a simple for loop to cycle through the array and return the smallest value it can fine.


float x1 = 1.0f;
    for (int row = 0; row< height; row++) {
        for(int column = 0; column <width; column ++){
               
               float cur = depthArray[column][row];
               if (cur == 1.0);
               else if( cur < x1){
               x1 = cur;
               }
           }
   }
    System.out.println(x1);


now this returns      -8.8E-44

and at a camera angel -10 is also return -8.8E-44

either its reading it wrong or some other adaptation need to be done to the buffer reading to get the actual value....

nothing is ever simple is it..

any other ideas greatly appreciated :)
Title: Gettin depth value's from glReadPixels
Post by: tomb on March 08, 2005, 15:47:00
Something is wrong because as it says all values is in the range [0,1]. Have you looked at pixelStore? Try adding this before reading the pixels:

// set pixel packing
GL11.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, 0);
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
GL11.glPixelStorei(GL11.GL_PACK_SKIP_ROWS, 0);
GL11.glPixelStorei(GL11.GL_PACK_SKIP_PIXELS, 0);

It's possible it insert a byte or two between the rows that messes with the getFloat offset.

If that don't work you need to setup some debuging frame work. I would create an image from the depth values that you read. Display it in a awt frame and see what is going on. Setup the near and far clipping plane so that you can just fit a rotating cube. Clamp the zvalues read to [0, 1]. Good luck!
Title: Gettin depth value's from glReadPixels
Post by: Mattbooth on March 09, 2005, 00:52:29
that last bit was over my head mate  :roll:

i've got rid of the offsets and the reading come out at -1.0002978 for every value at any distance....

any quick fix?
Title: Gettin depth value's from glReadPixels
Post by: tomb on March 09, 2005, 01:14:20
I'm out of idees, so you are on your own. If I were in your situation I would first go over the code a couple of times. Check the javadocs and opengl docs to make sure there is no stupid mistakes. Then I would start  messing around. I would look at the output, literaly. That was why I suggested you create an image of the z values read. To see the output. Then I would change the input, wich would include:
-render overlapping objects to make sure I have actually enabled the depth buffer, and that it is working on screen
-render different scenes to see if outputs changes
-mess with th near and far clipping planes
-mess with the variables related the this particular readPixels mentioned in the gl man pages
-etc,etc

Basicly gather as much information about the problem as possible. Then speculate what is wrong and what to do to fix it. In other words I would debug.
Title: Gettin depth value's from glReadPixels
Post by: Mattbooth on March 09, 2005, 09:15:37
Thanks for your help mate :)

patience is a virtue as they say :D