0

I'm trying to implement DepthBuffer-like functionality using OpenGL ES on Android.

In other words I'm trying to get the 3D point on surface that is rendered on point [x, y] on the user device. In order to make that I need to be able to read the distance of the fragment at that given point.

Answer in different circumstances:

When using normal OpenGL you could achieve this by creating FrameBuffer and then attach either RenderBuffer or Texture with depth component to it. Both of those approaches use glReadPixels, with internal format of GL_DEPTH_COMPONENT to retrieve the data from the buffer/texture. Unfortunately OpenGL ES only supports GL_ALPHA, GL_RGB, and GL_RGBA as the readback formats, so there's really no way to reach the framebuffer's depth data directly.

The only viable approach that I can think of (and that I have found suggested on the internet) is to create different shaders just for depth buffering. The shader, that is used only for depth rendering, should write gl_FragCoord.z value (=the distance value that we want to read.) on the gl_FragColor. However:

The actual Question:

When I write gl_FragCoord.z value on the gl_FragColor = new Vec4(vec3(gl_FragCoord.z), 1.0); and later use glReadPixels to read back the rgb values, those read values don't match up with the input.

What I have tried:

I realize that there's only 24 bits (r, g, b * 8 bits each) representing the depth data so I tried shifting the returned value by 8 - to get 32 bits, but it didn't seem to work. I also tried to shift distance when applying it to red, green and blue, but that didn't seem to work as expected. I have been trying to figure out what's wrong by observing the bits, results at the bottom.

fragmentShader.glsl(candidate #3):

void main() {

highp float distance = 1.0; //currently just 1.0 to test the results with different values.
lowp float red = distance / exp2(16.0);
lowp float green = distance / exp2(8.0);
lowp float blue = distance / exp2(0.0);
gl_FragColor = vec4(red, green, blue, 1.0);

}

Method to read the values (=glReadPixels)

private float getDepth(int x, int y){
    FloatBuffer buffer = GeneralSettings.getFloatBuffer(1); //just creates FloatBuffer with capacity of 1 float value.
    terrainDepthBuffer.bindFrameBuffer(); //bind the framebuffer before read back.
    GLES20.glReadPixels(x, y, 1, 1, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, buffer); //read the values from previously bind framebuffer.
    GeneralSettings.checkGlError("glReadPixels"); //Make sure there is no gl related errors.
    terrainDepthBuffer.unbindCurrentFrameBuffer(); //Remember to unbind the buffer after reading/writing.
    System.out.println(buffer.get(0)); //Print the value.
}

Observations in bits using the shader & method above:

Value   |           Shader input            | ReadPixels output
1.0f    |  111111100000000000000000000000   | 111111110000000100000000
0.0f    |               0                   | 0
0.5f    |   111111000000000000000000000000  | 100000000000000100000000
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
ppxxy
  • 21
  • 4
  • https://stackoverflow.com/questions/18453302/how-do-you-pack-one-32bit-int-into-4-8bit-ints-in-glsl-webgl/18454838#18454838 – LJᛃ Aug 08 '17 at 23:54
  • 1
    The last part is wrong because you write to float buffer but the source is unsigned byte: GLES20.GL_UNSIGNED_BYTE to FloatBuffer. Your shader should work normally without doing any transformation to get the color. You should get a value between 0 and 255. The only thing is you might need to change range of gl_FragCoord.z from [-1,1] to [0,1] so you would need to use "gl_FragCoord.z*0.5 + 0.5". I am not 100% on that one though... – Matic Oblak Aug 09 '17 at 09:24
  • 1
    @MaticOblak `gl_FragCoord.z` is the fragment’s depth mapped in the non-linear range [0,1], which is written to `gl_FragDepth`. See [`gl_FragCoord`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/gl_FragCoord.xhtml) and [What does `gl_FragCoord` contain?](http://www.txutxi.com/?p=182). – Rabbid76 Aug 12 '17 at 21:25
  • @Rabbid76 Thank you for these. So the question here is why would you even use gl_fragCoord. The z coordinate of position seems to be more interesting to draw as color. – Matic Oblak Aug 13 '17 at 05:02

0 Answers0