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