From 053de11f54178318ecced82365c31d4e6183739c Mon Sep 17 00:00:00 2001
From: Lukas Werner <lks.werner@fau.de>
Date: Sun, 28 Jan 2018 22:37:24 +0100
Subject: [PATCH] Added blinn-phong lighting model

---
 src/pe/raytracing/Lighting.h    | 34 ++++++-----------
 src/pe/raytracing/Raytracer.cpp |  4 +-
 src/pe/raytracing/Raytracer.h   | 66 +++++++++++++++++++++++++++++----
 tests/pe/Raytracing.cpp         | 15 ++++----
 4 files changed, 79 insertions(+), 40 deletions(-)

diff --git a/src/pe/raytracing/Lighting.h b/src/pe/raytracing/Lighting.h
index f09985b02..e4a045659 100644
--- a/src/pe/raytracing/Lighting.h
+++ b/src/pe/raytracing/Lighting.h
@@ -29,14 +29,9 @@ namespace pe {
 namespace raytracing {
 struct Lighting {
    Vec3 pointLightOrigin;
-   
-   Vec3 ambientLight;
-   
    Vec3 diffuseColor;
-   real_t diffusePower;
-   
    Vec3 specularColor;
-   real_t specularPower;
+   Vec3 ambientColor;
    
    /*!\brief Instantiation constructor for the Lighting struct.
     */
@@ -46,18 +41,14 @@ struct Lighting {
    
    /*!\brief Instantiation constructor for the Lighting struct.
     * \param pointLightOrigin Origin of the point light.
-    * \param ambientLight Color of the ambient light.
     * \param diffuseColor Diffuse color.
-    * \param diffusePower Diffuse color power.
     * \param specularColor Specular color.
-    * \param specularPower Specular color power.
+    * \param ambientColor Color of the ambient light.
     */
-   Lighting (const Vec3& _pointLightOrigin, const Vec3& _ambientLight,
-             const Vec3& _diffuseColor, real_t _diffusePower,
-             const Vec3& _specularColor, real_t _specularPower)
-   : pointLightOrigin(_pointLightOrigin), ambientLight(_ambientLight),
-   diffuseColor(_diffuseColor), diffusePower(_diffusePower),
-   specularColor(_specularColor), specularPower(_specularPower) {
+   Lighting (const Vec3& _pointLightOrigin,
+             const Vec3& _diffuseColor, const Vec3& _specularColor, const Vec3& _ambientColor)
+   : pointLightOrigin(_pointLightOrigin),
+   diffuseColor(_diffuseColor), specularColor(_specularColor), ambientColor(_ambientColor) {
       
    }
    
@@ -65,19 +56,16 @@ struct Lighting {
     * \param config Config handle.
     *
     * The config block has to contain a pointLightOrigin parameter (Vec3).
-    * Optional are ambientLight (Vec3), for diffuse coloring diffuseColor (Vec3) and diffusePower (real) and
-    * for specular color specularColor (Vec3) and specularPower (real).
+    * Optional are ambientColor (Vec3), diffuseColor (Vec3), specularColor (Vec3).
     * Colors are Vec3's with values from 0 to 1.
     */
    Lighting (const Config::BlockHandle& config) {
       WALBERLA_CHECK(config.isValid(), "No valid config passed to raytracer lighting.");
 
-      pointLightOrigin = config.getParameter<Vec3>("pointLightOrigin"),
-      ambientLight = config.getParameter<Vec3>("ambientLight", Vec3(0,0,0)),
-      diffuseColor = config.getParameter<Vec3>("diffuseColor", Vec3(0,0,0));
-      diffusePower = config.getParameter<real_t>("diffusePower", real_t(0));
-      specularColor = config.getParameter<Vec3>("specularColor", Vec3(0,0,0));
-      specularPower = config.getParameter<real_t>("specularPower", real_t(0));
+      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));
    }
 };
 }
diff --git a/src/pe/raytracing/Raytracer.cpp b/src/pe/raytracing/Raytracer.cpp
index ad903e598..f0c73e765 100644
--- a/src/pe/raytracing/Raytracer.cpp
+++ b/src/pe/raytracing/Raytracer.cpp
@@ -222,11 +222,11 @@ void Raytracer::writeImageBufferToFile(const std::vector<Vec3>& imageBuffer, siz
  */
 void Raytracer::writeImageBufferToFile(const std::vector<Vec3>& imageBuffer, const std::string& fileName) const {
    namespace fs = boost::filesystem;
-   
+
    fs::path dir (getImageOutputDirectory());
    fs::path file (fileName);
    fs::path fullPath = dir / file;
-   
+      
    std::ofstream ofs(fullPath.string<std::string>(), std::ios::out | std::ios::binary);
    ofs << "P6\n" << pixelsHorizontal_ << " " << pixelsVertical_ << "\n255\n";
    for (size_t y = pixelsVertical_-1; y > 0; y--) {
diff --git a/src/pe/raytracing/Raytracer.h b/src/pe/raytracing/Raytracer.h
index e738d2b51..46349a7b8 100644
--- a/src/pe/raytracing/Raytracer.h
+++ b/src/pe/raytracing/Raytracer.h
@@ -143,6 +143,7 @@ private:
    
    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;
    //@}
@@ -456,7 +457,9 @@ void Raytracer::rayTrace(const size_t timestep) {
    }
    
    if (getImageOutputEnabled()) {
-      writeImageBufferToFile(imageBuffer, timestep);
+      if (getLocalImageOutputEnabled()) {
+         writeImageBufferToFile(imageBuffer, timestep);
+      }
       WALBERLA_ROOT_SECTION() {
          writeImageBufferToFile(fullImageBuffer, timestep, true);
       }
@@ -470,25 +473,72 @@ 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.
+ * \param Ray Ray which intersected the body.
+ * \param t Distance from eye to intersection point.
+ * \param n Intersection normal at the intersection point.
+ *
+ * \return Vector with RGB color components.
+ */
 inline Vec3 Raytracer::getColor(const BodyID body, const Ray& ray, real_t t, const Vec3& n) const {
-   Vec3 objectColor(real_t(0.6), real_t(0), real_t(0.9));
-   
+   //----
+   Vec3 diffuseColor(0.6, 0, 0.9);
+   Vec3 specularColor(0.8, 0.8, 0.8);
+   Vec3 ambientColor(0.5, 0, 0.8);
+   real_t shininess = 100;
+
    if (body->getTypeID() == Plane::getStaticTypeID()) {
-      objectColor = Vec3(real_t(0.7), real_t(0.7), real_t(0.7));
+      diffuseColor = Vec3(real_t(0.55), real_t(0.55), real_t(0.55));
+      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()) {
-      objectColor = Vec3(real_t(1), real_t(0.1), real_t(0.1));
+      diffuseColor = Vec3(real_t(0.5), real_t(0.5), real_t(0.5));
+      ambientColor.set(real_t(0.4), real_t(0.4), real_t(0.4));
+      specularColor.set(real_t(0.774597), real_t(0.774597), real_t(0.774597));
+      shininess = real_t(30);
    }
+   //----
    
    const Vec3 intersectionPoint = ray.getOrigin() + ray.getDirection() * t;
    Vec3 lightDirection = lighting_.pointLightOrigin - intersectionPoint;
    lightDirection = lightDirection.getNormalized();
+   
    real_t lambertian = std::max(real_t(0), lightDirection * n);
    
-   Vec3 color = objectColor * lambertian + lighting_.ambientLight;
+   real_t specular = real_t(0);
+   
+   if (lambertian > 0) {
+      // Blinn-Phong
+      Vec3 viewDirection = -ray.getDirection();
+      Vec3 halfDirection = (lightDirection + viewDirection).getNormalized();
+      real_t specularAngle = std::max(halfDirection * n, real_t(0));
+      specular = real_c(pow(specularAngle, shininess));
+   }
+   
+   Vec3 color = multiplyColors(lighting_.ambientColor, ambientColor)
+      + multiplyColors(lighting_.diffuseColor, diffuseColor)*lambertian
+      + multiplyColors(lighting_.specularColor, specularColor)*specular;
    
-   for (size_t c = 0; c < 2; c++) {
-      color[c] = std::min(color[c], real_t(1));
+   real_t colorMax = color.max();
+   if (colorMax > real_t(1)) {
+      color.set(color[0] / colorMax,
+                color[1] / colorMax,
+                color[2] / colorMax);
    }
    
    return color;
diff --git a/tests/pe/Raytracing.cpp b/tests/pe/Raytracing.cpp
index 297b6a779..e36cbbeb5 100644
--- a/tests/pe/Raytracing.cpp
+++ b/tests/pe/Raytracing.cpp
@@ -188,9 +188,10 @@ void RaytracerTest() {
    shared_ptr<BodyStorage> globalBodyStorage = make_shared<BodyStorage>();
    shared_ptr<BlockForest> forest = createBlockForest(AABB(0,-5,-5,10,5,5), Vec3(1,1,1), Vec3(false, false, false));
    auto storageID = forest->addBlockData(createStorageDataHandling<BodyTuple>(), "Storage");
-   Lighting lighting(Vec3(0, 3, 3), Vec3(0.1, 0.1, 0.1),
-                     Vec3(0.1, 0.1, 0.1), real_t(2),
-                     Vec3(0.4, 0.4, 0.4), real_t(4));
+   Lighting lighting(Vec3(0, 3, 3),
+                     Vec3(1, 1, 1), //diffuse
+                     Vec3(1, 1, 1), //specular
+                     Vec3(0.4, 0.4, 0.4)); //ambient
    Raytracer raytracer(forest, storageID, globalBodyStorage,
                        size_t(640), size_t(480),
                        49.13,
@@ -237,10 +238,10 @@ int main( int argc, char** argv )
    
    SetBodyTypeIDs<BodyTuple>::execute();
    
-   SphereIntersectsTest();
-   PlaneIntersectsTest();
-   BoxIntersectsTest();
-   AABBIntersectsTest();
+   //SphereIntersectsTest();
+   //PlaneIntersectsTest();
+   //BoxIntersectsTest();
+   //AABBIntersectsTest();
    RaytracerTest();
    
    return EXIT_SUCCESS;
-- 
GitLab