Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://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 //-----------------------------------------------------------------------------