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