1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkLineIntegralConvolution2D.h
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 // .NAME vtkLineIntegralConvolution2D - GPU-based implementation of Line
16 //  Integral Convolution (LIC)
17 //
18 // .SECTION Description
19 //  This class resorts to GLSL to implement GPU-based Line Integral Convolution
20 //  (LIC) for visualizing a 2D vector field that may be obtained by projecting
21 //  an original 3D vector field onto a surface (such that the resulting 2D
22 //  vector at each grid point on the surface is tangential to the local normal,
23 //  as done in vtkSurfaceLICPainter).
24 //
25 //  As an image-based technique, 2D LIC works by (1) integrating a bidirectional
26 //  streamline from the center of each pixel (of the LIC output image), (2)
27 //  locating the pixels along / hit by this streamline as the correlated pixels
28 //  of the starting pixel (seed point / pixel), (3) indexing a (usually white)
29 //  noise texture (another input to LIC, in addition to the 2D vector field,
30 //  usually with the same size as that of the 2D vetor field) to determine the
31 //  values (colors) of these pixels (the starting and the correlated pixels),
32 //  typically through bi-linear interpolation, and (4) performing convolution
33 //  (weighted averaging) on these values, by adopting a low-pass filter (such
34 //  as box, ramp, and Hanning kernels), to obtain the result value (color) that
35 //  is then assigned to the seed pixel.
36 //
37 //  The GLSL-based GPU implementation herein maps the aforementioned pipeline to
38 //  fragment shaders and a box kernel is employed. Both the white noise and the
39 //  vector field are provided to the GPU as texture objects (supported by the
40 //  multi-texturing capability). In addition, there are four texture objects
41 //  (color buffers) allocated to constitute two pairs that work in a ping-pong
42 //  fashion, with one as the read buffers and the other as the write / render
43 //  targets. Maintained by a frame buffer object (GL_EXT_framebuffer_object),
44 //  each pair employs one buffer to store the current (dynamically updated)
45 //  position (by means of the texture coordinate that keeps being warped by the
46 //  underlying vector) of the (virtual) particle initially released from each
47 //  fragment while using the bother buffer to store the current (dynamically
48 //  updated too) accumulated texture value that each seed fragment (before the
49 //  'mesh' is warped) collects. Given NumberOfSteps integration steps in each
50 //  direction, there are a total of (2 * NumberOfSteps + 1) fragments (including
51 //  the seed fragment) are convolved and each contributes 1 / (2 * NumberOfSteps
52 //  + 1) of the associated texture value to fulfill the box filter.
53 //
54 //  One pass of LIC (basic LIC) tends to produce low-contrast / blurred images and
55 //  vtkLineIntegralConvolution2D provides an option for creating enhanced LIC
56 //  images. Enhanced LIC improves image quality by increasing inter-streamline
57 //  contrast while suppressing artifacts. It performs two passes of LIC, with a
58 //  3x3 Laplacian high-pass filter in between that processes the output of pass
59 //  #1 LIC and forwards the result as the input 'noise' to pass #2 LIC.
60 //
61 //  vtkLineIntegralConvolution2D applies masking to zero-vector fragments so
62 //  that un-filtered white noise areas are made totally transparent by class
63 //  vtkSurfaceLICPainter to show the underlying geometry surface.
64 //
65 //  The convolution process tends to decrease both contrast and dynamic range,
66 //  sometimes leading to dull dark images. In order to counteract this, optional
67 //  contrast ehnancement stages have been added. These increase the dynamic range and
68 //  contrast and sharpen streaking patterns that emerge from the LIC process.
69 //
70 //  Under some circumstances, typically depending on the contrast and dynamic
71 //  range and graininess of the noise texture, jagged or pixelated patterns emerge
72 //  in the LIC. These can be reduced by enabling the optional anti-aliasing pass.
73 //
74 //  The internal pipeline is as follows, with optional stages denoted by ()
75 //  nested optional stages depend on their parent stage.
76 //  <pre>
77 //   noise texture
78 //           |
79 //           [ LIC ((CE) HPF LIC) (AA) (CE) ]
80 //           |                              |
81 //  vector field                       LIC'd image
82 // </pre>
83 //  where LIC is the LIC stage, HPF is the high-pass filter stage, CE is the
84 //  contrast ehnacement stage, and AA is the antialias stage.
85 //
86 // .SECTION See Also
87 //  vtkSurfaceLICPainter vtkImageDataLIC2D vtkStructuredGridLIC2D
88 
89 #ifndef vtkLineIntegralConvolution2D_h
90 #define vtkLineIntegralConvolution2D_h
91 
92 #include "vtkObject.h"
93 #include "vtkWeakPointer.h" // for ren context
94 #include "vtkRenderingLICModule.h" // for export macro
95 #include <deque> // for deque
96 
97 class vtkRenderWindow;
98 class vtkTextureObject;
99 class vtkPixelExtent;
100 class vtkShaderProgram2;
101 class vtkFrameBufferObject2;
102 class vtkPainterCommunicator;
103 
104 class VTKRENDERINGLIC_EXPORT vtkLineIntegralConvolution2D : public vtkObject
105 {
106 public:
107   static vtkLineIntegralConvolution2D *New();
108   vtkTypeMacro(vtkLineIntegralConvolution2D, vtkObject);
109   void PrintSelf(ostream & os, vtkIndent indent);
110 
111   // Description:
112   // Returns if the context supports the required extensions.
113   static bool IsSupported(vtkRenderWindow * renWin);
114 
115   // Description:
116   // Set/Get the rendering context. A reference is not explicity held,
117   // thus refernce to the context must be held externally.
118   void SetContext(vtkRenderWindow *context);
119   vtkRenderWindow *GetContext();
120 
121   // Description:
122   // EnhancedLIC mean compute the LIC twice with the second pass using
123   // the edge-enhanced result of the first pass as a noise texture. Edge
124   // enhancedment is made by a simple Laplace convolution.
125   vtkSetClampMacro(EnhancedLIC, int, 0, 1);
126   vtkGetMacro(EnhancedLIC, int);
127   vtkBooleanMacro(EnhancedLIC, int);
128 
129   // Description:
130   // Enable/Disable contrast and dynamic range correction stages. Stage 1 is applied
131   // on the input to the high-pass filter when the high-pass filter is enabled and
132   // skipped otherwise. Stage 2, when enabled is the final stage in the internal
133   // pipeline. Both stages are implemented by a histogram stretching of the gray scale
134   // colors in the LIC'd image as follows:
135   //
136   //     c = (c-m)/(M-m)
137   //
138   // where, c is the fragment color, m is the color value to map to 0, M is the
139   // color value to map to 1. The default values of m and M are the min and max
140   // over all fragments.
141   //
142   // This increase the dynamic range and contrast in the LIC'd image, both of which
143   //  are natuarly attenuated by the LI conovlution proccess.
144   //
145   //  ENHANCE_CONTRAST_OFF  -- don't enhance contrast
146   //  ENHANCE_CONTRAST_ON   -- enhance high-pass input and final stage output
147   //
148   // This feature is disabled by default.
149   enum {
150     ENHANCE_CONTRAST_OFF=0,
151     ENHANCE_CONTRAST_ON=1};
152   vtkSetClampMacro(EnhanceContrast, int, 0, 2);
153   vtkGetMacro(EnhanceContrast, int);
154   vtkBooleanMacro(EnhanceContrast, int);
155 
156   // Description:
157   // This feature is used to fine tune the contrast enhancement. Values are provided
158   // indicating the fraction of the range to adjust m and M by during contrast enahncement
159   // histogram stretching.  M and m are the intensity/lightness values that map to 1 and 0.
160   // (see EnhanceContrast for an explanation of the mapping procedure). m and M are computed
161   // using the factors as follows:
162   //
163   //     m = min(C) - mFactor * (max(C) - min(C))
164   //     M = max(C) - MFactor * (max(C) - min(C))
165   //
166   // the default values for mFactor and MFactor are 0 which result in
167   // m = min(C), M = max(C), where C is all of the colors in the image. Adjusting
168   // mFactor and MFactor above zero provide a means to control the saturation of
169   // normalization. These settings only affect the final normalization, the
170   // normalization that occurs on the input to the high-pass filter always uses
171   // the min and max.
172   vtkSetClampMacro(LowContrastEnhancementFactor, double, 0.0, 1.0);
173   vtkGetMacro(LowContrastEnhancementFactor, double);
174   vtkSetClampMacro(HighContrastEnhancementFactor, double, 0.0, 1.0);
175   vtkGetMacro(HighContrastEnhancementFactor, double);
176 
177   // Description:
178   // Enable/Disable the anti-aliasing pass. This optional pass (disabled by
179   // default) can be enabled to reduce jagged patterns in the final LIC image.
180   // Values greater than 0 control the number of iterations, one is typically
181   // sufficient.
182   vtkSetClampMacro(AntiAlias, int, 0, VTK_INT_MAX);
183   vtkGetMacro(AntiAlias, int);
184   vtkBooleanMacro(AntiAlias, int);
185 
186   // Description:
187   // Number of streamline integration steps (initial value is 1).
188   // In term of visual quality, the greater (within some range) the better.
189   vtkSetClampMacro(NumberOfSteps, int, 0, VTK_INT_MAX);
190   vtkGetMacro(NumberOfSteps, int);
191 
192   // Description:
193   // Get/Set the streamline integration step size (0.01 by default). This is
194   // the length of each step in normalized image space i.e. in range [0, FLOAT_MAX].
195   // In term of visual quality, the smaller the better. The type for the
196   // interface is double as VTK interface is, but GPU only supports float.
197   // Thus it will be converted to float in the execution of the algorithm.
198   vtkSetClampMacro(StepSize, double, 0.0, VTK_FLOAT_MAX);
199   vtkGetMacro(StepSize, double);
200 
201   // Description:
202   // If VectorField has >= 3 components, we must choose which 2 components
203   // form the (X, Y) components for the vector field. Must be in the range
204   // [0, 3].
205   void SetComponentIds(int c0, int c1);
SetComponentIds(int c[2])206   void SetComponentIds(int c[2]){ this->SetComponentIds(c[0], c[1]); }
207   vtkGetVector2Macro(ComponentIds, int);
208 
209   // Description:
210   // Set the max noise value for use during LIC integration normalization.
211   // The integration normalization factor is the max noise value times the
212   // number of steps taken. The default value is 1.
213   vtkSetClampMacro(MaxNoiseValue, double, 0.0, 1.0);
214   vtkGetMacro(MaxNoiseValue, double);
215 
216   // Description:
217   // This class performs LIC in the normalized image space. Hence, by default
218   // it transforms the input vectors to the normalized image space (using the
219   // GridSpacings and input vector field dimensions). Set this to 0 to disable
220   // tranformation if the vectors are already transformed.
221   void SetTransformVectors(int val);
222   vtkGetMacro(TransformVectors, int);
223 
224   // Description:
225   // Set/Get the spacing in each dimension of the plane on which the vector
226   // field is defined. This class performs LIC in the normalized image space
227   // and hence generally it needs to transform the input vector field (given
228   // in physical space) to the normalized image space. The Spacing is needed
229   // to determine the transform. Default is (1.0, 1.0). It is possible to
230   // disable vector transformation by setting TransformVectors to 0.
231   //vtkSetVector2Macro(GridSpacings, double);
232   //vtkGetVector2Macro(GridSpacings, double);
233 
234   // Description:
235   // Normalize vectors during integration. When set(the default) the input vector field
236   // is normalized during integration, and each integration occurs over the same arclength.
237   // When not set each integration occurs over an arc length proportional to the field
238   // magnitude as is customary in traditional numerical methods. See, "Imaging Vector
239   // Fields Using Line Integral Convolution" for an axample where normalization is used.
240   // See, "Image Space Based Visualization of Unsteady Flow on Surfaces" for an example
241   // of where no normalization is used.
242   void SetNormalizeVectors(int val);
243   vtkGetMacro(NormalizeVectors, int);
244 
245   // Description:
246   // The MaskThreshold controls blanking of the LIC texture. For fragments with
247   // |V|<threhold the LIC fragment is not rendered. The default value is 0.0.
248   //
249   // For surface LIC MaskThreshold units are in the original vector space. For image LIC
250   // be aware that while the vector field is transformed to image space while the mask
251   // threshold is not. Therefore the mask threshold must be specified in image space
252   // units.
253   vtkSetClampMacro(MaskThreshold, double, -1.0, VTK_FLOAT_MAX);
254   vtkGetMacro(MaskThreshold, double);
255 
256 
257   // Description:
258   // Compute the lic on the entire vector field texture.
259   vtkTextureObject *Execute(
260         vtkTextureObject *vectorTex,
261         vtkTextureObject *noiseTex);
262 
263   // Description:
264   // Compute the lic on the indicated subset of the vector field
265   // texture.
266   vtkTextureObject *Execute(
267         const int extent[4],
268         vtkTextureObject *vectorTex,
269         vtkTextureObject *noiseTex);
270 
271   //BTX
272   // Description:
273   // Compute LIC over the desired subset of the input texture. The
274   // result is copied into the desired subset of the provided output
275   // texture.
276   //
277   // inputTexExtent  : screen space extent of the input texture
278   // vectorExtent    : part of the inpute extent that has valid vectors
279   // licExtent       : part of the inpute extent to compute on
280   // outputTexExtent : screen space extent of the output texture
281   // outputExtent    : part of the output texture to store the result
282   //
283   vtkTextureObject *Execute(
284         const vtkPixelExtent &inputTexExtent,
285         const std::deque<vtkPixelExtent> &vectorExtent,
286         const std::deque<vtkPixelExtent> &licExtent,
287         vtkTextureObject *vectorTex,
288         vtkTextureObject *maskVectorTex,
289         vtkTextureObject *noiseTex);
290   //ETX
291 
292   // Description:
293   // Convenience functions to ensure that the input textures are
294   // configured correctly.
295   static
296   void SetVectorTexParameters(vtkTextureObject *vectors);
297 
298   static
299   void SetNoiseTexParameters(vtkTextureObject *noise);
300 
301   //BTX
302   // Description:
303   // Set the communicator to use during parallel operation
304   // The communicator will not be duplicated or reference
305   // counted for performance reasons thus caller should
306   // hold/manage reference to the communicator during use
307   // of the LIC object.
SetCommunicator(vtkPainterCommunicator *)308   virtual void SetCommunicator(vtkPainterCommunicator *){}
309   virtual vtkPainterCommunicator *GetCommunicator();
310 
311   // Description:
312   // For parallel operation, find global min/max
313   // min/max are in/out.
GetGlobalMinMax(vtkPainterCommunicator *,float &,float &)314   virtual void GetGlobalMinMax(
315         vtkPainterCommunicator*,
316         float&,
317         float&) {}
318   //ETX
319 
320   // Description:
321   // Methods used for parallel benchmarks. Use cmake to define
322   // vtkLineIntegralConviolution2DTIME to enable benchmarks.
323   // During each update timing information is stored, it can
324   // be written to disk by calling WriteLog.
WriteTimerLog(const char *)325   virtual void WriteTimerLog(const char *){}
326 
327 protected:
328   vtkLineIntegralConvolution2D();
329   virtual ~vtkLineIntegralConvolution2D();
330 
331   void SetVTShader(vtkShaderProgram2 *prog);
332   void SetLIC0Shader(vtkShaderProgram2 *prog);
333   void SetLICIShader(vtkShaderProgram2 *prog);
334   void SetLICNShader(vtkShaderProgram2 *prog);
335   void SetEEShader(vtkShaderProgram2 *prog);
336   void SetCEShader(vtkShaderProgram2 *prog);
337   void SetAAHShader(vtkShaderProgram2 *prog);
338   void SetAAVShader(vtkShaderProgram2 *prog);
339 
340   void BuildShaders();
341 
342   void RenderQuad(
343         float computeBounds[4],
344         vtkPixelExtent computeExtent);
345 
346   vtkTextureObject *AllocateBuffer(unsigned int texSize[2]);
347 
348   // Description:
349   // Convenience functions to ensure that the input textures are
350   // configured correctly.
351   void SetNoise2TexParameters(vtkTextureObject *noise);
352 
353   // Description:
354   // Methods used for parallel benchmarks. Use cmake to define
355   // vtkSurfaceLICPainterTIME to enable benchmarks. During each
356   // update timing information is stored, it can be written to
357   // disk by calling WriteLog (defined in vtkSurfaceLICPainter).
StartTimerEvent(const char *)358   virtual void StartTimerEvent(const char *){}
EndTimerEvent(const char *)359   virtual void EndTimerEvent(const char *){}
360 
361 protected:
362   vtkPainterCommunicator *Comm;
363 
364   vtkWeakPointer<vtkRenderWindow> Context;
365   vtkFrameBufferObject2 *FBO;
366 
367   int ShadersNeedBuild;
368   vtkShaderProgram2 *VTShader;
369   vtkShaderProgram2 *LIC0Shader;
370   vtkShaderProgram2 *LICIShader;
371   vtkShaderProgram2 *LICNShader;
372   vtkShaderProgram2 *EEShader;
373   vtkShaderProgram2 *CEShader;
374   vtkShaderProgram2 *AAHShader;
375   vtkShaderProgram2 *AAVShader;
376 
377   int     NumberOfSteps;
378   double  StepSize;
379   int     EnhancedLIC;
380   int     EnhanceContrast;
381   double  LowContrastEnhancementFactor;
382   double  HighContrastEnhancementFactor;
383   int     AntiAlias;
384   int     NoiseTextureLookupCompatibilityMode;
385   double  MaskThreshold;
386   int     TransformVectors;
387   int     NormalizeVectors;
388   int     ComponentIds[2];
389   double  MaxNoiseValue;
390 
391 private:
392   vtkLineIntegralConvolution2D(const vtkLineIntegralConvolution2D &); // Not implemented.
393   void operator = (const vtkLineIntegralConvolution2D &);             // Not implemented.
394 };
395 
396 #endif
397