From 5bf4ed6c996ee03ee9d5fcc425d46dc4acfd5c7b Mon Sep 17 00:00:00 2001
From: Lukas Werner <lks.werner@fau.de>
Date: Wed, 24 Jan 2018 23:33:07 +0100
Subject: [PATCH] Added padding for AABB intersection testing

---
 src/pe/raytracing/Intersects.h  |  9 +++++----
 src/pe/raytracing/Raytracer.cpp | 20 +++++++++++++++-----
 src/pe/raytracing/Raytracer.h   | 16 ++++++++++++----
 tests/pe/Raytracing.cpp         | 27 ++++++++++++++++++++++++---
 4 files changed, 56 insertions(+), 16 deletions(-)

diff --git a/src/pe/raytracing/Intersects.h b/src/pe/raytracing/Intersects.h
index 3b274630e..90d17f29b 100644
--- a/src/pe/raytracing/Intersects.h
+++ b/src/pe/raytracing/Intersects.h
@@ -38,7 +38,7 @@
 namespace walberla {
 namespace pe {
 namespace raytracing {
-inline bool intersects(const AABB& aabb, const Ray& ray, real_t& t);
+inline bool intersects(const AABB& aabb, const Ray& ray, real_t& t, real_t padding = real_t(0.0));
 
 inline bool intersects(const SphereID sphere, const Ray& ray, real_t& t);
 inline bool intersects(const PlaneID plane, const Ray& ray, real_t& t);
@@ -172,11 +172,12 @@ inline bool intersects(const BoxID box, const Ray& ray, real_t& t) {
    return true;
 }
 
-inline bool intersects(const AABB& aabb, const Ray& ray, real_t& t) {
+inline bool intersects(const AABB& aabb, const Ray& ray, real_t& t, real_t padding) {
    // An Efficient and Robust Ray–Box Intersection Algorithm: http://people.csail.mit.edu/amy/papers/box-jgt.pdf
+   const Vec3 paddingVector(padding, padding, padding);
    Vec3 bounds[2] = {
-      aabb.min(),
-      aabb.max()
+      aabb.min() - paddingVector,
+      aabb.max() + paddingVector
    };
    
    const Vector3<int8_t>& sign = ray.getInvDirectionSigns();
diff --git a/src/pe/raytracing/Raytracer.cpp b/src/pe/raytracing/Raytracer.cpp
index 0e56f74cb..0cce4b37c 100644
--- a/src/pe/raytracing/Raytracer.cpp
+++ b/src/pe/raytracing/Raytracer.cpp
@@ -39,15 +39,21 @@ namespace raytracing {
  * \param cameraPosition Position of the camera in the global world frame.
  * \param lookAtPoint Point the camera looks at in the global world frame.
  * \param upVector Vector indicating the upwards direction of the camera.
+ * \param blockAABBIntersectionPadding The padding applied in block AABB intersection pretesting. Usually not required.
+ *                                     Set it to the value of the farthest distance a object might protrude from
+ *                                     its containing block.
  */
-Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, const shared_ptr<BodyStorage> globalBodyStorage,
+Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
+                     const shared_ptr<BodyStorage> globalBodyStorage,
                      size_t pixelsHorizontal, size_t pixelsVertical,
                      real_t fov_vertical,
-                     const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector)
+                     const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
+                     real_t blockAABBIntersectionPadding)
    : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage),
    pixelsHorizontal_(pixelsHorizontal), pixelsVertical_(pixelsVertical),
    fov_vertical_(fov_vertical),
    cameraPosition_(cameraPosition), lookAtPoint_(lookAtPoint), upVector_(upVector),
+   blockAABBIntersectionPadding_(blockAABBIntersectionPadding),
    tBufferOutputEnabled_(false)
 {
    setupView_();
@@ -61,10 +67,12 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
  *
  * The config block has to contain image_x (int), image_y (int), fov_vertical (real, in degrees)
  * and tbuffer_output_directory (string) parameters. Additionally a vector of reals
- * for each of cameraPosition, lookAt and the upVector.
+ * for each of cameraPosition, lookAt and the upVector. Optional is blockAABBIntersectionPadding (real).
  */
-Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, const shared_ptr<BodyStorage> globalBodyStorage,
-                     const Config::BlockHandle& config) : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage) {
+Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
+                     const shared_ptr<BodyStorage> globalBodyStorage,
+                     const Config::BlockHandle& config)
+   : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage) {
    WALBERLA_CHECK(config.isValid(), "No valid config passed to raytracer");
    
    pixelsHorizontal_ = config.getParameter<size_t>("image_x");
@@ -80,6 +88,8 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
    cameraPosition_ = config.getParameter<Vec3>("cameraPosition");
    lookAtPoint_ = config.getParameter<Vec3>("lookAt");
    upVector_ = config.getParameter<Vec3>("upVector");
+   
+   blockAABBIntersectionPadding_ = config.getParameter<real_t>("blockAABBIntersectionPadding", real_t(0.0));
 
    setupView_();
 }
diff --git a/src/pe/raytracing/Raytracer.h b/src/pe/raytracing/Raytracer.h
index a0a8580f7..873760d30 100644
--- a/src/pe/raytracing/Raytracer.h
+++ b/src/pe/raytracing/Raytracer.h
@@ -66,11 +66,14 @@ class Raytracer {
 public:
    /*!\name Constructors */
    //@{
-   explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, const shared_ptr<BodyStorage> globalBodyStorage,
+   explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
+                      const shared_ptr<BodyStorage> globalBodyStorage,
                       size_t pixelsHorizontal, size_t pixelsVertical,
                       real_t fov_vertical,
-                      const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector);
-   explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID, const shared_ptr<BodyStorage> globalBodyStorage,
+                      const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
+                     real_t blockAABBIntersectionPadding = real_t(0.0));
+   explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
+                      const shared_ptr<BodyStorage> globalBodyStorage,
                       const Config::BlockHandle& config);
    //@}
 
@@ -89,10 +92,15 @@ private:
    Vec3 lookAtPoint_;         /*!< The point the camera looks at in the global world frame,
                                marks the center of the view plane.*/
    Vec3 upVector_;            //!< The vector indicating the upwards direction of the camera.
+   real_t blockAABBIntersectionPadding_; /*!< The padding applied in block AABB intersection pretesting, as
+                                          some objects within a block might protrude from the block's AABB.*/
+   
    bool tBufferOutputEnabled_; //!< Enable / disable dumping the tbuffer to a file
    std::string tBufferOutputDirectory_; //!< Path to the tbuffer output directory
+   
    std::set<walberla::id_t> invisibleBodyIDs_;  //!< The set for invisible body IDs.
    // std::set is used here because for a small number of elements it is often faster than std::unordered_set
+   
    //@}
    
    Vec3 n; // normal vector of viewing plane
@@ -283,7 +291,7 @@ void Raytracer::rayTrace(const size_t timestep) const {
          for (auto blockIt = forest_->begin(); blockIt != forest_->end(); ++blockIt) {
 #ifndef DISABLE_BLOCK_AABB_INTERSECTION_PRECHECK
             const AABB& blockAabb = blockIt->getAABB();
-            if (!intersects(blockAabb, ray, t)) {
+            if (!intersects(blockAabb, ray, t, blockAABBIntersectionPadding_)) {
                continue;
             }
 #endif
diff --git a/tests/pe/Raytracing.cpp b/tests/pe/Raytracing.cpp
index 43ca24d2b..17f738282 100644
--- a/tests/pe/Raytracing.cpp
+++ b/tests/pe/Raytracing.cpp
@@ -114,6 +114,26 @@ void BoxIntersectsTest() {
    WALBERLA_CHECK_FLOAT_EQUAL_EPSILON(t, real_t(2.67157), real_t(1e-4));
 }
 
+void AABBIntersectsTest() {
+   WALBERLA_LOG_INFO("RAY -> AABB");
+
+   Ray ray1(Vec3(-5,5,5), Vec3(1,0,0));
+   real_t t;
+   
+   AABB aabb(0,0,0,
+             10,10,10);
+   
+   WALBERLA_CHECK(intersects(aabb, ray1, t));
+   WALBERLA_CHECK_FLOAT_EQUAL(t, real_t(5));
+   
+   WALBERLA_CHECK(intersects(aabb, ray1, t, 1.0));
+   WALBERLA_CHECK_FLOAT_EQUAL(t, real_t(4));
+   
+   Ray ray2(Vec3(-5,5,10.5), Vec3(1,0,0)); // ray shooting over aabb, but within padding passed to intersects
+   WALBERLA_CHECK(intersects(aabb, ray1, t, 1.0));
+   WALBERLA_CHECK_FLOAT_EQUAL(t, real_t(4));
+}
+
 void RaytracerTest() {
    WALBERLA_LOG_INFO("Raytracer");
    shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
@@ -171,9 +191,10 @@ int main( int argc, char** argv )
    
    SetBodyTypeIDs<BodyTuple>::execute();
    
-   //SphereIntersectsTest();
-   //PlaneIntersectsTest();
-   //BoxIntersectsTest();
+   SphereIntersectsTest();
+   PlaneIntersectsTest();
+   BoxIntersectsTest();
+   AABBIntersectsTest();
    RaytracerTest();
    
    return EXIT_SUCCESS;
-- 
GitLab