1 /*=========================================================================
2 
3 Program:   Visualization Toolkit
4 Module:    vtkDepthPeelingPass.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 "vtkDepthPeelingPass.h"
17 #include "vtkInformation.h"
18 #include "vtkInformationIntegerKey.h"
19 #include "vtkInformationIntegerVectorKey.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkOpenGLError.h"
22 #include "vtkOpenGLRenderWindow.h"
23 #include "vtkOpenGLRenderer.h"
24 #include "vtkOpenGLShaderCache.h"
25 #include "vtkProp.h"
26 #include "vtkRenderState.h"
27 #include "vtkRenderer.h"
28 #include "vtkShaderProgram.h"
29 #include "vtkTextureObject.h"
30 #include <cassert>
31 #include <list>
32 
33 #include "vtkglVBOHelper.h"
34 
35 // the 2D blending shaders we use
36 #include "vtkDepthPeelingPassIntermediateFS.h"
37 #include "vtkDepthPeelingPassFinalFS.h"
38 #include "vtkTextureObjectVS.h"
39 
40 vtkStandardNewMacro(vtkDepthPeelingPass);
41 vtkCxxSetObjectMacro(vtkDepthPeelingPass,TranslucentPass,vtkRenderPass);
42 
43 vtkInformationKeyMacro(vtkDepthPeelingPass,OpaqueZTextureUnit,Integer);
44 vtkInformationKeyMacro(vtkDepthPeelingPass,TranslucentZTextureUnit,Integer);
45 vtkInformationKeyMacro(vtkDepthPeelingPass,DestinationSize,IntegerVector);
46 
47 // ----------------------------------------------------------------------------
vtkDepthPeelingPass()48 vtkDepthPeelingPass::vtkDepthPeelingPass()
49 {
50   this->TranslucentPass=0;
51   this->IsSupported=false;
52 
53   this->OcclusionRatio=0.0;
54   this->MaximumNumberOfPeels=4;
55   this->LastRenderingUsedDepthPeeling=false;
56   this->DepthPeelingHigherLayer=0;
57 
58   this->IntermediateBlendProgram = 0;
59   this->FinalBlendProgram = 0;
60 
61   this->DepthZData = 0;
62   this->OpaqueZTexture = NULL;
63   this->TranslucentZTexture = NULL;
64   this->OpaqueRGBATexture = NULL;
65   this->TranslucentRGBATexture = NULL;
66   this->CurrentRGBATexture = NULL;
67 }
68 
69 // ----------------------------------------------------------------------------
~vtkDepthPeelingPass()70 vtkDepthPeelingPass::~vtkDepthPeelingPass()
71 {
72   if(this->TranslucentPass!=0)
73     {
74     this->TranslucentPass->Delete();
75     }
76   if (this->DepthZData)
77     {
78     delete this->DepthZData;
79     this->DepthZData = 0;
80     }
81   if (this->OpaqueZTexture)
82     {
83     this->OpaqueZTexture->UnRegister(this);
84     this->OpaqueZTexture = NULL;
85     }
86   if (this->TranslucentZTexture)
87     {
88     this->TranslucentZTexture->UnRegister(this);
89     this->TranslucentZTexture = NULL;
90     }
91   if (this->OpaqueRGBATexture)
92     {
93     this->OpaqueRGBATexture->UnRegister(this);
94     this->OpaqueRGBATexture = NULL;
95     }
96   if (this->TranslucentRGBATexture)
97     {
98     this->TranslucentRGBATexture->UnRegister(this);
99     this->TranslucentRGBATexture = NULL;
100     }
101   if (this->CurrentRGBATexture)
102     {
103     this->CurrentRGBATexture->UnRegister(this);
104     this->CurrentRGBATexture = NULL;
105     }
106 }
107 
108 //-----------------------------------------------------------------------------
109 // Description:
110 // Destructor. Delete SourceCode if any.
ReleaseGraphicsResources(vtkWindow * w)111 void vtkDepthPeelingPass::ReleaseGraphicsResources(vtkWindow *w)
112 {
113   assert("pre: w_exists" && w!=0);
114 
115   if (this->FinalBlendProgram !=0)
116     {
117     this->FinalBlendProgram->ReleaseGraphicsResources(w);
118     delete this->FinalBlendProgram;
119     this->FinalBlendProgram = 0;
120     }
121   if (this->IntermediateBlendProgram !=0)
122     {
123     this->IntermediateBlendProgram->ReleaseGraphicsResources(w);
124     delete this->IntermediateBlendProgram;
125     this->IntermediateBlendProgram = 0;
126     }
127   if(this->TranslucentPass)
128     {
129     this->TranslucentPass->ReleaseGraphicsResources(w);
130     }
131 
132   if(this->TranslucentPass)
133     {
134     this->TranslucentPass->ReleaseGraphicsResources(w);
135     }
136 }
137 
138 // ----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)139 void vtkDepthPeelingPass::PrintSelf(ostream& os, vtkIndent indent)
140 {
141   this->Superclass::PrintSelf(os,indent);
142 
143   os << indent << "OcclusionRation: " << this->OcclusionRatio << endl;
144 
145   os << indent << "MaximumNumberOfPeels: " << this->MaximumNumberOfPeels
146      << endl;
147 
148   os << indent << "LastRenderingUsedDepthPeeling: ";
149   if(this->LastRenderingUsedDepthPeeling)
150     {
151     os << "On" << endl;
152     }
153   else
154     {
155     os << "Off" << endl;
156     }
157 
158   os << indent << "TranslucentPass:";
159   if(this->TranslucentPass!=0)
160     {
161     this->TranslucentPass->PrintSelf(os,indent);
162     }
163   else
164     {
165     os << "(none)" <<endl;
166     }
167 }
168 
vtkDepthPeelingPassCreateTextureObject(vtkOpenGLRenderWindow * context,int width,int height,int numComponents,bool isDepth,void * initialData)169 vtkTextureObject *vtkDepthPeelingPassCreateTextureObject(
170   vtkOpenGLRenderWindow *context, int width, int height,
171   int numComponents, bool isDepth, void *initialData)
172 {
173   vtkTextureObject *result = vtkTextureObject::New();
174   result->SetContext(context);
175 
176   if (isDepth == true)
177     {
178     if (initialData)
179       {
180       result->CreateDepthFromRaw(
181           width, height, vtkTextureObject::Float32, VTK_FLOAT, initialData);
182       }
183     else
184       {
185       result->AllocateDepth(width, height, vtkTextureObject::Float32);
186       }
187     }
188   else
189     {
190     result->Allocate2D(width, height, numComponents, VTK_UNSIGNED_CHAR);
191     }
192 
193   result->SetMinificationFilter(vtkTextureObject::Nearest);
194   result->SetMagnificationFilter(vtkTextureObject::Nearest);
195   result->SetWrapS(vtkTextureObject::ClampToEdge);
196   result->SetWrapT(vtkTextureObject::ClampToEdge);
197   result->SetWrapR(vtkTextureObject::ClampToEdge);
198   return result;
199 }
200 
BlendIntermediatePeels(vtkOpenGLRenderWindow * renWin)201 void vtkDepthPeelingPass::BlendIntermediatePeels(vtkOpenGLRenderWindow *renWin)
202 {
203   this->CurrentRGBATexture->CopyFromFrameBuffer(this->ViewportX, this->ViewportY,
204     this->ViewportX, this->ViewportY,
205     this->ViewportWidth, this->ViewportHeight);
206 
207   // take the TranslucentRGBA texture and blend it with the current frame buffer
208   if (!this->IntermediateBlendProgram)
209     {
210     this->IntermediateBlendProgram = new vtkgl::CellBO;
211     std::string VSSource = vtkTextureObjectVS;
212     std::string FSSource = vtkDepthPeelingPassIntermediateFS;
213     std::string GSSource;
214     this->IntermediateBlendProgram->Program =
215         renWin->GetShaderCache()->ReadyShader(VSSource.c_str(),
216                                               FSSource.c_str(),
217                                               GSSource.c_str());
218     }
219   else
220     {
221     renWin->GetShaderCache()->ReadyShader(this->IntermediateBlendProgram->Program);
222     }
223   this->IntermediateBlendProgram->Program->SetUniformi(
224     "translucentRGBATexture", this->TranslucentRGBATexture->GetTextureUnit());
225   this->IntermediateBlendProgram->Program->SetUniformi(
226     "currentRGBATexture", this->CurrentRGBATexture->GetTextureUnit());
227 
228   glDisable(GL_DEPTH_TEST);
229   this->CurrentRGBATexture->CopyToFrameBuffer(0, 0,
230          this->ViewportWidth-1, this->ViewportHeight-1,
231          0, 0, this->ViewportWidth, this->ViewportHeight,
232          this->IntermediateBlendProgram->Program,
233          &this->IntermediateBlendProgram->vao);
234 }
235 
236 
BlendFinalPeel(vtkOpenGLRenderWindow * renWin)237 void vtkDepthPeelingPass::BlendFinalPeel(vtkOpenGLRenderWindow *renWin)
238 {
239   if (!this->FinalBlendProgram)
240     {
241     this->FinalBlendProgram = new vtkgl::CellBO;
242     std::string VSSource = vtkTextureObjectVS;
243     std::string FSSource = vtkDepthPeelingPassFinalFS;
244     std::string GSSource;
245     this->FinalBlendProgram->Program =
246         renWin->GetShaderCache()->ReadyShader(VSSource.c_str(),
247                                               FSSource.c_str(),
248                                               GSSource.c_str());
249     }
250   else
251     {
252     renWin->GetShaderCache()->ReadyShader(this->FinalBlendProgram->Program);
253     }
254 
255   this->FinalBlendProgram->Program->SetUniformi(
256     "translucentRGBATexture", this->TranslucentRGBATexture->GetTextureUnit());
257 
258   this->OpaqueRGBATexture->Activate();
259   this->FinalBlendProgram->Program->SetUniformi(
260     "opaqueRGBATexture", this->OpaqueRGBATexture->GetTextureUnit());
261 
262   // blend in OpaqueRGBA
263   glDisable(GL_DEPTH_TEST);
264   this->OpaqueRGBATexture->CopyToFrameBuffer(0, 0,
265          this->ViewportWidth-1, this->ViewportHeight-1,
266          0, 0, this->ViewportWidth, this->ViewportHeight,
267          this->FinalBlendProgram->Program,
268          &this->FinalBlendProgram->vao);
269 }
270 
271 
272 
273 // ----------------------------------------------------------------------------
274 // Description:
275 // Perform rendering according to a render state \p s.
276 // \pre s_exists: s!=0
Render(const vtkRenderState * s)277 void vtkDepthPeelingPass::Render(const vtkRenderState *s)
278 {
279   assert("pre: s_exists" && s!=0);
280 
281   this->NumberOfRenderedProps=0;
282 
283   if(this->TranslucentPass==0)
284     {
285     vtkWarningMacro(<<"No TranslucentPass delegate set. Nothing can be rendered.");
286     return;
287     }
288 
289   // Any prop to render?
290   bool hasTranslucentPolygonalGeometry=false;
291   int i=0;
292   while(!hasTranslucentPolygonalGeometry && i<s->GetPropArrayCount())
293     {
294     hasTranslucentPolygonalGeometry=
295       s->GetPropArray()[i]->HasTranslucentPolygonalGeometry()==1;
296     ++i;
297     }
298   if(!hasTranslucentPolygonalGeometry)
299     {
300     return; // nothing to render.
301     }
302 
303   // we need alpha planes
304   GLint alphaBits;
305   glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
306   if (alphaBits < 8)
307     {
308     // just use alpha blending
309     this->TranslucentPass->Render(s);
310     return;
311     }
312 
313   // check driver support
314   vtkOpenGLRenderWindow *renWin
315     = vtkOpenGLRenderWindow::SafeDownCast(s->GetRenderer()->GetRenderWindow());
316 
317   // Depth peeling.
318   vtkRenderer *r=s->GetRenderer();
319 
320   if(s->GetFrameBuffer()==0)
321     {
322     // get the viewport dimensions
323     r->GetTiledSizeAndOrigin(&this->ViewportWidth,&this->ViewportHeight,
324                              &this->ViewportX,&this->ViewportY);
325     }
326   else
327     {
328     int size[2];
329     s->GetWindowSize(size);
330     this->ViewportWidth=size[0];
331     this->ViewportHeight=size[1];
332     this->ViewportX=0;
333     this->ViewportY=0;
334     }
335 
336   // has the size changed?
337   if (this->OpaqueRGBATexture && (
338       this->OpaqueRGBATexture->GetWidth() != static_cast<unsigned int>(this->ViewportWidth) ||
339       this->OpaqueRGBATexture->GetHeight() != static_cast<unsigned int>(this->ViewportHeight)))
340     {
341     delete this->DepthZData;
342     this->DepthZData = 0;
343 
344     this->OpaqueZTexture->UnRegister(this);
345     this->OpaqueZTexture = 0;
346 
347     this->OpaqueRGBATexture->UnRegister(this);
348     this->OpaqueRGBATexture = 0;
349 
350     this->TranslucentRGBATexture->UnRegister(this);
351     this->TranslucentRGBATexture = 0;
352 
353     this->CurrentRGBATexture->UnRegister(this);
354     this->CurrentRGBATexture = 0;
355     }
356 
357   // create textures we need if not done already
358   if (this->OpaqueZTexture == NULL)
359     {
360     this->OpaqueZTexture = vtkDepthPeelingPassCreateTextureObject(
361       renWin, this->ViewportWidth, this->ViewportHeight, 1, true, NULL);
362     this->OpaqueRGBATexture = vtkDepthPeelingPassCreateTextureObject(
363       renWin, this->ViewportWidth, this->ViewportHeight, 4, false, NULL);
364     this->TranslucentRGBATexture = vtkDepthPeelingPassCreateTextureObject(
365       renWin, this->ViewportWidth, this->ViewportHeight, 4, false, NULL);
366     this->CurrentRGBATexture = vtkDepthPeelingPassCreateTextureObject(
367       renWin, this->ViewportWidth, this->ViewportHeight, 4, false, NULL);
368     this->DepthZData = new std::vector<float>(this->ViewportWidth * this->ViewportHeight, 0.0);
369     }
370 
371   this->TranslucentZTexture = vtkDepthPeelingPassCreateTextureObject(
372     renWin, this->ViewportWidth, this->ViewportHeight, 1, true, &((*this->DepthZData)[0]));
373 
374   // Have to be set before a call to UpdateTranslucentPolygonalGeometry()
375   // because UpdateTranslucentPolygonalGeometry() will eventually call
376   // vtkOpenGLActor::Render() that uses this flag.
377   this->LastRenderingUsedDepthPeeling = true;
378   this->SetLastRenderingUsedDepthPeeling(s->GetRenderer(), true);
379 
380   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
381 //  glClearColor(0.0,0.0,0.0,0.0); // always clear to black
382  // glClearDepth(static_cast<GLclampf>(1.0));
383 #ifdef GL_MULTISAMPLE
384   glDisable(GL_MULTISAMPLE);
385 #endif
386   glDisable(GL_BLEND);
387 
388   // Get opaqueRGBA and opaqueZ
389   this->OpaqueRGBATexture->CopyFromFrameBuffer(this->ViewportX, this->ViewportY,
390     this->ViewportX, this->ViewportY,
391     this->ViewportWidth, this->ViewportHeight);
392   this->OpaqueRGBATexture->Deactivate(); // deactivate & unbind to save texture resources
393   this->OpaqueZTexture->CopyFromFrameBuffer(this->ViewportX, this->ViewportY,
394     this->ViewportX, this->ViewportY,
395     this->ViewportWidth, this->ViewportHeight);
396 
397   this->TranslucentZTexture->Activate();
398   this->OpaqueZTexture->Activate();
399 
400   // set the required keys on the props for the txture units
401   int destSize[2];
402   destSize[0] = this->ViewportWidth;
403   destSize[1] = this->ViewportHeight;
404 
405   int c = s->GetPropArrayCount();
406   for (i = 0; i < c; i++)
407     {
408     vtkProp *p=s->GetPropArray()[i];
409     vtkInformation *info = p->GetPropertyKeys();
410     if (!info)
411       {
412       info = vtkInformation::New();
413       p->SetPropertyKeys(info);
414       info->Delete();
415       }
416     info->Set(vtkDepthPeelingPass::OpaqueZTextureUnit(),
417       this->OpaqueZTexture->GetTextureUnit());
418     info->Set(vtkDepthPeelingPass::TranslucentZTextureUnit(),
419       this->TranslucentZTexture->GetTextureUnit());
420     info->Set(vtkDepthPeelingPass::DestinationSize(),destSize,2);
421     }
422 
423   // Do render loop until complete
424   unsigned int threshold=
425     static_cast<unsigned int>(this->ViewportWidth*this->ViewportHeight*OcclusionRatio);
426 
427 #if GL_ES_VERSION_2_0 != 1
428   GLuint queryId;
429   glGenQueries(1,&queryId);
430 #endif
431 
432   bool done = false;
433   GLuint nbPixels = 0;
434   int peelCount = 0;
435   while(!done)
436     {
437     glDepthMask(GL_TRUE);
438     glEnable(GL_DEPTH_TEST);
439 
440     // clear the zbuffer and color buffers
441     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
442 
443     // render the translucent geometry
444 #if GL_ES_VERSION_2_0 != 1
445     glBeginQuery(GL_SAMPLES_PASSED,queryId);
446 #endif
447 
448     this->TranslucentPass->Render(s);
449 
450     // update translucentZ
451     this->TranslucentZTexture->CopyFromFrameBuffer(this->ViewportX, this->ViewportY,
452         this->ViewportX, this->ViewportY,
453         this->ViewportWidth, this->ViewportHeight);
454 
455 #if GL_ES_VERSION_2_0 != 1
456     glEndQuery(GL_SAMPLES_PASSED);
457     glGetQueryObjectuiv(queryId,GL_QUERY_RESULT,&nbPixels);
458     if (nbPixels <= threshold)
459       {
460       done = true;
461       }
462 #endif
463     peelCount++;
464     if(this->MaximumNumberOfPeels && peelCount >= this->MaximumNumberOfPeels)
465       {
466       done = true;
467       }
468     //cerr << "Pass " << peelCount << " pixels Drawn " << nbPixels << "\n";
469 
470     // blend the last two peels together
471     if (peelCount > 1)
472       {
473       this->BlendIntermediatePeels(renWin);
474       }
475 
476     // update translucent RGBA
477     this->TranslucentRGBATexture->CopyFromFrameBuffer(this->ViewportX, this->ViewportY,
478       this->ViewportX, this->ViewportY,
479       this->ViewportWidth, this->ViewportHeight);
480     }
481 
482   // unload the textures we are done with
483   this->CurrentRGBATexture->Deactivate();
484   this->OpaqueZTexture->Deactivate();
485   this->TranslucentZTexture->UnRegister(this);
486   this->TranslucentZTexture = 0;
487 
488   // do the final blend
489   this->BlendFinalPeel(renWin);
490 
491   // unload the last two textures
492   this->TranslucentRGBATexture->Deactivate();
493   this->OpaqueRGBATexture->Deactivate();
494 
495   // restore blending
496   glEnable(GL_BLEND);
497 
498   this->NumberOfRenderedProps = this->TranslucentPass->GetNumberOfRenderedProps();
499 
500   vtkOpenGLCheckErrorMacro("failed after Render");
501 }
502