Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/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 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:38.
Permission is granted to use this page to write and publish articles regarding Visualization Library.