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