1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkUnstructuredGridPartialPreIntegration.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 
16 /*
17  * Copyright 2004 Sandia Corporation.
18  * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
19  * license for use of this work by or on behalf of the
20  * U.S. Government. Redistribution and use in source and binary forms, with
21  * or without modification, are permitted provided that this Notice and any
22  * statement of authorship are reproduced on all copies.
23  */
24 
25 /**
26  * @class   vtkUnstructuredGridPartialPreIntegration
27  * @brief   performs piecewise linear ray integration.
28  *
29  *
30  *
31  * vtkUnstructuredGridPartialPreIntegration performs piecewise linear ray
32  * integration.  This will give the same results as
33  * vtkUnstructuredGridLinearRayIntegration (with potentially a error due to
34  * table lookup quantization), but should be notably faster.  The algorithm
35  * used is given by Moreland and Angel, "A Fast High Accuracy Volume
36  * Renderer for Unstructured Data."
37  *
38  * This class is thread safe only after the first instance is created.
39  *
40  */
41 
42 #ifndef vtkUnstructuredGridPartialPreIntegration_h
43 #define vtkUnstructuredGridPartialPreIntegration_h
44 
45 #include "vtkMath.h"                  // For all the inline methods
46 #include "vtkRenderingVolumeModule.h" // For export macro
47 #include "vtkUnstructuredGridVolumeRayIntegrator.h"
48 
49 class vtkPartialPreIntegrationTransferFunction;
50 class vtkVolumeProperty;
51 
52 class VTKRENDERINGVOLUME_EXPORT vtkUnstructuredGridPartialPreIntegration
53   : public vtkUnstructuredGridVolumeRayIntegrator
54 {
55 public:
56   vtkTypeMacro(vtkUnstructuredGridPartialPreIntegration, vtkUnstructuredGridVolumeRayIntegrator);
57   static vtkUnstructuredGridPartialPreIntegration* New();
58   void PrintSelf(ostream& os, vtkIndent indent) override;
59 
60   void Initialize(vtkVolume* volume, vtkDataArray* scalars) override;
61 
62   void Integrate(vtkDoubleArray* intersectionLengths, vtkDataArray* nearIntersections,
63     vtkDataArray* farIntersections, float color[4]) override;
64 
65   ///@{
66   /**
67    * Integrates a single ray segment.  \c color is blended with the result
68    * (with \c color in front).  The result is written back into \c color.
69    */
70   static void IntegrateRay(double length, double intensity_front, double attenuation_front,
71     double intensity_back, double attenuation_back, float color[4]);
72   static void IntegrateRay(double length, const double color_front[3], double attenuation_front,
73     const double color_back[3], double attenuation_back, float color[4]);
74   ///@}
75 
76   ///@{
77   /**
78    * Looks up Psi (as defined by Moreland and Angel, "A Fast High Accuracy
79    * Volume Renderer for Unstructured Data") in a table.  The table must be
80    * created first, which happens on the first instantiation of this class
81    * or when BuildPsiTable is first called.
82    */
83   static float Psi(float taufD, float taubD);
84   static float* GetPsiTable(int& size);
85   static void BuildPsiTable();
86   ///@}
87 
88 protected:
89   vtkUnstructuredGridPartialPreIntegration();
90   ~vtkUnstructuredGridPartialPreIntegration() override;
91 
92   vtkVolumeProperty* Property;
93 
94   vtkPartialPreIntegrationTransferFunction* TransferFunctions;
95   vtkTimeStamp TransferFunctionsModified;
96   int NumIndependentComponents;
97 
98   enum
99   {
100     PSI_TABLE_SIZE = 512
101   };
102 
103   static float PsiTable[PSI_TABLE_SIZE * PSI_TABLE_SIZE];
104   static int PsiTableBuilt;
105 
106 private:
107   vtkUnstructuredGridPartialPreIntegration(
108     const vtkUnstructuredGridPartialPreIntegration&) = delete;
109   void operator=(const vtkUnstructuredGridPartialPreIntegration&) = delete;
110 };
111 
Psi(float taufD,float taubD)112 inline float vtkUnstructuredGridPartialPreIntegration::Psi(float taufD, float taubD)
113 {
114   float gammaf = taufD / (taufD + 1);
115   float gammab = taubD / (taubD + 1);
116   int gammafi = vtkMath::Floor(gammaf * PSI_TABLE_SIZE);
117   int gammabi = vtkMath::Floor(gammab * PSI_TABLE_SIZE);
118   return PsiTable[gammafi * PSI_TABLE_SIZE + gammabi];
119 }
120 
GetPsiTable(int & size)121 inline float* vtkUnstructuredGridPartialPreIntegration::GetPsiTable(int& size)
122 {
123   size = PSI_TABLE_SIZE;
124   return PsiTable;
125 }
126 
IntegrateRay(double length,double intensity_front,double attenuation_front,double intensity_back,double attenuation_back,float color[4])127 inline void vtkUnstructuredGridPartialPreIntegration::IntegrateRay(double length,
128   double intensity_front, double attenuation_front, double intensity_back, double attenuation_back,
129   float color[4])
130 {
131   float taufD = length * attenuation_front;
132   float taubD = length * attenuation_back;
133   float Psi = vtkUnstructuredGridPartialPreIntegration::Psi(taufD, taubD);
134   float zeta = static_cast<float>(exp(-0.5 * (taufD + taubD)));
135   float alpha = 1 - zeta;
136 
137   float newintensity =
138     (1 - color[3]) * (intensity_front * (1 - Psi) + intensity_back * (Psi - zeta));
139   // Is setting the RGB values the same the right thing to do?
140   color[0] += newintensity;
141   color[1] += newintensity;
142   color[2] += newintensity;
143   color[3] += (1 - color[3]) * alpha;
144 }
145 
IntegrateRay(double length,const double color_front[3],double attenuation_front,const double color_back[3],double attenuation_back,float color[4])146 inline void vtkUnstructuredGridPartialPreIntegration::IntegrateRay(double length,
147   const double color_front[3], double attenuation_front, const double color_back[3],
148   double attenuation_back, float color[4])
149 {
150   float taufD = length * attenuation_front;
151   float taubD = length * attenuation_back;
152   float Psi = vtkUnstructuredGridPartialPreIntegration::Psi(taufD, taubD);
153   float zeta = static_cast<float>(exp(-0.5 * (taufD + taubD)));
154   float alpha = 1 - zeta;
155 
156   color[0] += (1 - color[3]) * (color_front[0] * (1 - Psi) + color_back[0] * (Psi - zeta));
157   color[1] += (1 - color[3]) * (color_front[1] * (1 - Psi) + color_back[1] * (Psi - zeta));
158   color[2] += (1 - color[3]) * (color_front[2] * (1 - Psi) + color_back[2] * (Psi - zeta));
159   color[3] += (1 - color[3]) * alpha;
160 }
161 
162 #endif // vtkUnstructuredGridPartialPreIntegration_h
163