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