Question

Using the WebGL API, how can I get a value from the depth buffer, or in any other way determine 3D coordinates from screen coordinates (i.e. to find a location clicked on), other than by performing my own raycasting?

Was it helpful?

Solution

Several years have passed, these days the WEBGL_depth_texture extension is widely available... unless you need to support IE.

General usage:

Preparation:

  1. Query the extension (required)
  2. Allocate a separate color and depth texture (gl.DEPTH_COMPONENT)
  3. Combine both textures in to a single framebuffer (gl.COLOR_ATTACHMENT0, gl.DEPTH_ATTACHMENT)

Rendering:

  1. Bind the framebuffer, render your scene (usually a simplified version)
  2. Unbind the framebuffer, pass the depth texture to your shaders and read it like any other texture:

    texPos.xyz = (gl_Position.xyz / gl_Position.w) * 0.5 + 0.5;
    float depthFromZBuffer = texture2D(uTexDepthBuffer, texPos.xy).x;
    

OTHER TIPS

I don't know if it's possible to directly access the depth buffer but if you want depth information in a texture, you'll have to create a rgba texture, attach it as a colour attachment to an frame buffer object and render depth information into the texture, using a fragment shader that writes the depth value into gl_FragColor.

For more information, see the answers to one of my older questions: WebGL - render depth to fbo texture does not work

If you google for opengl es and shadow mapping or depth, you'll find more explanations and example source code.

From section 5.13.12 of the WebGL specification it seems you cannot directly read the depth buffer, so maybe Markus' suggestion is the best way to do it, although you might not neccessarily need an FBO for this.

But if you want to do something like picking, there are other methods for it. Just browse SO, as it has been asked very often.

Not really a duplicate but see also: How to get object in WebGL 3d space from a mouse click coordinate

Aside of unprojecting and casting a ray (and then performing intersection tests against it as needed), your best bet is to look at 'picking'. This won't give exact 3D coordinates, but it is a useful substitute for unprojection when you only care about which object was clicked on, and don't really need per-pixel precision.

Picking in WebGL means to render the entire scene (or at least, the objects you care about) using a specific shader. The shader renders each object with a different unique ID, which is encoded in the red and green channels, using the blue channel as a key (non-blue means no object of interest). The scene is rendered into an offscreen framebuffer so that it's not visible to the end user. Then you read back, using gl.readPixels(), the pixel or pixels of interest and see which object ID was encoded at the given position.

If it helps, see my own implementation of WebGL picking. This implementation picks a rectangular region of pixels; passing in a 1x1 region results in picking at a single pixel. See also the functions at lines 146, 162, and 175.

As of January 23, 2012, there is a draft WebGL extension to enable depth buffer reading, WEBGL_depth_texture. I have no information about its availability in implementations, but I do not expect it at this early date.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top