From 47e8f4a86dc17a6d5908cbda0dac134b486c86c9 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 2 Dec 2012 17:33:59 +0100 Subject: [PATCH] Improved raycast unit test so that it exits early if the ray leaves the volume. --- .../include/PolyVoxCore/BaseVolume.h | 3 +- .../include/PolyVoxCore/BaseVolumeSampler.inl | 14 ++++---- tests/TestRaycast.cpp | 34 +++++++++++++------ 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.h b/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.h index 0622a823..f44fbc7d 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.h @@ -65,6 +65,8 @@ namespace PolyVox Vector3DInt32 getPosition(void) const; inline VoxelType getVoxel(void) const; + bool isCurrentPositionValid(void) const; + void setPosition(const Vector3DInt32& v3dNewPos); void setPosition(int32_t xPos, int32_t yPos, int32_t zPos); inline bool setVoxel(VoxelType tValue); @@ -110,7 +112,6 @@ namespace PolyVox protected: VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; - bool isCurrentPositionValid(void) const; DerivedVolumeType* mVolume; diff --git a/library/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl b/library/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl index b82aff5e..b3004074 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl @@ -60,6 +60,13 @@ namespace PolyVox return mVolume->getVoxelAt(mXPosInVolume, mYPosInVolume, mZPosInVolume); } + template + template + bool inline BaseVolume::Sampler::isCurrentPositionValid(void) const + { + return m_bIsCurrentPositionValidInX && m_bIsCurrentPositionValidInY && m_bIsCurrentPositionValidInZ; + } + template template void BaseVolume::Sampler::setPosition(const Vector3DInt32& v3dNewPos) @@ -374,11 +381,4 @@ namespace PolyVox } } } - - template - template - bool inline BaseVolume::Sampler::isCurrentPositionValid(void) const - { - return m_bIsCurrentPositionValidInX && m_bIsCurrentPositionValidInY && m_bIsCurrentPositionValidInZ; - } } diff --git a/tests/TestRaycast.cpp b/tests/TestRaycast.cpp index 96fb2ce8..364bff04 100644 --- a/tests/TestRaycast.cpp +++ b/tests/TestRaycast.cpp @@ -42,18 +42,30 @@ class RaycastTestFunctor { public: RaycastTestFunctor() - :m_uTotalVoxelsTouched(0) + :m_uVoxelsTouched(0) + ,m_bRayLeftVolume(false) { } bool operator()(const SimpleVolume::Sampler& sampler) { - m_uTotalVoxelsTouched++; + m_uVoxelsTouched++; + // For this particular test we know that we are always starting a ray inside the volume, + // so if it ever leaves the volume we know it can't go back in and so we can terminate early. + // This optimisation is worthwhile because samplers get slow once outside the volume. + if(!sampler.isCurrentPositionValid()) + { + m_bRayLeftVolume = true; + return false; + } + + // We are in the volume, so decide whether to continue based on the voxel value. return sampler.getVoxel() <= 0; } - uint32_t m_uTotalVoxelsTouched; + uint32_t m_uVoxelsTouched; + bool m_bRayLeftVolume; }; void TestRaycast::testExecute() @@ -81,23 +93,25 @@ void TestRaycast::testExecute() } //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. - RaycastTestFunctor raycastTestFunctor; + Vector3DFloat start (uVolumeSideLength / 2, uVolumeSideLength / 2, uVolumeSideLength / 2); // 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; + uint32_t uTotalVoxelsTouched = 0; // Cast a large number of random rays for(int ct = 0; ct < 1000000; ct++) { + RaycastTestFunctor raycastTestFunctor; RaycastResult result = raycastWithDirection(&volData, start, randomUnitVectors[ct % 1024] * 1000.0f, raycastTestFunctor); - if(result == RaycastResults::Interupted) + uTotalVoxelsTouched += raycastTestFunctor.m_uVoxelsTouched; + + // If the raycast completed then we know it did not hit anything.If it was interupted then it + // probably hit something, unless we noted that the reason it was interupted was that it left the volume. + if((result == RaycastResults::Interupted) && (raycastTestFunctor.m_bRayLeftVolume == false)) { hits++; } @@ -107,7 +121,7 @@ void TestRaycast::testExecute() QCOMPARE(hits, 687494); // Check the total number of voxels touched - QCOMPARE(raycastTestFunctor.m_uTotalVoxelsTouched, static_cast(486219343)); + QCOMPARE(uTotalVoxelsTouched, static_cast(29783248)); } QTEST_MAIN(TestRaycast)