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