Developer Documentation
SSAO.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 #include <ACG/GL/acg_glew.hh>
46 
47 #include "SSAO.hh"
50 #include <ACG/GL/GLError.hh>
51 
52 // shader debug mode triggers a shader reload after resizing the view window
53 //#define SSAO_SHADER_DEBUG_MODE
54 
55 const unsigned int SSAOPlugin::numSamples_ = 32;
56 
57 
58 SSAOPlugin::SSAOPlugin() :
59  randomVecTex_(0)
60 {
61  for (unsigned int i = 0; i < 10; ++i)
62  shaders_[i] = 0;
63 
64  for (unsigned int i = 0; i < 6; ++i)
65  programs_[i] = 0;
66 }
67 
68 SSAOPlugin::~SSAOPlugin()
69 {
70 
71 }
72 
73 QString SSAOPlugin::checkOpenGL()
74 {
76  return QString("SSAO rendering-plugin is not yet compatible with Core Profile contexts.");
77  if (!ACG::openGLVersion(3,2))
78  return QString("Insufficient OpenGL Version! OpenGL 3.2 or higher required");
79 
80  QString missing("");
81  if ( !ACG::checkExtensionSupported("GL_ARB_vertex_buffer_object") )
82  missing += "GL_ARB_vertex_buffer_object extension missing\n";
83 
84 #ifndef __APPLE__
85  if ( !ACG::checkExtensionSupported("GL_ARB_vertex_program") )
86  missing += "GL_ARB_vertex_program extension missing\n";
87 #endif
88 
89  if ( !ACG::checkExtensionSupported("GL_ARB_texture_float") )
90  missing += "GL_ARB_texture_float extension missing\n";
91 
92  if ( !ACG::checkExtensionSupported("GL_EXT_framebuffer_object") )
93  missing += "GL_EXT_framebuffer_object extension missing\n";
94 
95  return missing;
96 }
97 
98 
99 void SSAOPlugin::initializePlugin()
100 {
101  memset(shaders_, 0, sizeof(shaders_));
102  memset(programs_, 0, sizeof(programs_));
103 
104  randomVecTex_ = 0;
105 
106  generateSamplingKernel();
107 }
108 
110 
112 {
113  for (unsigned int i = 0; i < numSamples_; ++i)
114  {
115  ACG::Vec3f r; // get 3 random floats in [-0.5, 0.5]
116  for (int k = 0; k < 3; ++k)
117  {
118  unsigned int x = (rand()*rand()*rand()) & RAND_MAX;
119  r[k] = float(x) / float(RAND_MAX); // [0, 1]
120  r[k] -= 0.5f;
121  }
122  // sphere to hemisphere
123  r[2] = fabsf(r[2]);
124 
125  r.normalize();
126 
127  // more samples near the fragment
128  // compute a sample distance accordingly
129  float d = float(i+1) / float(numSamples_);
130  d *= d;
131  if (d < 0.1f) d = 0.1f;
132 
133  r *= d;
134 
135  samplingKernel_[i] = r;
136  }
137 }
138 
140 
141 void SSAOPlugin::exit()
142 {
143  destroyResources();
144 }
145 
147 
148 QString SSAOPlugin::rendererName() {
149  return QString("SSAO Renderer");
150 }
151 
153 
154 void SSAOPlugin::supportedDrawModes(ACG::SceneGraph::DrawModes::DrawMode& _mode)
155 {
157 }
158 
160 
161 void SSAOPlugin::reloadResources(int _viewerId, unsigned int _sceneTexWidth, unsigned int _sceneTexHeight)
162 {
163  ViewerResources* p = &viewerRes_[_viewerId];
164 
165  // save window size
166  unsigned int vpWidth = p->glWidth_, vpHeight = p->glHeight_;
167  if (!p->glWidth_ || !p->glHeight_) return;
168 
169  destroyResources(_viewerId);
170 
171  p->glWidth_ = vpWidth;
172  p->glHeight_ = vpHeight;
173 
174  p->rtWidth_ = p->glWidth_;
175  p->rtHeight_ = p->glHeight_;
176 
177  p->rtDownWidth_ = p->rtWidth_ / 2;
178  p->rtDownHeight_ = p->rtHeight_ / 2;
179 
180  p->rtSceneWidth_ = _sceneTexWidth;
181  p->rtSceneHeight_ = _sceneTexHeight;
182 
183  // the scene texture contains the color result of a standard scene render pass
184  // format: R8G8B8A8
185  glGenTextures(1, &p->sceneBufTex_);
186  ACG::GLState::bindTexture(GL_TEXTURE_2D, p->sceneBufTex_);
187  // texture access: clamped
188  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
189  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
190  // filter: none (1 to 1 mapping in final pass)
191  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
192  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
193  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p->rtSceneWidth_, p->rtSceneHeight_, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
194 
195  // depth buf render texture
196  // format: R32F, maybe change to R16F if it works ok
197  glGenTextures(1, &p->depthBufTex_);
198  ACG::GLState::bindTexture(GL_TEXTURE_2D, p->depthBufTex_);
199  // texture access: clamped
200  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
201  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
202  // filter: linear
203  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
204  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
205  glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, p->glWidth_, p->glHeight_, 0, GL_RGB, GL_FLOAT, 0);
206 
207  // scene normals
208  glGenTextures(1, &p->sceneNormalTex_);
209  ACG::GLState::bindTexture(GL_TEXTURE_2D, p->sceneNormalTex_);
210  // texture access: clamped
211  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
212  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
213  // filter: linear
214  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
215  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
216  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, p->glWidth_, p->glHeight_, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
217 
218  // downsampled render textures
219  // format: R32F
220  for (int i = 0; i < 2; ++i)
221  {
222  glGenTextures(1, i ? (&p->downsampledTex_) : (&p->downsampledTmpTex_));
223  ACG::GLState::bindTexture(GL_TEXTURE_2D, i ? (p->downsampledTex_) : (p->downsampledTmpTex_));
224  // texture access: clamped
225  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
226  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
227  // filter: linear
228  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
229  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
230  glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, p->rtDownWidth_, p->rtDownHeight_, 0, GL_RGB, GL_FLOAT, 0);
231  }
232 
233  glGenTextures(1, &p->occlusionTex_);
234  ACG::GLState::bindTexture(GL_TEXTURE_2D, p->occlusionTex_);
235  // texture access: clamped
236  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
237  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
238  // filter: linear
239  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
240  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
241  glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, p->glWidth_, p->glHeight_, 0, GL_RGB, GL_FLOAT, 0);
242 
243  // end of texture creation
244  ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
245 
247 
248  // create depth render buffer
249  glGenRenderbuffers(1, &p->depthSSAORenderBuf_);
250  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, p->depthSSAORenderBuf_);
251  glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, p->glWidth_, p->glHeight_);
252  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
253 
254  // initialize the fbo
255  glGenFramebuffers(1, &p->ssaoFbo_);
256  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, p->ssaoFbo_);
257 
258  // color_attachment order:
259  // scene color, depth, scene normals, occlusion
260  glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, p->depthBufTex_, 0);
261  glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, p->sceneNormalTex_, 0);
262  glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_2D, p->occlusionTex_, 0);
263  glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, p->depthSSAORenderBuf_);
264 
265  GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
266  if(fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
267  printf("SSAO Plugin: ssaoFbo failed to initialize\n");
268 
269 
270  glGenFramebuffers(1, &p->sceneFbo_);
271  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, p->sceneFbo_);
272  glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, p->sceneBufTex_, 0);
273 
274  if (p->rtSceneWidth_ > p->rtWidth_ || p->rtSceneHeight_ > p->rtHeight_)
275  {
276  // use new depth buffer for multisampling
277  glGenRenderbuffers(1, &p->depthSceneRenderBuf_);
278  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, p->depthSceneRenderBuf_);
279  glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, p->rtSceneWidth_, p->rtSceneHeight_);
280  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
281 
282  glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, p->depthSceneRenderBuf_);
283  }
284  else
285  glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, p->depthSSAORenderBuf_);
286 
287  fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
288  if(fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
289  printf("SSAO Plugin: sceneFbo failed to initialize\n");
290 
291 
292  glGenFramebuffers(1, &p->blurFbo_);
293  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, p->blurFbo_);
294  glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, p->downsampledTex_, 0);
295  glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, p->downsampledTmpTex_, 0);
296 
297 
298  fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
299  if(fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
300  printf("SSAO Plugin: blurFbo failed to initialize\n");
301 
302 
303  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
304 
305 
306  // load shaders
307 
308  const char* ShaderFiles[] = {"SSAO/init_vertex.glsl",
309  "SSAO/fullscreen_vertex.glsl",
310  "SSAO/init_fragment.glsl",
311  "SSAO/downsampling_fragment.glsl",
312  "SSAO/blur_fragment.glsl",
313  "SSAO/ssao_fragment.glsl",
314  "SSAO/final_fragment.glsl",
315  "SSAO/final_MSAA_vertex.glsl",
316  "SSAO/final_MSAA_fragment.glsl"};
317 
318  for (int i = 0; i < 9; ++i)
319  {
320  QString shaderFile = OpenFlipper::Options::shaderDirStr() + QDir::separator() + QString(ShaderFiles[i]);
321 
322 #ifdef SSAO_SHADER_DEBUG_MODE
323  delete shaders_[i];
324 #else
325  if (shaders_[i]) continue;
326 #endif
327 
328  if (i < 2 || i == 7) // first two are vertex shaders
329  shaders_[i] = GLSL::loadVertexShader(shaderFile.toUtf8());
330  else
331  shaders_[i] = GLSL::loadFragmentShader(shaderFile.toUtf8());
332 
333  if (!shaders_[i])
334  {
335  log(LOGERR, QString(ShaderFiles[i]) + QString(" could not be loaded and compiled"));
336  return;
337  }
338  }
339 
340  // all needed glprograms
341  for (int i = 0; i < 6; ++i)
342  {
343 #ifndef SSAO_SHADER_DEBUG_MODE
344  if (!programs_[i])
345 #endif
346  {
347  delete programs_[i];
348  programs_[i] = new GLSL::Program();
349  GLSL::Program* pr = programs_[i];
350 
351  switch (i)
352  {
353  case PROG_INIT:
354  pr->attach(shaders_[0]);
355  pr->attach(shaders_[2]); break;
356 
357  case PROG_DOWNSAMPLING:
358  pr->attach(shaders_[1]);
359  pr->attach(shaders_[3]); break;
360 
361  case PROG_BLUR:
362  pr->attach(shaders_[1]);
363  pr->attach(shaders_[4]); break;
364 
365  case PROG_SSAO:
366  pr->attach(shaders_[1]);
367  pr->attach(shaders_[5]); break;
368 
369  case PROG_FINAL:
370  pr->attach(shaders_[1]);
371  pr->attach(shaders_[6]); break;
372 
373  case PROG_FINAL_MSAA:
374  pr->attach(shaders_[7]);
375  pr->attach(shaders_[8]); break;
376  }
377 
378  pr->link();
379  }
380  }
381 
382  if (!randomVecTex_)
383  {
384  // random vector texture
385  glGenTextures(1, &randomVecTex_);
386  ACG::GLState::bindTexture(GL_TEXTURE_2D, randomVecTex_);
387  // texture access: wrapped
388  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
389  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
390  // filter: none
391  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
392  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
393 
394  ACG::Vec4f randVecs[16];
395  for (int i = 0; i < 16; ++i)
396  {
397  ACG::Vec3f x;
398  for (int k = 0; k < 3; ++k)
399  x[k] = float(rand()) / float(RAND_MAX);
400 
401  float theta = x[0] * 6.2831853f; // 2pi
402  float phi = x[1] * 6.2831853f;
403  randVecs[i][0] = sinf(phi);
404  randVecs[i][1] = cosf(phi);
405  randVecs[i][2] = sinf(theta);
406  randVecs[i][3] = cosf(theta);
407  }
408  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, 4, 4, 0, GL_RGBA, GL_FLOAT, randVecs);
409  }
410 
411  ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
412 
414 }
415 
417 
419 
420  for (unsigned int i = 0; i < sizeof(programs_) / sizeof(programs_[0]); ++i)
421  {
422  delete programs_[i]; programs_[i] = 0;
423  }
424 
425  for (unsigned int i = 0; i < sizeof(shaders_) / sizeof(shaders_[0]); ++i)
426  {
427  delete shaders_[i];
428  shaders_[i] = 0;
429  }
430 
431  if (randomVecTex_) glDeleteTextures(1, &randomVecTex_);
432  randomVecTex_ = 0;
433 
434  // free all viewer specific resources
435  std::map<int, ViewerResources>::iterator resIt = viewerRes_.begin();
436  for (; resIt != viewerRes_.end(); ++resIt)
437  destroyResources(resIt->first);
438 }
439 
441 
442 void SSAOPlugin::destroyResources(int _viewerId)
443 {
444  ViewerResources* p = &viewerRes_[_viewerId];
445 
446  if (p->sceneFbo_) glDeleteFramebuffers(1, &p->sceneFbo_);
447  if (p->ssaoFbo_) glDeleteFramebuffers(1, &p->ssaoFbo_);
448  if (p->blurFbo_) glDeleteFramebuffers(1, &p->blurFbo_);
449 
450  if (p->depthSSAORenderBuf_) glDeleteRenderbuffers(1, &p->depthSSAORenderBuf_);
451 
452  if (p->depthSceneRenderBuf_) glDeleteRenderbuffers(1, &p->depthSceneRenderBuf_);
453 
454  if (p->sceneBufTex_) glDeleteTextures(1, &p->sceneBufTex_);
455  if (p->depthBufTex_) glDeleteTextures(1, &p->depthBufTex_);
456  if (p->downsampledTex_) glDeleteTextures(1, &p->downsampledTex_);
457  if (p->downsampledTmpTex_) glDeleteTextures(1, &p->downsampledTmpTex_);
458  if (p->occlusionTex_) glDeleteTextures(1, &p->occlusionTex_);
459  if (p->sceneNormalTex_) glDeleteTextures(1, &p->sceneNormalTex_);
460 
461  // zero out
462  *p = ViewerResources();
463 }
464 
466 
467 void SSAOPlugin::drawQuadProj(float x0, float y0, float w, float h)
468 {
469  // quad in projection space
470  // here only position are passed to GL
471  // tex-coords can be generated in a vertex-shader as follows
472  // uv = pos * (.5, -.5) + (.5, .5)
473 
474  glBegin(GL_QUADS);
475  {
476  glVertex2f(x0, y0);
477  glVertex2f(x0, y0-h);
478  glVertex2f(x0+w, y0-h);
479  glVertex2f(x0+w, y0);
480  }
481  glEnd();
482 }
483 
485 
486 void SSAOPlugin::drawScenePass(ACG::GLState* _glState, Viewer::ViewerProperties& _properties, BaseNode* _sceneGraphRoot)
487 {
488  ACG::SceneGraph::DrawAction action(_properties.drawMode(), *_glState, false);
489  ACG::SceneGraph::traverse_multipass(_sceneGraphRoot, action, *_glState, _properties.drawMode());
490 }
491 
493 
494 void SSAOPlugin::gaussianBlurPass(const ViewerResources* _pViewer, const float* _texelSize,
495  GLenum _targetAttachement, GLuint _srcTexture)
496 {
497  // standard deviation for gaussian blur filter
498  const float gaussStDev = 1.0f;
499 
500  ACG::GLState::drawBuffer(_targetAttachement);
501 
502  float gaussKernel[5];
503  float sum = 0.0f; // sum of kernel tabs
504  for (int i = 0; i < 5; ++i)
505  {
506  // 1 / (4 pi s^2) e^(-x^2 / s^2 ), constant factor useless here
507  gaussKernel[i] = powf(2.71828f, -float(i*i)*(_texelSize[0]*_texelSize[0] + _texelSize[1]*_texelSize[1]) /
508  (gaussStDev*gaussStDev));
509  sum += gaussKernel[i];
510  }
511  // normalize kernel
512  for (int i = 0; i < 5; ++i)
513  gaussKernel[i] /= sum;
514 
515  ACG::GLState::activeTexture(GL_TEXTURE0);
516  ACG::GLState::bindTexture(GL_TEXTURE_2D, _srcTexture);
517 
518  programs_[PROG_BLUR]->setUniform("Tex", 0);
519  programs_[PROG_BLUR]->setUniform("TexelSize", ACG::Vec2f(_texelSize));
520  programs_[PROG_BLUR]->setUniform("Kernel", gaussKernel, 5);
521 
522  drawQuadProj();
523 }
524 
526 
527 void SSAOPlugin::render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties)
528 {
529  glPushAttrib(GL_ALL_ATTRIB_BITS);
530 
531  const GLuint targetFbo = ACG::GLState::getFramebufferDraw();
532 
533  int viewerId = _properties.viewerId();
534 
535  ViewerResources* pViewer = &viewerRes_[viewerId];
536  pViewer->glWidth_ = _glState->viewport_width();
537  pViewer->glHeight_ = _glState->viewport_height();
538 
539  if (_properties.multisampling())
540  {
541  if ((pViewer->glWidth_ * 2 != pViewer->rtSceneWidth_) || (pViewer->glHeight_ * 2 != pViewer->rtSceneHeight_))
542  reloadResources(viewerId, pViewer->glWidth_ * 2, pViewer->glHeight_ * 2);
543  }
544  else if ((pViewer->glWidth_ != pViewer->rtSceneWidth_) || (pViewer->glHeight_ != pViewer->rtSceneHeight_))
545  reloadResources(viewerId, pViewer->glWidth_, pViewer->glHeight_);
546 
548 
549  GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
550  GL_COLOR_ATTACHMENT1_EXT,
551  GL_COLOR_ATTACHMENT2_EXT,
552  GL_COLOR_ATTACHMENT3_EXT,
553  GL_COLOR_ATTACHMENT4_EXT,
554  GL_COLOR_ATTACHMENT5_EXT,
555  GL_COLOR_ATTACHMENT6_EXT};
556 
557  // the farthest depth value possible in the depth buffer
558  const float maxDepth = 1000.0f;
559 
560  GLint oldViewport[4];
561  glGetIntegerv(GL_VIEWPORT, oldViewport);
562 
563  for (int i = 0; i < 6; ++i)
564  {
565  ACG::GLState::activeTexture(GL_TEXTURE0 + i);
566  ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
567  }
568 
569  float texelSize[4] = {1.0f / float(pViewer->rtWidth_), 1.0f / float(pViewer->rtHeight_), 0.0f, 0.0f};
570 
571 
572  // ---------------------------------------------
573  // 1. render scene with standard materials:
574  glViewport(0, 0, pViewer->rtSceneWidth_, pViewer->rtSceneHeight_);
575 
576  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, pViewer->sceneFbo_);
577  ACG::GLState::drawBuffer(drawBuffers[0]); // scene buffer in render target 0
578  glClearColor(_glState->clear_color()[0], _glState->clear_color()[1], _glState->clear_color()[2], 1.f);
579 
580  // NOTE: for some reason the early z pass optimization does not work here
581  // using the depth buffer from previous pass gives z fighting
582  // early z cull optimization settings:
583  // ACG::GLState::enable(GL_DEPTH_TEST);
584  // ACG::GLState::depthFunc(GL_LEQUAL);
585  // ACG::GLState::lockDepthFunc();
586  // glDepthMask(GL_FALSE); // disable z writing
587  // glClear(GL_COLOR_BUFFER_BIT);
588 
589  // without early z cull:
590  ACG::GLState::enable(GL_DEPTH_TEST);
591  ACG::GLState::depthFunc(GL_LESS);
592  glDepthMask(GL_TRUE);
593  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
594 
595  drawScenePass(_glState, _properties, sceneGraphRoot);
596 
597  ACG::GLState::unlockDepthFunc(); // unlock less-equal depth function
598 
599 
600  if (pViewer->rtSceneWidth_ != pViewer->glWidth_ || pViewer->rtSceneHeight_ != pViewer->glHeight_)
601  glViewport(0, 0, pViewer->glWidth_, pViewer->glHeight_);
602 
603  // ---------------------------------------------
604  // 2. init depth and normal targets
605  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, pViewer->ssaoFbo_);
606  ACG::GLState::enable(GL_DEPTH_TEST);
607  ACG::GLState::depthFunc(GL_LESS);
608  glDepthMask(GL_TRUE);
609 
610  // color attachment 0 and 1 stores the scene depth and normals
611  // clear first
612  ACG::GLState::drawBuffer(drawBuffers[0]);
613  glClearColor(maxDepth, 0.0f, 0.0f, 0.0f);
614  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
615 
616  ACG::GLState::drawBuffer(drawBuffers[1]);
617  glClearColor(0.5f, 0.5f, 0.0f, 0.0f);
618  glClear(GL_COLOR_BUFFER_BIT);
619 
620  ACG::GLState::drawBuffers(2, drawBuffers);
621 
622  programs_[PROG_INIT]->use();
623  drawScenePass(_glState, _properties, sceneGraphRoot);
624  programs_[PROG_INIT]->disable();
625 
626  // ---------------------------------------------
627  // 3. compute occlusion
628  ACG::GLState::drawBuffer(drawBuffers[2]); // occlusion buffer in render target 2
629  ACG::GLState::disable(GL_DEPTH_TEST);
630 
631  texelSize[0] = 1.0f / float(pViewer->rtWidth_);
632  texelSize[1] = 1.0f / float(pViewer->rtHeight_);
633 
634  programs_[PROG_SSAO]->use();
635  programs_[PROG_SSAO]->setUniform("TexelSize", ACG::Vec2f(texelSize[0], texelSize[1]));
636  programs_[PROG_SSAO]->setUniform("ScreenSize", ACG::Vec2f(pViewer->rtWidth_, pViewer->rtHeight_));
637  {
638  GLint location = programs_[PROG_SSAO]->getUniformLocation("Kernel");
639  glUniform3fv(location, 32, (GLfloat*)samplingKernel_);
640  }
641 
642  programs_[PROG_SSAO]->setUniform("RandTex", 3);
643  programs_[PROG_SSAO]->setUniform("NormalTex", 2);
644  programs_[PROG_SSAO]->setUniform("SceneTex", 1);
645  programs_[PROG_SSAO]->setUniform("DepthTex", 0);
646 
647  ACG::GLState::activeTexture(GL_TEXTURE3);
648  ACG::GLState::bindTexture(GL_TEXTURE_2D, randomVecTex_);
649 
650  ACG::GLState::activeTexture(GL_TEXTURE2);
651  ACG::GLState::bindTexture(GL_TEXTURE_2D, pViewer->sceneNormalTex_);
652 
653  ACG::GLState::activeTexture(GL_TEXTURE1);
654  ACG::GLState::bindTexture(GL_TEXTURE_2D, pViewer->sceneBufTex_);
655 
656  ACG::GLState::activeTexture(GL_TEXTURE0);
657  ACG::GLState::bindTexture(GL_TEXTURE_2D, pViewer->depthBufTex_);
658 
659  drawQuadProj();
660 
661 
662  ACG::GLState::activeTexture(GL_TEXTURE2);
663  ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
664 
665  // ---------------------------------------------
666  // 4. downsample the occlusion texture to 1/4 its size
667  glViewport(0, 0, pViewer->rtDownWidth_, pViewer->rtDownHeight_);
668 
669  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, pViewer->blurFbo_);
670  ACG::GLState::drawBuffer(drawBuffers[0]);
671  // disable depth testing and writing from now on
672  ACG::GLState::disable(GL_DEPTH_TEST);
673 
674  programs_[PROG_DOWNSAMPLING]->use();
675  programs_[PROG_DOWNSAMPLING]->setUniform("TexelSize", ACG::Vec2f(texelSize));
676 
677  // bind depth rt
678  ACG::GLState::activeTexture(GL_TEXTURE0);
679  ACG::GLState::bindTexture(GL_TEXTURE_2D, pViewer->occlusionTex_);
680  programs_[PROG_DOWNSAMPLING]->setUniform("Tex", 0);
681 
682  drawQuadProj();
683 
684  //-----------------------------------------
685  // 5. gaussian blur filter
686 
687  programs_[PROG_BLUR]->use();
688  programs_[PROG_BLUR]->setUniform("DepthTex", 1);
689  programs_[PROG_BLUR]->setUniform("EdgeBlur", _properties.multisampling() ? 0.3f : 0.0f);
690  ACG::GLState::activeTexture(GL_TEXTURE1);
691  ACG::GLState::bindTexture(GL_TEXTURE_2D, pViewer->depthBufTex_);
692 
693  // horizontal
694  texelSize[0] = 1.0f / float(pViewer->rtDownWidth_);
695  texelSize[1] = 0.0f;
696 
697  gaussianBlurPass(pViewer, texelSize, drawBuffers[1], pViewer->downsampledTex_);
698 
699  // vertical
700  texelSize[0] = 0.0f;
701  texelSize[1] = 1.0f / float(pViewer->rtDownHeight_);
702 
703  gaussianBlurPass(pViewer, texelSize, drawBuffers[0], pViewer->downsampledTmpTex_);
704  // blurred result in pViewer->downsampledTex_
705 
706  //-----------------------------------------
707  // 6. final pass, present result
708  glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
709  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, targetFbo);
710 
711  ACG::GLState::activeTexture(GL_TEXTURE1);
712  ACG::GLState::bindTexture(GL_TEXTURE_2D, pViewer->downsampledTex_);
713 
714  ACG::GLState::activeTexture(GL_TEXTURE0);
715  ACG::GLState::bindTexture(GL_TEXTURE_2D, pViewer->sceneBufTex_);
716 
717  GLSL::Program* finalProg = programs_[_properties.multisampling() ? PROG_FINAL_MSAA : PROG_FINAL];
718 
719  finalProg->use();
720  finalProg->setUniform("OcclusionTex", 1);
721  finalProg->setUniform("SceneTex", 0);
722  if (_properties.multisampling())
723  finalProg->setUniform("SceneTexelSize", ACG::Vec2f(1.0f / float(pViewer->rtSceneWidth_), 1.0f / float(pViewer->rtSceneHeight_)));
724 
725  drawQuadProj();
726 
727  finalProg->disable();
728  //-----------------------------------------
729 
730 
731  glPopAttrib();
732 }
733 
734 
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
Definition: GLState.cc:1507
unsigned int glHeight_
viewer window height
Definition: SSAO.hh:135
GLuint depthSceneRenderBuf_
depth renderbuffer for sceneFbo
Definition: SSAO.hh:163
static const unsigned int numSamples_
number of samples
Definition: SSAO.hh:212
void drawScenePass(ACG::GLState *_glState, Viewer::ViewerProperties &_properties, BaseNode *_sceneGraphRoot)
draw the current scene
Definition: SSAO.cc:486
void use()
Enables the program object for using.
Definition: GLSLShader.cc:345
unsigned int glWidth_
viewer window width
Definition: SSAO.hh:132
int viewport_width() const
get viewport width
Definition: GLState.hh:822
GLSL::PtrFragmentShader loadFragmentShader(const char *name, const GLSL::StringList *macros, bool verbose)
Loads, compiles and installs a new vertex shader.
Definition: GLSLShader.cc:983
GLuint downsampledTex_
downsampled depth render target
Definition: SSAO.hh:169
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition: GLState.cc:1868
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node
void drawMode(ACG::SceneGraph::DrawModes::DrawMode _mode)
set draw mode (No test if this mode is available!)
unsigned int rtDownHeight_
downsampled rt height
Definition: SSAO.hh:150
static void drawBuffers(GLsizei _n, const GLenum *_bufs)
replaces glDrawBuffers, supports locking
Definition: GLState.cc:2048
GLuint depthBufTex_
depth buffer render target
Definition: SSAO.hh:153
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:941
GLuint downsampledTmpTex_
downsampled temp rt for intermediate results
Definition: SSAO.hh:172
void traverse_multipass(BaseNode *_node, Action &_action, const unsigned int &_pass)
Definition: SceneGraph.hh:254
void glCheckErrors()
Definition: GLError.hh:96
static GLuint getFramebufferDraw()
get current draw framebuffer of a target
Definition: GLState.cc:2074
void attach(PtrConstShader _shader)
Attaches a shader object to the program object.
Definition: GLSLShader.cc:292
DrawMode DEFAULT
use the default (global) draw mode and not the node&#39;s own.
Definition: DrawModes.cc:72
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition: GLState.cc:1527
GLSL program class.
Definition: GLSLShader.hh:211
GLuint sceneBufTex_
standard scene without a render target
Definition: SSAO.hh:166
int viewport_height() const
get viewport height
Definition: GLState.hh:824
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:385
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition: gl.cc:129
void disable()
Resets to standard rendering pipeline.
Definition: GLSLShader.cc:355
unsigned int rtWidth_
render target width
Definition: SSAO.hh:143
GLuint depthSSAORenderBuf_
depth renderbuffer for ssaoFbo
Definition: SSAO.hh:160
GLuint occlusionTex_
occlusion render target
Definition: SSAO.hh:175
GLSL::PtrVertexShader loadVertexShader(const char *name, const GLSL::StringList *macros, bool verbose)
Loads, compiles and installs a new vertex shader.
Definition: GLSLShader.cc:969
unsigned int rtSceneHeight_
scene render target height
Definition: SSAO.hh:140
void drawQuadProj(float _x0=-1.0f, float _y0=1.0f, float _w=2.0f, float _h=2.0f)
draw a quad in projection space (only positions)
Definition: SSAO.cc:467
void multisampling(bool _state)
set multisampling on/off
void generateSamplingKernel()
computes a hemisphere sampling kernel in [0,1] range
Definition: SSAO.cc:111
bool checkExtensionSupported(const std::string &_extension)
Definition: gl.cc:107
unsigned int rtHeight_
render target height
Definition: SSAO.hh:145
unsigned int rtDownWidth_
downsampled rt width
Definition: SSAO.hh:148
int viewerId()
Get the id of the viewer this viewerproperties belongs to.
void compatibilityProfile(bool _enableCoreProfile)
Store opengl core profile setting.
Definition: gl.cc:166
void destroyResources()
free all gl resources
Definition: SSAO.cc:418
static void bindFramebuffer(GLenum _target, GLuint _framebuffer)
replaces glBindFramebuffer, supports locking
Definition: GLState.cc:2089
static void drawBuffer(GLenum _mode)
replaces glDrawBuffer, supports locking
Definition: GLState.cc:2033
unsigned int rtSceneWidth_
scene render target width
Definition: SSAO.hh:138
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:434
void link()
Links the shader objects to the program.
Definition: GLSLShader.cc:326
void reloadResources(int _viewerId, unsigned int _sceneTexWidth, unsigned int _sceneTexHeight)
reload gl resources
Definition: SSAO.cc:161
const Vec4f & clear_color() const
get background color
Definition: GLState.hh:921
static void activeTexture(GLenum _texunit)
replaces glActiveTexture, no locking support
Definition: GLState.cc:1857