From 270b932d213fa076c723bd1c7c4f5b438e369dc2 Mon Sep 17 00:00:00 2001
From: Lukas Werner <lks.werner@fau.de>
Date: Sat, 3 Feb 2018 12:32:10 +0100
Subject: [PATCH] Added Color class

---
 src/pe/raytracing/Color.h       | 78 +++++++++++++++++++++++++++++++++
 src/pe/raytracing/Lighting.h    | 15 ++++---
 src/pe/raytracing/Raytracer.cpp | 10 ++---
 src/pe/raytracing/Raytracer.h   | 62 ++++++++++----------------
 tests/pe/Raytracing.cpp         |  9 ++--
 5 files changed, 120 insertions(+), 54 deletions(-)
 create mode 100644 src/pe/raytracing/Color.h

diff --git a/src/pe/raytracing/Color.h b/src/pe/raytracing/Color.h
new file mode 100644
index 000000000..9bf6cfee7
--- /dev/null
+++ b/src/pe/raytracing/Color.h
@@ -0,0 +1,78 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla is free software: you can
+//  redistribute it and/or modify it under the terms of the GNU General Public
+//  License as published by the Free Software Foundation, either version 3 of
+//  the License, or (at your option) any later version.
+//
+//  waLBerla is distributed in the hope that it will be useful, but WITHOUT
+//  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+//  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+//  for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \author Lukas Werner
+//
+//======================================================================================================================
+
+#pragma once
+
+#include "core/math/Vector3.h"
+
+namespace walberla {
+namespace pe {
+namespace raytracing {
+class Color: public Vector3<real_t> {
+public:
+   /*!\name Constructors */
+   //@{
+   /*!\brief Instantiation constructor for the Color class. Defaults to white.
+    */
+   Color () : Color(1, 1, 1) {
+
+   }
+   
+   /*!\brief Instantiation constructor for the Color class.
+   * \param r Red component
+   * \param g Green component
+   * \param b Blue component
+   * Instantiation constructor for the Color class with RGB components. Each value should be between 0 and 1 (soft limits)
+   */
+   Color (real_t r, real_t g, real_t b) : Vector3<real_t>(r, g, b) {
+      
+   }
+   //@}
+   
+   /*!\brief Instantiation constructor for the Color class.
+    * \param r Red component
+    * \param g Green component
+    * \param b Blue component
+    * Instantiation constructor for the Color class with RGB components. Each value should be between 0 and 1 (soft limits)
+    */
+   Color (const Vec3& vector) : Color(vector[0], vector[1], vector[2]) {
+      
+   }
+   //@}
+   
+   /*!\brief Multiply this color with another component wise.
+    * \return Color with components of this and other multiplied.
+    */
+   inline Color mulComponentWise(const Color& other) const {
+      return Color((*this)[0]*other[0],
+                   (*this)[1]*other[1],
+                   (*this)[2]*other[2]);
+   }
+   
+   /*!\brief Clamps this colors component values between 0 and 1.
+    */
+   inline void clamp() {
+      (*this)[0] = std::min(std::max((*this)[0], real_t(0)), real_t(1));
+      (*this)[1] = std::min(std::max((*this)[1], real_t(0)), real_t(1));
+      (*this)[2] = std::min(std::max((*this)[2], real_t(0)), real_t(1));
+   }
+};
+}
+}
+}
diff --git a/src/pe/raytracing/Lighting.h b/src/pe/raytracing/Lighting.h
index e4a045659..29ff1e3b3 100644
--- a/src/pe/raytracing/Lighting.h
+++ b/src/pe/raytracing/Lighting.h
@@ -23,15 +23,16 @@
 #include <pe/basic.h>
 #include <pe/Types.h>
 #include <core/math/Vector3.h>
+#include <pe/raytracing/Color.h>
 
 namespace walberla {
 namespace pe {
 namespace raytracing {
 struct Lighting {
    Vec3 pointLightOrigin;
-   Vec3 diffuseColor;
-   Vec3 specularColor;
-   Vec3 ambientColor;
+   Color diffuseColor;
+   Color specularColor;
+   Color ambientColor;
    
    /*!\brief Instantiation constructor for the Lighting struct.
     */
@@ -46,7 +47,7 @@ struct Lighting {
     * \param ambientColor Color of the ambient light.
     */
    Lighting (const Vec3& _pointLightOrigin,
-             const Vec3& _diffuseColor, const Vec3& _specularColor, const Vec3& _ambientColor)
+             const Color& _diffuseColor, const Color& _specularColor, const Color& _ambientColor)
    : pointLightOrigin(_pointLightOrigin),
    diffuseColor(_diffuseColor), specularColor(_specularColor), ambientColor(_ambientColor) {
       
@@ -63,9 +64,9 @@ struct Lighting {
       WALBERLA_CHECK(config.isValid(), "No valid config passed to raytracer lighting.");
 
       pointLightOrigin = config.getParameter<Vec3>("pointLightOrigin");
-      diffuseColor = config.getParameter<Vec3>("diffuseColor", Vec3(1,1,1));
-      specularColor = config.getParameter<Vec3>("specularColor", Vec3(1,1,1));
-      ambientColor = config.getParameter<Vec3>("ambientColor", Vec3(0.5,0.5,0.5));
+      diffuseColor = config.getParameter<Color>("diffuseColor", Color(1,1,1));
+      specularColor = config.getParameter<Color>("specularColor", Color(1,1,1));
+      ambientColor = config.getParameter<Color>("ambientColor", Color(0.5,0.5,0.5));
    }
 };
 }
diff --git a/src/pe/raytracing/Raytracer.cpp b/src/pe/raytracing/Raytracer.cpp
index 7eaed3b7f..785f865c9 100644
--- a/src/pe/raytracing/Raytracer.cpp
+++ b/src/pe/raytracing/Raytracer.cpp
@@ -50,7 +50,7 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
                      real_t fov_vertical,
                      const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
                      const Lighting& lighting,
-                     const Vec3& backgroundColor,
+                     const Color& backgroundColor,
                      real_t blockAABBIntersectionPadding)
    : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage),
    pixelsHorizontal_(pixelsHorizontal), pixelsVertical_(pixelsVertical),
@@ -110,7 +110,7 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
    lookAtPoint_ = config.getParameter<Vec3>("lookAt");
    upVector_ = config.getParameter<Vec3>("upVector");
    lighting_ = Lighting(config.getBlock("Lighting"));
-   backgroundColor_ = config.getParameter<Vec3>("backgroundColor", Vec3(0.1, 0.1, 0.1));
+   backgroundColor_ = config.getParameter<Color>("backgroundColor", Vec3(0.1, 0.1, 0.1));
 
    blockAABBIntersectionPadding_ = config.getParameter<real_t>("blockAABBIntersectionPadding", real_t(0.0));
 
@@ -208,7 +208,7 @@ void Raytracer::writeTBufferToFile(const std::vector<real_t>& tBuffer, const std
  * \param timestep Timestep this image is from.
  * \param isGlobalImage Whether this image is the fully stitched together one.
  */
-void Raytracer::writeImageBufferToFile(const std::vector<Vec3>& imageBuffer, size_t timestep, bool isGlobalImage) const {
+void Raytracer::writeImageBufferToFile(const std::vector<Color>& imageBuffer, size_t timestep, bool isGlobalImage) const {
    WALBERLA_CHECK(timestep < 100000, "Raytracer only supports outputting 99 999 timesteps.");
    mpi::MPIRank rank = mpi::MPIManager::instance()->rank();
    uint8_t padding = (timestep < 10 ? 4 :
@@ -224,7 +224,7 @@ void Raytracer::writeImageBufferToFile(const std::vector<Vec3>& imageBuffer, siz
  * \param imageBuffer Buffer with color vectors.
  * \param fileName Name of the output file.
  */
-void Raytracer::writeImageBufferToFile(const std::vector<Vec3>& imageBuffer, const std::string& fileName) const {
+void Raytracer::writeImageBufferToFile(const std::vector<Color>& imageBuffer, const std::string& fileName) const {
    namespace fs = boost::filesystem;
 
    fs::path dir (getImageOutputDirectory());
@@ -236,7 +236,7 @@ void Raytracer::writeImageBufferToFile(const std::vector<Vec3>& imageBuffer, con
    for (size_t y = pixelsVertical_-1; y > 0; y--) {
       for (size_t x = 0; x < pixelsHorizontal_; x++) {
          size_t i = coordinateToArrayIndex(x, y);
-         const Vec3& color = imageBuffer[i];
+         const Color& color = imageBuffer[i];
          char r = (char)(255 * color[0]);
          char g = (char)(255 * color[1]);
          char b = (char)(255 * color[2]);
diff --git a/src/pe/raytracing/Raytracer.h b/src/pe/raytracing/Raytracer.h
index 6afa38e18..5bb9fa77b 100644
--- a/src/pe/raytracing/Raytracer.h
+++ b/src/pe/raytracing/Raytracer.h
@@ -59,7 +59,7 @@ public:
                       real_t fov_vertical,
                       const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
                       const Lighting& lighting,
-                      const Vec3& backgroundColor = Vec3(0.1, 0.1, 0.1),
+                      const Color& backgroundColor = Color(0.1, 0.1, 0.1),
                       real_t blockAABBIntersectionPadding = real_t(0.0));
    explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
                       const shared_ptr<BodyStorage> globalBodyStorage,
@@ -82,7 +82,7 @@ private:
                                marks the center of the view plane.*/
    Vec3 upVector_;            //!< The vector indicating the upwards direction of the camera.
    Lighting lighting_;        //!< The lighting of the scene.
-   Vec3 backgroundColor_;     //!< Background color of the scene.
+   Color backgroundColor_;     //!< Background color of the scene.
    real_t blockAABBIntersectionPadding_; /*!< The padding applied in block AABB intersection pretesting, as
                                           some objects within a block might protrude from the block's AABB.*/
    
@@ -115,7 +115,7 @@ public:
    inline const Vec3& getCameraPosition() const;
    inline const Vec3& getLookAtPoint() const;
    inline const Vec3& getUpVector() const;
-   inline const Vec3& getBackgroundColor() const;
+   inline const Color& getBackgroundColor() const;
    inline bool getTBufferOutputEnabled() const;
    inline const std::string& getTBufferOutputDirectory() const;
    inline bool getImageOutputEnabled() const;
@@ -125,7 +125,7 @@ public:
 
    /*!\name Set functions */
    //@{
-   inline void setBackgroundColor(const Vec3& color);
+   inline void setBackgroundColor(const Color& color);
    inline void setTBufferOutputEnabled(const bool enabled);
    inline void setTBufferOutputDirectory(const std::string& path);
    inline void setImageOutputEnabled(const bool enabled);
@@ -142,14 +142,13 @@ public:
 private:
    void writeTBufferToFile(const std::vector<real_t>& tBuffer, size_t timestep, bool isGlobalImage = false) const;
    void writeTBufferToFile(const std::vector<real_t>& tBuffer, const std::string& fileName) const;
-   void writeImageBufferToFile(const std::vector<Vec3>& imageBuffer, size_t timestep, bool isGlobalImage = false) const;
-   void writeImageBufferToFile(const std::vector<Vec3>& imageBuffer, const std::string& fileName) const;
+   void writeImageBufferToFile(const std::vector<Color>& imageBuffer, size_t timestep, bool isGlobalImage = false) const;
+   void writeImageBufferToFile(const std::vector<Color>& imageBuffer, const std::string& fileName) const;
    
    inline bool isPlaneVisible(const PlaneID plane, const Ray& ray) const;
    inline size_t coordinateToArrayIndex(size_t x, size_t y) const;
-   inline Vec3 multiplyColors(const Vec3& a, const Vec3& b) const;
    
-   inline Vec3 getColor(const BodyID body, const Ray& ray, real_t t, const Vec3& n) const;
+   inline Color getColor(const BodyID body, const Ray& ray, real_t t, const Vec3& n) const;
    //@}
 };
    
@@ -214,7 +213,7 @@ inline const Vec3& Raytracer::getUpVector() const {
  *
  * Returns the background color of the scene.
  */
-inline const Vec3& Raytracer::getBackgroundColor() const {
+inline const Color& Raytracer::getBackgroundColor() const {
    return backgroundColor_;
 }
 
@@ -262,7 +261,7 @@ inline const std::string& Raytracer::getImageOutputDirectory() const {
  *
  * \param color New background color.
  */
-inline void Raytracer::setBackgroundColor(const Vec3& color) {
+inline void Raytracer::setBackgroundColor(const Color& color) {
    backgroundColor_ = color;
 }
    
@@ -346,7 +345,7 @@ void Raytracer::rayTrace(const size_t timestep) {
    int rank = mpi::MPIManager::instance()->rank();
    
    std::vector<real_t> tBuffer(pixelsVertical_ * pixelsHorizontal_, inf);
-   std::vector<Vec3> imageBuffer(pixelsVertical_ * pixelsHorizontal_);
+   std::vector<Color> imageBuffer(pixelsVertical_ * pixelsHorizontal_);
    std::vector<BodyIntersectionInfo> intersections; // contains for each pixel information about an intersection, if existent
    
    real_t t, t_closest;
@@ -417,7 +416,7 @@ void Raytracer::rayTrace(const size_t timestep) {
          }
          
          if (!realIsIdentical(t_closest, inf) && body_closest != NULL) {
-            Vec3 color = getColor(body_closest, ray, t_closest, n_closest);
+            Color color = getColor(body_closest, ray, t_closest, n_closest);
             imageBuffer[coordinateToArrayIndex(x, y)] = color;
             BodyIntersectionInfo intersectionInfo = {
                x,
@@ -445,7 +444,7 @@ void Raytracer::rayTrace(const size_t timestep) {
    }
    int gatheredIntersectionCount = 0;
    std::vector<real_t> fullTBuffer(pixelsHorizontal_ * pixelsVertical_, inf);
-   std::vector<Vec3> fullImageBuffer(pixelsHorizontal_ * pixelsVertical_, backgroundColor_);
+   std::vector<Color> fullImageBuffer(pixelsHorizontal_ * pixelsVertical_, backgroundColor_);
    mpi::RecvBuffer recvBuffer;
    
    mpi::gathervBuffer(sendBuffer, recvBuffer, 0);
@@ -501,17 +500,6 @@ void Raytracer::rayTrace(const size_t timestep) {
    }
 }
 
-/*!\brief Multiplies same-index components of two vectors.
- *
- * \param a Vector to multiply.
- * \param b Vector to multiply.
- *
- * \return Vec3 with components a[i] * b[i]
- */
-inline Vec3 Raytracer::multiplyColors(const Vec3& a, const Vec3& b) const {
-   return Vec3(a[0]*b[0], a[1]*b[1], a[2]*b[2]);
-}
-
 /*!\brief Computes the color for a certain intersection.
  *
  * \param body Intersected body.
@@ -519,29 +507,29 @@ inline Vec3 Raytracer::multiplyColors(const Vec3& a, const Vec3& b) const {
  * \param t Distance from eye to intersection point.
  * \param n Intersection normal at the intersection point.
  *
- * \return Vector with RGB color components.
+ * \return Computed color.
  */
-inline Vec3 Raytracer::getColor(const BodyID body, const Ray& ray, real_t t, const Vec3& n) const {
+inline Color Raytracer::getColor(const BodyID body, const Ray& ray, real_t t, const Vec3& n) const {
    //----
-   Vec3 diffuseColor(0.6, 0, 0.9);
-   Vec3 specularColor(0.8, 0.8, 0.8);
-   Vec3 ambientColor(0.5, 0, 0.8);
+   Color diffuseColor(0.6, 0, 0.9);
+   Color specularColor(0.8, 0.8, 0.8);
+   Color ambientColor(0.5, 0, 0.8);
    real_t shininess = 100;
 
    if (body->getTypeID() == Plane::getStaticTypeID()) {
-      diffuseColor = Vec3(real_t(0.7), real_t(0.7), real_t(0.7));
+      diffuseColor = Color(real_t(0.7), real_t(0.7), real_t(0.7));
       ambientColor.set(real_t(0.5), real_t(0.5), real_t(0.5));
       specularColor.set(real_t(0), real_t(0), real_t(0));
       shininess = real_t(0);
    }
    if (body->getTypeID() == Sphere::getStaticTypeID()) {
-      diffuseColor = Vec3(real_t(0.98), real_t(0.1), real_t(0.1));
+      diffuseColor = Color(real_t(0.98), real_t(0.1), real_t(0.1));
       ambientColor.set(real_t(0.6), real_t(0.05), real_t(0.05));
       specularColor.set(real_t(1), real_t(1), real_t(1));
       shininess = real_t(30);
    }
    if (body->getTypeID() == Capsule::getStaticTypeID()) {
-      diffuseColor = Vec3(real_t(0.15), real_t(0.44), real_t(0.91));
+      diffuseColor = Color(real_t(0.15), real_t(0.44), real_t(0.91));
       ambientColor.set(real_t(0), real_t(0), real_t(0.3));
       specularColor.set(real_t(1), real_t(1), real_t(1));
       shininess = real_t(20);
@@ -564,15 +552,13 @@ inline Vec3 Raytracer::getColor(const BodyID body, const Ray& ray, real_t t, con
       specular = real_c(pow(specularAngle, shininess));
    }
    
-   Vec3 color = multiplyColors(lighting_.ambientColor, ambientColor)
-      + multiplyColors(lighting_.diffuseColor, diffuseColor)*lambertian
-      + multiplyColors(lighting_.specularColor, specularColor)*specular;
+   Color color = lighting_.ambientColor.mulComponentWise(ambientColor)
+      + lighting_.diffuseColor.mulComponentWise(diffuseColor)*lambertian
+      + lighting_.specularColor.mulComponentWise(specularColor)*specular;
    
    // Capping of color channels to 1.
    // Capping instead of scaling will make specular highlights stronger.
-   color[0] = std::min(real_t(1), color[0]);
-   color[1] = std::min(real_t(1), color[1]);
-   color[2] = std::min(real_t(1), color[2]);
+   color.clamp();
 
    return color;
 }
diff --git a/tests/pe/Raytracing.cpp b/tests/pe/Raytracing.cpp
index ee9d0528d..ba13106b2 100644
--- a/tests/pe/Raytracing.cpp
+++ b/tests/pe/Raytracing.cpp
@@ -19,6 +19,7 @@
 #include <pe/raytracing/Ray.h>
 #include <pe/raytracing/Intersects.h>
 #include <pe/raytracing/Raytracer.h>
+#include <pe/raytracing/Color.h>
 
 using namespace walberla;
 using namespace walberla::pe;
@@ -214,15 +215,15 @@ void RaytracerTest() {
    shared_ptr<BlockForest> forest = createBlockForest(AABB(0,0,0,10,10,10), Vec3(1,1,1), Vec3(false, false, false));
    auto storageID = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
    Lighting lighting(Vec3(0, 5, 8), // 8, 5, 9.5 gut für ebenen, 0,5,8
-                     Vec3(1, 1, 1), //diffuse
-                     Vec3(1, 1, 1), //specular
-                     Vec3(0.4, 0.4, 0.4)); //ambient
+                     Color(1, 1, 1), //diffuse
+                     Color(1, 1, 1), //specular
+                     Color(0.4, 0.4, 0.4)); //ambient
    Raytracer raytracer(forest, storageID, globalBodyStorage,
                        size_t(640), size_t(480),
                        49.13,
                        Vec3(-5,5,5), Vec3(-1,5,5), Vec3(0,0,1), //-5,5,5; -1,5,5
                        lighting,
-                       Vec3(0.2,0.2,0.2));
+                       Color(0.2,0.2,0.2));
 
    MaterialID iron = Material::find("iron");
    
-- 
GitLab