# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/src/vlGraphics/OcclusionCullRenderer.cpp

Go to the documentation of this file.

    00001 /**************************************************************************************/
    00002 /*                                                                                    */
    00003 /*  Visualization Library                                                             */
    00004 /*  http://www.visualizationlibrary.org                                               */
    00005 /*                                                                                    */
    00006 /*  Copyright (c) 2005-2011, Michele Bosi                                             */
    00007 /*  All rights reserved.                                                              */
    00008 /*                                                                                    */
    00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
    00010 /*  are permitted provided that the following conditions are met:                     */
    00011 /*                                                                                    */
    00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
    00013 /*  list of conditions and the following disclaimer.                                  */
    00014 /*                                                                                    */
    00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
    00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
    00017 /*  other materials provided with the distribution.                                   */
    00018 /*                                                                                    */
    00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
    00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
    00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
    00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
    00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
    00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
    00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
    00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
    00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
    00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
    00029 /*                                                                                    */
    00030 /**************************************************************************************/
    00031
    00032 #include <vlGraphics/OcclusionCullRenderer.hpp>
    00033 #include <vlGraphics/RenderQueue.hpp>
    00034 #include <vlGraphics/OpenGLContext.hpp>
    00035 #include <vlCore/Log.hpp>
    00036 #include <vlCore/Say.hpp>
    00037
    00038 using namespace vl;
    00039
    00040 //-----------------------------------------------------------------------------
    00041 OcclusionCullRenderer::OcclusionCullRenderer()
    00042 {
    00043   VL_DEBUG_SET_OBJECT_NAME()
    00044
    00045   mPrevWrapRenderer = NULL;
    00046
    00047   mStatsTotalObjects = 0;
    00048   mStatsOccludedObjects = 0;
    00049
    00050   mCulledRenderQueue = new RenderQueue;
    00051   mOcclusionThreshold      = 0;
    00052
    00053   // todo: support GL 3.x CORE
    00054   mOcclusionShader = new Shader;
    00055   mOcclusionShader->gocDepthMask()->set(false);
    00056   mOcclusionShader->gocDepthFunc()->set(vl::FU_LEQUAL);
    00057   mOcclusionShader->gocColorMask()->set(false, false, false, false);
    00058   mOcclusionShader->enable(vl::EN_CULL_FACE);
    00059   mOcclusionShader->enable(vl::EN_DEPTH_TEST);
    00060   mOcclusionShader->enable(vl::EN_POLYGON_OFFSET_FILL);
    00061   mOcclusionShader->gocPolygonOffset()->set(-1.0f, -1.0f);
    00062
    00063   // for debugging purposes only
    00064   // mOcclusionShader->gocColorMask()->set(true, true, true, true);
    00065   // mOcclusionShader->gocPolygonMode()->set(vl::PM_LINE, vl::PM_LINE);
    00066 }
    00067 //-----------------------------------------------------------------------------
    00068 const RenderQueue* OcclusionCullRenderer::render(const RenderQueue* in_render_queue, Camera* camera, real frame_clock)
    00069 {
    00070   // skip if renderer is disabled
    00071   if (enableMask() == 0)
    00072     return in_render_queue;
    00073
    00074   // enter/exit behavior contract
    00075
    00076   class InOutContract
    00077   {
    00078     RendererAbstract* mRenderer;
    00079
    00080   public:
    00081     InOutContract(RendererAbstract* renderer): mRenderer(renderer)
    00082     {
    00083       // increment the render tick.
    00084       mRenderer->incrementRenderTick();
    00085
    00086       // dispatch the renderer-started event.
    00087       mRenderer->dispatchOnRendererStarted();
    00088
    00089       // check user-generated errors.
    00090       VL_CHECK_OGL()
    00091     }
    00092
    00093     ~InOutContract()
    00094     {
    00095       // dispatch the renderer-finished event
    00096       mRenderer->dispatchOnRendererFinished();
    00097
    00098       // check user-generated errors.
    00099       VL_CHECK_OGL()
    00100     }
    00101   } contract(this);
    00102
    00103   // --------------- rendering ---------------
    00104
    00105   if (!mWrappedRenderer)
    00106   {
    00107     Log::error("OcclusionCullRenderer::render(): no Renderer is wrapped!\n");
    00108     VL_TRAP();
    00109     return in_render_queue;
    00110   }
    00111
    00112   // (1)
    00113   // verify visibility from previous occlusion queries.
    00114   render_pass1( in_render_queue );
    00115
    00116   // (2)
    00117   // render only non occluded objects.
    00118   mWrappedRenderer->render( mCulledRenderQueue.get(), camera, frame_clock );
    00119
    00120   // (3)
    00121   // perform occlusion query on all objects.
    00122   render_pass2( in_render_queue, camera );
    00123
    00124   // return only the visible, non occluded, objects.
    00125   return mCulledRenderQueue.get();
    00126 }
    00127 //-----------------------------------------------------------------------------
    00128 void OcclusionCullRenderer::setWrappedRenderer(Renderer* renderer)
    00129 {
    00130   mWrappedRenderer = renderer;
    00131 }
    00132 //-----------------------------------------------------------------------------
    00133 const Framebuffer* OcclusionCullRenderer::framebuffer() const
    00134 {
    00135   if (mWrappedRenderer)
    00136     return mWrappedRenderer->framebuffer();
    00137   else
    00138     return NULL;
    00139 }
    00140 //-----------------------------------------------------------------------------
    00141 Framebuffer* OcclusionCullRenderer::framebuffer()
    00142 {
    00143   if (mWrappedRenderer)
    00144     return mWrappedRenderer->framebuffer();
    00145   else
    00146     return NULL;
    00147 }
    00148 //-----------------------------------------------------------------------------
    00149 void OcclusionCullRenderer::render_pass1(const RenderQueue* in_render_queue )
    00150 {
    00151   // reset occluded objects statistics
    00152   mStatsOccludedObjects = 0;
    00153   mStatsTotalObjects    = in_render_queue->size();
    00154
    00155   // reset visible objects.
    00156   mCulledRenderQueue->clear();
    00157
    00158   // iterate incoming render tokens and output only visible ones
    00159   for( int i=0; i<in_render_queue->size(); ++i)
    00160   {
    00161     const Actor* actor = in_render_queue->at(i)->mActor;
    00162
    00163     if ( !mWrappedRenderer->isEnabled(actor->enableMask()) )
    00164       continue;
    00165
    00166     bool occluded = false;
    00167     VL_CHECK(Has_Occlusion_Query)
    00168
    00169     if ( actor->occlusionQuery() &&
    00170          actor->occlusionQueryTick() == mWrappedRenderer->renderTick() &&
    00171          mPrevWrapRenderer == mWrappedRenderer.get() )
    00172     {
    00173       #if 0
    00174         GLint ready = GL_FALSE;
    00175         glGetQueryObjectiv(actor->occlusionQuery(), GL_QUERY_RESULT_AVAILABLE, &ready); VL_CHECK_OGL();
    00176         if (ready == GL_FALSE)
    00177           vl::Log::error("Occlusion culling query not yet available.\n");
    00178       #endif
    00179       // query the occlusion status: note that this might flush the pipeline
    00180       GLint pixels = 0;
    00181       glGetQueryObjectiv(actor->occlusionQuery(), GL_QUERY_RESULT, &pixels); VL_CHECK_OGL();
    00182       if (pixels <= occlusionThreshold())
    00183         occluded = true;
    00184     }
    00185
    00186     if (occluded == false)
    00187     {
    00188       // pass over the incoming render token to the list of visible objects
    00189       RenderToken* tok = mCulledRenderQueue->newToken(false);
    00190       *tok = *in_render_queue->at(i);
    00191     }
    00192     else
    00193       mStatsOccludedObjects++;
    00194   }
    00195
    00196   mPrevWrapRenderer = mWrappedRenderer.get();
    00197 }
    00198 //-----------------------------------------------------------------------------
    00199 void OcclusionCullRenderer::render_pass2(const RenderQueue* non_occluded_render_queue, Camera* camera)
    00200 {
    00201   // note that we return the occluded render queue
    00202   if (enableMask() == 0)
    00203     return;
    00204
    00205 #ifndef NDEBUG
    00206   GLint buffer = 0;
    00207   glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buffer);
    00208   VL_CHECK(buffer == 0);
    00209 #endif
    00210
    00211   // --------------- render target activation ---------------
    00212
    00213   /* keep the currently active render target */
    00214   // framebuffer()->activate();
    00215
    00216   // --------------- viewport activation ---------------
    00217
    00218   /* don't touch the current viewport */
    00219   //camera->viewport()->setClearFlags(vl::CF_DO_NOT_CLEAR);
    00220   //camera->viewport()->activate();
    00221
    00222   // --------------- default scissor ---------------
    00223
    00224   // scissor the viewport by default: needed for points and lines since they are not clipped against the viewport.
    00225   #if 1
    00226     glEnable(GL_SCISSOR_TEST);
    00227     glScissor(camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height());
    00228   #else
    00229     glDisable(GL_SCISSOR_TEST);
    00230   #endif
    00231
    00232   const Scissor* cur_scissor = NULL;
    00233
    00234   // --------------- setup occlusion shader once and for all ---------------
    00235
    00236   OpenGLContext* opengl_context = framebuffer()->openglContext();
    00237   GLSLProgram*   glsl_program   = mOcclusionShader->glslProgram();
    00238   Transform*     cur_transform  = NULL;
    00239
    00240   opengl_context->resetRenderStates();
    00241   opengl_context->resetEnables();
    00242   opengl_context->applyRenderStates( mOcclusionShader->getRenderStateSet(), camera );
    00243   opengl_context->applyEnables( mOcclusionShader->getEnableSet() );
    00244   projViewTransfCallback()->updateMatrices( true, true, glsl_program, camera, cur_transform );
    00245
    00246   // camera/eye position for later usage
    00247
    00248   vec3 eye = camera->modelingMatrix().getT();
    00249
    00250   // --------------- rendering ---------------
    00251
    00252   // iterate over render tokens
    00253
    00254   // glColor3f(1.0f, 0.0f, 1.0f); // for debugging only
    00255   glEnableClientState(GL_VERTEX_ARRAY); VL_CHECK_OGL();
    00256
    00257   for( int i=0; i<non_occluded_render_queue->size(); ++i)
    00258   {
    00259     const RenderToken* tok = non_occluded_render_queue->at(i);
    00260     Actor* actor = tok->mActor;
    00261
    00262     if ( !mWrappedRenderer->isEnabled(actor->enableMask()) )
    00263       continue;
    00264
    00265     // --------------- Actor's scissor ---------------
    00266
    00267     const Scissor* scissor = actor->scissor() ? actor->scissor() : tok->mShader->scissor();
    00268     if (cur_scissor != scissor)
    00269     {
    00270       cur_scissor = scissor;
    00271       if (cur_scissor)
    00272       {
    00273         cur_scissor->enable(camera->viewport());
    00274       }
    00275       else
    00276       {
    00277         #if 1
    00278           // scissor the viewport by default: needed for points and lines with size > 1.0 as they are not clipped against the viewport.
    00279           VL_CHECK(glIsEnabled(GL_SCISSOR_TEST))
    00280           glScissor(camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height());
    00281         #else
    00282           glDisable(GL_SCISSOR_TEST);
    00283         #endif
    00284       }
    00285     }
    00286
    00287     if ( !actor->boundingBox().isInside(eye) )
    00288     {
    00289       VL_CHECK(Has_Occlusion_Query)
    00290
    00291       // if occludee -> perform occlusion test to be used for the next frame
    00292       if (actor->isOccludee())
    00293       {
    00294
    00295         if (tok->mActor->transform() != cur_transform)
    00296         {
    00297           cur_transform = tok->mActor->transform();
    00298           projViewTransfCallback()->updateMatrices( false, true, glsl_program, camera, cur_transform );
    00299         }
    00300
    00301         // register occlusion query tick
    00302         actor->setOcclusionQueryTick( mWrappedRenderer->renderTick() );
    00303
    00304         // compute Renderable AABB geometry (we are using the currently active Transform)
    00305         const AABB& aabb = tok->mRenderable->boundingBox();
    00306         const float verts[] =
    00307         {
    00308           (float)aabb.minCorner().x(), (float)aabb.minCorner().y(), (float)aabb.minCorner().z(),
    00309           (float)aabb.maxCorner().x(), (float)aabb.minCorner().y(), (float)aabb.minCorner().z(),
    00310           (float)aabb.maxCorner().x(), (float)aabb.maxCorner().y(), (float)aabb.minCorner().z(),
    00311           (float)aabb.minCorner().x(), (float)aabb.maxCorner().y(), (float)aabb.minCorner().z(),
    00312           (float)aabb.minCorner().x(), (float)aabb.minCorner().y(), (float)aabb.maxCorner().z(),
    00313           (float)aabb.maxCorner().x(), (float)aabb.minCorner().y(), (float)aabb.maxCorner().z(),
    00314           (float)aabb.maxCorner().x(), (float)aabb.maxCorner().y(), (float)aabb.maxCorner().z(),
    00315           (float)aabb.minCorner().x(), (float)aabb.maxCorner().y(), (float)aabb.maxCorner().z()
    00316         };
    00317         const unsigned quads[] = { 3,2,1,0, 2,6,5,1, 3,7,6,2, 7,3,0,4, 4,0,1,5, 6,7,4,5 };
    00318         glVertexPointer(3, GL_FLOAT, 0, verts); VL_CHECK_OGL();
    00319         actor->createOcclusionQuery(); VL_CHECK_OGL();
    00320         glBeginQuery(GL_SAMPLES_PASSED, actor->occlusionQuery()); VL_CHECK_OGL();
    00321         glDrawElements(GL_QUADS, 6*4, GL_UNSIGNED_INT, quads); VL_CHECK_OGL();
    00322         glEndQuery(GL_SAMPLES_PASSED); VL_CHECK_OGL();
    00323       }
    00324     }
    00325   }
    00326
    00327   glDisableClientState(GL_VERTEX_ARRAY); VL_CHECK_OGL();
    00328   glVertexPointer(3, GL_FLOAT, 0, NULL); VL_CHECK_OGL();
    00329
    00330   // clear enables
    00331   opengl_context->applyEnables( mDummyEnables.get() );
    00332
    00333   // clear render states
    00334   opengl_context->applyRenderStates( mDummyStateSet.get(), camera );
    00335
    00336   glDisable(GL_SCISSOR_TEST);
    00337 }
    00338 //-----------------------------------------------------------------------------

Visualization Library v2011.09.1162 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu Jan 26 2012 00:43:39.
Permission is granted to use this page to write and publish articles regarding Visualization Library.