1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkDualDepthPeelingPass.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #include "vtkDualDepthPeelingPass.h"
17 
18 #include "vtkAbstractVolumeMapper.h"
19 #include "vtkOpenGLFramebufferObject.h"
20 #include "vtkInformation.h"
21 #include "vtkInformationKey.h"
22 #include "vtkNew.h"
23 #include "vtkObjectFactory.h"
24 #include "vtkOpenGLActor.h"
25 #include "vtkOpenGLBufferObject.h"
26 #include "vtkOpenGLError.h"
27 #include "vtkOpenGLQuadHelper.h"
28 #include "vtkOpenGLRenderUtilities.h"
29 #include "vtkOpenGLRenderWindow.h"
30 #include "vtkOpenGLShaderCache.h"
31 #include "vtkOpenGLState.h"
32 #include "vtkOpenGLVertexArrayObject.h"
33 #include "vtkRenderer.h"
34 #include "vtkRenderState.h"
35 #include "vtkRenderTimerLog.h"
36 #include "vtkShaderProgram.h"
37 #include "vtkTextureObject.h"
38 #include "vtkTypeTraits.h"
39 
40 #include <algorithm>
41 
42 // Define to output details about each peel:
43 //#define DEBUG_PEEL
44 
45 // Define to output details about each frame:
46 //#define DEBUG_FRAME
47 
48 // Define to render the categorization of the initial volume-prepass pixel:
49 // - Pixels with no opaque or translucent geometry will be red.
50 // - Pixels with only opaque geometry will be green.
51 // - Pixels with only translucent geometry will be blue.
52 // - Pixels with both opaque and translucent geometry will be purple.
53 //#define DEBUG_VOLUME_PREPASS_PIXELS
54 
55 // Recent OSX/ATI drivers perform some out-of-order execution that's causing
56 // the dFdx/dFdy calls to be conditionally executed. Specifically, it looks
57 // like the early returns when the depth is not on a current peel layer
58 // (Peeling pass, VTK::PreColor::Impl hook) are moved before the dFdx/dFdy
59 // calls used to compute normals. Disable the early returns on apple for now, I
60 // don't think most GPUs really benefit from them anyway at this point.
61 #ifdef __APPLE__
62 #define NO_PRECOLOR_EARLY_RETURN
63 #endif
64 
65 using RenderEvent = vtkRenderTimerLog::ScopedEventLogger;
66 
67 #define TIME_FUNCTION(functionName) \
68   VTK_SCOPED_RENDER_EVENT(#functionName, this->Timer);
69 
70 vtkStandardNewMacro(vtkDualDepthPeelingPass)
71 vtkCxxSetObjectMacro(vtkDualDepthPeelingPass, VolumetricPass, vtkRenderPass)
72 
73 namespace
74 {
annotate(const std::string & str)75 void annotate(const std::string &str)
76 {
77   vtkOpenGLRenderUtilities::MarkDebugEvent(str);
78 }
79 }
80 
81 //------------------------------------------------------------------------------
PrintSelf(std::ostream & os,vtkIndent indent)82 void vtkDualDepthPeelingPass::PrintSelf(std::ostream &os, vtkIndent indent)
83 {
84   this->Superclass::PrintSelf(os, indent);
85 }
86 
87 //------------------------------------------------------------------------------
Render(const vtkRenderState * s)88 void vtkDualDepthPeelingPass::Render(const vtkRenderState *s)
89 {
90   VTK_SCOPED_RENDER_EVENT("vtkDualDepthPeelingPass::Render",
91                           s->GetRenderer()->GetRenderWindow()->GetRenderTimer());
92 
93   vtkOpenGLRenderWindow *renWin = static_cast<vtkOpenGLRenderWindow*>(
94         s->GetRenderer()->GetRenderWindow());
95 
96   this->State = renWin->GetState();
97 
98   // Setup vtkOpenGLRenderPass
99   this->PreRender(s);
100 
101   this->Initialize(s);
102   this->Prepare();
103 
104   if (this->IsRenderingVolumes())
105   {
106     this->PeelVolumesOutsideTranslucentRange();
107   }
108 
109 #ifndef DEBUG_VOLUME_PREPASS_PIXELS
110   while (!this->PeelingDone())
111   {
112     this->Peel();
113   }
114 #endif // DEBUG_VOLUME_PREPASS_PIXELS
115 
116   this->Finalize();
117 
118   this->PostRender(s);
119 }
120 
121 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * win)122 void vtkDualDepthPeelingPass::ReleaseGraphicsResources(vtkWindow* win)
123 {
124   if (this->VolumetricPass)
125   {
126     this->VolumetricPass->ReleaseGraphicsResources(win);
127   }
128   if (this->BlendHelper)
129   {
130     delete this->BlendHelper;
131     this->BlendHelper = nullptr;
132   }
133   if (this->BackBlendHelper)
134   {
135     delete this->BackBlendHelper;
136     this->BackBlendHelper = nullptr;
137   }
138   if (this->CopyColorHelper)
139   {
140     delete this->CopyColorHelper;
141     this->CopyColorHelper = nullptr;
142   }
143   if (this->CopyDepthHelper)
144   {
145     delete this->CopyDepthHelper;
146     this->CopyDepthHelper = nullptr;
147   }
148 
149   this->FreeGLObjects();
150 }
151 
152 //------------------------------------------------------------------------------
PreReplaceShaderValues(std::string & vertexShader,std::string & geometryShader,std::string & fragmentShader,vtkAbstractMapper * mapper,vtkProp * prop)153 bool vtkDualDepthPeelingPass::PreReplaceShaderValues(
154     std::string &vertexShader,
155     std::string &geometryShader,
156     std::string &fragmentShader,
157     vtkAbstractMapper *mapper,
158     vtkProp *prop)
159 {
160   switch (this->CurrentPeelType)
161   {
162     case vtkDualDepthPeelingPass::TranslucentPeel:
163       // Do nothing -- these are handled in the post-replacements.
164       return true;
165     case vtkDualDepthPeelingPass::VolumetricPeel:
166       // Forward to volumetric implementation:
167       return this->PreReplaceVolumetricShaderValues(vertexShader,
168                                                     geometryShader,
169                                                     fragmentShader,
170                                                     mapper, prop);
171     default:
172       break;
173   }
174   return false;
175 }
176 
177 //------------------------------------------------------------------------------
PostReplaceShaderValues(std::string & vertexShader,std::string & geometryShader,std::string & fragmentShader,vtkAbstractMapper * mapper,vtkProp * prop)178 bool vtkDualDepthPeelingPass::PostReplaceShaderValues(
179   std::string &vertexShader,
180   std::string &geometryShader,
181   std::string &fragmentShader,
182   vtkAbstractMapper *mapper,
183   vtkProp *prop)
184 {
185   switch (this->CurrentPeelType)
186   {
187     case vtkDualDepthPeelingPass::TranslucentPeel:
188       // Forward to translucent implementation:
189       return this->PostReplaceTranslucentShaderValues(vertexShader,
190                                                       geometryShader,
191                                                       fragmentShader,
192                                                       mapper, prop);
193     case vtkDualDepthPeelingPass::VolumetricPeel:
194       // Do nothing; these are handled in the pre-replacements.
195       return true;
196 
197     default:
198       break;
199   }
200   return false;
201 }
202 
203 //------------------------------------------------------------------------------
SetShaderParameters(vtkShaderProgram * program,vtkAbstractMapper * mapper,vtkProp * prop,vtkOpenGLVertexArrayObject * VAO)204 bool vtkDualDepthPeelingPass::SetShaderParameters(vtkShaderProgram *program,
205                                    vtkAbstractMapper *mapper, vtkProp *prop,
206                                    vtkOpenGLVertexArrayObject *VAO)
207 {
208   switch (this->CurrentPeelType)
209   {
210     case vtkDualDepthPeelingPass::TranslucentPeel:
211       return this->SetTranslucentShaderParameters(program, mapper, prop, VAO);
212     case vtkDualDepthPeelingPass::VolumetricPeel:
213       return this->SetVolumetricShaderParameters(program, mapper, prop, VAO);
214     default:
215       break;
216   }
217   return false;
218 }
219 
220 //------------------------------------------------------------------------------
GetShaderStageMTime()221 vtkMTimeType vtkDualDepthPeelingPass::GetShaderStageMTime()
222 {
223   return this->CurrentStageTimeStamp.GetMTime();
224 }
225 
226 //------------------------------------------------------------------------------
PostReplaceTranslucentShaderValues(std::string &,std::string &,std::string & fragmentShader,vtkAbstractMapper *,vtkProp *)227 bool vtkDualDepthPeelingPass::PostReplaceTranslucentShaderValues(
228     std::string &, std::string &, std::string &fragmentShader,
229     vtkAbstractMapper *, vtkProp *)
230 {
231   switch (this->CurrentStage)
232   {
233     case vtkDualDepthPeelingPass::InitializingDepth:
234       // Set gl_FragDepth if it isn't set already. It may have already been
235       // replaced by the mapper, in which case the substitution will fail and
236       // the previously set depth value will be used.
237       vtkShaderProgram::Substitute(
238             fragmentShader, "//VTK::Depth::Impl",
239             "gl_FragDepth = gl_FragCoord.z;");
240       vtkShaderProgram::Substitute(
241             fragmentShader, "//VTK::DepthPeeling::Dec",
242             "uniform sampler2D opaqueDepth;\n");
243       vtkShaderProgram::Substitute(
244             fragmentShader, "//VTK::DepthPeeling::PreColor",
245             "ivec2 pixel = ivec2(gl_FragCoord.xy);\n"
246             "  float oDepth = texelFetch(opaqueDepth, pixel, 0).y;\n"
247             "  if (oDepth != -1. && gl_FragDepth > oDepth)\n"
248             "    { // Ignore fragments that are occluded by opaque geometry:\n"
249             "    gl_FragData[1].xy = vec2(-1., oDepth);\n"
250             "    return;\n"
251             "    }\n"
252             "  else\n"
253             "    {\n"
254             "    gl_FragData[1].xy = vec2(-gl_FragDepth, gl_FragDepth);\n"
255             "    return;\n"
256             "    }\n"
257             );
258       break;
259 
260     case vtkDualDepthPeelingPass::Peeling:
261       // Set gl_FragDepth if it isn't set already. It may have already been
262       // replaced by the mapper, in which case the substitution will fail and
263       // the previously set depth value will be used.
264       vtkShaderProgram::Substitute(
265             fragmentShader, "//VTK::Depth::Impl",
266             "gl_FragDepth = gl_FragCoord.z;");
267       vtkShaderProgram::Substitute(
268             fragmentShader, "//VTK::DepthPeeling::Dec",
269             "uniform sampler2D lastFrontPeel;\n"
270             "uniform sampler2D lastDepthPeel;\n");
271       vtkShaderProgram::Substitute(
272             fragmentShader, "//VTK::DepthPeeling::PreColor",
273             "  ivec2 pixelCoord = ivec2(gl_FragCoord.xy);\n"
274             "  vec4 front = texelFetch(lastFrontPeel, pixelCoord, 0);\n"
275             "  vec2 minMaxDepth = texelFetch(lastDepthPeel, pixelCoord, 0).xy;\n"
276             "  float minDepth = -minMaxDepth.x;\n"
277             "  float maxDepth = minMaxDepth.y;\n"
278             "  // Use a tolerance when checking if we're on a current peel.\n"
279             "  // Some OSX drivers compute slightly different fragment depths\n"
280             "  // from one pass to the next. This value was determined\n"
281             "  // through trial-and-error -- it may need to be increased at\n"
282             "  // some point. See also the comment in vtkDepthPeelingPass's\n"
283             "  // shader.\n"
284             "  float epsilon = 0.0000001;\n"
285             "\n"
286             "  // Default outputs (no data/change):\n"
287             "  gl_FragData[0] = vec4(0.);\n"
288             "  gl_FragData[1] = front;\n"
289             "  gl_FragData[2].xy = vec2(-1.);\n"
290             "\n"
291             "  // Is this fragment outside the current peels?\n"
292             "  if (gl_FragDepth < minDepth - epsilon ||\n"
293             "      gl_FragDepth > maxDepth + epsilon)\n"
294             "    {\n"
295 #ifndef NO_PRECOLOR_EARLY_RETURN
296             "    return;\n"
297 #else
298             "    // Early return removed to avoid instruction-reordering bug\n"
299             "    // with dFdx/dFdy on OSX drivers.\n"
300             "    // return;\n"
301 #endif
302             "    }\n"
303             "\n"
304             "  // Is this fragment inside the current peels?\n"
305             "  if (gl_FragDepth > minDepth + epsilon &&\n"
306             "      gl_FragDepth < maxDepth - epsilon)\n"
307             "    {\n"
308             "    // Write out depth so this frag will be peeled later:\n"
309             "    gl_FragData[2].xy = vec2(-gl_FragDepth, gl_FragDepth);\n"
310 #ifndef NO_PRECOLOR_EARLY_RETURN
311             "    return;\n"
312 #else
313             "    // Early return removed to avoid instruction-reordering bug\n"
314             "    // with dFdx/dFdy on OSX drivers.\n"
315             "    // return;\n"
316 #endif
317             "    }\n"
318             "\n"
319             "  // Continue processing for fragments on the current peel:\n"
320             );
321       vtkShaderProgram::Substitute(
322             fragmentShader, "//VTK::DepthPeeling::Impl",
323             "vec4 frag = gl_FragData[0];\n"
324             "  // Default outputs (no data/change):\n"
325             "\n"
326             "  // This fragment is on a current peel:\n"
327             "  if (gl_FragDepth >= minDepth - epsilon &&\n"
328             "      gl_FragDepth <= minDepth + epsilon)\n"
329             "    { // Front peel:\n"
330             "    // Clear the back color:\n"
331             "    gl_FragData[0] = vec4(0.);\n"
332             "\n"
333             "    // We store the front alpha value as (1-alpha) to allow MAX\n"
334             "    // blending. This also means it is really initialized to 1,\n"
335             "    // as it should be for under-blending.\n"
336             "    front.a = 1. - front.a;\n"
337             "\n"
338             "    // Use under-blending to combine fragment with front color:\n"
339             "    gl_FragData[1].rgb = front.a * frag.a * frag.rgb + front.rgb;\n"
340             "    // Write out (1-alpha):\n"
341             "    gl_FragData[1].a = 1. - (front.a * (1. - frag.a));\n"
342             "    }\n"
343 #ifndef NO_PRECOLOR_EARLY_RETURN
344             // just 'else' is ok. We'd return earlier in this case.
345             "  else // (gl_FragDepth == maxDepth)\n"
346 #else
347             // Need to explicitly test if this is the back peel, since early
348             // returns are removed.
349             "  else if (gl_FragDepth >= maxDepth - epsilon &&\n"
350             "           gl_FragDepth <= maxDepth + epsilon)\n"
351 #endif
352             "    { // Back peel:\n"
353             "    // Dump premultiplied fragment, it will be blended later:\n"
354             "    frag.rgb *= frag.a;\n"
355             "    gl_FragData[0] = frag;\n"
356             "    }\n"
357 #ifdef NO_PRECOLOR_EARLY_RETURN
358             // Since the color outputs now get clobbered without the early
359             // returns, reset them here.
360             "  else\n"
361             "    { // Need to clear the colors if not on a current peel.\n"
362             "    gl_FragData[0] = vec4(0.);\n"
363             "    gl_FragData[1] = front;\n"
364             "    }\n"
365 #endif
366             );
367       break;
368 
369     case vtkDualDepthPeelingPass::AlphaBlending:
370       // Set gl_FragDepth if it isn't set already. It may have already been
371       // replaced by the mapper, in which case the substitution will fail and
372       // the previously set depth value will be used.
373       vtkShaderProgram::Substitute(
374             fragmentShader, "//VTK::Depth::Impl",
375             "gl_FragDepth = gl_FragCoord.z;");
376       vtkShaderProgram::Substitute(
377             fragmentShader, "//VTK::DepthPeeling::Dec",
378             "uniform sampler2D lastDepthPeel;\n");
379       vtkShaderProgram::Substitute(
380             fragmentShader, "//VTK::DepthPeeling::PreColor",
381             "  ivec2 pixelCoord = ivec2(gl_FragCoord.xy);\n"
382             "  vec2 minMaxDepth = texelFetch(lastDepthPeel, pixelCoord, 0).xy;\n"
383             "  float minDepth = -minMaxDepth.x;\n"
384             "  float maxDepth = minMaxDepth.y;\n"
385             "\n"
386             "  // Discard all fragments outside of the last set of peels:\n"
387             "  if (gl_FragDepth < minDepth || gl_FragDepth > maxDepth)\n"
388             "    {\n"
389             "    discard;\n"
390             "    }\n"
391             );
392       vtkShaderProgram::Substitute(
393             fragmentShader, "//VTK::DepthPeeling::Impl",
394             "\n"
395             "  // Pre-multiply alpha for depth peeling:\n"
396             "  gl_FragData[0].rgb *= gl_FragData[0].a;\n"
397             );
398       break;
399 
400     default:
401       break;
402   }
403 
404   return true;
405 }
406 
407 //------------------------------------------------------------------------------
PreReplaceVolumetricShaderValues(std::string &,std::string &,std::string & fragmentShader,vtkAbstractMapper * mapper,vtkProp *)408 bool vtkDualDepthPeelingPass::PreReplaceVolumetricShaderValues(
409     std::string &, std::string &, std::string &fragmentShader,
410     vtkAbstractMapper *mapper, vtkProp *)
411 {
412   auto vmapper = vtkAbstractVolumeMapper::SafeDownCast(mapper);
413   if (!vmapper)
414   { // not a volume
415     return true;
416   }
417 
418   std::string rayInit =
419     "  // Transform zStart and zEnd to texture_coordinates\n"
420     "  mat4 NDCToTextureCoords = ip_inverseTextureDataAdjusted * in_inverseVolumeMatrix[0] *\n"
421     "    in_inverseModelViewMatrix * in_inverseProjectionMatrix;\n"
422     "  \n"
423     "  // Start point\n"
424     "  vec4 startPoint = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, zStart);\n"
425     "  startPoint = NDCToTextureCoords * startPoint;\n"
426     "  startPoint /= startPoint.w;\n"
427 
428     // startPoint could be located outside of the bounding box (bbox), this
429     // is the case in:
430     // 1. PeelVolumesOutside: Areas external to any geometry.
431     // 2. PeelVolumetricGeometry: Areas where the volume is contained within
432     // translucent geometry but the containing geometry lies outside of the bbox
433     // (startPoint is either in-front or behind the bbox depending on the viewpoint).
434     //
435     // Given that startPoint could be located either in-front, inside or behind the\n"
436     // bbox (the ray exit is unknown hence it is not possible to use clamp() directly),\n"
437     // the clamp is divided in these three zones:\n"
438     // a. In-front: clamp to ip_textureCoords (bbox's texture coord).\n"
439     // b. Inside: use startPoint directly as it is peeling within the bbox.\n"
440     // c. Behind: discard by returning vec4(0.f).\n"
441 
442     "\n"
443     "  // Initialize g_dataPos as if startPoint lies Inside (b.)\n"
444     "  g_dataPos = startPoint.xyz + g_rayJitter;\n"
445     "\n"
446     "  bool isInsideBBox = !(any(greaterThan(g_dataPos, in_texMax[0])) ||\n"
447     "                        any(lessThan(g_dataPos, in_texMin[0])));\n"
448     "  if (!isInsideBBox)\n"
449     "  {\n"
450     "    vec3 distStartTexCoord = g_rayOrigin - g_dataPos;\n"
451     "    if (dot(distStartTexCoord, g_dirStep) < 0)\n"
452     "    {\n"
453     "      // startPoint lies behind the bounding box (c.)\n"
454     "      return vec4(0.0);\n"
455     "    }\n"
456     "    // startPoint lies in-front (a.)\n"
457     "    g_dataPos = g_rayOrigin + g_rayJitter;\n"
458     "  }\n"
459     "\n"
460     "  // End point\n"
461     "  {\n"
462     "    vec4 endPoint = WindowToNDC(gl_FragCoord.x, gl_FragCoord.y, zEnd);\n"
463     "    endPoint = NDCToTextureCoords * endPoint;\n"
464     "    g_terminatePos = endPoint.xyz / endPoint.w;\n"
465     "  }\n"
466     "\n";
467 
468   if (vmapper->GetClippingPlanes())
469   {
470     rayInit +=
471         "  // Adjust the ray segment to account for clipping range:\n"
472         "  if (!AdjustSampleRangeForClipping(g_dataPos.xyz, g_terminatePos.xyz))\n"
473         "  {\n"
474         "    return vec4(0.);\n"
475         "  }\n"
476         "\n";
477   }
478   rayInit +=
479       "  // Update the number of ray marching steps to account for the clipped entry point (\n"
480       "  // this is necessary in case the ray hits geometry after marching behind the plane,\n"
481       "  // given that the number of steps was assumed to be from the not-clipped entry).\n"
482       "  g_terminatePointMax = length(g_terminatePos.xyz - g_dataPos.xyz) /\n"
483       "    length(g_dirStep);\n"
484       "\n";
485 
486   const std::string pathCheck =
487     "  // Make sure that we're sampling consistently across boundaries:\n"
488     "  g_dataPos = ClampToSampleLocation(g_rayOrigin, g_dirStep, g_dataPos, true /*ceil*/);\n"
489     "\n"
490     "  // Ensure end is not located before start. This could be the case\n"
491     "  // if end lies outside of the volume's bounding box. In those cases\n"
492     "  // a transparent color is returned.\n"
493     "  vec3 rgrif = g_terminatePos.xyz - g_dataPos.xyz;\n"
494     "  if (dot(rgrif, g_dirStep) < 0)\n"
495     "  {\n"
496     "    return vec4(0.f);\n"
497     "  }\n"
498     "\n"
499     "  // Compute the number of steps and reinitialize the step counter.\n"
500     "  g_terminatePointMax = length(rgrif) / length(g_dirStep);\n"
501     "  g_currentT = 0.0;\n"
502     "  g_fragColor = vec4(0.0);\n"
503     "\n";
504 
505   switch (this->CurrentStage)
506   {
507     case vtkDualDepthPeelingPass::InitializingDepth:
508       // At this point, both CopyOpaqueDepthBuffer and InitializeDepth have run.
509       //
510       // DepthSource (inner) has either:
511       // a. Same as outer/DepthDestination, or
512       // b. (-transGeoDepthMin, transGeoDepthMax)
513       // (a) if no transparent geo in front of opaque, (b) otherwise.
514       //
515       // DepthDestination (outer) has (-1, opaqueDepth), or (-1, -1) if no
516       // opaque geometry.
517       //
518       // All color buffers are empty, so we can draw directly to them. No input
519       // passthrough or blending needed.
520       //
521       // We'll check both of the depth buffers:
522       //
523       // 1) If the inner.y < 0, there is no geometry here. Render volume from
524       //    0 --> 1 into the back buffer.
525       // 2) If the outer.x == -1 and inner.y < 0, we have only opaque geometry
526       //    here. Render volumes from 0 --> outer.y into the back buffer.
527       // 3) If the 'max' depth differs between the buffers, then peel:
528       //    0 --> -inner.x into front buffer
529       //    inner.y --> outer.y into back buffer. If outer.y < 0, replace with 1
530 
531       vtkShaderProgram::Substitute(
532             fragmentShader, "//VTK::Termination::Init",
533             "// Termination is defined somewhere else within the pass (CallWorker::Impl \n "
534             "// and Ray::Init), so this tag is substituted for an empty implementation\n"
535             "// to avoid unnecessary code.\n");
536 
537       vtkShaderProgram::Substitute(
538             fragmentShader, "//VTK::DepthPeeling::Dec",
539             "uniform sampler2D outerDepthTex;\n"
540             "uniform sampler2D innerDepthTex;\n"
541             );
542       vtkShaderProgram::Substitute(
543             fragmentShader, "//VTK::CallWorker::Impl",
544             "  vec2 pixelCoord = vec2(gl_FragCoord.x, gl_FragCoord.y);\n"
545             "  vec2 inner = texture2D(innerDepthTex, pixelCoord * in_inverseWindowSize).xy;\n"
546             "  vec2 outer = texture2D(outerDepthTex, pixelCoord * in_inverseWindowSize).xy;\n"
547             "\n"
548             "  initializeRayCast();\n"
549             "  vec4 front = vec4(0.f);\n"
550             "  vec4 back = vec4(0.f);\n"
551             "\n"
552             "  // Check for the presence of opaque/trans geometry:\n"
553             "  bool hasOpaqueGeometry = outer.y >= 0.f;\n"
554             "  bool hasTranslucentGeometry = inner.x != -1.f;\n"
555             "  bool hasAnyGeometry = hasOpaqueGeometry ||\n"
556             "                        hasTranslucentGeometry;\n"
557             "\n"
558 #ifndef DEBUG_VOLUME_PREPASS_PIXELS
559             "  vec2 frontRange = vec2(1.f, -1.f);\n"
560             "  vec2 backRange = vec2(1.f, -1.f);\n"
561             "\n"
562 #endif // not DEBUG_VOLUME_PREPASS_PIXELS
563             "  if (!hasAnyGeometry)\n"
564             "  { // No opaque or translucent geometry\n"
565 #ifndef DEBUG_VOLUME_PREPASS_PIXELS
566             "    backRange = vec2(0., 1.);\n"
567 #else // not DEBUG_VOLUME_PREPASS_PIXELS
568             "    back = vec4(1.f, 0.f, 0.f, 1.f);\n"
569 #endif // not DEBUG_VOLUME_PREPASS_PIXELS
570             "  }\n"
571             "  else if (!hasTranslucentGeometry)\n"
572             "  { // Opaque geometry only.\n"
573 #ifndef DEBUG_VOLUME_PREPASS_PIXELS
574             "    float opaqueDepth = inner.y;\n"
575             "    backRange = vec2(0.f, opaqueDepth);\n"
576 #else // not DEBUG_VOLUME_PREPASS_PIXELS
577             "    back = vec4(0.f, 1.f, 0.f, 1.f);\n"
578 #endif // not DEBUG_VOLUME_PREPASS_PIXELS
579             "  }\n"
580             "  else // translucent geometry, maybe opaque, too:\n"
581             "  {\n"
582 #ifndef DEBUG_VOLUME_PREPASS_PIXELS
583             "    float opaqueDepth = hasOpaqueGeometry ? outer.y : 1.f;\n"
584             "    frontRange = vec2(0.f, -inner.x);\n"
585             "    backRange = vec2(inner.y, opaqueDepth);\n"
586             "\n"
587 #else // not DEBUG_VOLUME_PREPASS_PIXELS
588             "    float blue = hasOpaqueGeometry ? 1.f : 0.f;\n"
589             "    back = vec4(blue, 0.f, 1.f, 1.f);\n"
590 #endif // not DEBUG_VOLUME_PREPASS_PIXELS
591             "  }\n"
592             "\n"
593 #ifndef DEBUG_VOLUME_PREPASS_PIXELS
594             "  if (frontRange.x < frontRange.y)\n"
595             "  {\n"
596             "    front = castRay(frontRange.x, frontRange.y);\n"
597             "  }\n"
598             "  if (backRange.x < backRange.y && // range valid\n"
599             "      front.a < g_opacityThreshold) // early termination\n"
600             "  {\n"
601             "    back = castRay(backRange.x, backRange.y);\n"
602             "  }\n"
603             "\n"
604 #endif // not DEBUG_VOLUME_PREPASS_PIXELS
605             "  gl_FragData[0] = back;\n"
606             "  gl_FragData[1] = front;\n"
607             );
608 
609       vtkShaderProgram::Substitute(fragmentShader,
610             "//VTK::DepthPeeling::Ray::Init", rayInit);
611 
612       vtkShaderProgram::Substitute(fragmentShader,
613             "//VTK::DepthPeeling::Ray::PathCheck", pathCheck);
614 
615       return true;
616 
617     case vtkDualDepthPeelingPass::Peeling:
618       vtkShaderProgram::Substitute(
619             fragmentShader, "//VTK::DepthPeeling::Dec",
620             "uniform sampler2D outerDepthTex;\n"
621             "uniform sampler2D innerDepthTex;\n"
622             "uniform sampler2D lastFrontColorTex;\n"
623             "uniform sampler2D opaqueDepthTex;\n"
624             );
625       vtkShaderProgram::Substitute(
626             fragmentShader, "//VTK::CallWorker::Impl",
627             "  vec2 pixelCoord = vec2(gl_FragCoord.x, gl_FragCoord.y);\n"
628             "  vec2 innerDepths = texture2D(innerDepthTex, pixelCoord * in_inverseWindowSize).xy;\n"
629             "  vec2 outerDepths = texture2D(outerDepthTex, pixelCoord * in_inverseWindowSize).xy;\n"
630             "  vec4 lastFrontColor = texture2D(lastFrontColorTex, pixelCoord * in_inverseWindowSize);\n"
631             "\n"
632             "  // Discard processed fragments\n"
633             "  if (outerDepths.x == -1)\n"
634             "  {\n"
635             "    discard;\n"
636             "  }\n"
637             "\n"
638             "  // Negate the near depths; they're negative for MAX blending:\n"
639             "  float frontStartDepth = -outerDepths.x;\n"
640             "  float frontEndDepth   = -innerDepths.x;\n"
641             "  float backStartDepth  = innerDepths.y;\n"
642             "  float backEndDepth    = outerDepths.y;\n"
643             "\n"
644             "  // Only record the back color (for occlusion queries) if the\n"
645             "  // front/back ranges are the same:\n"
646             "  bool onlyBack = frontStartDepth == backStartDepth &&\n"
647             "                  frontEndDepth == backEndDepth;\n"
648             "\n"
649 
650             // In the last peel, innerDepths may be (-1, -1) for most of the
651             // fragments. Casting a ray from [outerDepths.x, 1.0] would result
652             // in accumulating areas that have already been accounted for in
653             // former volume peels.  In this case frontEndDepth should be the
654             // outer max instead. Because of this, the back castRay() is also
655             // skipped.
656 
657             "  bool noInnerDepths = innerDepths.x == -1.0;\n"
658             "  if (noInnerDepths)\n"
659             "  {\n"
660             "    frontEndDepth = outerDepths.y;\n"
661             "  }\n"
662             "\n"
663 
664             // Peel passes set -1 in pixels that contain only opaque geometry,
665             // so the opaque depth is fetched in order to z-composite volumes
666             // with opaque goemetry. To do this, the end point of front is clamped
667             // to opaque-depth and back ray-cast is skipped altogether since it
668             // would be covered by opaque geometry anyway.
669 
670             "  float oDepth = texture2D(opaqueDepthTex, pixelCoord * in_inverseWindowSize).x;\n"
671             "  bool endBehindOpaque = frontEndDepth >= oDepth;\n"
672             "  float clampedFrontEnd = frontEndDepth;\n"
673             "  if (endBehindOpaque)\n"
674             "  {\n"
675             "    clampedFrontEnd = clamp(frontEndDepth, oDepth, oDepth);\n"
676             "  }\n"
677             "  \n"
678             "  initializeRayCast();\n"
679             "  vec4 frontColor = vec4(0.f);\n"
680             "  if (!onlyBack)\n"
681             "  {\n"
682             "    frontColor = castRay(frontStartDepth,\n"
683             "                         clampedFrontEnd);\n"
684             "  }\n"
685             "\n"
686             "  vec4 backColor = vec4(0.);\n"
687             "  if (!endBehindOpaque && !noInnerDepths)"
688             "  {\n"
689             "    backColor = castRay(backStartDepth,\n"
690             "                        backEndDepth);\n"
691             "  }\n"
692             "\n"
693             "  // The color returned by castRay() has alpha pre-multiplied,\n"
694             "  // as required for back-blending.\n"
695             "  gl_FragData[0] = backColor;\n"
696             "\n"
697             "  // Front color is written with negated alpha for MAX blending:\n"
698             "  lastFrontColor.a = 1. - lastFrontColor.a;\n"
699             "\n"
700             "  // Use under-blending to mix the front color on-the-fly:\n"
701             "  // (note that frontColor.rgb is already multiplied by its\n"
702             "  // alpha, this is done within castRay())\n"
703             "  gl_FragData[1].rgb =\n"
704             "    lastFrontColor.a * frontColor.rgb + lastFrontColor.rgb;\n"
705             "\n"
706             "  // Write out (1-alpha) for MAX blending:\n"
707             "  gl_FragData[1].a = 1. - (lastFrontColor.a * (1. - frontColor.a));\n"
708             );
709 
710       vtkShaderProgram::Substitute(fragmentShader,
711             "//VTK::DepthPeeling::Ray::Init", rayInit);
712 
713       vtkShaderProgram::Substitute(fragmentShader,
714             "//VTK::DepthPeeling::Ray::PathCheck", pathCheck);
715 
716       break;
717 
718     case vtkDualDepthPeelingPass::AlphaBlending:
719       vtkShaderProgram::Substitute(
720             fragmentShader, "//VTK::DepthPeeling::Dec",
721             "uniform sampler2D depthRangeTex;\n");
722       vtkShaderProgram::Substitute(
723             fragmentShader, "//VTK::CallWorker::Impl",
724             "  vec2 pixelCoord = vec2(gl_FragCoord.x, gl_FragCoord.y);\n"
725             "  vec2 depthRange = texture2D(depthRangeTex, pixelCoord * in_inverseWindowSize).xy;\n"
726             "\n"
727             "  // Discard processed fragments\n"
728             "  if (depthRange.x == -1.0)\n"
729             "  {\n"
730             "    discard;\n"
731             "  }\n"
732             "\n"
733             "  float startDepth = -depthRange.x;\n"
734             "  float endDepth = depthRange.y;\n"
735             "\n"
736             "  initializeRayCast();\n"
737             "  vec4 color = castRay(startDepth, endDepth);\n"
738             "\n"
739             "  // The color returned by castRay() has alpha pre-multiplied,\n"
740             "  // as required for back-blending.\n"
741             "  gl_FragData[0] = color;\n"
742             );
743 
744       vtkShaderProgram::Substitute(fragmentShader,
745             "//VTK::DepthPeeling::Ray::Init", rayInit);
746 
747       vtkShaderProgram::Substitute(fragmentShader,
748             "//VTK::DepthPeeling::Ray::PathCheck", pathCheck);
749 
750       break;
751 
752     default:
753       break;
754   }
755 
756   return true;
757 }
758 
759 //------------------------------------------------------------------------------
SetTranslucentShaderParameters(vtkShaderProgram * program,vtkAbstractMapper *,vtkProp *,vtkOpenGLVertexArrayObject *)760 bool vtkDualDepthPeelingPass::SetTranslucentShaderParameters(
761     vtkShaderProgram *program, vtkAbstractMapper *, vtkProp *,
762     vtkOpenGLVertexArrayObject *)
763 {
764   switch (this->CurrentStage)
765   {
766     case vtkDualDepthPeelingPass::InitializingDepth:
767       program->SetUniformi(
768             "opaqueDepth",
769             this->Textures[this->DepthDestination]->GetTextureUnit());
770       break;
771 
772     case vtkDualDepthPeelingPass::Peeling:
773       program->SetUniformi(
774             "lastDepthPeel",
775             this->Textures[this->DepthSource]->GetTextureUnit());
776       program->SetUniformi(
777             "frontDepthPeel",
778             this->Textures[this->FrontSource]->GetTextureUnit());
779       break;
780 
781     case vtkDualDepthPeelingPass::AlphaBlending:
782       program->SetUniformi(
783             "lastDepthPeel",
784             this->Textures[this->DepthSource]->GetTextureUnit());
785       break;
786 
787     default:
788       break;
789   }
790 
791   return true;
792 }
793 
794 //------------------------------------------------------------------------------
SetVolumetricShaderParameters(vtkShaderProgram * program,vtkAbstractMapper *,vtkProp *,vtkOpenGLVertexArrayObject *)795 bool vtkDualDepthPeelingPass::SetVolumetricShaderParameters(
796     vtkShaderProgram *program, vtkAbstractMapper *, vtkProp *,
797     vtkOpenGLVertexArrayObject *)
798 {
799   switch (this->CurrentStage)
800   {
801     case vtkDualDepthPeelingPass::InitializingDepth:
802       program->SetUniformi(
803             "outerDepthTex",
804             this->Textures[this->DepthDestination]->GetTextureUnit());
805       program->SetUniformi(
806             "innerDepthTex",
807             this->Textures[this->DepthSource]->GetTextureUnit());
808       return true;
809 
810     case vtkDualDepthPeelingPass::Peeling:
811       program->SetUniformi(
812             "outerDepthTex",
813             this->Textures[this->DepthSource]->GetTextureUnit());
814       program->SetUniformi(
815             "innerDepthTex",
816             this->Textures[this->DepthDestination]->GetTextureUnit());
817       program->SetUniformi(
818             "lastFrontColorTex",
819             this->Textures[this->FrontSource]->GetTextureUnit());
820       program->SetUniformi(
821             "opaqueDepthTex", this->Textures[OpaqueDepth]->GetTextureUnit());
822       break;
823 
824     case vtkDualDepthPeelingPass::AlphaBlending:
825       program->SetUniformi(
826             "depthRangeTex",
827             this->Textures[this->DepthSource]->GetTextureUnit());
828       break;
829 
830     default:
831       break;
832   }
833 
834   return true;
835 }
836 
837 //------------------------------------------------------------------------------
vtkDualDepthPeelingPass()838 vtkDualDepthPeelingPass::vtkDualDepthPeelingPass()
839   : VolumetricPass(nullptr),
840     RenderState(nullptr),
841     CopyColorHelper(nullptr),
842     CopyDepthHelper(nullptr),
843     BackBlendHelper(nullptr),
844     BlendHelper(nullptr),
845     FrontSource(FrontA),
846     FrontDestination(FrontB),
847     DepthSource(DepthA),
848     DepthDestination(DepthB),
849     CurrentStage(Inactive),
850     CurrentPeelType(TranslucentPeel),
851     LastPeelHadVolumes(false),
852     CurrentPeel(0),
853     TranslucentOcclusionQueryId(0),
854     TranslucentWrittenPixels(0),
855     VolumetricOcclusionQueryId(0),
856     VolumetricWrittenPixels(0),
857     OcclusionThreshold(0),
858     TranslucentRenderCount(0),
859     VolumetricRenderCount(0),
860     SaveScissorTestState(false),
861     CullFaceMode(0),
862     CullFaceEnabled(false),
863     DepthTestEnabled(true)
864 {
865   std::fill(this->Textures, this->Textures + static_cast<int>(NumberOfTextures),
866             static_cast<vtkTextureObject*>(nullptr));
867 }
868 
869 //------------------------------------------------------------------------------
~vtkDualDepthPeelingPass()870 vtkDualDepthPeelingPass::~vtkDualDepthPeelingPass()
871 {
872   this->FreeGLObjects();
873 
874   if (this->VolumetricPass)
875   {
876     this->SetVolumetricPass(nullptr);
877   }
878   if (this->BlendHelper)
879   {
880     delete this->BlendHelper;
881     this->BlendHelper = nullptr;
882   }
883   if (this->BackBlendHelper)
884   {
885     delete this->BackBlendHelper;
886     this->BackBlendHelper = nullptr;
887   }
888   if (this->CopyColorHelper)
889   {
890     delete this->CopyColorHelper;
891     this->CopyColorHelper = nullptr;
892   }
893   if (this->CopyDepthHelper)
894   {
895     delete this->CopyDepthHelper;
896     this->CopyDepthHelper = nullptr;
897   }
898 }
899 
900 //------------------------------------------------------------------------------
SetCurrentStage(ShaderStage stage)901 void vtkDualDepthPeelingPass::SetCurrentStage(ShaderStage stage)
902 {
903   if (stage != this->CurrentStage)
904   {
905     this->CurrentStage = stage;
906     this->CurrentStageTimeStamp.Modified();
907   }
908 }
909 
910 //------------------------------------------------------------------------------
FreeGLObjects()911 void vtkDualDepthPeelingPass::FreeGLObjects()
912 {
913   for (int i = 0; i < static_cast<int>(NumberOfTextures); ++i)
914   {
915     if (this->Textures[i])
916     {
917       this->Textures[i]->Delete();
918       this->Textures[i] = nullptr;
919     }
920   }
921 }
922 
923 //------------------------------------------------------------------------------
RenderTranslucentPass()924 void vtkDualDepthPeelingPass::RenderTranslucentPass()
925 {
926   TIME_FUNCTION(vtkDualDepthPeelingPass::RenderTranslucentPass);
927   this->TranslucentPass->Render(this->RenderState);
928   ++this->TranslucentRenderCount;
929 }
930 
931 //------------------------------------------------------------------------------
RenderVolumetricPass()932 void vtkDualDepthPeelingPass::RenderVolumetricPass()
933 {
934   TIME_FUNCTION(vtkDualDepthPeelingPass::RenderVolumetricPass);
935   this->VolumetricPass->Render(this->RenderState);
936   ++this->VolumetricRenderCount;
937   this->LastPeelHadVolumes =
938       this->VolumetricPass->GetNumberOfRenderedProps() > 0;
939 }
940 
941 //------------------------------------------------------------------------------
IsRenderingVolumes()942 bool vtkDualDepthPeelingPass::IsRenderingVolumes()
943 {
944   return this->VolumetricPass && this->LastPeelHadVolumes;
945 }
946 
947 //------------------------------------------------------------------------------
Initialize(const vtkRenderState * s)948 void vtkDualDepthPeelingPass::Initialize(const vtkRenderState *s)
949 {
950   this->RenderState = s;
951   this->LastPeelHadVolumes = true;
952 
953   // Get current viewport size:
954   vtkRenderer *r = s->GetRenderer();
955   if(s->GetFrameBuffer()==nullptr)
956   {
957     // get the viewport dimensions
958     r->GetTiledSizeAndOrigin(&this->ViewportWidth, &this->ViewportHeight,
959                              &this->ViewportX, &this->ViewportY);
960   }
961   else
962   {
963     int size[2];
964     s->GetWindowSize(size);
965     this->ViewportWidth = size[0];
966     this->ViewportHeight = size[1];
967     this->ViewportX =0 ;
968     this->ViewportY = 0;
969   }
970 
971   this->Timer = r->GetRenderWindow()->GetRenderTimer();
972 
973   // The above code shouldn't touch the OpenGL command stream, so it's okay to
974   // start the event here:
975   TIME_FUNCTION(vtkDualDepthPeelingPass::Initialize);
976 
977   // adjust size as needed
978   for (int i = 0; i < static_cast<int>(NumberOfTextures); ++i)
979   {
980     if (this->Textures[i])
981     {
982       this->Textures[i]->Resize(this->ViewportWidth, this->ViewportHeight);
983     }
984   }
985 
986   // Allocate new textures if needed:
987   if (!this->Framebuffer)
988   {
989     this->Framebuffer = vtkOpenGLFramebufferObject::New();
990   }
991 
992   if (!this->Textures[BackTemp])
993   {
994     std::generate(this->Textures,
995                   this->Textures + static_cast<int>(NumberOfTextures),
996                   &vtkTextureObject::New);
997 
998     this->InitColorTexture(this->Textures[BackTemp], s);
999     this->InitColorTexture(this->Textures[Back], s);
1000     this->InitColorTexture(this->Textures[FrontA], s);
1001     this->InitColorTexture(this->Textures[FrontB], s);
1002     this->InitDepthTexture(this->Textures[DepthA], s);
1003     this->InitDepthTexture(this->Textures[DepthB], s);
1004     this->InitOpaqueDepthTexture(this->Textures[OpaqueDepth], s);
1005   }
1006 
1007   this->InitFramebuffer(s);
1008 }
1009 
1010 //------------------------------------------------------------------------------
InitColorTexture(vtkTextureObject * tex,const vtkRenderState * s)1011 void vtkDualDepthPeelingPass::InitColorTexture(vtkTextureObject *tex,
1012                                                const vtkRenderState *s)
1013 {
1014   tex->SetContext(static_cast<vtkOpenGLRenderWindow*>(
1015                     s->GetRenderer()->GetRenderWindow()));
1016   tex->SetFormat(GL_RGBA);
1017   tex->SetInternalFormat(GL_RGBA8);
1018   tex->Allocate2D(this->ViewportWidth, this->ViewportHeight, 4,
1019                   vtkTypeTraits<vtkTypeUInt8>::VTK_TYPE_ID);
1020 }
1021 
1022 //------------------------------------------------------------------------------
InitDepthTexture(vtkTextureObject * tex,const vtkRenderState * s)1023 void vtkDualDepthPeelingPass::InitDepthTexture(vtkTextureObject *tex,
1024                                                const vtkRenderState *s)
1025 {
1026   tex->SetContext(static_cast<vtkOpenGLRenderWindow*>(
1027                     s->GetRenderer()->GetRenderWindow()));
1028   tex->SetFormat(GL_RG);
1029   tex->SetInternalFormat(GL_RG32F);
1030   tex->Allocate2D(this->ViewportWidth, this->ViewportHeight, 2,
1031                   vtkTypeTraits<vtkTypeFloat32>::VTK_TYPE_ID);
1032 }
1033 
1034 //------------------------------------------------------------------------------
InitOpaqueDepthTexture(vtkTextureObject * tex,const vtkRenderState * s)1035 void vtkDualDepthPeelingPass::InitOpaqueDepthTexture(vtkTextureObject *tex,
1036                                                      const vtkRenderState *s)
1037 {
1038   tex->SetContext(static_cast<vtkOpenGLRenderWindow*>(
1039                     s->GetRenderer()->GetRenderWindow()));
1040   tex->AllocateDepth(this->ViewportWidth, this->ViewportHeight,
1041                      vtkTextureObject::Float32);
1042 }
1043 
1044 //------------------------------------------------------------------------------
InitFramebuffer(const vtkRenderState * s)1045 void vtkDualDepthPeelingPass::InitFramebuffer(const vtkRenderState *s)
1046 {
1047   this->Framebuffer->SetContext(static_cast<vtkOpenGLRenderWindow*>(
1048                                   s->GetRenderer()->GetRenderWindow()));
1049 
1050   // Save the current FBO bindings to restore them later.
1051   this->Framebuffer->SaveCurrentBindingsAndBuffers(GL_DRAW_FRAMEBUFFER);
1052 }
1053 
1054 //------------------------------------------------------------------------------
ActivateDrawBuffers(const TextureName * ids,size_t numTex)1055 void vtkDualDepthPeelingPass::ActivateDrawBuffers(const TextureName *ids,
1056                                                   size_t numTex)
1057 {
1058   this->Framebuffer->DeactivateDrawBuffers();
1059   for (size_t i = 0; i < numTex; ++i)
1060   {
1061     this->Framebuffer->AddColorAttachment(GL_DRAW_FRAMEBUFFER,
1062                                           static_cast<unsigned int>(i),
1063                                           this->Textures[ids[i]]);
1064   }
1065 
1066   const unsigned int numBuffers = static_cast<unsigned int>(numTex);
1067   this->SetActiveDrawBuffers(numBuffers);
1068   this->Framebuffer->ActivateDrawBuffers(numBuffers);
1069 }
1070 
1071 //------------------------------------------------------------------------------
Prepare()1072 void vtkDualDepthPeelingPass::Prepare()
1073 {
1074   TIME_FUNCTION(vtkDualDepthPeelingPass::Prepare);
1075 
1076   // Since we're rendering into a temporary non-default framebuffer, we need to
1077   // remove the translation from the viewport and disable the scissor test;
1078   // otherwise we'll capture the wrong area of the rendered geometry.
1079   this->State->vtkglViewport(0, 0,
1080              this->ViewportWidth, this->ViewportHeight);
1081   this->SaveScissorTestState = this->State->GetEnumState(GL_SCISSOR_TEST);
1082   this->State->vtkglDisable(GL_SCISSOR_TEST);
1083 
1084   // bad sync here
1085   this->State->vtkglGetIntegerv(GL_CULL_FACE_MODE, &this->CullFaceMode);
1086   this->CullFaceEnabled = this->State->GetEnumState(GL_CULL_FACE);
1087 
1088   this->DepthTestEnabled = this->State->GetEnumState(GL_DEPTH_TEST);
1089 
1090   // Prevent vtkOpenGLActor from messing with the depth mask:
1091   size_t numProps = this->RenderState->GetPropArrayCount();
1092   for (size_t i = 0; i < numProps; ++i)
1093   {
1094     vtkProp *prop = this->RenderState->GetPropArray()[i];
1095     vtkInformation *info = prop->GetPropertyKeys();
1096     if (!info)
1097     {
1098       info = vtkInformation::New();
1099       prop->SetPropertyKeys(info);
1100       info->FastDelete();
1101     }
1102     info->Set(vtkOpenGLActor::GLDepthMaskOverride(), -1);
1103   }
1104 
1105   // Setup GL state:
1106   this->State->vtkglDisable(GL_DEPTH_TEST);
1107   this->InitializeOcclusionQuery();
1108   this->CurrentPeel = 0;
1109   this->TranslucentRenderCount = 0;
1110   this->VolumetricRenderCount = 0;
1111 
1112   // Save the current FBO bindings to restore them later.
1113   this->Framebuffer->SaveCurrentBindingsAndBuffers(GL_DRAW_FRAMEBUFFER);
1114   this->Framebuffer->Bind(GL_DRAW_FRAMEBUFFER);
1115 
1116   // The source front buffer must be initialized, since it simply uses additive
1117   // blending.
1118   // The back-blending may discard fragments, so the back peel accumulator needs
1119   // initialization as well.
1120   std::array<TextureName, 2> targets = { { Back, this->FrontSource } };
1121   this->ActivateDrawBuffers(targets);
1122   this->State->vtkglClearColor(0.f, 0.f, 0.f, 0.f);
1123   this->State->vtkglClear(GL_COLOR_BUFFER_BIT);
1124 
1125   // Fill both depth buffers with -1, -1. This lets us discard fragments in
1126   // CopyOpaqueDepthBuffers, which gives a moderate performance boost.
1127   targets[0] = this->DepthSource;
1128   targets[1] = this->DepthDestination;
1129   this->ActivateDrawBuffers(targets);
1130   this->State->vtkglClearColor(-1, -1, 0, 0);
1131   this->State->vtkglClear(GL_COLOR_BUFFER_BIT);
1132 
1133   // Pre-fill the depth buffer with opaque pass data:
1134   this->CopyOpaqueDepthBuffer();
1135 
1136   // Initialize the transparent depths for the peeling algorithm:
1137   this->InitializeDepth();
1138 }
1139 
1140 //------------------------------------------------------------------------------
InitializeOcclusionQuery()1141 void vtkDualDepthPeelingPass::InitializeOcclusionQuery()
1142 {
1143   glGenQueries(1, &this->TranslucentOcclusionQueryId);
1144   glGenQueries(1, &this->VolumetricOcclusionQueryId);
1145 
1146   int numPixels = this->ViewportHeight * this->ViewportWidth;
1147   this->OcclusionThreshold = numPixels * this->OcclusionRatio;
1148   this->TranslucentWrittenPixels = this->OcclusionThreshold + 1;
1149   this->VolumetricWrittenPixels = this->OcclusionThreshold + 1;
1150 }
1151 
1152 //------------------------------------------------------------------------------
CopyOpaqueDepthBuffer()1153 void vtkDualDepthPeelingPass::CopyOpaqueDepthBuffer()
1154 {
1155   TIME_FUNCTION(vtkDualDepthPeelingPass::CopyOpaqueDepthBuffer);
1156 
1157   // Initialize the peeling depth buffer using the existing opaque depth buffer.
1158   // Note that the min component is stored as -depth, allowing
1159   // glBlendEquation = GL_MAX to be used during peeling.
1160 
1161   // Copy from the current (default) framebuffer's depth buffer into a texture:
1162   this->Framebuffer->RestorePreviousBindingsAndBuffers(GL_DRAW_FRAMEBUFFER);
1163   this->Textures[OpaqueDepth]->CopyFromFrameBuffer(
1164         this->ViewportX, this->ViewportY, 0, 0,
1165         this->ViewportWidth, this->ViewportHeight);
1166   this->Framebuffer->SaveCurrentBindingsAndBuffers(GL_DRAW_FRAMEBUFFER);
1167   this->Framebuffer->Bind(GL_DRAW_FRAMEBUFFER);
1168 
1169   // Fill both depth buffers with the opaque fragment depths. InitializeDepth
1170   // will compare translucent fragment depths with values in DepthDestination
1171   // and write to DepthSource using MAX blending, so we need both to have opaque
1172   // fragments (src/dst seem reversed because they're named for their usage in
1173   // PeelRender).
1174   std::array<TextureName, 2> targets = { { this->DepthSource,
1175                                            this->DepthDestination } };
1176   this->ActivateDrawBuffers(targets);
1177   this->Textures[OpaqueDepth]->Activate();
1178 
1179   this->State->vtkglDisable(GL_BLEND);
1180 
1181   vtkOpenGLRenderWindow *renWin = static_cast<vtkOpenGLRenderWindow*>(
1182         this->RenderState->GetRenderer()->GetRenderWindow());
1183   if (!this->CopyDepthHelper)
1184   {
1185     std::string fragShader =
1186       vtkOpenGLRenderUtilities::GetFullScreenQuadFragmentShaderTemplate();
1187     vtkShaderProgram::Substitute(
1188           fragShader, "//VTK::FSQ::Decl",
1189           "uniform float clearValue;\n"
1190           "uniform sampler2D oDepth;\n");
1191     vtkShaderProgram::Substitute(
1192           fragShader, "//VTK::FSQ::Impl",
1193           "  float d = texture2D(oDepth, texCoord).x;\n"
1194           "  if (d == clearValue)\n"
1195           "    { // If no depth value has been written, discard the frag:\n"
1196           "    discard;\n"
1197           "    }\n"
1198           "  gl_FragData[0] = gl_FragData[1] = vec4(-1, d, 0., 0.);\n"
1199           );
1200     this->CopyDepthHelper = new vtkOpenGLQuadHelper(renWin,
1201           nullptr,
1202           fragShader.c_str(),
1203           nullptr);
1204   }
1205   else
1206   {
1207     renWin->GetShaderCache()->ReadyShaderProgram(this->CopyDepthHelper->Program);
1208   }
1209 
1210   if (!this->CopyDepthHelper->Program)
1211   {
1212     return;
1213   }
1214 
1215   // Get the clear value. We don't set this, so it should still be what the
1216   // opaque pass uses:
1217   GLfloat clearValue = 1.f;
1218   glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearValue);
1219   this->CopyDepthHelper->Program->SetUniformf("clearValue", clearValue);
1220   this->CopyDepthHelper->Program->SetUniformi(
1221         "oDepth", this->Textures[OpaqueDepth]->GetTextureUnit());
1222 
1223   annotate("Copying opaque depth!");
1224   this->CopyDepthHelper->Render();
1225   annotate("Opaque depth copied!");
1226 
1227   this->Textures[OpaqueDepth]->Deactivate();
1228 }
1229 
1230 //------------------------------------------------------------------------------
InitializeDepth()1231 void vtkDualDepthPeelingPass::InitializeDepth()
1232 {
1233   TIME_FUNCTION(vtkDualDepthPeelingPass::InitializeDepth);
1234 
1235   // Add the translucent geometry to our depth peeling buffer:
1236 
1237   // We bind the back temporary buffer as render target 0 -- the data we
1238   // write to it isn't used, but this makes it easier to work with the existing
1239   // polydata shaders as they expect gl_FragData[0] to be RGBA. The front
1240   // destination buffer is cleared prior to peeling, so it's just a dummy
1241   // buffer at this point.
1242   std::array<TextureName, 2> targets = { { BackTemp, this->DepthSource } };
1243   this->ActivateDrawBuffers(targets);
1244 
1245   this->SetCurrentStage(InitializingDepth);
1246   this->SetCurrentPeelType(TranslucentPeel);
1247   this->Textures[this->DepthDestination]->Activate();
1248 
1249   this->State->vtkglEnable(GL_BLEND);
1250   this->State->vtkglBlendEquation(GL_MAX);
1251   annotate("Initializing depth.");
1252   this->RenderTranslucentPass();
1253   annotate("Depth initialized");
1254 
1255   this->Textures[this->DepthDestination]->Deactivate();
1256 }
1257 
1258 //------------------------------------------------------------------------------
PeelVolumesOutsideTranslucentRange()1259 void vtkDualDepthPeelingPass::PeelVolumesOutsideTranslucentRange()
1260 {
1261   TIME_FUNCTION(vtkDualDepthPeelingPass::PeelVolumesOutsideTranslucentRange);
1262 
1263   // Enable the destination targets. Note that we're rendering directly into
1264   // the Back accumulation buffer and the FrontSource buffer, since we know
1265   // this is the first time these buffers will be drawn into.
1266   std::array<TextureName, 2> targets = { { Back, this->FrontSource } };
1267   this->ActivateDrawBuffers(targets);
1268 
1269   // Cull back fragments of the volume's proxy geometry since they are
1270   // not necessary anyway.
1271   this->State->vtkglCullFace(GL_BACK);
1272   this->State->vtkglEnable(GL_CULL_FACE);
1273 
1274   this->SetCurrentStage(InitializingDepth);
1275   this->SetCurrentPeelType(VolumetricPeel);
1276 
1277   this->Textures[this->DepthSource]->Activate();
1278   this->Textures[this->DepthDestination]->Activate();
1279 
1280   annotate("Peeling volumes external to translucent geometry.");
1281   this->RenderVolumetricPass();
1282   annotate("External volume peel done.");
1283 
1284   this->State->vtkglCullFace(this->CullFaceMode);
1285   this->State->vtkglDisable(GL_CULL_FACE);
1286 
1287   this->Textures[this->DepthSource]->Deactivate();
1288   this->Textures[this->DepthDestination]->Deactivate();
1289 }
1290 
1291 //------------------------------------------------------------------------------
PeelingDone()1292 bool vtkDualDepthPeelingPass::PeelingDone()
1293 {
1294   // Note that we do NOT check the volumetric occlusion info as an early
1295   // termination criterion. A volume may not exist for every slice, or may
1296   // only be found in the front slice (only the back is counted for occlusion
1297   // tests). This can lead to incorrect early termination of volume peeling.
1298   return this->CurrentPeel >= this->MaximumNumberOfPeels ||
1299          this->TranslucentWrittenPixels <= this->OcclusionThreshold;
1300 }
1301 
1302 //------------------------------------------------------------------------------
Peel()1303 void vtkDualDepthPeelingPass::Peel()
1304 {
1305   TIME_FUNCTION(vtkDualDepthPeelingPass::Peel);
1306 
1307   this->InitializeTargetsForTranslucentPass();
1308   this->PeelTranslucentGeometry();
1309   this->StartTranslucentOcclusionQuery();
1310   this->BlendBackBuffer();
1311   this->EndTranslucentOcclusionQuery();
1312   this->SwapFrontBufferSourceDest();
1313 
1314   if (this->IsRenderingVolumes())
1315   {
1316     this->InitializeTargetsForVolumetricPass();
1317     this->PeelVolumetricGeometry();
1318 
1319     this->StartVolumetricOcclusionQuery();
1320     this->BlendBackBuffer();
1321     this->EndVolumetricOcclusionQuery();
1322     this->SwapFrontBufferSourceDest();
1323   }
1324 
1325   this->SwapDepthBufferSourceDest();
1326 
1327   ++this->CurrentPeel;
1328 
1329 #ifdef DEBUG_PEEL
1330   std::cout << "Peel " << this->CurrentPeel << ": Pixels written: trans="
1331             << this->TranslucentWrittenPixels << " volume="
1332             << this->VolumetricWrittenPixels << " (threshold: "
1333             << this->OcclusionThreshold << ")\n";
1334 #endif // DEBUG_PEEL
1335 }
1336 
1337 //------------------------------------------------------------------------------
PrepareFrontDestination()1338 void vtkDualDepthPeelingPass::PrepareFrontDestination()
1339 {
1340   // If we're not using volumes, clear the front destination buffer and just
1341   // let the shaders pass-through the colors from the previous peel.
1342   //
1343   // If we are rendering volumes, we can't rely on the shader pass-through,
1344   // since the volumetric and translucent geometry may not cover the same
1345   // pixels, and information would be lost if we simply cleared the front
1346   // buffer. In this case, we're essentially forcing a fullscreen pass-through
1347   // prior to the any actual rendering calls.
1348   if (!this->IsRenderingVolumes())
1349   {
1350     this->ClearFrontDestination();
1351   }
1352   else
1353   {
1354     this->CopyFrontSourceToFrontDestination();
1355   }
1356 }
1357 
1358 //------------------------------------------------------------------------------
ClearFrontDestination()1359 void vtkDualDepthPeelingPass::ClearFrontDestination()
1360 {
1361   TIME_FUNCTION(vtkDualDepthPeelingPass::ClearFrontDestination);
1362   annotate("ClearFrontDestination()");
1363   this->ActivateDrawBuffer(this->FrontDestination);
1364   this->State->vtkglClearColor(0.f, 0.f, 0.f, 0.f);
1365   this->State->vtkglClear(GL_COLOR_BUFFER_BIT);
1366 }
1367 
1368 //------------------------------------------------------------------------------
CopyFrontSourceToFrontDestination()1369 void vtkDualDepthPeelingPass::CopyFrontSourceToFrontDestination()
1370 {
1371   TIME_FUNCTION(vtkDualDepthPeelingPass::CopyFrontSourceToFrontDestination);
1372 
1373   this->ActivateDrawBuffer(this->FrontDestination);
1374 
1375   this->State->vtkglDisable(GL_BLEND);
1376 
1377   vtkOpenGLRenderWindow *renWin = static_cast<vtkOpenGLRenderWindow*>(
1378         this->RenderState->GetRenderer()->GetRenderWindow());
1379   if (!this->CopyColorHelper)
1380   {
1381     std::string fragShader =
1382       vtkOpenGLRenderUtilities::GetFullScreenQuadFragmentShaderTemplate();
1383     vtkShaderProgram::Substitute(
1384           fragShader, "//VTK::FSQ::Decl",
1385           "uniform sampler2D inTex;\n");
1386     vtkShaderProgram::Substitute(
1387           fragShader, "//VTK::FSQ::Impl",
1388           "  gl_FragData[0] = texture2D(inTex, texCoord);\n");
1389     this->CopyColorHelper = new vtkOpenGLQuadHelper(renWin,
1390           nullptr,
1391           fragShader.c_str(),
1392           nullptr);
1393   }
1394   else
1395   {
1396     renWin->GetShaderCache()->ReadyShaderProgram(this->CopyColorHelper->Program);
1397   }
1398 
1399   if (!this->CopyColorHelper->Program)
1400   {
1401     return;
1402   }
1403 
1404   this->Textures[this->FrontSource]->Activate();
1405   this->CopyColorHelper->Program->SetUniformi(
1406         "inTex", this->Textures[this->FrontSource]->GetTextureUnit());
1407 
1408   annotate("Copying front texture src -> dst for pre-pass initialization!");
1409   this->CopyColorHelper->Render();
1410   annotate("Front texture copied!");
1411 
1412 
1413   this->Textures[this->FrontSource]->Deactivate();
1414 }
1415 
1416 //------------------------------------------------------------------------------
InitializeTargetsForTranslucentPass()1417 void vtkDualDepthPeelingPass::InitializeTargetsForTranslucentPass()
1418 {
1419   TIME_FUNCTION(vtkDualDepthPeelingPass::InitializeTargetsForTranslucentPass);
1420 
1421   // Initialize destination buffers to their minima, since we're MAX blending,
1422   // this ensures that valid outputs are captured.
1423   this->ActivateDrawBuffer(BackTemp);
1424   this->State->vtkglClearColor(0.f, 0.f, 0.f, 0.f);
1425   this->State->vtkglClear(GL_COLOR_BUFFER_BIT);
1426 
1427   this->ActivateDrawBuffer(this->DepthDestination);
1428   this->State->vtkglClearColor(-1.f, -1.f, 0.f, 0.f);
1429   this->State->vtkglClear(GL_COLOR_BUFFER_BIT);
1430 
1431   this->PrepareFrontDestination();
1432 }
1433 
1434 //------------------------------------------------------------------------------
InitializeTargetsForVolumetricPass()1435 void vtkDualDepthPeelingPass::InitializeTargetsForVolumetricPass()
1436 {
1437   TIME_FUNCTION(vtkDualDepthPeelingPass::InitializeTargetsForVolumetricPass);
1438 
1439   // Clear the back buffer to ensure that current fragments are captured for
1440   // later blending into the back accumulation buffer:
1441   this->ActivateDrawBuffer(BackTemp);
1442   this->State->vtkglClearColor(0.f, 0.f, 0.f, 0.f);
1443   this->State->vtkglClear(GL_COLOR_BUFFER_BIT);
1444 
1445   this->PrepareFrontDestination();
1446 }
1447 
1448 //------------------------------------------------------------------------------
PeelTranslucentGeometry()1449 void vtkDualDepthPeelingPass::PeelTranslucentGeometry()
1450 {
1451   TIME_FUNCTION(vtkDualDepthPeelingPass::PeelTranslucentGeometry);
1452 
1453   // Enable the destination targets:
1454   std::array<TextureName, 3> targets = { { BackTemp,
1455                                            this->FrontDestination,
1456                                            this->DepthDestination } };
1457   this->ActivateDrawBuffers(targets);
1458 
1459   // Use MAX blending to capture peels:
1460   this->State->vtkglEnable(GL_BLEND);
1461   this->State->vtkglBlendEquation(GL_MAX);
1462 
1463   this->SetCurrentStage(Peeling);
1464   this->SetCurrentPeelType(TranslucentPeel);
1465   this->Textures[this->FrontSource]->Activate();
1466   this->Textures[this->DepthSource]->Activate();
1467 
1468   annotate("Start translucent peeling!");
1469   this->RenderTranslucentPass();
1470   annotate("Translucent peeling done!");
1471 
1472   this->Textures[this->FrontSource]->Deactivate();
1473   this->Textures[this->DepthSource]->Deactivate();
1474 }
1475 
1476 //------------------------------------------------------------------------------
PeelVolumetricGeometry()1477 void vtkDualDepthPeelingPass::PeelVolumetricGeometry()
1478 {
1479   TIME_FUNCTION(vtkDualDepthPeelingPass::PeelVolumeGeometry);
1480 
1481   // Enable the destination targets:
1482   std::array<TextureName, 2> targets = { { BackTemp, this->FrontDestination } };
1483   this->ActivateDrawBuffers(targets);
1484 
1485   // Cull back fragments of the volume's proxy geometry since they are
1486   // not necessary anyway.
1487   this->State->vtkglCullFace(GL_BACK);
1488   this->State->vtkglEnable(GL_CULL_FACE);
1489 
1490   // Use MAX blending to capture peels:
1491   this->State->vtkglEnable(GL_BLEND);
1492   this->State->vtkglBlendEquation(GL_MAX);
1493 
1494   this->SetCurrentStage(Peeling);
1495   this->SetCurrentPeelType(VolumetricPeel);
1496 
1497   this->Textures[this->FrontSource]->Activate();
1498   this->Textures[this->DepthSource]->Activate();
1499   this->Textures[this->DepthDestination]->Activate();
1500   this->Textures[OpaqueDepth]->Activate();
1501 
1502   annotate("Start volumetric peeling!");
1503   this->RenderVolumetricPass();
1504   annotate("Volumetric peeling done!");
1505 
1506   this->Textures[this->FrontSource]->Deactivate();
1507   this->Textures[this->DepthSource]->Deactivate();
1508   this->Textures[this->DepthDestination]->Deactivate();
1509   this->Textures[OpaqueDepth]->Deactivate();
1510 
1511   this->State->vtkglCullFace(this->CullFaceMode);
1512   this->State->vtkglDisable(GL_CULL_FACE);
1513 }
1514 
1515 //------------------------------------------------------------------------------
BlendBackBuffer()1516 void vtkDualDepthPeelingPass::BlendBackBuffer()
1517 {
1518   TIME_FUNCTION(vtkDualDepthPeelingPass::BlendBackBuffer);
1519 
1520   this->ActivateDrawBuffer(Back);
1521   this->Textures[BackTemp]->Activate();
1522 
1523   /* For this step, we blend the last peel's back fragments into a back-
1524    * accumulation buffer. The full over-blending equations are:
1525    *
1526    * (f = front frag (incoming peel); b = back frag (current accum. buffer))
1527    *
1528    * a = f.a + (1. - f.a) * b.a
1529    *
1530    * if a == 0, C == (0, 0, 0). Otherwise,
1531    *
1532    * C = ( f.a * f.rgb + (1. - f.a) * b.a * b.rgb ) / a
1533    *
1534    * We use premultiplied alphas to save on computations, resulting in:
1535    *
1536    * [a * C] = [f.a * f.rgb] + (1 - f.a) * [ b.a * b.rgb ]
1537    * a = f.a + (1. - f.a) * b.a
1538    */
1539 
1540   this->State->vtkglEnable(GL_BLEND);
1541   this->State->vtkglBlendEquation(GL_FUNC_ADD);
1542   this->State->vtkglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1543 
1544   vtkOpenGLRenderWindow *renWin = static_cast<vtkOpenGLRenderWindow*>(
1545         this->RenderState->GetRenderer()->GetRenderWindow());
1546   if (!this->BackBlendHelper)
1547   {
1548     std::string fragShader =
1549       vtkOpenGLRenderUtilities::GetFullScreenQuadFragmentShaderTemplate();
1550     vtkShaderProgram::Substitute(
1551           fragShader, "//VTK::FSQ::Decl",
1552           "uniform sampler2D newPeel;\n"
1553           );
1554     vtkShaderProgram::Substitute(
1555           fragShader, "//VTK::FSQ::Impl",
1556           "  vec4 f = texture2D(newPeel, texCoord); // new frag\n"
1557           "  if (f.a == 0.)\n"
1558           "    {\n"
1559           "    discard;\n"
1560           "    }\n"
1561           "\n"
1562           "  gl_FragData[0] = f;\n"
1563           );
1564     this->BackBlendHelper = new vtkOpenGLQuadHelper(renWin,
1565           nullptr,
1566           fragShader.c_str(),
1567           nullptr);
1568   }
1569   else
1570   {
1571     renWin->GetShaderCache()->ReadyShaderProgram(this->BackBlendHelper->Program);
1572   }
1573 
1574   if (!this->BackBlendHelper->Program)
1575   {
1576     return;
1577   }
1578 
1579   this->BackBlendHelper->Program->SetUniformi(
1580         "newPeel", this->Textures[BackTemp]->GetTextureUnit());
1581 
1582 
1583   annotate("Start blending back!");
1584   this->BackBlendHelper->Render();
1585   annotate("Back blended!");
1586 
1587 
1588   this->Textures[BackTemp]->Deactivate();
1589 }
1590 
1591 //------------------------------------------------------------------------------
StartTranslucentOcclusionQuery()1592 void vtkDualDepthPeelingPass::StartTranslucentOcclusionQuery()
1593 {
1594   // ES 3.0 only supports checking if *any* samples passed. We'll just use
1595   // that query to stop peeling once all frags are processed, and ignore the
1596   // requested occlusion ratio.
1597 #if GL_ES_VERSION_3_0 == 1
1598   glBeginQuery(GL_ANY_SAMPLES_PASSED, this->TranslucentOcclusionQueryId);
1599 #else // GL ES 3.0
1600   glBeginQuery(GL_SAMPLES_PASSED, this->TranslucentOcclusionQueryId);
1601 #endif // GL ES 3.0
1602 }
1603 
1604 //------------------------------------------------------------------------------
EndTranslucentOcclusionQuery()1605 void vtkDualDepthPeelingPass::EndTranslucentOcclusionQuery()
1606 {
1607   // We time the end, but not the start, since this is where we stall to
1608   // sync the stream.
1609   TIME_FUNCTION(vtkDualDepthPeelingPass::EndTranslucentOcclusionQuery);
1610 
1611 #if GL_ES_VERSION_3_0 == 1
1612   glEndQuery(GL_ANY_SAMPLES_PASSED);
1613   GLuint anySamplesPassed;
1614   glGetQueryObjectuiv(this->TranslucentOcclusionQueryId, GL_QUERY_RESULT,
1615                       &anySamplesPassed);
1616   this->TranslucentWrittenPixels =
1617       anySamplesPassed ? this->OcclusionThreshold + 1 : 0;
1618 #else // GL ES 3.0
1619   glEndQuery(GL_SAMPLES_PASSED);
1620   glGetQueryObjectuiv(this->TranslucentOcclusionQueryId, GL_QUERY_RESULT,
1621                       &this->TranslucentWrittenPixels);
1622 #endif // GL ES 3.0
1623 }
1624 
1625 //------------------------------------------------------------------------------
StartVolumetricOcclusionQuery()1626 void vtkDualDepthPeelingPass::StartVolumetricOcclusionQuery()
1627 {
1628   // ES 3.0 only supports checking if *any* samples passed. We'll just use
1629   // that query to stop peeling once all frags are processed, and ignore the
1630   // requested occlusion ratio.
1631 #if GL_ES_VERSION_3_0 == 1
1632   glBeginQuery(GL_ANY_SAMPLES_PASSED, this->VolumetricOcclusionQueryId);
1633 #else // GL ES 3.0
1634   glBeginQuery(GL_SAMPLES_PASSED, this->VolumetricOcclusionQueryId);
1635 #endif // GL ES 3.0
1636 }
1637 
1638 //------------------------------------------------------------------------------
EndVolumetricOcclusionQuery()1639 void vtkDualDepthPeelingPass::EndVolumetricOcclusionQuery()
1640 {
1641   // We time the end, but not the start, since this is where we stall to
1642   // sync the stream.
1643   TIME_FUNCTION(vtkDualDepthPeelingPass::EndVolumetricOcclusionQuery);
1644 
1645 #if GL_ES_VERSION_3_0 == 1
1646   glEndQuery(GL_ANY_SAMPLES_PASSED);
1647   GLuint anySamplesPassed;
1648   glGetQueryObjectuiv(this->VolumetricOcclusionQueryId, GL_QUERY_RESULT,
1649                       &anySamplesPassed);
1650   this->VolumetricWrittenPixels =
1651       anySamplesPassed ? this->OcclusionThreshold + 1 : 0;
1652 #else // GL ES 3.0
1653   glEndQuery(GL_SAMPLES_PASSED);
1654   glGetQueryObjectuiv(this->VolumetricOcclusionQueryId, GL_QUERY_RESULT,
1655                       &this->VolumetricWrittenPixels);
1656 #endif // GL ES 3.0
1657 
1658 }
1659 
1660 //------------------------------------------------------------------------------
SwapFrontBufferSourceDest()1661 void vtkDualDepthPeelingPass::SwapFrontBufferSourceDest()
1662 {
1663   std::swap(this->FrontSource, this->FrontDestination);
1664 }
1665 
1666 //------------------------------------------------------------------------------
SwapDepthBufferSourceDest()1667 void vtkDualDepthPeelingPass::SwapDepthBufferSourceDest()
1668 {
1669   std::swap(this->DepthSource, this->DepthDestination);
1670 }
1671 
1672 //------------------------------------------------------------------------------
Finalize()1673 void vtkDualDepthPeelingPass::Finalize()
1674 {
1675   TIME_FUNCTION(vtkDualDepthPeelingPass::Finalize);
1676 
1677   // Mop up any unrendered fragments using simple alpha blending into the back
1678   // buffer.
1679 #ifndef DEBUG_VOLUME_PREPASS_PIXELS
1680   if (this->TranslucentWrittenPixels > 0 ||
1681       this->VolumetricWrittenPixels > 0)
1682   {
1683     this->AlphaBlendRender();
1684   }
1685 #endif // DEBUG_VOLUME_PREPASS_PIXELS
1686 
1687   this->NumberOfRenderedProps =
1688       this->TranslucentPass->GetNumberOfRenderedProps();
1689 
1690   if (this->IsRenderingVolumes())
1691   {
1692     this->NumberOfRenderedProps +=
1693         this->VolumetricPass->GetNumberOfRenderedProps();
1694   }
1695 
1696   this->Framebuffer->UnBind(GL_DRAW_FRAMEBUFFER);
1697   this->Framebuffer->RestorePreviousBindingsAndBuffers(GL_DRAW_FRAMEBUFFER);
1698   this->BlendFinalImage();
1699 
1700   // Restore blending parameters:
1701   this->State->vtkglEnable(GL_BLEND);
1702   this->State->vtkglBlendEquation(GL_FUNC_ADD);
1703   this->State->vtkglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1704 
1705   size_t numProps = this->RenderState->GetPropArrayCount();
1706   for (size_t i = 0; i < numProps; ++i)
1707   {
1708     vtkProp *prop = this->RenderState->GetPropArray()[i];
1709     vtkInformation *info = prop->GetPropertyKeys();
1710     if (info)
1711     {
1712       info->Remove(vtkOpenGLActor::GLDepthMaskOverride());
1713     }
1714   }
1715 
1716   this->Timer = nullptr;
1717   this->RenderState = nullptr;
1718   this->DeleteOcclusionQueryIds();
1719   this->SetCurrentStage(Inactive);
1720 
1721   if (this->CullFaceEnabled)
1722   {
1723     this->State->vtkglEnable(GL_CULL_FACE);
1724   }
1725   else
1726   {
1727     this->State->vtkglDisable(GL_CULL_FACE);
1728   }
1729   if (this->DepthTestEnabled)
1730   {
1731     this->State->vtkglEnable(GL_DEPTH_TEST);
1732   }
1733 #ifdef DEBUG_FRAME
1734   std::cout << "Depth peel done:\n"
1735             << "  - Number of peels: " << this->CurrentPeel << "\n"
1736             << "  - Number of geometry passes: "
1737             << this->TranslucentRenderCount << "\n"
1738             << "  - Number of volume passes: "
1739             << this->VolumetricRenderCount << "\n"
1740             << "  - Occlusion Ratio: trans="
1741             << static_cast<float>(this->TranslucentWrittenPixels) /
1742                static_cast<float>(this->ViewportWidth * this->ViewportHeight)
1743             << " volume="
1744             << static_cast<float>(this->VolumetricWrittenPixels) /
1745                static_cast<float>(this->ViewportWidth * this->ViewportHeight)
1746             << " (target: " << this->OcclusionRatio << ")\n";
1747 #endif // DEBUG_FRAME
1748 }
1749 
1750 //------------------------------------------------------------------------------
AlphaBlendRender()1751 void vtkDualDepthPeelingPass::AlphaBlendRender()
1752 {
1753   TIME_FUNCTION(vtkDualDepthPeelingPass::AlphaBlendRender);
1754 
1755   /* This pass is mopping up the remaining fragments when we exceed the max
1756    * number of peels or hit the occlusion limit. We'll simply render all of the
1757    * remaining fragments into the back destination buffer using the
1758    * premultiplied-alpha over-blending equations:
1759    *
1760    * aC = f.a * f.rgb + (1 - f.a) * b.a * b.rgb
1761    * a = f.a + (1 - f.a) * b.a
1762    */
1763   this->State->vtkglEnable(GL_BLEND);
1764   this->State->vtkglBlendEquation(GL_FUNC_ADD);
1765   this->State->vtkglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1766 
1767   this->SetCurrentStage(AlphaBlending);
1768   this->ActivateDrawBuffer(Back);
1769   this->Textures[this->DepthSource]->Activate();
1770 
1771   if (this->TranslucentWrittenPixels > 0)
1772   {
1773     this->SetCurrentPeelType(TranslucentPeel);
1774     annotate("Alpha blend translucent render start");
1775     this->RenderTranslucentPass();
1776     annotate("Alpha blend translucent render end");
1777   }
1778 
1779   // Do not check VolumetricWrittenPixels to determine if alpha blending
1780   // volumes is needed -- there's no guarantee that a previous slice had
1781   // volume data if the current slice does.
1782   if (this->IsRenderingVolumes())
1783   {
1784     this->SetCurrentPeelType(VolumetricPeel);
1785     annotate("Alpha blend volumetric render start");
1786     this->RenderVolumetricPass();
1787     annotate("Alpha blend volumetric render end");
1788   }
1789 
1790   this->Textures[this->DepthSource]->Deactivate();
1791 }
1792 
1793 //------------------------------------------------------------------------------
BlendFinalImage()1794 void vtkDualDepthPeelingPass::BlendFinalImage()
1795 {
1796   TIME_FUNCTION(vtkDualDepthPeelingPass::BlendFinalImage);
1797 
1798   this->Textures[this->FrontSource]->Activate();
1799   this->Textures[Back]->Activate();
1800 
1801   /* Peeling is done, time to blend the front and back peel textures with the
1802    * opaque geometry in the existing framebuffer. First, we'll underblend the
1803    * back texture beneath the front texture in the shader:
1804    *
1805    * Blend 'b' under 'f' to form 't':
1806    * t.rgb = f.a * b.a * b.rgb + f.rgb
1807    * t.a   = (1 - b.a) * f.a
1808    *
1809    * ( t = translucent layer (back + front), f = front layer, b = back layer )
1810    *
1811    * Also in the shader, we adjust the translucent layer's alpha so that it
1812    * can be used for back-to-front blending, so
1813    *
1814    * alphaOverBlend = 1. - alphaUnderBlend
1815    *
1816    * To blend the translucent layer over the opaque layer, use regular
1817    * overblending via glBlendEquation/glBlendFunc:
1818    *
1819    * Blend 't' over 'o'
1820    * C = t.rgb + o.rgb * (1 - t.a)
1821    * a = t.a + o.a * (1 - t.a)
1822    *
1823    * These blending parameters and fragment shader perform this work.
1824    * Note that the opaque fragments are assumed to have premultiplied alpha
1825    * in this implementation. */
1826   this->State->vtkglEnable(GL_BLEND);
1827   this->State->vtkglBlendEquation(GL_FUNC_ADD);
1828   this->State->vtkglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1829 
1830   // Restore the original viewport and scissor test settings (see note in
1831   // Prepare).
1832   this->State->vtkglViewport(this->ViewportX, this->ViewportY,
1833              this->ViewportWidth, this->ViewportHeight);
1834   if (this->SaveScissorTestState)
1835   {
1836     this->State->vtkglEnable(GL_SCISSOR_TEST);
1837   }
1838   else
1839   {
1840     this->State->vtkglDisable(GL_SCISSOR_TEST);
1841   }
1842 
1843   vtkOpenGLRenderWindow *renWin = static_cast<vtkOpenGLRenderWindow*>(
1844         this->RenderState->GetRenderer()->GetRenderWindow());
1845   if (!this->BlendHelper)
1846   {
1847     std::string fragShader =
1848       vtkOpenGLRenderUtilities::GetFullScreenQuadFragmentShaderTemplate();
1849     vtkShaderProgram::Substitute(
1850           fragShader, "//VTK::FSQ::Decl",
1851           "uniform sampler2D frontTexture;\n"
1852           "uniform sampler2D backTexture;\n"
1853           );
1854     vtkShaderProgram::Substitute(
1855           fragShader, "//VTK::FSQ::Impl",
1856           "  vec4 front = texture2D(frontTexture, texCoord);\n"
1857           "  vec4 back = texture2D(backTexture, texCoord);\n"
1858           "  front.a = 1. - front.a; // stored as (1 - alpha)\n"
1859           "  // Underblend. Back color is premultiplied:\n"
1860           "  gl_FragData[0].rgb = (front.rgb + back.rgb * front.a);\n"
1861           "  // The first '1. - ...' is to convert the 'underblend' alpha to\n"
1862           "  // an 'overblend' alpha, since we'll be letting GL do the\n"
1863           "  // transparent-over-opaque blending pass.\n"
1864           "  gl_FragData[0].a = (1. - front.a * (1. - back.a));\n"
1865           );
1866     this->BlendHelper = new vtkOpenGLQuadHelper(renWin,
1867           nullptr,
1868           fragShader.c_str(),
1869           nullptr);
1870   }
1871   else
1872   {
1873     renWin->GetShaderCache()->ReadyShaderProgram(this->BlendHelper->Program);
1874   }
1875 
1876   if (!this->BlendHelper->Program)
1877   {
1878     return;
1879   }
1880 
1881   this->BlendHelper->Program->SetUniformi(
1882         "frontTexture", this->Textures[this->FrontSource]->GetTextureUnit());
1883   this->BlendHelper->Program->SetUniformi(
1884         "backTexture", this->Textures[Back]->GetTextureUnit());
1885 
1886 
1887   annotate("blending final!");
1888   this->BlendHelper->Render();
1889   annotate("final blended!");
1890 
1891 
1892   this->Textures[this->FrontSource]->Deactivate();
1893   this->Textures[Back]->Deactivate();
1894 }
1895 
1896 //------------------------------------------------------------------------------
DeleteOcclusionQueryIds()1897 void vtkDualDepthPeelingPass::DeleteOcclusionQueryIds()
1898 {
1899   glDeleteQueries(1, &this->TranslucentOcclusionQueryId);
1900   glDeleteQueries(1, &this->VolumetricOcclusionQueryId);
1901 }
1902