From 81a6b6ff3d7faed43f0bcbe211cdb1385519c731 Mon Sep 17 00:00:00 2001
From: Lukas Werner <lks.werner@fau.de>
Date: Thu, 5 Dec 2013 23:06:52 +0100
Subject: [PATCH] Added basic antialiasing using supersampling

---
 src/pe/raytracing/Raytracer.cpp | 38 ++++++++++++++++---------
 src/pe/raytracing/Raytracer.h   | 13 +++++----
 tests/pe/Raytracing.cpp         | 50 ++++++++++++++++-----------------
 3 files changed, 58 insertions(+), 43 deletions(-)

diff --git a/src/pe/raytracing/Raytracer.cpp b/src/pe/raytracing/Raytracer.cpp
index ac75c6f93..0664440ec 100644
--- a/src/pe/raytracing/Raytracer.cpp
+++ b/src/pe/raytracing/Raytracer.cpp
@@ -75,7 +75,7 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, const BlockDataID st
                      const shared_ptr<BodyStorage> globalBodyStorage,
                      const BlockDataID ccdID,
                      uint16_t pixelsHorizontal, uint16_t pixelsVertical,
-                     real_t fov_vertical,
+                     real_t fov_vertical, uint8_t antiAliasFactor,
                      const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
                      const Lighting& lighting,
                      const Color& backgroundColor,
@@ -83,7 +83,7 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, const BlockDataID st
                      std::function<ShadingParameters (const BodyID)> bodyToShadingParamsFunction)
    : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage), ccdID_(ccdID),
    pixelsHorizontal_(pixelsHorizontal), pixelsVertical_(pixelsVertical),
-   fov_vertical_(fov_vertical),
+   fov_vertical_(fov_vertical), antiAliasFactor_(antiAliasFactor),
    cameraPosition_(cameraPosition), lookAtPoint_(lookAtPoint), upVector_(upVector),
    lighting_(lighting),
    backgroundColor_(backgroundColor),
@@ -109,12 +109,13 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, const BlockDataID st
  * \param storageID Storage ID of the block data storage the raytracer operates on.
  * \param config Config block for the raytracer.
  *
- * 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. Optional is blockAABBIntersectionPadding (real) and backgroundColor (Vec3).
+ * The config block has to contain image_x (int), image_y (int), fov_vertical (real, in degrees) and
+ * antiAliasFactor (uint, between 1 and 4). Additionally a vector of reals for each of cameraPosition, lookAt
+ * and the upVector. Optional is blockAABBIntersectionPadding (real) and backgroundColor (Vec3).
  * To output both process local and global tbuffers after raytracing, set tbuffer_output_directory (string).
  * For image output after raytracing, set image_output_directory (string); for local image output additionally set
- * local_image_output_enabled (bool) to true. outputFilenameTimestepZeroPadding (int) sets zero padding for timesteps of output filenames.
+ * local_image_output_enabled (bool) to true. outputFilenameTimestepZeroPadding (int) sets zero padding
+ * for timesteps of output filenames.
  * For the lighting a config block named Lighting has to be defined, information about its contents is in Lighting.h.
  */
 Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, const BlockDataID storageID,
@@ -131,6 +132,7 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, const BlockDataID st
    pixelsHorizontal_ = config.getParameter<uint16_t>("image_x");
    pixelsVertical_ = config.getParameter<uint16_t>("image_y");
    fov_vertical_ = config.getParameter<real_t>("fov_vertical");
+   antiAliasFactor_ = config.getParameter<uint8_t>("antiAliasFactor", 1);
    
    if (config.isDefined("tbuffer_output_directory")) {
       setTBufferOutputEnabled(true);
@@ -196,8 +198,8 @@ void Raytracer::setupView_() {
    viewingPlaneWidth_ = viewingPlaneHeight_ * aspectRatio_;
    viewingPlaneOrigin_ = lookAtPoint_ - u_*viewingPlaneWidth_/real_t(2.) - v_*viewingPlaneHeight_/real_t(2.);
    
-   pixelWidth_ = viewingPlaneWidth_ / real_c(pixelsHorizontal_);
-   pixelHeight_ = viewingPlaneHeight_ / real_c(pixelsVertical_);
+   pixelWidth_ = viewingPlaneWidth_ / real_c(pixelsHorizontal_*antiAliasFactor_);
+   pixelHeight_ = viewingPlaneHeight_ / real_c(pixelsVertical_*antiAliasFactor_);
 }
 
 /*!\brief Utility function for initializing the attribute filenameRankWidth.
@@ -360,12 +362,22 @@ void Raytracer::writeImageToFile(const std::vector<BodyIntersectionInfo>& inters
    std::vector<u_char> lodeImageBuffer(pixelsHorizontal_*pixelsVertical_*3);
    
    uint32_t l = 0;
+   real_t patchSize = real_c(antiAliasFactor_*antiAliasFactor_);
    for (int y = pixelsVertical_-1; y >= 0; y--) {
-      for (size_t x = 0; x < pixelsHorizontal_; x++) {
-         size_t i = coordinateToArrayIndex(x, uint_c(y));
-         u_char r = (u_char)(255 * intersectionsBuffer[i].r);
-         u_char g = (u_char)(255 * intersectionsBuffer[i].g);
-         u_char b = (u_char)(255 * intersectionsBuffer[i].b);
+      for (uint x = 0; x < pixelsHorizontal_; x++) {
+         real_t r_sum = 0, g_sum = 0, b_sum = 0;
+         for (uint ay = y*antiAliasFactor_; ay < (y+1)*antiAliasFactor_; ay++) {
+            for (uint ax = x*antiAliasFactor_; ax < (x+1)*antiAliasFactor_; ax++) {
+               size_t i = coordinateToArrayIndex(ax, ay);
+               r_sum += intersectionsBuffer[i].r;
+               g_sum += intersectionsBuffer[i].g;
+               b_sum += intersectionsBuffer[i].b;
+            }
+         }
+         u_char r = (u_char)(255 * (r_sum/patchSize));
+         u_char g = (u_char)(255 * (g_sum/patchSize));
+         u_char b = (u_char)(255 * (b_sum/patchSize));
+         
          lodeImageBuffer[l] = r;
          lodeImageBuffer[l+1] = g;
          lodeImageBuffer[l+2] = b;
diff --git a/src/pe/raytracing/Raytracer.h b/src/pe/raytracing/Raytracer.h
index f3ecb4983..3f25bdba9 100644
--- a/src/pe/raytracing/Raytracer.h
+++ b/src/pe/raytracing/Raytracer.h
@@ -71,7 +71,7 @@ public:
                       const shared_ptr<BodyStorage> globalBodyStorage,
                       const BlockDataID ccdID,
                       uint16_t pixelsHorizontal, uint16_t pixelsVertical,
-                      real_t fov_vertical,
+                      real_t fov_vertical, uint8_t antiAliasFactor,
                       const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
                       const Lighting& lighting,
                       const Color& backgroundColor = Color(real_t(0.1), real_t(0.1), real_t(0.1)),
@@ -95,6 +95,8 @@ private:
    uint16_t pixelsHorizontal_;  //!< The horizontal amount of pixels of the generated image.
    uint16_t pixelsVertical_;    //!< The vertical amount of pixels of the generated image.
    real_t fov_vertical_;      //!< The vertical field-of-view of the camera.
+   uint8_t antiAliasFactor_;  /*!< Factor used for oversampling. Should be between 1 (fast, but jagged edges)
+                               * and 4 (16 times slower, very smooth edges).*/
    Vec3 cameraPosition_;      //!< The position of the camera in the global world frame.
    Vec3 lookAtPoint_;         /*!< The point the camera looks at in the global world frame,
                                marks the center of the view plane.*/
@@ -420,7 +422,7 @@ inline bool Raytracer::isPlaneVisible(const PlaneID plane, const Ray& ray) const
  * \return Array index.
  */
 inline size_t Raytracer::coordinateToArrayIndex(size_t x, size_t y) const {
-   return y*pixelsHorizontal_ + x;
+   return y*pixelsHorizontal_*antiAliasFactor_ + x;
 }
 
 /*!\brief Traces a ray in the global body storage and finds the closest ray-body intersection.
@@ -547,7 +549,8 @@ void Raytracer::generateImage(const size_t timestep, WcTimingTree* tt) {
    real_t inf = std::numeric_limits<real_t>::max();
    
    std::vector<BodyIntersectionInfo> intersections;
-   std::vector<BodyIntersectionInfo> intersectionsBuffer(pixelsVertical_ * pixelsHorizontal_); // contains for each pixel information about an intersection, if existent
+   // contains for each pixel information about an intersection:
+   std::vector<BodyIntersectionInfo> intersectionsBuffer(pixelsVertical_*antiAliasFactor_ * pixelsHorizontal_*antiAliasFactor_);
 
    if (raytracingAlgorithm_ == RAYTRACE_HASHGRIDS || raytracingAlgorithm_ == RAYTRACE_COMPARE_BOTH
       || raytracingAlgorithm_ == RAYTRACE_COMPARE_BOTH_STRICTLY) {
@@ -576,8 +579,8 @@ void Raytracer::generateImage(const size_t timestep, WcTimingTree* tt) {
 #endif
    
    if (tt != NULL) tt->start("Intersection Testing");
-   for (size_t x = 0; x < pixelsHorizontal_; x++) {
-      for (size_t y = 0; y < pixelsVertical_; y++) {
+   for (size_t x = 0; x < pixelsHorizontal_*antiAliasFactor_; x++) {
+      for (size_t y = 0; y < pixelsVertical_*antiAliasFactor_; y++) {
          Vec3 pixelLocation = viewingPlaneOrigin_ + u_*(real_c(x)+real_t(0.5))*pixelWidth_ + v_*(real_c(y)+real_t(0.5))*pixelHeight_;
          Vec3 direction = (pixelLocation - cameraPosition_).getNormalized();
          ray.setDirection(direction);
diff --git a/tests/pe/Raytracing.cpp b/tests/pe/Raytracing.cpp
index c12dda18c..5b450b9d1 100644
--- a/tests/pe/Raytracing.cpp
+++ b/tests/pe/Raytracing.cpp
@@ -233,7 +233,7 @@ ShadingParameters customBodyToShadingParams(const BodyID body) {
    }
 }
 
-void RaytracerTest(Raytracer::Algorithm raytracingAlgorithm = Raytracer::RAYTRACE_HASHGRIDS) {
+void RaytracerTest(Raytracer::Algorithm raytracingAlgorithm = Raytracer::RAYTRACE_HASHGRIDS, uint8_t antiAliasFactor = 1) {
    WALBERLA_LOG_INFO("Raytracer");
    shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
    shared_ptr<BlockForest> forest = createBlockForest(AABB(0,0,0,10,10,10), Vector3<uint_t>(1,1,1), Vector3<bool>(false, false, false));
@@ -246,7 +246,7 @@ void RaytracerTest(Raytracer::Algorithm raytracingAlgorithm = Raytracer::RAYTRAC
                      Color(real_t(0.4), real_t(0.4), real_t(0.4))); //ambient
    Raytracer raytracer(forest, storageID, globalBodyStorage, ccdID,
                        size_t(640), size_t(480),
-                       real_t(49.13),
+                       real_t(49.13), antiAliasFactor,
                        Vec3(-5,5,5), Vec3(-1,5,5), Vec3(0,0,1), //-5,5,5; -1,5,5
                        lighting,
                        Color(real_t(0.2), real_t(0.2), real_t(0.2)),
@@ -335,7 +335,7 @@ ShadingParameters customSpheresBodyToShadingParams(const BodyID body) {
    }
 }
 
-void RaytracerSpheresTestScene(Raytracer::Algorithm raytracingAlgorithm = Raytracer::RAYTRACE_HASHGRIDS) {
+void RaytracerSpheresTestScene(Raytracer::Algorithm raytracingAlgorithm = Raytracer::RAYTRACE_HASHGRIDS, uint8_t antiAliasFactor = 1) {
    WALBERLA_LOG_INFO("Raytracer Spheres Scene");
    shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
    shared_ptr<BlockForest> forest = createBlockForest(AABB(0,0,0,10,10,10), Vector3<uint_t>(1,1,1), Vector3<bool>(false, false, false));
@@ -348,7 +348,7 @@ void RaytracerSpheresTestScene(Raytracer::Algorithm raytracingAlgorithm = Raytra
                      Color(real_t(0.4), real_t(0.4), real_t(0.4))); //ambient
    Raytracer raytracer(forest, storageID, globalBodyStorage, ccdID,
                        size_t(640), size_t(480),
-                       real_t(49.13),
+                       real_t(49.13), antiAliasFactor,
                        Vec3(-5,5,5), Vec3(-1,5,5), Vec3(0,0,1), //-5,5,5; -1,5,5
                        lighting,
                        Color(real_t(0.2),real_t(0.2),real_t(0.2)),
@@ -387,7 +387,7 @@ ShadingParameters customHashGridsBodyToShadingParams(const BodyID body) {
 }
 
 
-void HashGridsTest(Raytracer::Algorithm raytracingAlgorithm,
+void HashGridsTest(Raytracer::Algorithm raytracingAlgorithm, uint8_t antiAliasFactor,
                    size_t boxes, size_t capsules, size_t spheres, size_t numberOfViews = 1,
                    real_t boxLenMin = real_t(0.1), real_t boxLenMax = real_t(0.2), bool boxRotation = false,
                    real_t capRadiusMin = real_t(0.1), real_t capRadiusMax = real_t(0.2), real_t capLenMin = real_t(0.1), real_t capLenMax = real_t(0.3),
@@ -529,7 +529,7 @@ void HashGridsTest(Raytracer::Algorithm raytracingAlgorithm,
       
       Raytracer raytracer(forest, storageID, globalBodyStorage, ccdID,
                            size_t(640), size_t(480),
-                           real_t(49.13),
+                           real_t(49.13), antiAliasFactor,
                            std::get<0>(vector),
                            std::get<1>(vector),
                            std::get<2>(vector),
@@ -558,7 +558,7 @@ ShadingParameters customArtifactsBodyToShadingParams(const BodyID body) {
    return defaultShadingParams(body);
 }
 
-void raytraceArtifactsForest(Raytracer::Algorithm raytracingAlgorithm,
+void raytraceArtifactsForest(Raytracer::Algorithm raytracingAlgorithm, uint8_t antiAliasFactor,
                              const shared_ptr<BlockStorage> forest, const BlockDataID storageID,
                              const shared_ptr<BodyStorage> globalBodyStorage,
                              const BlockDataID ccdID,
@@ -573,7 +573,7 @@ void raytraceArtifactsForest(Raytracer::Algorithm raytracingAlgorithm,
    
    Raytracer raytracer(forest, storageID, globalBodyStorage, ccdID,
                        size_t(640), size_t(480),
-                       real_t(49.13),
+                       real_t(49.13), antiAliasFactor,
                        cameraPosition,
                        lookAtPoint,
                        upVector,
@@ -593,7 +593,7 @@ void raytraceArtifactsForest(Raytracer::Algorithm raytracingAlgorithm,
    }
 }
 
-void HashGridsArtifactsTest(Raytracer::Algorithm raytracingAlgorithm,
+void HashGridsArtifactsTest(Raytracer::Algorithm raytracingAlgorithm, uint8_t antiAliasFactor,
                             size_t boxes, real_t boxLenMin = real_t(0.1), real_t boxLenMax = real_t(0.2)) {
    WALBERLA_LOG_INFO_ON_ROOT("HashGrids Artifacts Test - In negative Z direction");
    
@@ -628,13 +628,13 @@ void HashGridsArtifactsTest(Raytracer::Algorithm raytracingAlgorithm,
       WALBERLA_CHECK(box_ != NULL);
    }
    
-   raytraceArtifactsForest(raytracingAlgorithm,
+   raytraceArtifactsForest(raytracingAlgorithm, antiAliasFactor,
                            forest, storageID, globalBodyStorage, ccdID,
                            Vec3(2, 2, 7), Vec3(2, 2, 4), Vec3(0,1,0),
                            boxes, 3);
 }
 
-void HashGridsFromNegativeArtifactsTest(Raytracer::Algorithm raytracingAlgorithm,
+void HashGridsFromNegativeArtifactsTest(Raytracer::Algorithm raytracingAlgorithm, uint8_t antiAliasFactor,
                                         size_t boxes, real_t boxLenMin = real_t(0.1), real_t boxLenMax = real_t(0.2)) {
    WALBERLA_LOG_INFO_ON_ROOT("HashGrids Artifacts Test - In positive Z direction");
    
@@ -673,13 +673,13 @@ void HashGridsFromNegativeArtifactsTest(Raytracer::Algorithm raytracingAlgorithm
       WALBERLA_CHECK(box_ != NULL);
    }
    
-   raytraceArtifactsForest(raytracingAlgorithm,
+   raytraceArtifactsForest(raytracingAlgorithm, antiAliasFactor,
                            forest, storageID, globalBodyStorage, ccdID,
                            Vec3(2, 2, -3), Vec3(2, 2, 0), Vec3(0,1,0),
                            boxes, 4);
 }
 
-void HashGridsFromNegativeXArtifactsTest(Raytracer::Algorithm raytracingAlgorithm,
+void HashGridsFromNegativeXArtifactsTest(Raytracer::Algorithm raytracingAlgorithm, uint8_t antiAliasFactor,
                                          size_t boxes, real_t boxLenMin = real_t(0.1), real_t boxLenMax = real_t(0.2)) {
    WALBERLA_LOG_INFO_ON_ROOT("HashGrids Artifacts Test - In positive X direction");
    WALBERLA_LOG_INFO_ON_ROOT(" Generating " << boxes << " boxes");
@@ -716,7 +716,7 @@ void HashGridsFromNegativeXArtifactsTest(Raytracer::Algorithm raytracingAlgorith
       WALBERLA_CHECK(box_ != NULL);
    }
    
-   raytraceArtifactsForest(raytracingAlgorithm,
+   raytraceArtifactsForest(raytracingAlgorithm, antiAliasFactor,
                            forest, storageID, globalBodyStorage, ccdID,
                            Vec3(-3, 2, 2), Vec3(0, 2, 2), Vec3(0,0,1),
                            boxes, 6);
@@ -727,7 +727,7 @@ Vec3 minCornerToGpos(const Vec3& minCorner, real_t lengths) {
    return minCorner + Vec3(lengths/2, lengths/2, lengths/2);
 }
 
-void HashGridsTestScene(Raytracer::Algorithm raytracingAlgorithm = Raytracer::RAYTRACE_HASHGRIDS) {
+void HashGridsTestScene(Raytracer::Algorithm raytracingAlgorithm = Raytracer::RAYTRACE_HASHGRIDS, uint8_t antiAliasFactor = 1) {
    WALBERLA_LOG_INFO_ON_ROOT("HashGrids Test Scene");
    
    shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
@@ -813,7 +813,7 @@ void HashGridsTestScene(Raytracer::Algorithm raytracingAlgorithm = Raytracer::RA
    for (auto& vector: viewVectors) {
       Raytracer raytracer(forest, storageID, globalBodyStorage, ccdID,
                           size_t(640), size_t(480),
-                          real_t(49.13),
+                          real_t(49.13), antiAliasFactor,
                           std::get<0>(vector),
                           std::get<1>(vector),
                           std::get<2>(vector),
@@ -851,22 +851,22 @@ int main( int argc, char** argv )
    CapsuleIntersectsTest();
    
    const Raytracer::Algorithm algorithm = Raytracer::RAYTRACE_COMPARE_BOTH_STRICTLY;
-
-   RaytracerTest(algorithm);
-   //RaytracerSpheresTestScene(algorithm);
-   HashGridsTestScene(algorithm);
-   HashGridsTest(algorithm,
+   const uint8_t antiAliasFactor = 1;
+   RaytracerTest(algorithm, antiAliasFactor);
+   //RaytracerSpheresTestScene(algorithm, antiAliasFactor);
+   HashGridsTestScene(algorithm, antiAliasFactor);
+   HashGridsTest(algorithm, antiAliasFactor,
                  50, 30, 130,
                  10);
-   HashGridsTest(algorithm,
+   HashGridsTest(algorithm, antiAliasFactor,
                  60, 60, 3,
                  1,
                  real_t(0.1), real_t(0.3), true,
                  real_t(0.1), real_t(0.2), real_t(0.1), real_t(0.2),
                  real_t(0.5), real_t(0.6));
-   HashGridsArtifactsTest(algorithm, 750, real_t(0.2), real_t(0.3));
-   HashGridsFromNegativeArtifactsTest(algorithm, 750, real_t(0.2), real_t(0.3));
-   HashGridsFromNegativeXArtifactsTest(algorithm, 750, real_t(0.2), real_t(0.3));
+   HashGridsArtifactsTest(algorithm, antiAliasFactor, 750, real_t(0.2), real_t(0.3));
+   HashGridsFromNegativeArtifactsTest(algorithm, antiAliasFactor, 750, real_t(0.2), real_t(0.3));
+   HashGridsFromNegativeXArtifactsTest(algorithm, antiAliasFactor, 750, real_t(0.2), real_t(0.3));
    
    return EXIT_SUCCESS;
 }
-- 
GitLab