Developer Documentation
DepthPeeling.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 #include <ACG/GL/acg_glew.hh>
45 
46 #include "DepthPeeling.hh"
47 
50 
51 
52 #include <ACG/GL/ShaderCache.hh>
53 #include <ACG/GL/GLError.hh>
54 #include <ACG/GL/ScreenQuad.hh>
55 
56 using namespace ACG;
57 
58 
59 // =================================================
60 // depth peeling shader modifier
61 
63 {
64 public:
65 
66 
68  {
69  _shader->addUniform("sampler2D g_DepthLayer");
70 
71  _shader->addOutput("float outDepth");
72  }
73 
74  void modifyFragmentBeginCode(QStringList* _code)
75  {
76  // compare current depth with previous layer
77  _code->push_back("float dp_prevDepth = texture(g_DepthLayer, sg_vScreenPos).x;");
78  _code->push_back("if (gl_FragCoord.z <= dp_prevDepth) discard;");
79  }
80 
81  void modifyFragmentEndCode(QStringList* _code)
82  {
83  _code->push_back("outFragment = vec4(sg_cColor.rgb * sg_cColor.a, sg_cColor.a);");
84  _code->push_back("outDepth = gl_FragCoord.z;");
85  }
86 
87  static PeelLayerModifier instance;
88 };
89 
90 
92 {
93 public:
94 
96  {
97  _shader->addOutput("float outDepth");
98  }
99 
100  void modifyFragmentEndCode(QStringList* _code)
101  {
102  _code->push_back("outFragment = vec4(sg_cColor.rgb * sg_cColor.a, 1.0 - sg_cColor.a);");
103  _code->push_back("outDepth = gl_FragCoord.z;");
104  }
105 
106  static PeelInitModifier instance;
107 };
108 
109 // for dual depth peeling only
111 {
112 public:
113 
115  {
116  _shader->addUniform("sampler2D g_DepthLayer");
117  _shader->addUniform("sampler2D g_FrontLayer");
118 
119  // MRT: color + depth output + last layer (eventually)
120  _shader->addOutput("vec4 outDepth");
121  _shader->addOutput("vec4 outBackColor");
122  }
123 
124  void modifyFragmentBeginCode(QStringList* _code)
125  {
126  _code->push_back("float fragDepth = gl_FragCoord.z;");
127 
128 #ifdef __APPLE__
129  if(ACG::openGLVersion(3,3))
130  {
131  //on Apple systems with OpenGL 3.3 or higher, ht eGLSL version 330 is used no matter what we write
132  _code->push_back("vec2 depthLayer = texture(g_DepthLayer, sg_vScreenPos).xy;");
133  _code->push_back("vec4 forwardTemp = texture(g_FrontLayer, sg_vScreenPos);");
134  }
135  else
136 #endif
137  {
138  _code->push_back("vec2 depthLayer = texture2D(g_DepthLayer, sg_vScreenPos).xy;");
139  _code->push_back("vec4 forwardTemp = texture2D(g_FrontLayer, sg_vScreenPos);");
140  }
141  _code->push_back("outDepth = vec4(depthLayer, 0, 0);");
142  _code->push_back("outFragment = forwardTemp;");
143  _code->push_back("outBackColor = vec4(0,0,0,0);");
144 
145 
146  _code->push_back("float nearestDepth = -depthLayer.x;");
147  _code->push_back("float farthestDepth = depthLayer.y;");
148  _code->push_back("float alphaMultiplier = 1.0 - forwardTemp.w;");
149 
150 
151  _code->push_back("if (fragDepth < nearestDepth || fragDepth > farthestDepth) {");
152  _code->push_back("outDepth = vec4(-1,-1,-1,-1);");
153  _code->push_back("return;");
154  _code->push_back("}");
155 
156  _code->push_back("if (fragDepth > nearestDepth && fragDepth < farthestDepth) {");
157  _code->push_back("outDepth = vec4(-fragDepth, fragDepth, 0, 0);");
158  _code->push_back("return;");
159  _code->push_back("}");
160  }
161 
162 
163  void modifyFragmentEndCode(QStringList* _code)
164  {
165  _code->push_back("outDepth = vec4(-1,-1,-1,-1);");
166  _code->push_back("outFragment = forwardTemp;");
167 
168  _code->push_back("if (fragDepth == nearestDepth) {");
169  _code->push_back("outFragment.xyz += sg_cColor.rgb * sg_cColor.a * alphaMultiplier;");
170  _code->push_back("outFragment.w = 1.0 - alphaMultiplier * (1.0 - sg_cColor.a);");
171 
172 // _code->push_back("outFragment = vec4(alphaMultiplier,alphaMultiplier,alphaMultiplier,1);");
173 
174  _code->push_back("} else {");
175  _code->push_back("outBackColor += sg_cColor;");
176  _code->push_back("}");
177  }
178 
179  static PeelDualLayerModifier instance;
180 };
181 
183 {
184 public:
185  void modifyFragmentEndCode(QStringList* _code)
186  {
187  _code->push_back("outFragment = vec4(-gl_FragCoord.z, gl_FragCoord.z, 0, 0);");
188  }
189 
190  static PeelDualInitModifier instance;
191 };
192 
193 
194 PeelInitModifier PeelInitModifier::instance;
195 PeelLayerModifier PeelLayerModifier::instance;
196 PeelDualLayerModifier PeelDualLayerModifier::instance;
197 PeelDualInitModifier PeelDualInitModifier::instance;
198 
199 // internal shader-attribute flags
200 
201 #define RENDERFLAG_ALLOW_PEELING 1
202 
203 
204 // =================================================
205 
206 DepthPeeling::DepthPeeling()
207  : peelMode_(1), copyFrontDepth_(1), maxPeelCount_(20), peelBlend_(0), peelFinal_(0), peelQueryID_(0),
208 peelBlendDual_(0), peelFinalDual_(0)
209 {
210 }
211 
212 
213 DepthPeeling::~DepthPeeling()
214 {
215 }
216 
217 
218 
219 QString DepthPeeling::checkOpenGL()
220 {
221  //if(!ACG::compatibilityProfile())
222  // return QString("DepthPeeling render-plugin is nto yet compatible with core profile contexts.");
223  if (!ACG::openGLVersion(3, 2))
224  return QString("Insufficient OpenGL Version! OpenGL 3.2 or higher required");
225 
226  //no other extensions are necessary, as OpenGL version 3.2 includes them all in the spec
227 
228  return QString("");
229 }
230 
231 
232 void DepthPeeling::initializePlugin()
233 {
234  ACG::ShaderProgGenerator::setShaderDir(OpenFlipper::Options::shaderDirStr());
235 }
236 
237 void DepthPeeling::exit()
238 {
239  delete peelBlend_;
240  peelBlend_ = 0;
241 
242  delete peelFinal_;
243  peelFinal_ = 0;
244 
245  delete peelBlendDual_;
246  peelBlendDual_ = 0;
247 
248  delete peelFinalDual_;
249  peelFinalDual_ = 0;
250 
251  if (peelQueryID_)
252  glDeleteQueries(1, &peelQueryID_);
253  peelQueryID_ = 0;
254 
255  viewerRes_.clear();
256 }
257 
258 void DepthPeeling::slotModeChanged( QAction * _action)
259 {
260  // Prepare Picking Debugger Flag
261  if ( _action->text() == "Front to Back") {
262  peelMode_ = 0;
263  } else if ( _action->text() == "Dual") {
264  peelMode_ = 1;
265  } else {
266  std::cerr << "Error : optionHandling unable to find peeling mode!!! " << _action->text().toStdString() << std::endl;
267  peelMode_ = 1;
268  }
269 }
270 
271 void DepthPeeling::render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties)
272 {
273  // debugging utilities
274 // if (!dbgProg_)
275 // dbgProg_ = GLSL::loadProgram("DepthPeeling/screenquad.glsl", "DepthPeeling/dbg_shader.glsl");
276 
277 
278  // collect renderobjects
279  prepareRenderingPipeline(_glState, _properties.drawMode(), PluginFunctions::getSceneGraphRootNode());
280 
281 
282  if (peelMode_ == 0)
283  renderFrontPeeling(_glState, _properties);
284  else
285  renderDualPeeling(_glState, _properties);
286 
287  // restore common opengl state
288  // log window remains hidden otherwise
289  finishRenderingPipeline();
290 }
291 
292 
293 
294 
295 
297  Viewer::ViewerProperties& _properties)
298 {
299  const int numRenderObjects = getNumRenderObjects();
300 
301  // begin rendering
302  // find last transparent object
303  int lastPeeledObject = -1;
304 
305  for (int i = numRenderObjects - 1; i > lastPeeledObject; --i)
306  {
307  if ((sortedObjects_[i]->internalFlags_ & RENDERFLAG_ALLOW_PEELING) && sortedObjects_[i]->alpha < 0.99f)
308  lastPeeledObject = i;
309  }
310 
311  if (lastPeeledObject == -1)
312  {
313  // no transparent objects
314  for (int i = 0; i < numRenderObjects; ++i)
315  renderObject(sortedObjects_[i]);
316  }
317  else
318  {
319  // depth peeling code
320 
321  // make sure shaders and occlusion query are initialized
322  initDepthPeeling();
323 
324  // resize fbo as necessary
325  ViewerResources* viewRes = &viewerRes_[_properties.viewerId()];
326  viewRes->resize(false, (unsigned int)_glState->viewport_width(), (unsigned int)_glState->viewport_height());
327 
328 
329  // init MRT slots:
330  // RT0 - color blend texture
331  // RT1 - depth buffer copy
332  const GLenum depthTarget = GL_COLOR_ATTACHMENT0;
333  const GLenum colorTarget = GL_COLOR_ATTACHMENT1;
334  const GLenum colorBlendTarget = GL_COLOR_ATTACHMENT4;
335  GLenum peelLayerTargets[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
336 
337  const float clearDepth = 1.0f;
338 
339  // begin peeling
340  // draw first layer
341  // target depth buffer: depth0, front0
342  glViewport(0, 0, viewRes->width_, viewRes->height_);
343  glBindFramebuffer(GL_FRAMEBUFFER, viewRes->singleFbo_->getFboID());
344 
345  // allow color+depth write access
346  glDepthMask(1);
347  glColorMask(1,1,1,1);
348 
349  // clear color blend target
350  glDrawBuffer(colorBlendTarget);
351  glClearColor(_glState->clear_color()[0], _glState->clear_color()[1], _glState->clear_color()[2], 0);
352  glClear(GL_COLOR_BUFFER_BIT);
353 
354  // clear colors (front and back colors per pass)
355  glDrawBuffer(colorTarget);
356  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
357  glClear(GL_COLOR_BUFFER_BIT);
358 
359  // clear depths
360  glDrawBuffer(depthTarget);
361  glClearColor(clearDepth, 0.0f, 0.0f, 0.0f);
362  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
363 
364 
365  // 1. Pass: initialize depth values
366  // the init shader also writes the first front layer colors in accumulation buffer
367  peelLayerTargets[0] = colorBlendTarget;
368  peelLayerTargets[1] = depthTarget;
369  glDrawBuffers(2, peelLayerTargets); // write to MRT slots (color, depth)
370 
371  glDisable(GL_BLEND);
372  glDisable(GL_ALPHA_TEST);
373 
374  glEnable(GL_DEPTH_TEST);
375  glDepthFunc(GL_LESS);
376  glDisable(GL_CULL_FACE);
377 
378  for (int i = 0; i < numRenderObjects; ++i)
379  {
380 // if ((sortedObjects_[i]->internalFlags_ & RENDERFLAG_ALLOW_PEELING) && sortedObjects_[i]->alpha < 0.99f)
381  {
382  GLSL::Program* initProg = ShaderCache::getInstance()->getProgram(&sortedObjects_[i]->shaderDesc, PeelInitModifier::instance);
383 
384  if (initProg->getFragDataLocation("outFragment") != 0 || initProg->getFragDataLocation("outDepth") != 1)
385  {
386  initProg->bindFragDataLocation(0, "outFragment"); // color -> slot0
387  initProg->bindFragDataLocation(1, "outDepth"); // depth -> slot1
388  initProg->link();
389  }
390 
391  renderObject(sortedObjects_[i], initProg, true);
392  }
393  }
394 
395  // copy depth values to input depth buffer if requested
396  if (copyFrontDepth_)
397  copyDepthToBackBuffer(viewRes->singleDepthTex_[0], 1.0f);
398 
399  // peel layers, we start at index 1 instead of 0
400  // since the front layer is already initialized in
401  // depth buffer 0 and we want to extract the second one now
402 
403  for (int pass = 1; pass < maxPeelCount_; ++pass)
404  {
405  const int currID = pass & 1;
406  const int prevID = 1 - currID;
407  const int bufID = currID * 2;
408 
409  // peeling MRT slots:
410  // RT0 - color
411  // RT1 - depth buffer copy
412  const GLenum targetBuffer[2] = {colorTarget + bufID, depthTarget + bufID};
413 
414  // ---------------------------------------------------------------
415  // 1st peel next layer
416 
417  // clear color texture
418  glDrawBuffer(targetBuffer[0]);
419  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
420  glClear(GL_COLOR_BUFFER_BIT);
421  // clear depth texture
422  glDrawBuffer(targetBuffer[1]);
423  glClearColor(clearDepth, 0.0f, 0.0f, 0.0f);
424  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
425 
426 
427  glDrawBuffers(2, targetBuffer);
428 
429 
430  glDisable(GL_BLEND);
431  glEnable(GL_DEPTH_TEST);
432 
433  // count # passed fragments
434  glBeginQuery(GL_SAMPLES_PASSED, peelQueryID_);
435 
436 
437  // bind previous depth layer to texture unit 4
438  glActiveTexture(GL_TEXTURE4);
439  glBindTexture(GL_TEXTURE_2D, viewRes->singleDepthTex_[prevID]);
440 
441  // render scene
442  for (int k = 0; k < numRenderObjects; ++k)
443  {
444  if ((sortedObjects_[k]->internalFlags_ & RENDERFLAG_ALLOW_PEELING) && sortedObjects_[k]->alpha < 0.99f)
445  {
446  GLSL::Program* peelProg = ShaderCache::getInstance()->getProgram(&sortedObjects_[k]->shaderDesc, PeelLayerModifier::instance);
447 
448  if (peelProg->getFragDataLocation("outFragment") != 0 || peelProg->getFragDataLocation("outDepth") != 1)
449  {
450  peelProg->bindFragDataLocation(0, "outFragment");
451  peelProg->bindFragDataLocation(1, "outDepth");
452  peelProg->link();
453  }
454 
455  peelProg->use();
456  peelProg->setUniform("g_DepthLayer", 4);
457 
458  renderObject(sortedObjects_[k], peelProg, true);
459  }
460  }
461 
462  glEndQuery(GL_SAMPLES_PASSED);
463 
464 
465 
466  // ---------------------------------------------------------------
467  // 2nd underblend layer with current scene
468  // (fullscreen pass)
469  glDrawBuffer(colorBlendTarget);
470 
471  glDepthMask(1);
472  glColorMask(1,1,1,1);
473 
474  glDisable(GL_DEPTH_TEST);
475  glEnable(GL_BLEND);
476 
477  glBlendEquation(GL_FUNC_ADD);
478  ACG::GLState::blendFuncSeparate(GL_DST_ALPHA, GL_ONE,
479  GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
480 
481 
482  peelBlend_->use();
483  peelBlend_->setUniform("BlendTex", 0);
484 
485  glActiveTexture(GL_TEXTURE0);
486  glBindTexture(GL_TEXTURE_2D, viewRes->singleFrontTex_[currID]);
487 
488  ACG::ScreenQuad::draw(peelBlend_);
489 
490 
491  glDisable(GL_BLEND);
492 
493 
494 
495  GLuint passedSamples;
496  glGetQueryObjectuiv(peelQueryID_, GL_QUERY_RESULT, &passedSamples);
497  if (passedSamples == 0)
498  break;
499  }
500 
501 
502  // copy to back buffer
503  restoreInputFbo();
504 
505  glDepthMask(1);
506  glColorMask(1,1,1,1);
507 
508  glDisable(GL_DEPTH_TEST);
509 
510  peelFinal_->use();
511 
512 
513  ACG::Vec3f bkgColor;
514  bkgColor[0] = _properties.backgroundColor()[0];
515  bkgColor[1] = _properties.backgroundColor()[1];
516  bkgColor[2] = _properties.backgroundColor()[2];
517 
518  peelFinal_->setUniform("BkgColor", bkgColor);
519 
520  peelFinal_->setUniform("SceneTex", 0);
521 
522  glActiveTexture(GL_TEXTURE0);
523  glBindTexture(GL_TEXTURE_2D, viewRes->singleBlendTex_);
524 
525  ACG::ScreenQuad::draw(peelFinal_);
526 
528 
529 
530 
531 
532  // draw rest of scene
533  glEnable(GL_DEPTH_TEST);
534 
535 
536 // // draw rest of opaque objects
537 // for (int i = lastPeeledObject + 1; i < numRenderObjects; ++i)
538 // renderObject(sortedObjects_[i]);
539 
540  }
541 }
542 
543 
545 {
546  const int numRenderObjects = getNumRenderObjects();
547 
548  // begin rendering
549  // find last transparent object
550  int lastPeeledObject = -1;
551 
552  for (int i = numRenderObjects - 1; i > lastPeeledObject; --i)
553  {
554  if ((sortedObjects_[i]->internalFlags_ & RENDERFLAG_ALLOW_PEELING) && sortedObjects_[i]->alpha < 0.99f)
555  lastPeeledObject = i;
556  }
557 
558  if (0) //lastPeeledObject == -1)
559  {
560  // no transparent objects
561  for (int i = 0; i < numRenderObjects; ++i)
562  renderObject(sortedObjects_[i]);
563  }
564  else
565  {
566  // depth peeling code
567 
568  // make sure shaders and occlusion query are initialized
569  initDualDepthPeeling();
570 
571  // resize fbo as necessary
572  ViewerResources* viewRes = &viewerRes_[_properties.viewerId()];
573  viewRes->resize(true, (unsigned int)_glState->viewport_width(), (unsigned int)_glState->viewport_height());
574 
575 
576  // enable color/depth write access
577  glDepthMask(1);
578  glColorMask(1,1,1,1);
579 
580 
581  // clear render targets
582 // viewRes->dualFboACG_->bind();
583  glViewport(0, 0, _glState->viewport_width(), _glState->viewport_height());
584  glBindFramebuffer(GL_FRAMEBUFFER, viewRes->dualFbo_->getFboID());
585 
586  const GLenum depthTarget = GL_COLOR_ATTACHMENT0; // stores (-minDepth, maxDepth)
587  const GLenum colorTargets[] = {GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
588  const GLenum colorBlendTarget = GL_COLOR_ATTACHMENT6;
589 
590  // clear colors (front and back colors per pass)
591  glDrawBuffers(2, colorTargets);
592  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
593  glClear(GL_COLOR_BUFFER_BIT);
594 
595  // clear color blend target
596  glDrawBuffer(colorBlendTarget);
597  glClearColor(_glState->clear_color()[0], _glState->clear_color()[1], _glState->clear_color()[2], 0);
598  glClear(GL_COLOR_BUFFER_BIT);
599 
600  // clear depths
601  glDrawBuffer(depthTarget);
602  glClearColor(-1.0f, -1.0f, 0.0f, 0.0f);
603  glClear(GL_COLOR_BUFFER_BIT);
604 
605 
606  // 1. Pass: initialize depth values
607  // the init shader writes min/max depth values (-z, +z)
608  glEnable(GL_BLEND);
609  glBlendEquation(GL_MAX_EXT); // get min/max depth
610 
611  if(_glState->compatibilityProfile())
612  glDisable(GL_ALPHA_TEST);
613 
614  glEnable(GL_DEPTH_TEST);
615  glDepthFunc(GL_LESS);
616  glDisable(GL_CULL_FACE);
617 
618  for (int i = 0; i < numRenderObjects; ++i)
619  {
620  GLSL::Program* initProg = ShaderCache::getInstance()->getProgram(&sortedObjects_[i]->shaderDesc, PeelDualInitModifier::instance);
621 
622  renderObject(sortedObjects_[i], initProg, true);
623  }
624 
625 
626  // copy depth values of first front layer to input depth buffer if requested
627  if (copyFrontDepth_)
628  {
629  glDisable(GL_BLEND);
630  copyDepthToBackBuffer(viewRes->dualDepthTex_[0], -1.0f);
631  // dual peeling requires blending
632  glEnable(GL_BLEND);
633  }
634 
635  // 2. peeling passes + color accumulation
636 
637  int currID = 0; // ping-pong render targets
638 
639 //if (0){
640 
641  for (int pass = 1; 1 && pass < maxPeelCount_; ++pass)
642  {
643  currID = pass & 1;
644  const int prevID = 1 - currID;
645  const int bufID = currID * 3;
646 
647  GLenum targetBuffer[3];
648  targetBuffer[0] = GL_COLOR_ATTACHMENT0 + bufID;
649  targetBuffer[1] = GL_COLOR_ATTACHMENT1 + bufID;
650  targetBuffer[2] = GL_COLOR_ATTACHMENT2 + bufID;
651 // GLenum sourceBuffer[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
652 
653  // clear target colors
654  glDrawBuffers(2, targetBuffer + 1);
655  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
656  glClear(GL_COLOR_BUFFER_BIT);
657 
658  // clear target depth
659  glDrawBuffer(targetBuffer[0]);
660  glClearColor(-1.0f, -1.0f, 0.0f, 0.0f);
661  glClear(GL_COLOR_BUFFER_BIT);
662 
663 
664 
665  // Peel pass
666 
667  // set target
668  glBlendEquation(GL_MAX_EXT);
669  glDrawBuffers(3, targetBuffer); // shader writes to (depth_tex, front_color_tex, back_color_tex)
670 
671  // set texture source (provide previous layer)
672  // slot 4 - depth
673  // slot 5 - front color
674 
675  glActiveTexture(GL_TEXTURE5);
676  glBindTexture(GL_TEXTURE_2D, viewRes->dualFrontTex_[prevID]);
677 
678  glActiveTexture(GL_TEXTURE4);
679  glBindTexture(GL_TEXTURE_2D, viewRes->dualDepthTex_[prevID]);
680 
681  // restore active tex marker to default slot
682  glActiveTexture(GL_TEXTURE0);
683 
684  // peel scene
685  for (int i = 0; i < numRenderObjects; ++i)
686  {
687  GLSL::Program* peelProg = ShaderCache::getInstance()->getProgram(&sortedObjects_[i]->shaderDesc, PeelDualLayerModifier::instance);
688 
689  peelProg->use();
690  peelProg->setUniform("g_DepthLayer", 4);
691  peelProg->setUniform("g_FrontLayer", 5);
692 
693  // setup MRT
694  // outFragment -> front
695  // outDepth -> depth
696  // outBackColor -> back
697 
698  int locOutFrag = peelProg->getFragDataLocation("outFragment");
699  int locOutDepth = peelProg->getFragDataLocation("outDepth");
700  int locOutBackColor = peelProg->getFragDataLocation("outBackColor");
701 
702  if (locOutFrag != 1 ||
703  locOutDepth != 0 ||
704  locOutBackColor != 2)
705  {
706  // linking is slow; only link if necessary
707  peelProg->bindFragDataLocation(1, "outFragment");
708  peelProg->bindFragDataLocation(0, "outDepth");
709  peelProg->bindFragDataLocation(2, "outBackColor");
710 
711  peelProg->link();
712  }
713 
714 
715 
716  renderObject(sortedObjects_[i], peelProg, true);
717  }
718 
719 
720 
721 
722  // ----------------------
723  // debugging
724 /*
725  if (pass == 1)
726  {
727  dbgDrawTex(viewRes->dualFrontTex_[currID]);
728  return;
729  }
730 */
731  //
732 
733 
734 
735 
736  // blend back color into accumulation buffer
737  glDrawBuffer(colorBlendTarget);
738 
739  glBlendEquation(GL_FUNC_ADD);
740  ACG::GLState::blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
741 
742  // bind back color texture to slot 0
743  glActiveTexture(GL_TEXTURE0);
744  glBindTexture(GL_TEXTURE_2D, viewRes->dualBackTex_[currID]);
745 
746 
747  glBeginQuery(GL_SAMPLES_PASSED_ARB, peelQueryID_);
748 
749  peelBlendDual_->use();
750  peelBlendDual_->setUniform("BlendTex", 0);
751 
752  ACG::ScreenQuad::draw(peelBlendDual_);
753 
754  glEndQuery(GL_SAMPLES_PASSED_ARB);
755 
756 
757 
758  // termination check
759  GLuint passedSamples;
760  glGetQueryObjectuiv(peelQueryID_, GL_QUERY_RESULT, &passedSamples);
761  if (passedSamples == 0)
762  break;
763  }
764 
765 //}
766 
767  // Final pass: combine accumulated front and back colors
768  restoreInputFbo();
769 
770  glDepthMask(1);
771  glColorMask(1,1,1,1);
772 
773  glDisable(GL_DEPTH_TEST);
774  glDisable(GL_BLEND);
775 
776 
777  peelFinalDual_->use();
778 
779 
780  ACG::Vec3f bkgColor;
781  bkgColor[0] = _properties.backgroundColor()[0];
782  bkgColor[1] = _properties.backgroundColor()[1];
783  bkgColor[2] = _properties.backgroundColor()[2];
784 
785  peelFinalDual_->setUniform("BkgColor", bkgColor);
786 
787  // slot 0 - front colors
788  // slot 1 - back colors
789 
790  peelFinalDual_->setUniform("FrontSceneTex", 0);
791  peelFinalDual_->setUniform("BackSceneTex", 1);
792 
793  glActiveTexture(GL_TEXTURE1);
794  glBindTexture(GL_TEXTURE_2D, viewRes->dualBlendTex_);
795 
796  glActiveTexture(GL_TEXTURE0);
797  glBindTexture(GL_TEXTURE_2D, viewRes->dualFrontTex_[currID]);
798 
799 // drawProjQuad(peelFinalDual_);
800  ACG::ScreenQuad::draw(peelFinalDual_);
801 
802 
803  peelFinalDual_->disable();
804 
805 
806 
807 
808 
809  // ------------------------------------------
810  // debugging
811 
812 // dbgDrawTex(viewRes->dualDepthTex_[0]);
813 
814 
815  // ------------------------------------------
816 
817 
818 
819 
820 
821 
822 
823 
825 
826 
827 // // draw rest of scene
828 // glEnable(GL_DEPTH_TEST);
829 //
830 //
831 // // draw rest of opaque objects
832 // for (int i = lastPeeledObject + 1; i < numRenderObjects; ++i)
833 // renderObject(sortedObjects_[i]);
834 
835  }
836 }
837 
839 {
840  // do some more checks for error detection
841  if (!_renderObject->vertexDecl)
842  std::cout << "error: missing vertex declaration" << std::endl;
843  else
844  {
845  renderObjects_.push_back(*_renderObject);
846 
847 
848  RenderObject* p = &renderObjects_.back();
849 
850  if (!p->shaderDesc.numLights)
851  p->shaderDesc.numLights = numLights_;
852 
853  else if (p->shaderDesc.numLights < 0 || p->shaderDesc.numLights >= SG_MAX_SHADER_LIGHTS)
854  p->shaderDesc.numLights = 0;
855 
856  p->internalFlags_ = 0;
857 
858  // allow potential depth peeling only for compatible
859  // render states
860 
861  if (p->alpha < 1.0f &&
862  p->depthTest &&
863  p->depthWrite && (p->depthFunc == GL_LESS ||
864  p->depthFunc == GL_LEQUAL))
865  p->internalFlags_ = RENDERFLAG_ALLOW_PEELING;
866 
867 
868  // precompile shader
870 
871  }
872 }
873 
874 
875 
876 
877 DepthPeeling::ViewerResources::ViewerResources()
878 : width_(0), height_(0), singleBlendTex_(0), singleFbo_(0), dualBlendTex_(0), dualFbo_(0)
879 {
880  memset(singleDepthTex_, 0, sizeof(singleDepthTex_));
881  memset(singleFrontTex_, 0, sizeof(singleFrontTex_));
882 
883  memset(dualDepthTex_, 0, sizeof(dualDepthTex_));
884  memset(dualFrontTex_, 0, sizeof(dualFrontTex_));
885  memset(dualBackTex_, 0, sizeof(dualBackTex_));
886 }
887 
888 
889 DepthPeeling::ViewerResources::~ViewerResources()
890 {
891  delete singleFbo_;
892  delete dualFbo_;
893 }
894 
895 
896 void DepthPeeling::ViewerResources::resize(bool _dualPeeling, unsigned int _width, unsigned int _height)
897 {
898  if (!_width || !_height)
899  return;
900 
901  width_ = _width;
902  height_ = _height;
903 
904  if (!_dualPeeling)
905  {
906  if (!singleFbo_)
907  {
908  singleFbo_ = new ACG::FBO();
909 
910  singleFbo_->init();
911 
912  // texture formats:
913  // depth textures: store layer depth as float
914  // front color textures: store (r,g,b,a) colors as R8G8B8A8
915  // color blending and accumulation texture: (r,g,b,a) color as R8G8B8A8
916  GLint wrapmode;
917  if(ACG::openGLVersion(3,2))
918  wrapmode = GL_CLAMP_TO_EDGE;
919  else
920  wrapmode = GL_CLAMP;
921 
922  singleFbo_->attachTexture2D(GL_COLOR_ATTACHMENT0, width_, height_, GL_R32F, GL_RGB, wrapmode, GL_NEAREST, GL_NEAREST);
923  singleFbo_->attachTexture2D(GL_COLOR_ATTACHMENT1, width_, height_, GL_RGBA, GL_RGBA, wrapmode, GL_NEAREST, GL_NEAREST);
924 
925  singleFbo_->attachTexture2D(GL_COLOR_ATTACHMENT2, width_, height_, GL_R32F, GL_RGB, wrapmode, GL_NEAREST, GL_NEAREST);
926  singleFbo_->attachTexture2D(GL_COLOR_ATTACHMENT3, width_, height_, GL_RGBA, GL_RGBA, wrapmode, GL_NEAREST, GL_NEAREST);
927 
928  singleFbo_->attachTexture2D(GL_COLOR_ATTACHMENT4, width_, height_, GL_RGBA, GL_RGBA, wrapmode, GL_NEAREST, GL_NEAREST);
929 
930  singleFbo_->attachTexture2DDepth(width_, height_);
931 
932  singleDepthTex_[0] = singleFbo_->getAttachment(GL_COLOR_ATTACHMENT0);
933  singleDepthTex_[1] = singleFbo_->getAttachment(GL_COLOR_ATTACHMENT2);
934 
935  singleFrontTex_[0] = singleFbo_->getAttachment(GL_COLOR_ATTACHMENT1);
936  singleFrontTex_[1] = singleFbo_->getAttachment(GL_COLOR_ATTACHMENT3);
937 
938  singleBlendTex_ = singleFbo_->getAttachment(GL_COLOR_ATTACHMENT4);
939 
940 
941  singleFbo_->checkFramebufferStatus();
942 
944  }
945  else
946  singleFbo_->resize(_width, _height);
947 
948  }
949  else
950  {
951  // dual peeling render targets
952 
953  // fbo
954  if (!dualFbo_)
955  {
956  dualFbo_ = new ACG::FBO();
957 
958  dualFbo_->init();
959 
960  // texture formats:
961  // depth textures: store (min,max) depth as float2
962  // front+back color textures: store (r,g,b,a) colors as R8G8B8A8
963  // color blending and accumulation texture: (r,g,b) color as R8G8B8X8
964  GLint wrapmode;
965  if(ACG::openGLVersion(3,2))
966  {
967  wrapmode = GL_CLAMP_TO_EDGE;
968  }
969  else
970  wrapmode = GL_CLAMP;
971  dualFbo_->attachTexture2D(GL_COLOR_ATTACHMENT0, width_, height_, GL_RG32F, GL_RGB, wrapmode, GL_NEAREST, GL_NEAREST);
972  dualFbo_->attachTexture2D(GL_COLOR_ATTACHMENT1, width_, height_, GL_RGBA, GL_RGBA, wrapmode, GL_NEAREST, GL_NEAREST);
973  dualFbo_->attachTexture2D(GL_COLOR_ATTACHMENT2, width_, height_, GL_RGBA, GL_RGBA, wrapmode, GL_NEAREST, GL_NEAREST);
974 
975  dualFbo_->attachTexture2D(GL_COLOR_ATTACHMENT3, width_, height_, GL_RG32F, GL_RGB, wrapmode, GL_NEAREST, GL_NEAREST);
976  dualFbo_->attachTexture2D(GL_COLOR_ATTACHMENT4, width_, height_, GL_RGBA, GL_RGBA, wrapmode, GL_NEAREST, GL_NEAREST);
977  dualFbo_->attachTexture2D(GL_COLOR_ATTACHMENT5, width_, height_, GL_RGBA, GL_RGBA, wrapmode, GL_NEAREST, GL_NEAREST);
978 
979  dualFbo_->attachTexture2D(GL_COLOR_ATTACHMENT6, width_, height_, GL_RGB, GL_RGB, wrapmode, GL_NEAREST, GL_NEAREST);
980 
981  dualDepthTex_[0] = dualFbo_->getAttachment(GL_COLOR_ATTACHMENT0);
982  dualDepthTex_[1] = dualFbo_->getAttachment(GL_COLOR_ATTACHMENT3);
983 
984  dualFrontTex_[0] = dualFbo_->getAttachment(GL_COLOR_ATTACHMENT1);
985  dualFrontTex_[1] = dualFbo_->getAttachment(GL_COLOR_ATTACHMENT4);
986 
987  dualBackTex_[0] = dualFbo_->getAttachment(GL_COLOR_ATTACHMENT2);
988  dualBackTex_[1] = dualFbo_->getAttachment(GL_COLOR_ATTACHMENT5);
989 
990  dualBlendTex_ = dualFbo_->getAttachment(GL_COLOR_ATTACHMENT6);
991 
992 
993  dualFbo_->checkFramebufferStatus();
994 
996  }
997  else
998  dualFbo_->resize(_width, _height);
999 
1000  }
1001 
1002 
1003  glBindFramebuffer(GL_FRAMEBUFFER, 0);
1004 
1006 }
1007 
1009 {
1010  // check if already initialized
1011  if (peelBlend_ && peelFinal_ && peelQueryID_)
1012  return;
1013 
1014  // register shader modifiers
1015  ShaderProgGenerator::registerModifier(&PeelInitModifier::instance);
1016  ShaderProgGenerator::registerModifier(&PeelLayerModifier::instance);
1017 
1018  // load intermediate blending and final shader
1019 #ifdef __APPLE__
1020  if(ACG::openGLVersion(3,3))
1021  {
1022  if (!peelBlend_)
1023  peelBlend_ = GLSL::loadProgram("DepthPeeling/screenquad_330.glsl", "DepthPeeling/blend_330.glsl");
1024 
1025  if (!peelFinal_)
1026  peelFinal_ = GLSL::loadProgram("DepthPeeling/screenquad_330.glsl", "DepthPeeling/final_330.glsl");
1027  }
1028  else
1029 #endif
1030  {
1031  if (!peelBlend_)
1032  peelBlend_ = GLSL::loadProgram("DepthPeeling/screenquad.glsl", "DepthPeeling/blend.glsl");
1033 
1034  if (!peelFinal_)
1035  peelFinal_ = GLSL::loadProgram("DepthPeeling/screenquad.glsl", "DepthPeeling/final.glsl");
1036  }
1037 
1038  // occ query id
1039  if (!peelQueryID_)
1040  glGenQueries(1, &peelQueryID_);
1041 
1043 }
1044 
1046 {
1047  // check if already initialized
1048  if (peelBlendDual_ && peelFinalDual_ && peelQueryID_)
1049  return;
1050 
1051  // register shader modifiers
1052  ShaderProgGenerator::registerModifier(&PeelDualInitModifier::instance);
1053  ShaderProgGenerator::registerModifier(&PeelDualLayerModifier::instance);
1054 
1055  // load intermediate blending and final shader
1056 #ifdef __APPLE__ //this is fugly, pimpl pattern would be much appreciated
1057  if(ACG::openGLVersion(3,3))
1058  {
1059  if(!peelBlendDual_)
1060  peelBlendDual_ = GLSL::loadProgram("DepthPeeling/screenquad_330.glsl", "DepthPeeling/blend_dual_330.glsl");
1061  if (!peelFinalDual_)
1062  peelFinalDual_ = GLSL::loadProgram("DepthPeeling/screenquad_330.glsl", "DepthPeeling/final_dual_330.glsl");
1063  }
1064  else
1065 #endif
1066  {
1067  if(!peelBlendDual_)
1068  peelBlendDual_ = GLSL::loadProgram("DepthPeeling/screenquad.glsl", "DepthPeeling/blend_dual.glsl");
1069  if (!peelFinalDual_)
1070  peelFinalDual_ = GLSL::loadProgram("DepthPeeling/screenquad.glsl", "DepthPeeling/final_dual.glsl");
1071  }
1072 
1073  // occ query id
1074  if (!peelQueryID_)
1075  glGenQueries(1, &peelQueryID_);
1076 
1078 }
1079 
1080 QString DepthPeeling::renderObjectsInfo( bool _outputShaderInfo )
1081 {
1082  QString infoString;
1083 
1084  ACG::ShaderModifier* availableMods[4] =
1085  {
1086  &PeelInitModifier::instance, &PeelLayerModifier::instance,
1087  &PeelDualInitModifier::instance, &PeelDualLayerModifier::instance
1088  };
1089 
1090 
1091  // write modified shaders for init and peel passes
1092 
1093  infoString += "PeelInit:\n\n\n";
1094 
1095  std::vector<ACG::ShaderModifier*> mods;
1096  mods.push_back(availableMods[peelMode_*2]);
1097 
1098  infoString += dumpCurrentRenderObjectsToString(&sortedObjects_[0],_outputShaderInfo, &mods);
1099 
1100 
1101  infoString += "\n\n-----------------------------------------------\n\n\n\n";
1102  infoString += "PeelLayer:\n\n\n";
1103 
1104  mods[0] = availableMods[peelMode_*2 + 1];
1105 
1106  infoString += dumpCurrentRenderObjectsToString(&sortedObjects_[0],_outputShaderInfo, &mods);
1107 
1108  return infoString;
1109 }
1110 
1111 
1112 //
1113 // void DepthPeeling::dbgDrawTex( GLuint _texID )
1114 // {
1115 // glBindFramebuffer(GL_FRAMEBUFFER, 0);
1116 // glDrawBuffer(GL_BACK);
1117 // glClearColor(0,0,0,0);
1118 // glClear(GL_COLOR_BUFFER_BIT);
1119 //
1120 //
1121 // glDepthMask(1);
1122 // glColorMask(1,1,1,1);
1123 //
1124 // glDisable(GL_DEPTH_TEST);
1125 // glDisable(GL_BLEND);
1126 //
1127 // dbgProg_->use();
1128 //
1129 // dbgProg_->setUniform("Tex", 0);
1130 //
1131 // glActiveTexture(GL_TEXTURE0);
1132 // glBindTexture(GL_TEXTURE_2D, _texID);
1133 //
1134 // drawProjQuad(dbgProg_);
1135 //
1136 // dbgProg_->disable();
1137 // }
1138 //
1139 
1140 
1141 
1142 
static void blendFuncSeparate(GLenum _srcRGB, GLenum _dstRGB, GLenum _srcAlpha, GLenum _dstAlpha)
replaces glBlendFuncSeparate, supports locking
Definition: GLState.cc:1621
void modifyFragmentIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the fragment shader.
Definition: DepthPeeling.cc:95
Definition: FBO.hh:71
void addOutput(const QString &_output)
Add one GLSL output specifier.
static void draw(GLSL::Program *_prog=0)
Draw the screen quad.
Definition: ScreenQuad.cc:138
void use()
Enables the program object for using.
Definition: GLSLShader.cc:345
int viewport_width() const
get viewport width
Definition: GLState.hh:822
Namespace providing different geometric functions concerning angles.
void initDepthPeeling()
Allocate framebuffers and load shaders for depth-peeling.
GLenum depthFunc
GL_LESS, GL_LEQUAL, GL_GREATER ..
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node
void drawMode(ACG::SceneGraph::DrawModes::DrawMode _mode)
set draw mode (No test if this mode is available!)
void modifyFragmentEndCode(QStringList *_code)
Append code the the fragment shader.
ShaderGenDesc shaderDesc
Drawmode and other shader params.
int getFragDataLocation(const char *_name)
Get location of the fragment data output.
Definition: GLSLShader.cc:724
GLuint getFboID()
return opengl id
Definition: FBO.cc:604
unsigned int internalFlags_
may be used internally by the renderer
unsigned int width_
viewer window width
void glCheckErrors()
Definition: GLError.hh:96
void modifyFragmentBeginCode(QStringList *_code)
Append code the the fragment shader.
Definition: DepthPeeling.cc:74
void modifyFragmentEndCode(QStringList *_code)
Append code the the fragment shader.
Definition: DepthPeeling.cc:81
GLSL::PtrProgram loadProgram(const char *vertexShaderFile, const char *tessControlShaderFile, const char *tessEvaluationShaderFile, const char *geometryShaderFile, const char *fragmentShaderFile, const GLSL::StringList *macros, bool verbose)
Definition: GLSLShader.cc:1076
void initDualDepthPeeling()
Allocate framebuffers and load shaders for dual-depth-peeling.
GLSL program class.
Definition: GLSLShader.hh:211
static void setShaderDir(QString _dir)
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
Definition: ShaderCache.cc:84
Collection of framebuffers for each viewport.
QString renderObjectsInfo(bool _outputShaderInfo)
Return a qstring of the current render objects.
int viewport_height() const
get viewport height
Definition: GLState.hh:824
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
Definition: ShaderCache.cc:102
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:385
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition: gl.cc:129
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
void modifyFragmentIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the fragment shader.
Definition: DepthPeeling.cc:67
void addUniform(QString _uniform, QString _comment="")
Add one GLSL uniform specifier.
ACG::Vec4f backgroundColor()
Get current background color.
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: GLState.hh:307
unsigned int height_
viewer window height
void bindFragDataLocation(unsigned int _index, const char *_name)
Bind fragment output data to name.
Definition: GLSLShader.cc:692
void modifyFragmentIO(ShaderGenerator *_shader)
Add your own inputs/outputs to the fragment shader.
static unsigned int registerModifier(ShaderModifier *_modifier)
Shader modifiers have to be registered before they can be used. They also must remain allocated for t...
int viewerId()
Get the id of the viewer this viewerproperties belongs to.
void modifyFragmentBeginCode(QStringList *_code)
Append code the the fragment shader.
void renderDualPeeling(ACG::GLState *_glState, Viewer::ViewerProperties &_properties)
peel the scene with dual depth peeling, two layers per pass
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:98
void link()
Links the shader objects to the program.
Definition: GLSLShader.cc:326
void addRenderObject(ACG::RenderObject *_renderObject)
overide addRenderObject function to include OIT check
void modifyFragmentEndCode(QStringList *_code)
Append code the the fragment shader.
const Vec4f & clear_color() const
get background color
Definition: GLState.hh:921
void modifyFragmentEndCode(QStringList *_code)
Append code the the fragment shader.
void renderFrontPeeling(ACG::GLState *_glState, Viewer::ViewerProperties &_properties)
peel the scene from front to back, one layer per pass