diff --git a/Base/Geometry/Mesh/imstkMesh.cpp b/Base/Geometry/Mesh/imstkMesh.cpp
index c4c2cf56140a2003f07ace376d5411188a4c6d42..ffa3fc6e5af3345fbdff29df8b69918e2a653b1e 100644
--- a/Base/Geometry/Mesh/imstkMesh.cpp
+++ b/Base/Geometry/Mesh/imstkMesh.cpp
@@ -154,7 +154,8 @@ Mesh::setVertexDisplacements(const Vectord& u)
     m_transformApplied = false;
 }
 
-void Mesh::translateVertices(const Vec3d& t)
+void
+Mesh::translateVertices(const Vec3d& t)
 {
     for (size_t i = 0; i < m_vertexPositions.size(); ++i)
     {
@@ -200,7 +201,7 @@ Mesh::getPointDataArray(const std::string& arrayName) const
     return &(it->second);
 }
 
-const size_t
+size_t
 Mesh::getNumVertices() const
 {
     return m_initialVertexPositions.size();
diff --git a/Base/Geometry/Mesh/imstkMesh.h b/Base/Geometry/Mesh/imstkMesh.h
index f3d6d8c53eae23687c38505bf7ab1d962b4699c1..8dc103505d40c886956e3aa07f2926665421ef00 100644
--- a/Base/Geometry/Mesh/imstkMesh.h
+++ b/Base/Geometry/Mesh/imstkMesh.h
@@ -136,7 +136,7 @@ public:
     ///
     /// \brief Returns the number of total vertices in the mesh
     ///
-    const size_t getNumVertices() const;
+    size_t getNumVertices() const;
 
     ///
     /// \brief Set the topologyChanged flag
diff --git a/Base/Geometry/Reader/imstkAssimpMeshIO.cpp b/Base/Geometry/Reader/imstkAssimpMeshIO.cpp
index 405f75b613da7a9fbffea217268dc33c4d338a01..f8e9e369d031c9705392ce0d3e9547a2b3e2c718 100644
--- a/Base/Geometry/Reader/imstkAssimpMeshIO.cpp
+++ b/Base/Geometry/Reader/imstkAssimpMeshIO.cpp
@@ -116,7 +116,7 @@ AssimpMeshIO::readMeshData(const std::string& filePath)
         }
     }
 
-    if (importedMesh->HasTangentsAndBitangents())
+    if (importedMesh->HasTangentsAndBitangents() && importedMesh->HasTextureCoords(0))
     {
         for (unsigned int i = 0; i < numVertices; i++)
         {
@@ -136,7 +136,7 @@ AssimpMeshIO::readMeshData(const std::string& filePath)
     mesh->setVertexTangents(tangents);
     mesh->setVertexBitangents(bitangents);
 
-    // UV coordinates normals
+    // UV coordinates
     StdVectorOfVectorf UVs(numVertices);
     if (importedMesh->HasTextureCoords(0))
     {
diff --git a/Base/Materials/imstkRenderMaterial.cpp b/Base/Materials/imstkRenderMaterial.cpp
index 73bfb7d94db614714c5d99df03f2ec6164141330..d0ae03e3f6cdf323124a37eb4df008ea418550ed 100644
--- a/Base/Materials/imstkRenderMaterial.cpp
+++ b/Base/Materials/imstkRenderMaterial.cpp
@@ -32,7 +32,7 @@ RenderMaterial::RenderMaterial()
     }
 }
 
-const RenderMaterial::DisplayMode
+RenderMaterial::DisplayMode
 RenderMaterial::getDisplayMode() const
 {
     return m_displayMode;
@@ -50,7 +50,7 @@ RenderMaterial::setDisplayMode(const DisplayMode displayMode)
     m_modified = true;
 }
 
-const float
+float
 RenderMaterial::getLineWidth() const
 {
     return m_lineWidth;
@@ -68,7 +68,7 @@ RenderMaterial::setLineWidth(const float width)
     m_modified = true;
 }
 
-const float
+float
 RenderMaterial::getPointSize() const
 {
     return m_pointSize;
@@ -86,7 +86,7 @@ RenderMaterial::setPointSize(const float size)
     m_modified = true;
 }
 
-const bool
+bool
 RenderMaterial::getBackFaceCulling() const
 {
     return m_backfaceCulling;
@@ -129,29 +129,28 @@ RenderMaterial::setDiffuseColor(const Color color)
     m_modified = true;
 }
 
-const Color&
-RenderMaterial::getSpecularColor() const
+const float&
+RenderMaterial::getMetalness() const
 {
-    return m_specularColor;
+    return m_metalness;
 }
 
 void
-RenderMaterial::setSpecularColor(const Color color)
+RenderMaterial::setMetalness(const float metalness)
 {
-    m_specularColor = color;
-    m_modified = true;
+    m_metalness = metalness;
 }
 
 const float&
-RenderMaterial::getSpecularity() const
+RenderMaterial::getRoughness() const
 {
-    return m_specularity;
+    return m_roughness;
 }
 
 void
-RenderMaterial::setSpecularity(const float specularity)
+RenderMaterial::setRoughness(const float roughness)
 {
-    m_specularity = specularity;
+    m_roughness = roughness;
 }
 
 std::shared_ptr<Texture>
diff --git a/Base/Materials/imstkRenderMaterial.h b/Base/Materials/imstkRenderMaterial.h
index 2f1327be53a33103691170cef259a9ecc9854b4a..c73587cbef4c2ba098a0d35526e3886f6036dd29 100644
--- a/Base/Materials/imstkRenderMaterial.h
+++ b/Base/Materials/imstkRenderMaterial.h
@@ -52,25 +52,25 @@ public:
     ///
     /// \brief Get/Set display mode
     ///
-    const DisplayMode getDisplayMode() const;
+    DisplayMode getDisplayMode() const;
     void setDisplayMode(const DisplayMode displayMode);
 
     ///
     /// \brief Get/Set line width or the wireframe
     ///
-    const float getLineWidth() const;
+    float getLineWidth() const;
     void setLineWidth(const float width);
 
     ///
     /// \brief Get/Set point size
     ///
-    const float getPointSize() const;
+    float getPointSize() const;
     void setPointSize(const float size);
 
     ///
     /// \brief Backface culling on/off
     ///
-    const bool getBackFaceCulling() const;
+    bool getBackFaceCulling() const;
     void setBackFaceCulling(const bool culling);
     void backfaceCullingOn();
     void backfaceCullingOff();
@@ -82,16 +82,16 @@ public:
     void setDiffuseColor(const Color color);
 
     ///
-    /// \brief Get/Set the specular color (only set for metals)
+    /// \brief Get/Set the metalness
     ///
-    const Color& getSpecularColor() const;
-    void setSpecularColor(const Color color);
+    const float& getMetalness() const;
+    void setMetalness(const float metalness);
 
     ///
-    /// \brief Get/Set the specularity
+    /// \brief Get/Set the roughness
     ///
-    const float& getSpecularity() const;
-    void setSpecularity(const float specularity);
+    const float& getRoughness() const;
+    void setRoughness(const float roughness);
 
     ///
     /// \brief Add/Get texture
@@ -123,10 +123,10 @@ protected:
 
     // Colors
     Color m_diffuseColor = Color::White;
-    Color m_specularColor = Color::Black;
 
     // Classical values
-    float m_specularity = 0.0; ///< Not shiny by default
+    float m_metalness = 0.0; ///< Value for metalness with range: [0.0, 1.0]
+    float m_roughness = 0.0; ///< Value for roughness with range: [0.0, 1.0]
 
     // Textures
     std::vector<std::shared_ptr<Texture>> m_textures; ///< Ordered by Texture::Type
diff --git a/Base/Materials/imstkTexture.cpp b/Base/Materials/imstkTexture.cpp
index 6b4ce2d65a6d78d02faa7f05eddd28efa3393e10..4e8a4dd46a8d576f16ee23a36353e77dc8530b0a 100644
--- a/Base/Materials/imstkTexture.cpp
+++ b/Base/Materials/imstkTexture.cpp
@@ -29,7 +29,7 @@ Texture::Texture(std::string path, Type type)
     m_type = type;
 }
 
-const Texture::Type
+Texture::Type
 Texture::getType() const
 {
     return m_type;
diff --git a/Base/Materials/imstkTexture.h b/Base/Materials/imstkTexture.h
index 585e6c9fcd2d52264e61bfc430aa1fec0cfc6fe2..7095a05ed87a4f4c7808fc02312cbbb1f59c3eb8 100644
--- a/Base/Materials/imstkTexture.h
+++ b/Base/Materials/imstkTexture.h
@@ -67,7 +67,7 @@ public:
     ///
     /// \brief Get type
     ///
-    const Type getType() const;
+    Type getType() const;
 
     ///
     /// \brief Get path
diff --git a/Base/Rendering/CMakeLists.txt b/Base/Rendering/CMakeLists.txt
index 8df1347a0a59e9b9f090d1a8c8f0882914370d09..a603e2e972e3ea400c9a631c50ceb4e0b1341e7c 100644
--- a/Base/Rendering/CMakeLists.txt
+++ b/Base/Rendering/CMakeLists.txt
@@ -6,6 +6,7 @@ imstk_add_library( Rendering
   H_FILES
     imstkVTKRenderer.h
     imstkVTKTextureDelegate.h
+    imstkVTKCustomPolyDataMapper.h
     RenderDelegate/imstkVTKCubeRenderDelegate.h
     RenderDelegate/imstkVTKLineMeshRenderDelegate.h
     RenderDelegate/imstkVTKPlaneRenderDelegate.h
@@ -21,6 +22,7 @@ imstk_add_library( Rendering
   CPP_FILES
     imstkVTKRenderer.cpp
     imstkVTKTextureDelegate.cpp
+    imstkVTKCustomPolyDataMapper.cpp
     RenderDelegate/imstkVTKCubeRenderDelegate.cpp
     RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
     RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
@@ -46,4 +48,4 @@ imstk_add_library( Rendering
 #-----------------------------------------------------------------------------
 if( iMSTK_BUILD_TESTING )
   add_subdirectory( Testing )
-endif()
+endif()
\ No newline at end of file
diff --git a/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
index 621b98b9582c213096e61d7cf1c9b11349c53779..0c145c64439ce0dc565e8661b231f60f5aeebe13 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
@@ -41,7 +41,7 @@ VTKCapsuleRenderDelegate::VTKCapsuleRenderDelegate(std::shared_ptr<Capsule> caps
     m_transformFilter->SetTransform(vtkSmartPointer<vtkTransform>::New());
 
     this->update();
-    this->setUpMapper(m_transformFilter->GetOutputPort(), true);
+    this->setUpMapper(m_transformFilter->GetOutputPort(), true, m_geometry);
 }
 
 void
diff --git a/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
index f4dc13a0f06b1fa2a2aa5ee21d7cedbe7ec350f0..05ae2335ce111a3ed911ed1c5339835dbbea6e27 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
@@ -39,7 +39,7 @@ VTKCubeRenderDelegate::VTKCubeRenderDelegate(std::shared_ptr<Cube> cube) :
     m_transformFilter->SetTransform(vtkSmartPointer<vtkTransform>::New());
 
     this->update();
-    this->setUpMapper(m_transformFilter->GetOutputPort(), true);
+    this->setUpMapper(m_transformFilter->GetOutputPort(), true, m_geometry);
 }
 
 void
diff --git a/Base/Rendering/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
index 1d85cbac58131b99115ee6910f66f84152db8664..958c3abc47d6a91173ac4f9e411428152eb183fd 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
@@ -38,7 +38,7 @@ VTKCylinderRenderDelegate::VTKCylinderRenderDelegate(std::shared_ptr<Cylinder> c
     m_transformFilter->SetTransform(vtkSmartPointer<vtkTransform>::New());
 
     this->update();
-    this->setUpMapper(m_transformFilter->GetOutputPort(), true);
+    this->setUpMapper(m_transformFilter->GetOutputPort(), true, m_geometry);
 }
 
 void
diff --git a/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
index dd88a3d0ca2cb9901c7b8aa866dc22ded0360838..d05dd76bb6807d0b0cd27b5f94ce46079d0de10f 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
@@ -51,7 +51,7 @@ VTKLineMeshRenderDelegate::VTKLineMeshRenderDelegate(std::shared_ptr<LineMesh> l
     m_geometry->m_dataModified = false;
 
     // Setup Mapper & Actor
-    this->setUpMapper(lines->GetOutputPort(), true);
+    this->setUpMapper(lines->GetOutputPort(), true, m_geometry);
 
     // Update Transform, Render Properties
     this->update();
diff --git a/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
index edfeae893087c03a21c9d0c4ec4d3965a401ed47..4719676789462cff5518bf460f1e16d7d1b4d906 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
@@ -37,7 +37,7 @@ VTKPlaneRenderDelegate::VTKPlaneRenderDelegate(std::shared_ptr<Plane>plane) :
     m_transformFilter->SetTransform(vtkSmartPointer<vtkTransform>::New());
 
     this->update();
-    this->setUpMapper(m_transformFilter->GetOutputPort(), true);
+    this->setUpMapper(m_transformFilter->GetOutputPort(), true, m_geometry);
 }
 
 void
diff --git a/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp
index 55ec3203b3d8412f54b3cf38c92d2c3865118ebc..15c78b8c337ed6608f0de942335f877bdfd22e44 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp
@@ -111,7 +111,9 @@ VTKRenderDelegate::make_delegate(std::shared_ptr<Geometry> geom)
 }
 
 void
-VTKRenderDelegate::setUpMapper(vtkAlgorithmOutput *source, const bool rigid)
+VTKRenderDelegate::setUpMapper(vtkAlgorithmOutput *source,
+                               const bool rigid,
+                               std::shared_ptr<Geometry> geometry)
 {
     // Add normals
     vtkSmartPointer<vtkPolyDataAlgorithm> normalGen;
@@ -130,9 +132,16 @@ VTKRenderDelegate::setUpMapper(vtkAlgorithmOutput *source, const bool rigid)
 
     // Disable auto Shift & Scale which is slow for deformable objects
     // as it needs to compute a bounding box at every frame
-    if(auto mapper = vtkOpenGLPolyDataMapper::SafeDownCast(m_mapper.GetPointer()))
+    if(auto mapper = VTKCustomPolyDataMapper::SafeDownCast(m_mapper.GetPointer()))
     {
         mapper->SetVBOShiftScaleMethod(vtkOpenGLVertexBufferObject::DISABLE_SHIFT_SCALE);
+
+        if (!geometry->getRenderMaterial())
+        {
+            geometry->setRenderMaterial(std::make_shared<RenderMaterial>());
+        }
+
+        mapper->setGeometry(geometry);
     }
 }
 
@@ -179,12 +188,7 @@ VTKRenderDelegate::updateActorProperties()
 
     // Colors & Light
     auto diffuseColor = material->m_diffuseColor;
-    auto specularColor = material->m_specularColor;
-    auto specularity = material->m_specularity;
     actorProperty->SetDiffuseColor(diffuseColor.r, diffuseColor.g, diffuseColor.b);
-    actorProperty->SetSpecularColor(specularColor.r, specularColor.g, specularColor.b);
-    actorProperty->SetSpecularPower(specularity);
-    actorProperty->SetSpecular(1.0);
 
     // Material state is now up to date
     material->m_modified = false;
diff --git a/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.h
index 18f78c2f7d9c9a30e761a99d308dea3eddefaafd..44eb7d1bc5db79aa35e95e9437099417c35f7939 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.h
@@ -28,6 +28,7 @@
 #include "imstkRenderMaterial.h"
 #include "imstkVTKTextureDelegate.h"
 #include "imstkTextureManager.h"
+#include "imstkVTKCustomPolyDataMapper.h"
 
 #include "vtkSmartPointer.h"
 #include "vtkAlgorithmOutput.h"
@@ -60,7 +61,9 @@ public:
     ///
     /// \brief Set up normals and mapper
     ///
-    void setUpMapper(vtkAlgorithmOutput *source, const bool rigid);
+    void setUpMapper(vtkAlgorithmOutput *source,
+                     const bool rigid,
+                     std::shared_ptr<Geometry> geometry);
 
     ///
     /// \brief Return geometry to render
@@ -99,14 +102,14 @@ protected:
     VTKRenderDelegate()
     {
         m_actor = vtkSmartPointer<vtkActor>::New();
-        m_mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        m_mapper = vtkSmartPointer<VTKCustomPolyDataMapper>::New();
         m_transform = vtkSmartPointer<vtkTransform>::New();
         m_actor->SetMapper(m_mapper);
         m_actor->SetUserTransform(m_transform);
     }
 
     vtkSmartPointer<vtkActor> m_actor;
-    vtkSmartPointer<vtkPolyDataMapper> m_mapper;
+    vtkSmartPointer<VTKCustomPolyDataMapper> m_mapper;
     vtkSmartPointer<vtkTransform> m_transform;
 };
 }
diff --git a/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
index dc6676b3e17622a5d5214836c915773777d278f9..07f5f11e87a590c20961de77db96c35ae2ba470d 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
@@ -39,7 +39,7 @@ VTKSphereRenderDelegate::VTKSphereRenderDelegate(std::shared_ptr<Sphere>sphere)
     m_transformFilter->SetTransform(vtkSmartPointer<vtkTransform>::New());
 
     this->update();
-    this->setUpMapper(m_transformFilter->GetOutputPort(), true);
+    this->setUpMapper(m_transformFilter->GetOutputPort(), true, m_geometry);
 }
 
 void
diff --git a/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
index 4da2d278a3ad31a835ef50dae0a3e95791b16ba5..a7602ed570714c7b8ae8cc5b38112ee4faeb9e81 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
@@ -109,9 +109,26 @@ VTKSurfaceMeshRenderDelegate::VTKSurfaceMeshRenderDelegate(std::shared_ptr<Surfa
         }
     }
 
+    // Update tangents
+    if (m_geometry->getVertexTangents().size() > 0)
+    {
+        auto tangents = vtkSmartPointer<vtkFloatArray>::New();
+        tangents->SetName("tangents");
+        tangents->SetNumberOfComponents(3);
+
+        for (auto const tangent : m_geometry->getVertexTangents())
+        {
+            float tempTangent[3] = {(float)tangent[0],
+                                    (float)tangent[1],
+                                    (float)tangent[2]};
+            tangents->InsertNextTuple(tempTangent);
+        }
+        polydata->GetPointData()->AddArray(tangents);
+    }
+
     // Update Transform, Render Properties
     this->update();
-    this->setUpMapper(source->GetOutputPort(), false);
+    this->setUpMapper(source->GetOutputPort(), false, m_geometry);
 }
 
 void
@@ -136,6 +153,8 @@ VTKSurfaceMeshRenderDelegate::initializeTextures(TextureManager<VTKTextureDelega
         return;
     }
 
+    unsigned int currentUnit = 0;
+
     // Go through all of the textures
     for (int unit = 0; unit < Texture::Type::NONE; unit++)
     {
@@ -165,7 +184,8 @@ VTKSurfaceMeshRenderDelegate::initializeTextures(TextureManager<VTKTextureDelega
         */
 
         // Set texture
-        m_actor->GetProperty()->SetTexture(unit, textureDelegate->getTexture());
+        m_actor->GetProperty()->SetTexture(currentUnit, textureDelegate->getTexture());
+        currentUnit++;
     }
 }
 
diff --git a/Base/Rendering/VTKShaders/mesh.frag b/Base/Rendering/VTKShaders/mesh.frag
new file mode 100644
index 0000000000000000000000000000000000000000..4bda13a998398fe3679c755e99159a563c6ec052
--- /dev/null
+++ b/Base/Rendering/VTKShaders/mesh.frag
@@ -0,0 +1,115 @@
+out vec4 gl_FragData[0];
+
+uniform vec3 cameraPosition = vec3(0, 0, 1);
+uniform int numLights = 0;
+
+in Vertex
+{
+    vec3 position;
+    vec3 normal;
+    vec2 uv;
+} vertex;
+
+// Lights
+uniform vec3 lightPosition[16];
+uniform int lightType[16];
+uniform vec4 lightColor[16];
+uniform vec4 lightDirection[16];
+
+// Textures
+#ifdef SHADED
+uniform sampler2D diffuseTexture;
+uniform samplerCube cubemapTexture;
+#endif
+
+// Material properties
+uniform float metalness = 0;
+uniform float roughness = 1.0;
+
+// Colors
+vec3 diffuseColor = vec3(1);
+vec3 reflectionColor = vec3(1);
+vec3 specularColor = vec3(0);
+vec3 finalSpecular = vec3(0);
+vec3 finalDiffuse = vec3(0);
+vec3 finalColor = vec3(0);
+
+// Other information
+vec3 normal = vec3(0, 0, 1);
+vec3 cameraDirection = vec3(0, 0, 1);
+
+void calculateClassicalLighting(vec3 lightDirection, vec3 color, float intensity);
+vec3 toneMap(vec3 color);
+
+void main()
+{
+#ifdef SHADED
+    normal = normalize(vertex.normal);
+    cameraDirection = normalize(vertex.position - cameraPosition);
+
+#ifdef DIFFUSE_TEXTURE
+    diffuseColor = pow(texture(diffuseTexture, vertex.uv).rgb, vec3(2.2));
+#endif
+#ifdef CUBEMAP_TEXTURE
+    reflectionColor = pow(texture(cubemapTexture, reflect(cameraDirection, normal)).rgb, vec3(2.2));
+#endif
+
+    specularColor = mix(vec3(1), diffuseColor, metalness);
+    diffuseColor = mix(diffuseColor, reflectionColor * diffuseColor, metalness);
+
+    float lightIntensity = 0;
+
+    vec3 lightDir = vec3(0);
+    for (int i = 0; i < numLights; i++)
+    {
+        if (lightType[i] > 1)
+        {
+            lightDir = vertex.position.xyz - lightPosition[i];
+            float distance_squared = dot(lightDir, lightDir);
+            lightIntensity = lightColor[i].a / distance_squared;
+
+            if (lightType[i] == 3)
+            {
+                if (lightDirection[i].a > dot(normalize(lightDir), normalize(lightDirection[i].xyz)))
+                {
+                    lightIntensity = 0;
+                }
+            }
+        }
+        else
+        {
+            lightDir = lightDirection[i].xyz;
+            lightIntensity = lightColor[i].a;
+        }
+        calculateClassicalLighting(normalize(lightDir),
+            lightColor[i].rgb, lightIntensity);
+    }
+
+    // Sum components and apply gamma correction
+    finalColor = mix(0.5, 1.0, roughness) * finalDiffuse + mix(0.5, 0.0, roughness) * finalSpecular;
+
+    // Apply tone mapping
+    finalColor = toneMap(finalColor);
+
+    gl_FragData[0] = vec4(pow(finalColor, vec3(1.0 / 2.2)), 1);
+#else
+    gl_FragData[0] = vec4(0, 0, 0, 1);
+#endif
+}
+
+void calculateClassicalLighting(vec3 lightDirection, vec3 lightColor, float lightIntensity)
+{
+    float diffusePow = max(dot(normal, -lightDirection), 0.0);
+    finalDiffuse += max(lightColor * lightIntensity * diffuseColor * diffusePow, 0.0);
+
+    vec3 halfway = normalize(-cameraDirection - lightDirection);
+    float specularPow = max(dot(normal, halfway), 0.0);
+    finalSpecular += specularColor * lightColor * lightIntensity * vec3(pow(specularPow, (1.0 - roughness) * 100.0));
+}
+
+// Reinhard tonemapping
+vec3 toneMap(vec3 color)
+{
+    float luminance = dot(color, vec3(.21, .72, .07));
+    return (luminance / (luminance + vec3(1.0))) * color;
+}
\ No newline at end of file
diff --git a/Base/Rendering/VTKShaders/mesh.vert b/Base/Rendering/VTKShaders/mesh.vert
new file mode 100644
index 0000000000000000000000000000000000000000..1e26f78dc94b92e36833ead07cb4f63e8cfeb396
--- /dev/null
+++ b/Base/Rendering/VTKShaders/mesh.vert
@@ -0,0 +1,29 @@
+// Matrices
+uniform mat4 projectionMatrix;
+uniform mat4 viewMatrix;
+uniform mat4 modelMatrix;
+uniform mat3 normalMatrix;
+
+in vec3 inputPosition;
+in vec3 inputNormal;
+in vec3 inputTangent;
+in vec2 inputUV;
+
+out Vertex
+{
+    vec3 position;
+    vec3 normal;
+    vec2 uv;
+} vertex;
+
+void main()
+{
+    mat3 rotationMatrix = mat3(normalMatrix);
+
+    vertex.normal = normalize(rotationMatrix * normalize(inputNormal));
+    vec3 position = vec3(modelMatrix * vec4(inputPosition, 1));
+
+    vertex.uv = inputUV;
+    vertex.position = position;
+    gl_Position = projectionMatrix * viewMatrix * vec4(position, 1);
+}
\ No newline at end of file
diff --git a/Base/Rendering/imstkVTKCustomPolyDataMapper.cpp b/Base/Rendering/imstkVTKCustomPolyDataMapper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..20a56b7997fa3763eeec0307ca8201fea14f4010
--- /dev/null
+++ b/Base/Rendering/imstkVTKCustomPolyDataMapper.cpp
@@ -0,0 +1,277 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkVTKCustomPolyDataMapper.h"
+
+namespace imstk
+{
+vtkStandardNewMacro(VTKCustomPolyDataMapper);
+
+void
+VTKCustomPolyDataMapper::BuildBufferObjects(vtkRenderer * renderer, vtkActor * actor)
+{
+    auto polyData = this->GetInput();
+
+    auto renderWindow = (vtkOpenGLRenderWindow*)renderer->GetRenderWindow();
+    auto VBOCache = renderWindow->GetVBOCache();
+
+    this->VBOs->CacheDataArray("inputPosition", polyData->GetPoints()->GetData(), VBOCache, VTK_FLOAT);
+    this->VBOs->CacheDataArray("inputNormal", polyData->GetPointData()->GetNormals(), VBOCache, VTK_FLOAT);
+    this->VBOs->CacheDataArray("inputUV", polyData->GetPointData()->GetTCoords(), VBOCache, VTK_FLOAT);
+
+    if (polyData->GetPointData()->GetArray("tangents"))
+    {
+        this->VBOs->CacheDataArray("inputTangent", polyData->GetPointData()->GetArray("tangents"), VBOCache, VTK_FLOAT);
+    }
+
+    this->VBOs->BuildAllVBOs(VBOCache);
+
+    this->BuildIBO(renderer, actor, polyData);
+    this->VBOBuildTime.Modified();
+}
+
+void
+VTKCustomPolyDataMapper::ReplaceShaderValues(
+    std::map<vtkShader::Type, vtkShader*> vtkNotUsed(shaders),
+    vtkRenderer * vtkNotUsed(renderer),
+    vtkActor * vtkNotUsed(actor))
+{
+}
+
+void
+VTKCustomPolyDataMapper::GetShaderTemplate(
+    std::map<vtkShader::Type, vtkShader*> shaders,
+    vtkRenderer * vtkNotUsed(renderer),
+    vtkActor * actor)
+{
+    this->loadShader("./Shaders/VTKShaders/mesh.vert", m_vertexShaderSource);
+    this->loadShader("./Shaders/VTKShaders/mesh.frag", m_fragmentShaderSource);
+
+    auto renderMaterial = m_geometry->getRenderMaterial();
+
+    auto diffuseTexture = renderMaterial->getTexture(Texture::DIFFUSE);
+    auto cubemapTexture = renderMaterial->getTexture(Texture::CUBEMAP);
+
+    auto surfaceMesh = std::dynamic_pointer_cast<SurfaceMesh>(m_geometry);
+
+    if (this->GetOpenGLMode(actor->GetProperty()->GetRepresentation(), this->LastBoundBO->PrimitiveType) == GL_TRIANGLES)
+    {
+        m_fragmentShaderSource = "#define SHADED\n" + m_fragmentShaderSource;
+    }
+
+    if (diffuseTexture->getPath() != "" && surfaceMesh)
+    {
+        m_fragmentShaderSource = "#define DIFFUSE_TEXTURE\n" + m_fragmentShaderSource;
+    }
+    if (cubemapTexture->getPath() != "" && surfaceMesh)
+    {
+        m_fragmentShaderSource = "#define CUBEMAP_TEXTURE\n" + m_fragmentShaderSource;
+    }
+
+    m_vertexShaderSource = "#version 330\n" + m_vertexShaderSource;
+    m_fragmentShaderSource = "#version 330\n" + m_fragmentShaderSource;
+    shaders[vtkShader::Vertex]->SetSource(m_vertexShaderSource.c_str());
+    shaders[vtkShader::Fragment]->SetSource(m_fragmentShaderSource.c_str());
+}
+
+void
+VTKCustomPolyDataMapper::SetMapperShaderParameters(
+    vtkOpenGLHelper& helper,
+    vtkRenderer * renderer,
+    vtkActor * actor)
+{
+    auto textures = this->GetTextures(actor);
+
+    helper.VAO->Bind();
+
+    this->VBOs->AddAllAttributesToVAO(helper.Program, helper.VAO);
+    auto camera = renderer->GetActiveCamera();
+
+    vtkMatrix4x4 * viewMatrix;
+    vtkMatrix4x4 * projectionMatrix;
+    vtkMatrix3x3 * rotationMatrix;
+    vtkMatrix4x4 * viewProjectionMatrix;
+    vtkMatrix3x3 * modelRotationMatrix;
+    vtkMatrix4x4 * modelMatrix;
+
+    ((vtkOpenGLCamera*)camera)->GetKeyMatrices(renderer, viewMatrix, rotationMatrix, projectionMatrix, viewProjectionMatrix);
+    ((vtkOpenGLActor*)actor)->GetKeyMatrices(modelMatrix, modelRotationMatrix);
+
+    // Per renderer: 16 light limit for iMSTK, VTK supports 6
+    float lightPosition[16][3]; // 3 float position
+    int lightType[16]; // 1 bool directional vs. point light
+    float lightColor[16][4]; // 3 float color, 1 float intensity
+    float lightDirection[16][4]; // 3 float direction, 1 float angle
+
+    auto lights = renderer->GetLights();
+    lights->InitTraversal();
+
+    for (unsigned int i = 0; i < 16; i++)
+    {
+        auto light = lights->GetNextItem();
+
+        if (light)
+        {
+            lightPosition[i][0] = light->GetPosition()[0];
+            lightPosition[i][1] = light->GetPosition()[1];
+            lightPosition[i][2] = light->GetPosition()[2];
+
+            if (light->GetPositional())
+            {
+                lightType[i] = 2;
+
+                if (light->GetConeAngle() < 178.0)
+                {
+                    lightType[i] = 3;
+                }
+            }
+            else
+            {
+                lightType[i] = 1;
+            }
+
+            lightColor[i][0] = light->GetDiffuseColor()[0];
+            lightColor[i][1] = light->GetDiffuseColor()[1];
+            lightColor[i][2] = light->GetDiffuseColor()[2];
+            lightColor[i][3] = light->GetIntensity();
+
+            lightDirection[i][0] = light->GetFocalPoint()[0] - light->GetPosition()[0];
+            lightDirection[i][1] = light->GetFocalPoint()[1] - light->GetPosition()[1];
+            lightDirection[i][2] = light->GetFocalPoint()[2] - light->GetPosition()[2];
+            lightDirection[i][3] = std::abs(std::cos(vtkMath::RadiansFromDegrees(light->GetConeAngle())));
+        }
+        else
+        {
+            lightType[i] = 0;
+        }
+    }
+
+    helper.Program->SetUniform3fv("lightPosition", 16,
+        lightPosition);
+    helper.Program->SetUniform1iv("lightType", 16,
+        lightType);
+    helper.Program->SetUniform4fv("lightColor", 16,
+        lightColor);
+    helper.Program->SetUniform4fv("lightDirection", 16,
+        lightDirection);
+
+    // Per camera
+    helper.Program->SetUniformMatrix("projectionMatrix",
+        projectionMatrix);
+    helper.Program->SetUniformMatrix("viewMatrix",
+        viewMatrix);
+
+    auto cameraPosition = camera->GetPosition();
+    float cameraPos[3] = { (float)cameraPosition[0],
+                           (float)cameraPosition[1],
+                           (float)cameraPosition[2] };
+
+    helper.Program->SetUniform3f("cameraPosition",
+        cameraPos);
+    helper.Program->SetUniformi("numLights", lights->GetNumberOfItems());
+
+    // Per model
+    helper.Program->SetUniformMatrix("modelMatrix",
+        modelMatrix);
+    helper.Program->SetUniformMatrix("normalMatrix",
+        modelRotationMatrix);
+
+    helper.AttributeUpdateTime.Modified();
+
+    helper.Program->SetUniformf("metalness", m_geometry->getRenderMaterial()->getMetalness());
+    helper.Program->SetUniformf("roughness", m_geometry->getRenderMaterial()->getRoughness());
+
+    unsigned int textureCount = 0;
+    unsigned int currentTexture = 0;
+
+    auto renderWindow = (vtkOpenGLRenderWindow*)(renderer->GetRenderWindow());
+
+    if (this->GetOpenGLMode(actor->GetProperty()->GetRepresentation(), helper.PrimitiveType) == GL_TRIANGLES)
+    {
+        auto diffuseTexture = m_geometry->getRenderMaterial()->getTexture(Texture::DIFFUSE);
+        if (diffuseTexture->getPath() != "" && textureCount < textures.size())
+        {
+            auto texture = (vtkOpenGLTexture*)textures[currentTexture];
+            helper.Program->SetUniformi("diffuseTexture", texture->GetTextureUnit());
+            renderWindow->DeactivateTexture(texture->GetTextureObject());
+            currentTexture++;
+        }
+
+        auto cubemapTexture = m_geometry->getRenderMaterial()->getTexture(Texture::CUBEMAP);
+        if (cubemapTexture->getPath() != "" && textureCount < textures.size())
+        {
+            auto texture = (vtkOpenGLTexture*)textures[currentTexture];
+            helper.Program->SetUniformi("cubemapTexture", texture->GetTextureUnit());
+            renderWindow->DeactivateTexture(texture->GetTextureObject());
+            currentTexture++;
+        }
+    }
+}
+
+void
+VTKCustomPolyDataMapper::SetPropertyShaderParameters(
+    vtkOpenGLHelper& vtkNotUsed(helper),
+    vtkRenderer * vtkNotUsed(renderer),
+    vtkActor * vtkNotUsed(actor))
+{
+}
+
+void
+VTKCustomPolyDataMapper::SetLightingShaderParameters(
+    vtkOpenGLHelper& vtkNotUsed(helper),
+    vtkRenderer * vtkNotUsed(renderer),
+    vtkActor * vtkNotUsed(actor))
+{
+}
+
+void
+VTKCustomPolyDataMapper::SetCameraShaderParameters(
+    vtkOpenGLHelper& vtkNotUsed(helper),
+    vtkRenderer * vtkNotUsed(renderer),
+    vtkActor * vtkNotUsed(actor))
+{
+}
+
+void
+VTKCustomPolyDataMapper::UpdateShaders(
+    vtkOpenGLHelper& helper,
+    vtkRenderer * renderer,
+    vtkActor * actor)
+{
+    vtkOpenGLPolyDataMapper::UpdateShaders(helper, renderer, actor);
+}
+
+void
+VTKCustomPolyDataMapper::loadShader(const std::string filename, std::string& source)
+{
+    std::stringstream stream;
+    std::ifstream file(filename);
+    stream << file.rdbuf();
+    source = stream.str();
+    file.close();
+}
+
+void
+VTKCustomPolyDataMapper::setGeometry(std::shared_ptr<Geometry> geometry)
+{
+    m_geometry = geometry;
+}
+}
\ No newline at end of file
diff --git a/Base/Rendering/imstkVTKCustomPolyDataMapper.h b/Base/Rendering/imstkVTKCustomPolyDataMapper.h
new file mode 100644
index 0000000000000000000000000000000000000000..3a468ee46fbb126aad43a3dba54420c00f64a244
--- /dev/null
+++ b/Base/Rendering/imstkVTKCustomPolyDataMapper.h
@@ -0,0 +1,151 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkVTKCustomPolyDataMapper_h
+#define imstkVTKCustomPolyDataMapper_h
+
+#include <fstream>
+#include <sstream>
+
+#include "vtkOpenGLPolyDataMapper.h"
+#include "vtkOpenGLBufferObject.h"
+#include "vtkObjectFactory.h"
+#include "vtkActor.h"
+#include "vtkProperty.h"
+#include "vtkOpenGLVertexArrayObject.h"
+#include "vtkOpenGLVertexBufferObject.h"
+#include "vtkOpenGLVertexBufferObjectCache.h"
+#include "vtkOpenGLVertexBufferObjectGroup.h"
+#include "vtkOpenGLRenderWindow.h"
+#include "vtkRenderWindow.h"
+#include "vtkShaderProgram.h"
+#include "vtkRenderer.h"
+#include "vtkCamera.h"
+#include "vtkMatrix4x4.h"
+#include "vtkOpenGLCamera.h"
+#include "vtkOpenGLActor.h"
+#include "vtkPolyData.h"
+#include "vtkPointData.h"
+#include "vtkLightCollection.h"
+#include "vtkLight.h"
+#include "vtkOpenGLTexture.h"
+#include "vtkOpenGLError.h"
+
+#include "imstkGeometry.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkRenderMaterial.h"
+
+namespace imstk
+{
+///
+/// \class VTKCustomPolyDataMapper
+///
+/// \brief Custom interface between shaders and iMSTK.
+///
+/// This class overrides behavior in VTK regarding shading.
+///
+class VTKCustomPolyDataMapper : public vtkOpenGLPolyDataMapper
+{
+public:
+    vtkTypeMacro(VTKCustomPolyDataMapper, vtkOpenGLPolyDataMapper);
+
+    static VTKCustomPolyDataMapper * New();
+
+    void setGeometry(std::shared_ptr<Geometry> geometry);
+
+protected:
+    ///
+    /// \brief Sets up the VBO and VAO
+    ///
+    void BuildBufferObjects(vtkRenderer * renderer, vtkActor * actor) override;
+
+    ///
+    /// \brief Overridden method to prevent shader overwriting
+    ///
+    virtual void ReplaceShaderValues(
+        std::map<vtkShader::Type, vtkShader*> shaders,
+        vtkRenderer * renderer,
+        vtkActor * actor) override;
+
+    ///
+    /// \brief Loads the shader and injects preprocessor commands
+    ///
+    virtual void GetShaderTemplate(
+        std::map<vtkShader::Type, vtkShader*> shaders,
+        vtkRenderer * renderer,
+        vtkActor * actor) override;
+
+    ///
+    /// \brief Does all of the uniform/texture setting
+    ///
+    virtual void SetMapperShaderParameters(
+        vtkOpenGLHelper& helper,
+        vtkRenderer * renderer,
+        vtkActor * actor) override;
+
+    ///
+    /// \brief Overwritten to prevent extra uniform assignment
+    ///
+    virtual void SetCameraShaderParameters(
+        vtkOpenGLHelper& helper,
+        vtkRenderer * renderer,
+        vtkActor * actor) override;
+
+    ///
+    /// \brief Overwritten to prevent extra uniform assignment
+    ///
+    virtual void SetLightingShaderParameters(
+        vtkOpenGLHelper& helper,
+        vtkRenderer * renderer,
+        vtkActor * actor) override;
+
+    ///
+    /// \brief Overwritten to prevent extra uniform assignment
+    ///
+    virtual void SetPropertyShaderParameters(
+        vtkOpenGLHelper& helper,
+        vtkRenderer * renderer,
+        vtkActor * actor) override;
+
+    ///
+    /// \brief Allows for debugging interaction with VTK
+    ///
+    virtual void UpdateShaders(vtkOpenGLHelper& helper,
+                               vtkRenderer * renderer,
+                               vtkActor * actor) override;
+
+    ///
+    /// \brief Loads a shader
+    ///
+    void loadShader(const std::string filename, std::string& source);
+
+    std::shared_ptr<Geometry> m_geometry; ///< Geometry reference
+
+    std::string m_vertexShaderSource = ""; ///< Source for vertex shader
+    std::string m_fragmentShaderSource = ""; ///< Source for fragment shader
+
+    vtkOpenGLBufferObject * m_positionsVBO; ///< Vertex positions VBO
+    vtkOpenGLBufferObject * m_normalsVBO; ///< Vertex normals VBO
+    vtkOpenGLBufferObject * m_uvVBO; ///< Vertex UVs VBO
+};
+}
+
+#endif
\ No newline at end of file
diff --git a/Base/Rendering/imstkVTKRenderer.cpp b/Base/Rendering/imstkVTKRenderer.cpp
index a050dc44930b3b04a43b48a53f1d31982ff22bad..2e1abb76247f7ad622d07c6b1e3ce777dad6a1df 100644
--- a/Base/Rendering/imstkVTKRenderer.cpp
+++ b/Base/Rendering/imstkVTKRenderer.cpp
@@ -74,7 +74,8 @@ VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene)
     for ( const auto& light : scene->getLights() )
     {
         m_vtkLights.push_back( light->getVtkLight() );
-        if( light->isPositional() )
+        if (light->getType() == LightType::POINT_LIGHT ||
+            light->getType() == LightType::SPOT_LIGHT)
         {
             auto lightActor = vtkSmartPointer<vtkLightActor>::New();
             lightActor->SetLight( light->getVtkLight() );
diff --git a/Base/Rendering/imstkVTKTextureDelegate.cpp b/Base/Rendering/imstkVTKTextureDelegate.cpp
index 7a0d081a8c59622148c05ba9b28240022f6cc019..6978600469ece248f8c3ba4d2554baa15fba736e 100644
--- a/Base/Rendering/imstkVTKTextureDelegate.cpp
+++ b/Base/Rendering/imstkVTKTextureDelegate.cpp
@@ -37,20 +37,56 @@ VTKTextureDelegate::loadTexture(std::shared_ptr<Texture> texture)
 
     auto readerFactory = vtkSmartPointer<vtkImageReader2Factory>::New();
 
-    // Read texture image
-    auto imgReader = readerFactory->CreateImageReader2(texture->getPath().c_str());
-    if (!imgReader)
+    m_sourceTexture = vtkSmartPointer<vtkTexture>::New();
+
+    if (texture->getType() == Texture::CUBEMAP)
     {
-        LOG(WARNING) << "VTKTextureDelegate::loadTexture error: could not find reader for "
-                     << tFileName;
-        return;
+        std::string sideNames[6] = {"posx", "negx", "posy", "negy", "posz", "negz"};
+        m_sourceTexture->SetCubeMap(true);
+
+        for (int i = 0; i < 6; i++)
+        {
+            vtkImageReader2 * imgReader;
+
+            auto index = tFileName.find(".");
+            auto tempName = tFileName.substr(0, index);
+            auto extension = tFileName.substr(index);
+            auto sideName = tempName + sideNames[i] + extension;
+
+            imgReader = readerFactory->CreateImageReader2(sideName.c_str());
+
+            if (!imgReader)
+            {
+                LOG(WARNING) << "VTKTextureDelegate::loadTexture error: could not find reader for "
+                             << sideName;
+                return;
+            }
+
+            auto imageFlip = vtkSmartPointer<vtkImageFlip>::New();
+            imageFlip->SetFilteredAxis(1);
+            imgReader->SetFileName(sideName.c_str());
+            imgReader->Update();
+            imageFlip->SetInputConnection(imgReader->GetOutputPort());
+            m_sourceTexture->SetInputConnection(i, imageFlip->GetOutputPort());
+        }
     }
+    else
+    {
+        vtkImageReader2 * imgReader;
+        imgReader = readerFactory->CreateImageReader2(tFileName.c_str());
 
-    imgReader->SetFileName(tFileName.c_str());
-    imgReader->Update();
-    m_sourceTexture = vtkSmartPointer<vtkTexture>::New();
-    m_sourceTexture->SetInputConnection(imgReader->GetOutputPort());
-    m_sourceTexture->SetBlendingMode(vtkTexture::VTK_TEXTURE_BLENDING_MODE_ADD);
-    m_sourceTexture->RepeatOff();
+        if (!imgReader)
+        {
+            LOG(WARNING) << "VTKTextureDelegate::loadTexture error: could not find reader for "
+                         << tFileName;
+            return;
+        }
+
+        imgReader->SetFileName(tFileName.c_str());
+        imgReader->Update();
+        m_sourceTexture->SetBlendingMode(vtkTexture::VTK_TEXTURE_BLENDING_MODE_ADD);
+        m_sourceTexture->RepeatOff();
+        m_sourceTexture->SetInputConnection(imgReader->GetOutputPort());
+    }
 }
 }
diff --git a/Base/Rendering/imstkVTKTextureDelegate.h b/Base/Rendering/imstkVTKTextureDelegate.h
index 52bae8ac202cdc06e045e2da7907292f500794b6..7e48b573ad3325ec9cb5bea4199df82c8ba64565 100644
--- a/Base/Rendering/imstkVTKTextureDelegate.h
+++ b/Base/Rendering/imstkVTKTextureDelegate.h
@@ -30,6 +30,7 @@
 #include <vtkSmartPointer.h>
 #include <vtkImageReader2Factory.h>
 #include <vtkImageReader2.h>
+#include <vtkImageFlip.h>
 
 #include <string>
 #include <memory>
diff --git a/Base/SceneElements/Light/imstkLight.cpp b/Base/SceneElements/Light/imstkLight.cpp
index 9aeaf539e2adb57ecbcb86846674fd7ea02e1456..7a8243fcf4857dca379065c758071274153b795a 100644
--- a/Base/SceneElements/Light/imstkLight.cpp
+++ b/Base/SceneElements/Light/imstkLight.cpp
@@ -25,32 +25,20 @@
 
 namespace imstk
 {
-const LightType
+LightType
 Light::getType()
 {
-    if( m_vtkLight->LightTypeIsSceneLight() )
-    {
-        return LightType::SCENE_LIGHT;
-    }
-
-    return LightType::HEAD_LIGHT;
+    return m_type;
 }
 
 void
 Light::setType(const LightType& type)
 {
-    if( type == LightType::SCENE_LIGHT )
-    {
-        m_vtkLight->SetLightTypeToSceneLight();
-    }
-    else
-    {
-        m_vtkLight->SetLightTypeToHeadlight();
-    }
+    m_type = type;
 }
 
 const Vec3d
-Light::getPosition() const
+PointLight::getPosition() const
 {
     double p[3];
     m_vtkLight->GetPosition(p);
@@ -58,17 +46,16 @@ Light::getPosition() const
 }
 
 void
-Light::setPosition(const Vec3d& p)
+PointLight::setPosition(const Vec3d& p)
 {
     this->setPosition(p[0], p[1], p[2]);
 }
 
 void
-Light::setPosition(const double& x,
-                   const double& y,
-                   const double& z)
+PointLight::setPosition(const double& x,
+                        const double& y,
+                        const double& z)
 {
-    this->warningIfHeadLight();
     m_vtkLight->SetPosition(x, y, z);
 }
 
@@ -91,14 +78,13 @@ Light::setFocalPoint(const double& x,
                      const double& y,
                      const double& z)
 {
-    this->warningIfHeadLight();
     m_vtkLight->SetFocalPoint(x, y, z);
 }
 
-const bool
+bool
 Light::isOn()
 {
-    return m_vtkLight->GetSwitch();
+    return m_vtkLight->GetSwitch() != 0;
 }
 
 void
@@ -107,7 +93,7 @@ Light::switchOn()
     m_vtkLight->SwitchOn();
 }
 
-const bool
+bool
 Light::isOff()
 {
     return !this->isOn();
@@ -119,38 +105,14 @@ Light::switchOff()
     m_vtkLight->SwitchOff();
 }
 
-const bool
-Light::isPositional()
-{
-    return m_vtkLight->GetPositional();
-}
-
-void
-Light::setPositional()
-{
-    m_vtkLight->PositionalOn();
-}
-
-const bool
-Light::isDirectional()
-{
-    return !this->isPositional();
-}
-
-void
-Light::setDirectional()
-{
-    m_vtkLight->PositionalOff();
-}
-
-const double
-Light::getSpotAngle() const
+double
+SpotLight::getSpotAngle() const
 {
     return m_vtkLight->GetConeAngle();
 }
 
 void
-Light::setSpotAngle(const double& angle)
+SpotLight::setSpotAngle(const double& angle)
 {
     m_vtkLight->SetConeAngle(angle);
 }
@@ -166,7 +128,19 @@ Light::getColor() const
 void
 Light::setColor(const Color& c)
 {
-    m_vtkLight->SetDiffuseColor(c(0), c(1), c(2));
+    m_vtkLight->SetColor(c(0), c(1), c(2));
+}
+
+float
+Light::getIntensity() const
+{
+    return m_vtkLight->GetIntensity();
+}
+
+void
+Light::setIntensity(const float intensity)
+{
+    m_vtkLight->SetIntensity(intensity);
 }
 
 vtkSmartPointer<vtkLight>
@@ -186,16 +160,4 @@ Light::setName(std::string name)
 {
     m_name = name;
 }
-
-void
-Light::warningIfHeadLight()
-{
-    if( this->getType() == LightType::HEAD_LIGHT )
-    {
-        LOG(WARNING) << "Can not change position or focal point "
-                     << "for a HEAD_LIGHT (linked to the active camera).\n"
-                     << "Set your light type to SCENE_LIGHT to manually "
-                     << "edit those parameters.";
-    }
-}
 } // imstk
diff --git a/Base/SceneElements/Light/imstkLight.h b/Base/SceneElements/Light/imstkLight.h
index df2a42ba3c8366a62740eb0b50f02b52d14300e9..31795810e90c8f64e6323b099c510533510a6628 100644
--- a/Base/SceneElements/Light/imstkLight.h
+++ b/Base/SceneElements/Light/imstkLight.h
@@ -39,14 +39,15 @@ namespace imstk
 ///
 enum class LightType
 {
-    SCENE_LIGHT,
-    HEAD_LIGHT
+    DIRECTIONAL_LIGHT,
+    POINT_LIGHT,
+    SPOT_LIGHT
 };
 
 ///
 /// \class Light
 ///
-/// \brief Generic class for scene lights
+/// \brief Abstract class for lights
 ///
 class Light
 {
@@ -54,17 +55,7 @@ public:
     ///
     /// \brief
     ///
-    Light(std::string name) : m_name(name) {}
-
-    ///
-    /// \brief
-    ///
-    ~Light() = default;
-
-    ///
-    /// \brief
-    ///
-    const LightType getType();
+    LightType getType();
 
     ///
     /// \brief
@@ -72,25 +63,12 @@ public:
     void setType(const LightType& type);
 
     ///
-    /// \brief
-    ///
-    const Vec3d getPosition() const;
-
-    ///
-    /// \brief
-    ///
-    void setPosition(const Vec3d& p);
-    void setPosition(const double& x,
-                     const double& y,
-                     const double& z);
-
-    ///
-    /// \brief
+    /// \brief Get the light focal point
     ///
     const Vec3d getFocalPoint() const;
 
     ///
-    /// \brief
+    /// \brief Set the light focal point
     ///
     void setFocalPoint(const Vec3d& p);
     void setFocalPoint(const double& x,
@@ -100,7 +78,7 @@ public:
     ///
     /// \brief
     ///
-    const bool isOn();
+    bool isOn();
 
     ///
     /// \brief
@@ -110,7 +88,7 @@ public:
     ///
     /// \brief
     ///
-    const bool isOff();
+    bool isOff();
 
     ///
     /// \brief
@@ -118,68 +96,124 @@ public:
     void switchOff();
 
     ///
-    /// \brief
+    /// \brief Get the light color
     ///
-    const bool isPositional();
+    const Color getColor() const;
 
     ///
-    /// \brief
+    /// \brief Set the light color
     ///
-    void setPositional();
+    void setColor(const Color& c);
 
     ///
-    /// \brief
+    /// \brief Get the light intensity
     ///
-    const bool isDirectional();
+    float getIntensity() const;
 
     ///
-    /// \brief
+    /// \brief Set the light intensity. This value is unbounded.
     ///
-    void setDirectional();
+    void setIntensity(float intensity);
 
     ///
-    /// \brief
+    /// \brief Get the VTK light
     ///
-    const double getSpotAngle() const;
+    vtkSmartPointer<vtkLight> getVtkLight() const;
 
     ///
-    /// \brief
+    /// \brief Get the light name
     ///
-    void setSpotAngle(const double& angle);
+    const std::string& getName() const;
 
     ///
-    /// \brief
+    /// \brief Set the light name
     ///
-    const Color getColor() const;
+    void setName(std::string name);
 
-    ///
-    /// \brief
-    ///
-    void setColor(const Color& c);
+protected:
+    Light(std::string name)
+    {
+        m_name = name;
+    };
+
+    vtkSmartPointer<vtkLight> m_vtkLight = vtkSmartPointer<vtkLight>::New();
+    std::string m_name;
+    LightType m_type;
+};
+
+///
+/// \class DirectionalLight
+///
+/// \brief Directional light class
+///
+/// A directional light has no position or range. The focal point is the
+/// direction.
+///
+class DirectionalLight : public Light
+{
+public:
+    DirectionalLight(std::string name) : Light(name)
+    {
+        m_type = LightType::DIRECTIONAL_LIGHT;
+        m_vtkLight->SetPositional(false);
+    };
+};
+
+///
+/// \class PointLight
+///
+/// \brief Point light class
+///
+/// A point light has a position, and it's range is determined by it's
+/// intensity.
+///
+class PointLight : public Light
+{
+public:
+    PointLight(std::string name) : Light(name)
+    {
+        m_type = LightType::POINT_LIGHT;
+        m_vtkLight->SetPositional(true);
+        m_vtkLight->SetConeAngle(179.0);
+    };
 
     ///
-    /// \brief
+    /// \brief Get the light position
     ///
-    vtkSmartPointer<vtkLight> getVtkLight() const;
+    const Vec3d getPosition() const;
 
     ///
-    /// \brief
+    /// \brief Set the light position
     ///
-    const std::string& getName() const;
+    void setPosition(const Vec3d& p);
+    void setPosition(const double& x,
+                     const double& y,
+                     const double& z);
+};
+
+///
+/// \class Spot light class
+///
+/// \brief A spot light is a point light in a cone shape.
+///
+class SpotLight : public PointLight
+{
+public:
+    SpotLight(std::string name) : PointLight(name)
+    {
+        m_type = LightType::SPOT_LIGHT;
+        m_vtkLight->SetConeAngle(45);
+    };
 
     ///
-    /// \brief
+    /// \brief Get the spotlight angle in degrees
     ///
-    void setName(std::string name);
+    double getSpotAngle() const;
 
-protected:
     ///
-    /// \brief
+    /// \brief Set the spotlight angle in degrees
     ///
-    void warningIfHeadLight();
-
-    vtkSmartPointer<vtkLight> m_vtkLight = vtkSmartPointer<vtkLight>::New();
-    std::string m_name;
+    void setSpotAngle(const double& angle);
 };
 } // imstk
 
diff --git a/Base/SimulationManager/imstkVTKInteractorStyle.h b/Base/SimulationManager/imstkVTKInteractorStyle.h
index 49548804a07ce7bf39ae18160c4fa6294e613c4a..3ce8925e0d7900b51a4c0150df0239cb441898ec 100644
--- a/Base/SimulationManager/imstkVTKInteractorStyle.h
+++ b/Base/SimulationManager/imstkVTKInteractorStyle.h
@@ -114,6 +114,14 @@ public:
     ///
     virtual void OnMouseWheelBackward() override;
 
+    ///
+    /// \brief Not implemented
+    ///
+    virtual void OnFourthButtonDown(){};
+    virtual void OnFifthButtonDown(){};
+    virtual void OnFourthButtonUp(){};
+    virtual void OnFifthButtonUp(){};
+
 private:
 
     VTKInteractorStyle();
diff --git a/CMake/External/External_VTK.cmake b/CMake/External/External_VTK.cmake
index 573ddb24d2be6133670fb84fdf4adfa63ef670a2..4c6add183b0bc9c924360aa5c0c66adf7cd7b76a 100644
--- a/CMake/External/External_VTK.cmake
+++ b/CMake/External/External_VTK.cmake
@@ -4,7 +4,7 @@
 include(imstkAddExternalProject)
 imstk_add_external_project( VTK
   GIT_REPOSITORY https://gitlab.kitware.com/vtk/vtk.git
-  GIT_TAG 1f89d2d1acf154522cbaab67766066c72817659e
+  GIT_TAG 7b563776b89f829b382ba080d8963a04d7a47ecc
   INSTALL_COMMAND ${SKIP_STEP_COMMAND}
   CMAKE_ARGS
       -DBUILD_EXAMPLES:BOOL=OFF
diff --git a/Data/textures/cubemaps/ReadMe.txt.sha512 b/Data/textures/cubemaps/ReadMe.txt.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..c0ff8b2fbd48f5f22e82d0e625797491b3e5ff14
--- /dev/null
+++ b/Data/textures/cubemaps/ReadMe.txt.sha512
@@ -0,0 +1 @@
+e2a19c63c27545b5b65daca51f9f8cb7325840beede5adea0b456ec042fed34f20cd609d48d36f046bdb3908705c1bb3fdbcb43dd256f6da18a9b1260ab2e068
\ No newline at end of file
diff --git a/Data/textures/cubemaps/clouds1_negx.jpg.sha512 b/Data/textures/cubemaps/clouds1_negx.jpg.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..db08cf70cd992a57a57af553ad79e969875e7c7d
--- /dev/null
+++ b/Data/textures/cubemaps/clouds1_negx.jpg.sha512
@@ -0,0 +1 @@
+fd0f4aa0b45cf6847837f478def9415ff01ffa06445151949448445c7155b014b24793e1dca0d1ff5b18705fa256a893f06736ea140686ba7ded7313464017a0
\ No newline at end of file
diff --git a/Data/textures/cubemaps/clouds1_negy.jpg.sha512 b/Data/textures/cubemaps/clouds1_negy.jpg.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..b4d1577532c8faf81f0ecdc775e25469407418d3
--- /dev/null
+++ b/Data/textures/cubemaps/clouds1_negy.jpg.sha512
@@ -0,0 +1 @@
+2b9f3f9146a0e6eb209bd2b1bd4d209931fdfffab237604fcf35d77684b3f8223757380067071695db71b5de91d7ebf120df0841614246320f243ae7cb51f18a
\ No newline at end of file
diff --git a/Data/textures/cubemaps/clouds1_negz.jpg.sha512 b/Data/textures/cubemaps/clouds1_negz.jpg.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..890fb1ab507e23af20969e727f9faad28b95bf5a
--- /dev/null
+++ b/Data/textures/cubemaps/clouds1_negz.jpg.sha512
@@ -0,0 +1 @@
+ab901d0468fe7ce7652a0e9681626c501229d3344d81f579c3dae93e3f401e02b639b8eedb5a7f3b48d9604443665ee96ed888c26c17ceca31b14b6c25ca56fd
\ No newline at end of file
diff --git a/Data/textures/cubemaps/clouds1_posx.jpg.sha512 b/Data/textures/cubemaps/clouds1_posx.jpg.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..a1d2464be80dc4fdbce01717527cd82d26cd1aaa
--- /dev/null
+++ b/Data/textures/cubemaps/clouds1_posx.jpg.sha512
@@ -0,0 +1 @@
+8180436fbfd924674a3b5c4d704a3d0fcdb8ea7931faa469ec83a9a6f3b04392512274a9bf1bed11eb7c8acd0d33eaeb1c099ac2ecf421e981e4feeea018555c
\ No newline at end of file
diff --git a/Data/textures/cubemaps/clouds1_posy.jpg.sha512 b/Data/textures/cubemaps/clouds1_posy.jpg.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..cdc46545c6ceb70fa0524bd9be806c81367d0ba0
--- /dev/null
+++ b/Data/textures/cubemaps/clouds1_posy.jpg.sha512
@@ -0,0 +1 @@
+bc1bb434e3a19ad24f56f5c109707a88718421cf6ea101832f94fb8c6ce6aa4d2291dffc7007af1b2cc6453186ce5d5179b85b91dacdfa094acaf7bc6420fd01
\ No newline at end of file
diff --git a/Data/textures/cubemaps/clouds1_posz.jpg.sha512 b/Data/textures/cubemaps/clouds1_posz.jpg.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..f0a29bd2122acaf5bbcb89fecda256d887631267
--- /dev/null
+++ b/Data/textures/cubemaps/clouds1_posz.jpg.sha512
@@ -0,0 +1 @@
+27d1e12f315410d4508c12394c2ab6f4aa096c5c05c108d32b8143b19af679f83206ac3f9d7018dfd3812a3769f4aaa5bf8e61d4a04d0f0c86b1ed929a378362
\ No newline at end of file
diff --git a/Examples/Sandbox/CMakeLists.txt b/Examples/Sandbox/CMakeLists.txt
index 79c5e3b9292eaa55350c5c65eb72b6fd9c821152..7e592751371e1ddf50ebc7a5a64a6db64b0947c0 100644
--- a/Examples/Sandbox/CMakeLists.txt
+++ b/Examples/Sandbox/CMakeLists.txt
@@ -50,6 +50,15 @@ list(APPEND FILE_LIST
     tetBeads/,REGEX:.*
     textured_organs/,REGEX:.*
     textured_organs/texture_set_1/,REGEX:.*
-    textured_organs/texture_set_2/,REGEX:.*)
+    textured_organs/texture_set_2/,REGEX:.*
+    textures/cubemaps/,REGEX:.*)
 
 imstk_add_data(${PROJECT_NAME} ${FILE_LIST})
+
+#-----------------------------------------------------------------------------
+# Shaders
+#-----------------------------------------------------------------------------
+file(COPY ${CMAKE_SOURCE_DIR}/Base/Rendering/VTKShaders
+  DESTINATION ${PROJECT_BINARY_DIR}/Shaders)
+file(COPY ${CMAKE_SOURCE_DIR}/Base/Rendering/VTKShaders
+  DESTINATION ${CMAKE_PROGRAM_PATH}/Shaders)
\ No newline at end of file
diff --git a/Examples/Sandbox/main.cpp b/Examples/Sandbox/main.cpp
index 4b09a66da9e7a47a076d024d516609c207dd8821..08ab9f2204fa0e2d58b240fd3474a1135fe6267c 100644
--- a/Examples/Sandbox/main.cpp
+++ b/Examples/Sandbox/main.cpp
@@ -148,7 +148,7 @@ int main()
     /*------------------
     Test rendering
     ------------------*/
-    //testMultiObjectWithTextures();
+    testMultiObjectWithTextures();
     //testViewer();
     //testScreenShotUtility();
     //testCapsule();
@@ -208,9 +208,9 @@ int main()
     ------------------*/
     //testScenesManagement();
     //testVectorPlotters();
-    testVirtualCoupling();
+    //testVirtualCoupling();
     //testBoneDrilling();
-    testVirtualCouplingCylinder();
+    //testVirtualCouplingCylinder();
 
 
     return 0;
@@ -252,6 +252,12 @@ void testLapToolController()
     cam->setPosition(imstk::Vec3d(0, 30, 60));
     cam->setFocalPoint(imstk::Vec3d(0, 0, 0));
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -312,6 +318,12 @@ void testMshAndVegaIO()
     scene->addSceneObject(objectA);
     scene->addSceneObject(objectB);
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -324,14 +336,17 @@ void testMultiObjectWithTextures()
     auto scene = sdk->createNewScene("multiObjectWithTexturesTest");
 
     // Read surface mesh
-    auto objMesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/textured_organs/heart.obj");
+    auto objMesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
     auto surfaceMesh = std::dynamic_pointer_cast<imstk::SurfaceMesh>(objMesh);
     surfaceMesh->translate(-8, 0, 0, Geometry::TransformType::ApplyToData);
 
     // Read and setup texture/material
-    auto texture = std::make_shared<Texture>(iMSTK_DATA_ROOT "/textured_organs/texture_set_1/diffuse.png");
+    auto diffuseTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "/textured_organs/texture_set_1/diffuse.png");
+    auto cubemapTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "/textures/cubemaps/clouds1_.jpg", Texture::CUBEMAP);
     auto material = std::make_shared<RenderMaterial>();
-    material->addTexture(texture);
+    material->addTexture(diffuseTexture);
+    material->addTexture(cubemapTexture);
+    material->setRoughness(1.0);
     surfaceMesh->setRenderMaterial(material);
 
     // Create object and add to scene
@@ -345,15 +360,19 @@ void testMultiObjectWithTextures()
     if (secondObject)
     {
         // Read surface mesh1
-        auto objMesh1 = imstk::MeshIO::read(iMSTK_DATA_ROOT "/textured_organs/heart.obj");
+        auto objMesh1 = imstk::MeshIO::read(iMSTK_DATA_ROOT "/spheres/big.vtk");
         auto surfaceMesh1 = std::dynamic_pointer_cast<imstk::SurfaceMesh>(objMesh1);
 
         // Read and setup texture/material
         if (secondObjectTexture)
         {
-            auto texture1 = std::make_shared<Texture>(iMSTK_DATA_ROOT "/textured_organs/texture_set_2/diffuse.png");
+            auto diffuseTexture1 = std::make_shared<Texture>(iMSTK_DATA_ROOT "/textured_organs/texture_set_2/diffuse.png");
+            auto cubemapTexture1 = std::make_shared<Texture>(iMSTK_DATA_ROOT "/textures/cubemaps/clouds1_.jpg", Texture::CUBEMAP);
             auto material1 = std::make_shared<RenderMaterial>();
-            material1->addTexture(texture1);
+            material1->addTexture(diffuseTexture1);
+            material1->addTexture(cubemapTexture1);
+            material1->setMetalness(1.0);
+            material1->setRoughness(0.0);
             material1->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE);
             surfaceMesh1->setRenderMaterial(material1);
         }
@@ -364,6 +383,12 @@ void testMultiObjectWithTextures()
         scene->addSceneObject(object1);
     }
 
+    // Light (white)
+    auto whiteLight = std::make_shared<imstk::DirectionalLight>("whiteLight");
+    whiteLight->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    whiteLight->setIntensity(10);
+    scene->addLight(whiteLight);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -410,6 +435,12 @@ void testMeshCCD()
         mesh2->setVertexPositions(mesh2_3->getVertexPositions());
     });
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -472,6 +503,12 @@ void testPenaltyRigidCollision()
         CollisionHandling::Type::Penalty,
         CollisionHandling::Type::Penalty);
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -573,6 +610,12 @@ void testTwoFalcons()
 //    falcon1->setPostUpdateCallback(postUpdateFoo);
 //    falcon1->setPostCleanUpCallback(postCleanUpFoo);
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -623,6 +666,12 @@ void testTwoOmnis()
     auto sphere0Geom = sphere0Obj->getVisualGeometry();
     cam->setFocalPoint(Vec3d(-2, 2.5, 0));
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(false);
@@ -664,6 +713,12 @@ void testObjectController()
     cam->setPosition(imstk::Vec3d(0, 0, 10));
     cam->setFocalPoint(geom->getPosition());
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(false);
@@ -711,6 +766,12 @@ void testCameraController()
                                      imstk::CameraController::InvertFlag::rotZ);
 #endif
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -743,6 +804,12 @@ void testReadMesh()
     object->setVisualGeometry(surfaceMesh); // change to any mesh created above
     scene->addSceneObject(object);
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -770,18 +837,18 @@ void testViewer()
         imstk::Geometry::Type::Sphere, sceneTest, "VisualSphere", 0.3, Vec3d(0, 2., 0));
 
     // Light (white)
-    auto whiteLight = std::make_shared<imstk::Light>("whiteLight");
+    auto whiteLight = std::make_shared<imstk::PointLight>("whiteLight");
     whiteLight->setPosition(imstk::Vec3d(5, 8, 5));
-    whiteLight->setPositional();
+    whiteLight->setIntensity(100);
     sceneTest->addLight(whiteLight);
 
     // Light (red)
-    auto colorLight = std::make_shared<imstk::Light>("colorLight");
+    auto colorLight = std::make_shared<imstk::SpotLight>("colorLight");
     colorLight->setPosition(imstk::Vec3d(4, -3, 1));
     colorLight->setFocalPoint(imstk::Vec3d(0, 0, 0));
     colorLight->setColor(imstk::Color::Red);
-    colorLight->setPositional();
-    colorLight->setSpotAngle(15);
+    colorLight->setIntensity(100);
+    colorLight->setSpotAngle(1);
     sceneTest->addLight(colorLight);
 
     // Update Camera
@@ -834,6 +901,12 @@ void testCapsule()
     cam1->setPosition(imstk::Vec3d(5., 5., 5.));
     cam1->setFocalPoint(imstk::Vec3d(1, 1, 0));
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -963,6 +1036,12 @@ void testIsometricMap()
     rigidMap->apply();
     LOG(INFO) << cubeGeom->getPosition();
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    geometryMapTest->addLight(light);
+
     // Start simulation
     sdk->setCurrentScene(geometryMapTest);
     sdk->startSimulation(imstk::VTKRenderer::Mode::DEBUG);
@@ -1312,6 +1391,12 @@ void testDeformableBody()
         LOG(INFO) << "\n-- Post cleanup of " << module->getName() << " module";
     });
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run the simulation
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -1402,6 +1487,12 @@ void testPbdVolume()
     planeObj->setCollidingGeometry(planeGeom);
     scene->addSceneObject(planeObj);
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
 }
@@ -1473,17 +1564,17 @@ void testPbdCloth()
     scene->addNonlinearSolver(pbdSolver);
 
     // Light (white)
-    auto whiteLight = std::make_shared<imstk::Light>("whiteLight");
+    auto whiteLight = std::make_shared<imstk::PointLight>("whiteLight");
     whiteLight->setPosition(imstk::Vec3d(10, 2, 10));
+    whiteLight->setIntensity(100);
     whiteLight->setFocalPoint(imstk::Vec3d(0, -2, 0));
-    whiteLight->setPositional();
 
     // Light (red)
-    auto colorLight = std::make_shared<imstk::Light>("colorLight");
+    auto colorLight = std::make_shared<imstk::SpotLight>("colorLight");
     colorLight->setPosition(imstk::Vec3d(5, -3, 5));
     colorLight->setFocalPoint(imstk::Vec3d(-5, -5, 0));
+    colorLight->setIntensity(100);
     colorLight->setColor(imstk::Color::Red);
-    colorLight->setPositional();
     colorLight->setSpotAngle(15);
 
     // Add in scene
@@ -1830,6 +1921,13 @@ void testPbdCollision()
 
         colGraph->addInteractionPair(pair);
     }
+
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
 }
@@ -2167,6 +2265,13 @@ void testLineMesh()
         scene->getCamera()->setPosition(0, 5, 5);
         scene->getCamera()->setFocalPoint(surfMesh.get()->getInitialVertexPosition(20));
     }
+
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -2203,16 +2308,16 @@ void testScreenShotUtility()
     sphereObj->setVisualGeometry(sphereGeom);
 
     // Light (white)
-    auto whiteLight = std::make_shared<imstk::Light>("whiteLight");
+    auto whiteLight = std::make_shared<imstk::PointLight>("whiteLight");
+    whiteLight->setIntensity(100);
     whiteLight->setPosition(imstk::Vec3d(5, 8, 5));
-    whiteLight->setPositional();
 
     // Light (red)
-    auto colorLight = std::make_shared<imstk::Light>("colorLight");
+    auto colorLight = std::make_shared<imstk::SpotLight>("colorLight");
     colorLight->setPosition(imstk::Vec3d(4, -3, 1));
     colorLight->setFocalPoint(imstk::Vec3d(0, 0, 0));
+    colorLight->setIntensity(100);
     colorLight->setColor(imstk::Color::Red);
-    colorLight->setPositional();
     colorLight->setSpotAngle(15);
 
     // Add in scene
@@ -2331,6 +2436,12 @@ void testDeformableBodyCollision()
     cam->setPosition(imstk::Vec3d(0, 20, 20));
     cam->setFocalPoint(imstk::Vec3d(0, 0, 0));
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -2472,6 +2583,12 @@ void liverToolInteraction()
     cam->setPosition(imstk::Vec3d(0, 20, 20));
     cam->setFocalPoint(imstk::Vec3d(0, 0, 0));
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(true);
@@ -2545,6 +2662,12 @@ void testVirtualCoupling()
     cam->setPosition(imstk::Vec3d(200, 200, 200));
     cam->setFocalPoint(imstk::Vec3d(0, 0, 0));
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     //Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(false);
@@ -2605,6 +2728,12 @@ void testGeometryTransforms()
     cam->setPosition(imstk::Vec3d(0, 30, 30));
     cam->setFocalPoint(imstk::Vec3d(0, 0, 0));
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     // Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(false);
@@ -2798,6 +2927,12 @@ void testBoneDrilling()
 
 #endif
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     //Run
     auto cam = scene->getCamera();
     cam->setPosition(imstk::Vec3d(0, 0, 15));
@@ -2879,6 +3014,12 @@ void testVirtualCouplingCylinder()
     cam->setPosition(imstk::Vec3d(200, 200, 200));
     cam->setFocalPoint(imstk::Vec3d(0, 0, 0));
 
+    // Light
+    auto light = std::make_shared<imstk::DirectionalLight>("light");
+    light->setFocalPoint(imstk::Vec3d(5, -8, -5));
+    light->setIntensity(1);
+    scene->addLight(light);
+
     //Run
     sdk->setCurrentScene(scene);
     sdk->startSimulation(false);