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"
48 #include <OpenFlipper/common/GlobalOptions.hh>
49 #include <OpenFlipper/BasePlugin/PluginFunctions.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 {
75 if(!ACG::compatibilityProfile())
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
111 void SSAOPlugin::generateSamplingKernel()
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 {
156 _mode = ACG::SceneGraph::DrawModes::DEFAULT;
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
246 ACG::glCheckErrors();
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
413 ACG::glCheckErrors();
414 }
415
417
418 void SSAOPlugin::destroyResources() {
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
547 BaseNode* sceneGraphRoot = PluginFunctions::getSceneGraphRootNode();
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
ACG::GLState::enable
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
Definition: GLState.cc:1507
LOGERR
Definition: LoggingInterface.hh:96
SSAOPlugin::ViewerResources::glHeight_
unsigned int glHeight_
viewer window height
Definition: SSAO.hh:135
SSAOPlugin::ViewerResources::depthSceneRenderBuf_
GLuint depthSceneRenderBuf_
depth renderbuffer for sceneFbo
Definition: SSAO.hh:163
Viewer::ViewerProperties
Definition: ViewerProperties.hh:107
SSAOPlugin::ViewerResources::blurFbo_
GLuint blurFbo_
Definition: SSAO.hh:187
SSAOPlugin::numSamples_
static const unsigned int numSamples_
number of samples
Definition: SSAO.hh:212
SSAOPlugin::drawScenePass
void drawScenePass(ACG::GLState *_glState, Viewer::ViewerProperties &_properties, BaseNode *_sceneGraphRoot)
draw the current scene
Definition: SSAO.cc:486
SSAOPlugin::ViewerResources
Definition: SSAO.hh:127
ACG::GLState
Definition: GLState.hh:213
GLSL::Program::use
void use()
Enables the program object for using.
Definition: GLSLShader.cc:345
SSAOPlugin::ViewerResources::glWidth_
unsigned int glWidth_
viewer window width
Definition: SSAO.hh:132
ACG::GLState::viewport_width
int viewport_width() const
get viewport width
Definition: GLState.hh:822
GLSL::loadFragmentShader
GLSL::PtrFragmentShader loadFragmentShader(const char *name, const GLSL::StringList *macros, bool verbose)
Loads, compiles and installs a new vertex shader.
Definition: GLSLShader.cc:983
SSAOPlugin::ViewerResources::downsampledTex_
GLuint downsampledTex_
downsampled depth render target
Definition: SSAO.hh:169
GlobalOptions.hh
ACG::GLState::bindTexture
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition: GLState.cc:1868
PluginFunctions::getSceneGraphRootNode
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node
Definition: PluginFunctions.cc:959
Viewer::ViewerProperties::drawMode
void drawMode(ACG::SceneGraph::DrawModes::DrawMode _mode)
set draw mode (No test if this mode is available!)
Definition: ViewerProperties.cc:151
SSAOPlugin::ViewerResources::rtDownHeight_
unsigned int rtDownHeight_
downsampled rt height
Definition: SSAO.hh:150
OpenMesh::VectorT
Definition: Vector11T.hh:83
SSAOPlugin::ViewerResources::sceneFbo_
GLuint sceneFbo_
Definition: SSAO.hh:179
ACG::GLState::drawBuffers
static void drawBuffers(GLsizei _n, const GLenum *_bufs)
replaces glDrawBuffers, supports locking
Definition: GLState.cc:2048
SSAOPlugin::ViewerResources::depthBufTex_
GLuint depthBufTex_
depth buffer render target
Definition: SSAO.hh:153
SSAOPlugin::ViewerResources::ssaoFbo_
GLuint ssaoFbo_
Definition: SSAO.hh:183
ACG::GLState::depthFunc
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:941
SSAOPlugin::ViewerResources::downsampledTmpTex_
GLuint downsampledTmpTex_
downsampled temp rt for intermediate results
Definition: SSAO.hh:172
PluginFunctions.hh
ACG::SceneGraph::traverse_multipass
void traverse_multipass(BaseNode *_node, Action &_action, const unsigned int &_pass)
Definition: SceneGraph.hh:254
ACG::glCheckErrors
void glCheckErrors()
Definition: GLError.hh:96
ACG::GLState::getFramebufferDraw
static GLuint getFramebufferDraw()
get current draw framebuffer of a target
Definition: GLState.cc:2074
GLSL::Program::attach
void attach(PtrConstShader _shader)
Attaches a shader object to the program object.
Definition: GLSLShader.cc:292
ACG::SceneGraph::DrawAction
Definition: SceneGraph.hh:687
ACG::SceneGraph::DrawModes::DEFAULT
DrawMode DEFAULT
use the default (global) draw mode and not the node&#39;s own.
Definition: DrawModes.cc:72
ACG::GLState::disable
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition: GLState.cc:1527
GLSL::Program
GLSL program class.
Definition: GLSLShader.hh:211
SSAOPlugin::ViewerResources::sceneBufTex_
GLuint sceneBufTex_
standard scene without a render target
Definition: SSAO.hh:166
ACG::GLState::viewport_height
int viewport_height() const
get viewport height
Definition: GLState.hh:824
GLSL::Program::setUniform
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:385
ACG::openGLVersion
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition: gl.cc:129
SSAOPlugin::ViewerResources::sceneNormalTex_
GLuint sceneNormalTex_
Definition: SSAO.hh:157
ACG::SceneGraph::BaseNode
Definition: BaseNode.hh:104
GLSL::Program::disable
void disable()
Resets to standard rendering pipeline.
Definition: GLSLShader.cc:355
SSAOPlugin::ViewerResources::rtWidth_
unsigned int rtWidth_
render target width
Definition: SSAO.hh:143
SSAOPlugin::ViewerResources::depthSSAORenderBuf_
GLuint depthSSAORenderBuf_
depth renderbuffer for ssaoFbo
Definition: SSAO.hh:160
SSAOPlugin::ViewerResources::occlusionTex_
GLuint occlusionTex_
occlusion render target
Definition: SSAO.hh:175
ACG::SceneGraph::DrawModes::DrawMode
Specifies a DrawMode.
Definition: DrawModes.hh:288
GLSL::loadVertexShader
GLSL::PtrVertexShader loadVertexShader(const char *name, const GLSL::StringList *macros, bool verbose)
Loads, compiles and installs a new vertex shader.
Definition: GLSLShader.cc:969
SSAOPlugin::ViewerResources::rtSceneHeight_
unsigned int rtSceneHeight_
scene render target height
Definition: SSAO.hh:140
SSAOPlugin::drawQuadProj
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
Viewer::ViewerProperties::multisampling
void multisampling(bool _state)
set multisampling on/off
Definition: ViewerProperties.cc:292
SSAOPlugin::generateSamplingKernel
void generateSamplingKernel()
computes a hemisphere sampling kernel in [0,1] range
Definition: SSAO.cc:111
ACG::checkExtensionSupported
bool checkExtensionSupported(const std::string &_extension)
Definition: gl.cc:107
SSAOPlugin::ViewerResources::rtHeight_
unsigned int rtHeight_
render target height
Definition: SSAO.hh:145
SSAOPlugin::ViewerResources::rtDownWidth_
unsigned int rtDownWidth_
downsampled rt width
Definition: SSAO.hh:148
Viewer::ViewerProperties::viewerId
int viewerId()
Get the id of the viewer this viewerproperties belongs to.
Definition: ViewerProperties.cc:142
ACG::compatibilityProfile
void compatibilityProfile(bool _enableCoreProfile)
Store opengl core profile setting.
Definition: gl.cc:166
SSAOPlugin::destroyResources
void destroyResources()
free all gl resources
Definition: SSAO.cc:418
ACG::GLState::bindFramebuffer
static void bindFramebuffer(GLenum _target, GLuint _framebuffer)
replaces glBindFramebuffer, supports locking
Definition: GLState.cc:2089
ACG::GLState::drawBuffer
static void drawBuffer(GLenum _mode)
replaces glDrawBuffer, supports locking
Definition: GLState.cc:2033
SSAOPlugin::ViewerResources::rtSceneWidth_
unsigned int rtSceneWidth_
scene render target width
Definition: SSAO.hh:138
OpenMesh::VectorT::normalize
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:434
GLSL::Program::link
void link()
Links the shader objects to the program.
Definition: GLSLShader.cc:326
SSAOPlugin::reloadResources
void reloadResources(int _viewerId, unsigned int _sceneTexWidth, unsigned int _sceneTexHeight)
reload gl resources
Definition: SSAO.cc:161
ACG::GLState::clear_color
const Vec4f & clear_color() const
get background color
Definition: GLState.hh:921
ACG::GLState::activeTexture
static void activeTexture(GLenum _texunit)
replaces glActiveTexture, no locking support
Definition: GLState.cc:1857