diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index 660aa8c8..6e178ca0 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -79,8 +79,6 @@ SET(CORE_INC_FILES include/PolyVoxCore/RawVolumeSampler.inl include/PolyVoxCore/Raycast.h include/PolyVoxCore/Raycast.inl - include/PolyVoxCore/RaycastWithCallback.h - include/PolyVoxCore/RaycastWithCallback.inl include/PolyVoxCore/Region.h include/PolyVoxCore/SimpleInterface.h include/PolyVoxCore/SimpleVolume.h diff --git a/library/PolyVoxCore/include/PolyVoxCore/Raycast.h b/library/PolyVoxCore/include/PolyVoxCore/Raycast.h index ddb9c36a..1e95f60b 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Raycast.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Raycast.h @@ -28,23 +28,17 @@ freely, subject to the following restrictions: namespace PolyVox { - /// Stores the result of a raycast operation. - //////////////////////////////////////////////////////////////////////////////// - /// A instance of this structure is passed to a Raycast object, and is filled in - /// as the ray traverses the volume. The 'foundIntersection' field indicates whether - /// the ray hit any solid voxels, and if so the 'intersectionVoxel' field indicates - ///the voxel's position - //////////////////////////////////////////////////////////////////////////////// - struct RaycastResult + namespace MyRaycastResults { - ///Indicates whether an intersection was found - bool foundIntersection; - ///If an intersection was found then this field holds the intersecting voxel, otherwise it is undefined. - Vector3DInt32 intersectionVoxel; - Vector3DInt32 previousVoxel; - }; + enum MyRaycastResult + { + Completed, + Interupted + }; + } + typedef MyRaycastResults::MyRaycastResult MyRaycastResult; - /// The Raycast class can be used to find the fist filled voxel along a given path. + /// OUT OF DATE SINCE UNCLASSING //////////////////////////////////////////////////////////////////////////////// /// The principle behind raycasting is to fire a 'ray' through the volume and determine /// what (if anything) that ray hits. This simple test can be used for the purpose of @@ -91,133 +85,12 @@ namespace PolyVox /// surace extractors. It's behaviour with the Marching Cubes surface extractor has not /// been tested yet. //////////////////////////////////////////////////////////////////////////////// - template - class Raycast - { - public: - ///Constructor - Raycast(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, RaycastResult& result, polyvox_function funcIsPassable); - - ///Sets the start position for the ray. - void setStart(const Vector3DFloat& v3dStart); - ///Set the direction for the ray. - void setDirection(const Vector3DFloat& v3dDirectionAndLength); - - ///Performs the raycast. - void execute(); - - private: - RaycastResult& m_result; - - polyvox_function m_funcIsPassable; - - void doRaycast(float x1, float y1, float z1, float x2, float y2, float z2); - - VolumeType* m_volData; - typename VolumeType::Sampler m_sampVolume; - - Vector3DFloat m_v3dStart; - Vector3DFloat m_v3dDirectionAndLength; - float m_fMaxDistance; - }; - - namespace MyRaycastResults - { - enum MyRaycastResult - { - Completed, - Interupted - }; - } - typedef MyRaycastResults::MyRaycastResult MyRaycastResult; template - MyRaycastResult raycastWithEndpoints(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dEnd, Callback& callback) - { - VolumeType::Sampler sampler(volData); - - //The doRaycast function is assuming that it is iterating over the areas defined between - //voxels. We actually want to define the areas as being centered on voxels (as this is - //what the CubicSurfaceExtractor generates). We add 0.5 here to adjust for this. - float x1 = v3dStart.getX() + 0.5f; - float y1 = v3dStart.getY() + 0.5f; - float z1 = v3dStart.getZ() + 0.5f; - float x2 = v3dEnd.getX() + 0.5f; - float y2 = v3dEnd.getY() + 0.5f; - float z2 = v3dEnd.getZ() + 0.5f; - - int i = (int)floorf(x1); - int j = (int)floorf(y1); - int k = (int)floorf(z1); - - int iend = (int)floorf(x2); - int jend = (int)floorf(y2); - int kend = (int)floorf(z2); - - int di = ((x1 < x2) ? 1 : ((x1 > x2) ? -1 : 0)); - int dj = ((y1 < y2) ? 1 : ((y1 > y2) ? -1 : 0)); - int dk = ((z1 < z2) ? 1 : ((z1 > z2) ? -1 : 0)); - - float deltatx = 1.0f / std::abs(x2 - x1); - float deltaty = 1.0f / std::abs(y2 - y1); - float deltatz = 1.0f / std::abs(z2 - z1); - - float minx = floorf(x1), maxx = minx + 1.0f; - float tx = ((x1 > x2) ? (x1 - minx) : (maxx - x1)) * deltatx; - float miny = floorf(y1), maxy = miny + 1.0f; - float ty = ((y1 > y2) ? (y1 - miny) : (maxy - y1)) * deltaty; - float minz = floorf(z1), maxz = minz + 1.0f; - float tz = ((z1 > z2) ? (z1 - minz) : (maxz - z1)) * deltatz; - - sampler.setPosition(i,j,k); - //m_result.previousVoxel = Vector3DInt32(i,j,k); - - for(;;) - { - if(!callback(sampler)) - { - //m_result.foundIntersection = true; - //m_result.intersectionVoxel = Vector3DInt32(i,j,k); - return MyRaycastResults::Interupted; - } - //m_result.previousVoxel = Vector3DInt32(i,j,k); - - if(tx <= ty && tx <= tz) - { - if(i == iend) break; - tx += deltatx; - i += di; - - if(di == 1) sampler.movePositiveX(); - if(di == -1) sampler.moveNegativeX(); - } else if (ty <= tz) - { - if(j == jend) break; - ty += deltaty; - j += dj; - - if(dj == 1) sampler.movePositiveY(); - if(dj == -1) sampler.moveNegativeY(); - } else - { - if(k == kend) break; - tz += deltatz; - k += dk; - - if(dk == 1) sampler.movePositiveZ(); - if(dk == -1) sampler.moveNegativeZ(); - } - } - - return MyRaycastResults::Completed; - } + MyRaycastResult raycastWithEndpoints(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dEnd, Callback& callback); template - MyRaycastResult raycastWithDirection(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, Callback& callback) - { - Vector3DFloat v3dEnd = v3dStart + v3dDirectionAndLength; - return raycastWithEndpoints(volData, v3dStart, v3dEnd, callback); - } + MyRaycastResult raycastWithDirection(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, Callback& callback); } #include "PolyVoxCore/Raycast.inl" diff --git a/library/PolyVoxCore/include/PolyVoxCore/Raycast.inl b/library/PolyVoxCore/include/PolyVoxCore/Raycast.inl index 77c79ad5..6ad915bc 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Raycast.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Raycast.inl @@ -23,63 +23,6 @@ freely, subject to the following restrictions: namespace PolyVox { - //////////////////////////////////////////////////////////////////////////////// - /// Builds a Raycast object. - /// \param volData A pointer to the volume through which the ray will be cast. - /// \param v3dStart The starting position of the ray. - /// \param v3dDirectionAndLength The direction of the ray. The length of this vector also - /// represents the length of the ray. - /// \param result An instance of RaycastResult in which the result will be stored. - //////////////////////////////////////////////////////////////////////////////// - template - Raycast::Raycast(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, RaycastResult& result, polyvox_function funcIsPassable) - :m_result(result) - ,m_funcIsPassable(funcIsPassable) - ,m_volData(volData) - ,m_sampVolume(volData) - ,m_v3dStart(v3dStart) - ,m_v3dDirectionAndLength(v3dDirectionAndLength) - { - } - - //////////////////////////////////////////////////////////////////////////////// - /// \param v3dStart The starting position of the ray. - //////////////////////////////////////////////////////////////////////////////// - template - void Raycast::setStart(const Vector3DFloat& v3dStart) - { - m_v3dStart = v3dStart; - } - - //////////////////////////////////////////////////////////////////////////////// - /// \param v3dDirectionAndLength The direction of the ray. The length of this vector also - /// represents the length of the ray. - //////////////////////////////////////////////////////////////////////////////// - template - void Raycast::setDirection(const Vector3DFloat& v3dDirectionAndLength) - { - //FIXME: We should add a warning when the ray direction is of length one, as this seems to be a common mistake. - m_v3dDirectionAndLength = v3dDirectionAndLength; - } - - //////////////////////////////////////////////////////////////////////////////// - /// The result is stored in the RaycastResult instance which was passed to the constructor. - //////////////////////////////////////////////////////////////////////////////// - template - void Raycast::execute(void) - { - //The doRaycast function is assuming that it is iterating over the areas defined between - //voxels. We actually want to define the areas as being centered on voxels (as this is - //what the CubicSurfaceExtractor generates). We add (0.5,0.5,0.5) here to adjust for this. - Vector3DFloat v3dStart = m_v3dStart + Vector3DFloat(0.5f, 0.5f, 0.5f); - - //Compute the end point - Vector3DFloat v3dEnd = v3dStart + m_v3dDirectionAndLength; - - //Do the raycast - doRaycast(v3dStart.getX(), v3dStart.getY(), v3dStart.getZ(), v3dEnd.getX(), v3dEnd.getY(), v3dEnd.getZ()); - } - // This function is based on Christer Ericson's code and description of the 'Uniform Grid Intersection Test' in // 'Real Time Collision Detection'. The following information from the errata on the book website is also relevent: // @@ -108,10 +51,22 @@ namespace PolyVox // page 328. The if-statement that reads "if (ty <= tx && ty <= tz)" has a superfluous condition. // It should simply read "if (ty <= tz)". // - // This error was reported by Joey Hammer (PixelActive). - template - void Raycast::doRaycast(float x1, float y1, float z1, float x2, float y2, float z2) + // This error was reported by Joey Hammer (PixelActive). + template + MyRaycastResult raycastWithEndpoints(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dEnd, Callback& callback) { + VolumeType::Sampler sampler(volData); + + //The doRaycast function is assuming that it is iterating over the areas defined between + //voxels. We actually want to define the areas as being centered on voxels (as this is + //what the CubicSurfaceExtractor generates). We add 0.5 here to adjust for this. + float x1 = v3dStart.getX() + 0.5f; + float y1 = v3dStart.getY() + 0.5f; + float z1 = v3dStart.getZ() + 0.5f; + float x2 = v3dEnd.getX() + 0.5f; + float y2 = v3dEnd.getY() + 0.5f; + float z2 = v3dEnd.getZ() + 0.5f; + int i = (int)floorf(x1); int j = (int)floorf(y1); int k = (int)floorf(z1); @@ -135,18 +90,14 @@ namespace PolyVox float minz = floorf(z1), maxz = minz + 1.0f; float tz = ((z1 > z2) ? (z1 - minz) : (maxz - z1)) * deltatz; - m_sampVolume.setPosition(i,j,k); - m_result.previousVoxel = Vector3DInt32(i,j,k); + sampler.setPosition(i,j,k); for(;;) { - if(!m_funcIsPassable(m_sampVolume)) + if(!callback(sampler)) { - m_result.foundIntersection = true; - m_result.intersectionVoxel = Vector3DInt32(i,j,k); - return; + return MyRaycastResults::Interupted; } - m_result.previousVoxel = Vector3DInt32(i,j,k); if(tx <= ty && tx <= tz) { @@ -154,30 +105,34 @@ namespace PolyVox tx += deltatx; i += di; - if(di == 1) m_sampVolume.movePositiveX(); - if(di == -1) m_sampVolume.moveNegativeX(); + if(di == 1) sampler.movePositiveX(); + if(di == -1) sampler.moveNegativeX(); } else if (ty <= tz) { if(j == jend) break; ty += deltaty; j += dj; - if(dj == 1) m_sampVolume.movePositiveY(); - if(dj == -1) m_sampVolume.moveNegativeY(); + if(dj == 1) sampler.movePositiveY(); + if(dj == -1) sampler.moveNegativeY(); } else { if(k == kend) break; tz += deltatz; k += dk; - if(dk == 1) m_sampVolume.movePositiveZ(); - if(dk == -1) m_sampVolume.moveNegativeZ(); + if(dk == 1) sampler.movePositiveZ(); + if(dk == -1) sampler.moveNegativeZ(); } } - //Didn't hit anything - m_result.foundIntersection = false; - m_result.intersectionVoxel = Vector3DInt32(0,0,0); - m_result.previousVoxel = Vector3DInt32(0,0,0); + return MyRaycastResults::Completed; + } + + template + MyRaycastResult raycastWithDirection(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, Callback& callback) + { + Vector3DFloat v3dEnd = v3dStart + v3dDirectionAndLength; + return raycastWithEndpoints(volData, v3dStart, v3dEnd, callback); } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/RaycastWithCallback.h b/library/PolyVoxCore/include/PolyVoxCore/RaycastWithCallback.h deleted file mode 100644 index 767972df..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/RaycastWithCallback.h +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#ifndef __PolyVox_RaycastWithCallback_H__ -#define __PolyVox_RaycastWithCallback_H__ - -#include "PolyVoxCore/Vector.h" - -namespace PolyVox -{ - template - class RaycastWithCallback - { - public: - ///Constructor - RaycastWithCallback(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, polyvox_function funcCallback); - - ///Sets the start position for the ray. - void setStart(const Vector3DFloat& v3dStart); - ///Set the direction for the ray. - void setDirection(const Vector3DFloat& v3dDirectionAndLength); - - ///Performs the raycast. - void execute(); - - private: - polyvox_function m_funcCallback; - - void doRaycast(float x1, float y1, float z1, float x2, float y2, float z2); - - VolumeType* m_volData; - typename VolumeType::Sampler m_sampVolume; - - Vector3DFloat m_v3dStart; - Vector3DFloat m_v3dDirectionAndLength; - float m_fMaxDistance; - }; -} - -#include "PolyVoxCore/RaycastWithCallback.inl" - -#endif //__PolyVox_RaycastWithCallback_H__ \ No newline at end of file diff --git a/library/PolyVoxCore/include/PolyVoxCore/RaycastWithCallback.inl b/library/PolyVoxCore/include/PolyVoxCore/RaycastWithCallback.inl deleted file mode 100644 index a8fc8def..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/RaycastWithCallback.inl +++ /dev/null @@ -1,155 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -namespace PolyVox -{ - template - RaycastWithCallback::RaycastWithCallback(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, polyvox_function funcCallback) - :m_volData(volData) - ,m_sampVolume(volData) - ,m_v3dStart(v3dStart) - ,m_v3dDirectionAndLength(v3dDirectionAndLength) - ,m_funcCallback(funcCallback) - { - //Check the user provided a callback, because it - //is used to determine when to finish the raycast. - assert(m_funcCallback); - } - - template - void RaycastWithCallback::setStart(const Vector3DFloat& v3dStart) - { - m_v3dStart = v3dStart; - } - - template - void RaycastWithCallback::setDirection(const Vector3DFloat& v3dDirectionAndLength) - { - m_v3dDirectionAndLength = v3dDirectionAndLength; - } - - template - void RaycastWithCallback::execute(void) - { - //The doRaycast function is assuming that it is iterating over the areas defined between - //voxels. We actually want to define the areas as being centered on voxels (as this is - //what the CubicSurfaceExtractor generates). We add (0.5,0.5,0.5) here to adjust for this. - Vector3DFloat v3dStart = m_v3dStart + Vector3DFloat(0.5f, 0.5f, 0.5f); - - //Compute the end point - Vector3DFloat v3dEnd = v3dStart + m_v3dDirectionAndLength; - - //Do the raycast - doRaycast(v3dStart.getX(), v3dStart.getY(), v3dStart.getZ(), v3dEnd.getX(), v3dEnd.getY(), v3dEnd.getZ()); - } - - // This function is based on Christer Ericson's code and description of the 'Uniform Grid Intersection Test' in - // 'Real Time Collision Detection'. The following information from the errata on the book website is also relevent: - // - // pages 326-327. In the function VisitCellsOverlapped() the two lines calculating tx and ty are incorrect. - // The less-than sign in each line should be a greater-than sign. That is, the two lines should read: - // - // float tx = ((x1 > x2) ? (x1 - minx) : (maxx - x1)) / Abs(x2 - x1); - // float ty = ((y1 > y2) ? (y1 - miny) : (maxy - y1)) / Abs(y2 - y1); - // - // Thanks to Jetro Lauha of Fathammer in Helsinki, Finland for reporting this error. - // - // Jetro also points out that the computations of i, j, iend, and jend are incorrectly rounded if the line - // coordinates are allowed to go negative. While that was not really the intent of the code — that is, I - // assumed grids to be numbered from (0, 0) to (m, n) — I'm at fault for not making my assumption clear. - // Where it is important to handle negative line coordinates the computation of these variables should be - // changed to something like this: - // - // // Determine start grid cell coordinates (i, j) - // int i = (int)floorf(x1 / CELL_SIDE); - // int j = (int)floorf(y1 / CELL_SIDE); - // - // // Determine end grid cell coordinates (iend, jend) - // int iend = (int)floorf(x2 / CELL_SIDE); - // int jend = (int)floorf(y2 / CELL_SIDE); - // - // page 328. The if-statement that reads "if (ty <= tx && ty <= tz)" has a superfluous condition. - // It should simply read "if (ty <= tz)". - // - // This error was reported by Joey Hammer (PixelActive). - template - void RaycastWithCallback::doRaycast(float x1, float y1, float z1, float x2, float y2, float z2) - { - int i = (int)floorf(x1); - int j = (int)floorf(y1); - int k = (int)floorf(z1); - - int iend = (int)floorf(x2); - int jend = (int)floorf(y2); - int kend = (int)floorf(z2); - - int di = ((x1 < x2) ? 1 : ((x1 > x2) ? -1 : 0)); - int dj = ((y1 < y2) ? 1 : ((y1 > y2) ? -1 : 0)); - int dk = ((z1 < z2) ? 1 : ((z1 > z2) ? -1 : 0)); - - float deltatx = 1.0f / std::abs(x2 - x1); - float deltaty = 1.0f / std::abs(y2 - y1); - float deltatz = 1.0f / std::abs(z2 - z1); - - float minx = floorf(x1), maxx = minx + 1.0f; - float tx = ((x1 > x2) ? (x1 - minx) : (maxx - x1)) * deltatx; - float miny = floorf(y1), maxy = miny + 1.0f; - float ty = ((y1 > y2) ? (y1 - miny) : (maxy - y1)) * deltaty; - float minz = floorf(z1), maxz = minz + 1.0f; - float tz = ((z1 > z2) ? (z1 - minz) : (maxz - z1)) * deltatz; - - m_sampVolume.setPosition(i,j,k); - - for(;;) - { - //Call the callback. If it returns false then finish the loop. - if(!m_funcCallback(Vector3DInt32(i,j,k))) - { - break; - } - - if(tx <= ty && tx <= tz) - { - tx += deltatx; - i += di; - - if(di == 1) m_sampVolume.movePositiveX(); - if(di == -1) m_sampVolume.moveNegativeX(); - } else if (ty <= tz) - { - ty += deltaty; - j += dj; - - if(dj == 1) m_sampVolume.movePositiveY(); - if(dj == -1) m_sampVolume.moveNegativeY(); - } else - { - tz += deltatz; - k += dk; - - if(dk == 1) m_sampVolume.movePositiveZ(); - if(dk == -1) m_sampVolume.moveNegativeZ(); - } - } - } -} \ No newline at end of file