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 "vtkOpenGLError.h"
21 #include "vtkOpenGLFramebufferObject.h"
22 #include "vtkOpenGLRenderWindow.h"
23 #include "vtkOpenGLShaderCache.h"
24 #include "vtkOpenGLState.h"
25 #include "vtkOpenGLVertexArrayObject.h"
26 #include "vtkRenderState.h"
27 #include "vtkRenderer.h"
28 #include "vtkShaderProgram.h"
29 #include "vtkTextureObject.h"
30
31 #include "vtkOpenGLHelper.h"
32
33 #include "vtkSimpleMotionBlurPassFS.h"
34 #include "vtkTextureObjectVS.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 << "): setting SubFrames to "
95 << 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(
134 &this->ViewportWidth, &this->ViewportHeight, &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(this->ViewportWidth, this->ViewportHeight, 4, VTK_UNSIGNED_CHAR);
160 }
161 this->ColorTexture->Resize(this->ViewportWidth, this->ViewportHeight);
162
163 for (int i = 0; i < 2; i++)
164 {
165 this->AccumulationTexture[i]->SetContext(renWin);
166 if (!this->AccumulationTexture[i]->GetHandle())
167 {
168 this->AccumulationTexture[i]->SetInternalFormat(GL_RGBA16F);
169 this->AccumulationTexture[i]->SetDataType(GL_FLOAT);
170 this->AccumulationTexture[i]->Allocate2D(
171 this->ViewportWidth, this->ViewportHeight, 4, VTK_UNSIGNED_CHAR);
172 }
173 this->AccumulationTexture[i]->Resize(this->ViewportWidth, this->ViewportHeight);
174 }
175 // Depth texture
176 this->DepthTexture->SetContext(renWin);
177 if (!this->DepthTexture->GetHandle())
178 {
179 this->DepthTexture->AllocateDepth(this->ViewportWidth, this->ViewportHeight, this->DepthFormat);
180 }
181 this->DepthTexture->Resize(this->ViewportWidth, this->ViewportHeight);
182
183 if (this->FrameBufferObject == nullptr)
184 {
185 this->FrameBufferObject = vtkOpenGLFramebufferObject::New();
186 this->FrameBufferObject->SetContext(renWin);
187 }
188
189 renWin->GetState()->PushFramebufferBindings();
190 this->RenderDelegate(s, this->ViewportWidth, this->ViewportHeight, this->ViewportWidth,
191 this->ViewportHeight, this->FrameBufferObject, this->ColorTexture, this->DepthTexture);
192
193 // has something changed that would require us to recreate the shader?
194 if (!this->BlendProgram)
195 {
196 this->BlendProgram = new vtkOpenGLHelper;
197 // build the shader source code
198 std::string VSSource = vtkTextureObjectVS;
199 std::string FSSource = vtkSimpleMotionBlurPassFS;
200 std::string GSSource;
201
202 // compile and bind it if needed
203 vtkShaderProgram* newShader = renWin->GetShaderCache()->ReadyShaderProgram(
204 VSSource.c_str(), FSSource.c_str(), GSSource.c_str());
205
206 // if the shader changed reinitialize the VAO
207 if (newShader != this->BlendProgram->Program)
208 {
209 this->BlendProgram->Program = newShader;
210 this->BlendProgram->VAO->ShaderProgramChanged(); // reset the VAO as the shader has changed
211 }
212
213 this->BlendProgram->ShaderSourceTime.Modified();
214 }
215 else
216 {
217 renWin->GetShaderCache()->ReadyShaderProgram(this->BlendProgram->Program);
218 }
219
220 this->FrameBufferObject->AddColorAttachment(
221 0, this->AccumulationTexture[this->ActiveAccumulationTexture]);
222
223 ostate->vtkglViewport(0, 0, this->ViewportWidth, this->ViewportHeight);
224 ostate->vtkglScissor(0, 0, this->ViewportWidth, this->ViewportHeight);
225
226 // clear the accumulator on 0
227 if (this->CurrentSubFrame == 0)
228 {
229 ostate->vtkglClearColor(0.0, 0.0, 0.0, 0.0);
230 ostate->vtkglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
231 ostate->vtkglClear(GL_COLOR_BUFFER_BIT);
232 }
233
234 this->ColorTexture->Activate();
235 int sourceId = this->ColorTexture->GetTextureUnit();
236 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
238 this->BlendProgram->Program->SetUniformi("source", sourceId);
239 this->BlendProgram->Program->SetUniformf("blendScale", 1.0 / this->SubFrames);
240 ostate->vtkglDisable(GL_DEPTH_TEST);
241
242 // save off current state of src / dst blend functions
243 // local scope for bfsaver
244 {
245 vtkOpenGLState::ScopedglBlendFuncSeparate bfsaver(ostate);
246 ostate->vtkglBlendFunc(GL_ONE, GL_ONE);
247 this->FrameBufferObject->RenderQuad(0, this->ViewportWidth - 1, 0, this->ViewportHeight - 1,
248 this->BlendProgram->Program, this->BlendProgram->VAO);
249 this->ColorTexture->Deactivate();
250 // restore blend func on scope exit
251 }
252
253 // blit either the last or the current FO
254 this->CurrentSubFrame++;
255 if (this->CurrentSubFrame < this->SubFrames)
256 {
257 this->FrameBufferObject->AddColorAttachment(
258 0, this->AccumulationTexture[this->ActiveAccumulationTexture == 0 ? 1 : 0]);
259 }
260 else
261 {
262 this->CurrentSubFrame = 0;
263 this->ActiveAccumulationTexture = (this->ActiveAccumulationTexture == 0 ? 1 : 0);
264 }
265
266 renWin->GetState()->PopFramebufferBindings();
267
268 // now copy the result to the outer FO
269 renWin->GetState()->PushReadFramebufferBinding();
270 this->FrameBufferObject->Bind(vtkOpenGLFramebufferObject::GetReadMode());
271
272 ostate->vtkglViewport(
273 this->ViewportX, this->ViewportY, this->ViewportWidth, this->ViewportHeight);
274 ostate->vtkglScissor(this->ViewportX, this->ViewportY, this->ViewportWidth, this->ViewportHeight);
275
276 ostate->vtkglBlitFramebuffer(0, 0, this->ViewportWidth, this->ViewportHeight, this->ViewportX,
277 this->ViewportY, this->ViewportX + this->ViewportWidth, this->ViewportY + this->ViewportHeight,
278 GL_COLOR_BUFFER_BIT, GL_LINEAR);
279
280 renWin->GetState()->PopReadFramebufferBinding();
281
282 vtkOpenGLCheckErrorMacro("failed after Render");
283 }
284
285 //------------------------------------------------------------------------------
286 // Description:
287 // Release graphics resources and ask components to release their own
288 // resources.
289 // \pre w_exists: w!=0
ReleaseGraphicsResources(vtkWindow * w)290 void vtkSimpleMotionBlurPass::ReleaseGraphicsResources(vtkWindow* w)
291 {
292 assert("pre: w_exists" && w != nullptr);
293
294 this->Superclass::ReleaseGraphicsResources(w);
295
296 if (this->FrameBufferObject != nullptr)
297 {
298 this->FrameBufferObject->Delete();
299 this->FrameBufferObject = nullptr;
300 }
301 if (this->ColorTexture != nullptr)
302 {
303 this->ColorTexture->ReleaseGraphicsResources(w);
304 }
305 if (this->DepthTexture != nullptr)
306 {
307 this->DepthTexture->ReleaseGraphicsResources(w);
308 }
309 if (this->AccumulationTexture[0] != nullptr)
310 {
311 this->AccumulationTexture[0]->ReleaseGraphicsResources(w);
312 }
313 if (this->AccumulationTexture[1] != nullptr)
314 {
315 this->AccumulationTexture[1]->ReleaseGraphicsResources(w);
316 }
317 if (this->BlendProgram != nullptr)
318 {
319 this->BlendProgram->ReleaseGraphicsResources(w);
320 delete this->BlendProgram;
321 this->BlendProgram = nullptr;
322 }
323 }
324