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?
glGetTexImage
. Pretty inefficient, considering I need to grab the entire texture, and can't just read the one pixel, but I assume it's the clip z coordinate? – Fault Dec 03 '13 at 20:30