• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

PolyVoxCore/include/PolyVoxCore/Raycast.inl

Go to the documentation of this file.
00001 /*******************************************************************************
00002 Copyright (c) 2005-2009 David Williams
00003 
00004 This software is provided 'as-is', without any express or implied
00005 warranty. In no event will the authors be held liable for any damages
00006 arising from the use of this software.
00007 
00008 Permission is granted to anyone to use this software for any purpose,
00009 including commercial applications, and to alter it and redistribute it
00010 freely, subject to the following restrictions:
00011 
00012     1. The origin of this software must not be misrepresented; you must not
00013     claim that you wrote the original software. If you use this software
00014     in a product, an acknowledgment in the product documentation would be
00015     appreciated but is not required.
00016 
00017     2. Altered source versions must be plainly marked as such, and must not be
00018     misrepresented as being the original software.
00019 
00020     3. This notice may not be removed or altered from any source
00021     distribution.   
00022 *******************************************************************************/
00023 
00024 namespace PolyVox
00025 {
00034     template< template<typename> class VolumeType, typename VoxelType>
00035     Raycast<VolumeType, VoxelType>::Raycast(VolumeType<VoxelType>* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirection, RaycastResult& result)
00036         :m_result(result)
00037         ,m_volData(volData)
00038         ,m_sampVolume(volData)
00039         ,m_v3dStart(v3dStart)
00040         ,m_v3dDirection(v3dDirection)
00041     {
00042     }
00043 
00047     template< template<typename> class VolumeType, typename VoxelType>
00048     void Raycast<VolumeType, VoxelType>::setStart(const Vector3DFloat& v3dStart)
00049     {
00050         m_v3dStart = v3dStart;
00051     }
00052 
00057     template< template<typename> class VolumeType, typename VoxelType>
00058     void Raycast<VolumeType, VoxelType>::setDirection(const Vector3DFloat& v3dDirection)
00059     {
00060         m_v3dDirection = v3dDirection;
00061     }
00062 
00066     template< template<typename> class VolumeType, typename VoxelType>
00067     void Raycast<VolumeType, VoxelType>::execute(void)
00068     {
00069         //The doRaycast function is assuming that it is iterating over the areas defined between
00070         //voxels. We actually want to define the areas as being centered on voxels (as this is
00071         //what the CubicSurfaceExtractor generates). We add (0.5,0.5,0.5) here to adjust for this.
00072         Vector3DFloat v3dStart = m_v3dStart + Vector3DFloat(0.5f, 0.5f, 0.5f);
00073 
00074         //Compute the end point
00075         Vector3DFloat v3dEnd = v3dStart + m_v3dDirection;
00076 
00077         //Do the raycast
00078         doRaycast(v3dStart.getX(), v3dStart.getY(), v3dStart.getZ(), v3dEnd.getX(), v3dEnd.getY(), v3dEnd.getZ());
00079     }
00080 
00081     // This function is based on Christer Ericson's code and description of the 'Uniform Grid Intersection Test' in
00082     // 'Real Time Collision Detection'. The following information from the errata on the book website is also relevent:
00083     //
00084     //  pages 326-327. In the function VisitCellsOverlapped() the two lines calculating tx and ty are incorrect.
00085     //  The less-than sign in each line should be a greater-than sign. That is, the two lines should read:
00086     //
00087     //  float tx = ((x1 > x2) ? (x1 - minx) : (maxx - x1)) / Abs(x2 - x1);
00088     //  float ty = ((y1 > y2) ? (y1 - miny) : (maxy - y1)) / Abs(y2 - y1);
00089     //
00090     //  Thanks to Jetro Lauha of Fathammer in Helsinki, Finland for reporting this error.
00091     //
00092     //  Jetro also points out that the computations of i, j, iend, and jend are incorrectly rounded if the line
00093     //  coordinates are allowed to go negative. While that was not really the intent of the code — that is, I
00094     //  assumed grids to be numbered from (0, 0) to (m, n) — I'm at fault for not making my assumption clear.
00095     //  Where it is important to handle negative line coordinates the computation of these variables should be
00096     //  changed to something like this:
00097     //
00098     //  // Determine start grid cell coordinates (i, j)
00099     //  int i = (int)floorf(x1 / CELL_SIDE);
00100     //  int j = (int)floorf(y1 / CELL_SIDE);
00101     //
00102     //  // Determine end grid cell coordinates (iend, jend)
00103     //  int iend = (int)floorf(x2 / CELL_SIDE);
00104     //  int jend = (int)floorf(y2 / CELL_SIDE);
00105     //
00106     //  page 328. The if-statement that reads "if (ty <= tx && ty <= tz)" has a superfluous condition.
00107     //  It should simply read "if (ty <= tz)".
00108     //
00109     //  This error was reported by Joey Hammer (PixelActive). 
00110     template< template<typename> class VolumeType, typename VoxelType>
00111     void Raycast<VolumeType, VoxelType>::doRaycast(float x1, float y1, float z1, float x2, float y2, float z2)
00112     {
00113         int i = (int)floorf(x1);
00114         int j = (int)floorf(y1);
00115         int k = (int)floorf(z1);
00116 
00117         int iend = (int)floorf(x2);
00118         int jend = (int)floorf(y2);
00119         int kend = (int)floorf(z2);
00120 
00121         int di = ((x1 < x2) ? 1 : ((x1 > x2) ? -1 : 0));
00122         int dj = ((y1 < y2) ? 1 : ((y1 > y2) ? -1 : 0));
00123         int dk = ((z1 < z2) ? 1 : ((z1 > z2) ? -1 : 0));
00124 
00125         float minx = floorf(x1), maxx = minx + 1.0f;
00126         float tx = ((x1 > x2) ? (x1 - minx) : (maxx - x1)) / abs(x2 - x1);
00127         float miny = floorf(y1), maxy = miny + 1.0f;
00128         float ty = ((y1 > y2) ? (y1 - miny) : (maxy - y1)) / abs(y2 - y1);
00129         float minz = floorf(z1), maxz = minz + 1.0f;
00130         float tz = ((z1 > z2) ? (z1 - minz) : (maxz - z1)) / abs(z2 - z1);
00131 
00132         float deltatx = 1.0f / abs(x2 - x1);
00133         float deltaty = 1.0f / abs(y2 - y1);
00134         float deltatz = 1.0f / abs(z2 - z1);
00135 
00136         m_sampVolume.setPosition(i,j,k);
00137         m_result.previousVoxel = Vector3DInt32(i,j,k);
00138 
00139         for(;;)
00140         {
00141             if(m_sampVolume.getVoxel().getDensity() > VoxelType::getThreshold())
00142             {
00143                 m_result.foundIntersection = true;
00144                 m_result.intersectionVoxel = Vector3DInt32(i,j,k);
00145                 return;
00146             }
00147             m_result.previousVoxel = Vector3DInt32(i,j,k);
00148 
00149             if(tx <= ty && tx <= tz)
00150             {
00151                 if(i == iend) break;
00152                 tx += deltatx;
00153                 i += di;
00154 
00155                 if(di == 1) m_sampVolume.movePositiveX();
00156                 if(di == -1) m_sampVolume.moveNegativeX();
00157             } else if (ty <= tz)
00158             {
00159                 if(j == jend) break;
00160                 ty += deltaty;
00161                 j += dj;
00162 
00163                 if(dj == 1) m_sampVolume.movePositiveY();
00164                 if(dj == -1) m_sampVolume.moveNegativeY();
00165             } else 
00166             {
00167                 if(k == kend) break;
00168                 tz += deltatz;
00169                 k += dk;
00170 
00171                 if(dk == 1) m_sampVolume.movePositiveZ();
00172                 if(dk == -1) m_sampVolume.moveNegativeZ();
00173             }
00174         }
00175 
00176         //Didn't hit anything
00177         m_result.foundIntersection = false;
00178         m_result.intersectionVoxel = Vector3DInt32(0,0,0);
00179         m_result.previousVoxel = Vector3DInt32(0,0,0);
00180     }
00181 }

Generated on Sat Nov 19 2011 00:27:30 for PolyVox by  doxygen 1.7.1