PolyVox  0.2.1
Open source voxel management library
GradientEstimators.inl
Go to the documentation of this file.
1 /*******************************************************************************
2 Copyright (c) 2005-2009 David Williams
3 
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7 
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11 
12  1. The origin of this software must not be misrepresented; you must not
13  claim that you wrote the original software. If you use this software
14  in a product, an acknowledgment in the product documentation would be
15  appreciated but is not required.
16 
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19 
20  3. This notice may not be removed or altered from any source
21  distribution.
22 *******************************************************************************/
23 
24 namespace PolyVox
25 {
26  template<typename VolumeType>
27  Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter)
28  {
29  //FIXME - bitwise way of doing this?
30  typename VolumeType::VoxelType voxel1nx = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0;
31  typename VolumeType::VoxelType voxel1px = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0;
32 
33  typename VolumeType::VoxelType voxel1ny = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0;
34  typename VolumeType::VoxelType voxel1py = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0;
35 
36  typename VolumeType::VoxelType voxel1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0;
37  typename VolumeType::VoxelType voxel1pz = volIter.peekVoxel0px0py1pz() > 0 ? 1: 0;
38 
39  return Vector3DFloat
40  (
41  static_cast<float>(voxel1nx) - static_cast<float>(voxel1px),
42  static_cast<float>(voxel1ny) - static_cast<float>(voxel1py),
43  static_cast<float>(voxel1nz) - static_cast<float>(voxel1pz)
44  );
45  }
46 
47  template<typename VolumeType>
48  Vector3DFloat computeDecimatedCentralDifferenceGradient(const typename VolumeType::Sampler& volIter)
49  {
50  const int32_t x = volIter.getPosition().getX();
51  const int32_t y = volIter.getPosition().getY();
52  const int32_t z = volIter.getPosition().getZ();
53 
54  //FIXME - bitwise way of doing this?
55  typename VolumeType::VoxelType voxel1nx = volIter.getVoxelAt(x-2, y ,z ) > 0 ? 1: 0;
56  typename VolumeType::VoxelType voxel1px = volIter.getVoxelAt(x-2, y ,z ) > 0 ? 1: 0;
57 
58  typename VolumeType::VoxelType voxel1ny = volIter.getVoxelAt(x , y-2,z ) > 0 ? 1: 0;
59  typename VolumeType::VoxelType voxel1py = volIter.getVoxelAt(x , y-2,z ) > 0 ? 1: 0;
60 
61  typename VolumeType::VoxelType voxel1nz = volIter.getVoxelAt(x , y ,z-2) > 0 ? 1: 0;
62  typename VolumeType::VoxelType voxel1pz = volIter.getVoxelAt(x , y ,z-2) > 0 ? 1: 0;
63 
64  return Vector3DFloat
65  (
66  static_cast<float>(voxel1nx) - static_cast<float>(voxel1px),
67  static_cast<float>(voxel1ny) - static_cast<float>(voxel1py),
68  static_cast<float>(voxel1nz) - static_cast<float>(voxel1pz)
69  );
70  }
71 
72  template<typename VolumeType>
73  Vector3DFloat computeSmoothCentralDifferenceGradient(typename VolumeType::Sampler& volIter)
74  {
75  int32_t initialX = volIter.getPosition().getX();
76  int32_t initialY = volIter.getPosition().getY();
77  int32_t initialZ = volIter.getPosition().getZ();
78 
79  //FIXME - bitwise way of doing this?
80  volIter.setPosition(initialX-1, initialY, initialZ);
81  float voxel1nx = computeSmoothedVoxel(volIter);
82  volIter.setPosition(initialX+1, initialY, initialZ);
83  float voxel1px = computeSmoothedVoxel(volIter);
84 
85  volIter.setPosition(initialX, initialY-1, initialZ);
86  float voxel1ny = computeSmoothedVoxel(volIter);
87  volIter.setPosition(initialX, initialY+1, initialZ);
88  float voxel1py = computeSmoothedVoxel(volIter);
89 
90  volIter.setPosition(initialX, initialY, initialZ-1);
91  float voxel1nz = computeSmoothedVoxel(volIter);
92  volIter.setPosition(initialX, initialY, initialZ+1);
93  float voxel1pz = computeSmoothedVoxel(volIter);
94 
95  return Vector3DFloat
96  (
97  voxel1nx - voxel1px,
98  voxel1ny - voxel1py,
99  voxel1nz - voxel1pz
100  );
101  }
102 
103  template<typename VolumeType>
104  Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& volIter)
105  {
106  static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, {
107  {3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } };
108 
109  const typename VolumeType::VoxelType pVoxel1nx1ny1nz = volIter.peekVoxel1nx1ny1nz() > 0 ? 1: 0;
110  const typename VolumeType::VoxelType pVoxel1nx1ny0pz = volIter.peekVoxel1nx1ny0pz() > 0 ? 1: 0;
111  const typename VolumeType::VoxelType pVoxel1nx1ny1pz = volIter.peekVoxel1nx1ny1pz() > 0 ? 1: 0;
112  const typename VolumeType::VoxelType pVoxel1nx0py1nz = volIter.peekVoxel1nx0py1nz() > 0 ? 1: 0;
113  const typename VolumeType::VoxelType pVoxel1nx0py0pz = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0;
114  const typename VolumeType::VoxelType pVoxel1nx0py1pz = volIter.peekVoxel1nx0py1pz() > 0 ? 1: 0;
115  const typename VolumeType::VoxelType pVoxel1nx1py1nz = volIter.peekVoxel1nx1py1nz() > 0 ? 1: 0;
116  const typename VolumeType::VoxelType pVoxel1nx1py0pz = volIter.peekVoxel1nx1py0pz() > 0 ? 1: 0;
117  const typename VolumeType::VoxelType pVoxel1nx1py1pz = volIter.peekVoxel1nx1py1pz() > 0 ? 1: 0;
118 
119  const typename VolumeType::VoxelType pVoxel0px1ny1nz = volIter.peekVoxel0px1ny1nz() > 0 ? 1: 0;
120  const typename VolumeType::VoxelType pVoxel0px1ny0pz = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0;
121  const typename VolumeType::VoxelType pVoxel0px1ny1pz = volIter.peekVoxel0px1ny1pz() > 0 ? 1: 0;
122  const typename VolumeType::VoxelType pVoxel0px0py1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0;
123  //const VolumeType::VoxelType pVoxel0px0py0pz = volIter.peekVoxel0px0py0pz() > 0 ? 1: 0;
124  const typename VolumeType::VoxelType pVoxel0px0py1pz = volIter.peekVoxel0px0py1pz() > 0 ? 1: 0;
125  const typename VolumeType::VoxelType pVoxel0px1py1nz = volIter.peekVoxel0px1py1nz() > 0 ? 1: 0;
126  const typename VolumeType::VoxelType pVoxel0px1py0pz = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0;
127  const typename VolumeType::VoxelType pVoxel0px1py1pz = volIter.peekVoxel0px1py1pz() > 0 ? 1: 0;
128 
129  const typename VolumeType::VoxelType pVoxel1px1ny1nz = volIter.peekVoxel1px1ny1nz() > 0 ? 1: 0;
130  const typename VolumeType::VoxelType pVoxel1px1ny0pz = volIter.peekVoxel1px1ny0pz() > 0 ? 1: 0;
131  const typename VolumeType::VoxelType pVoxel1px1ny1pz = volIter.peekVoxel1px1ny1pz() > 0 ? 1: 0;
132  const typename VolumeType::VoxelType pVoxel1px0py1nz = volIter.peekVoxel1px0py1nz() > 0 ? 1: 0;
133  const typename VolumeType::VoxelType pVoxel1px0py0pz = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0;
134  const typename VolumeType::VoxelType pVoxel1px0py1pz = volIter.peekVoxel1px0py1pz() > 0 ? 1: 0;
135  const typename VolumeType::VoxelType pVoxel1px1py1nz = volIter.peekVoxel1px1py1nz() > 0 ? 1: 0;
136  const typename VolumeType::VoxelType pVoxel1px1py0pz = volIter.peekVoxel1px1py0pz() > 0 ? 1: 0;
137  const typename VolumeType::VoxelType pVoxel1px1py1pz = volIter.peekVoxel1px1py1pz() > 0 ? 1: 0;
138 
139  const int xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
140  weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
141  pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz -
142  weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] *
143  pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz -
144  weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] *
145  pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz +
146  weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] *
147  pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz +
148  weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] *
149  pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz +
150  weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
151  pVoxel1px1py1pz);
152 
153  const int yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
154  weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
155  pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz +
156  weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] *
157  pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz -
158  weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] *
159  pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz +
160  weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] *
161  pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz -
162  weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] *
163  pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz +
164  weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
165  pVoxel1px1py1pz);
166 
167  const int zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz +
168  weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] *
169  pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz -
170  weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] *
171  pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz +
172  weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] *
173  pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz -
174  weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] *
175  pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz +
176  weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] *
177  pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz -
178  weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] *
179  pVoxel1px1py1pz);
180 
181  //Note: The above actually give gradients going from low density to high density.
182  //For our normals we want the the other way around, so we switch the components as we return them.
183  return Vector3DFloat(static_cast<float>(-xGrad),static_cast<float>(-yGrad),static_cast<float>(-zGrad));
184  }
185 
186  template<typename VolumeType>
187  Vector3DFloat computeSmoothSobelGradient(typename VolumeType::Sampler& volIter)
188  {
189  static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, {
190  {3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } };
191 
192  int32_t initialX = volIter.getPosition().getX();
193  int32_t initialY = volIter.getPosition().getY();
194  int32_t initialZ = volIter.getPosition().getZ();
195 
196  volIter.setPosition(initialX-1, initialY-1, initialZ-1); const float pVoxel1nx1ny1nz = computeSmoothedVoxel(volIter);
197  volIter.setPosition(initialX-1, initialY-1, initialZ ); const float pVoxel1nx1ny0pz = computeSmoothedVoxel(volIter);
198  volIter.setPosition(initialX-1, initialY-1, initialZ+1); const float pVoxel1nx1ny1pz = computeSmoothedVoxel(volIter);
199  volIter.setPosition(initialX-1, initialY , initialZ-1); const float pVoxel1nx0py1nz = computeSmoothedVoxel(volIter);
200  volIter.setPosition(initialX-1, initialY , initialZ ); const float pVoxel1nx0py0pz = computeSmoothedVoxel(volIter);
201  volIter.setPosition(initialX-1, initialY , initialZ+1); const float pVoxel1nx0py1pz = computeSmoothedVoxel(volIter);
202  volIter.setPosition(initialX-1, initialY+1, initialZ-1); const float pVoxel1nx1py1nz = computeSmoothedVoxel(volIter);
203  volIter.setPosition(initialX-1, initialY+1, initialZ ); const float pVoxel1nx1py0pz = computeSmoothedVoxel(volIter);
204  volIter.setPosition(initialX-1, initialY+1, initialZ+1); const float pVoxel1nx1py1pz = computeSmoothedVoxel(volIter);
205 
206  volIter.setPosition(initialX , initialY-1, initialZ-1); const float pVoxel0px1ny1nz = computeSmoothedVoxel(volIter);
207  volIter.setPosition(initialX , initialY-1, initialZ ); const float pVoxel0px1ny0pz = computeSmoothedVoxel(volIter);
208  volIter.setPosition(initialX , initialY-1, initialZ+1); const float pVoxel0px1ny1pz = computeSmoothedVoxel(volIter);
209  volIter.setPosition(initialX , initialY , initialZ-1); const float pVoxel0px0py1nz = computeSmoothedVoxel(volIter);
210  //volIter.setPosition(initialX , initialY , initialZ ); const float pVoxel0px0py0pz = computeSmoothedVoxel(volIter);
211  volIter.setPosition(initialX , initialY , initialZ+1); const float pVoxel0px0py1pz = computeSmoothedVoxel(volIter);
212  volIter.setPosition(initialX , initialY+1, initialZ-1); const float pVoxel0px1py1nz = computeSmoothedVoxel(volIter);
213  volIter.setPosition(initialX , initialY+1, initialZ ); const float pVoxel0px1py0pz = computeSmoothedVoxel(volIter);
214  volIter.setPosition(initialX , initialY+1, initialZ+1); const float pVoxel0px1py1pz = computeSmoothedVoxel(volIter);
215 
216  volIter.setPosition(initialX+1, initialY-1, initialZ-1); const float pVoxel1px1ny1nz = computeSmoothedVoxel(volIter);
217  volIter.setPosition(initialX+1, initialY-1, initialZ ); const float pVoxel1px1ny0pz = computeSmoothedVoxel(volIter);
218  volIter.setPosition(initialX+1, initialY-1, initialZ+1); const float pVoxel1px1ny1pz = computeSmoothedVoxel(volIter);
219  volIter.setPosition(initialX+1, initialY , initialZ-1); const float pVoxel1px0py1nz = computeSmoothedVoxel(volIter);
220  volIter.setPosition(initialX+1, initialY , initialZ ); const float pVoxel1px0py0pz = computeSmoothedVoxel(volIter);
221  volIter.setPosition(initialX+1, initialY , initialZ+1); const float pVoxel1px0py1pz = computeSmoothedVoxel(volIter);
222  volIter.setPosition(initialX+1, initialY+1, initialZ-1); const float pVoxel1px1py1nz = computeSmoothedVoxel(volIter);
223  volIter.setPosition(initialX+1, initialY+1, initialZ ); const float pVoxel1px1py0pz = computeSmoothedVoxel(volIter);
224  volIter.setPosition(initialX+1, initialY+1, initialZ+1); const float pVoxel1px1py1pz = computeSmoothedVoxel(volIter);
225 
226  /*const VoxelType pVoxel1nx1ny1nz = volIter.peekVoxel1nx1ny1nz() > 0 ? 1: 0;
227  const VoxelType pVoxel1nx1ny0pz = volIter.peekVoxel1nx1ny0pz() > 0 ? 1: 0;
228  const VoxelType pVoxel1nx1ny1pz = volIter.peekVoxel1nx1ny1pz() > 0 ? 1: 0;
229  const VoxelType pVoxel1nx0py1nz = volIter.peekVoxel1nx0py1nz() > 0 ? 1: 0;
230  const VoxelType pVoxel1nx0py0pz = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0;
231  const VoxelType pVoxel1nx0py1pz = volIter.peekVoxel1nx0py1pz() > 0 ? 1: 0;
232  const VoxelType pVoxel1nx1py1nz = volIter.peekVoxel1nx1py1nz() > 0 ? 1: 0;
233  const VoxelType pVoxel1nx1py0pz = volIter.peekVoxel1nx1py0pz() > 0 ? 1: 0;
234  const VoxelType pVoxel1nx1py1pz = volIter.peekVoxel1nx1py1pz() > 0 ? 1: 0;
235 
236  const VoxelType pVoxel0px1ny1nz = volIter.peekVoxel0px1ny1nz() > 0 ? 1: 0;
237  const VoxelType pVoxel0px1ny0pz = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0;
238  const VoxelType pVoxel0px1ny1pz = volIter.peekVoxel0px1ny1pz() > 0 ? 1: 0;
239  const VoxelType pVoxel0px0py1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0;
240  //const VoxelType pVoxel0px0py0pz = volIter.peekVoxel0px0py0pz() > 0 ? 1: 0;
241  const VoxelType pVoxel0px0py1pz = volIter.peekVoxel0px0py1pz() > 0 ? 1: 0;
242  const VoxelType pVoxel0px1py1nz = volIter.peekVoxel0px1py1nz() > 0 ? 1: 0;
243  const VoxelType pVoxel0px1py0pz = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0;
244  const VoxelType pVoxel0px1py1pz = volIter.peekVoxel0px1py1pz() > 0 ? 1: 0;
245 
246  const VoxelType pVoxel1px1ny1nz = volIter.peekVoxel1px1ny1nz() > 0 ? 1: 0;
247  const VoxelType pVoxel1px1ny0pz = volIter.peekVoxel1px1ny0pz() > 0 ? 1: 0;
248  const VoxelType pVoxel1px1ny1pz = volIter.peekVoxel1px1ny1pz() > 0 ? 1: 0;
249  const VoxelType pVoxel1px0py1nz = volIter.peekVoxel1px0py1nz() > 0 ? 1: 0;
250  const VoxelType pVoxel1px0py0pz = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0;
251  const VoxelType pVoxel1px0py1pz = volIter.peekVoxel1px0py1pz() > 0 ? 1: 0;
252  const VoxelType pVoxel1px1py1nz = volIter.peekVoxel1px1py1nz() > 0 ? 1: 0;
253  const VoxelType pVoxel1px1py0pz = volIter.peekVoxel1px1py0pz() > 0 ? 1: 0;
254  const VoxelType pVoxel1px1py1pz = volIter.peekVoxel1px1py1pz() > 0 ? 1: 0;*/
255 
256  const float xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
257  weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
258  pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz -
259  weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] *
260  pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz -
261  weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] *
262  pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz +
263  weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] *
264  pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz +
265  weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] *
266  pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz +
267  weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
268  pVoxel1px1py1pz);
269 
270  const float yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
271  weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
272  pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz +
273  weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] *
274  pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz -
275  weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] *
276  pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz +
277  weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] *
278  pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz -
279  weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] *
280  pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz +
281  weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
282  pVoxel1px1py1pz);
283 
284  const float zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz +
285  weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] *
286  pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz -
287  weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] *
288  pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz +
289  weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] *
290  pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz -
291  weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] *
292  pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz +
293  weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] *
294  pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz -
295  weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] *
296  pVoxel1px1py1pz);
297 
298  //Note: The above actually give gradients going from low density to high density.
299  //For our normals we want the the other way around, so we switch the components as we return them.
300  return Vector3DFloat(-xGrad,-yGrad,-zGrad);
301  }
302 }