Gettin depth value's from glReadPixels

Started by Mattbooth, March 07, 2005, 20:53:45

Previous topic - Next topic

Mattbooth

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 :)

princec

Ahem... need to post your error message again ;)

Cas :)

Mattbooth

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 ;)

napier

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.
penGL/Java/LWJGL demos and code: http://potatoland.org/code/gl

Mattbooth

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 :)

....

tomb

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.

Mattbooth

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

tomb

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?

Mattbooth

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

tomb

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);

Mattbooth

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 :)

tomb

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!

Mattbooth

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?

tomb

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.

Mattbooth

Thanks for your help mate :)

patience is a virtue as they say :D