Visualization Library 2.0.0

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

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
OcclusionCullRenderer.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
35 #include <vlCore/Log.hpp>
36 #include <vlCore/Say.hpp>
37 
38 using namespace vl;
39 
40 //-----------------------------------------------------------------------------
42 {
43  VL_DEBUG_SET_OBJECT_NAME()
44 
46 
49 
52 
53  // todo: support GL 3.x CORE
57  mOcclusionShader->gocColorMask()->set(false, false, false, false);
61  mOcclusionShader->gocPolygonOffset()->set(-1.0f, -1.0f);
62 
63  // for debugging purposes only
64  // mOcclusionShader->gocColorMask()->set(true, true, true, true);
65  // mOcclusionShader->gocPolygonMode()->set(vl::PM_LINE, vl::PM_LINE);
66 }
67 //-----------------------------------------------------------------------------
68 const RenderQueue* OcclusionCullRenderer::render(const RenderQueue* in_render_queue, Camera* camera, real frame_clock)
69 {
70  // skip if renderer is disabled
71  if (enableMask() == 0)
72  return in_render_queue;
73 
74  // enter/exit behavior contract
75 
76  class InOutContract
77  {
78  RendererAbstract* mRenderer;
79 
80  public:
81  InOutContract(RendererAbstract* renderer): mRenderer(renderer)
82  {
83  // increment the render tick.
84  mRenderer->incrementRenderTick();
85 
86  // dispatch the renderer-started event.
87  mRenderer->dispatchOnRendererStarted();
88 
89  // check user-generated errors.
90  VL_CHECK_OGL()
91  }
92 
93  ~InOutContract()
94  {
95  // dispatch the renderer-finished event
96  mRenderer->dispatchOnRendererFinished();
97 
98  // check user-generated errors.
99  VL_CHECK_OGL()
100  }
101  } contract(this);
102 
103  // --------------- rendering ---------------
104 
105  if (!mWrappedRenderer)
106  {
107  Log::error("OcclusionCullRenderer::render(): no Renderer is wrapped!\n");
108  VL_TRAP();
109  return in_render_queue;
110  }
111 
112  // (1)
113  // verify visibility from previous occlusion queries.
114  render_pass1( in_render_queue );
115 
116  // (2)
117  // render only non occluded objects.
118  mWrappedRenderer->render( mCulledRenderQueue.get(), camera, frame_clock );
119 
120  // (3)
121  // perform occlusion query on all objects.
122  render_pass2( in_render_queue, camera );
123 
124  // return only the visible, non occluded, objects.
125  return mCulledRenderQueue.get();
126 }
127 //-----------------------------------------------------------------------------
129 {
130  mWrappedRenderer = renderer;
131 }
132 //-----------------------------------------------------------------------------
134 {
135  if (mWrappedRenderer)
136  return mWrappedRenderer->framebuffer();
137  else
138  return NULL;
139 }
140 //-----------------------------------------------------------------------------
142 {
143  if (mWrappedRenderer)
144  return mWrappedRenderer->framebuffer();
145  else
146  return NULL;
147 }
148 //-----------------------------------------------------------------------------
150 {
151  // reset occluded objects statistics
153  mStatsTotalObjects = in_render_queue->size();
154 
155  // reset visible objects.
156  mCulledRenderQueue->clear();
157 
158  // iterate incoming render tokens and output only visible ones
159  for( int i=0; i<in_render_queue->size(); ++i)
160  {
161  const Actor* actor = in_render_queue->at(i)->mActor;
162 
163  if ( ! mWrappedRenderer->isEnabled(actor) )
164  continue;
165 
166  bool occluded = false;
168 
169  if ( actor->occlusionQuery() &&
170  actor->occlusionQueryTick() == mWrappedRenderer->renderTick() &&
172  {
173  #if 0
174  GLint ready = GL_FALSE;
175  glGetQueryObjectiv(actor->occlusionQuery(), GL_QUERY_RESULT_AVAILABLE, &ready); VL_CHECK_OGL();
176  if (ready == GL_FALSE)
177  vl::Log::error("Occlusion culling query not yet available.\n");
178  #endif
179  // query the occlusion status: note that this might flush the pipeline
180  GLint pixels = 0;
181  glGetQueryObjectiv(actor->occlusionQuery(), GL_QUERY_RESULT, &pixels); VL_CHECK_OGL();
182  if (pixels <= occlusionThreshold())
183  occluded = true;
184  }
185 
186  if (occluded == false)
187  {
188  // pass over the incoming render token to the list of visible objects
189  RenderToken* tok = mCulledRenderQueue->newToken(false);
190  *tok = *in_render_queue->at(i);
191  }
192  else
194  }
195 
197 }
198 //-----------------------------------------------------------------------------
199 void OcclusionCullRenderer::render_pass2(const RenderQueue* non_occluded_render_queue, Camera* camera)
200 {
201  // note that we return the occluded render queue
202  if (enableMask() == 0)
203  return;
204 
205 #ifndef NDEBUG
206  GLint buffer = 0;
207  glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buffer);
208  VL_CHECK(buffer == 0);
209 #endif
210 
211  // --------------- render target activation ---------------
212 
213  /* keep the currently active render target */
214  // framebuffer()->activate();
215 
216  // --------------- viewport activation ---------------
217 
218  /* don't touch the current viewport */
219  //camera->viewport()->setClearFlags(vl::CF_DO_NOT_CLEAR);
220  //camera->viewport()->activate();
221 
222  // --------------- default scissor ---------------
223 
224  // scissor the viewport by default: needed for points and lines since they are not clipped against the viewport.
225  #if 1
226  glEnable(GL_SCISSOR_TEST);
227  glScissor(camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height());
228  #else
229  glDisable(GL_SCISSOR_TEST);
230  #endif
231 
232  const Scissor* cur_scissor = NULL;
233 
234  // --------------- setup occlusion shader once and for all ---------------
235 
236  OpenGLContext* opengl_context = framebuffer()->openglContext();
237  GLSLProgram* glsl_program = mOcclusionShader->glslProgram();
238  Transform* cur_transform = NULL;
239 
240  opengl_context->resetRenderStates();
241  opengl_context->resetEnables();
242  opengl_context->applyRenderStates( mOcclusionShader->getRenderStateSet(), camera );
243  opengl_context->applyEnables( mOcclusionShader->getEnableSet() );
244  projViewTransfCallback()->updateMatrices( true, true, glsl_program, camera, cur_transform );
245 
246  // camera/eye position for later usage
247 
248  vec3 eye = camera->modelingMatrix().getT();
249 
250  // --------------- rendering ---------------
251 
252  // iterate over render tokens
253 
254  // glColor3f(1.0f, 0.0f, 1.0f); // for debugging only
255  glEnableClientState(GL_VERTEX_ARRAY); VL_CHECK_OGL();
256 
257  for( int i=0; i<non_occluded_render_queue->size(); ++i)
258  {
259  const RenderToken* tok = non_occluded_render_queue->at(i);
260  Actor* actor = tok->mActor;
261 
262  if ( ! mWrappedRenderer->isEnabled(actor) )
263  continue;
264 
265  // --------------- Actor's scissor ---------------
266 
267  const Scissor* scissor = actor->scissor() ? actor->scissor() : tok->mShader->scissor();
268  if (cur_scissor != scissor)
269  {
270  cur_scissor = scissor;
271  if (cur_scissor)
272  {
273  cur_scissor->enable(camera->viewport());
274  }
275  else
276  {
277  #if 1
278  // scissor the viewport by default: needed for points and lines with size > 1.0 as they are not clipped against the viewport.
279  VL_CHECK(glIsEnabled(GL_SCISSOR_TEST))
280  glScissor(camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height());
281  #else
282  glDisable(GL_SCISSOR_TEST);
283  #endif
284  }
285  }
286 
287  if ( !actor->boundingBox().isInside(eye) )
288  {
290 
291  // if occludee -> perform occlusion test to be used for the next frame
292  if (actor->isOccludee())
293  {
294 
295  if (tok->mActor->transform() != cur_transform)
296  {
297  cur_transform = tok->mActor->transform();
298  projViewTransfCallback()->updateMatrices( false, true, glsl_program, camera, cur_transform );
299  }
300 
301  // register occlusion query tick
302  actor->setOcclusionQueryTick( mWrappedRenderer->renderTick() );
303 
304  // compute Renderable AABB geometry (we are using the currently active Transform)
305  const AABB& aabb = tok->mRenderable->boundingBox();
306  const float verts[] =
307  {
308  (float)aabb.minCorner().x(), (float)aabb.minCorner().y(), (float)aabb.minCorner().z(),
309  (float)aabb.maxCorner().x(), (float)aabb.minCorner().y(), (float)aabb.minCorner().z(),
310  (float)aabb.maxCorner().x(), (float)aabb.maxCorner().y(), (float)aabb.minCorner().z(),
311  (float)aabb.minCorner().x(), (float)aabb.maxCorner().y(), (float)aabb.minCorner().z(),
312  (float)aabb.minCorner().x(), (float)aabb.minCorner().y(), (float)aabb.maxCorner().z(),
313  (float)aabb.maxCorner().x(), (float)aabb.minCorner().y(), (float)aabb.maxCorner().z(),
314  (float)aabb.maxCorner().x(), (float)aabb.maxCorner().y(), (float)aabb.maxCorner().z(),
315  (float)aabb.minCorner().x(), (float)aabb.maxCorner().y(), (float)aabb.maxCorner().z()
316  };
317  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 };
318  glVertexPointer(3, GL_FLOAT, 0, verts); VL_CHECK_OGL();
320  glBeginQuery(GL_SAMPLES_PASSED, actor->occlusionQuery()); VL_CHECK_OGL();
321  glDrawElements(GL_QUADS, 6*4, GL_UNSIGNED_INT, quads); VL_CHECK_OGL();
322  glEndQuery(GL_SAMPLES_PASSED); VL_CHECK_OGL();
323  }
324  }
325  }
326 
327  glDisableClientState(GL_VERTEX_ARRAY); VL_CHECK_OGL();
328  glVertexPointer(3, GL_FLOAT, 0, NULL); VL_CHECK_OGL();
329 
330  // clear enables
331  opengl_context->applyEnables( mDummyEnables.get() );
332 
333  // clear render states
334  opengl_context->applyRenderStates( mDummyStateSet.get(), camera );
335 
336  glDisable(GL_SCISSOR_TEST);
337 }
338 //-----------------------------------------------------------------------------
Associates a Renderable object to an Effect and Transform.
Definition: Actor.hpp:130
int y() const
Definition: Viewport.hpp:67
const ProjViewTransfCallback * projViewTransfCallback() const
Definition: Renderer.hpp:68
Transform * transform()
Returns the Transform bound tho an Actor.
Definition: Actor.hpp:190
Implements a 4x4 matrix transform used to define the position and orientation of an Actor...
Definition: Transform.hpp:72
const Framebuffer * framebuffer() const
Returns the wrapped Renderer&#39;s Framebuffer.
GLuint occlusionQuery() const
For internal use only.
Definition: Actor.hpp:439
If enabled, do depth comparisons and update the depth buffer; Note that even if the depth buffer exis...
The Renderer class executes the actual rendering on the given RenderQueue.
Definition: Renderer.hpp:48
void applyEnables(const EnableSet *cur)
Applies an EnableSet to an OpenGLContext - Typically for internal use only.
const T_Scalar & z() const
Definition: Vector3.hpp:91
int size() const
Definition: RenderQueue.hpp:90
vl::ref< EnableSet > mDummyEnables
Definition: Renderer.hpp:108
EnableSet * getEnableSet()
Definition: Shader.hpp:2229
Renderable * mRenderable
Definition: RenderToken.hpp:59
Represents an OpenGL context, possibly a widget or a pbuffer, which can also respond to keyboard...
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
void resetEnables()
Resets all the interanal enable-tables - For internal use only.
Wraps a GLSL program to which you can bind vertex, fragment and geometry shaders. ...
Definition: GLSL.hpp:233
void createOcclusionQuery()
For internal use only.
Definition: Actor.cpp:63
Internally used by the rendering engine.
Definition: RenderToken.hpp:47
void dispatchOnRendererFinished()
Dispatches the onRendererFinished() event to the registered RenderEventCallback objects.
void set(EFunction depthfunc)
Definition: Shader.hpp:475
If enabled, and if the polygon is rendered in GL_FILL mode, an offset is added to depth values of a p...
Viewport * viewport()
The viewport bound to a camera.
Definition: Camera.hpp:141
Visualization Library main namespace.
PolygonOffset * gocPolygonOffset()
Definition: Shader.cpp:125
virtual const RenderQueue * render(const RenderQueue *in_render_queue, Camera *camera, real frame_clock)
Renders using the wrapped renderer but also performing occlusion culling.
DepthFunc * gocDepthFunc()
Definition: Shader.cpp:99
bool isOccludee() const
If is_occludee equals true an occlusion test will be performed before the rendering of the Actor (if ...
Definition: Actor.hpp:427
int height() const
Definition: Viewport.hpp:71
const Scissor * scissor() const
Returns the Scissor used when rendering an Actor.
Definition: Actor.hpp:411
#define VL_TRAP()
Definition: checks.hpp:70
int width() const
Definition: Viewport.hpp:69
The AABB class implements an axis-aligned bounding box using vl::real precision.
Definition: AABB.hpp:44
vl::ref< Renderer > mWrappedRenderer
const vec3 & maxCorner() const
Returns the corner of the AABB with the maximum x y z coordinates.
Definition: AABB.hpp:193
const Shader * mShader
Definition: RenderToken.hpp:60
void render_pass1(const RenderQueue *in_render_queue)
Retrieves the occlusion culling query results from the previous rendering frame.
const mat4 & modelingMatrix() const
Returns the Camera&#39;s modelingMatrix() (inverse of the view matrix).
Definition: Camera.hpp:169
vl::ref< RenderStateSet > mDummyStateSet
Definition: Renderer.hpp:109
void incrementRenderTick()
Increments the rendering tick count.
const T_Scalar & y() const
Definition: Vector3.hpp:90
Base class providing all the basic funtionalities of a Renderer.
bool Has_Occlusion_Query
Definition: OpenGL.cpp:94
int x() const
Definition: Viewport.hpp:65
const AABB & boundingBox() const
Returns the bounding box (not guaranteed to be up to date) that contains this Actor.
Definition: Actor.hpp:205
void setOcclusionQueryTick(unsigned tick)
For internal use only.
Definition: Actor.hpp:442
void applyRenderStates(const RenderStateSet *cur, const Camera *camera)
Applies a RenderStateSet to an OpenGLContext - Typically for internal use only.
#define NULL
Definition: OpenGLDefs.hpp:81
Manages most of the OpenGL rendering states responsible of the final aspect of the rendered objects...
Definition: Shader.hpp:1830
const Scissor * scissor() const
Returns the Scissor to be used when rendering an Actor.
Definition: Shader.hpp:2309
const vec3 & minCorner() const
Returns the corner of the AABB with the minimum x y z coordinates.
Definition: AABB.hpp:190
The RenderQueue class collects a list of RenderToken objects to be sorted and rendered.
Definition: RenderQueue.hpp:45
OpenGLContext * openglContext()
The OpenGLContext bound to a render target.
Definition: Framebuffer.hpp:66
Vector3< T_Scalar > getT() const
Definition: Matrix4.hpp:131
#define VL_CHECK_OGL()
Definition: OpenGL.hpp:156
unsigned occlusionQueryTick() const
For internal use only.
Definition: Actor.hpp:445
void set(bool red, bool green, bool blue, bool alpha)
Definition: Shader.hpp:1502
virtual void updateMatrices(bool cam_changed, bool transf_changed, const GLSLProgram *glsl_program, const Camera *camera, const Transform *transform)
Update matrices of the current GLSLProgram, if glsl_program == NULL then fixed function pipeline is a...
bool isInside(const vec3 &p, bool clipx, bool clipy, bool clipz) const
Returns true if the given point is inside the AABB.
Definition: AABB.cpp:122
ColorMask * gocColorMask()
Definition: Shader.cpp:109
RenderStateSet * getRenderStateSet()
Definition: Shader.hpp:2235
int occlusionThreshold() const
The number of pixels visible for an actor to be considered occluded (default = 0) ...
const RenderToken * at(int i) const
Definition: RenderQueue.hpp:57
const T_Scalar & x() const
Definition: Vector3.hpp:89
void set(bool depthmask)
Definition: Shader.hpp:508
void setWrappedRenderer(Renderer *renderer)
The renderer to be wrapped by this occlusion culling renderer.
void resetRenderStates()
Resets all the interanal render-states-tables - For internal use only.
Represents a virtual camera defining, among other things, the point of view from which scenes can be ...
Definition: Camera.hpp:50
const AABB & boundingBox() const
Returns the bounding box of a Renderable without recomputing the bounds if dirty. ...
Definition: Renderable.hpp:151
The Scissor class wraps the OpenGL function glScissor(), see http://www.opengl.org/sdk/docs/man/xhtml...
Definition: Scissor.hpp:47
const GLSLProgram * glslProgram() const
Returns the GLSLProgram associated to a Shader (if any)
Definition: Shader.hpp:2194
void enable(const Viewport *viewport) const
Enables the scissor test on the area specified by scissorRect() clipped against the given Viewport...
Definition: Scissor.hpp:61
#define VL_CHECK(expr)
Definition: checks.hpp:73
DepthMask * gocDepthMask()
Definition: Shader.cpp:101
void enable(EEnable capability)
Definition: Shader.hpp:2158
unsigned int enableMask() const
Enable mask used to enable/disable the rendering of matching Actors.
The Framebuffer class defines an abstract &#39;surface&#39; where OpenGL can render into. ...
Definition: Framebuffer.hpp:49
void dispatchOnRendererStarted()
Dispatches the onRendererStarted() event to the registered RenderEventCallback objects.
void set(float factor, float units)
Definition: Shader.hpp:979
If enabled, cull polygons based on their winding in window coordinates, see also CullFace.
void render_pass2(const RenderQueue *in_render_queue, Camera *camera)
Performs a new set of occlusion culling queries to be tested the next frame.