diff --git a/src/pe/raytracing/Intersects.h b/src/pe/raytracing/Intersects.h
index 0bba3fbd71e5f83218a9958528050ca22028ae9c..a1fdb7c657d7e09bda33fd9f30448aebd84e1eb1 100644
--- a/src/pe/raytracing/Intersects.h
+++ b/src/pe/raytracing/Intersects.h
@@ -189,7 +189,7 @@ inline bool intersects(const BoxID box, const Ray& ray, real_t& t, Vec3& n) {
    
    if (transformedRay.getDirection() * n > 0) {
       n = -n;
-   }   
+   }
    n = box->vectorFromBFtoWF(n);
    
    t = t_;
diff --git a/src/pe/raytracing/Lighting.h b/src/pe/raytracing/Lighting.h
new file mode 100644
index 0000000000000000000000000000000000000000..f09985b02c274cd5f856f30498bca2a5b728dac7
--- /dev/null
+++ b/src/pe/raytracing/Lighting.h
@@ -0,0 +1,85 @@
+//======================================================================================================================
+//
+//  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/>.
+//
+//! \file PointLight.h
+//! \author Lukas Werner
+//
+//======================================================================================================================
+
+#pragma once
+
+#include <pe/basic.h>
+#include <pe/Types.h>
+#include <core/math/Vector3.h>
+
+namespace walberla {
+namespace pe {
+namespace raytracing {
+struct Lighting {
+   Vec3 pointLightOrigin;
+   
+   Vec3 ambientLight;
+   
+   Vec3 diffuseColor;
+   real_t diffusePower;
+   
+   Vec3 specularColor;
+   real_t specularPower;
+   
+   /*!\brief Instantiation constructor for the Lighting 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.
+    */
+   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) {
+      
+   }
+   
+   /*!\brief Instantiation constructor for the Lighting struct.
+    * \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).
+    * 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));
+   }
+};
+}
+}
+}
diff --git a/src/pe/raytracing/Ray.h b/src/pe/raytracing/Ray.h
index cfd80cab71245f9671f3c010e50fbe929f9d9e2f..c3e5d28d63291f4864667ac3144379ffe83c924c 100644
--- a/src/pe/raytracing/Ray.h
+++ b/src/pe/raytracing/Ray.h
@@ -38,7 +38,7 @@ public:
    }
    
    /*!\brief Instantiation constructor for the Raytracer class.
-    * \param origin Origin of the ray.
+    * \param origin Origin of the ray. ()
     * \param direction Normalized direction of the ray.
     */
    Ray (Vec3 origin, Vec3 direction) {
diff --git a/src/pe/raytracing/Raytracer.cpp b/src/pe/raytracing/Raytracer.cpp
index f79883314b0efa046541d60d1889f7f8450e3aa2..ad903e598f8a270fc35f596ba51e52604b3d30f7 100644
--- a/src/pe/raytracing/Raytracer.cpp
+++ b/src/pe/raytracing/Raytracer.cpp
@@ -48,13 +48,17 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
                      size_t pixelsHorizontal, size_t pixelsVertical,
                      real_t fov_vertical,
                      const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
+                     const Lighting& lighting,
                      real_t blockAABBIntersectionPadding)
    : forest_(forest), storageID_(storageID), globalBodyStorage_(globalBodyStorage),
    pixelsHorizontal_(pixelsHorizontal), pixelsVertical_(pixelsVertical),
    fov_vertical_(fov_vertical),
    cameraPosition_(cameraPosition), lookAtPoint_(lookAtPoint), upVector_(upVector),
+   lighting_(lighting),
    blockAABBIntersectionPadding_(blockAABBIntersectionPadding),
-   tBufferOutputEnabled_(false)
+   tBufferOutputEnabled_(false),
+   imageOutputEnabled_(false),
+   localImageOutputEnabled_(false)
 {
    setupView_();
 }
@@ -68,6 +72,10 @@ 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. Optional is blockAABBIntersectionPadding (real).
+ * 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.
+ * 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, BlockDataID storageID,
                      const shared_ptr<BodyStorage> globalBodyStorage,
@@ -85,9 +93,20 @@ Raytracer::Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageI
       WALBERLA_LOG_INFO_ON_ROOT("t buffers will be written to " << getTBufferOutputDirectory() << ".");
    }
    
+   setLocalImageOutputEnabled(config.getParameter<bool>("local_image_output_enabled", false));
+      
+   if (config.isDefined("image_output_directory")) {
+      setImageOutputEnabled(true);
+      setImageOutputDirectory(config.getParameter<std::string>("image_output_directory"));
+      WALBERLA_LOG_INFO_ON_ROOT("Images will be written to " << getImageOutputDirectory() << ".");
+   } else if (getLocalImageOutputEnabled()) {
+      WALBERLA_ABORT("Cannot enable local image output without image_output_directory parameter being set.");
+   }
+   
    cameraPosition_ = config.getParameter<Vec3>("cameraPosition");
    lookAtPoint_ = config.getParameter<Vec3>("lookAt");
    upVector_ = config.getParameter<Vec3>("upVector");
+   lighting_ = Lighting(config.getBlock("Lighting"));
    
    blockAABBIntersectionPadding_ = config.getParameter<real_t>("blockAABBIntersectionPadding", real_t(0.0));
 
@@ -180,6 +199,49 @@ void Raytracer::writeTBufferToFile(const std::vector<real_t>& tBuffer, const std
    ofs.close();
 }
 
+/*!\brief Writes a image buffer to a file in the image output directory.
+ * \param imageBuffer Buffer with color vectors.
+ * \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 {
+   WALBERLA_CHECK(timestep < 100000, "Raytracer only supports outputting 99 999 timesteps.");
+   mpi::MPIRank rank = mpi::MPIManager::instance()->rank();
+   uint8_t padding = (timestep < 10 ? 4 :
+                      (timestep < 100 ? 3 :
+                       (timestep < 1000 ? 2 :
+                        (timestep < 10000 ? 1 :
+                         0))));
+   std::string fileName = "image_" + std::string(padding, '0') + std::to_string(timestep) + "+" + (isGlobalImage ? "global" : std::to_string(rank)) + ".ppm";
+   writeImageBufferToFile(imageBuffer, fileName);
+}
+
+/*!\brief Writes the image buffer to a file in the image output directory.
+ * \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 {
+   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--) {
+      for (size_t x = 0; x < pixelsHorizontal_; x++) {
+         size_t i = coordinateToArrayIndex(x, y);
+         const Vec3& color = imageBuffer[i];
+         char r = (char)(255 * color[0]);
+         char g = (char)(255 * color[1]);
+         char b = (char)(255 * color[2]);
+         ofs << r << g << b;
+      }
+   }
+   
+   ofs.close();
+}
 }
 }
 }
diff --git a/src/pe/raytracing/Raytracer.h b/src/pe/raytracing/Raytracer.h
index 3dc53f15fbdca89425d06d147492e32547f5266f..e738d2b518b31afd87f6e577a90b21d163a36dce 100644
--- a/src/pe/raytracing/Raytracer.h
+++ b/src/pe/raytracing/Raytracer.h
@@ -29,6 +29,7 @@
 #include <core/timing/TimingTree.h>
 #include "Ray.h"
 #include "Intersects.h"
+#include "Lighting.h"
 
 using namespace walberla;
 using namespace walberla::pe;
@@ -45,6 +46,7 @@ struct BodyIntersectionInfo {
    size_t imageY;                //!< viewing plane y pixel coordinate the ray belongs to.
    walberla::id_t bodySystemID;  //!< system ID of body which was hit.
    real_t t;                     //!< distance from camera to intersection point on body.
+   Vec3 color;                   //!< color computed for the pixel.
 };
 
 class Raytracer {
@@ -56,6 +58,7 @@ public:
                       size_t pixelsHorizontal, size_t pixelsVertical,
                       real_t fov_vertical,
                       const Vec3& cameraPosition, const Vec3& lookAtPoint, const Vec3& upVector,
+                      const Lighting& lighting,
                       real_t blockAABBIntersectionPadding = real_t(0.0));
    explicit Raytracer(const shared_ptr<BlockStorage> forest, BlockDataID storageID,
                       const shared_ptr<BodyStorage> globalBodyStorage,
@@ -77,11 +80,16 @@ 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.
+   Lighting lighting_;        //!< The lighting 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.*/
    
-   bool tBufferOutputEnabled_; //!< Enable / disable dumping the tbuffer to a file
-   std::string tBufferOutputDirectory_; //!< Path to the tbuffer output directory
+   bool tBufferOutputEnabled_; //!< Enable / disable dumping the tbuffer to file.
+   std::string tBufferOutputDirectory_; //!< Path to the tbuffer output directory.
+   
+   bool imageOutputEnabled_;  //!< Enable / disable writing images to file.
+   bool localImageOutputEnabled_; //!< Enable / disable writing images of the local process to file.
+   std::string imageOutputDirectory_; //!< Path to the image output directory.
    //@}
    
    Vec3 n_;                   //!< The normal vector of the viewing plane.
@@ -107,12 +115,18 @@ public:
    inline const Vec3& getUpVector() const;
    inline bool getTBufferOutputEnabled() const;
    inline const std::string& getTBufferOutputDirectory() const;
+   inline bool getImageOutputEnabled() const;
+   inline bool getLocalImageOutputEnabled() const;
+   inline const std::string& getImageOutputDirectory() const;
    //@}
 
    /*!\name Set functions */
    //@{
    inline void setTBufferOutputEnabled(const bool enabled);
    inline void setTBufferOutputDirectory(const std::string& path);
+   inline void setImageOutputEnabled(const bool enabled);
+   inline void setLocalImageOutputEnabled(const bool enabled);
+   inline void setImageOutputDirectory(const std::string& path);
    //@}
    
    /*!\name Functions */
@@ -124,8 +138,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;
+   
    inline bool isPlaneVisible(const PlaneID plane, const Ray& ray) const;
    inline size_t coordinateToArrayIndex(size_t x, size_t y) const;
+   
+   inline Vec3 getColor(const BodyID body, const Ray& ray, real_t t, const Vec3& n) const;
    //@}
 };
    
@@ -200,7 +219,31 @@ inline const std::string& Raytracer::getTBufferOutputDirectory() const {
    return tBufferOutputDirectory_;
 }
    
-/*!\brief Enabled / disable outputting the tBuffer to a file in the specified directory.
+/*!\brief Returns true if image output to a file is enabled.
+ *
+ * \return True if image output enabled, otherwise false.
+ */
+inline bool Raytracer::getImageOutputEnabled() const {
+   return imageOutputEnabled_;
+}
+
+/*!\brief Returns true if local image output to a file is enabled.
+ *
+ * \return True if local image output enabled, otherwise false.
+ */
+inline bool Raytracer::getLocalImageOutputEnabled() const {
+   return localImageOutputEnabled_;
+}
+   
+/*!\brief Returns the directory where the images will be saved in.
+ *
+ * \return Path to the image output directory.
+ */
+inline const std::string& Raytracer::getImageOutputDirectory() const {
+   return imageOutputDirectory_;
+}
+   
+/*!\brief Enable / disable outputting the tBuffer to a file in the specified directory.
  * \param enabled Set to true / false to enable / disable tbuffer output.
  */
 inline void Raytracer::setTBufferOutputEnabled(const bool enabled) {
@@ -219,6 +262,32 @@ inline void Raytracer::setTBufferOutputDirectory(const std::string& path) {
    tBufferOutputDirectory_ = path;
 }
    
+/*!\brief Enable / disable outputting images in the specified directory.
+ * \param enabled Set to true / false to enable / disable image output.
+ */
+inline void Raytracer::setImageOutputEnabled(const bool enabled) {
+   imageOutputEnabled_ = enabled;
+}
+
+/*!\brief Enable / disable outputting local images in the specified directory.
+ * \param enabled Set to true / false to enable / disable image output.
+ */
+inline void Raytracer::setLocalImageOutputEnabled(const bool enabled) {
+   localImageOutputEnabled_ = enabled;
+}
+   
+/*!\brief Enable / disable outputting images in the specified directory.
+ * \param enabled Set to true / false to enable / disable image output.
+ */
+inline void Raytracer::setImageOutputDirectory(const std::string& path) {
+   namespace fs = boost::filesystem;
+   
+   fs::path dir (path);
+   WALBERLA_CHECK(fs::exists(dir) && fs::is_directory(dir), "Image output directory " << path << " is invalid.");
+   
+   imageOutputDirectory_ = path;
+}
+   
 /*!\brief Checks if a plane should get rendered.
  * \param plane Plane to check for visibility.
  * \param ray Ray which is intersected with plane.
@@ -251,11 +320,13 @@ void Raytracer::rayTrace(const size_t timestep) {
    real_t inf = std::numeric_limits<real_t>::max();
 
    std::vector<real_t> tBuffer(pixelsVertical_ * pixelsHorizontal_, inf);
+   std::vector<Vec3> imageBuffer(pixelsVertical_ * pixelsHorizontal_);
    std::vector<BodyIntersectionInfo> intersections; // contains for each pixel information about an intersection, if existent
    
    real_t t, t_closest;
    Vec3 n;
-   RigidBody* body_closest = NULL;
+   Vec3 n_closest;
+   BodyID body_closest = NULL;
    Ray ray(cameraPosition_, Vec3(1,0,0));
    IntersectsFunctor func(ray, t, n);
    tp_["Raytracing"].start();
@@ -265,7 +336,7 @@ void Raytracer::rayTrace(const size_t timestep) {
          Vec3 direction = (pixelLocation - cameraPosition_).getNormalized();
          ray.setDirection(direction);
          
-         n[0] = n[1] = n[2] = real_t(0);
+         n.reset();
          t_closest = inf;
          body_closest = NULL;
          for (auto blockIt = forest_->begin(); blockIt != forest_->end(); ++blockIt) {
@@ -289,6 +360,7 @@ void Raytracer::rayTrace(const size_t timestep) {
                   // body was shot by ray and currently closest to camera
                   t_closest = t;
                   body_closest = *bodyIt;
+                  n_closest = n;
                }
             }
          }
@@ -310,16 +382,20 @@ void Raytracer::rayTrace(const size_t timestep) {
                   // body was shot by ray and currently closest to camera
                   t_closest = t;
                   body_closest = *bodyIt;
+                  n_closest = n;
                }
             }
          }
          
          if (!realIsIdentical(t_closest, inf) && body_closest != NULL) {
+            Vec3 color = getColor(body_closest, ray, t_closest, n_closest);
+            imageBuffer[coordinateToArrayIndex(x, y)] = color;
             BodyIntersectionInfo intersectionInfo = {
                x,
                y,
                body_closest->getSystemID(),
-               t_closest
+               t_closest,
+               color
             };
             intersections.push_back(intersectionInfo);
          }
@@ -334,10 +410,13 @@ void Raytracer::rayTrace(const size_t timestep) {
    // intersections synchronisieren
    mpi::SendBuffer sendBuffer;
    for (auto& info: intersections) {
-      sendBuffer << info.imageX << info.imageY << info.bodySystemID << info.t;
+      sendBuffer << info.imageX << info.imageY
+      << info.bodySystemID << info.t
+      << info.color[0] << info.color[1] << info.color[2];
    }
    int gatheredIntersectionCount = 0;
-   std::vector<real_t> fullImage(pixelsHorizontal_ * pixelsVertical_, inf);
+   std::vector<real_t> fullTBuffer(pixelsHorizontal_ * pixelsVertical_, inf);
+   std::vector<Vec3> fullImageBuffer(pixelsHorizontal_ * pixelsVertical_);
    mpi::RecvBuffer recvBuffer;
    
    mpi::gathervBuffer(sendBuffer, recvBuffer, 0);
@@ -350,11 +429,15 @@ void Raytracer::rayTrace(const size_t timestep) {
          recvBuffer >> info.imageY;
          recvBuffer >> info.bodySystemID;
          recvBuffer >> info.t;
+         recvBuffer >> info.color[0];
+         recvBuffer >> info.color[1];
+         recvBuffer >> info.color[2];
          
          size_t i = coordinateToArrayIndex(info.imageX, info.imageY);
-         real_t currentFullImageT = fullImage[i];
-         if (currentFullImageT > info.t) {
-            fullImage[i] = info.t;
+         real_t currentFullTBufferT = fullTBuffer[i];
+         if (currentFullTBufferT > info.t) {
+            fullTBuffer[i] = info.t;
+            fullImageBuffer[i] = info.color;
          }
          
          gatheredIntersectionCount++;
@@ -372,14 +455,44 @@ void Raytracer::rayTrace(const size_t timestep) {
       tpReduced->print(std::cout);
    }
    
+   if (getImageOutputEnabled()) {
+      writeImageBufferToFile(imageBuffer, timestep);
+      WALBERLA_ROOT_SECTION() {
+         writeImageBufferToFile(fullImageBuffer, timestep, true);
+      }
+   }
+   
    if (getTBufferOutputEnabled()) {
       writeTBufferToFile(tBuffer, timestep);
       WALBERLA_ROOT_SECTION() {
-         writeTBufferToFile(fullImage, timestep, true);
+         writeTBufferToFile(fullTBuffer, timestep, true);
       }
    }
 }
+
+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));
+   
+   if (body->getTypeID() == Plane::getStaticTypeID()) {
+      objectColor = Vec3(real_t(0.7), real_t(0.7), real_t(0.7));
+   }
+   if (body->getTypeID() == Sphere::getStaticTypeID()) {
+      objectColor = Vec3(real_t(1), real_t(0.1), real_t(0.1));
+   }
    
+   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;
+   
+   for (size_t c = 0; c < 2; c++) {
+      color[c] = std::min(color[c], real_t(1));
+   }
+   
+   return color;
+}
 }
 }
 }
diff --git a/tests/pe/Raytracing.cpp b/tests/pe/Raytracing.cpp
index 3722f69f8f9ef131cc46e7cf0fb91ba19bb45275..297b6a779135b0aee83d03bff84ff7376e2c80b2 100644
--- a/tests/pe/Raytracing.cpp
+++ b/tests/pe/Raytracing.cpp
@@ -98,6 +98,13 @@ void PlaneIntersectsTest() {
    // plane with center -10,3,3 and parallel to y-z plane
    Plane pl4(1, 1, Vec3(-10, 3, 3), Vec3(1, 0, 0), real_t(1.0), iron);
    WALBERLA_CHECK(!intersects(&pl4, ray1, t, n), "ray hit plane behind origin");
+   
+   Plane pl6(1, 1, Vec3(3, 3, 0), Vec3(-1, 0, 0), real_t(1.0), iron);
+   Ray ray4(Vec3(0,0,5), Vec3(1, 0, -1).getNormalized());
+   WALBERLA_CHECK(intersects(&pl6, ray4, t, n), "ray didnt hit");
+   WALBERLA_CHECK_FLOAT_EQUAL(n[0], real_t(-1), "incorrect normal calculated");
+   WALBERLA_CHECK_FLOAT_EQUAL(n[1], real_t(0), "incorrect normal calculated");
+   WALBERLA_CHECK_FLOAT_EQUAL(n[2], real_t(0), "incorrect normal calculated");
 }
 
 void BoxIntersectsTest() {
@@ -181,11 +188,14 @@ 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));
    Raytracer raytracer(forest, storageID, globalBodyStorage,
                        size_t(640), size_t(480),
                        49.13,
-                       Vec3(-5,0,0), Vec3(-1,0,0), Vec3(0,0,1));
+                       Vec3(-5,0,0), Vec3(-1,0,0), Vec3(0,0,1),
+                       lighting);
    
    MaterialID iron = Material::find("iron");
    
@@ -214,6 +224,8 @@ void RaytracerTest() {
    
    raytracer.setTBufferOutputDirectory("/Users/ng/Desktop/walberla");
    raytracer.setTBufferOutputEnabled(true);
+   raytracer.setImageOutputDirectory("/Users/ng/Desktop/walberla");
+   raytracer.setImageOutputEnabled(true);
    
    raytracer.rayTrace<BodyTuple>(0);
 }