Developer Documentation
Loading...
Searching...
No Matches
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
55const unsigned int SSAOPlugin::numSamples_ = 32;
56
57
58SSAOPlugin::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
68SSAOPlugin::~SSAOPlugin()
69{
70
71}
72
73QString 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
99void SSAOPlugin::initializePlugin()
100{
101 memset(shaders_, 0, sizeof(shaders_));
102 memset(programs_, 0, sizeof(programs_));
103
104 randomVecTex_ = 0;
105
107}
108
110
112{
113 for (unsigned int i = 0; i < numSamples_; ++i)
114 {
115 ACG::Vec3f r; // get 3 random floats in [-0.5, 0.5]
116 for (int k = 0; k < 3; ++k)
117 {
118 unsigned int x = (rand()*rand()*rand()) & RAND_MAX;
119 r[k] = float(x) / float(RAND_MAX); // [0, 1]
120 r[k] -= 0.5f;
121 }
122 // sphere to hemisphere
123 r[2] = fabsf(r[2]);
124
125 r.normalize();
126
127 // more samples near the fragment
128 // compute a sample distance accordingly
129 float d = float(i+1) / float(numSamples_);
130 d *= d;
131 if (d < 0.1f) d = 0.1f;
132
133 r *= d;
134
135 samplingKernel_[i] = r;
136 }
137}
138
140
141void SSAOPlugin::exit()
142{
144}
145
147
148QString SSAOPlugin::rendererName() {
149 return QString("SSAO Renderer");
150}
151
153
154void SSAOPlugin::supportedDrawModes(ACG::SceneGraph::DrawModes::DrawMode& _mode)
155{
157}
158
160
161void 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_);
210 // texture access: clamped
211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
212 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
213 // filter: linear
214 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
215 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
216 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, p->glWidth_, p->glHeight_, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
217
218 // downsampled render textures
219 // format: R32F
220 for (int i = 0; i < 2; ++i)
221 {
222 glGenTextures(1, i ? (&p->downsampledTex_) : (&p->downsampledTmpTex_));
223 ACG::GLState::bindTexture(GL_TEXTURE_2D, i ? (p->downsampledTex_) : (p->downsampledTmpTex_));
224 // texture access: clamped
225 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
227 // filter: linear
228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
230 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, p->rtDownWidth_, p->rtDownHeight_, 0, GL_RGB, GL_FLOAT, 0);
231 }
232
233 glGenTextures(1, &p->occlusionTex_);
234 ACG::GLState::bindTexture(GL_TEXTURE_2D, p->occlusionTex_);
235 // texture access: clamped
236 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
238 // filter: linear
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
241 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, p->glWidth_, p->glHeight_, 0, GL_RGB, GL_FLOAT, 0);
242
243 // end of texture creation
244 ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
245
247
248 // create depth render buffer
249 glGenRenderbuffers(1, &p->depthSSAORenderBuf_);
250 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, p->depthSSAORenderBuf_);
251 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, p->glWidth_, p->glHeight_);
252 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
253
254 // initialize the fbo
255 glGenFramebuffers(1, &p->ssaoFbo_);
256 ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, p->ssaoFbo_);
257
258 // color_attachment order:
259 // scene color, depth, scene normals, occlusion
260 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, p->depthBufTex_, 0);
261 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, p->sceneNormalTex_, 0);
262 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_2D, p->occlusionTex_, 0);
263 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, p->depthSSAORenderBuf_);
264
265 GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
266 if(fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
267 printf("SSAO Plugin: ssaoFbo failed to initialize\n");
268
269
270 glGenFramebuffers(1, &p->sceneFbo_);
271 ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, p->sceneFbo_);
272 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, p->sceneBufTex_, 0);
273
274 if (p->rtSceneWidth_ > p->rtWidth_ || p->rtSceneHeight_ > p->rtHeight_)
275 {
276 // use new depth buffer for multisampling
277 glGenRenderbuffers(1, &p->depthSceneRenderBuf_);
278 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, p->depthSceneRenderBuf_);
279 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, p->rtSceneWidth_, p->rtSceneHeight_);
280 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
281
282 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, p->depthSceneRenderBuf_);
283 }
284 else
285 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, p->depthSSAORenderBuf_);
286
287 fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
288 if(fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
289 printf("SSAO Plugin: sceneFbo failed to initialize\n");
290
291
292 glGenFramebuffers(1, &p->blurFbo_);
293 ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, p->blurFbo_);
294 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, p->downsampledTex_, 0);
295 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, p->downsampledTmpTex_, 0);
296
297
298 fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
299 if(fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
300 printf("SSAO Plugin: blurFbo failed to initialize\n");
301
302
303 ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
304
305
306 // load shaders
307
308 const char* ShaderFiles[] = {"SSAO/init_vertex.glsl",
309 "SSAO/fullscreen_vertex.glsl",
310 "SSAO/init_fragment.glsl",
311 "SSAO/downsampling_fragment.glsl",
312 "SSAO/blur_fragment.glsl",
313 "SSAO/ssao_fragment.glsl",
314 "SSAO/final_fragment.glsl",
315 "SSAO/final_MSAA_vertex.glsl",
316 "SSAO/final_MSAA_fragment.glsl"};
317
318 for (int i = 0; i < 9; ++i)
319 {
320 QString shaderFile = OpenFlipper::Options::shaderDirStr() + QDir::separator() + QString(ShaderFiles[i]);
321
322#ifdef SSAO_SHADER_DEBUG_MODE
323 delete shaders_[i];
324#else
325 if (shaders_[i]) continue;
326#endif
327
328 if (i < 2 || i == 7) // first two are vertex shaders
329 shaders_[i] = GLSL::loadVertexShader(shaderFile.toUtf8());
330 else
331 shaders_[i] = GLSL::loadFragmentShader(shaderFile.toUtf8());
332
333 if (!shaders_[i])
334 {
335 log(LOGERR, QString(ShaderFiles[i]) + QString(" could not be loaded and compiled"));
336 return;
337 }
338 }
339
340 // all needed glprograms
341 for (int i = 0; i < 6; ++i)
342 {
343#ifndef SSAO_SHADER_DEBUG_MODE
344 if (!programs_[i])
345#endif
346 {
347 delete programs_[i];
348 programs_[i] = new GLSL::Program();
349 GLSL::Program* pr = programs_[i];
350
351 switch (i)
352 {
353 case PROG_INIT:
354 pr->attach(shaders_[0]);
355 pr->attach(shaders_[2]); break;
356
357 case PROG_DOWNSAMPLING:
358 pr->attach(shaders_[1]);
359 pr->attach(shaders_[3]); break;
360
361 case PROG_BLUR:
362 pr->attach(shaders_[1]);
363 pr->attach(shaders_[4]); break;
364
365 case PROG_SSAO:
366 pr->attach(shaders_[1]);
367 pr->attach(shaders_[5]); break;
368
369 case PROG_FINAL:
370 pr->attach(shaders_[1]);
371 pr->attach(shaders_[6]); break;
372
373 case PROG_FINAL_MSAA:
374 pr->attach(shaders_[7]);
375 pr->attach(shaders_[8]); break;
376 }
377
378 pr->link();
379 }
380 }
381
382 if (!randomVecTex_)
383 {
384 // random vector texture
385 glGenTextures(1, &randomVecTex_);
387 // texture access: wrapped
388 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
389 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
390 // filter: none
391 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
392 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
393
394 ACG::Vec4f randVecs[16];
395 for (int i = 0; i < 16; ++i)
396 {
397 ACG::Vec3f x;
398 for (int k = 0; k < 3; ++k)
399 x[k] = float(rand()) / float(RAND_MAX);
400
401 float theta = x[0] * 6.2831853f; // 2pi
402 float phi = x[1] * 6.2831853f;
403 randVecs[i][0] = sinf(phi);
404 randVecs[i][1] = cosf(phi);
405 randVecs[i][2] = sinf(theta);
406 randVecs[i][3] = cosf(theta);
407 }
408 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, 4, 4, 0, GL_RGBA, GL_FLOAT, randVecs);
409 }
410
411 ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
412
414}
415
417
419
420 for (unsigned int i = 0; i < sizeof(programs_) / sizeof(programs_[0]); ++i)
421 {
422 delete programs_[i]; programs_[i] = 0;
423 }
424
425 for (unsigned int i = 0; i < sizeof(shaders_) / sizeof(shaders_[0]); ++i)
426 {
427 delete shaders_[i];
428 shaders_[i] = 0;
429 }
430
431 if (randomVecTex_) glDeleteTextures(1, &randomVecTex_);
432 randomVecTex_ = 0;
433
434 // free all viewer specific resources
435 std::map<int, ViewerResources>::iterator resIt = viewerRes_.begin();
436 for (; resIt != viewerRes_.end(); ++resIt)
437 destroyResources(resIt->first);
438}
439
441
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
467void 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
486void 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
494void 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
527void SSAOPlugin::render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties)
528{
529 glPushAttrib(GL_ALL_ATTRIB_BITS);
530
531 const GLuint targetFbo = ACG::GLState::getFramebufferDraw();
532
533 int viewerId = _properties.viewerId();
534
535 ViewerResources* pViewer = &viewerRes_[viewerId];
536 pViewer->glWidth_ = _glState->viewport_width();
537 pViewer->glHeight_ = _glState->viewport_height();
538
539 if (_properties.multisampling())
540 {
541 if ((pViewer->glWidth_ * 2 != pViewer->rtSceneWidth_) || (pViewer->glHeight_ * 2 != pViewer->rtSceneHeight_))
542 reloadResources(viewerId, pViewer->glWidth_ * 2, pViewer->glHeight_ * 2);
543 }
544 else if ((pViewer->glWidth_ != pViewer->rtSceneWidth_) || (pViewer->glHeight_ != pViewer->rtSceneHeight_))
545 reloadResources(viewerId, pViewer->glWidth_, pViewer->glHeight_);
546
548
549 GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
550 GL_COLOR_ATTACHMENT1_EXT,
551 GL_COLOR_ATTACHMENT2_EXT,
552 GL_COLOR_ATTACHMENT3_EXT,
553 GL_COLOR_ATTACHMENT4_EXT,
554 GL_COLOR_ATTACHMENT5_EXT,
555 GL_COLOR_ATTACHMENT6_EXT};
556
557 // the farthest depth value possible in the depth buffer
558 const float maxDepth = 1000.0f;
559
560 GLint oldViewport[4];
561 glGetIntegerv(GL_VIEWPORT, oldViewport);
562
563 for (int i = 0; i < 6; ++i)
564 {
565 ACG::GLState::activeTexture(GL_TEXTURE0 + i);
566 ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
567 }
568
569 float texelSize[4] = {1.0f / float(pViewer->rtWidth_), 1.0f / float(pViewer->rtHeight_), 0.0f, 0.0f};
570
571
572 // ---------------------------------------------
573 // 1. render scene with standard materials:
574 glViewport(0, 0, pViewer->rtSceneWidth_, pViewer->rtSceneHeight_);
575
576 ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, pViewer->sceneFbo_);
577 ACG::GLState::drawBuffer(drawBuffers[0]); // scene buffer in render target 0
578 glClearColor(_glState->clear_color()[0], _glState->clear_color()[1], _glState->clear_color()[2], 1.f);
579
580 // NOTE: for some reason the early z pass optimization does not work here
581 // using the depth buffer from previous pass gives z fighting
582 // early z cull optimization settings:
583 // ACG::GLState::enable(GL_DEPTH_TEST);
584 // ACG::GLState::depthFunc(GL_LEQUAL);
585 // ACG::GLState::lockDepthFunc();
586 // glDepthMask(GL_FALSE); // disable z writing
587 // glClear(GL_COLOR_BUFFER_BIT);
588
589 // without early z cull:
590 ACG::GLState::enable(GL_DEPTH_TEST);
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);
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);
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
@ LOGERR
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
Definition GLState.cc:1507
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition GLState.cc:1911
int viewport_width() const
get viewport width
Definition GLState.hh:847
static void drawBuffers(GLsizei _n, const GLenum *_bufs)
replaces glDrawBuffers, supports locking
Definition GLState.cc:2091
static void activeTexture(GLenum _texunit)
replaces glActiveTexture, no locking support
Definition GLState.cc:1900
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition GLState.cc:1527
const Vec4f & clear_color() const
get background color
Definition GLState.hh:946
int viewport_height() const
get viewport height
Definition GLState.hh:849
static GLuint getFramebufferDraw()
get current draw framebuffer of a target
Definition GLState.cc:2117
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition GLState.cc:941
static void drawBuffer(GLenum _mode)
replaces glDrawBuffer, supports locking
Definition GLState.cc:2076
static void bindFramebuffer(GLenum _target, GLuint _framebuffer)
replaces glBindFramebuffer, supports locking
Definition GLState.cc:2132
GLSL program class.
int getUniformLocation(const char *_name)
Get location of the specified uniform.
void disable()
Resets to standard rendering pipeline.
void link()
Links the shader objects to the program.
void use()
Enables the program object for using.
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
void attach(PtrConstShader _shader)
Attaches a shader object to the program object.
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM > >().norm())
Definition Vector11T.hh:454
static const unsigned int numSamples_
number of samples
Definition SSAO.hh:212
GLuint randomVecTex_
random vector table for sample offset rotation
Definition SSAO.hh:209
void drawScenePass(ACG::GLState *_glState, Viewer::ViewerProperties &_properties, BaseNode *_sceneGraphRoot)
draw the current scene
Definition SSAO.cc:486
void destroyResources()
free all gl resources
Definition SSAO.cc:418
void reloadResources(int _viewerId, unsigned int _sceneTexWidth, unsigned int _sceneTexHeight)
reload gl resources
Definition SSAO.cc:161
ACG::Vec3f samplingKernel_[128]
ssao sampling kernel
Definition SSAO.hh:215
GLSL::Shader * shaders_[10]
shader resources
Definition SSAO.hh:193
void generateSamplingKernel()
computes a hemisphere sampling kernel in [0,1] range
Definition SSAO.cc:111
GLSL::Program * programs_[6]
shader programs
Definition SSAO.hh:206
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
int viewerId()
Get the id of the viewer this viewerproperties belongs to.
void drawMode(ACG::SceneGraph::DrawModes::DrawMode _mode)
set draw mode (No test if this mode is available!)
void multisampling(bool _state)
set multisampling on/off
DrawMode DEFAULT
use the default (global) draw mode and not the node's own.
Definition DrawModes.cc:72
void traverse_multipass(BaseNode *_node, Action &_action, const unsigned int &_pass)
bool checkExtensionSupported(const std::string &_extension)
Definition gl.cc:107
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition gl.cc:129
void glCheckErrors()
Definition GLError.hh:96
bool compatibilityProfile()
get opengl core profile setting
Definition gl.cc:171
GLSL::PtrFragmentShader loadFragmentShader(const char *name, const GLSL::StringList *macros, bool verbose)
Loads, compiles and installs a new vertex shader.
GLSL::PtrVertexShader loadVertexShader(const char *name, const GLSL::StringList *macros, bool verbose)
Loads, compiles and installs a new vertex shader.
int viewerId()
Return unique viewer id.
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node
GLuint depthSceneRenderBuf_
depth renderbuffer for sceneFbo
Definition SSAO.hh:163
GLuint depthBufTex_
depth buffer render target
Definition SSAO.hh:153
unsigned int rtHeight_
render target height
Definition SSAO.hh:145
GLuint downsampledTex_
downsampled depth render target
Definition SSAO.hh:169
unsigned int rtDownWidth_
downsampled rt width
Definition SSAO.hh:148
unsigned int rtSceneWidth_
scene render target width
Definition SSAO.hh:138
unsigned int rtDownHeight_
downsampled rt height
Definition SSAO.hh:150
unsigned int rtSceneHeight_
scene render target height
Definition SSAO.hh:140
GLuint downsampledTmpTex_
downsampled temp rt for intermediate results
Definition SSAO.hh:172
GLuint occlusionTex_
occlusion render target
Definition SSAO.hh:175
GLuint depthSSAORenderBuf_
depth renderbuffer for ssaoFbo
Definition SSAO.hh:160
GLuint sceneBufTex_
standard scene without a render target
Definition SSAO.hh:166
unsigned int glWidth_
viewer window width
Definition SSAO.hh:132
unsigned int glHeight_
viewer window height
Definition SSAO.hh:135
unsigned int rtWidth_
render target width
Definition SSAO.hh:143