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