vtkDepthOfFieldPass.cxx 9.75 KB
Newer Older
Ken Martin's avatar
Ken Martin committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDepthOfFieldPass.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkDepthOfFieldPass.h"
#include "vtkObjectFactory.h"
#include <cassert>

#include "vtkCamera.h"
#include "vtkRenderState.h"
#include "vtkRenderer.h"
#include "vtkFrameBufferObject.h"
#include "vtkTextureObject.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkOpenGLError.h"
#include "vtkShaderProgram.h"
#include "vtkOpenGLShaderCache.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkOpenGLVertexArrayObject.h"

#include "vtkOpenGLHelper.h"

#include "vtkDepthOfFieldPassFS.h"
#include "vtkTextureObjectVS.h"

vtkStandardNewMacro(vtkDepthOfFieldPass);

// ----------------------------------------------------------------------------
vtkDepthOfFieldPass::vtkDepthOfFieldPass()
{
  this->FrameBufferObject=0;
  this->Pass1=0;
  this->Pass1Depth=0;
  this->Supported=false;
  this->SupportProbed=false;
  this->BlurProgram = NULL;
Ken Martin's avatar
Ken Martin committed
48
  this->AutomaticFocalDistance = true;
Ken Martin's avatar
Ken Martin committed
49
50
51
52
53
54
}

// ----------------------------------------------------------------------------
vtkDepthOfFieldPass::~vtkDepthOfFieldPass()
{
  if(this->FrameBufferObject!=0)
55
  {
Ken Martin's avatar
Ken Martin committed
56
    vtkErrorMacro(<<"FrameBufferObject should have been deleted in ReleaseGraphicsResources().");
57
  }
Ken Martin's avatar
Ken Martin committed
58
   if(this->Pass1!=0)
59
   {
Ken Martin's avatar
Ken Martin committed
60
    vtkErrorMacro(<<"Pass1 should have been deleted in ReleaseGraphicsResources().");
61
   }
Ken Martin's avatar
Ken Martin committed
62
   if(this->Pass1Depth!=0)
63
   {
Ken Martin's avatar
Ken Martin committed
64
    vtkErrorMacro(<<"Pass1Depth should have been deleted in ReleaseGraphicsResources().");
65
   }
Ken Martin's avatar
Ken Martin committed
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
}

// ----------------------------------------------------------------------------
void vtkDepthOfFieldPass::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

// ----------------------------------------------------------------------------
// Description:
// Perform rendering according to a render state \p s.
// \pre s_exists: s!=0
void vtkDepthOfFieldPass::Render(const vtkRenderState *s)
{
  assert("pre: s_exists" && s!=0);

  vtkOpenGLClearErrorMacro();

  this->NumberOfRenderedProps=0;

  vtkRenderer *r=s->GetRenderer();
  vtkOpenGLRenderWindow *renWin = static_cast<vtkOpenGLRenderWindow *>(r->GetRenderWindow());

  if(this->DelegatePass == 0)
90
  {
Ken Martin's avatar
Ken Martin committed
91
92
    vtkWarningMacro(<<" no delegate.");
    return;
93
  }
Ken Martin's avatar
Ken Martin committed
94
95

  if(!this->SupportProbed)
96
  {
Ken Martin's avatar
Ken Martin committed
97
98
99
100
101
    this->SupportProbed=true;
    // Test for Hardware support. If not supported, just render the delegate.
    bool supported=vtkFrameBufferObject::IsSupported(renWin);

    if(!supported)
102
    {
Ken Martin's avatar
Ken Martin committed
103
      vtkErrorMacro("FBOs are not supported by the context. Cannot blur the image.");
104
    }
Ken Martin's avatar
Ken Martin committed
105
106

    if(supported)
107
    {
Ken Martin's avatar
Ken Martin committed
108
109
      // FBO extension is supported. Is the specific FBO format supported?
      if(this->FrameBufferObject==0)
110
      {
Ken Martin's avatar
Ken Martin committed
111
112
        this->FrameBufferObject=vtkFrameBufferObject::New();
        this->FrameBufferObject->SetContext(renWin);
113
      }
Ken Martin's avatar
Ken Martin committed
114
      if(this->Pass1==0)
115
      {
Ken Martin's avatar
Ken Martin committed
116
117
        this->Pass1=vtkTextureObject::New();
        this->Pass1->SetContext(renWin);
118
      }
Ken Martin's avatar
Ken Martin committed
119
120
121
122
123
124
      this->Pass1->Create2D(64,64,4,VTK_UNSIGNED_CHAR,false);
      this->FrameBufferObject->SetColorBuffer(0,this->Pass1);
      this->FrameBufferObject->SetNumberOfRenderTargets(1);
      this->FrameBufferObject->SetActiveBuffer(0);
      this->FrameBufferObject->SetDepthBufferNeeded(true);

Ken Martin's avatar
Ken Martin committed
125
#if GL_ES_VERSION_3_0 != 1
Ken Martin's avatar
Ken Martin committed
126
127
128
129
130
      GLint savedCurrentDrawBuffer;
      glGetIntegerv(GL_DRAW_BUFFER,&savedCurrentDrawBuffer);
#endif
      supported=this->FrameBufferObject->StartNonOrtho(64,64,false);
      if(!supported)
131
      {
Ken Martin's avatar
Ken Martin committed
132
        vtkErrorMacro("The requested FBO format is not supported by the context. Cannot blur the image.");
133
      }
Ken Martin's avatar
Ken Martin committed
134
      else
135
      {
Ken Martin's avatar
Ken Martin committed
136
        this->FrameBufferObject->UnBind();
Ken Martin's avatar
Ken Martin committed
137
#if GL_ES_VERSION_3_0 != 1
Ken Martin's avatar
Ken Martin committed
138
139
140
141
        glDrawBuffer(static_cast<GLenum>(savedCurrentDrawBuffer));
#endif
      }
    }
142
143
    this->Supported=supported;
  }
Ken Martin's avatar
Ken Martin committed
144
145

  if(!this->Supported)
146
  {
Ken Martin's avatar
Ken Martin committed
147
148
149
150
    this->DelegatePass->Render(s);
    this->NumberOfRenderedProps+=
      this->DelegatePass->GetNumberOfRenderedProps();
    return;
151
  }
Ken Martin's avatar
Ken Martin committed
152

Ken Martin's avatar
Ken Martin committed
153
#if GL_ES_VERSION_3_0 != 1
Ken Martin's avatar
Ken Martin committed
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  GLint savedDrawBuffer;
  glGetIntegerv(GL_DRAW_BUFFER,&savedDrawBuffer);
#endif

  // 1. Create a new render state with an FBO.

  int width;
  int height;
  int size[2];
  s->GetWindowSize(size);
  width = size[0];
  height = size[1];

  // I suggest set this to 100 for debugging, makes some errors
  // much easier to find.
  // Objects that are out of view can blur onto the image due to
  // the COC, so we render a few border pixels to prevent discontinuities
  const int extraPixels = 16;

  int w = width + extraPixels*2;
  int h = height + extraPixels*2;

  if(this->Pass1==0)
177
  {
Ken Martin's avatar
Ken Martin committed
178
179
    this->Pass1 = vtkTextureObject::New();
    this->Pass1->SetContext(renWin);
180
  }
Ken Martin's avatar
Ken Martin committed
181
182
  if(this->Pass1->GetWidth()!=static_cast<unsigned int>(w) ||
     this->Pass1->GetHeight()!=static_cast<unsigned int>(h))
183
  {
Ken Martin's avatar
Ken Martin committed
184
185
186
    this->Pass1->Create2D(static_cast<unsigned int>(w),
                          static_cast<unsigned int>(h),4,
                          VTK_UNSIGNED_CHAR,false);
187
  }
Ken Martin's avatar
Ken Martin committed
188
189
190

  // Depth texture
  if (this->Pass1Depth == 0)
191
  {
Ken Martin's avatar
Ken Martin committed
192
193
    this->Pass1Depth = vtkTextureObject::New();
    this->Pass1Depth->SetContext(renWin);
194
  }
Ken Martin's avatar
Ken Martin committed
195
196
  if (this->Pass1Depth->GetWidth() != static_cast<unsigned int> (w)
      || this->Pass1Depth->GetHeight() != static_cast<unsigned int> (h))
197
  {
Ken Martin's avatar
Ken Martin committed
198
199
    this->Pass1Depth->AllocateDepth(
      w, h, vtkTextureObject::Float32);
200
  }
Ken Martin's avatar
Ken Martin committed
201
202

  if(this->FrameBufferObject==0)
203
  {
Ken Martin's avatar
Ken Martin committed
204
205
    this->FrameBufferObject=vtkFrameBufferObject::New();
    this->FrameBufferObject->SetContext(renWin);
206
  }
Ken Martin's avatar
Ken Martin committed
207
208
209
210
211
212

  this->RenderDelegate(s,width,height,w,h,this->FrameBufferObject,
                       this->Pass1, this->Pass1Depth);

  this->FrameBufferObject->UnBind();

Ken Martin's avatar
Ken Martin committed
213
#if GL_ES_VERSION_3_0 != 1
Ken Martin's avatar
Ken Martin committed
214
215
216
217
218
  glDrawBuffer(static_cast<GLenum>(savedDrawBuffer));
#endif

  // has something changed that would require us to recreate the shader?
  if (!this->BlurProgram)
219
  {
Ken Martin's avatar
Ken Martin committed
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
    this->BlurProgram = new vtkOpenGLHelper;
    // build the shader source code
    std::string VSSource = vtkTextureObjectVS;
    std::string FSSource = vtkDepthOfFieldPassFS;
    std::string GSSource;

    // compile and bind it if needed
    vtkShaderProgram *newShader =
      renWin->GetShaderCache()->ReadyShaderProgram(
        VSSource.c_str(),
        FSSource.c_str(),
        GSSource.c_str());

    // if the shader changed reinitialize the VAO
    if (newShader != this->BlurProgram->Program)
235
    {
Ken Martin's avatar
Ken Martin committed
236
237
      this->BlurProgram->Program = newShader;
      this->BlurProgram->VAO->ShaderProgramChanged(); // reset the VAO as the shader has changed
238
    }
Ken Martin's avatar
Ken Martin committed
239
240

    this->BlurProgram->ShaderSourceTime.Modified();
241
  }
Ken Martin's avatar
Ken Martin committed
242
  else
243
  {
Ken Martin's avatar
Ken Martin committed
244
    renWin->GetShaderCache()->ReadyShaderProgram(this->BlurProgram->Program);
245
  }
Ken Martin's avatar
Ken Martin committed
246

Ken Martin's avatar
Ken Martin committed
247
248
  glDisable(GL_BLEND);
  glDisable(GL_DEPTH_TEST);
Ken Martin's avatar
Ken Martin committed
249
250
251
252
253
254
255
256
257
258
259
260

  this->Pass1->Activate();
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  this->BlurProgram->Program->SetUniformi("source",this->Pass1->GetTextureUnit());

  this->Pass1Depth->Activate();
  this->BlurProgram->Program->SetUniformi("depth",this->Pass1Depth->GetTextureUnit());

  vtkCamera *cam = r->GetActiveCamera();
  double *frange = cam->GetClippingRange();
  float fdist = cam->GetDistance();
Ken Martin's avatar
Ken Martin committed
261
//  fdist = fdist - 0.1*(frange[1] - frange[0]);
Ken Martin's avatar
Ken Martin committed
262
263
264
265
266
267
268
  float focalDisk = cam->GetFocalDisk();
  float vAngle = cam->GetViewAngle();
  double *aspect = r->GetAspect();

  float winWidth;
  float winHeight;
  if(cam->GetUseHorizontalViewAngle())
269
  {
Ken Martin's avatar
Ken Martin committed
270
271
    winWidth = 2.0*tan(vAngle/2.0)*fdist;
    winHeight = winWidth*aspect[1]/aspect[0];
272
  }
Ken Martin's avatar
Ken Martin committed
273
  else
274
  {
Ken Martin's avatar
Ken Martin committed
275
276
    winHeight = 2.0*tan(vAngle/2.0)*fdist;
    winWidth = winHeight*aspect[0]/aspect[1];
277
  }
Ken Martin's avatar
Ken Martin committed
278
279
280
281
282
283
284
285

  float offset[2];
  offset[0] = 1.0/winWidth;
  offset[1] = 1.0/winHeight;
  this->BlurProgram->Program->SetUniform2f("worldToTCoord", offset);
  offset[0] = 1.0/w;
  offset[1] = 1.0/h;
  this->BlurProgram->Program->SetUniform2f("pixelToTCoord", offset);
Ken Martin's avatar
Ken Martin committed
286
287
288
289
290
  this->BlurProgram->Program->SetUniformf("nearC",frange[0]);
  this->BlurProgram->Program->SetUniformf("farC",frange[1]);
  this->BlurProgram->Program->SetUniformf("focalDisk",focalDisk);

  if (this->AutomaticFocalDistance)
291
  {
Ken Martin's avatar
Ken Martin committed
292
    this->BlurProgram->Program->SetUniformf("focalDistance",0.0);
293
  }
Ken Martin's avatar
Ken Martin committed
294
  else
295
  {
Ken Martin's avatar
Ken Martin committed
296
    this->BlurProgram->Program->SetUniformf("focalDistance",fdist);
297
  }
Ken Martin's avatar
Ken Martin committed
298
299
300
301
302
303
304
305

  this->Pass1->CopyToFrameBuffer(extraPixels, extraPixels,
                                w-1-extraPixels,h-1-extraPixels,
                                0,0, width, height,
                                this->BlurProgram->Program,
                                this->BlurProgram->VAO);

  this->Pass1->Deactivate();
306
  this->Pass1Depth->Deactivate();
Ken Martin's avatar
Ken Martin committed
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322

  vtkOpenGLCheckErrorMacro("failed after Render");
}

// ----------------------------------------------------------------------------
// Description:
// Release graphics resources and ask components to release their own
// resources.
// \pre w_exists: w!=0
void vtkDepthOfFieldPass::ReleaseGraphicsResources(vtkWindow *w)
{
  assert("pre: w_exists" && w!=0);

  this->Superclass::ReleaseGraphicsResources(w);

  if (this->BlurProgram !=0)
323
  {
Ken Martin's avatar
Ken Martin committed
324
325
326
    this->BlurProgram->ReleaseGraphicsResources(w);
    delete this->BlurProgram;
    this->BlurProgram = 0;
327
  }
Ken Martin's avatar
Ken Martin committed
328
  if(this->FrameBufferObject!=0)
329
  {
Ken Martin's avatar
Ken Martin committed
330
331
    this->FrameBufferObject->Delete();
    this->FrameBufferObject=0;
332
  }
Ken Martin's avatar
Ken Martin committed
333
   if(this->Pass1!=0)
334
   {
Ken Martin's avatar
Ken Martin committed
335
336
    this->Pass1->Delete();
    this->Pass1=0;
337
   }
Ken Martin's avatar
Ken Martin committed
338
   if(this->Pass1Depth!=0)
339
   {
Ken Martin's avatar
Ken Martin committed
340
341
    this->Pass1Depth->Delete();
    this->Pass1Depth=0;
342
   }
Ken Martin's avatar
Ken Martin committed
343
}