1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkSimpleMotionBlurPass.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 "vtkSimpleMotionBlurPass.h"
17 #include "vtkObjectFactory.h"
18 #include <cassert>
19
20 #include "vtkRenderState.h"
21 #include "vtkRenderer.h"
22 #include "vtkOpenGLFramebufferObject.h"
23 #include "vtkTextureObject.h"
24 #include "vtkOpenGLRenderWindow.h"
25 #include "vtkOpenGLState.h"
26 #include "vtkOpenGLError.h"
27 #include "vtkShaderProgram.h"
28 #include "vtkOpenGLShaderCache.h"
29 #include "vtkOpenGLVertexArrayObject.h"
30
31 #include "vtkOpenGLHelper.h"
32
33 #include "vtkTextureObjectVS.h"
34 #include "vtkSimpleMotionBlurPassFS.h"
35
36 vtkStandardNewMacro(vtkSimpleMotionBlurPass);
37
38 // ----------------------------------------------------------------------------
vtkSimpleMotionBlurPass()39 vtkSimpleMotionBlurPass::vtkSimpleMotionBlurPass()
40 {
41 this->SubFrames = 30;
42 this->CurrentSubFrame = 0;
43 this->BlendProgram = nullptr;
44
45 this->FrameBufferObject=nullptr;
46 this->AccumulationTexture[0] = vtkTextureObject::New();
47 this->AccumulationTexture[1] = vtkTextureObject::New();
48 this->ActiveAccumulationTexture = 0;
49 this->ColorTexture = vtkTextureObject::New();
50 this->DepthTexture = vtkTextureObject::New();
51 this->DepthFormat = vtkTextureObject::Float32;
52 this->ColorFormat = vtkTextureObject::Fixed8;
53 }
54
55 // ----------------------------------------------------------------------------
~vtkSimpleMotionBlurPass()56 vtkSimpleMotionBlurPass::~vtkSimpleMotionBlurPass()
57 {
58 if(this->FrameBufferObject!=nullptr)
59 {
60 vtkErrorMacro(<<"FrameBufferObject should have been deleted in ReleaseGraphicsResources().");
61 }
62 if(this->AccumulationTexture[0] != nullptr)
63 {
64 this->AccumulationTexture[0]->Delete();
65 this->AccumulationTexture[0] = nullptr;
66 }
67 if(this->AccumulationTexture[1] != nullptr)
68 {
69 this->AccumulationTexture[1]->Delete();
70 this->AccumulationTexture[1] = nullptr;
71 }
72 if(this->ColorTexture!=nullptr)
73 {
74 this->ColorTexture->Delete();
75 this->ColorTexture = nullptr;
76 }
77 if(this->DepthTexture !=nullptr)
78 {
79 this->DepthTexture->Delete();
80 this->DepthTexture = nullptr;
81 }
82 }
83
84 //----------------------------------------------------------------------------
SetSubFrames(int subFrames)85 void vtkSimpleMotionBlurPass::SetSubFrames(int subFrames)
86 {
87 if (this->SubFrames != subFrames)
88 {
89 this->SubFrames = subFrames;
90 if (this->CurrentSubFrame >= this->SubFrames)
91 {
92 this->CurrentSubFrame = 0;
93 }
94 vtkDebugMacro(<< this->GetClassName() << " (" << this
95 << "): setting SubFrames to " << subFrames);
96 this->Modified();
97 }
98 }
99
100 // ----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)101 void vtkSimpleMotionBlurPass::PrintSelf(ostream& os, vtkIndent indent)
102 {
103 os << indent << "SubFrames: " << this->SubFrames << "\n";
104 this->Superclass::PrintSelf(os,indent);
105 }
106
107 // ----------------------------------------------------------------------------
108 // Description:
109 // Perform rendering according to a render state \p s.
110 // \pre s_exists: s!=0
Render(const vtkRenderState * s)111 void vtkSimpleMotionBlurPass::Render(const vtkRenderState *s)
112 {
113 assert("pre: s_exists" && s!=nullptr);
114
115 vtkOpenGLClearErrorMacro();
116
117 this->NumberOfRenderedProps=0;
118
119 vtkRenderer *r=s->GetRenderer();
120 vtkOpenGLRenderWindow *renWin = static_cast<vtkOpenGLRenderWindow *>(r->GetRenderWindow());
121 vtkOpenGLState *ostate = renWin->GetState();
122
123 if(this->DelegatePass == nullptr)
124 {
125 vtkWarningMacro(<<" no delegate.");
126 return;
127 }
128
129 // 1. Create a new render state with an FO.
130 if(s->GetFrameBuffer()==nullptr)
131 {
132 // get the viewport dimensions
133 r->GetTiledSizeAndOrigin(&this->ViewportWidth,&this->ViewportHeight,
134 &this->ViewportX,&this->ViewportY);
135 }
136 else
137 {
138 int size[2];
139 s->GetWindowSize(size);
140 this->ViewportWidth=size[0];
141 this->ViewportHeight=size[1];
142 this->ViewportX=0;
143 this->ViewportY=0;
144 }
145
146 this->ColorTexture->SetContext(renWin);
147 if (!this->ColorTexture->GetHandle())
148 {
149 if (this->ColorFormat == vtkTextureObject::Float16)
150 {
151 this->ColorTexture->SetInternalFormat(GL_RGBA16F);
152 this->ColorTexture->SetDataType(GL_FLOAT);
153 }
154 if (this->ColorFormat == vtkTextureObject::Float32)
155 {
156 this->ColorTexture->SetInternalFormat(GL_RGBA32F);
157 this->ColorTexture->SetDataType(GL_FLOAT);
158 }
159 this->ColorTexture->Allocate2D(
160 this->ViewportWidth, this->ViewportHeight, 4,
161 VTK_UNSIGNED_CHAR);
162 }
163 this->ColorTexture->Resize(this->ViewportWidth, this->ViewportHeight);
164
165 for (int i = 0; i < 2; i++)
166 {
167 this->AccumulationTexture[i]->SetContext(renWin);
168 if (!this->AccumulationTexture[i]->GetHandle())
169 {
170 this->AccumulationTexture[i]->SetInternalFormat(GL_RGBA16F);
171 this->AccumulationTexture[i]->SetDataType(GL_FLOAT);
172 this->AccumulationTexture[i]->Allocate2D(
173 this->ViewportWidth, this->ViewportHeight, 4,
174 VTK_UNSIGNED_CHAR);
175 }
176 this->AccumulationTexture[i]->Resize(this->ViewportWidth, this->ViewportHeight);
177 }
178 // Depth texture
179 this->DepthTexture->SetContext(renWin);
180 if (!this->DepthTexture->GetHandle())
181 {
182 this->DepthTexture->AllocateDepth(
183 this->ViewportWidth, this->ViewportHeight, this->DepthFormat);
184 }
185 this->DepthTexture->Resize(this->ViewportWidth, this->ViewportHeight);
186
187 if(this->FrameBufferObject==nullptr)
188 {
189 this->FrameBufferObject=vtkOpenGLFramebufferObject::New();
190 this->FrameBufferObject->SetContext(renWin);
191 }
192
193 this->FrameBufferObject->SaveCurrentBindingsAndBuffers();
194 this->RenderDelegate(s,
195 this->ViewportWidth, this->ViewportHeight,
196 this->ViewportWidth, this->ViewportHeight,
197 this->FrameBufferObject,
198 this->ColorTexture, this->DepthTexture);
199
200 // has something changed that would require us to recreate the shader?
201 if (!this->BlendProgram)
202 {
203 this->BlendProgram = new vtkOpenGLHelper;
204 // build the shader source code
205 std::string VSSource = vtkTextureObjectVS;
206 std::string FSSource = vtkSimpleMotionBlurPassFS;
207 std::string GSSource;
208
209 // compile and bind it if needed
210 vtkShaderProgram *newShader =
211 renWin->GetShaderCache()->ReadyShaderProgram(
212 VSSource.c_str(),
213 FSSource.c_str(),
214 GSSource.c_str());
215
216 // if the shader changed reinitialize the VAO
217 if (newShader != this->BlendProgram->Program)
218 {
219 this->BlendProgram->Program = newShader;
220 this->BlendProgram->VAO->ShaderProgramChanged(); // reset the VAO as the shader has changed
221 }
222
223 this->BlendProgram->ShaderSourceTime.Modified();
224 }
225 else
226 {
227 renWin->GetShaderCache()->ReadyShaderProgram(this->BlendProgram->Program);
228 }
229
230 this->FrameBufferObject->AddColorAttachment(
231 this->FrameBufferObject->GetBothMode(), 0,
232 this->AccumulationTexture[this->ActiveAccumulationTexture]);
233
234 ostate->vtkglViewport(0, 0,
235 this->ViewportWidth, this->ViewportHeight);
236 ostate->vtkglScissor(0, 0,
237 this->ViewportWidth, this->ViewportHeight);
238
239 // clear the accumulator on 0
240 if (this->CurrentSubFrame == 0)
241 {
242 ostate->vtkglClearColor(0.0,0.0,0.0,0.0);
243 ostate->vtkglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
244 ostate->vtkglClear(GL_COLOR_BUFFER_BIT);
245 }
246
247 this->ColorTexture->Activate();
248 int sourceId = this->ColorTexture->GetTextureUnit();
249 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
250 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
251 this->BlendProgram->Program->SetUniformi("source",sourceId);
252 this->BlendProgram->Program->SetUniformf("blendScale",1.0/this->SubFrames);
253 ostate->vtkglDisable(GL_DEPTH_TEST);
254
255 // save off current state of src / dst blend functions
256 // local scope for bfsaver
257 {
258 vtkOpenGLState::ScopedglBlendFuncSeparate bfsaver(ostate);
259 ostate->vtkglBlendFunc( GL_ONE, GL_ONE);
260 this->FrameBufferObject->RenderQuad(
261 0, this->ViewportWidth - 1,
262 0, this->ViewportHeight - 1,
263 this->BlendProgram->Program, this->BlendProgram->VAO);
264 this->ColorTexture->Deactivate();
265 // restore blend func on scope exit
266 }
267
268 // blit either the last or the current FO
269 this->CurrentSubFrame++;
270 if (this->CurrentSubFrame < this->SubFrames)
271 {
272 this->FrameBufferObject->AddColorAttachment(
273 this->FrameBufferObject->GetBothMode(), 0,
274 this->AccumulationTexture[
275 this->ActiveAccumulationTexture == 0 ? 1 : 0]);
276 }
277 else
278 {
279 this->CurrentSubFrame = 0;
280 this->ActiveAccumulationTexture =
281 (this->ActiveAccumulationTexture == 0 ? 1 : 0);
282 }
283
284 this->FrameBufferObject->RestorePreviousBindingsAndBuffers();
285
286 // now copy the result to the outer FO
287 this->FrameBufferObject->SaveCurrentBindingsAndBuffers(
288 this->FrameBufferObject->GetReadMode());
289 this->FrameBufferObject->Bind(
290 this->FrameBufferObject->GetReadMode());
291
292 ostate->vtkglViewport(this->ViewportX, this->ViewportY,
293 this->ViewportWidth, this->ViewportHeight);
294 ostate->vtkglScissor(this->ViewportX, this->ViewportY,
295 this->ViewportWidth, this->ViewportHeight);
296
297 glBlitFramebuffer(
298 0, 0, this->ViewportWidth, this->ViewportHeight,
299 this->ViewportX, this->ViewportY,
300 this->ViewportX + this->ViewportWidth,
301 this->ViewportY + this->ViewportHeight,
302 GL_COLOR_BUFFER_BIT,
303 GL_LINEAR);
304
305 this->FrameBufferObject->RestorePreviousBindingsAndBuffers(
306 this->FrameBufferObject->GetReadMode());
307
308 vtkOpenGLCheckErrorMacro("failed after Render");
309 }
310
311 // ----------------------------------------------------------------------------
312 // Description:
313 // Release graphics resources and ask components to release their own
314 // resources.
315 // \pre w_exists: w!=0
ReleaseGraphicsResources(vtkWindow * w)316 void vtkSimpleMotionBlurPass::ReleaseGraphicsResources(vtkWindow *w)
317 {
318 assert("pre: w_exists" && w!=nullptr);
319
320 this->Superclass::ReleaseGraphicsResources(w);
321
322 if(this->FrameBufferObject!=nullptr)
323 {
324 this->FrameBufferObject->Delete();
325 this->FrameBufferObject=nullptr;
326 }
327 if(this->ColorTexture!=nullptr)
328 {
329 this->ColorTexture->ReleaseGraphicsResources(w);
330 }
331 if(this->DepthTexture!=nullptr)
332 {
333 this->DepthTexture->ReleaseGraphicsResources(w);
334 }
335 if(this->AccumulationTexture[0] !=nullptr)
336 {
337 this->AccumulationTexture[0]->ReleaseGraphicsResources(w);
338 }
339 if(this->AccumulationTexture[1] !=nullptr)
340 {
341 this->AccumulationTexture[1]->ReleaseGraphicsResources(w);
342 }
343 if (this->BlendProgram !=nullptr)
344 {
345 this->BlendProgram->ReleaseGraphicsResources(w);
346 delete this->BlendProgram;
347 this->BlendProgram = nullptr;
348 }
349 }
350