From 7af38d83a33c9171aad0adaf5b917e41323cc9bd Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 2 Oct 2012 16:52:43 +0200 Subject: [PATCH] Added meaningful raycast return values and improved tests. --- CHANGELOG.txt | 5 +- .../PolyVoxCore/include/PolyVoxCore/Raycast.h | 16 ++++- tests/TestRaycast.cpp | 62 +++++++++---------- 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index ba4954eb..027e419c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -29,4 +29,7 @@ Changes to Raycast It's been unclassed (makes sense, removes template parameters). Switch from std::function to STL approach. Note functor is passed by reference rather than by value. -Remove 0.5 offset? \ No newline at end of file +Remove 0.5 offset? +Resolved endpoints vs direction confusion +Prevent short directions +Prevent infinite loops (by preventing long directions? \ No newline at end of file diff --git a/library/PolyVoxCore/include/PolyVoxCore/Raycast.h b/library/PolyVoxCore/include/PolyVoxCore/Raycast.h index 4d77658e..e645dcbf 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Raycast.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Raycast.h @@ -121,8 +121,18 @@ namespace PolyVox float m_fMaxDistance; }; + namespace MyRaycastResults + { + enum MyRaycastResult + { + Completed, + Interupted + }; + } + typedef MyRaycastResults::MyRaycastResult MyRaycastResult; + template - void raycast(VolumeType* volData, /*const*/ Vector3DFloat/*&*/ v3dStart, const Vector3DFloat& v3dDirectionAndLength, Callback& callback) + MyRaycastResult raycast(VolumeType* volData, /*const*/ Vector3DFloat/*&*/ v3dStart, const Vector3DFloat& v3dDirectionAndLength, Callback& callback) { VolumeType::Sampler sampler(volData); @@ -173,7 +183,7 @@ namespace PolyVox { //m_result.foundIntersection = true; //m_result.intersectionVoxel = Vector3DInt32(i,j,k); - return; + return MyRaycastResults::Interupted; } //m_result.previousVoxel = Vector3DInt32(i,j,k); @@ -203,6 +213,8 @@ namespace PolyVox if(dk == -1) sampler.moveNegativeZ(); } } + + return MyRaycastResults::Completed; } } diff --git a/tests/TestRaycast.cpp b/tests/TestRaycast.cpp index 0e49e79a..ca79af7e 100644 --- a/tests/TestRaycast.cpp +++ b/tests/TestRaycast.cpp @@ -33,31 +33,27 @@ freely, subject to the following restrictions: using namespace PolyVox; -bool foundIntersection; - -bool isPassableByRay(const SimpleVolume::Sampler& sampler) -{ - if(sampler.getVoxel() > 0) - { - foundIntersection = true; - } - return sampler.getVoxel() <= 0; -} - // This is the callback functor which is called by the raycast() function for every voxel it touches. // It's primary purpose is to tell the raycast whether or not to continue (i.e. it tests whether the -// ray has hit a solid voxel). Because the instance of this class is passed to the raycast() function by reference we can also use it to encapsulate some state. +// ray has hit a solid voxel). Because the instance of this class is passed to the raycast() function +// by reference we can also use it to encapsulate some state. We're testing this by counting the total +// number of voxels touched. class MyFunctor { public: + MyFunctor() + :m_uTotalVoxelsTouched(0) + { + } + bool operator()(const SimpleVolume::Sampler& sampler) { - if(sampler.getVoxel() > 0) - { - foundIntersection = true; - } + m_uTotalVoxelsTouched++; + return sampler.getVoxel() <= 0; } + + uint32_t m_uTotalVoxelsTouched; }; void TestRaycast::testExecute() @@ -84,36 +80,34 @@ void TestRaycast::testExecute() } } - QTime timer; - timer.start(); - //Cast rays from the centre. Roughly 2/3 should escape. Vector3DFloat start (uVolumeSideLength / 2, uVolumeSideLength / 2, uVolumeSideLength / 2); + + // For demonstration purposes we are using the same function object for all raycasts. + // Therefore, the state it maintains (total voxels touched) is accumulated over all raycsts. + MyFunctor myFunctor; + + // We could have counted the total number of hits in the same way as the total number of voxels + // touched, but for demonstration and testing purposes we are making use of the raycast return value + // and counting them seperatly in this variable. int hits = 0; + + // Cast a large number of random rays for(int ct = 0; ct < 1000000; ct++) { - /*RaycastResult result; - Raycast< SimpleVolume > raycast(&volData, start, randomUnitVectors[ct % 1024] * 1000.0f, result, isPassableByRay); - raycast.execute(); - if(result.foundIntersection) - { - hits++; - }*/ + MyRaycastResult result = raycast(&volData, start, randomUnitVectors[ct % 1024] * 1000.0f, myFunctor); - foundIntersection = false; - MyFunctor myFunctor; - raycast(&volData, start, randomUnitVectors[ct % 1024] * 1000.0f, myFunctor); - - if(foundIntersection) + if(result == MyRaycastResults::Interupted) { hits++; } } - std::cout << "Finished in " << timer.elapsed() << "ms" << std::endl; - - //Check the number of hits. + // Check the number of hits. QCOMPARE(hits, 687494); + + // Check the total number of voxels touched + QCOMPARE(myFunctor.m_uTotalVoxelsTouched, static_cast(486219343)); } QTEST_MAIN(TestRaycast)