Hello friends, I’m developing Graphic Engine from more than one year and I’ve tested more than few ways to do Occlusion Culling.
Testing environment:
[ul]
[li]nVidia Quadro FX 360M for notebook[/li][li]Intel Centrino DualCore 2.5GHz, 4GB RAM[/li][li]only frustum culling for objects outside frustum (with 6 planes in CPU)[/li][li]no octrees or other hierarchical order[/li][li]no physics or other stuff…just simple rendering using VBOs and Shaders 3.30[/li][li]tests done with same initial camera position[/li][li]50 objects (40.000 vertices, 16MB of total textures loaded)[/li][li]double buffer active and VSync disabled (using SwapBuffers function)[/li][/ul]
Using ARB_occlusion_query extension[HR][/HR]First pass:
[ol]
[li]sort objects from front to back order (Z-Depth was retrivied during frustum calculation)[/li][li]disable glColorMask(…)[/li][li]for each 3D object:[/li][LIST=1]
[li]BeginQuery(…)[/li][li]glDraw() object[/li][li]EndQuery(…)[/li][li]glGetQueryObject() results[/li][li]if (visiblePixels < threshold) set object’s variable “occluded = true”[/li][/ol]
[li]enable glColorMask(…)[/li][/LIST]
Second pass:
[ol]
[li]for each 3D object:[/li][LIST=1]
[li]if (occluded == true) skip object[/li][li]glDraw() object[/li][/ol]
[/LIST]
With ARB_occlusion_query I get 120fps.
Using glReadPixel (with same tecnique of Color Picking):
Pre-phase: I was already using a color picking tecnique during Mouse Selection, so I’ve tried to use same tecnique to do occlusion. Color Picking tecnique renders in a single pass all objects, each single object with a different color. In this way if one pixel is “158,0,0,0” (B,G,R,A format during glReadPixels) I’m sure at least one pixel of that object (ID=158) is visible, so I can render it during rendering.
Trick&Tips: the trick is to use a FrameBufferObject (for off-screen rendering) and two PBO (for async glReadPixels readback) to get pixels, but all those buffers are in different SIZE (width*height) of the real rendering phase.
Example: rendering scene at 1900x1200 (as in my notebook) but those FBO and PBOs are only 20% of that resolution
Concept: during occlusion I’m not really interested to know if ONE object’s pixel is visible, but I’m interested if few pixels are visible. So it’s useless rendering at the same resolution as final image (due to Fragment Shader calculations over more pixels/fragments and the readback procedure, using glReadPixels, over milions of pixels). The solution is to use a proportional reduced resolution for FBO and PBOs, and render to a smaller resolution. Less precision but very good speed!
[HR][/HR]First pass:
[ol]
[li]create a FrameBufferObject(FBO) for off-screen rendering smaller than rendering viewport[/li][li]create two PBOs (one for color_attachment0 and one for depth_attachment component) with the same previous FBO’s size[/li][li]enable rendering (color and depth) to our FBO[/li][li]clClear(…color…depth…)[/li][li]change current viewport size to fits FBO’s dimensions[/li][li]render objects are usual (or just in bouding_box mode for super fast process)[/li][li]execute glReadPixels() process to get an array of B,G,R,A values of our FBO[/li][li]parse the array (for few thousand pixels at this reduced resolution) and check BGRA values to identify object_IDs[/li][li]if object_ID is valid search set its variable “occluded = true”[/li][li]disable rendering to FBO and returns to window’s back_buffer[/li][li]change current viewport size to previous values (full render size)[/li][/ol]
Second pass:
[ol]
[li]for each 3D object:[/li][LIST=1]
[li]if (occluded == true) skip object[/li][li]glDraw() object[/li][/ol]
[/LIST]
With this procedure I get [b]144fps
[/b]
This test demonstrate that ARB_occlusion_query could be worst than other half-hardware methods.
With second tecnique I don’t need to order objects from front to back, and it is not so bad!!!
Hope this helps someone during occlusion or color picking procedure