c++openglfloating-accuracyray-picking

Ray picking with depth buffer: horribly inaccurate?


I'm trying to implement a ray picking algorithm, for painting and selecting blocks (thus I need a fair amount of accuracy). Initially I went with a ray casting implementation, but I didn't feel it was accurate enough (although the fault may have been with my intersection testing). Regardless, I decided to try picking by using the depth buffer, and transforming the mouse coordinates to world coordinates. Implementation below:

glm::vec3 Renderer::getMouseLocation(glm::vec2 coordinates) {
    float depth = deferredFBO->getDepth(coordinates);

    // Calculate the width and height of the deferredFBO
    float viewPortWidth = deferredArea.z - deferredArea.x;
    float viewPortHeight = deferredArea.w - deferredArea.y;

    // Calculate homogenous coordinates for mouse x and y
    float windowX = (2.0f * coordinates.x) / viewPortWidth - 1.0f;
    float windowY = 1.0f - (2.0f * coordinates.y) / viewPortHeight;

    // cameraToClip = projection matrix
    glm::vec4 cameraCoordinates = glm::inverse(cameraToClipMatrix) 
                                * glm::vec4(windowX, windowY, depth, 1.0f);

    // Normalize
    cameraCoordinates /= cameraCoordinates.w;

    glm::vec4 worldCoordinates = glm::inverse(worldToCameraMatrix) 
                               * cameraCoordinates;

    return glm::vec3(worldCoordinates);
}

The problem is that the values are easily ±3 units (blocks are 1 unit wide), only getting accurate enough when very close to the near clipping plane.

Does the inaccuracy stem from using single-precision floats, or maybe some step in my calculations? Would it help if I used double-precision values, and does OpenGL even support that for depth buffers?

And lastly, if this method doesn't work, am I best off using colour IDs to accurately identify which polygon was picked?


Solution

  • Colors are the way to go, the depth buffers accuracy depend on the plane distances, the resolution of the FBO texture, also on the normal or slope of the surface.The same precision problem happens during the standard shadowing.(Using colors is a bit easier because of with the depth intersection test one object have more "color", depth values. It's more accurate if one object has one color.)

    Also, maybe its just me, but I like to avoid rather complex matrix calculations if they're not necessary. It's enough for the poor CPU to do the other stuffs.

    For double precision values, that could drop performance badly. I've encountered this kind of performance drop, it was about 3x slower for me to use doubles rather than floats:

    my post: GLSL performance - function return value/type and an article about this: https://superuser.com/questions/386456/why-does-a-geforce-card-perform-4x-slower-in-double-precision-than-a-tesla-card

    so yep, you can, use 64 bit floats (double): http://www.opengl.org/registry/specs...hader_fp64.txt, and http://www.opengl.org/registry/specs...trib_64bit.txt, but you should not.

    All in all use colored polys, I like colors khmm...

    EDIT: more about double precision depth : http://www.opengl.org/discussion_boards/showthread.php/173450-Double-Precision, its a pretty good discussion