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