My vertex format has a float4 Flags element used to pass miscellaneous data to shaders. Each mouse-collidable object that is rendered has a unique ObjectID that is written to an ObjectID-rendertarget which can be CPU-sampled to index the hovered object. The remaining render targets are geometry/lighting data.
I've found this has advantages:
- I set (Flags.x = ObjectID) upon object creation so the vertex buffer only needs an initial upload and updates only when new ObjectID's (that will be rendered) are created. Everything else is per-object/instance. Essentially, "no" overhead added by using a Flags component for ObjectID.
- I'm semi-certain that, since I have to render everything anyway, outputting one additional color to one additional rendertarget is already cheaper than ANY clever bounding/container collision testing algorithm. Currently, I copy the entire ObjectID-rendertarget back to the CPU, but even that could be further optimized.
- The depth buffer (that I'm using anyway) automatically ensures that the pixel I sample is the ObjectID of the top-most, visible, mouse-collidable, object. I don't have to check if the mouse position/ray is within the bounds of anything, intersects with anything, visibilities, nothing. All of that is already sorted out by rendering the scene properly.
- Rendering the interface components first and reusing the ObjectID depth-buffer to render the world, reduces the fill-volume for the 3D scene; drastically, if a lot of interface is visible.
I've found only one disadvantage:
- Since I render the interface first, if the camera has moved (the world hasn't been rendered yet), the WorldCoordinate available during Update() is incorrect. If the camera hasn't changed, the coordinate is correct. Immediately after rendering to the geometry buffers, but before any cursor-dependent shaders are invoked, I update the CPU-buffer and WorldCoordinate. The CPU-buffer is only updated when necessary and, at most, once per-frame. The "second sample" is during the following Update() and just re-reads the (wrong if the camera has moved) value from the byte array. Still, no significant overhead and this is basically just a slight annoyance because I'm just debugging the value anyway. Currently, when the WorldCoordinate is usefully-used (during render), it is correct.
Overall, I've got pixel-perfect, anything-on-the-screen, mouse-collision detection, with zero* additional overhead beyond standard rendering.
*Minimal and/or approximately-fixed, regardless of screen/scene complexity
Why is this method not popular and/or tutorialized?
-I assume most new-ish games post-process geometry buffers but I found nothing similar to this and just worked my way through the issues as they came up. To me, it appears as though I've got collision detection working for all of the objects/classes that I haven't even written yet. All of the "tech" involved here is obvious and easy, so I feel like I must be missing something; a future problem that I can't think of yet.
-Comments/critiques of the "algorithm" are welcome. Best answers would point out critical flaw(s) and, for bonus points, work-arounds.
-If this has been done before, is there an accepted best-practice? Links to similars would be ok.