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