1 /*=========================================================================
2 
3 Program:   Visualization Toolkit
4 Module:    vtkOrderIndependentTranslucentPass.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 "vtkOrderIndependentTranslucentPass.h"
17 #include "vtkOpenGLFramebufferObject.h"
18 #include "vtkInformation.h"
19 #include "vtkObjectFactory.h"
20 #include "vtkOpenGLActor.h"
21 #include "vtkOpenGLError.h"
22 #include "vtkOpenGLQuadHelper.h"
23 #include "vtkOpenGLRenderWindow.h"
24 #include "vtkOpenGLRenderer.h"
25 #include "vtkOpenGLShaderCache.h"
26 #include "vtkOpenGLState.h"
27 #include "vtkProp.h"
28 #include "vtkRenderState.h"
29 #include "vtkRenderer.h"
30 #include "vtkShaderProgram.h"
31 #include "vtkTextureObject.h"
32 #include <cassert>
33 #include <list>
34 
35 #include "vtkRenderStepsPass.h"
36 
37 #include "vtkOpenGLHelper.h"
38 
39 // the 2D blending shaders we use
40 #include "vtkOrderIndependentTranslucentPassFinalFS.h"
41 
42 vtkStandardNewMacro(vtkOrderIndependentTranslucentPass);
43 vtkCxxSetObjectMacro(vtkOrderIndependentTranslucentPass,TranslucentPass,vtkRenderPass);
44 
45 // ----------------------------------------------------------------------------
vtkOrderIndependentTranslucentPass()46 vtkOrderIndependentTranslucentPass::vtkOrderIndependentTranslucentPass() :
47   Framebuffer(nullptr), State(nullptr)
48 {
49   this->TranslucentPass=nullptr;
50 
51   this->FinalBlend = nullptr;
52 
53   this->TranslucentZTexture = vtkTextureObject::New();
54 
55   this->TranslucentRGBATexture = vtkTextureObject::New();
56   this->TranslucentRTexture = vtkTextureObject::New();
57 
58   this->ViewportX = 0;
59   this->ViewportY = 0;
60   this->ViewportWidth = 100;
61   this->ViewportHeight = 100;
62 }
63 
64 // ----------------------------------------------------------------------------
~vtkOrderIndependentTranslucentPass()65 vtkOrderIndependentTranslucentPass::~vtkOrderIndependentTranslucentPass()
66 {
67   if(this->TranslucentPass!=nullptr)
68   {
69     this->TranslucentPass->Delete();
70   }
71   if (this->TranslucentZTexture)
72   {
73     this->TranslucentZTexture->UnRegister(this);
74     this->TranslucentZTexture = nullptr;
75   }
76   if (this->TranslucentRGBATexture)
77   {
78     this->TranslucentRGBATexture->UnRegister(this);
79     this->TranslucentRGBATexture = nullptr;
80   }
81   if (this->TranslucentRTexture)
82   {
83     this->TranslucentRTexture->UnRegister(this);
84     this->TranslucentRTexture = nullptr;
85   }
86   if (this->Framebuffer)
87   {
88     this->Framebuffer->UnRegister(this);
89     this->Framebuffer = nullptr;
90   }
91 }
92 
93 //-----------------------------------------------------------------------------
94 // Description:
95 // Destructor. Delete SourceCode if any.
ReleaseGraphicsResources(vtkWindow * w)96 void vtkOrderIndependentTranslucentPass::ReleaseGraphicsResources(vtkWindow *w)
97 {
98   assert("pre: w_exists" && w!=nullptr);
99 
100   if (this->FinalBlend !=nullptr)
101   {
102     delete this->FinalBlend;
103     this->FinalBlend = nullptr;
104   }
105   if(this->TranslucentPass)
106   {
107     this->TranslucentPass->ReleaseGraphicsResources(w);
108   }
109   if (this->TranslucentZTexture)
110   {
111     this->TranslucentZTexture->ReleaseGraphicsResources(w);
112   }
113   if (this->TranslucentRGBATexture)
114   {
115     this->TranslucentRGBATexture->ReleaseGraphicsResources(w);
116   }
117   if (this->TranslucentRTexture)
118   {
119     this->TranslucentRTexture->ReleaseGraphicsResources(w);
120   }
121   if (this->Framebuffer)
122   {
123     this->Framebuffer->ReleaseGraphicsResources(w);
124     this->Framebuffer->UnRegister(this);
125     this->Framebuffer = nullptr;
126   }
127 
128 }
129 
130 // ----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)131 void vtkOrderIndependentTranslucentPass::PrintSelf(ostream& os, vtkIndent indent)
132 {
133   this->Superclass::PrintSelf(os,indent);
134 
135   os << indent << "TranslucentPass:";
136   if(this->TranslucentPass!=nullptr)
137   {
138     this->TranslucentPass->PrintSelf(os,indent);
139   }
140   else
141   {
142     os << "(none)" <<endl;
143   }
144 }
145 
BlendFinalPeel(vtkOpenGLRenderWindow * renWin)146 void vtkOrderIndependentTranslucentPass::BlendFinalPeel(vtkOpenGLRenderWindow *renWin)
147 {
148   if (!this->FinalBlend)
149   {
150     this->FinalBlend = new vtkOpenGLQuadHelper(renWin,
151       nullptr,
152       vtkOrderIndependentTranslucentPassFinalFS,
153       "");
154   }
155   else
156   {
157     renWin->GetShaderCache()->ReadyShaderProgram(
158       this->FinalBlend->Program);
159   }
160 
161   if (this->FinalBlend->Program)
162   {
163     this->TranslucentRGBATexture->Activate();
164     this->TranslucentRTexture->Activate();
165 
166     this->FinalBlend->Program->SetUniformi(
167       "translucentRGBATexture",
168       this->TranslucentRGBATexture->GetTextureUnit());
169     this->FinalBlend->Program->SetUniformi(
170       "translucentRTexture",
171       this->TranslucentRTexture->GetTextureUnit());
172 
173     this->FinalBlend->Render();
174   }
175 }
176 
177 
178 // ----------------------------------------------------------------------------
179 // Description:
180 // Perform rendering according to a render state \p s.
181 // \pre s_exists: s!=0
Render(const vtkRenderState * s)182 void vtkOrderIndependentTranslucentPass::Render(const vtkRenderState *s)
183 {
184   assert("pre: s_exists" && s!=nullptr);
185 
186   this->NumberOfRenderedProps=0;
187 
188   if(this->TranslucentPass==nullptr)
189   {
190     vtkWarningMacro(<<"No TranslucentPass delegate set. Nothing can be rendered.");
191     return;
192   }
193 
194   // Any prop to render?
195   bool hasTranslucentPolygonalGeometry=false;
196   int i=0;
197   while(!hasTranslucentPolygonalGeometry && i<s->GetPropArrayCount())
198   {
199     hasTranslucentPolygonalGeometry=
200       s->GetPropArray()[i]->HasTranslucentPolygonalGeometry()==1;
201     ++i;
202   }
203   if(!hasTranslucentPolygonalGeometry)
204   {
205     return; // nothing to render.
206   }
207 
208   vtkOpenGLRenderWindow *renWin
209     = vtkOpenGLRenderWindow::SafeDownCast(s->GetRenderer()->GetRenderWindow());
210   this->State = renWin->GetState();
211 
212   vtkRenderer *r=s->GetRenderer();
213   if(s->GetFrameBuffer()==nullptr)
214   {
215     // get the viewport dimensions
216     r->GetTiledSizeAndOrigin(&this->ViewportWidth,&this->ViewportHeight,
217                              &this->ViewportX,&this->ViewportY);
218   }
219   else
220   {
221     int size[2];
222     s->GetWindowSize(size);
223     this->ViewportWidth=size[0];
224     this->ViewportHeight=size[1];
225     this->ViewportX=0;
226     this->ViewportY=0;
227   }
228 
229   // create textures we need if not done already
230   if (this->TranslucentRGBATexture->GetHandle() == 0)
231   {
232     this->TranslucentRGBATexture->SetInternalFormat(GL_RGBA16F);
233     this->TranslucentRGBATexture->SetFormat(GL_RGBA);
234     this->TranslucentRGBATexture->SetDataType(GL_HALF_FLOAT);
235     this->TranslucentRGBATexture->SetContext(renWin);
236     this->TranslucentRGBATexture->Allocate2D(
237       this->ViewportWidth, this->ViewportHeight, 4, VTK_FLOAT);
238 
239     this->TranslucentRTexture->SetInternalFormat(GL_R16F);
240     this->TranslucentRTexture->SetFormat(GL_RED);
241     this->TranslucentRTexture->SetDataType(GL_HALF_FLOAT);
242     this->TranslucentRTexture->SetContext(renWin);
243     this->TranslucentRTexture->Allocate2D(
244       this->ViewportWidth, this->ViewportHeight, 1, VTK_FLOAT);
245 
246     // what depth format should we use?
247     this->TranslucentZTexture->SetContext(renWin);
248     int dbits =renWin->GetDepthBufferSize();
249     if (dbits == 32)
250     {
251       this->TranslucentZTexture->AllocateDepth(
252         this->ViewportWidth, this->ViewportHeight, vtkTextureObject::Float32);
253     }
254     else
255     {
256       this->TranslucentZTexture->AllocateDepth(
257         this->ViewportWidth, this->ViewportHeight, vtkTextureObject::Fixed24);
258     }
259     this->TranslucentZTexture->SetWrapS(vtkTextureObject::ClampToEdge);
260     this->TranslucentZTexture->SetWrapT(vtkTextureObject::ClampToEdge);
261   }
262   else
263   {
264     // make sure texture sizes are up to date
265     this->TranslucentRGBATexture->Resize(
266       this->ViewportWidth, this->ViewportHeight);
267     this->TranslucentRTexture->Resize(
268       this->ViewportWidth, this->ViewportHeight);
269     this->TranslucentZTexture->Resize(
270       this->ViewportWidth, this->ViewportHeight);
271   }
272 
273   // create framebuffer if not done already
274   if (!this->Framebuffer)
275   {
276     this->Framebuffer = vtkOpenGLFramebufferObject::New();
277     this->Framebuffer->SetContext(renWin);
278     this->Framebuffer->SaveCurrentBindingsAndBuffers();
279     this->Framebuffer->Bind();
280     this->Framebuffer->AddDepthAttachment(
281       this->Framebuffer->GetBothMode(), this->TranslucentZTexture);
282     this->Framebuffer->AddColorAttachment(
283       this->Framebuffer->GetBothMode(), 0,
284       this->TranslucentRGBATexture);
285     this->Framebuffer->AddColorAttachment(
286       this->Framebuffer->GetDrawMode(), 1,
287       this->TranslucentRTexture);
288     this->Framebuffer->RestorePreviousBindingsAndBuffers();
289   }
290 
291   this->State->vtkglViewport(0, 0,
292              this->ViewportWidth, this->ViewportHeight);
293   bool saveScissorTestState = this->State->GetEnumState(GL_SCISSOR_TEST);
294   this->State->vtkglDisable(GL_SCISSOR_TEST);
295 
296   // bind the draw mode but leave read as the previous FO
297   this->Framebuffer->SaveCurrentBindingsAndBuffers();
298   this->Framebuffer->Bind(this->Framebuffer->GetDrawMode());
299   this->Framebuffer->ActivateDrawBuffers(2);
300 
301 #ifdef GL_MULTISAMPLE
302   bool multiSampleStatus = this->State->GetEnumState(GL_MULTISAMPLE);
303   this->State->vtkglDisable(GL_MULTISAMPLE);
304 #endif
305 
306   this->State->vtkglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
307   this->State->vtkglClearColor(0.0,0.0,0.0,1.0);
308   this->State->vtkglDepthMask(GL_TRUE);
309   this->State->vtkglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
310 
311 #if defined(__APPLE__)
312   this->State->vtkglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
313   // apple fails if not the upper left corenr of the window
314   // blit on apple is fubar, so rerender opaque
315   // to get a good depth buffer
316   r->DeviceRenderOpaqueGeometry();
317   this->State->vtkglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
318 #else
319   // blit read buffer depth to FO depth texture
320   glBlitFramebuffer(
321     this->ViewportX, this->ViewportY,
322     this->ViewportX + this->ViewportWidth,
323     this->ViewportY + this->ViewportHeight,
324     0, 0, this->ViewportWidth, this->ViewportHeight,
325     GL_DEPTH_BUFFER_BIT,
326     GL_NEAREST);
327 #endif
328 
329 
330   // now bind both read and draw
331   this->Framebuffer->Bind();
332 
333   // Setup property keys for actors:
334   this->PreRender(s);
335 
336   // Enable the depth buffer (otherwise it's disabled for translucent geometry)
337   assert("Render state valid." && s);
338 
339   this->State->vtkglEnable(GL_DEPTH_TEST);
340   this->State->vtkglEnable(GL_BLEND);
341 
342   // basic gist is we accumulate color into RGB
343   // We compute final opacity into A
344   // We store accumulated opacity into R of the
345   // R texture.
346   this->State->vtkglBlendFuncSeparate(
347     GL_ONE,
348     GL_ONE,
349     GL_ZERO,
350     GL_ONE_MINUS_SRC_ALPHA
351     );
352 
353   // render the translucent data into the FO
354   this->TranslucentPass->Render(s);
355 
356   // back to the original FO
357   this->Framebuffer->RestorePreviousBindingsAndBuffers();
358 
359   this->State->vtkglBlendFuncSeparate(
360     GL_ONE_MINUS_SRC_ALPHA,
361     GL_SRC_ALPHA,
362     GL_ONE_MINUS_SRC_ALPHA,
363     GL_SRC_ALPHA
364     );
365 
366   // Restore the original viewport and scissor test settings
367   this->State->vtkglViewport(this->ViewportX, this->ViewportY,
368              this->ViewportWidth, this->ViewportHeight);
369   if (saveScissorTestState)
370   {
371     this->State->vtkglEnable(GL_SCISSOR_TEST);
372   }
373   else
374   {
375     this->State->vtkglDisable(GL_SCISSOR_TEST);
376   }
377 
378   // do not write zvalues on final blend
379   this->State->vtkglDepthMask(GL_FALSE);
380   this->State->vtkglDepthFunc( GL_ALWAYS );
381   this->BlendFinalPeel(renWin);
382 
383   // unload the textures
384   this->TranslucentRGBATexture->Deactivate();
385   this->TranslucentRTexture->Deactivate();
386   this->TranslucentZTexture->Deactivate();
387 
388   this->State->vtkglDepthFunc( GL_LEQUAL );
389 
390 #ifdef GL_MULTISAMPLE
391    if(multiSampleStatus)
392    {
393       this->State->vtkglEnable(GL_MULTISAMPLE);
394    }
395 #endif
396 
397   // Restore blending parameters:
398   this->State->vtkglBlendFuncSeparate(
399     GL_SRC_ALPHA,
400     GL_ONE_MINUS_SRC_ALPHA,
401     GL_ONE,
402     GL_ONE_MINUS_SRC_ALPHA
403     );
404 
405   this->PostRender(s);
406 
407   this->NumberOfRenderedProps = this->TranslucentPass->GetNumberOfRenderedProps();
408 
409   vtkOpenGLCheckErrorMacro("failed after Render");
410 }
411 
412 //------------------------------------------------------------------------------
PostReplaceShaderValues(std::string &,std::string &,std::string & fragmentShader,vtkAbstractMapper *,vtkProp *)413 bool vtkOrderIndependentTranslucentPass::PostReplaceShaderValues(std::string &,
414                                               std::string &,
415                                               std::string &fragmentShader,
416                                               vtkAbstractMapper *,
417                                               vtkProp *)
418 {
419   vtkShaderProgram::Substitute(
420         fragmentShader, "//VTK::DepthPeeling::Impl",
421         "  gl_FragData[0] = vec4(gl_FragData[0].rgb*gl_FragData[0].a, gl_FragData[0].a);\n"
422         "  gl_FragData[1].r = gl_FragData[0].a;\n"
423         );
424 
425   return true;
426 }
427