1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4 
5   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
6   All rights reserved.
7   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
8 
9      This software is distributed WITHOUT ANY WARRANTY; without even
10      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11      PURPOSE.  See the above copyright notice for more information.
12 
13 =========================================================================*/
14 
15 #include "vtkOpenGLFluidMapper.h"
16 #include "vtkOpenGLHelper.h"
17 
18 #include "vtkCommand.h"
19 #include "vtkExecutive.h"
20 #include "vtkMath.h"
21 #include "vtkMatrix3x3.h"
22 #include "vtkMatrix4x4.h"
23 #include "vtkObjectFactory.h"
24 #include "vtkOpenGLActor.h"
25 #include "vtkOpenGLCamera.h"
26 #include "vtkOpenGLFramebufferObject.h"
27 #include "vtkOpenGLIndexBufferObject.h"
28 #include "vtkOpenGLQuadHelper.h"
29 #include "vtkOpenGLRenderWindow.h"
30 #include "vtkOpenGLRenderer.h"
31 #include "vtkOpenGLShaderCache.h"
32 #include "vtkOpenGLState.h"
33 #include "vtkOpenGLTexture.h"
34 #include "vtkOpenGLVertexArrayObject.h"
35 #include "vtkOpenGLVertexBufferObject.h"
36 #include "vtkOpenGLVertexBufferObjectGroup.h"
37 #include "vtkPBRPrefilterTexture.h"
38 #include "vtkPointData.h"
39 #include "vtkPolyData.h"
40 #include "vtkProperty.h"
41 #include "vtkShaderProgram.h"
42 #include "vtkTextureObject.h"
43 #include "vtkVolumeProperty.h"
44 
45 #include "vtkFluidMapperDepthFilterBiGaussFS.h"
46 #include "vtkFluidMapperDepthFilterNarrowRangeFS.h"
47 #include "vtkFluidMapperFS.h"
48 #include "vtkFluidMapperFinalFS.h"
49 #include "vtkFluidMapperGS.h"
50 #include "vtkFluidMapperSurfaceNormalFS.h"
51 #include "vtkFluidMapperThicknessAndVolumeColorFilterFS.h"
52 #include "vtkFluidMapperVS.h"
53 
54 #include "vtk_glew.h"
55 
56 #include <cassert>
57 #include <sstream>
58 
59 //------------------------------------------------------------------------------
60 vtkStandardNewMacro(vtkOpenGLFluidMapper);
61 
62 //------------------------------------------------------------------------------
vtkOpenGLFluidMapper()63 vtkOpenGLFluidMapper::vtkOpenGLFluidMapper()
64   : VBOs(vtkOpenGLVertexBufferObjectGroup::New())
65   , TempMatrix4(vtkMatrix4x4::New())
66 {
67   for (int i = 0; i < NumTexBuffers; ++i)
68   {
69     this->TexBuffer[i] = vtkTextureObject::New();
70   }
71   for (int i = 0; i < NumOptionalTexBuffers; ++i)
72   {
73     this->OptionalTexBuffer[i] = vtkTextureObject::New();
74   }
75   this->CamDCVC = vtkMatrix4x4::New();
76   this->CamInvertedNorms = vtkMatrix3x3::New();
77 }
78 
79 //------------------------------------------------------------------------------
~vtkOpenGLFluidMapper()80 vtkOpenGLFluidMapper::~vtkOpenGLFluidMapper()
81 {
82   this->TempMatrix4->Delete();
83   this->VBOs->Delete();
84   for (int i = 0; i < NumTexBuffers; ++i)
85   {
86     this->TexBuffer[i]->Delete();
87   }
88   for (int i = 0; i < NumOptionalTexBuffers; ++i)
89   {
90     this->OptionalTexBuffer[i]->Delete();
91   }
92   this->CamDCVC->Delete();
93   this->CamInvertedNorms->Delete();
94 }
95 
96 //------------------------------------------------------------------------------
SetInputData(vtkPolyData * input)97 void vtkOpenGLFluidMapper::SetInputData(vtkPolyData* input)
98 {
99   this->SetInputDataInternal(0, input);
100 }
101 
102 //------------------------------------------------------------------------------
103 // Specify the input data or filter.
GetInput()104 vtkPolyData* vtkOpenGLFluidMapper::GetInput()
105 {
106   return vtkPolyData::SafeDownCast(this->GetExecutive()->GetInputData(0, 0));
107 }
108 
109 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)110 void vtkOpenGLFluidMapper::PrintSelf(ostream& os, vtkIndent indent)
111 {
112   this->Superclass::PrintSelf(os, indent);
113   os << indent << "Particle radius: " << this->ParticleRadius << "\n";
114 }
115 
116 //------------------------------------------------------------------------------
UpdateDepthThicknessColorShaders(vtkOpenGLHelper & glHelper,vtkRenderer * renderer,vtkVolume * actor)117 void vtkOpenGLFluidMapper::UpdateDepthThicknessColorShaders(
118   vtkOpenGLHelper& glHelper, vtkRenderer* renderer, vtkVolume* actor)
119 {
120   const auto renderWindow = vtkOpenGLRenderWindow::SafeDownCast(renderer->GetRenderWindow());
121 
122   glHelper.VAO->Bind();
123 
124   // Has something changed that would require us to recreate the shader?
125   if (!glHelper.Program)
126   {
127     // Build the shader source code
128     std::map<vtkShader::Type, vtkShader*> shaders;
129 
130     vtkShader* vertexShader = vtkShader::New();
131     vertexShader->SetType(vtkShader::Vertex);
132     vertexShader->SetSource(vtkFluidMapperVS);
133     shaders[vtkShader::Vertex] = vertexShader;
134 
135     vtkShader* geomShader = vtkShader::New();
136     geomShader->SetType(vtkShader::Geometry);
137     geomShader->SetSource(vtkFluidMapperGS);
138     shaders[vtkShader::Geometry] = geomShader;
139 
140     vtkShader* fragmentShader = vtkShader::New();
141     fragmentShader->SetType(vtkShader::Fragment);
142     fragmentShader->SetSource(vtkFluidMapperFS);
143     shaders[vtkShader::Fragment] = fragmentShader;
144 
145     // Compile and bind the program if needed
146     vtkShaderProgram* newProgram = renderWindow->GetShaderCache()->ReadyShaderProgram(shaders);
147 
148     // Done with you, now you're thrown away
149     fragmentShader->Delete();
150     geomShader->Delete();
151     vertexShader->Delete();
152 
153     // If the shader changed, reinitialize the VAO
154     if (newProgram != glHelper.Program)
155     {
156       glHelper.Program = newProgram;
157       // reset the VAO as the shader has changed
158       glHelper.VAO->ReleaseGraphicsResources();
159     }
160     glHelper.ShaderSourceTime.Modified();
161   }
162   else
163   {
164     renderWindow->GetShaderCache()->ReadyShaderProgram(glHelper.Program);
165   }
166 
167   if (glHelper.Program)
168   {
169     this->SetDepthThicknessColorShaderParameters(glHelper, renderer, actor);
170 
171     // Allow the program to set what it wants
172     this->InvokeEvent(vtkCommand::UpdateShaderEvent, glHelper.Program);
173   }
174 }
175 
176 //------------------------------------------------------------------------------
SetDepthThicknessColorShaderParameters(vtkOpenGLHelper & glHelper,vtkRenderer * ren,vtkVolume * actor)177 void vtkOpenGLFluidMapper::SetDepthThicknessColorShaderParameters(
178   vtkOpenGLHelper& glHelper, vtkRenderer* ren, vtkVolume* actor)
179 {
180   if (glHelper.IBO->IndexCount &&
181     (this->VBOs->GetMTime() > glHelper.AttributeUpdateTime ||
182       glHelper.ShaderSourceTime > glHelper.AttributeUpdateTime))
183   {
184     glHelper.VAO->Bind();
185     this->VBOs->AddAllAttributesToVAO(glHelper.Program, glHelper.VAO);
186     glHelper.AttributeUpdateTime.Modified();
187   }
188 
189   const auto program = glHelper.Program;
190 
191   program->SetUniformi("outputEyeZ", this->InDepthPass);
192   if (!this->InDepthPass)
193   {
194     // based on clipping range
195     program->SetUniformf("minThickness", ren->GetActiveCamera()->GetClippingRange()[1] * 1.0e-9);
196   }
197   if (this->HasVertexColor)
198   {
199     program->SetUniformi("hasVertexColor", this->HasVertexColor);
200   }
201 
202   // Set texture and particle radius
203   program->SetUniformi("opaqueZTexture", this->TexBuffer[OpaqueZ]->GetTextureUnit());
204   program->SetUniformf("particleRadius", this->ParticleRadius);
205 
206   // Set camera
207   if (program->IsUniformUsed("VCDCMatrix"))
208   {
209     program->SetUniformMatrix("VCDCMatrix", this->CamVCDC);
210   }
211 
212   if (program->IsUniformUsed("MCVCMatrix"))
213   {
214     if (!actor->GetIsIdentity())
215     {
216       vtkMatrix4x4* mcwc;
217       vtkMatrix3x3* anorms;
218       ((vtkOpenGLActor*)actor)->GetKeyMatrices(mcwc, anorms);
219       vtkMatrix4x4::Multiply4x4(mcwc, this->CamWCVC, this->TempMatrix4);
220       program->SetUniformMatrix("MCVCMatrix", this->TempMatrix4);
221     }
222     else
223     {
224       program->SetUniformMatrix("MCVCMatrix", this->CamWCVC);
225     }
226   }
227   if (program->IsUniformUsed("cameraParallel"))
228   {
229     glHelper.Program->SetUniformi("cameraParallel", this->CamParallelProjection);
230   }
231 }
232 
SetupBuffers(vtkOpenGLRenderWindow * const renderWindow)233 void vtkOpenGLFluidMapper::SetupBuffers(vtkOpenGLRenderWindow* const renderWindow)
234 {
235   // create textures we need if not done already
236   if (this->TexBuffer[0]->GetHandle() == 0)
237   {
238     for (int i = 0; i < NumTexBuffers; ++i)
239     {
240       this->TexBuffer[i]->SetContext(renderWindow);
241       switch (i)
242       {
243         case OpaqueZ:
244         case FluidZ:
245           this->TexBuffer[i]->AllocateDepth(static_cast<unsigned int>(this->ViewportWidth),
246             static_cast<unsigned int>(this->ViewportHeight), vtkTextureObject::Float32);
247           break;
248         case FluidEyeZ:
249         case SmoothedFluidEyeZ:
250         case FluidThickness:
251         case SmoothedFluidThickness:
252           this->TexBuffer[i]->SetInternalFormat(GL_R32F);
253           this->TexBuffer[i]->SetFormat(GL_RED);
254           this->TexBuffer[i]->Allocate2D(static_cast<unsigned int>(this->ViewportWidth),
255             static_cast<unsigned int>(this->ViewportHeight), 1, VTK_FLOAT);
256           break;
257         case FluidNormal:
258           this->TexBuffer[i]->Allocate2D(static_cast<unsigned int>(this->ViewportWidth),
259             static_cast<unsigned int>(this->ViewportHeight), 3, VTK_FLOAT);
260           break;
261         case OpaqueRGBA:
262           this->TexBuffer[i]->Allocate2D(static_cast<unsigned int>(this->ViewportWidth),
263             static_cast<unsigned int>(this->ViewportHeight), 4, VTK_UNSIGNED_CHAR);
264           break;
265         default:;
266       }
267 
268       this->TexBuffer[i]->SetMinificationFilter(vtkTextureObject::Nearest);
269       this->TexBuffer[i]->SetMagnificationFilter(vtkTextureObject::Nearest);
270       this->TexBuffer[i]->SetWrapS(vtkTextureObject::ClampToEdge);
271       this->TexBuffer[i]->SetWrapT(vtkTextureObject::ClampToEdge);
272     }
273   }
274   else
275   {
276     // make sure we handle size changes
277     for (int i = 0; i < NumTexBuffers; ++i)
278     {
279       this->TexBuffer[i]->Resize(static_cast<unsigned int>(this->ViewportWidth),
280         static_cast<unsigned int>(this->ViewportHeight));
281     }
282   }
283 
284   // Allocate additional 2 texture bufferes for color data
285   if (this->HasVertexColor)
286   {
287     if (this->OptionalTexBuffer[0]->GetHandle() == 0)
288     {
289       for (int i = 0; i < NumOptionalTexBuffers; ++i)
290       {
291         this->OptionalTexBuffer[i]->SetContext(renderWindow);
292         this->OptionalTexBuffer[i]->Allocate2D(static_cast<unsigned int>(this->ViewportWidth),
293           static_cast<unsigned int>(this->ViewportHeight), 3, VTK_FLOAT);
294         this->OptionalTexBuffer[i]->SetMinificationFilter(vtkTextureObject::Nearest);
295         this->OptionalTexBuffer[i]->SetMagnificationFilter(vtkTextureObject::Nearest);
296         this->OptionalTexBuffer[i]->SetWrapS(vtkTextureObject::ClampToEdge);
297         this->OptionalTexBuffer[i]->SetWrapT(vtkTextureObject::ClampToEdge);
298       }
299     }
300     else
301     {
302       // make sure we handle size changes
303       for (int i = 0; i < NumOptionalTexBuffers; ++i)
304       {
305         this->OptionalTexBuffer[i]->Resize(static_cast<unsigned int>(this->ViewportWidth),
306           static_cast<unsigned int>(this->ViewportHeight));
307       }
308     }
309   }
310 
311   // copy the opaque buffers into textures
312   this->TexBuffer[OpaqueZ]->CopyFromFrameBuffer(this->ViewportX, this->ViewportY, this->ViewportX,
313     this->ViewportY, this->ViewportWidth, this->ViewportHeight);
314   this->TexBuffer[OpaqueRGBA]->CopyFromFrameBuffer(this->ViewportX, this->ViewportY,
315     this->ViewportX, this->ViewportY, this->ViewportWidth, this->ViewportHeight);
316 
317   if (!this->FBFluidEyeZ)
318   {
319     this->FBFluidEyeZ = vtkOpenGLFramebufferObject::New();
320     this->FBFluidEyeZ->SetContext(renderWindow);
321     this->FBFluidEyeZ->AddDepthAttachment(this->TexBuffer[FluidZ]); // Must have a depth buffer
322   }
323 
324   if (!this->FBThickness)
325   {
326     this->FBThickness = vtkOpenGLFramebufferObject::New();
327     this->FBThickness->SetContext(renderWindow);
328     this->FBThickness->AddDepthAttachment(this->TexBuffer[FluidZ]); // Must have a depth buffer
329   }
330 
331   if (!this->FBFilterThickness)
332   {
333     this->FBFilterThickness = vtkOpenGLFramebufferObject::New();
334     this->FBFilterThickness->SetContext(renderWindow);
335     // Color attachment will be dynamically added later
336   }
337 
338   if (!this->FBFilterDepth)
339   {
340     this->FBFilterDepth = vtkOpenGLFramebufferObject::New();
341     this->FBFilterDepth->SetContext(renderWindow);
342     // Color attachment will be dynamically added later
343   }
344 
345   if (!this->FBCompNormal)
346   {
347     this->FBCompNormal = vtkOpenGLFramebufferObject::New();
348     this->FBCompNormal->SetContext(renderWindow);
349     this->FBCompNormal->AddColorAttachment(0, this->TexBuffer[FluidNormal]);
350   }
351 }
352 
353 //------------------------------------------------------------------------------
Render(vtkRenderer * renderer,vtkVolume * vol)354 void vtkOpenGLFluidMapper::Render(vtkRenderer* renderer, vtkVolume* vol)
355 {
356   // make sure we have data
357   vtkPolyData* input = vtkPolyData::SafeDownCast(GetInputDataObject(0, 0));
358   if (input == nullptr || input->GetPoints() == nullptr)
359   {
360     return;
361   }
362 
363   // check to see if we are using vertex coloring
364   int cellFlag = 0;
365   vtkDataArray* scalars = vtkOpenGLFluidMapper::GetScalars(
366     input, this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, cellFlag);
367 
368   this->HasVertexColor = false;
369   if (scalars && cellFlag == 0 && scalars->GetNumberOfComponents() == 3 && this->ScalarVisibility)
370   {
371     this->HasVertexColor = true;
372   }
373 
374   // Get the viewport dimensions
375   renderer->GetTiledSizeAndOrigin(
376     &this->ViewportWidth, &this->ViewportHeight, &this->ViewportX, &this->ViewportY);
377 
378   // Get the camera parameters
379   const auto cam = static_cast<vtkOpenGLCamera*>(renderer->GetActiveCamera());
380   vtkMatrix3x3* tmpNormMat;
381   cam->GetKeyMatrices(renderer, this->CamWCVC, tmpNormMat, this->CamVCDC, this->CamWCDC);
382   this->CamDCVC->DeepCopy(this->CamVCDC);
383   this->CamDCVC->Invert();
384   this->CamInvertedNorms->DeepCopy(tmpNormMat);
385   this->CamInvertedNorms->Invert();
386   this->CamParallelProjection = cam->GetParallelProjection();
387 
388   // Prepare the texture and frame buffers
389   const auto renderWindow = vtkOpenGLRenderWindow::SafeDownCast(renderer->GetRenderWindow());
390   this->SetupBuffers(renderWindow);
391 
392   const auto glState = renderWindow->GetState();
393   glState->vtkglViewport(0, 0, this->ViewportWidth, this->ViewportHeight);
394   bool saveScissorTestState = glState->GetEnumState(GL_SCISSOR_TEST);
395 #ifdef GL_MULTISAMPLE
396   glState->vtkglDisable(GL_MULTISAMPLE);
397 #endif
398 
399   double* crange = cam->GetClippingRange();
400 
401   // Generate depth
402   {
403     // Attach texture every time, since it will be swapped out during smoothing
404     this->FBFluidEyeZ->SetContext(renderWindow);
405     glState->PushFramebufferBindings();
406     this->FBFluidEyeZ->Bind();
407     this->FBFluidEyeZ->AddColorAttachment(0U, this->TexBuffer[FluidEyeZ]);
408     this->FBFluidEyeZ->ActivateDrawBuffers(1);
409     this->FBFluidEyeZ->CheckFrameBufferStatus(GL_FRAMEBUFFER);
410     glState->vtkglDisable(GL_SCISSOR_TEST);
411     glState->vtkglClearDepth(1.0);
412     glState->vtkglColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
413     // Set a clear color value to be slightly past the far clipping plane
414     glState->vtkglClearColor(-1.1 * crange[1], 0.0, 0.0, 0.0);
415     glState->vtkglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
416 
417     // Render the spheres to get the eye coordinate z values
418     this->TexBuffer[OpaqueZ]->Activate();
419     glState->vtkglDepthMask(GL_TRUE);
420     glState->vtkglEnable(GL_DEPTH_TEST);
421     glState->vtkglDepthFunc(GL_LEQUAL);
422     this->InDepthPass = true;
423     this->RenderParticles(renderer, vol);
424     this->InDepthPass = false;
425     this->TexBuffer[OpaqueZ]->Deactivate();
426     this->FBFluidEyeZ->DeactivateDrawBuffers();
427     this->FBFluidEyeZ->RemoveColorAttachment(0U);
428     glState->PopFramebufferBindings();
429   }
430 
431   // Generate thickness and color (if applicable)
432   {
433     // Attache texture every time, since it will be swapped out during smoothing
434     this->FBThickness->SetContext(renderWindow);
435     glState->PushFramebufferBindings();
436     this->FBThickness->Bind();
437     this->FBThickness->AddColorAttachment(0U, this->TexBuffer[FluidThickness]);
438     this->FBThickness->ActivateDrawBuffers(1);
439     this->FBThickness->CheckFrameBufferStatus(GL_FRAMEBUFFER);
440     if (this->HasVertexColor)
441     {
442       this->FBThickness->AddColorAttachment(1, this->OptionalTexBuffer[Color]);
443       this->FBThickness->ActivateDrawBuffers(2);
444       this->FBThickness->CheckFrameBufferStatus(GL_FRAMEBUFFER);
445     }
446     glState->vtkglDisable(GL_SCISSOR_TEST);
447     glState->vtkglClearDepth(1.0);
448     glState->vtkglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
449     glState->vtkglClearColor(0.0, 0.0, 0.0, 0.0);
450     glState->vtkglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
451 
452     vtkOpenGLState::ScopedglBlendFuncSeparate bf(glState);
453     glState->vtkglBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ONE);
454 
455     this->TexBuffer[OpaqueZ]->Activate();
456     glState->vtkglDepthMask(GL_FALSE);
457     glState->vtkglDisable(GL_DEPTH_TEST);
458     glState->vtkglDepthFunc(GL_ALWAYS);
459     this->RenderParticles(renderer, vol);
460     this->TexBuffer[OpaqueZ]->Deactivate();
461     this->FBThickness->DeactivateDrawBuffers();
462     if (this->HasVertexColor)
463     {
464       this->FBThickness->RemoveColorAttachment(1U);
465     }
466     this->FBThickness->RemoveColorAttachment(0U);
467     glState->PopFramebufferBindings();
468   }
469 
470   // Filter fluid thickness and color (if applicable)
471   if (true)
472   {
473     if (!this->QuadThicknessFilter)
474     {
475       this->QuadThicknessFilter = new vtkOpenGLQuadHelper(
476         renderWindow, nullptr, vtkFluidMapperThicknessAndVolumeColorFilterFS, "");
477     }
478     else
479     {
480       renderWindow->GetShaderCache()->ReadyShaderProgram(this->QuadThicknessFilter->Program);
481     }
482     const auto program = this->QuadThicknessFilter->Program;
483     assert(program);
484 
485     // Attache texture every time, since it will be swapped out during smoothing
486     this->FBFilterThickness->SetContext(renderWindow);
487     glState->PushFramebufferBindings();
488 
489     for (uint32_t iter = 0; iter < this->ThicknessAndVolumeColorFilterIterations; ++iter)
490     {
491       this->FBFilterThickness->Bind();
492       this->FBFilterThickness->AddColorAttachment(0U, this->TexBuffer[SmoothedFluidThickness]);
493       this->FBFilterThickness->ActivateDrawBuffers(1);
494       this->FBFilterThickness->CheckFrameBufferStatus(GL_FRAMEBUFFER);
495       glState->vtkglClearDepth(1.0);
496       glState->vtkglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
497       glState->vtkglClearColor(0.0, 0.0, 0.0, 0.0);
498       glState->vtkglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
499       if (this->HasVertexColor)
500       {
501         this->FBFilterThickness->AddColorAttachment(1, this->OptionalTexBuffer[SmoothedColor]);
502         this->FBFilterThickness->ActivateDrawBuffers(2);
503         this->OptionalTexBuffer[Color]->Activate();
504         program->SetUniformi("hasVertexColor", this->HasVertexColor);
505         program->SetUniformi("fluidColorTexture", this->OptionalTexBuffer[Color]->GetTextureUnit());
506       }
507 
508       this->TexBuffer[FluidThickness]->Activate();
509       program->SetUniformi(
510         "fluidThicknessTexture", this->TexBuffer[FluidThickness]->GetTextureUnit());
511 
512       program->SetUniformi("viewportHeight", this->ViewportHeight);
513       program->SetUniformi("viewportWidth", this->ViewportWidth);
514       program->SetUniformi(
515         "filterRadius", static_cast<int>(this->ThicknessAndVolumeColorFilterRadius));
516 
517       this->QuadThicknessFilter->Render();
518       this->TexBuffer[FluidThickness]->Deactivate();
519       this->FBFilterThickness->DeactivateDrawBuffers();
520       this->FBFilterThickness->RemoveColorAttachment(0U);
521 
522       std::swap(this->TexBuffer[FluidThickness], this->TexBuffer[SmoothedFluidThickness]);
523       if (this->HasVertexColor)
524       {
525         this->OptionalTexBuffer[Color]->Deactivate();
526         std::swap(this->OptionalTexBuffer[Color], this->OptionalTexBuffer[SmoothedColor]);
527       }
528     }
529     glState->PopFramebufferBindings();
530   }
531 
532   if (true)
533   {
534     // Filter depth surface
535     if (DisplayMode != UnfilteredOpaqueSurface && DisplayMode != UnfilteredSurfaceNormal)
536     {
537       if (!this->QuadFluidDepthFilter[SurfaceFilterMethod])
538       {
539         switch (this->SurfaceFilterMethod)
540         {
541           case BilateralGaussian:
542             this->QuadFluidDepthFilter[SurfaceFilterMethod] = new vtkOpenGLQuadHelper(
543               renderWindow, nullptr, vtkFluidMapperDepthFilterBiGaussFS, "");
544             break;
545           case NarrowRange:
546             this->QuadFluidDepthFilter[SurfaceFilterMethod] = new vtkOpenGLQuadHelper(
547               renderWindow, nullptr, vtkFluidMapperDepthFilterNarrowRangeFS, "");
548             break;
549           // New filter method is added here
550           default:
551             vtkErrorMacro("Invalid filter method");
552         }
553       }
554       else
555       {
556         renderWindow->GetShaderCache()->ReadyShaderProgram(
557           this->QuadFluidDepthFilter[SurfaceFilterMethod]->Program);
558       }
559 
560       const auto program = this->QuadFluidDepthFilter[SurfaceFilterMethod]->Program;
561       assert(program);
562       this->FBFilterDepth->SetContext(renderWindow);
563       glState->PushFramebufferBindings();
564 
565       program->SetUniformi("viewportHeight", this->ViewportHeight);
566       program->SetUniformi("viewportWidth", this->ViewportWidth);
567       program->SetUniformi("filterRadius", static_cast<int>(this->SurfaceFilterRadius));
568       program->SetUniformf("particleRadius", this->ParticleRadius);
569       program->SetUniformf("farZValue", -crange[1]);
570 
571       for (uint32_t iter = 0; iter < this->SurfaceFilterIterations; ++iter)
572       {
573         this->FBFilterDepth->Bind();
574         this->FBFilterDepth->AddColorAttachment(
575           0U, this->TexBuffer[SmoothedFluidEyeZ]); // Replace color attachement
576         this->FBFilterDepth->ActivateDrawBuffers(1);
577         this->FBFilterDepth->CheckFrameBufferStatus(GL_FRAMEBUFFER);
578         glState->vtkglClearDepth(1.0);
579         glState->vtkglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
580         glState->vtkglClearColor(0.0, 0.0, 0.0, 0.0);
581         glState->vtkglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
582 
583         switch (SurfaceFilterMethod)
584         {
585           case BilateralGaussian:
586             program->SetUniformf("sigmaDepth", this->BiGaussFilterSigmaDepth);
587             break;
588           case NarrowRange:
589             program->SetUniformf("lambda", this->NRFilterLambda);
590             program->SetUniformf("mu", this->NRFilterMu);
591             break;
592           // New filter method is added here
593           default:
594             vtkErrorMacro("Invalid filter method");
595         }
596 
597         glState->vtkglEnable(GL_DEPTH_TEST);
598         this->TexBuffer[FluidEyeZ]->Activate();
599         program->SetUniformi("fluidZTexture", this->TexBuffer[FluidEyeZ]->GetTextureUnit());
600 
601         this->QuadFluidDepthFilter[SurfaceFilterMethod]->Render();
602         this->TexBuffer[FluidEyeZ]->Deactivate();
603         this->FBFilterDepth->DeactivateDrawBuffers();
604         this->FBFilterDepth->RemoveColorAttachment(0);
605 
606         // Swap the filtered buffers
607         std::swap(this->TexBuffer[FluidEyeZ], this->TexBuffer[SmoothedFluidEyeZ]);
608       }
609 
610       glState->PopFramebufferBindings();
611     }
612   }
613 
614   // Compute normal for the filtered depth surface
615   if (true)
616   {
617     if (!this->QuadFluidNormal)
618     {
619       this->QuadFluidNormal =
620         new vtkOpenGLQuadHelper(renderWindow, nullptr, vtkFluidMapperSurfaceNormalFS, "");
621     }
622     else
623     {
624       renderWindow->GetShaderCache()->ReadyShaderProgram(this->QuadFluidNormal->Program);
625     }
626 
627     const auto program = this->QuadFluidNormal->Program;
628     assert(program);
629 
630     this->FBCompNormal->SetContext(renderWindow);
631     glState->PushFramebufferBindings();
632     this->FBCompNormal->Bind();
633     this->FBCompNormal->AddColorAttachment(0, this->TexBuffer[FluidNormal]);
634     this->FBCompNormal->ActivateDrawBuffers(1);
635     this->FBCompNormal->CheckFrameBufferStatus(GL_FRAMEBUFFER);
636 
637     this->TexBuffer[FluidEyeZ]->Activate();
638     program->SetUniformi("fluidZTexture", this->TexBuffer[FluidEyeZ]->GetTextureUnit());
639 
640     program->SetUniformi("viewportHeight", this->ViewportHeight);
641     program->SetUniformi("viewportWidth", this->ViewportWidth);
642     program->SetUniformMatrix("DCVCMatrix", this->CamDCVC);
643     program->SetUniformMatrix("VCDCMatrix", this->CamVCDC);
644 
645     glState->vtkglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
646     glState->vtkglDepthMask(GL_FALSE);
647     glState->vtkglDisable(GL_DEPTH_TEST);
648     glState->vtkglDepthFunc(GL_ALWAYS);
649     glState->vtkglClearColor(0.0, 0.0, 0.0, 0.0);
650     glState->vtkglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
651 
652     this->QuadFluidNormal->Render();
653     this->TexBuffer[FluidEyeZ]->Deactivate();
654     this->FBCompNormal->DeactivateDrawBuffers();
655     glState->PopFramebufferBindings();
656   }
657 
658   vtkOpenGLRenderer* oren = static_cast<vtkOpenGLRenderer*>(renderer);
659 
660   // Restore the original viewport properties
661   glState->vtkglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
662   glState->vtkglViewport(
663     this->ViewportX, this->ViewportY, this->ViewportWidth, this->ViewportHeight);
664   saveScissorTestState ? glState->vtkglEnable(GL_SCISSOR_TEST)
665                        : glState->vtkglDisable(GL_SCISSOR_TEST);
666 
667   {
668     bool useIBL = oren->GetUseImageBasedLighting() && oren->GetEnvironmentTexture();
669 
670     // Final blend, render everything
671     if (!this->QuadFinalBlend)
672     {
673       std::ostringstream toString;
674 
675       // todo this needs to be done when the lighting code changes
676       // if the light complexity changed then update the shader code
677       std::string fssource = vtkFluidMapperFinalFS;
678       vtkShaderProgram::Substitute(fssource, "//VTK::Light::Dec", oren->GetLightingUniforms());
679       switch (oren->GetLightingComplexity())
680       {
681         // no lighting
682         case 0:
683           vtkShaderProgram::Substitute(fssource, "//VTK::Light::Impl",
684             "  accumulatedLightSpecularColor = vec3(1.0,1.0,1.0);", false);
685           break;
686 
687         // headlight
688         case 1:
689           vtkShaderProgram::Substitute(fssource, "//VTK::Light::Impl",
690             "  float df = max(0.0,N.z);\n"
691             "  float sf = pow(df, fluidShininess);\n"
692             "  accumulatedLightDiffuseColor = df * lightColor0;\n"
693             "  accumulatedLightSpecularColor = sf * lightColor0;\n"
694             "  //VTK::Light::Impl\n",
695             false);
696           break;
697         case 2:
698           toString << "  float df;\n"
699                       "  float sf;\n";
700           for (int i = 0; i < oren->GetLightingCount(); ++i)
701           {
702             toString << "  df = max(0.0, dot(N, -lightDirectionVC" << i
703                      << "));\n"
704                         "  accumulatedLightDiffuseColor += (df * lightColor"
705                      << i << ");\n"
706                      << "  sf = sign(df)*pow(max(0.0, dot( reflect(lightDirectionVC" << i
707                      << "     , N), normalize(-position))), fluidShininess);\n"
708                         "  accumulatedLightSpecularColor += (sf * lightColor"
709                      << i << ");\n";
710           }
711           vtkShaderProgram::Substitute(fssource, "//VTK::Light::Impl", toString.str(), false);
712           break;
713         case 3:
714           toString << "  vec3 vertLightDirectionVC;\n"
715                       "  float attenuation;\n"
716                       "  float df;\n"
717                       "  float sf;\n";
718           for (int i = 0; i < oren->GetLightingCount(); ++i)
719           {
720             toString << "    attenuation = 1.0;\n"
721                         "    if (lightPositional"
722                      << i
723                      << " == 0) {\n"
724                         "      vertLightDirectionVC = lightDirectionVC"
725                      << i
726                      << "; }\n"
727                         "    else {\n"
728                         "      vertLightDirectionVC = position - lightPositionVC"
729                      << i
730                      << ";\n"
731                         "      float distanceVC = length(vertLightDirectionVC);\n"
732                         "      vertLightDirectionVC = "
733                         "normalize(vertLightDirectionVC);\n"
734                         "      attenuation = 1.0 /\n"
735                         "        (lightAttenuation"
736                      << i
737                      << ".x\n"
738                         "         + lightAttenuation"
739                      << i
740                      << ".y * distanceVC\n"
741                         "         + lightAttenuation"
742                      << i
743                      << ".z * distanceVC * distanceVC);\n"
744                         "      // per OpenGL standard cone angle is 90 or less for a "
745                         "spot light\n"
746                         "      if (lightConeAngle"
747                      << i
748                      << " <= 90.0) {\n"
749                         "        float coneDot = dot(vertLightDirectionVC, "
750                         "lightDirectionVC"
751                      << i
752                      << ");\n"
753                         "        // if inside the cone\n"
754                         "        if (coneDot >= cos(radians(lightConeAngle"
755                      << i
756                      << "))) {\n"
757                         "          attenuation = attenuation * pow(coneDot, "
758                         "lightExponent"
759                      << i
760                      << "); }\n"
761                         "        else {\n"
762                         "          attenuation = 0.0; }\n"
763                         "        }\n"
764                         "      }\n"
765                      << "    df = max(0.0,attenuation*dot(N, "
766                         "-vertLightDirectionVC));\n"
767                         "    accumulatedLightDiffuseColor += (df * lightColor"
768                      << i << ");\n"
769                      << "    sf = sign(df)*attenuation*pow( max(0.0, dot( "
770                         "reflect(vertLightDirectionVC, N), normalize(-position))), "
771                         "fluidShininess);\n"
772                         "    accumulatedLightSpecularColor += (sf * lightColor"
773                      << i << ");\n";
774           }
775 
776           vtkShaderProgram::Substitute(fssource, "//VTK::Light::Impl", toString.str(), false);
777           break;
778       }
779 
780       if (useIBL)
781       {
782         vtkShaderProgram::Substitute(fssource, "//VTK::UseIBL::Dec", "#define UseIBL", false);
783       }
784 
785       this->QuadFinalBlend = new vtkOpenGLQuadHelper(renderWindow, nullptr, fssource.c_str(), "");
786     }
787     else
788     {
789       renderWindow->GetShaderCache()->ReadyShaderProgram(this->QuadFinalBlend->Program);
790     }
791 
792     const auto program = this->QuadFinalBlend->Program;
793     assert(program);
794 
795     oren->UpdateLightingUniforms(program);
796 
797     // Add IBL textures
798     if (useIBL)
799     {
800       program->SetUniformi("prefilterTex", oren->GetEnvMapPrefiltered()->GetTextureUnit());
801       program->SetUniformMatrix("invNormalMatrix", this->CamInvertedNorms);
802     }
803 
804     this->TexBuffer[FluidEyeZ]->Activate();
805     program->SetUniformi("fluidZTexture", this->TexBuffer[FluidEyeZ]->GetTextureUnit());
806 
807     this->TexBuffer[FluidThickness]->Activate();
808     program->SetUniformi(
809       "fluidThicknessTexture", this->TexBuffer[FluidThickness]->GetTextureUnit());
810 
811     this->TexBuffer[FluidNormal]->Activate();
812     program->SetUniformi("fluidNormalTexture", this->TexBuffer[FluidNormal]->GetTextureUnit());
813 
814     this->TexBuffer[OpaqueRGBA]->Activate();
815     program->SetUniformi("opaqueRGBATexture", this->TexBuffer[OpaqueRGBA]->GetTextureUnit());
816 
817     if (this->HasVertexColor)
818     {
819       this->OptionalTexBuffer[Color]->Activate();
820       program->SetUniformi("fluidColorTexture", this->OptionalTexBuffer[Color]->GetTextureUnit());
821       program->SetUniformi("hasVertexColor", this->HasVertexColor);
822       program->SetUniformf("vertexColorPower", this->ParticleColorPower);
823       program->SetUniformf("vertexColorScale", this->ParticleColorScale);
824     }
825 
826     program->SetUniformMatrix("DCVCMatrix", this->CamDCVC);
827     program->SetUniformMatrix("VCDCMatrix", this->CamVCDC);
828     if (this->QuadFinalBlend->Program->IsUniformUsed("MCVCMatrix"))
829     {
830       if (!vol->GetIsIdentity())
831       {
832         vtkMatrix4x4* mcwc;
833         vtkMatrix3x3* anorms;
834         ((vtkOpenGLActor*)vol)->GetKeyMatrices(mcwc, anorms);
835         vtkMatrix4x4::Multiply4x4(mcwc, this->CamWCVC, this->TempMatrix4);
836         this->QuadFinalBlend->Program->SetUniformMatrix("MCVCMatrix", this->TempMatrix4);
837       }
838       else
839       {
840         this->QuadFinalBlend->Program->SetUniformMatrix("MCVCMatrix", this->CamWCVC);
841       }
842     }
843 
844     program->SetUniformi("displayModeOpaqueSurface",
845       this->DisplayMode == UnfilteredOpaqueSurface || this->DisplayMode == FilteredOpaqueSurface);
846     program->SetUniformi("displayModeSurfaceNormal",
847       this->DisplayMode == UnfilteredSurfaceNormal || this->DisplayMode == FilteredSurfaceNormal);
848     program->SetUniformf("attenuationScale", this->AttenuationScale);
849     program->SetUniformf("additionalReflection", this->AdditionalReflection);
850     program->SetUniformf("refractiveIndex", this->RefractiveIndex);
851     program->SetUniformf("refractionScale", this->RefractionScale);
852     program->SetUniform3f("fluidOpaqueColor", this->OpaqueColor);
853     program->SetUniform3f("fluidAttenuationColor", this->AttenuationColor);
854     program->SetUniformf("farZValue", -crange[1]);
855     program->SetUniformf("ambientValue", vol->GetProperty()->GetAmbient());
856     glState->vtkglEnable(GL_DEPTH_TEST);
857     glState->vtkglDepthMask(GL_TRUE);
858     glState->vtkglDepthFunc(GL_ALWAYS);
859 
860     this->QuadFinalBlend->Render();
861 
862     this->TexBuffer[OpaqueZ]->Deactivate();
863     this->TexBuffer[OpaqueRGBA]->Deactivate();
864     this->TexBuffer[FluidEyeZ]->Deactivate();
865     this->TexBuffer[FluidThickness]->Deactivate();
866     this->TexBuffer[FluidNormal]->Deactivate();
867     if (this->HasVertexColor)
868     {
869       this->OptionalTexBuffer[Color]->Deactivate();
870     }
871 
872     glState->vtkglDepthFunc(GL_LEQUAL);
873   }
874 }
875 
876 //------------------------------------------------------------------------------
RenderParticles(vtkRenderer * renderer,vtkVolume * vol)877 void vtkOpenGLFluidMapper::RenderParticles(vtkRenderer* renderer, vtkVolume* vol)
878 {
879   vtkPolyData* input = vtkPolyData::SafeDownCast(GetInputDataObject(0, 0));
880   if (input == nullptr || input->GetPoints() == nullptr)
881   {
882     return;
883   }
884 
885   if (this->VBOBuildTime < input->GetPoints()->GetMTime())
886   {
887     this->VBOs->CacheDataArray("vertexMC", input->GetPoints()->GetData(), renderer, VTK_FLOAT);
888 
889     if (this->HasVertexColor)
890     {
891       int cellFlag = 0;
892       vtkDataArray* scalars = vtkOpenGLFluidMapper::GetScalars(
893         input, this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, cellFlag);
894       this->VBOs->CacheDataArray("vertexColor", scalars, renderer, VTK_FLOAT);
895     }
896     this->VBOs->BuildAllVBOs(renderer);
897 
898     vtkIdType numPts = input->GetPoints()->GetNumberOfPoints();
899     this->GLHelperDepthThickness.IBO->IndexCount = static_cast<size_t>(numPts);
900     this->VBOBuildTime.Modified();
901   }
902 
903   // draw polygons
904   int numVerts = this->VBOs->GetNumberOfTuples("vertexMC");
905   if (numVerts)
906   {
907     // First we do the triangles, update the shader, set uniforms, etc.
908     this->UpdateDepthThicknessColorShaders(this->GLHelperDepthThickness, renderer, vol);
909     glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(numVerts));
910   }
911 }
912 
913 //------------------------------------------------------------------------------
914 // Description:
915 // Destructor. Delete SourceCode if any.
ReleaseGraphicsResources(vtkWindow * w)916 void vtkOpenGLFluidMapper::ReleaseGraphicsResources(vtkWindow* w)
917 {
918   if (this->FBFluidEyeZ != nullptr)
919   {
920     this->FBFluidEyeZ->ReleaseGraphicsResources(w);
921     this->FBFluidEyeZ->UnRegister(this);
922     this->FBFluidEyeZ = nullptr;
923   }
924   if (this->FBThickness != nullptr)
925   {
926     this->FBThickness->ReleaseGraphicsResources(w);
927     this->FBThickness->UnRegister(this);
928     this->FBThickness = nullptr;
929   }
930   if (this->FBFilterThickness != nullptr)
931   {
932     this->FBFilterThickness->ReleaseGraphicsResources(w);
933     this->FBFilterThickness->UnRegister(this);
934     this->FBFilterThickness = nullptr;
935   }
936   if (this->FBCompNormal != nullptr)
937   {
938     this->FBCompNormal->ReleaseGraphicsResources(w);
939     this->FBCompNormal->UnRegister(this);
940     this->FBCompNormal = nullptr;
941   }
942   if (this->FBFilterDepth != nullptr)
943   {
944     this->FBFilterDepth->ReleaseGraphicsResources(w);
945     this->FBFilterDepth->UnRegister(this);
946     this->FBFilterDepth = nullptr;
947   }
948 
949   if (this->QuadThicknessFilter != nullptr)
950   {
951     delete this->QuadThicknessFilter;
952     this->QuadThicknessFilter = nullptr;
953   }
954   if (this->QuadFluidNormal != nullptr)
955   {
956     delete this->QuadFluidNormal;
957     this->QuadFluidNormal = nullptr;
958   }
959   if (this->QuadFinalBlend != nullptr)
960   {
961     delete this->QuadFinalBlend;
962     this->QuadFinalBlend = nullptr;
963   }
964   for (int i = 0; i < this->NumFilterMethods; ++i)
965   {
966     if (this->QuadFluidDepthFilter[i] != nullptr)
967     {
968       delete this->QuadFluidDepthFilter[i];
969       this->QuadFluidDepthFilter[i] = nullptr;
970     }
971   }
972 
973   this->VBOs->ReleaseGraphicsResources(w);
974 
975   for (int i = 0; i < NumTexBuffers; ++i)
976   {
977     this->TexBuffer[i]->ReleaseGraphicsResources(w);
978   }
979   for (int i = 0; i < NumOptionalTexBuffers; ++i)
980   {
981     this->OptionalTexBuffer[i]->ReleaseGraphicsResources(w);
982   }
983 
984   this->GLHelperDepthThickness.ReleaseGraphicsResources(w);
985 
986   this->Modified();
987 }
988