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