diff --git a/CMake/External/CMakeLists.txt b/CMake/External/CMakeLists.txt
index 7a84bfba365d80e03e33e5c11e2787accaa7245f..166bf7059c8e190d6d19d4d7ed79af3f17c80684 100644
--- a/CMake/External/CMakeLists.txt
+++ b/CMake/External/CMakeLists.txt
@@ -95,7 +95,7 @@ ExternalProject_Add( ${PROJECT_NAME}
     -D${PROJECT_NAME}_BUILD_EXAMPLES:BOOL=${${PROJECT_NAME}_BUILD_EXAMPLES}
     -D${PROJECT_NAME}_BUILD_TESTING:BOOL=${${PROJECT_NAME}_BUILD_TESTING}
     -D${PROJECT_NAME}_USE_OpenHaptics:BOOL=${${PROJECT_NAME}_USE_OpenHaptics}
-    -D${PROJECT_NAME}_USE_MODEL_REDUCTION:BOOL={${PROJECT_NAME}_USE_MODEL_REDUCTION}
+    -D${PROJECT_NAME}_USE_MODEL_REDUCTION:BOOL=${${PROJECT_NAME}_USE_MODEL_REDUCTION}
     -D${PROJECT_NAME}_USE_Vulkan:BOOL=${${PROJECT_NAME}_USE_Vulkan}
     -D${PROJECT_NAME}_ENABLE_AUDIO:BOOL=${${PROJECT_NAME}_ENABLE_AUDIO}
     -D${PROJECT_NAME}_ENABLE_VR:BOOL=${${PROJECT_NAME}_ENABLE_VR}
diff --git a/CMake/External/External_Eigen3.cmake b/CMake/External/External_Eigen3.cmake
index f86d8b8f7324c1c37e15bff616ac944f64e72c3e..7d19d5e75158471d8190680ccbcb6d8b3a3e7201 100644
--- a/CMake/External/External_Eigen3.cmake
+++ b/CMake/External/External_Eigen3.cmake
@@ -3,7 +3,7 @@
 #-----------------------------------------------------------------------------
 include(imstkAddExternalProject)
 imstk_add_external_project( Eigen3
-  URL "https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.gz"
+  URL "https://gitlab.kitware.com/iMSTK/eigen/-/archive/3.3.7/eigen-3.3.7.tar.gz"
   URL_HASH MD5=9e30f67e8531477de4117506fe44669b
   CMAKE_CACHE_ARGS
         -DBUILD_TESTING:BOOL=OFF
diff --git a/CMake/External/External_GTest.cmake b/CMake/External/External_GTest.cmake
index 2e3919db28bfaea740106c071da38dbeca963f82..2fe9d9757da31e54dbe4aa409503ad35acbc4f2b 100644
--- a/CMake/External/External_GTest.cmake
+++ b/CMake/External/External_GTest.cmake
@@ -3,8 +3,8 @@
 #-----------------------------------------------------------------------------
 include(imstkAddExternalProject)
 imstk_add_external_project( GTest
-  URL https://github.com/google/googletest/archive/release-1.10.0.zip
-  URL_MD5 82358affdd7ab94854c8ee73a180fc53
+  URL https://gitlab.kitware.com/iMSTK/googletest/-/archive/release-1.10.0/googletest-release-1.10.0.zip
+  URL_MD5 1878d0300f865cb54df06b220ded5168
   CMAKE_CACHE_ARGS
     -DBUILD_GMOCK:BOOL=ON
     -DBUILD_GTEST:BOOL=ON
diff --git a/CMake/External/External_VTK.cmake b/CMake/External/External_VTK.cmake
index 7b69e0068ca24015a26f994ee53cfd83fcc43e30..03cb81629292f5fa76a9c73d6cbde45da50d614b 100644
--- a/CMake/External/External_VTK.cmake
+++ b/CMake/External/External_VTK.cmake
@@ -1,13 +1,7 @@
 #-----------------------------------------------------------------------------
 # Dependencies
 #-----------------------------------------------------------------------------
-set(VTK_DEPENDENCIES "")
-set(VTK_ENABLE_OPENVR "NO")
-if(${${PROJECT_NAME}_ENABLE_VR})
-  list(APPEND VTK_DEPENDENCIES "openvr")
-  set(VTK_ENABLE_OPENVR "YES")
-endif()
-
+set(VTK_DEPENDENCIES "openvr")
 
 set(${PROJECT_NAME}_VTK_REPO_SOURCE "9.0" CACHE STRING "Select VTK Source Branch/Tag")
 set(VTK_SOURCES "9.0;master;release;nightly-master" CACHE INTERNAL "List of available VTK branch,tags to get")
@@ -15,8 +9,12 @@ set_property(CACHE ${PROJECT_NAME}_VTK_REPO_SOURCE PROPERTY STRINGS ${VTK_SOURCE
 
 set(VTK_MODULE_SETTINGS
   -DVTK_MODULE_ENABLE_VTK_ChartsCore:STRING=YES
+  -DVTK_MODULE_ENABLE_VTK_FiltersCore:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_FiltersExtraction:STRING=YES
+  -DVTK_MODULE_ENABLE_VTK_FiltersGeneral:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_FiltersModeling:STRING=YES
+  -DVTK_MODULE_ENABLE_VTK_ImagingGeneral:STRING=YES
+  -DVTK_MODULE_ENABLE_VTK_ImagingStencil:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_IOExport:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_IOGeometry:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_IOImport:STRING=YES
@@ -31,14 +29,18 @@ set(VTK_MODULE_SETTINGS
   -DVTK_MODULE_ENABLE_VTK_RenderingContext2D:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_RenderingContextOpenGL2:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_RenderingOpenGL2:STRING=YES
-  -DVTK_MODULE_ENABLE_VTK_RenderingOpenVR:STRING=${VTK_ENABLE_OPENVR}
+  -DVTK_MODULE_ENABLE_VTK_RenderingOpenVR:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_RenderingVolumeOpenGL2:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_ViewsContext2D:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_glew:STRING=YES
   -DVTK_BUILD_EXAMPLES:STRING=DONT_WANT
   -DVTK_BUILD_TESTING:STRING=OFF
   -DVTK_GROUP_ENABLE_StandAlone:STRING=DONT_WANT
-  -DVTK_GROUP_ENABLE_Rendering:STRING=DONT_WANT)
+  -DVTK_GROUP_ENABLE_Rendering:STRING=DONT_WANT
+  )
+if (${PROJECT_NAME}_USE_VTK_OSMESA)
+  list(APPEND VTK_MODULE_SETTINGS  -DVTK_DEFAULT_RENDER_WINDOW_OFFSCREEN=1 -DVTK_OPENGL_HAS_OSMESA=1 -DVTK_USE_COCOA=0 -DVTK_USE_X=0)
+endif()
 set(${PROJECT_NAME}_VTK_SOURCE GIT_REPOSITORY https://gitlab.kitware.com/vtk/vtk.git)
 
 if(${PROJECT_NAME}_VTK_REPO_SOURCE EQUAL "9.0")
diff --git a/CMake/External/External_glfw.cmake b/CMake/External/External_glfw.cmake
index ee9acff818f7466812519503db6a5b20acf45433..ade86cf630d32bbdb0961ed0bf84a90beaa37dd7 100644
--- a/CMake/External/External_glfw.cmake
+++ b/CMake/External/External_glfw.cmake
@@ -3,7 +3,7 @@
 #-----------------------------------------------------------------------------
 include(imstkAddExternalProject)
 imstk_add_external_project( glfw
-  URL https://github.com/glfw/glfw/archive/3.2.1.zip
+  URL https://gitlab.kitware.com/iMSTK/glfw/-/archive/3.2.1/glfw-3.2.1.zip
   URL_MD5 cb412cba8daba35d849ddfe78700a210
   CMAKE_ARGS
     -DGLFW_BUILD_DOCS:BOOL=OFF
diff --git a/CMake/External/External_openvr.cmake b/CMake/External/External_openvr.cmake
index 2437d8b4e2580eb62afeaf9c3ef81498d6c71d0a..b83957b23948ca7799be43696402435fac10ef78 100644
--- a/CMake/External/External_openvr.cmake
+++ b/CMake/External/External_openvr.cmake
@@ -1,4 +1,3 @@
-set(_version "1.0.9")
 #-----------------------------------------------------------------------------
 # Set project prefix path
 #-----------------------------------------------------------------------------
@@ -51,8 +50,8 @@ set(copy_openvr_lib_command
 #-----------------------------------------------------------------------------
 include(imstkAddExternalProject)
 imstk_add_external_project( openvr
-  URL "https://github.com/ValveSoftware/openvr/archive/v${_version}.tar.gz"
-  URL_MD5 "0de39e805155cf4e0e907bb181924c48"
+  URL "https://gitlab.kitware.com/iMSTK/openvr/-/archive/v1.12.5/openvr-v1.12.5.tar.gz"
+  URL_MD5 "42c4d1c4a194860aaa4e793b009b99c0"
   DOWNLOAD_DIR ${OPENVR_PREFIX}
   SOURCE_DIR ${OPENVR_EXTRACT_DIR}
   BINARY_DIR ${OPENVR_EXTRACT_DIR}
diff --git a/CMake/Utilities/imstkAddLibrary.cmake b/CMake/Utilities/imstkAddLibrary.cmake
index f124ed858ef0cdad7c997f7ee9997fd1e6b5ddfb..41901e34ae2560f7c77b68dad47003a13e85c274 100644
--- a/CMake/Utilities/imstkAddLibrary.cmake
+++ b/CMake/Utilities/imstkAddLibrary.cmake
@@ -93,7 +93,7 @@ function(imstk_add_library target)
   #-----------------------------------------------------------------------------  
   target_compile_options(${target} PRIVATE
                            $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
-                                -Wall>
+                                -Wall -Wno-unused-function>
                            $<$<CXX_COMPILER_ID:MSVC>:
                                 -W4 -MP>)
 
diff --git a/CMake/iMSTKConfig.cmake.in b/CMake/iMSTKConfig.cmake.in
index 641e239b5325ab2fcdfb179cd1581a6743896b4b..4df73501ad856831d1baa623685713f927e45d94 100644
--- a/CMake/iMSTKConfig.cmake.in
+++ b/CMake/iMSTKConfig.cmake.in
@@ -55,14 +55,11 @@ find_package( LibNiFalcon REQUIRED)
 find_package( Libusb REQUIRED)
 
 # OpenVR
-if(iMSTK_ENABLE_VR)
-  add_definitions( -DiMSTK_ENABLE_VR )
-  find_package( openvr REQUIRED )
-endif()
+find_package( openvr REQUIRED )
 
 # PhysX
 find_package(PhysX REQUIRED)
-#
+
 #SCCD
 find_package( SCCD REQUIRED )
 
@@ -90,36 +87,41 @@ if(iMSTK_USE_OpenHaptics)
 endif()
 
 # VTK
+list(GET OPENVR_INCLUDE_DIRS 0 OpenVR_INCLUDE_DIR)
+list(GET OPENVR_LIBRARIES 1 OpenVR_LIBRARY)
+set(OpenVR_INCLUDE_DIR ${OpenVR_INCLUDE_DIR} CACHE INTERNAL "")
+set(OpenVR_LIBRARY ${OpenVR_LIBRARY} CACHE INTERNAL "")
 set(VTK_DIR @VTK_DIR@)
 find_dependency(VTK CONFIG)
 # modules are linked via `VTK::CommonCore`
 # vtk_module_autoinit is needed
-list(APPEND VTK_DEPENDENCIES
+find_dependency(VTK COMPONENTS
   ChartsCore
   CommonCore
   CommonDataModel
+  FiltersCore
+  FiltersExtraction
   FiltersGeneral
-  FiltersSources
   FiltersModeling
-  FiltersExtraction
+  FiltersSources
   IOExport
   IOImport
   IOPLY
   IOParallel
   IOParallelXML
   ImagingCore
+  ImagingGeneral
+  ImagingStencil
   InteractionStyle
   RenderingAnnotation
   RenderingContext2D
   RenderingContextOpenGL2
   RenderingCore
   RenderingOpenGL2
+  RenderingOpenVR
   RenderingVolume
   RenderingVolumeOpenGL2
   ViewsContext2D)
-if (${PROJECT_NAME}_ENABLE_VR)
-  list(APPEND VTK_DEPENDENCIES vtkRenderingOpenVR)
-endif()
 find_dependency(VTK COMPONENTS ${VTK_DEPENDENCIES})
 
 # glfw, gli
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f344847c01c7a62d93e6b6cad555655379ade6e7..e5713ed7d95203806a0aad46fd6fd668c9569773 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -89,6 +89,11 @@ if (${PROJECT_NAME}_BUILD_TESTING)
   set(BUILD_TESTING ON)
 endif ()
 option(${PROJECT_NAME}_USE_MODEL_REDUCTION "Build with model reduction, requires a VegaFEM built with Intel MKL and arpack" OFF)
+option(${PROJECT_NAME}_USE_VTK_OSMESA "Build with VTK OSMesa rendering" OFF)
+if (${${PROJECT_NAME}_USE_VTK_OSMESA} AND NOT UNIX)
+  message(WARNING "OSMesa only works on unix, building without")
+  set(${PROJECT_NAME}_USE_VTK_OSMESA FALSE CACHE BOOL "Build with VTK OSMesa rendering" FORCE)
+endif()
 
 #-----------------------------------------------------------------------------
 # CTest/Dashboards
@@ -139,6 +144,7 @@ if(${PROJECT_NAME}_SUPERBUILD)
   imstk_define_dependency(glm)
   imstk_define_dependency(imgui)
   imstk_define_dependency(LibNiFalcon)
+  imstk_define_dependency(openvr)
   imstk_define_dependency(PhysX)
   imstk_define_dependency(SCCD)
   imstk_define_dependency(tbb)
@@ -166,12 +172,6 @@ if(${PROJECT_NAME}_SUPERBUILD)
     imstk_define_dependency(Vulkan)
   endif()
 
-  option(${PROJECT_NAME}_ENABLE_VR "Allow the usage of VR rendering." OFF)
-
-  if(${PROJECT_NAME}_ENABLE_VR)
-    imstk_define_dependency(openvr)
-  endif()
-
   if(${PROJECT_NAME}_BUILD_TESTING)
     imstk_define_dependency(GTest)
 
@@ -234,14 +234,8 @@ find_package( imgui REQUIRED )
 find_package( LibNiFalcon REQUIRED)
 # Libusb
 find_package( Libusb REQUIRED)
-
 # OpenVR
-if(${PROJECT_NAME}_ENABLE_VR)
-  add_definitions( -DiMSTK_ENABLE_VR )
-  find_package( openvr REQUIRED )
-else()
-  remove_definitions( -DiMSTK_ENABLE_VR )
-endif()
+find_package( openvr REQUIRED )
 
 # Select the release version of PhysX to use
 set(PHYSX_CONFIGURATION "${PHYSX_CONFIGURATION}" CACHE STRING "Select PhysX Library Type for Release and RelWithDebInfo builds")
@@ -292,28 +286,29 @@ list(APPEND VTK_DEPENDENCIES
   ChartsCore
   CommonCore
   CommonDataModel
+  FiltersCore
+  FiltersExtraction
   FiltersGeneral
-  FiltersSources
   FiltersModeling
-  FiltersExtraction
+  FiltersSources
   IOExport
   IOImport
   IOPLY
   IOParallel
   IOParallelXML
   ImagingCore
+  ImagingGeneral
+  ImagingStencil
   InteractionStyle
   RenderingAnnotation
   RenderingContext2D
   RenderingContextOpenGL2
   RenderingCore
   RenderingOpenGL2
+  RenderingOpenVR
   RenderingVolume
   RenderingVolumeOpenGL2
   ViewsContext2D)
-if (${PROJECT_NAME}_ENABLE_VR)
-  list(APPEND VTK_DEPENDENCIES vtkRenderingOpenVR)
-endif()
 find_package(VTK COMPONENTS ${VTK_DEPENDENCIES})
 
 # Vulkan
@@ -400,6 +395,7 @@ add_subdirectory(Source/Scene)
 add_subdirectory(Source/SimulationManager)
 add_subdirectory(Source/apiUtilities)
 add_subdirectory(Source/Pulse)
+add_subdirectory(Source/Filtering)
 
 #--------------------------------------------------------------------------
 # Add Examples subdirectories
diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Albedo.png.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Albedo.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..76e8554bbf01c84865ed830d051f81308cd689e6
--- /dev/null
+++ b/Data/Surgical Instruments/Scalpel/Scalpel_Albedo.png.sha512	
@@ -0,0 +1 @@
+ad0495eb4b68162adeff1cd199ae87896e1cb9707d99109160fc339fc06b7410b629d4044d537e632d4b30c2c170def129c2f729e5fb3ef9441f7a6c32c35e4d
\ No newline at end of file
diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Blade10.obj.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Blade10.obj.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..4d0197c17e91a3af9101aff5b126a33e527dee41
--- /dev/null
+++ b/Data/Surgical Instruments/Scalpel/Scalpel_Blade10.obj.sha512	
@@ -0,0 +1 @@
+b3020f808f1589756d438d689bfde4ef673a3ab51f93f699bb7c16dbefc21fd48bdd5660810c509f5bfa4256bb4fa2aa8955c3b59ca011e24c72414890291616
\ No newline at end of file
diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Blade10_Hull.stl.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Blade10_Hull.stl.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..034890c59bc0acf07d468a2df98bf4f7a7f59fcd
--- /dev/null
+++ b/Data/Surgical Instruments/Scalpel/Scalpel_Blade10_Hull.stl.sha512	
@@ -0,0 +1 @@
+3314f75a94b2ea8b026053678f3754e5203dd90b35e80f99e4ae83f38957461b9ab0f4fbb60c94240f3e6622a99ee4a1929e8d98b29e02b894c03da9a716f4c9
\ No newline at end of file
diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Blade11.obj.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Blade11.obj.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..6f0e02f90ebf77c320736922db2c8a09e9ee35fb
--- /dev/null
+++ b/Data/Surgical Instruments/Scalpel/Scalpel_Blade11.obj.sha512	
@@ -0,0 +1 @@
+a68a897914f25b37381a833da42e1efd6242f3f43b3f3be3d53662151e41819a3b467d86884e199933364a5e3e09fe3999dd763b8ee9282cdd9e664f9ba1cf66
\ No newline at end of file
diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Blade15.obj.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Blade15.obj.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..85bace8d1d48801ab5bd52ac739552d7d6b66c8a
--- /dev/null
+++ b/Data/Surgical Instruments/Scalpel/Scalpel_Blade15.obj.sha512	
@@ -0,0 +1 @@
+53c94e1d26114f36ad553fa6de26d6bdd1d9ccb7b693b4560ac25a520ce60f17fbd5819aba5d7c7580ca2c1875665439744b39f6f3a530138f2af9409a110f37
\ No newline at end of file
diff --git a/Data/Surgical Instruments/Scalpel/Scalpel_Handle.obj.sha512 b/Data/Surgical Instruments/Scalpel/Scalpel_Handle.obj.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..8e87f96ea38351bdcf2829fdb54a10d85ed1dd99
--- /dev/null
+++ b/Data/Surgical Instruments/Scalpel/Scalpel_Handle.obj.sha512	
@@ -0,0 +1 @@
+5bfa843d28651bf9e1573d627434905ca7980541877c9a2aa3cd24d3c85f914245a416340de3d22cdeba73d641daf23d7aab9be753072c7c40e875f688ce506a
\ No newline at end of file
diff --git a/Data/legs/femoralArtery.stl.sha512 b/Data/legs/femoralArtery.stl.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..38f05c91be8f057de0050bad71eb6c4a779e0a37
--- /dev/null
+++ b/Data/legs/femoralArtery.stl.sha512
@@ -0,0 +1 @@
+0ef3e5b862501a2988de967f04e37ad37661819ea153b4cd2d26ebc89df287bf5a04bf3f3ac3faf3a7d7fed8009a127a7637f63869ffd3627efcd9cd6099fafc
\ No newline at end of file
diff --git a/Data/legs/femoralArteryCut.stl.sha512 b/Data/legs/femoralArteryCut.stl.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..bb7284da5bb9197475e73969e2c14b9e9ed4c9f3
--- /dev/null
+++ b/Data/legs/femoralArteryCut.stl.sha512
@@ -0,0 +1 @@
+e16c4335d3020f8540843f3c6b4f769304eb44e10e9181ddf30ad30297e87e89680f73dae86238b51e10d3248c8b64c8c4e62966302a141aaf51bbf8ab3ac79f
\ No newline at end of file
diff --git a/Data/legs/femurBone.stl.sha512 b/Data/legs/femurBone.stl.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..0a81cd0b9fde9675343ff8964c1f2e0f35150eda
--- /dev/null
+++ b/Data/legs/femurBone.stl.sha512
@@ -0,0 +1 @@
+0d8f71d9a75d32802ace47a2ea2f63c1dbd2cd15a286c59686a93bad9258dcea60042e682efb652ad4eb908df899982905cf284ab8292e9fd6d1fe847b7ac4b7
\ No newline at end of file
diff --git a/Data/legs/femurBone_SDF.nii.sha512 b/Data/legs/femurBone_SDF.nii.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..a9bc981d6eabd920b2161deb19114fe3e5ab2455
--- /dev/null
+++ b/Data/legs/femurBone_SDF.nii.sha512
@@ -0,0 +1 @@
+777b16098845cca8d45f3254de1fb941c05a1c1b11619173e788e49c323f693d71f216e23063ca8ee340b26ba4fb58bf45988ff6dac974596e0c872b5251d904
\ No newline at end of file
diff --git a/Data/legs/legsBones.stl.sha512 b/Data/legs/legsBones.stl.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..c49859390b44361a1eec3931428b8b04980c21ca
--- /dev/null
+++ b/Data/legs/legsBones.stl.sha512
@@ -0,0 +1 @@
+bb4ec0204bcfecd346b6ff3c8b5cd6992d7f9507bce29e35b33be80236d29dc3d1c7197453cd724bf1dd0a10e714de2b1e0eee4d51dfe7b58216a52641271b7b
\ No newline at end of file
diff --git a/Data/legs/legsCutaway.stl.sha512 b/Data/legs/legsCutaway.stl.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..6429fd6602f8b6b76e21ef4b23e0f8df5483d827
--- /dev/null
+++ b/Data/legs/legsCutaway.stl.sha512
@@ -0,0 +1 @@
+8ad322ea48cffa1296af8cfb226e33e0a305ca95db9ec22ec101d93b3229c4a1b36244017ba4785aacd42fdb100f475cd2a66e901b03501a94bb2a907c1ee064
\ No newline at end of file
diff --git a/Examples/Audio/AudioExample.cpp b/Examples/Audio/AudioExample.cpp
index 8924f88f5f4e193930e39737dfe719941bf48adf..a66278b8ccce8b5ff2c6bf678d227520ff95dc4c 100644
--- a/Examples/Audio/AudioExample.cpp
+++ b/Examples/Audio/AudioExample.cpp
@@ -23,10 +23,7 @@
 #include "imstkLogger.h"
 
 #ifdef iMSTK_AUDIO_ENABLED
-
-// Audio
 #include <SFML/Audio.hpp>
-
 #endif
 
 using namespace imstk;
@@ -41,10 +38,10 @@ playSound(const std::string& filename)
     CHECK(buffer.loadFromFile(filename)) << "testSound: Could not open the input sound file: " << filename;
 
     // Display sound informations
-    std::cout << filename << std::endl;
-    std::cout << " " << buffer.getDuration().asSeconds() << " seconds" << std::endl;
-    std::cout << " " << buffer.getSampleRate() << " samples / sec" << std::endl;
-    std::cout << " " << buffer.getChannelCount() << " channels" << std::endl;
+    LOG(INFO) << filename;
+    LOG(INFO) << " " << buffer.getDuration().asSeconds() << " seconds";
+    LOG(INFO) << " " << buffer.getSampleRate() << " samples / sec";
+    LOG(INFO) << " " << buffer.getChannelCount() << " channels";
 
     // Create a sound instance and play it
     sf::Sound sound(buffer);
@@ -66,11 +63,11 @@ playSound(const std::string& filename)
         sf::Listener::setPosition((float)listnerPos.x(), (float)listnerPos.y(), (float)listnerPos.z());
 
         // Display the playing position
-        std::cout << "\rPlaying... " << sound.getPlayingOffset().asSeconds() << " sec        ";
-        std::cout << std::flush;
+        LOG(INFO) << "\rPlaying... " << sound.getPlayingOffset().asSeconds() << " sec        ";
+        LOG(INFO) << std::flush;
     }
-    std::cout << "\n" << std::endl;
-#else if
+    LOG(INFO) << "\n";
+#else
     LOG(INFO) << "testSound: Audio is supported only on windows!";
 #endif
 }
@@ -85,10 +82,10 @@ playMusic(const std::string& filename)
     CHECK(music.openFromFile(filename)) << "playMusic: Could not open the input music file: " << filename;
 
     // Display music informations
-    std::cout << filename << ":" << std::endl;
-    std::cout << " " << music.getDuration().asSeconds() << " seconds" << std::endl;
-    std::cout << " " << music.getSampleRate() << " samples / sec" << std::endl;
-    std::cout << " " << music.getChannelCount() << " channels" << std::endl;
+    LOG(INFO) << filename << ":";
+    LOG(INFO) << " " << music.getDuration().asSeconds() << " seconds";
+    LOG(INFO) << " " << music.getSampleRate() << " samples / sec";
+    LOG(INFO) << " " << music.getChannelCount() << " channels";
 
     // Play it
     music.play();
@@ -100,10 +97,10 @@ playMusic(const std::string& filename)
         sf::sleep(sf::milliseconds(100));
 
         // Display the playing position
-        std::cout << "\rPlaying... " << music.getPlayingOffset().asSeconds() << " sec        ";
-        std::cout << std::flush;
+        LOG(INFO) << "\rPlaying... " << music.getPlayingOffset().asSeconds() << " sec        ";
+        LOG(INFO) << std::flush;
     }
-    std::cout << "\n" << std::endl;
+    LOG(INFO) << "\n";
 #else
     LOG(INFO) << "playMusic: Audio is supported only on windows!";
 #endif
@@ -116,14 +113,12 @@ playMusic(const std::string& filename)
 int
 main()
 {
-    Logger& logger = Logger::getInstance();
-    logger.addFileSink("audio-Example", "./");
-    logger.addStdoutSink();
+    Logger::startLogger();
 
-    #ifndef iMSTK_AUDIO_ENABLED
+#ifndef iMSTK_AUDIO_ENABLED
     LOG(INFO) << "Audio not enabled at build time\n";
     return 1;
-    #endif
+#endif
 
     LOG(INFO) << "--Testing audio--\n";
 
diff --git a/Examples/BoneShaving/BoneShavingExample.cpp b/Examples/BoneShaving/BoneShavingExample.cpp
index 1c1e80fd08caeb6a862d810a8b744fc9bd98ea59..94ad4f0410a72dfb728627b55a142c3471d18821 100644
--- a/Examples/BoneShaving/BoneShavingExample.cpp
+++ b/Examples/BoneShaving/BoneShavingExample.cpp
@@ -19,37 +19,36 @@
 
 =========================================================================*/
 
+#include "imstkLogger.h"
 #include "imstkMath.h"
-#include "imstkTimer.h"
-#include "imstkSimulationManager.h"
+#include "imstkNew.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkVTKViewer.h"
 
 // Objects
-#include "imstkSceneObject.h"
-#include "imstkLight.h"
 #include "imstkCamera.h"
+#include "imstkCollidingObject.h"
+#include "imstkLight.h"
 
 // Geometry
+#include "imstkMeshIO.h"
 #include "imstkSphere.h"
 #include "imstkTetrahedralMesh.h"
-#include "imstkSurfaceMesh.h"
-#include "imstkMeshIO.h"
 
 // Devices and controllers
-#include "imstkDeviceTracker.h"
-#include "imstkHDAPIDeviceClient.h"
-#include "imstkHDAPIDeviceServer.h"
+#include "imstkHapticDeviceClient.h"
+#include "imstkHapticDeviceManager.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkMouseSceneControl.h"
 #include "imstkSceneObjectController.h"
 
 // Collisions
 #include "imstkCollisionGraph.h"
-#include "imstkInteractionPair.h"
-#include "imstkPointSetToSphereCD.h"
-#include "imstkVirtualCouplingCH.h"
-#include "imstkBoneDrillingCH.h"
+#include "imstkObjectInteractionFactory.h"
 
 // global variables
-const std::string phantomOmni1Name = "Phantom1";
+const std::string phantomOmni1Name = "Default Device";
 
 using namespace imstk;
 
@@ -60,68 +59,79 @@ using namespace imstk;
 int
 main()
 {
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("BoneDrilling");
-
-    // Add virtual coupling object in the scene.
-#ifdef iMSTK_USE_OPENHAPTICS
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
 
-    // Device clients
-    auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name);
+    // Create Scene
+    imstkNew<Scene> scene("BoneDrilling");
 
     // Device Server
-    auto server = std::make_shared<HDAPIDeviceServer>();
-    server->addDeviceClient(client);
-    simManager->addModule(server);
-
-    // Device tracker
-    auto deviceTracker = std::make_shared<DeviceTracker>(client);
+    imstkNew<HapticDeviceManager>       server;
+    std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name);
 
     // Create bone scene object
     // Load the mesh
-    auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
     if (!tetMesh)
     {
         LOG(FATAL) << "Could not read mesh from file.";
         return 1;
     }
-    auto bone = std::make_shared<CollidingObject>("Bone");
+    imstkNew<CollidingObject> bone("Bone");
     bone->setCollidingGeometry(tetMesh);
     bone->setVisualGeometry(tetMesh);
     scene->addSceneObject(bone);
 
     // Create a virtual coupling object: Drill
-    auto drillVisualGeom = std::make_shared<Sphere>();
-    drillVisualGeom->setRadius(3.);
-    auto drillCollidingGeom = std::make_shared<Sphere>();
-    drillCollidingGeom->setRadius(3.);
-    auto drill = std::make_shared<CollidingObject>("Drill");
-    drill->setCollidingGeometry(drillCollidingGeom);
-    drill->setVisualGeometry(drillVisualGeom);
+    imstkNew<Sphere>          drillGeom(Vec3d(0.0, 0.0, 0.0), 3.0);
+    imstkNew<CollidingObject> drill("Drill");
+    drill->setCollidingGeometry(drillGeom);
+    drill->setVisualGeometry(drillGeom);
     scene->addSceneObject(drill);
 
     // Create and add virtual coupling object controller in the scene
-    auto objController = std::make_shared<SceneObjectController>(drill, deviceTracker);
-    scene->addObjectController(objController);
+    imstkNew<SceneObjectController> controller(drill, client);
+    scene->addController(controller);
 
     // Add interaction
     scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(bone, drill,
-        InteractionType::FemObjToCollidingObjBoneDrilling, CollisionDetection::Type::PointSetToSphere));
-
-#endif
+        InteractionType::CollidingObjToCollidingObjBoneDrilling, CollisionDetection::Type::PointSetToSphere));
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
+    imstkNew<DirectionalLight> light("light");
+    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+    light->setIntensity(1.0);
     scene->addLight(light);
 
-    //Run
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(0, 0, 15));
+    scene->getActiveCamera()->setPosition(Vec3d(0.0, 3.0, 25.0));
 
-    simManager->setActiveScene(scene);
-    simManager->start();
+    //Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer 1");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager 1");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        viewer->addChildThread(server);       // Server starts/stops with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
     return 0;
 }
diff --git a/Examples/CameraController/CameraControllerExample.cpp b/Examples/CameraController/CameraControllerExample.cpp
index 8106d64527983b00f6e2bf9617dbae1733f6522b..5cb6ef3b6424a821f5c229d0ebc9bd9ecc889444 100644
--- a/Examples/CameraController/CameraControllerExample.cpp
+++ b/Examples/CameraController/CameraControllerExample.cpp
@@ -19,22 +19,24 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkSceneObject.h"
-#include "imstkLight.h"
 #include "imstkCamera.h"
-#include "imstkMeshIO.h"
-#include "imstkScene.h"
-
-// Devices and controllers
-#include "imstkHDAPIDeviceClient.h"
-#include "imstkHDAPIDeviceServer.h"
 #include "imstkCameraController.h"
-#include "imstkCollisionGraph.h"
-
+#include "imstkHapticDeviceClient.h"
+#include "imstkHapticDeviceManager.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkPlane.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObject.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkVTKViewer.h"
 
-const std::string phantomOmni1Name = "Phantom1";
+const std::string phantomOmni1Name = "Default Device";
 
 using namespace imstk;
 
@@ -45,58 +47,72 @@ using namespace imstk;
 int
 main()
 {
-    #ifndef iMSTK_USE_OPENHAPTICS
-    std::cout << "Audio not enabled at build time" << std::endl;
-    return 1;
-    #endif
-
-    // Create simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("CameraController");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
 
-#ifdef iMSTK_USE_OPENHAPTICS
-
-    auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name);
+    // Create Scene
+    imstkNew<Scene> scene("CameraController");
 
     // Device Server
-    auto server = std::make_shared<HDAPIDeviceServer>();
-    server->addDeviceClient(client);
-    simManager->addModule(server);
-#else
-    LOG(WARNING) << "Phantom device option not enabled during build!";
-#endif
+    imstkNew<HapticDeviceManager>       server;
+    std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name);
 
     // Load Mesh
-    auto mesh       = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
-    auto meshObject = std::make_shared<VisualObject>("meshObject");
+    auto                   mesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
+    imstkNew<VisualObject> meshObject("meshObject");
     meshObject->setVisualGeometry(mesh);
     scene->addSceneObject(meshObject);
 
-    // Update Camera position
-    auto camera = scene->getCamera();
-    camera->setPosition(Vec3d(0, 0, 10));
+    imstkNew<VisualObject> planeObject("Plane");
+    imstkNew<Plane>        plane(Vec3d(0.0, -2.0, 0.0));
+    plane->setWidth(1000.0);
+    planeObject->setVisualGeometry(plane);
+    scene->addSceneObject(planeObject);
 
-#ifdef iMSTK_USE_OPENHAPTICS
-
-    auto camController = std::make_shared<CameraController>(camera, client);
+    // Update Camera position
+    scene->getActiveCamera()->setPosition(Vec3d(0.0, 0.0, 10.0));
 
+    imstkNew<CameraController> camController(scene->getActiveCamera(), client);
     //camController->setTranslationScaling(100);
     //LOG(INFO) << camController->getTranslationOffset(); // should be the same than initial cam position
-    camController->setInversionFlags(CameraController::InvertFlag::rotY |
-                                     CameraController::InvertFlag::rotZ);
-
-    scene->addCameraController(camController);
-#endif
+    scene->addController(camController);
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
+    imstkNew<DirectionalLight> light("light");
+    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+    light->setIntensity(1.0);
     scene->addLight(light);
 
-    // Run
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    //Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer 1");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager 1");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        viewer->addChildThread(server);
+
+        // attach the camera controller to the viewer
+        viewer->addControl(camController);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer and its children
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/CollisionDetection/Box.cpp b/Examples/CollisionDetection/Box.cpp
index 9c428fd83d9e961f6629048360ef024e8f680812..bf4d1eb37e66116134e93fa5c342aba25ba356a6 100644
--- a/Examples/CollisionDetection/Box.cpp
+++ b/Examples/CollisionDetection/Box.cpp
@@ -22,6 +22,7 @@
 #include "imstkMath.h"
 
 #include <array>
+
 using namespace imstk;
 
 std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>>
diff --git a/Examples/CollisionDetection/BunnyMesh.cpp b/Examples/CollisionDetection/BunnyMesh.cpp
index 34ae07934852d15b2cb1c2e36f379fae34fd4c69..417538ef5baaaeb494c3a0daed1fc1f31086fdc9 100644
--- a/Examples/CollisionDetection/BunnyMesh.cpp
+++ b/Examples/CollisionDetection/BunnyMesh.cpp
@@ -23,6 +23,7 @@
 #include "imstkLogger.h"
 
 #include <array>
+
 using namespace imstk;
 
 std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>>
diff --git a/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp b/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp
index dfd7fca130b89d5d634e3854dd9e6c6d753cdf6a..40e28c6b2214b7f7eff8993168152ba70077e1c3 100644
--- a/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp
+++ b/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp
@@ -19,29 +19,26 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkLight.h"
-#include "imstkSceneObject.h"
-#include "imstkDebugRenderGeometry.h"
-#include "imstkAPIUtilities.h"
-#include "imstkVTKViewer.h"
-#include "imstkTimer.h"
-#include "imstkVTKTextStatusManager.h"
-#include "imstkCollisionData.h"
 #include "imstkCamera.h"
-#include "imstkDebugRenderGeometry.h"
 #include "imstkCollidingObject.h"
+#include "imstkCollisionData.h"
+#include "imstkDebugRenderGeometry.h"
+#include "imstkKeyboardDeviceClient.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkOctreeBasedCD.h"
+#include "imstkRenderMaterial.h"
+#include "imstkScene.h"
 #include "imstkSceneManager.h"
 #include "imstkSurfaceMesh.h"
-#include "imstkScene.h"
+#include "imstkTimer.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKRenderDelegate.h"
 #include "imstkVTKRenderer.h"
-
-// This is for collision detection between geometries
-#include "imstkOctreeBasedCD.h"
-
-#include <map>
-#include <thread>
-#include <chrono>
+#include "imstkVTKTextStatusManager.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -68,19 +65,18 @@ static std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> g_BunnyDa
 /// \brief Read a mesh, create a visual scene object and add to the scene
 ///
 std::shared_ptr<CollidingObject>
-createMeshObject(const std::shared_ptr<imstk::Scene>& scene,
-                 const std::string&                   objectName,
-                 Color                                color)
+createMeshObject(const std::string& objectName,
+                 Color              color)
 {
     // Create a surface mesh
-    auto meshObj = std::make_shared<SurfaceMesh>(objectName);
+    imstkNew<SurfaceMesh> meshObj(objectName);
     meshObj->initialize(MESH_DATA.first, MESH_DATA.second);
 
     // Create a visiual model
-    auto visualModel = std::make_shared<VisualModel>(meshObj);
-    auto material    = std::make_shared<RenderMaterial>();
+    imstkNew<VisualModel>    visualModel(meshObj.get());
+    imstkNew<RenderMaterial> material;
     material->setEdgeColor(color); // Wireframe color
-    material->setLineWidth(2);
+    material->setLineWidth(2.0);
     if (meshObj->getNumTriangles() > 100)
     {
         material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
@@ -92,12 +88,10 @@ createMeshObject(const std::shared_ptr<imstk::Scene>& scene,
     visualModel->setRenderMaterial(material);
 
     // Create object and add to scene
-    auto meshSceneObject = std::make_shared<CollidingObject>(objectName);
+    imstkNew<CollidingObject> meshSceneObject(objectName);
     meshSceneObject->setCollidingGeometry(meshObj);
     meshSceneObject->addVisualModel(visualModel);
-    scene->addSceneObject(meshSceneObject);
 
-    LOG_IF(FATAL, (!meshSceneObject)) << "ERROR: Unable to create scene object";
     return meshSceneObject;
 }
 
@@ -107,16 +101,16 @@ createMeshObject(const std::shared_ptr<imstk::Scene>& scene,
 std::shared_ptr<DebugRenderGeometry>
 addPointsDebugRendering(const std::shared_ptr<Scene>& scene)
 {
-    auto debugPoints = std::make_shared<DebugRenderPoints>("Debug Points");
-    auto material    = std::make_shared<RenderMaterial>();
+    imstkNew<DebugRenderPoints> debugPoints("Debug Points");
+    imstkNew<RenderMaterial>    material;
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
     material->setVertexColor(Color::Yellow);
-    material->setPointSize(8.);
+    material->setPointSize(8.0);
 
-    auto dbgViz = std::make_shared<VisualModel>(debugPoints, material);
+    imstkNew<VisualModel> dbgViz(debugPoints.get(), material);
     scene->addDebugVisualModel(dbgViz);
 
-    return std::dynamic_pointer_cast<DebugRenderGeometry>(debugPoints);
+    return debugPoints;
 }
 
 ///
@@ -125,16 +119,16 @@ addPointsDebugRendering(const std::shared_ptr<Scene>& scene)
 std::shared_ptr<DebugRenderGeometry>
 addVTConnectingLinesDebugRendering(const std::shared_ptr<Scene>& scene)
 {
-    auto debugLines = std::make_shared<DebugRenderLines>("Debug Connecting VT Lines");
-    auto material   = std::make_shared<RenderMaterial>();
+    imstkNew<DebugRenderLines> debugLines("Debug Connecting VT Lines");
+    imstkNew<RenderMaterial>   material;
     material->setBackFaceCulling(false);
     material->setEdgeColor(Color::Green);
     material->setLineWidth(4.0);
 
-    auto dbgViz = std::make_shared<VisualModel>(debugLines, material);
+    imstkNew<VisualModel> dbgViz(debugLines.get(), material);
     scene->addDebugVisualModel(dbgViz);
 
-    return std::dynamic_pointer_cast<DebugRenderGeometry>(debugLines);
+    return debugLines;
 }
 
 ///
@@ -143,16 +137,16 @@ addVTConnectingLinesDebugRendering(const std::shared_ptr<Scene>& scene)
 std::shared_ptr<DebugRenderGeometry>
 addEEConnectingLinesDebugRendering(const std::shared_ptr<Scene>& scene)
 {
-    auto debugLines = std::make_shared<DebugRenderLines>("Debug Connecting EE Lines");
-    auto material   = std::make_shared<RenderMaterial>();
+    imstkNew<DebugRenderLines> debugLines("Debug Connecting EE Lines");
+    imstkNew<RenderMaterial>   material;
     material->setBackFaceCulling(false);
     material->setEdgeColor(Color::Red);
     material->setLineWidth(4.0);
 
-    auto dbgViz = std::make_shared<VisualModel>(debugLines, material);
+    imstkNew<VisualModel> dbgViz(debugLines.get(), material);
     scene->addDebugVisualModel(dbgViz);
 
-    return std::dynamic_pointer_cast<DebugRenderGeometry>(debugLines);
+    return debugLines;
 }
 
 ///
@@ -161,16 +155,16 @@ addEEConnectingLinesDebugRendering(const std::shared_ptr<Scene>& scene)
 std::shared_ptr<DebugRenderGeometry>
 addHighlightedLinesDebugRendering(const std::shared_ptr<Scene>& scene)
 {
-    auto debugLines = std::make_shared<DebugRenderLines>("Debug Highlighted Lines");
-    auto material   = std::make_shared<RenderMaterial>();
+    imstkNew<DebugRenderLines> debugLines("Debug Highlighted Lines");
+    imstkNew<RenderMaterial>   material;
     material->setBackFaceCulling(false);
     material->setEdgeColor(Color::Orange);
     material->setLineWidth(8.0);
 
-    auto dbgViz = std::make_shared<VisualModel>(debugLines, material);
+    imstkNew<VisualModel> dbgViz(debugLines.get(), material);
     scene->addDebugVisualModel(dbgViz);
 
-    return std::dynamic_pointer_cast<DebugRenderGeometry>(debugLines);
+    return debugLines;
 }
 
 ///
@@ -202,23 +196,19 @@ getRandomColor()
 int
 main()
 {
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("Collision Test");
+    Logger::startLogger();
 
-    // Configure the VTKViewer
-    std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false);
+    imstkNew<Scene> scene("Collision Test");
+
+    // Setup a viewer to render in its own thread
+    imstkNew<VTKViewer> viewer("Viewer");
+    viewer->setActiveScene(scene);
     viewer->setWindowTitle("Collision Test");
-    viewer->getVtkRenderWindow()->SetSize(1920, 1080);
+    viewer->setSize(1920, 1080);
     auto statusManager = viewer->getTextStatusManager();
-    statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 25);
-    statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Orange);
-    simManager->setViewer(viewer);
-    simManager->setActiveScene(scene); // Viewer has depedence on scene
-
-    // Get VTK Renderer
-    auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer());
-    LOG_IF(FATAL, (!renderer)) << "Invalid renderer: Only VTKRenderer is supported for debug rendering";
+    statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 25);
+    statusManager->setStatusFontColor(VTKTextStatusManager::StatusType::Custom, Color::Orange);
+    std::shared_ptr<VTKRenderer> ren = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer());
 
 //    srand(123456); // Deterministic random generation, for random colors
     srand(static_cast<unsigned int>(time(nullptr)));
@@ -227,7 +217,8 @@ main()
     std::vector<std::shared_ptr<SurfaceMesh>> triMeshes;
     for (unsigned int i = 0; i < NUM_MESHES; ++i)
     {
-        const auto sceneObj = createMeshObject(scene, "Mesh-" + std::to_string(triMeshes.size()), getRandomColor());
+        std::shared_ptr<CollidingObject> sceneObj = createMeshObject("Mesh-" + std::to_string(triMeshes.size()), getRandomColor());
+        scene->addSceneObject(sceneObj);
         triMeshes.push_back(std::dynamic_pointer_cast<SurfaceMesh>(sceneObj->getVisualGeometry()));
     }
 
@@ -245,7 +236,7 @@ main()
     timer.start();
 
     // Create an octree
-    OctreeBasedCD octreeCD(Vec3d(0, 0, 0), 100.0, 0.125, 1);
+    OctreeBasedCD octreeCD(Vec3d(0.0, 0.0, 0.0), 100.0, 0.125, 1);
 
     for (const auto& obj: triMeshes)
     {
@@ -263,7 +254,7 @@ main()
         {
             if (i != j)
             {
-                octreeCD.addCollisionPair(triMeshes[i], triMeshes[j], CollisionDetection::Type::SurfaceMeshToSurfaceMesh);
+                octreeCD.addCollisionPair(triMeshes[i], triMeshes[j], CollisionDetection::Type::SurfaceMeshToSurfaceMesh, std::make_shared<CollisionData>());
             }
         }
     }
@@ -278,11 +269,11 @@ main()
 #ifdef DEBUG_RENDER_OCTREE
     const auto debugOctree = octreeCD.getDebugGeometry(8, false);
 
-    const auto matDbgViz = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> matDbgViz;
     matDbgViz->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
     matDbgViz->setEdgeColor(Color::Green);
     matDbgViz->setLineWidth(1.0);
-    auto octreeVizDbgModel = std::make_shared<VisualModel>(debugOctree, matDbgViz);
+    imstkNew<VisualModel> octreeVizDbgModel(debugOctree, matDbgViz);
     scene->addDebugVisualModel(octreeVizDbgModel);
 #endif
 
@@ -318,179 +309,197 @@ main()
         dirs[i][2] = -std::sin(rotation) * t;
     }
 
-    auto updateFunc =
-        [&](Module*) {
-            for (size_t i = 0; i < triMeshes.size(); ++i)
-            {
-                triMeshes[i]->translate(dirs[i][0], dirs[i][1], dirs[i][2], Geometry::TransformType::ApplyToData);
-                centers[i] += dirs[i];
-
-                // Trick to force update geometry postUpdateTransform
-                const auto positions = triMeshes[i]->getVertexPositions();
-                (void)positions;
-            }
-
-            Vec3d lowerCorners, upperCorner;
-            ParallelUtils::findAABB(centers, lowerCorners, upperCorner);
-            if ((lowerCorners - upperCorner).norm() > 70.0)
-            {
-                for (auto& dir : dirs)
-                {
-                    dir = -dir;
-                }
-            }
-
-            StopWatch timer;
-
-            // Update octree
-            timer.start();
-            octreeCD.update();
-            const auto updateTime = timer.getTimeElapsed();
+    auto updateFunc = [&](Event*)
+                      {
+                          for (size_t i = 0; i < triMeshes.size(); ++i)
+                          {
+                              triMeshes[i]->translate(dirs[i][0], dirs[i][1], dirs[i][2], Geometry::TransformType::ApplyToData);
+                              centers[i] += dirs[i];
+
+                              // Trick to force update geometry postUpdateTransform
+                              const auto positions = triMeshes[i]->getVertexPositions();
+                              (void)positions;
+                          }
+
+                          Vec3d lowerCorners, upperCorner;
+                          ParallelUtils::findAABB(centers, lowerCorners, upperCorner);
+                          if ((lowerCorners - upperCorner).norm() > 70.0)
+                          {
+                              for (auto& dir : dirs)
+                              {
+                                  dir = -dir;
+                              }
+                          }
+
+                          StopWatch timer;
+
+                          // Update octree
+                          timer.start();
+                          octreeCD.update();
+                          const auto updateTime = timer.getTimeElapsed();
 #ifdef DEBUG_RENDER_OCTREE
-            octreeCD.updateDebugGeometry();
+                          octreeCD.updateDebugGeometry();
 #endif
 
-            // Detect collision
-            timer.start();
-            octreeCD.detectCollision();
-            const auto CDTime = timer.getTimeElapsed();
-
-            const auto numActiveNodes = octreeCD.getNumActiveNodes();
-            const auto numTotalNodes  = octreeCD.getNumAllocatedNodes();
-            const auto numPrimitives  = octreeCD.getPrimitiveCount(OctreePrimitiveType::Point) +
-                                        octreeCD.getPrimitiveCount(OctreePrimitiveType::Triangle) +
-                                        octreeCD.getPrimitiveCount(OctreePrimitiveType::AnalyticalGeometry);
-            const auto maxNumPrimitivesInTree = octreeCD.getMaxNumPrimitivesInNodes();
-
-            // Clear collision debug rendering
-            debugPoints->clear();
-            debugVTConnectingLines->clear();
-            debugEEConnectingLines->clear();
-            debugHighlightedLines->clear();
-
-            size_t numVTCollisions = 0;
-            size_t numEECollisions = 0;
-            for (const auto& geoPair : octreeCD.getCollidingGeometryPairs())
-            {
-                const auto& colData = octreeCD.getCollisionPairData(geoPair.first->getGlobalIndex(),
+                          // Detect collision
+                          timer.start();
+                          octreeCD.detectCollision();
+                          const auto CDTime = timer.getTimeElapsed();
+
+                          const auto numActiveNodes = octreeCD.getNumActiveNodes();
+                          const auto numTotalNodes  = octreeCD.getNumAllocatedNodes();
+                          const auto numPrimitives  = octreeCD.getPrimitiveCount(OctreePrimitiveType::Point) +
+                                                      octreeCD.getPrimitiveCount(OctreePrimitiveType::Triangle) +
+                                                      octreeCD.getPrimitiveCount(OctreePrimitiveType::AnalyticalGeometry);
+                          const auto maxNumPrimitivesInTree = octreeCD.getMaxNumPrimitivesInNodes();
+
+                          // Clear collision debug rendering
+                          debugPoints->clear();
+                          debugVTConnectingLines->clear();
+                          debugEEConnectingLines->clear();
+                          debugHighlightedLines->clear();
+
+                          size_t numVTCollisions = 0;
+                          size_t numEECollisions = 0;
+                          for (const auto& geoPair : octreeCD.getCollidingGeometryPairs())
+                          {
+                              const auto& colData = octreeCD.getCollisionPairData(geoPair.first->getGlobalIndex(),
                                                                     geoPair.second->getGlobalIndex());
-                if (colData->VTColData.getSize())
-                {
-                    numVTCollisions += colData->VTColData.getSize();
-                    const auto mesh1 = static_cast<SurfaceMesh*>(geoPair.first);
-                    const auto mesh2 = static_cast<SurfaceMesh*>(geoPair.second);
-                    for (size_t i = 0; i < colData->VTColData.getSize(); ++i)
-                    {
-                        const auto tv = colData->VTColData[i];
-                        const auto v  = mesh1->getVertexPosition(tv.vertexIdx);
-                        debugPoints->appendVertex(v);
-
-                        const auto face = mesh2->getTrianglesVertices()[tv.triIdx];
-                        const auto tv0  = mesh2->getVertexPosition(face[0]);
-                        const auto tv1  = mesh2->getVertexPosition(face[1]);
-                        const auto tv2  = mesh2->getVertexPosition(face[2]);
-
-                        debugHighlightedLines->appendVertex(tv0);
-                        debugHighlightedLines->appendVertex(tv1);
-                        debugHighlightedLines->appendVertex(tv1);
-                        debugHighlightedLines->appendVertex(tv2);
-                        debugHighlightedLines->appendVertex(tv2);
-                        debugHighlightedLines->appendVertex(tv0);
-
-                        debugVTConnectingLines->appendVertex(v);
-                        debugVTConnectingLines->appendVertex((tv0 + tv1 + tv2) / 3.0);
-                    }
-                }
+                              if (colData->VTColData.getSize())
+                              {
+                                  numVTCollisions += colData->VTColData.getSize();
+                                  const auto mesh1 = static_cast<SurfaceMesh*>(geoPair.first);
+                                  const auto mesh2 = static_cast<SurfaceMesh*>(geoPair.second);
+                                  for (size_t i = 0; i < colData->VTColData.getSize(); ++i)
+                                  {
+                                      const auto tv = colData->VTColData[i];
+                                      const auto v  = mesh1->getVertexPosition(tv.vertexIdx);
+                                      debugPoints->appendVertex(v);
+
+                                      const auto face = mesh2->getTrianglesVertices()[tv.triIdx];
+                                      const auto tv0  = mesh2->getVertexPosition(face[0]);
+                                      const auto tv1  = mesh2->getVertexPosition(face[1]);
+                                      const auto tv2  = mesh2->getVertexPosition(face[2]);
+
+                                      debugHighlightedLines->appendVertex(tv0);
+                                      debugHighlightedLines->appendVertex(tv1);
+                                      debugHighlightedLines->appendVertex(tv1);
+                                      debugHighlightedLines->appendVertex(tv2);
+                                      debugHighlightedLines->appendVertex(tv2);
+                                      debugHighlightedLines->appendVertex(tv0);
+
+                                      debugVTConnectingLines->appendVertex(v);
+                                      debugVTConnectingLines->appendVertex((tv0 + tv1 + tv2) / 3.0);
+                                  }
+                              }
+
+                              if (colData->EEColData.getSize())
+                              {
+                                  numEECollisions += colData->EEColData.getSize();
+                                  const auto mesh1 = static_cast<SurfaceMesh*>(geoPair.first);
+                                  const auto mesh2 = static_cast<SurfaceMesh*>(geoPair.second);
+                                  for (size_t i = 0; i < colData->EEColData.getSize(); ++i)
+                                  {
+                                      const auto ee = colData->EEColData[i];
+
+                                      const auto e0v0     = mesh1->getVertexPosition(ee.edgeIdA.first);
+                                      const auto e0v1     = mesh1->getVertexPosition(ee.edgeIdA.second);
+                                      const auto e0Center = (e0v0 + e0v1) * 0.5;
+                                      debugPoints->appendVertex(e0Center);
+
+                                      const auto e1v0     = mesh2->getVertexPosition(ee.edgeIdB.first);
+                                      const auto e1v1     = mesh2->getVertexPosition(ee.edgeIdB.second);
+                                      const auto e1Center = (e1v0 + e1v1) * 0.5;
+                                      debugPoints->appendVertex(e1Center);
+
+                                      debugHighlightedLines->appendVertex(e0v0);
+                                      debugHighlightedLines->appendVertex(e0v1);
+                                      debugHighlightedLines->appendVertex(e1v0);
+                                      debugHighlightedLines->appendVertex(e1v1);
+
+                                      debugEEConnectingLines->appendVertex(e0Center);
+                                      debugEEConnectingLines->appendVertex(e1Center);
+                                  }
+                              }
+                          }
+
+                          debugPoints->setDataModified(true);
+                          debugVTConnectingLines->setDataModified(true);
+                          debugEEConnectingLines->setDataModified(true);
+                          debugHighlightedLines->setDataModified(true);
+
+                          std::stringstream ss;
+                          ss << "Octree update time: " << updateTime << " ms\n"
+                             << "Active nodes: " << numActiveNodes
+                             << " (" << static_cast<double>(numActiveNodes) / static_cast<double>(numTotalNodes) * 100.0
+                             << " % usage / total allocated nodes: " << numTotalNodes << ")\n"
+                             << "Num. primitives: " << numPrimitives
+                             << " | Max number of primitives in tree nodes: " << maxNumPrimitivesInTree
+                             << "\nCollision detection time: " << CDTime << " ms"
+                             << "\nNum. collision: " << numVTCollisions << " (VT) | "
+                             << numEECollisions << " (EE)";
+                          statusManager->setCustomStatus(ss.str());
+
+                          // Update debug rendering data
+                          for (auto& delegate : ren->getDebugRenderDelegates())
+                          {
+                              delegate->updateDataSource();
+                          }
+
+                          std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                      };
 
-                if (colData->EEColData.getSize())
-                {
-                    numEECollisions += colData->EEColData.getSize();
-                    const auto mesh1 = static_cast<SurfaceMesh*>(geoPair.first);
-                    const auto mesh2 = static_cast<SurfaceMesh*>(geoPair.second);
-                    for (size_t i = 0; i < colData->EEColData.getSize(); ++i)
-                    {
-                        const auto ee = colData->EEColData[i];
+    // Set Camera configuration
+    scene->getActiveCamera()->setPosition(Vec3d(0.0, 15.0, 50.0));
 
-                        const auto e0v0     = mesh1->getVertexPosition(ee.edgeIdA.first);
-                        const auto e0v1     = mesh1->getVertexPosition(ee.edgeIdA.second);
-                        const auto e0Center = (e0v0 + e0v1) * 0.5;
-                        debugPoints->appendVertex(e0Center);
+    // Light
+    imstkNew<DirectionalLight> light1("Light1");
+    light1->setFocalPoint(Vec3d(-1.0, -1.0, -1.0));
+    light1->setIntensity(1.0);
+    scene->addLight(light1);
 
-                        const auto e1v0     = mesh2->getVertexPosition(ee.edgeIdB.first);
-                        const auto e1v1     = mesh2->getVertexPosition(ee.edgeIdB.second);
-                        const auto e1Center = (e1v0 + e1v1) * 0.5;
-                        debugPoints->appendVertex(e1Center);
+    imstkNew<DirectionalLight> light2("Light2");
+    light2->setFocalPoint(Vec3d(1.0, -1.0, -1.0));
+    light2->setIntensity(1.0);
+    scene->addLight(light2);
 
-                        debugHighlightedLines->appendVertex(e0v0);
-                        debugHighlightedLines->appendVertex(e0v1);
-                        debugHighlightedLines->appendVertex(e1v0);
-                        debugHighlightedLines->appendVertex(e1v1);
+    // Run the simulation
+    {
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        connect<Event>(sceneManager, EventType::PostUpdate, updateFunc);
 
-                        debugEEConnectingLines->appendVertex(e0Center);
-                        debugEEConnectingLines->appendVertex(e1Center);
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+
+            // Add an extra control
+            connect<KeyPressEvent>(viewer->getKeyboardDevice(), EventType::KeyPress,
+                [&](KeyPressEvent* e)
+            {
+                if (e->m_key == 'b' && e->m_keyPressType == KEY_PRESS)
+                {
+                    for (auto& dir : dirs)
+                    {
+                        dir = -dir;
                     }
                 }
-            }
-
-            debugPoints->setDataModified(true);
-            debugVTConnectingLines->setDataModified(true);
-            debugEEConnectingLines->setDataModified(true);
-            debugHighlightedLines->setDataModified(true);
-
-            std::stringstream ss;
-            ss << "Octree update time: " << updateTime << " ms\n"
-               << "Active nodes: " << numActiveNodes
-               << " (" << static_cast<double>(numActiveNodes) / static_cast<double>(numTotalNodes) * 100.0
-               << " % usage / total allocated nodes: " << numTotalNodes << ")\n"
-               << "Num. primitives: " << numPrimitives
-               << " | Max number of primitives in tree nodes: " << maxNumPrimitivesInTree
-               << "\nCollision detection time: " << CDTime << " ms"
-               << "\nNum. collision: " << numVTCollisions << " (VT) | "
-               << numEECollisions << " (EE)";
-            statusManager->setCustomStatus(ss.str());
-
-            // Update debug rendering data
-            for (auto& delegate : renderer->getDebugRenderDelegates())
-            {
-                delegate->updateDataSource();
-            }
-
-            std::this_thread::sleep_for(std::chrono::milliseconds(100));
-        };
-    simManager->getSceneManager(scene)->setPostUpdateCallback(updateFunc);
-
-    // Press 'b' key to move objects in the reverse directions
-    viewer->setOnCharFunction('b',
-        [&](InteractorStyle*) -> bool
-    {
-        for (auto& dir : dirs)
-        {
-            dir = -dir;
+                });
         }
-        return true;
-    });
 
-    // Set Camera configuration
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(0, 15, 50));
-    cam->setFocalPoint(Vec3d(0, 0, 0));
-
-    // Light
-    {
-        auto light = std::make_shared<DirectionalLight>("Light 1");
-        light->setFocalPoint(Vec3d(-1, -1, -1));
-        light->setIntensity(1);
-        scene->addLight(light);
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
     }
-    {
-        auto light = std::make_shared<DirectionalLight>("Light 2");
-        light->setFocalPoint(Vec3d(1, -1, -1));
-        light->setIntensity(1);
-        scene->addLight(light);
-    }
-
-    // Run
-    simManager->start(SimulationStatus::Paused);
 
     return 0;
 }
diff --git a/Examples/CollisionDetection/Sphere.cpp b/Examples/CollisionDetection/Sphere.cpp
index f51842b78010099b998469758090a3b0629efde2..3dcc96683614fcffdb94b879760f9c1d5fa92417 100644
--- a/Examples/CollisionDetection/Sphere.cpp
+++ b/Examples/CollisionDetection/Sphere.cpp
@@ -22,6 +22,7 @@
 #include "imstkMath.h"
 
 #include <array>
+
 using namespace imstk;
 
 std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>>
diff --git a/Examples/CollisionDetection/Triangle.cpp b/Examples/CollisionDetection/Triangle.cpp
index c2c396fdb42256f056df1ea30c4c2e1076d0b62a..75fdd40c84a40b828a578d8fad1cd2850361f76c 100644
--- a/Examples/CollisionDetection/Triangle.cpp
+++ b/Examples/CollisionDetection/Triangle.cpp
@@ -22,6 +22,7 @@
 #include "imstkMath.h"
 
 #include <array>
+
 using namespace imstk;
 
 std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>>
diff --git a/Examples/CreateEnclosingMesh/CreateEnclosingMesh.cpp b/Examples/CreateEnclosingMesh/CreateEnclosingMesh.cpp
index 0fe78bb592a44389ceb61cab79e045de1cb73c01..2eaeef02cc57c46b1fb017cb7ca45538cdf5b96e 100644
--- a/Examples/CreateEnclosingMesh/CreateEnclosingMesh.cpp
+++ b/Examples/CreateEnclosingMesh/CreateEnclosingMesh.cpp
@@ -19,17 +19,22 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkSceneManager.h"
-#include "imstkLight.h"
 #include "imstkCamera.h"
-#include "imstkAPIUtilities.h"
-#include "imstkSurfaceMesh.h"
-#include "imstkTetrahedralMesh.h"
-#include "imstkMeshIO.h"
-#include "imstkVTKMeshIO.h"
 #include "imstkGeometryUtilities.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObject.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTetrahedralMesh.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -38,50 +43,77 @@ const size_t nx = 80 / 2, ny = 40 / 2, nz = 40 / 2;
 int
 main()
 {
-    // Create simulation manager
-    auto simManager = std::make_shared<SimulationManager>();
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
 
     // Create a sample scene
-    auto scene = simManager->createNewScene("renderMesh");
-    scene->getCamera()->setPosition(0, 2.0, 15.0);
-
-    // add scene object for surface object
-    auto surfaceObject = std::make_shared<VisualObject>("SurfaceObj");
-
-    auto surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"));
-
-    // configure and add the render model to the scene object
-    auto material = std::make_shared<RenderMaterial>();
-    material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
-    material->setColor(Color::LightGray);
-    auto surfMeshModel = std::make_shared<VisualModel>(surfMesh);
-    surfMeshModel->setRenderMaterial(material);
-    surfaceObject->addVisualModel(surfMeshModel);
-
-    // add the scene object to the scene
-    scene->addSceneObject(surfaceObject);
-
-    auto tetMesh = GeometryUtils::createTetrahedralMeshCover(surfMesh, nx, ny, nz);
-
-    // add scene object for surface object
-    auto volObject   = std::make_shared<VisualObject>("VolObj");
-    auto tetMaterial = std::make_shared<RenderMaterial>();
-    tetMaterial->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
-    tetMaterial->setEdgeColor(Color::Teal);
-    tetMaterial->setPointSize(7.);
-    tetMaterial->setLineWidth(3.);
-    auto tetVizModel = std::make_shared<VisualModel>(tetMesh, tetMaterial);
-    volObject->addVisualModel(tetVizModel);
-
-    scene->addSceneObject(volObject);
-
-    // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
-    scene->addLight(light);
-
-    simManager->setActiveScene(scene);
-    simManager->getViewer()->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true);
-    simManager->start();
+    imstkNew<Scene> scene("renderMesh");
+    {
+        scene->getActiveCamera()->setPosition(0.0, 2.0, 15.0);
+
+        // add scene object for surface object
+        imstkNew<VisualObject> surfObj("SurfaceObject");
+
+        auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
+
+        // configure and add the render model to the scene object
+        imstkNew<RenderMaterial> material;
+        material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+        material->setColor(Color::LightGray);
+        imstkNew<VisualModel> visualModel(surfMesh);
+        visualModel->setRenderMaterial(material);
+        surfObj->addVisualModel(visualModel);
+
+        // add the scene object to the scene
+        scene->addSceneObject(surfObj);
+
+        std::shared_ptr<TetrahedralMesh> tetMesh =
+            GeometryUtils::createTetrahedralMeshCover(surfMesh, nx, ny, nz);
+
+        // add scene object for surface object
+        imstkNew<VisualObject>   volObject("VolObj");
+        imstkNew<RenderMaterial> tetMaterial;
+        tetMaterial->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
+        tetMaterial->setEdgeColor(Color::Teal);
+        tetMaterial->setPointSize(7.0);
+        tetMaterial->setLineWidth(3.0);
+        imstkNew<VisualModel> tetVisualModel(tetMesh, tetMaterial);
+        volObject->addVisualModel(tetVisualModel);
+
+        scene->addSceneObject(volObject);
+
+        // Light
+        imstkNew<DirectionalLight> light("light");
+        light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+        light->setIntensity(1);
+        scene->addLight(light);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+        viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        viewer->start();
+    }
 }
diff --git a/Examples/DebugRendering/DebugRenderingExample.cpp b/Examples/DebugRendering/DebugRenderingExample.cpp
index 7e8ab3551d168247e5c53b7f369eeaf4a96ed163..f91fcb295b624f4c3afe166726cf9a17bf8ebae9 100644
--- a/Examples/DebugRendering/DebugRenderingExample.cpp
+++ b/Examples/DebugRendering/DebugRenderingExample.cpp
@@ -19,32 +19,33 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkSceneObject.h"
-#include "imstkLight.h"
 #include "imstkCamera.h"
-#include "imstkSceneManager.h"
 #include "imstkDebugRenderGeometry.h"
-#include "imstkAPIUtilities.h"
-#include "imstkVTKViewer.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkRenderMaterial.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKRenderDelegate.h"
 #include "imstkVTKRenderer.h"
 #include "imstkVTKTextStatusManager.h"
-#include "imstkScene.h"
-
-#include <thread>
-#include <chrono>
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
 std::shared_ptr<DebugRenderPoints>
 addPointsDebugRendering(const std::shared_ptr<Scene>& scene)
 {
-    auto debugPoints = std::make_shared<DebugRenderPoints>("Debug Points");
-    auto material    = std::make_shared<RenderMaterial>();
+    imstkNew<DebugRenderPoints> debugPoints("Debug Points");
+    imstkNew<RenderMaterial>    material;
     material->setDisplayMode(RenderMaterial::DisplayMode::Points);
     material->setPointSize(6.);
-    auto vizModel = std::make_shared<VisualModel>(debugPoints, material);
-    scene->addDebugVisualModel(vizModel);
+    imstkNew<VisualModel> visualModel(debugPoints.get(), material);
+    scene->addDebugVisualModel(visualModel);
 
     return debugPoints;
 }
@@ -52,14 +53,14 @@ addPointsDebugRendering(const std::shared_ptr<Scene>& scene)
 std::shared_ptr<DebugRenderLines>
 addLinesDebugRendering(const std::shared_ptr<Scene>& scene)
 {
-    auto debugLines = std::make_shared<DebugRenderLines>("Debug Lines");
-    auto material   = std::make_shared<RenderMaterial>();
+    imstkNew<DebugRenderLines> debugLines("Debug Lines");
+    imstkNew<RenderMaterial>   material;
     material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
     //material->setBackFaceCulling(false);
     material->setEdgeColor(Color::Green);
     material->setLineWidth(4.0);
-    auto vizModel = std::make_shared<VisualModel>(debugLines, material);
-    scene->addDebugVisualModel(vizModel);
+    imstkNew<VisualModel> visualModel(debugLines.get(), material);
+    scene->addDebugVisualModel(visualModel);
 
     return debugLines;
 }
@@ -67,19 +68,19 @@ addLinesDebugRendering(const std::shared_ptr<Scene>& scene)
 std::shared_ptr<DebugRenderTriangles>
 addTrianglesDebugRendering(const std::shared_ptr<Scene>& scene)
 {
-    auto debugTriangles = std::make_shared<DebugRenderTriangles>("Debug Triangles");
-    auto material       = std::make_shared<RenderMaterial>();
+    imstkNew<DebugRenderTriangles> debugTriangles("Debug Triangles");
+    imstkNew<RenderMaterial>       material;
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
     material->setBackFaceCulling(false);
     material->setColor(Color::Red);
-    auto vizModel = std::make_shared<VisualModel>(debugTriangles, material);
-    scene->addDebugVisualModel(vizModel);
+    imstkNew<VisualModel> visualModel(debugTriangles.get(), material);
+    scene->addDebugVisualModel(visualModel);
 
     return debugTriangles;
 }
 
 Vec3d
-getRandomPositions(double radius)
+getRandomPositions(const double radius)
 {
     return radius * Vec3d(2.0 * static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 1.0,
                           2.0 * static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 1.0,
@@ -92,20 +93,21 @@ getRandomPositions(double radius)
 int
 main()
 {
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("Debug rendering example");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    // Create a scene
+    imstkNew<Scene> scene("Debug rendering example");
 
-    // Get the VTKViewer
-    std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false);
+    // Setup a viewer to render in its own thread
+    imstkNew<VTKViewer> viewer("Viewer");
+    viewer->setActiveScene(scene);
     viewer->setWindowTitle("Debug Rendering");
-    viewer->getVtkRenderWindow()->SetSize(1920, 1080);
-    simManager->setViewer(viewer);
-    simManager->setActiveScene(scene); // Viewer has depedence on scene
+    viewer->setSize(1920, 1080);
 
     auto statusManager = viewer->getTextStatusManager();
-    statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30);
-    statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Orange);
+    statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 30);
+    statusManager->setStatusFontColor(VTKTextStatusManager::StatusType::Custom, Color::Orange);
 
     // Get VTK Renderer
     auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer());
@@ -119,7 +121,8 @@ main()
     int count = 0; // The number of times cycling between modes
 
     auto updateFunc =
-        [&](Module*) {
+        [&](Event*)
+        {
             if (count > 15)
             {
                 count = 0;
@@ -169,29 +172,43 @@ main()
 
             std::this_thread::sleep_for(std::chrono::milliseconds(500));
         };
-    simManager->getSceneManager(scene)->setPostUpdateCallback(updateFunc);
 
     // Set Camera configuration
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(0, 0, 50));
-    cam->setFocalPoint(Vec3d(0, 0, 0));
+    scene->getActiveCamera()->setPosition(Vec3d(0.0, 0.0, 50.0));
 
     // Light
+    imstkNew<DirectionalLight> light1("light1");
+    light1->setFocalPoint(Vec3d(-1.0, -1.0, -1.0));
+    light1->setIntensity(1.0);
+    scene->addLight(light1);
+
+    imstkNew<DirectionalLight> light2("light2");
+    light2->setFocalPoint(Vec3d(1.0, -1.0, -1.0));
+    light2->setIntensity(1.0);
+    scene->addLight(light2);
+
+    // Run the simulation
     {
-        auto light = std::make_shared<DirectionalLight>("Light 1");
-        light->setFocalPoint(Vec3d(-1, -1, -1));
-        light->setIntensity(1);
-        scene->addLight(light);
-    }
-    {
-        auto light = std::make_shared<DirectionalLight>("Light 2");
-        light->setFocalPoint(Vec3d(1, -1, -1));
-        light->setIntensity(1);
-        scene->addLight(light);
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        connect<Event>(sceneManager, EventType::PostUpdate, updateFunc);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        viewer->start();
     }
 
-    // Run
-    simManager->start();
-
     return 0;
 }
diff --git a/Examples/DeformableBody/DeformableBodyExample.cpp b/Examples/DeformableBody/DeformableBodyExample.cpp
index f6367107bef7acf2a86adbeee6218be9ae8e3952..132aa971517e0c2ec2f64a41e6ac70eab35a2fa8 100644
--- a/Examples/DeformableBody/DeformableBodyExample.cpp
+++ b/Examples/DeformableBody/DeformableBodyExample.cpp
@@ -19,31 +19,45 @@
 
 =========================================================================*/
 
-#include "imstkTimer.h"
-#include "imstkSimulationManager.h"
-#include "imstkFeDeformableObject.h"
 #include "imstkBackwardEuler.h"
-#include "imstkNonLinearSystem.h"
-#include "imstkNewtonSolver.h"
-#include "imstkGaussSeidel.h"
-#include "imstkPlane.h"
-#include "imstkTetrahedralMesh.h"
-#include "imstkMeshIO.h"
-#include "imstkOneToOneMap.h"
-#include "imstkAPIUtilities.h"
-#include "imstkConjugateGradient.h"
-#include "imstkLight.h"
 #include "imstkCamera.h"
+#include "imstkFeDeformableObject.h"
 #include "imstkFEMDeformableBodyModel.h"
-#include "imstkSurfaceMesh.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkOneToOneMap.h"
+#include "imstkPlane.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
-#include <memory>
+#include "imstkSceneManager.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTetrahedralMesh.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
-std::shared_ptr<DynamicObject> createAndAddFEDeformable(std::shared_ptr<Scene> scene, std::shared_ptr<PointSet> tetMesh);
+std::shared_ptr<DynamicObject> createAndAddFEDeformable(std::shared_ptr<Scene> scene, std::shared_ptr<TetrahedralMesh> tetMesh);
+
+enum Geom
+{
+    Dragon = 0,
+    Heart
+};
+
+struct Input
+{
+    std::string meshFileName;
+    std::vector<std::size_t> fixedNodeIds;
+};
 
-const std::string meshFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg";
+// Geom geom = Dragon;
+const Geom geom = Heart;
+Input      input;
 
 ///
 /// \brief This example demonstrates the soft body simulation
@@ -52,82 +66,114 @@ const std::string meshFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg";
 int
 main()
 {
-    // simManager and Scene
-    auto simConfig = std::make_shared<SimManagerConfig>();
-    simConfig->simulationMode = SimulationMode::Rendering;
-    auto simManager = std::make_shared<SimulationManager>(simConfig);
-    auto scene      = simManager->createNewScene("DeformableBodyFEM");
-    scene->getCamera()->setPosition(0, 2.0, 15.0);
-
-    // Load a tetrahedral mesh
-    auto tetMesh = MeshIO::read(meshFileName);
-
-    CHECK(tetMesh != nullptr) << "Could not read mesh from file.";
-
-    // Scene object 1: fe-FeDeformableObject
-    auto deformableObj = createAndAddFEDeformable(scene, tetMesh);
-    auto dynaModel     = std::dynamic_pointer_cast<FEMDeformableBodyModel>(deformableObj->getDynamicalModel());
-
-    // Scene object 2: Plane
-    auto planeGeom = std::make_shared<Plane>();
-    planeGeom->setWidth(40);
-    planeGeom->setPosition(0, -6, 0);
-    auto planeObj = std::make_shared<CollidingObject>("Plane");
-    planeObj->setVisualGeometry(planeGeom);
-    planeObj->setCollidingGeometry(planeGeom);
-    scene->addSceneObject(planeObj);
-
-    // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
-    scene->addLight(light);
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    if (geom == Dragon)
+    {
+        input.meshFileName = iMSTK_DATA_ROOT "asianDragon/asianDragon.veg";
+        input.fixedNodeIds = { 50, 126, 177 };
+    }
+    else if (geom == Heart)
+    {
+        input.meshFileName = iMSTK_DATA_ROOT "/heart/heart.veg";
+        input.fixedNodeIds = { 75, 82, 84, 94, 95, 105, 110, 124, 139, 150, 161, 171, 350 };
+    }
+
+    // Construct the scene
+    imstkNew<Scene> scene("DeformableBodyFEM");
+    {
+        std::shared_ptr<Camera> cam = scene->getActiveCamera();
+        cam->setPosition(0.0, 2.0, -25.0);
+        cam->setFocalPoint(0.0, 0.0, 0.0);
+
+        // Load a tetrahedral mesh
+        auto tetMesh = MeshIO::read<TetrahedralMesh>(input.meshFileName);
+        CHECK(tetMesh != nullptr) << "Could not read mesh from file.";
+
+        // Scene object 1: fe-FeDeformableObject
+        std::shared_ptr<DynamicObject> deformableObj = createAndAddFEDeformable(scene, tetMesh);
+
+        // Scene object 2: Plane
+        imstkNew<Plane> planeGeom;
+        planeGeom->setWidth(40);
+        planeGeom->setPosition(0, -6, 0);
+        imstkNew<CollidingObject> planeObj("Plane");
+        planeObj->setVisualGeometry(planeGeom);
+        planeObj->setCollidingGeometry(planeGeom);
+        scene->addSceneObject(planeObj);
+
+        // Light
+        imstkNew<DirectionalLight> light("light");
+        light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+        light->setIntensity(1);
+        scene->addLight(light);
+    }
 
     // Run the simulation
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer 1");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager 1");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
 
 std::shared_ptr<DynamicObject>
-createAndAddFEDeformable(std::shared_ptr<Scene>    scene,
-                         std::shared_ptr<PointSet> tetMesh)
+createAndAddFEDeformable(std::shared_ptr<Scene>           scene,
+                         std::shared_ptr<TetrahedralMesh> tetMesh)
 {
-    auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh);
-    CHECK(volTetMesh != nullptr) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!";
-    auto surfMesh = std::make_shared<SurfaceMesh>();
-    volTetMesh->extractSurfaceMesh(surfMesh, true);
+    imstkNew<SurfaceMesh> surfMesh;
+    tetMesh->extractSurfaceMesh(surfMesh, true);
 
     // Configure dynamic model
-    auto dynaModel = std::make_shared<FEMDeformableBodyModel>();
-    auto config    = std::make_shared<FEMModelConfig>();
-    config->m_fixedNodeIds = { 50, 126, 177 };
+    imstkNew<FEMDeformableBodyModel> dynaModel;
+    imstkNew<FEMModelConfig>         config;
+    config->m_fixedNodeIds = input.fixedNodeIds;
     dynaModel->configure(config);
     //dynaModel->configure(iMSTK_DATA_ROOT "/asianDragon/asianDragon.config");
 
     dynaModel->setTimeStepSizeType(TimeSteppingType::Fixed);
-    dynaModel->setModelGeometry(volTetMesh);
-    auto timeIntegrator = std::make_shared<BackwardEuler>(0.01);// Create and add Backward Euler time integrator
+    dynaModel->setModelGeometry(tetMesh);
+    imstkNew<BackwardEuler> timeIntegrator(0.01); // Create and add Backward Euler time integrator
     dynaModel->setTimeIntegrator(timeIntegrator);
 
-    auto material = std::make_shared<RenderMaterial>();
-    material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    material->setPointSize(10.);
-    material->setLineWidth(4.);
-    material->setEdgeColor(Color::Color::Orange);
-    auto surfMeshModel = std::make_shared<VisualModel>(surfMesh);
-    surfMeshModel->setRenderMaterial(material);
+    imstkNew<RenderMaterial> mat;
+    mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+    mat->setPointSize(10.);
+    mat->setLineWidth(4.);
+    mat->setEdgeColor(Color::Orange);
+    imstkNew<VisualModel> surfMeshModel(surfMesh.get());
+    surfMeshModel->setRenderMaterial(mat);
 
     // Scene object 1: Dragon
-    auto deformableObj = std::make_shared<FeDeformableObject>("Dragon");
+    imstkNew<FeDeformableObject> deformableObj("Dragon");
     deformableObj->addVisualModel(surfMeshModel);
-
-    deformableObj->setPhysicsGeometry(volTetMesh);
-
-    // Construct one to one nodal map based on the above meshes
-    auto oneToOneNodalMap = std::make_shared<OneToOneMap>(tetMesh, surfMesh);
-    deformableObj->setPhysicsToVisualMap(oneToOneNodalMap); //assign the computed map
+    deformableObj->setPhysicsGeometry(tetMesh);
+    // Map simulated geometry to visual
+    deformableObj->setPhysicsToVisualMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh));
     deformableObj->setDynamicalModel(dynaModel);
     scene->addSceneObject(deformableObj);
 
diff --git a/Examples/GeometryProcessing/CMakeLists.txt b/Examples/GeometryProcessing/CMakeLists.txt
index 9ed9446ba528efa332d3fcfd57371fa9ff47f766..0abe14903b4ffbda995eaa3d783c1fe8e8f9b060 100644
--- a/Examples/GeometryProcessing/CMakeLists.txt
+++ b/Examples/GeometryProcessing/CMakeLists.txt
@@ -31,4 +31,4 @@ SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples)
 #-----------------------------------------------------------------------------
 # Link libraries to executable
 #-----------------------------------------------------------------------------
-target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities)
+target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities Filtering)
diff --git a/Examples/GeometryProcessing/GeometryProcessingExample.cpp b/Examples/GeometryProcessing/GeometryProcessingExample.cpp
index 5a050fb534c2aed0e2fb9882bb9154c8ffe4b1ab..c0a793d99f05e195931c06d1c726b0a2289d25b6 100644
--- a/Examples/GeometryProcessing/GeometryProcessingExample.cpp
+++ b/Examples/GeometryProcessing/GeometryProcessingExample.cpp
@@ -19,81 +19,114 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkSceneObject.h"
-#include "imstkLight.h"
-#include "imstkPlane.h"
-#include "imstkCylinder.h"
-#include "imstkCube.h"
-#include "imstkAPIUtilities.h"
-#include "imstkGeometryUtilities.h"
 #include "imstkCamera.h"
+#include "imstkDataArray.h"
+#include "imstkImageData.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
 #include "imstkMeshIO.h"
+#include "imstkNew.h"
+#include "imstkQuadricDecimate.h"
+#include "imstkRenderMaterial.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObject.h"
 #include "imstkSurfaceMesh.h"
+#include "imstkSurfaceMeshDistanceTransform.h"
+#include "imstkSurfaceMeshFlyingEdges.h"
 #include "imstkTetrahedralMesh.h"
-#include "imstkScene.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
 ///
-/// \brief This example demonstrates the geometry transforms in imstk
+/// \brief This example demonstrates erosion of a mesh
 ///
 int
 main()
 {
+    Logger::startLogger();
+
     // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("GeometryTransforms");
+    imstkNew<Scene> scene("GeometryProcessing");
 
-    auto coarseTetMesh  = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"));
-    auto coarseSurfMesh = std::make_shared<SurfaceMesh>();
+    auto                  coarseTetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    imstkNew<SurfaceMesh> coarseSurfMesh;
     coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true);
 
-    std::shared_ptr<SurfaceMesh> fineSurfaceMesh(std::move(GeometryUtils::loopSubdivideSurfaceMesh(coarseSurfMesh)));
-
-    fineSurfaceMesh->translate(Vec3d(0., -5., 0.), Geometry::TransformType::ConcatenateToTransform);
-    coarseSurfMesh->translate(Vec3d(0., 5., 0.), Geometry::TransformType::ConcatenateToTransform);
-
-    auto material0 = std::make_shared<RenderMaterial>();
-    material0->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    material0->setPointSize(10.);
-    material0->setLineWidth(4.);
-    material0->setEdgeColor(Color::Color::Orange);
-    auto surfMeshModel0 = std::make_shared<VisualModel>(coarseSurfMesh);
-    surfMeshModel0->setRenderMaterial(material0);
-
-    auto sceneObj0 = std::make_shared<VisualObject>("coarse Mesh");
-    sceneObj0->addVisualModel(surfMeshModel0);
-
-    scene->addSceneObject(sceneObj0);
-
-    auto material = std::make_shared<RenderMaterial>();
-    material->setColor(imstk::Color::Red);
-    material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
-    material->setPointSize(6.);
-    material->setLineWidth(1.);
-    auto surfMeshModel = std::make_shared<VisualModel>(fineSurfaceMesh);
-    surfMeshModel->setRenderMaterial(material);
-
-    auto sceneObj = std::make_shared<VisualObject>("fine Mesh");
-    sceneObj->addVisualModel(surfMeshModel);
-
+    // Compute DT
+    imstkNew<SurfaceMeshDistanceTransform> createSdf;
+    createSdf->setInputMesh(coarseSurfMesh);
+    createSdf->setDimensions(150, 150, 150);
+    createSdf->update();
+
+    // Erode
+    const double       erosionDist = 0.2;
+    DataArray<double>& scalars     = *std::dynamic_pointer_cast<DataArray<double>>(createSdf->getOutputImage()->getScalars());
+    for (size_t i = 0; i < scalars.size(); i++)
+    {
+        scalars[i] += erosionDist;
+    }
+
+    // Extract surface
+    imstkNew<SurfaceMeshFlyingEdges> isoExtract;
+    isoExtract->setInputImage(createSdf->getOutputImage());
+    isoExtract->update();
+
+    // Reduce surface
+    imstkNew<QuadricDecimate> reduce;
+    reduce->setInputMesh(isoExtract->getOutputMesh());
+    reduce->setTargetReduction(0.5);
+    reduce->update();
+
+    // Create the scene object
+    imstkNew<VisualObject> sceneObj("Mesh");
+    // Create the eroded visual model
+    {
+        imstkNew<VisualModel>    surfMeshModel(reduce->getOutput());
+        imstkNew<RenderMaterial> material;
+        material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+        material->setLineWidth(4.0);
+        material->setEdgeColor(Color::Color::Orange);
+        surfMeshModel->setRenderMaterial(material);
+        sceneObj->addVisualModel(surfMeshModel);
+    }
+    // Create the original mesh visual model
+    {
+        imstkNew<VisualModel>    surfMeshModel(coarseSurfMesh.get());
+        imstkNew<RenderMaterial> material;
+        material->setColor(imstk::Color::Red);
+        material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+        material->setLineWidth(1.0);
+        material->setOpacity(0.2f);
+        surfMeshModel->setRenderMaterial(material);
+        sceneObj->addVisualModel(surfMeshModel);
+    }
     scene->addSceneObject(sceneObj);
 
     // Set Camera configuration
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(0, 12, 12));
-    cam->setFocalPoint(Vec3d(0, 0, 0));
+    scene->getActiveCamera()->setPosition(Vec3d(0.0, 12.0, 12.0));
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
+    imstkNew<DirectionalLight> light("light");
+    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
     light->setIntensity(1);
     scene->addLight(light);
 
-    // Run
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Running);
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/GeometryTransforms/GeometryTransformsExample.cpp b/Examples/GeometryTransforms/GeometryTransformsExample.cpp
index f80e4ef7b770d4e51f135fc793b9e1d6feacf263..ed6a7608206208986eb58dacd6fdb476d0737205 100644
--- a/Examples/GeometryTransforms/GeometryTransformsExample.cpp
+++ b/Examples/GeometryTransforms/GeometryTransformsExample.cpp
@@ -19,16 +19,22 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkSceneManager.h"
-#include "imstkSceneObject.h"
+#include "imstkAPIUtilities.h"
 #include "imstkCamera.h"
+#include "imstkCube.h"
+#include "imstkCylinder.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkPlane.h"
-#include "imstkCylinder.h"
-#include "imstkCube.h"
-#include "imstkAPIUtilities.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObject.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -38,96 +44,116 @@ using namespace imstk;
 int
 main()
 {
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("GeometryTransforms");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("GeometryTransforms");
 
     auto sceneObj = apiutils::createAndAddVisualSceneObject(scene, iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj", "Dragon");
 
     CHECK(sceneObj != nullptr) << "ERROR: Unable to create scene object";
 
     auto surfaceMesh = sceneObj->getVisualGeometry();
-    surfaceMesh->scale(5., Geometry::TransformType::ConcatenateToTransform);
+    surfaceMesh->scale(5.0, Geometry::TransformType::ConcatenateToTransform);
 
     //  Plane
-    auto planeGeom = std::make_shared<Plane>();
-    planeGeom->scale(80, Geometry::TransformType::ConcatenateToTransform);
-    planeGeom->translate(0, -20, 0, Geometry::TransformType::ConcatenateToTransform);
-    planeGeom->rotate(Vec3d(0, 1., 0), PI / 4, Geometry::TransformType::ConcatenateToTransform);
-
-    auto materialPlane = std::make_shared<RenderMaterial>();
-    materialPlane->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    materialPlane->setPointSize(6.);
-    materialPlane->setLineWidth(4.);
-    auto planeVizModel = std::make_shared<VisualModel>(planeGeom);
-    planeVizModel->setRenderMaterial(materialPlane);
-
-    auto planeObj = std::make_shared<VisualObject>("Plane");
+    imstkNew<Plane> planeGeom;
+    planeGeom->scale(80.0, Geometry::TransformType::ConcatenateToTransform);
+    planeGeom->translate(0.0, -20.0, 0.0, Geometry::TransformType::ConcatenateToTransform);
+    planeGeom->rotate(Vec3d(0.0, 1.0, 0.0), PI_4, Geometry::TransformType::ConcatenateToTransform);
+
+    imstkNew<RenderMaterial> planeMaterial;
+    planeMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+    planeMaterial->setPointSize(6.);
+    planeMaterial->setLineWidth(4.);
+    imstkNew<VisualModel> planeVisualModel(planeGeom.get());
+    planeVisualModel->setRenderMaterial(planeMaterial);
+
+    imstkNew<VisualObject> planeObj("Plane");
     //planeObj->setVisualGeometry(planeGeom);
-    planeObj->addVisualModel(planeVizModel);
+    planeObj->addVisualModel(planeVisualModel);
     scene->addSceneObject(planeObj);
 
     //  Cube
-    auto cubeGeom = std::make_shared<Cube>();
-    cubeGeom->setWidth(20.);
+    imstkNew<Cube> cubeGeom;
+    cubeGeom->setWidth(20.0);
     cubeGeom->scale(0.5, Geometry::TransformType::ConcatenateToTransform);
-    cubeGeom->rotate(Vec3d(1., 1., 0), PI / 4, Geometry::TransformType::ApplyToData);
-
-    auto materialCube = std::make_shared<RenderMaterial>();
-    materialCube->setColor(imstk::Color::Red);
-    materialCube->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    materialCube->setPointSize(6.);
-    materialCube->setLineWidth(4.);
-    auto cubeVizModel = std::make_shared<VisualModel>(cubeGeom);
-    cubeVizModel->setRenderMaterial(materialCube);
-
-    auto cubeObj = std::make_shared<VisualObject>("Cube");
-    //cubeObj->setVisualGeometry(cubeGeom);
-    cubeObj->addVisualModel(cubeVizModel);
+    cubeGeom->rotate(Vec3d(1.0, 1.0, 0.0), PI_4, Geometry::TransformType::ApplyToData);
+
+    auto                     materialCube = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> cubeMaterial;
+    cubeMaterial->setColor(imstk::Color::Red);
+    cubeMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+    cubeMaterial->setPointSize(6.);
+    cubeMaterial->setLineWidth(4.);
+    imstkNew<VisualModel> cubeVisualModel(cubeGeom.get());
+    cubeVisualModel->setRenderMaterial(cubeMaterial);
+
+    imstkNew<VisualObject> cubeObj("Cube");
+    cubeObj->addVisualModel(cubeVisualModel);
     scene->addSceneObject(cubeObj);
 
     //  Cylinder
-    auto CylinderGeom = std::make_shared<Cylinder>();
-    CylinderGeom->setRadius(4.);
-    CylinderGeom->setLength(8.);
-    CylinderGeom->scale(0.4, Geometry::TransformType::ConcatenateToTransform);
-    CylinderGeom->rotate(Vec3d(1., 1., 0), PI / 2, Geometry::TransformType::ApplyToData);
-
-    auto materialCyl = std::make_shared<RenderMaterial>();
-    materialCyl->setColor(imstk::Color::Red);
-    materialCyl->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    materialCyl->setPointSize(6.);
-    materialCyl->setLineWidth(4.);
-    auto cylVizModel = std::make_shared<VisualModel>(CylinderGeom);
-    cylVizModel->setRenderMaterial(materialCube);
-
-    auto CylinderObj = std::make_shared<VisualObject>("Cylinder");
-    //CylinderObj->setVisualGeometry(CylinderGeom);
-    CylinderObj->addVisualModel(cylVizModel);
-    scene->addSceneObject(CylinderObj);
-
-    // Rotate the dragon every frame
+    imstkNew<Cylinder> cylinderGeom;
+    cylinderGeom->setRadius(4.0);
+    cylinderGeom->setLength(8.0);
+    cylinderGeom->scale(0.4, Geometry::TransformType::ConcatenateToTransform);
+    cylinderGeom->rotate(Vec3d(1.0, 1.0, 0), PI_2, Geometry::TransformType::ApplyToData);
+
+    imstkNew<RenderMaterial> cylMaterial;
+    cylMaterial->setColor(imstk::Color::Red);
+    cylMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+    cylMaterial->setPointSize(6.0);
+    cylMaterial->setLineWidth(4.0);
+    imstkNew<VisualModel> cylVisualModel(cylinderGeom.get());
+    cylVisualModel->setRenderMaterial(materialCube);
+
+    imstkNew<VisualObject> cylObj("Cylinder");
+    cylObj->addVisualModel(cylVisualModel);
+    scene->addSceneObject(cylObj);
+
+    // Setup function to rotate the dragon every frame
     auto rotateFunc =
-        [&surfaceMesh](Module* module)
+        [&surfaceMesh](Event*)
         {
-            surfaceMesh->rotate(Vec3d(1., 0, 0), PI / 1000, Geometry::TransformType::ApplyToData);
+            surfaceMesh->rotate(Vec3d(1.0, 0.0, 0.0), PI * 0.0001, Geometry::TransformType::ApplyToData);
         };
-    simManager->getSceneManager(scene)->setPostUpdateCallback(rotateFunc);
 
     // Set Camera configuration
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(0, 30, 30));
-    cam->setFocalPoint(Vec3d(0, 0, 0));
+    scene->getActiveCamera()->setPosition(Vec3d(0.0, 30.0, 30.0));
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
+    imstkNew<DirectionalLight> light("light");
+    light->setDirection(Vec3d(5.0, -8.0, -5.0));
+    light->setIntensity(1.0);
     scene->addLight(light);
 
-    // Run
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Running);
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        connect<Event>(sceneManager, EventType::PostUpdate, rotateFunc);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/Graph/GraphExample.cpp b/Examples/Graph/GraphExample.cpp
index 7dff368ab5dff171bca762583a999232736ef5dc..a1f2aeb36510fb1301b3fa01228590d7847315af 100644
--- a/Examples/Graph/GraphExample.cpp
+++ b/Examples/Graph/GraphExample.cpp
@@ -19,13 +19,13 @@
 
 =========================================================================*/
 
+#include "imstkAPIUtilities.h"
 #include "imstkGraph.h"
-#include "imstkTetrahedralMesh.h"
+#include "imstkLogger.h"
 #include "imstkMeshIO.h"
-#include "imstkAPIUtilities.h"
+#include "imstkNew.h"
 #include "imstkSurfaceMesh.h"
-
-#include <iostream>
+#include "imstkTetrahedralMesh.h"
 
 using namespace imstk;
 
@@ -37,6 +37,8 @@ using namespace imstk;
 int
 main(int argc, char** argv)
 {
+    Logger::startLogger();
+
     // Using WelshPowell method by default
     Graph::ColoringMethod method = Graph::ColoringMethod::WelshPowell;
 
@@ -83,23 +85,22 @@ main(int argc, char** argv)
     g2.print();
     auto colorsG2 = g2.doColoring(method, true);
 
-    auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
     if (!tetMesh)
     {
-        std::cout << "Could not read mesh from file." << std::endl;
+        LOG(INFO) << "Could not read mesh from file.";
         return 1;
     }
     else
     {
-        auto volMesh      = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh);
-        auto colorsGVMesh = apiutils::getMeshGraph(volMesh)->doColoring(method, true);
+        auto colorsGVMesh = apiutils::getMeshGraph(tetMesh)->doColoring(method, true);
 
-        auto surfMesh = std::make_shared<SurfaceMesh>();
-        volMesh->extractSurfaceMesh(surfMesh, true);
-        auto colorsGSMesh = apiutils::getMeshGraph(surfMesh)->doColoring(method, true);
+        imstkNew<SurfaceMesh> surfMesh;
+        tetMesh->extractSurfaceMesh(surfMesh, true);
+        auto colorsGSMesh = apiutils::getMeshGraph(surfMesh.get())->doColoring(method, true);
     }
 
-    std::cout << "Press any key to exit!" << std::endl;
+    LOG(INFO) << "Press any key to exit!";
     getchar();
 
     return 0;
diff --git a/Examples/Interactions/CMakeLists.txt b/Examples/Interactions/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..964a9fe46555e89800ccc1ca30875fc8ac896dab
--- /dev/null
+++ b/Examples/Interactions/CMakeLists.txt
@@ -0,0 +1,21 @@
+#-----------------------------------------------------------------------------
+# Add Example subdirectories
+#-----------------------------------------------------------------------------
+macro(listOfSubDir result curdir)
+  file(GLOB children RELATIVE ${curdir} ${curdir}/*)
+  set(dirlist "")
+  foreach(child ${children})
+    if(IS_DIRECTORY ${curdir}/${child})
+      list(APPEND dirlist ${child})
+    endif()
+  endforeach()
+  set(${result} ${dirlist})
+endmacro()
+
+listOfSubDir(subDirs ${CMAKE_CURRENT_SOURCE_DIR})
+
+foreach(subdir ${subDirs})
+  add_subdirectory(${subdir})
+endforeach() 
+
+
diff --git a/Examples/Interactions/LevelSet-Rigid/CMakeLists.txt b/Examples/Interactions/LevelSet-Rigid/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..19424ad9054a3e7a6ff888831d6fa51f2350a0fc
--- /dev/null
+++ b/Examples/Interactions/LevelSet-Rigid/CMakeLists.txt
@@ -0,0 +1,34 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  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.
+#
+###########################################################################
+
+project(Example-LevelSet-RigidInteraction)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+imstk_add_executable(${PROJECT_NAME} LevelSet-RigidInteractionExample.cpp)
+
+#-----------------------------------------------------------------------------
+# Add the target to Examples folder
+#-----------------------------------------------------------------------------
+SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/Interaction)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} SimulationManager Filtering)
diff --git a/Examples/Interactions/LevelSet-Rigid/LevelSet-RigidInteractionExample.cpp b/Examples/Interactions/LevelSet-Rigid/LevelSet-RigidInteractionExample.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..da7be12fd68c495bfe2a5626b9536cd72870346d
--- /dev/null
+++ b/Examples/Interactions/LevelSet-Rigid/LevelSet-RigidInteractionExample.cpp
@@ -0,0 +1,229 @@
+/*=========================================================================
+
+   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 "imstkCamera.h"
+#include "imstkCollisionGraph.h"
+#include "imstkImageData.h"
+#include "imstkImplicitGeometryToImageData.h"
+#include "imstkLevelSetDeformableObject.h"
+#include "imstkLevelSetModel.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMeshIO.h"
+#include "imstkNew.h"
+#include "imstkOpenVRDeviceClient.h"
+#include "imstkPlane.h"
+#include "imstkRbdConstraint.h"
+#include "imstkRigidBodyModel2.h"
+#include "imstkRigidObject2.h"
+#include "imstkRigidObjectController.h"
+#include "imstkRigidObjectLevelSetCollisionPair.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkSurfaceMeshFlyingEdges.h"
+#include "imstkVisualModel.h"
+#include "imstkVolumeRenderMaterial.h"
+#include "imstkVTKOpenVRViewer.h"
+#include <vtkColorTransferFunction.h>
+#include <vtkPiecewiseFunction.h>
+#include <vtkVolumeProperty.h>
+#include "imstkSurfaceMeshSubdivide.h"
+
+using namespace imstk;
+using namespace imstk::expiremental;
+
+///
+/// \brief Creates cloth object
+///
+std::shared_ptr<LevelSetDeformableObject>
+makeLevelsetObj(const std::string& name)
+{
+    imstkNew<LevelSetDeformableObject> levelsetObj(name);
+
+    std::shared_ptr<ImageData> initLvlsetImage = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/legs/femurBone_SDF.nii")->cast(IMSTK_DOUBLE);
+    const Vec3d&               currSpacing     = initLvlsetImage->getSpacing();
+    initLvlsetImage->setSpacing(currSpacing * 0.0015);
+    initLvlsetImage->setOrigin(Vec3d(0.0, 1.0, -2.0));
+
+    // Setup the Parameters
+    imstkNew<LevelSetModelConfig> lvlSetConfig;
+    lvlSetConfig->m_sparseUpdate = true;
+    lvlSetConfig->m_dt = 0.001;
+
+    // Setup the Model
+    imstkNew<LevelSetModel> model;
+    model->setModelGeometry(initLvlsetImage);
+    model->configure(lvlSetConfig);
+
+    // Setup the VisualModel
+    imstkNew<VisualModel>          visualModel(initLvlsetImage);
+    imstkNew<VolumeRenderMaterial> mat;
+    {
+        vtkNew<vtkColorTransferFunction> color;
+        color->AddRGBPoint(0.0, 0.75, 0.73, 0.66);
+        mat->getVolumeProperty()->SetColor(color);
+        vtkNew<vtkPiecewiseFunction> opacity;
+        opacity->AddPoint(0.0, 0.0);
+        opacity->AddPoint(-0.001, 1.0);
+        mat->getVolumeProperty()->SetScalarOpacity(opacity);
+        mat->getVolumeProperty()->SetInterpolationTypeToLinear();
+        mat->getVolumeProperty()->ShadeOn();
+    }
+    visualModel->setRenderMaterial(mat);
+
+    // Setup the Object
+    levelsetObj->addVisualModel(visualModel);
+    levelsetObj->setPhysicsGeometry(initLvlsetImage);
+    levelsetObj->setCollidingGeometry(std::make_shared<SignedDistanceField>(initLvlsetImage));
+    levelsetObj->setDynamicalModel(model);
+
+    return levelsetObj;
+}
+
+std::shared_ptr<CollidingObject>
+makeCollidingObject(const std::string& name)
+{
+    imstkNew<CollidingObject> collideObj(name);
+
+    // Setup a plane, then cut with a sphere
+    imstkNew<Plane> plane(Vec3d(0.0, 0.0, 0.0), Vec3d(0.0, 1.0, 0.0));
+
+    // Put into an image
+    imstkNew<ImplicitGeometryToImageData> toSdf;
+    toSdf->setInputGeometry(plane);
+    Vec6d bounds;
+    bounds[0] = -5.0;
+    bounds[1] = 5.0;
+    bounds[2] = -5.0;
+    bounds[3] = 5.0;
+    bounds[4] = -5.0;
+    bounds[5] = 5.0;
+    toSdf->setBounds(bounds);
+    toSdf->setDimensions(Vec3i(35, 35, 35));
+    toSdf->update();
+    std::shared_ptr<ImageData> initLvlsetImage = toSdf->getOutputImage();
+
+    imstkNew<SurfaceMeshFlyingEdges> isoExtract;
+    isoExtract->setInputImage(initLvlsetImage);
+    isoExtract->update();
+
+    // Setup the VisualModel
+    imstkNew<VisualModel> visualModel(isoExtract->getOutputMesh());
+
+    // Setup the Object
+    collideObj->addVisualModel(visualModel);
+    collideObj->setCollidingGeometry(std::make_shared<SignedDistanceField>(initLvlsetImage));
+
+    return collideObj;
+}
+
+std::shared_ptr<RigidObject2>
+makeRigidObj(const std::string& name)
+{
+    imstkNew<RigidBodyModel2> rbdModel;
+    rbdModel->getConfig()->m_dt = 0.0005;
+    rbdModel->getConfig()->m_maxNumIterations = 10;
+
+    // Create the first rbd, plane floor
+    imstkNew<RigidObject2> rigidObj("Cube");
+
+    {
+        auto toolMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/Scalpel_Blade10_Hull.stl");
+        toolMesh->rotate(Vec3d(0.0, 1.0, 0.0), 3.14, Geometry::TransformType::ApplyToData);
+        toolMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.57, Geometry::TransformType::ApplyToData);
+        toolMesh->scale(0.07, Geometry::TransformType::ApplyToData);
+
+        imstkNew<VisualModel>    visualModel(toolMesh);
+        imstkNew<RenderMaterial> mat;
+        mat->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+        mat->setShadingModel(RenderMaterial::ShadingModel::PBR);
+        mat->setMetalness(0.9f);
+        mat->setRoughness(0.2f);
+        //mat->setDisplayMode(RenderMaterial::DisplayMode::Points);
+        //mat->setPointSize(15.0);
+        visualModel->setRenderMaterial(mat);
+
+        // Create the object
+        rigidObj->addVisualModel(visualModel);
+        rigidObj->setPhysicsGeometry(toolMesh);
+        rigidObj->setCollidingGeometry(toolMesh);
+        rigidObj->setVisualGeometry(toolMesh);
+        rigidObj->setDynamicalModel(rbdModel);
+        rigidObj->getRigidBody()->m_mass = 100.0;
+        rigidObj->getRigidBody()->setInertiaFromPointSet(toolMesh, 0.01, false);
+        rigidObj->getRigidBody()->m_initPos = Vec3d(0.0, 2.0, 0.0);
+    }
+    return rigidObj;
+}
+
+///
+/// \brief This example demonstrates evolution of a levelset
+///
+int
+main()
+{
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("LevelsetDeformable");
+    scene->getConfig()->writeTaskGraph = true;
+
+    std::shared_ptr<LevelSetDeformableObject> lvlSetObj = makeLevelsetObj("LevelSetObj");
+    scene->addSceneObject(lvlSetObj);
+
+    std::shared_ptr<RigidObject2> rbdObj = makeRigidObj("RigidObj");
+    scene->addSceneObject(rbdObj);
+
+    imstkNew<RigidObjectLevelSetCollisionPair> interaction(rbdObj, lvlSetObj);
+    scene->getCollisionGraph()->addInteraction(interaction);
+
+    // Light (white)
+    imstkNew<DirectionalLight> whiteLight("whiteLight");
+    whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+    whiteLight->setIntensity(1.0);
+    scene->addLight(whiteLight);
+
+    // Adjust camera
+    scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
+    scene->getActiveCamera()->setPosition(0.0, 10.0, -10.0);
+
+    {
+        // Add a module to run the viewer
+        imstkNew<VTKOpenVRViewer> viewer("VRViewer");
+        viewer->setActiveScene(scene);
+
+        // Add a module to run the scene
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // Start/stop scene with the view
+
+        // Add a VR controller for the sceneobject
+        imstkNew<RigidObjectController> controller(rbdObj, viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER));
+        scene->addController(controller);
+
+        // Start running
+        viewer->requestStatus(ThreadStatus::Running);
+        viewer->start();
+    }
+
+    return 0;
+}
\ No newline at end of file
diff --git a/Examples/Interactions/SPH-Obj-SDF/CMakeLists.txt b/Examples/Interactions/SPH-Obj-SDF/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ad294696502c30bb76b709361ee4d9c7dcbbd63e
--- /dev/null
+++ b/Examples/Interactions/SPH-Obj-SDF/CMakeLists.txt
@@ -0,0 +1,34 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  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.
+#
+###########################################################################
+
+project(Example-SPH-Obj-SDFInteraction)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+imstk_add_executable(${PROJECT_NAME} SPH-Obj-SDFInteractionExample.cpp)
+
+#-----------------------------------------------------------------------------
+# Add the target to Examples folder
+#-----------------------------------------------------------------------------
+SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/Interaction)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} SimulationManager Filtering)
diff --git a/Examples/Interactions/SPH-Obj-SDF/SPH-Obj-SDFInteractionExample.cpp b/Examples/Interactions/SPH-Obj-SDF/SPH-Obj-SDFInteractionExample.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1978990498370eeff54da7932fbb9ef75684a36b
--- /dev/null
+++ b/Examples/Interactions/SPH-Obj-SDF/SPH-Obj-SDFInteractionExample.cpp
@@ -0,0 +1,219 @@
+/*=========================================================================
+
+   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 "imstkCamera.h"
+#include "imstkCollisionGraph.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkRenderMaterial.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSignedDistanceField.h"
+#include "imstkSPHModel.h"
+#include "imstkSPHObject.h"
+#include "imstkSphObjectCollisionPair.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkSurfaceMeshDistanceTransform.h"
+#include "imstkViewer.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
+
+using namespace imstk;
+
+///
+/// \brief Generate a box-shape of fluid particles
+///
+std::shared_ptr<StdVectorOfVec3d>
+generateBoxShapeFluid(const double particleRadius, const Vec3d& boxCenter, const Vec3d& boxSize)
+{
+    double bounds[6] =
+    {
+        boxCenter.x() - boxSize.x() * 0.5,
+        boxCenter.x() + boxSize.x() * 0.5,
+        boxCenter.y() - boxSize.y() * 0.5,
+        boxCenter.y() + boxSize.y() * 0.5,
+        boxCenter.z() - boxSize.z() * 0.5,
+        boxCenter.z() + boxSize.z() * 0.5
+    };
+
+    const double spacing = 2.0 * particleRadius;
+    const Vec3i  dim     = {
+        static_cast<int>(boxSize.x() / spacing),
+        static_cast<int>(boxSize.y() / spacing),
+        static_cast<int>(boxSize.z() / spacing) };
+
+    imstkNew<StdVectorOfVec3d> particles;
+    particles->reserve(dim[0] * dim[1] * dim[2]);
+
+    for (double z = bounds[4]; z < bounds[5]; z += spacing)
+    {
+        for (double y = bounds[2]; y < bounds[3]; y += spacing)
+        {
+            for (double x = bounds[0]; x < bounds[1]; x += spacing)
+            {
+                particles->push_back(Vec3d(x, y, z));
+            }
+        }
+    }
+
+    return particles;
+}
+
+std::shared_ptr<SPHObject>
+makeSPHBoxObject(const std::string& name, const double particleRadius, const Vec3d& boxShift, const Vec3d& boxSize)
+{
+    // Create the sph object
+    imstkNew<SPHObject> fluidObj(name);
+
+    // Setup the Geometry
+    std::shared_ptr<StdVectorOfVec3d> particles = generateBoxShapeFluid(particleRadius, boxShift, boxSize);
+    LOG(INFO) << "Number of particles: " << particles->size();
+    imstkNew<PointSet> fluidGeometry;
+    fluidGeometry->initialize(*particles);
+
+    // Setup the Parameters
+    imstkNew<SPHModelConfig> sphParams(particleRadius);
+    sphParams->m_bNormalizeDensity = true;
+    sphParams->m_kernelOverParticleRadiusRatio = 6.0;
+    sphParams->m_viscosityCoeff = 0.5;
+    sphParams->m_surfaceTensionStiffness = 5.0;
+    sphParams->m_gravity = Vec3d(0.0, -70.0, 0.0);
+
+    // Setup the Model
+    imstkNew<SPHModel> sphModel;
+    sphModel->setModelGeometry(fluidGeometry);
+    sphModel->configure(sphParams);
+    sphModel->setTimeStepSizeType(TimeSteppingType::RealTime);
+
+    // Setup the VisualModel
+    imstkNew<VisualModel>    fluidVisualModel(fluidGeometry.get());
+    imstkNew<RenderMaterial> fluidMaterial;
+    fluidMaterial->setDisplayMode(RenderMaterial::DisplayMode::Fluid);
+    fluidMaterial->setVertexColor(Color::Orange);
+    fluidMaterial->setPointSize(static_cast<float>(particleRadius));
+    fluidVisualModel->setRenderMaterial(fluidMaterial);
+
+    // Setup the Object
+    fluidObj->addVisualModel(fluidVisualModel);
+    fluidObj->setCollidingGeometry(fluidGeometry);
+    fluidObj->setDynamicalModel(sphModel);
+    fluidObj->setPhysicsGeometry(fluidGeometry);
+
+    return fluidObj;
+}
+
+static std::shared_ptr<CollidingObject>
+makeDragonCollidingObject(const std::string& name, const Vec3d& position)
+{
+    // Create the pbd object
+    imstkNew<CollidingObject> collidingObj(name);
+
+    // Setup the Geometry (read dragon mesh)
+    auto dragonSurfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
+    dragonSurfMesh->translate(position, Geometry::TransformType::ApplyToData);
+
+    imstkNew<SurfaceMeshDistanceTransform> computeSdf;
+    computeSdf->setInputMesh(dragonSurfMesh);
+    computeSdf->setDimensions(100, 100, 100);
+    computeSdf->update();
+
+    // Setup the VisualModel
+    imstkNew<RenderMaterial> material;
+    material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+    imstkNew<VisualModel> surfMeshModel(dragonSurfMesh);
+    surfMeshModel->setRenderMaterial(material);
+
+    // Setup the Object
+    collidingObj->addVisualModel(surfMeshModel);
+    collidingObj->setCollidingGeometry(std::make_shared<SignedDistanceField>(computeSdf->getOutputImage()));
+
+    return collidingObj;
+}
+
+///
+/// \brief This example demonstrates interaction between sph fluid and a
+/// colliding object using signed distance fields (SDFs)
+///
+int
+main()
+{
+    // Write log to stdout and file
+    Logger::startLogger();
+
+    // Setup the scene
+    imstkNew<Scene> scene("SPH-Obj-SDFInteraction");
+    {
+        //scene->getConfig()->taskTimingEnabled = true;
+        scene->getActiveCamera()->setPosition(0, 2.0, 15.0);
+
+        // Static Dragon object
+        std::shared_ptr<CollidingObject> dragonObj = makeDragonCollidingObject("Dragon", Vec3d(0.0, 0.0, 0.0));
+        scene->addSceneObject(dragonObj);
+
+        // SPH fluid box overtop the dragon
+        std::shared_ptr<SPHObject> sphFluidBox = makeSPHBoxObject("Box", 0.1, Vec3d(0.0, 7.0, 0.0), Vec3d(3.0, 7.0, 3.0));
+        scene->addSceneObject(sphFluidBox);
+
+        // Interaction
+        imstkNew<SphObjectCollisionPair> interaction(sphFluidBox, dragonObj);
+        scene->getCollisionGraph()->addInteraction(interaction);
+
+        // Light
+        imstkNew<DirectionalLight> light("light");
+        light->setDirection(0.0, -1.0, -1.0);
+        light->setIntensity(1);
+        scene->addLight(light);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer 1");
+        viewer->setActiveScene(scene);
+        viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager 1");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
+
+    return 0;
+}
diff --git a/Examples/Levelset/CMakeLists.txt b/Examples/Levelset/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a7946cdf0d877d81e2967511b4feb209c88e981b
--- /dev/null
+++ b/Examples/Levelset/CMakeLists.txt
@@ -0,0 +1,34 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  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.
+#
+###########################################################################
+
+project(Example-Levelset)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+imstk_add_executable(${PROJECT_NAME} levelsetExample.cpp)
+
+#-----------------------------------------------------------------------------
+# Add the target to Examples folder
+#-----------------------------------------------------------------------------
+SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} SimulationManager Filtering)
diff --git a/Examples/Levelset/levelsetExample.cpp b/Examples/Levelset/levelsetExample.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1d9fbfbdbb13e0d7dd5267b3c7b9a7496a81084c
--- /dev/null
+++ b/Examples/Levelset/levelsetExample.cpp
@@ -0,0 +1,158 @@
+/*=========================================================================
+
+   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 "imstkCamera.h"
+#include "imstkCube.h"
+#include "imstkImageData.h"
+#include "imstkImplicitGeometryToImageData.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLevelSetDeformableObject.h"
+#include "imstkLevelSetModel.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkPlane.h"
+#include "imstkRenderMaterial.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSphere.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkSurfaceMeshDistanceTransform.h"
+#include "imstkVisualModel.h"
+#include "imstkVolumeRenderMaterial.h"
+#include "imstkVTKViewer.h"
+
+#include <vtkColorTransferFunction.h>
+#include <vtkPiecewiseFunction.h>
+#include <vtkVolumeProperty.h>
+
+using namespace imstk;
+
+///
+/// \brief Creates a shrinking level set dragon
+///
+std::shared_ptr<LevelSetDeformableObject>
+makeLevelsetObj(const std::string& name)
+{
+    imstkNew<LevelSetDeformableObject> levelsetObj(name);
+
+    // Setup the Geometry (read dragon mesh)
+    auto dragonSurfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
+    //dragonSurfMesh->translate(position, Geometry::TransformType::ApplyToData);
+    imstkNew<SurfaceMeshDistanceTransform> computeSdf;
+    computeSdf->setInputMesh(dragonSurfMesh);
+    computeSdf->setDimensions(50, 50, 50);
+    computeSdf->update();
+    std::shared_ptr<ImageData> initLvlsetImage = computeSdf->getOutputImage();
+
+    // Setup the Parameters
+    imstkNew<LevelSetModelConfig> lvlsetConfig;
+    lvlsetConfig->m_sparseUpdate = false;
+    lvlsetConfig->m_dt = 0.0003;
+    lvlsetConfig->m_constantVelocity = -6.0;
+
+    // Setup the Model
+    imstkNew<LevelSetModel> dynamicalModel;
+    dynamicalModel->setModelGeometry(initLvlsetImage);
+    dynamicalModel->configure(lvlsetConfig);
+
+    // Setup the VisualModel
+    imstkNew<VisualModel>          visualModel(initLvlsetImage);
+    imstkNew<VolumeRenderMaterial> mat;
+    {
+        vtkNew<vtkColorTransferFunction> color;
+        color->AddRGBPoint(0.0, 1.0, 0.0, 0.0);
+        color->AddRGBPoint(-0.01, 0.0, 0.0, 1.0);
+        mat->getVolumeProperty()->SetColor(color);
+        vtkNew<vtkPiecewiseFunction> opacity;
+        opacity->AddPoint(0.0, 0.0);
+        opacity->AddPoint(-0.01, 1.0);
+        mat->getVolumeProperty()->SetScalarOpacity(opacity);
+        mat->getVolumeProperty()->SetInterpolationTypeToLinear();
+        mat->getVolumeProperty()->ShadeOn();
+    }
+    visualModel->setRenderMaterial(mat);
+
+    // Setup the Object
+    levelsetObj->addVisualModel(visualModel);
+    levelsetObj->setPhysicsGeometry(initLvlsetImage);
+    levelsetObj->setDynamicalModel(dynamicalModel);
+
+    return levelsetObj;
+}
+
+///
+/// \brief This example demonstrates evolution of a levelset
+///
+int
+main()
+{
+    // Log to file and stdout
+    Logger::startLogger();
+
+    // Setup the scene
+    imstkNew<Scene> scene("Levelset");
+    {
+        std::shared_ptr<LevelSetDeformableObject> obj = makeLevelsetObj("DragonLevelset");
+        scene->addSceneObject(obj);
+
+        // Light (white)
+        imstkNew<DirectionalLight> whiteLight("whiteLight");
+        whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+        whiteLight->setIntensity(1.0);
+        scene->addLight(whiteLight);
+
+        // Adjust camera
+        scene->getActiveCamera()->setPosition(0.0, 10.0, -10.0);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
+
+    return 0;
+}
diff --git a/Examples/MeshIO/CMakeLists.txt b/Examples/MeshIO/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f749003dfa0637975632636f6325c54cf60e49c1
--- /dev/null
+++ b/Examples/MeshIO/CMakeLists.txt
@@ -0,0 +1,19 @@
+#-----------------------------------------------------------------------------
+# Add Example subdirectories
+#-----------------------------------------------------------------------------
+macro(listOfSubDir result curdir)
+  file(GLOB children RELATIVE ${curdir} ${curdir}/*)
+  set(dirlist "")
+  foreach(child ${children})
+    if(IS_DIRECTORY ${curdir}/${child})
+      list(APPEND dirlist ${child})
+    endif()
+  endforeach()
+  set(${result} ${dirlist})
+endmacro()
+
+listOfSubDir(subDirs ${CMAKE_CURRENT_SOURCE_DIR})
+
+foreach(subdir ${subDirs})
+  add_subdirectory(${subdir})
+endforeach() 
diff --git a/Examples/MeshIO/ConvertVTKToVega/CMakeLists.txt b/Examples/MeshIO/ConvertVTKToVega/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8c7b89cb5167089d4e3dcad7961a7fe657169974
--- /dev/null
+++ b/Examples/MeshIO/ConvertVTKToVega/CMakeLists.txt
@@ -0,0 +1,34 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  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.
+#
+###########################################################################
+
+project(Example-ConvertVTKToVega)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+imstk_add_executable(${PROJECT_NAME} ConvertVTKToVega.cpp)
+
+#-----------------------------------------------------------------------------
+# Add the target to Examples folder
+#-----------------------------------------------------------------------------
+SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/MeshIO)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} MeshIO)
diff --git a/Examples/MeshIO/ConvertVTKToVega/ConvertVTKToVega.cpp b/Examples/MeshIO/ConvertVTKToVega/ConvertVTKToVega.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..056c64db511ace4364dbedb82422601a0ac4e941
--- /dev/null
+++ b/Examples/MeshIO/ConvertVTKToVega/ConvertVTKToVega.cpp
@@ -0,0 +1,57 @@
+/*=========================================================================
+
+   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 "imstkMeshIO.h"
+#include "imstkVegaMeshIO.h"
+#include "imstkVTKMeshIO.h"
+#include "imstkTetrahedralMesh.h"
+
+#include <string>
+
+using namespace imstk;
+
+const std::string defaultFileName = iMSTK_DATA_ROOT "textured_organs/heart_volume.vtk";
+
+int
+main(int argc, char** argv)
+{
+    std::string vtkFileName  = defaultFileName;
+    std::string vegaFileName = "convertedMesh.veg";
+
+    if (argc > 1)
+    {
+        vtkFileName = std::string(argv[1]);
+    }
+
+    auto tetMesh = MeshIO::read<TetrahedralMesh>(vtkFileName);
+    tetMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.3, Geometry::TransformType::ApplyToData);
+    bool converted = VegaMeshIO::write(tetMesh, vegaFileName, MeshFileType::VEG);
+    {
+        std::string vtkFileName = "convertedMesh.vtk";
+        bool        converted   = VTKMeshIO::write(tetMesh, vtkFileName, MeshFileType::VTK);
+    }
+
+    if (converted)
+    {
+        return 0;
+    }
+    return 1;
+}
diff --git a/Examples/MultipleScenes/multipleScenes.cpp b/Examples/MultipleScenes/multipleScenes.cpp
index 8b5cd383bc0ab66fc08555a8da941cc08f20ffaf..c8fa6658955cf303e585e802b2e2c1b8d376f4d0 100644
--- a/Examples/MultipleScenes/multipleScenes.cpp
+++ b/Examples/MultipleScenes/multipleScenes.cpp
@@ -19,50 +19,160 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkPbdModel.h"
-#include "imstkPbdObject.h"
 #include "imstkAPIUtilities.h"
-#include "imstkOneToOneMap.h"
 #include "imstkCamera.h"
-#include "imstkSurfaceMesh.h"
+#include "imstkConsoleThread.h"
+#include "imstkKeyboardDeviceClient.h"
+#include "imstkLogger.h"
 #include "imstkMeshIO.h"
-#include "imstkTetrahedralMesh.h"
+#include "imstkNew.h"
+#include "imstkOneToOneMap.h"
+#include "imstkPbdModel.h"
+#include "imstkPbdObject.h"
 #include "imstkPlane.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTetrahedralMesh.h"
+#include "imstkViewer.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
+#include "imstkLight.h"
 
 using namespace imstk;
 
+///
+/// \brief Creates cloth geometry
+///
+static std::shared_ptr<SurfaceMesh>
+makeClothGeometry(const double width,
+                  const double height,
+                  const int    nRows,
+                  const int    nCols)
+{
+    imstkNew<SurfaceMesh> clothMesh;
+
+    StdVectorOfVec3d vertList;
+    vertList.resize(nRows * nCols);
+    const double dy = width / (double)(nCols - 1);
+    const double dx = height / (double)(nRows - 1);
+    for (int i = 0; i < nRows; ++i)
+    {
+        for (int j = 0; j < nCols; j++)
+        {
+            vertList[i * nCols + j] = Vec3d((double)dx * i, 1.0, (double)dy * j);
+        }
+    }
+    clothMesh->setInitialVertexPositions(vertList);
+    clothMesh->setVertexPositions(vertList);
+
+    // Add connectivity data
+    std::vector<SurfaceMesh::TriangleArray> triangles;
+    for (std::size_t i = 0; i < nRows - 1; ++i)
+    {
+        for (std::size_t j = 0; j < nCols - 1; j++)
+        {
+            SurfaceMesh::TriangleArray tri[2];
+            const size_t               index1 = i * nCols + j;
+            const size_t               index2 = index1 + nCols;
+            const size_t               index3 = index1 + 1;
+            const size_t               index4 = index2 + 1;
+
+            // Interleave [/][\]
+            if (i % 2 ^ j % 2)
+            {
+                tri[0] = { { index1, index2, index3 } };
+                tri[1] = { { index4, index3, index2 } };
+            }
+            else
+            {
+                tri[0] = { { index2, index4, index1 } };
+                tri[1] = { { index4, index3, index1 } };
+            }
+            triangles.push_back(tri[0]);
+            triangles.push_back(tri[1]);
+        }
+    }
+
+    clothMesh->setTrianglesVertices(triangles);
+
+    return clothMesh;
+}
+
+///
+/// \brief Creates cloth object
+///
+static std::shared_ptr<PbdObject>
+makeClothObj(const std::string& name,
+             const double       width,
+             const double       height,
+             const int          nRows,
+             const int          nCols)
+{
+    imstkNew<PbdObject> clothObj(name);
+
+    // Setup the Geometry
+    std::shared_ptr<SurfaceMesh> clothMesh(makeClothGeometry(width, height, nRows, nCols));
+
+    // Setup the Parameters
+    imstkNew<PBDModelConfig> pbdParams;
+    pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1.0e2);
+    pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1.0e1);
+    pbdParams->m_fixedNodeIds     = { 0, static_cast<size_t>(nCols) - 1 };
+    pbdParams->m_uniformMassValue = width * height / ((double)nRows * (double)nCols);
+    pbdParams->m_gravity    = Vec3d(0.0, -9.8, 0.0);
+    pbdParams->m_defaultDt  = 0.005;
+    pbdParams->m_iterations = 5;
+
+    // Setup the Model
+    imstkNew<PbdModel> pbdModel;
+    pbdModel->setModelGeometry(clothMesh);
+    pbdModel->configure(pbdParams);
+
+    // Setup the VisualModel
+    imstkNew<RenderMaterial> material;
+    material->setBackFaceCulling(false);
+    material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+
+    imstkNew<VisualModel> visualModel(clothMesh);
+    visualModel->setRenderMaterial(material);
+
+    // Setup the Object
+    clothObj->addVisualModel(visualModel);
+    clothObj->setPhysicsGeometry(clothMesh);
+    clothObj->setDynamicalModel(pbdModel);
+
+    return clothObj;
+}
+
 std::shared_ptr<Scene>
-createSoftBodyScene(std::shared_ptr<SimulationManager> simManager, const char* sceneName)
+createSoftBodyScene(std::string sceneName)
 {
-    auto sceneConfig = std::make_shared<SceneConfig>();
+    imstkNew<SceneConfig> sceneConfig;
     sceneConfig->lazyInitialization = true;
-    auto scene = simManager->createNewScene(sceneName, sceneConfig);
-    scene->getCamera()->setPosition(0, 2.0, 15.0);
+    imstkNew<Scene> scene(sceneName, sceneConfig);
+
+    scene->getActiveCamera()->setPosition(0.0, 2.0, 15.0);
 
     // Load a sample mesh
-    auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
 
     // Extract the surface mesh
-    auto surfMesh   = std::make_shared<SurfaceMesh>();
-    auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh);
-    volTetMesh->extractSurfaceMesh(surfMesh, true);
+    imstkNew<SurfaceMesh> surfMesh;
+    tetMesh->extractSurfaceMesh(surfMesh, true);
 
-    auto material = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> material;
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    auto surfMeshModel = std::make_shared<VisualModel>(surfMesh);
+    imstkNew<VisualModel> surfMeshModel(surfMesh.get());
     surfMeshModel->setRenderMaterial(material);
 
-    // Construct one to one nodal map based on the above meshes
-    auto oneToOneNodalMap = std::make_shared<OneToOneMap>(tetMesh, surfMesh);
-
-    auto deformableObj = std::make_shared<PbdObject>("Dragon");
-    auto pbdModel      = std::make_shared<PbdModel>();
-    pbdModel->setModelGeometry(volTetMesh);
+    imstkNew<PbdObject> deformableObj("Dragon");
+    imstkNew<PbdModel>  pbdModel;
+    pbdModel->setModelGeometry(tetMesh);
 
     // configure model
-    auto pbdParams = std::make_shared<PBDModelConfig>();
+    imstkNew<PBDModelConfig> pbdParams;
 
     // FEM constraint
     pbdParams->m_femParams->m_YoungModulus = 100.0;
@@ -72,27 +182,23 @@ createSoftBodyScene(std::shared_ptr<SimulationManager> simManager, const char* s
 
     // Other parameters
     pbdParams->m_uniformMassValue = 1.0;
-    pbdParams->m_gravity    = Vec3d(0, -9.8, 0);
+    pbdParams->m_gravity    = Vec3d(0.0, -9.8, 0.0);
     pbdParams->m_iterations = 45;
 
     // Set the parameters
     pbdModel->configure(pbdParams);
     deformableObj->setDynamicalModel(pbdModel);
     deformableObj->addVisualModel(surfMeshModel);
-    deformableObj->setPhysicsGeometry(volTetMesh);
-    deformableObj->setPhysicsToVisualMap(oneToOneNodalMap); //assign the computed map
-
+    deformableObj->setPhysicsGeometry(tetMesh);
+    deformableObj->setPhysicsToVisualMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh));
     deformableObj->setDynamicalModel(pbdModel);
-    /*auto pbdSolver = std::make_shared<PbdSolver>();
-    pbdSolver->setPbdObject(deformableObj);
-    scene->addNonlinearSolver(pbdSolver);*/
 
     scene->addSceneObject(deformableObj);
 
-    auto planeGeom = std::make_shared<Plane>();
-    planeGeom->setWidth(40);
+    imstkNew<Plane> planeGeom;
+    planeGeom->setWidth(40.0);
     planeGeom->setTranslation(0, -6, 0);
-    auto planeObj = std::make_shared<CollidingObject>("Plane");
+    imstkNew<CollidingObject> planeObj("Plane");
     planeObj->setVisualGeometry(planeGeom);
     planeObj->setCollidingGeometry(planeGeom);
     scene->addSceneObject(planeObj);
@@ -101,140 +207,79 @@ createSoftBodyScene(std::shared_ptr<SimulationManager> simManager, const char* s
 }
 
 std::shared_ptr<Scene>
-createClothScene(std::shared_ptr<SimulationManager> simManager, const char* sceneName)
+createClothScene(std::string sceneName)
 {
-    auto sceneConfig = std::make_shared<SceneConfig>();
-    sceneConfig->lazyInitialization = true;
-    auto scene = simManager->createNewScene(sceneName, sceneConfig);
-
-    // Create surface mesh
-    auto             surfMesh = std::make_shared<SurfaceMesh>();
-    StdVectorOfVec3d vertList;
-    const double     width  = 10.0;
-    const double     height = 10.0;
-    const int        nRows  = 11;
-    const int        nCols  = 11;
-    vertList.resize(nRows * nCols);
-    const double dy = width / (double)(nCols - 1);
-    const double dx = height / (double)(nRows - 1);
-    for (int i = 0; i < nRows; ++i)
+    imstkNew<Scene> scene("PBDCloth");
     {
-        for (int j = 0; j < nCols; j++)
-        {
-            vertList[i * nCols + j] = Vec3d((double)dx * i, 1.0, (double)dy * j);
-        }
+        std::shared_ptr<PbdObject> clothObj = makeClothObj("Cloth", 10.0, 10.0, 16, 16);
+        scene->addSceneObject(clothObj);
+
+        // Light (white)
+        imstkNew<DirectionalLight> whiteLight("whiteLight");
+        whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+        whiteLight->setIntensity(1.0);
+        scene->addLight(whiteLight);
+
+        // Light (red)
+        imstkNew<SpotLight> colorLight("colorLight");
+        colorLight->setPosition(Vec3d(-5.0, -3.0, 5.0));
+        colorLight->setFocalPoint(Vec3d(0.0, -5.0, 5.0));
+        colorLight->setIntensity(100.);
+        colorLight->setColor(Color::Red);
+        colorLight->setSpotAngle(30.0);
+        scene->addLight(colorLight);
+
+        // Adjust camera
+        scene->getActiveCamera()->setFocalPoint(0.0, -5.0, 5.0);
+        scene->getActiveCamera()->setPosition(-15.0, -5.0, 25.0);
+        scene->getActiveCamera()->setPosition(-15., -5.0, 15.0);
     }
-    surfMesh->setInitialVertexPositions(vertList);
-    surfMesh->setVertexPositions(vertList);
-
-    // Add connectivity data
-    std::vector<SurfaceMesh::TriangleArray> triangles;
-    for (std::size_t i = 0; i < nRows - 1; ++i)
-    {
-        for (std::size_t j = 0; j < nCols - 1; j++)
-        {
-            SurfaceMesh::TriangleArray tri[2];
-            tri[0] = { { i* nCols + j, (i + 1) * nCols + j, i* nCols + j + 1 } };
-            tri[1] = { { (i + 1) * nCols + j + 1, i* nCols + j + 1, (i + 1) * nCols + j } };
-            triangles.push_back(tri[0]);
-            triangles.push_back(tri[1]);
-        }
-    }
-
-    surfMesh->setTrianglesVertices(triangles);
-
-    // Create Object & Model
-    auto deformableObj = std::make_shared<PbdObject>("Cloth");
-    auto pbdModel      = std::make_shared<PbdModel>();
-    pbdModel->setModelGeometry(surfMesh);
-
-    // configure model
-    auto pbdParams = std::make_shared<PBDModelConfig>();
-
-    // Constraints
-    pbdParams->enableConstraint(PbdConstraint::Type::Distance, 0.1);
-    pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 0.001);
-    std::vector<size_t> fixedNodes(nCols);
-    for (size_t i = 0; i < fixedNodes.size(); i++)
-    {
-        fixedNodes[i] = i;
-    }
-    pbdParams->m_fixedNodeIds = fixedNodes;
-
-    // Other parameters
-    pbdParams->m_uniformMassValue = 1.0;
-    pbdParams->m_gravity    = Vec3d(0, -9.8, 0);
-    pbdParams->m_defaultDt  = 0.03;
-    pbdParams->m_iterations = 5;
-
-    // Set the parameters
-    pbdModel->configure(pbdParams);
-    deformableObj->setDynamicalModel(pbdModel);
-    deformableObj->setPhysicsGeometry(surfMesh);
-
-    auto material = std::make_shared<RenderMaterial>();
-    material->setBackFaceCulling(false);
-    material->setColor(Color::LightGray);
-    material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    auto surfMeshModel = std::make_shared<VisualModel>(surfMesh);
-    surfMeshModel->setRenderMaterial(material);
-    deformableObj->addVisualModel(surfMeshModel);
-
-    // Solver
-
-    scene->addSceneObject(deformableObj);
-
-    scene->getCamera()->setFocalPoint(0, -5, 5);
-    scene->getCamera()->setPosition(-15., -5.0, 15.0);
-
     return scene;
 }
 
 void
 testMultipleScenesInBackendMode()
 {
-    auto simConfig = std::make_shared<SimManagerConfig>();
-    simConfig->simulationMode = SimulationMode::Backend;
-    auto simManager = std::make_shared<SimulationManager>(simConfig);
+    imstkNew<SceneManager> sceneManager("SceneManager");
+    auto                   scene1 = createClothScene("clothScene");
+    sceneManager->addScene(scene1);
+    auto scene2 = createSoftBodyScene("deformableBodyScene");
+    sceneManager->addScene(scene2);
 
-    auto scene1 = createClothScene(simManager, "clothScene");
-    auto scene2 = createSoftBodyScene(simManager, "deformableBodyScene");
+    scene1->initialize();
+    scene2->initialize();
 
     // set to scene 1
-    simManager->setActiveScene(scene1);
+    sceneManager->setActiveScene(scene1);
 
-    simManager->initialize();
-
-    simManager->advanceFrame();
-    simManager->advanceFrame();
-    simManager->advanceFrame();
-    simManager->advanceFrame();
+    sceneManager->update();
+    sceneManager->update();
+    sceneManager->update();
+    sceneManager->update();
 
     // set to scene 2
-    simManager->setActiveScene(scene2);
+    sceneManager->setActiveScene(scene2);
 
-    simManager->advanceFrame();
-    simManager->advanceFrame();
-    simManager->advanceFrame();
-    simManager->advanceFrame();
+    sceneManager->update();
+    sceneManager->update();
+    sceneManager->update();
+    sceneManager->update();
 
     // set to scene 1
-    simManager->setActiveScene(scene1);
+    sceneManager->setActiveScene(scene1);
 
-    simManager->advanceFrame();
-    simManager->advanceFrame();
-    simManager->advanceFrame();
-    simManager->advanceFrame();
+    sceneManager->update();
+    sceneManager->update();
+    sceneManager->update();
+    sceneManager->update();
 
     // set to scene 2
-    simManager->setActiveScene(scene2);
-
-    simManager->advanceFrame();
-    simManager->advanceFrame();
-    simManager->advanceFrame();
-    simManager->advanceFrame();
+    sceneManager->setActiveScene(scene2);
 
-    simManager->end();
+    sceneManager->update();
+    sceneManager->update();
+    sceneManager->update();
+    sceneManager->update();
 
     std::cout << "Press any key to exit..." << std::endl;
 
@@ -245,75 +290,109 @@ void
 testMultipleScenesInRenderMode()
 {
     // Simulation manager defaults to rendering mode
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene1     = createClothScene(simManager, "clothScene");
-    auto scene2     = createSoftBodyScene(simManager, "deformableBodyScene");
+    auto scene1 = createClothScene("clothScene");
+    auto scene2 = createSoftBodyScene("deformableBodyScene");
 
     scene1->getConfig()->trackFPS = true;
 
+    scene1->initialize();
+    scene2->initialize();
+
     // set to scene 1
-    simManager->setActiveScene(scene2);
+    imstkNew<SceneManager> sceneManager("SceneManager");
+    sceneManager->setActiveScene(scene2);
+
+    // Setup a viewer to render in its own thread
+    imstkNew<VTKViewer> viewer("Viewer");
+    viewer->setActiveScene(scene2);
+    viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
 
     // Create a call back on key press of 's' to switch scenes
-    auto viewer = simManager->getViewer();
-    if (viewer)
-    {
-        std::cout << "Press 's/S' to switch scenes" << std::endl;
+    LOG(INFO) << "s/S followed by enter to switch scenes";
+    LOG(INFO) << "q/Q followed by enter to quit";
 
-        viewer->setOnCharFunction('s', [&](InteractorStyle* c) -> bool
+    connect<KeyPressEvent>(viewer->getKeyboardDevice(), EventType::KeyPress,
+        [&](KeyPressEvent* e)
+    {
+        if (e->m_keyPressType == KEY_PRESS)
         {
-            if (simManager->getActiveScene() == scene1)
+            if (e->m_key == 's' || e->m_key == 'S')
             {
-                simManager->setActiveScene(scene2);
+                if (sceneManager->getActiveScene() == scene1)
+                {
+                    sceneManager->setActiveScene(scene2);
+                    viewer->setActiveScene(scene2);
+                }
+                else
+                {
+                    sceneManager->setActiveScene(scene1);
+                    viewer->setActiveScene(scene1);
+                }
+
+                if (!sceneManager->getActiveScene())
+                {
+                    sceneManager->setActiveScene(scene1);
+                    viewer->setActiveScene(scene1);
+                }
             }
-            else
-            {
-                simManager->setActiveScene(scene1);
-            }
-
-            if (!simManager->getActiveScene())
+            else if (e->m_key == 'q' || e->m_key == 'Q')
             {
-                simManager->setActiveScene(scene1);
+                viewer->stop(false);
             }
-
-            return true;
+        }
         });
-    }
 
     if (scene1->getConfig()->trackFPS)
     {
-        apiutils::printUPS(simManager->getSceneManager(scene1));
+        apiutils::printUPS(sceneManager);
     }
 
-    simManager->start();
+    viewer->start();
 }
 
 void
 testMultipleScenesInBackgroundMode()
 {
-    auto simConfig = std::make_shared<SimManagerConfig>();
-    simConfig->simulationMode = SimulationMode::RunInBackgroundSync;
-    auto simManager = std::make_shared<SimulationManager>(simConfig);
-    auto scene1     = createClothScene(simManager, "clothScene");
-    auto scene2     = createSoftBodyScene(simManager, "deformableBodyScene");
+    imstkNew<ConsoleThread> consoleThread;
+
+    imstkNew<SceneManager> sceneManager("SceneManager");
+    consoleThread->addChildThread(sceneManager); // Start/stop scene with console
+    auto scene1 = createClothScene("clothScene");
+    auto scene2 = createSoftBodyScene("deformableBodyScene");
+    sceneManager->addScene(scene1);
+    sceneManager->addScene(scene2);
 
-    simManager->setActiveScene(scene1);
+    scene1->initialize();
+    scene2->initialize();
 
-    std::cout << "Press 's/S' to switch scenes" << std::endl;
-    auto keyPressFunc = [&]()
+    sceneManager->setActiveScene(scene1);
+
+    LOG(INFO) << "s/S followed by enter to switch scenes";
+    LOG(INFO) << "q/Q followed by enter to quit";
+    auto keyPressFunc = [&](KeyPressEvent* e)
                         {
-                            if (simManager->getActiveScene()->getName() == scene1->getName())
-                            {
-                                simManager->setActiveScene(scene2);
-                            }
-                            else
+                            if (e->m_keyPressType == KEY_PRESS)
                             {
-                                simManager->setActiveScene(scene1);
+                                if (e->m_key == 's' || e->m_key == 'S')
+                                {
+                                    if (sceneManager->getActiveScene()->getName() == scene1->getName())
+                                    {
+                                        sceneManager->setActiveScene(scene2);
+                                    }
+                                    else
+                                    {
+                                        sceneManager->setActiveScene(scene1);
+                                    }
+                                }
+                                else if (e->m_key == 'q' || e->m_key == 'Q')
+                                {
+                                    consoleThread->stop(false);
+                                }
                             }
                         };
-    simManager->addKeyPressCallback(keyPressFunc, 's');
+    connect<KeyPressEvent>(consoleThread->getKeyboardDevice(), EventType::KeyPress, keyPressFunc);
 
-    simManager->start();
+    consoleThread->start();
 }
 
 ///
@@ -322,6 +401,9 @@ testMultipleScenesInBackgroundMode()
 int
 main()
 {
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
     testMultipleScenesInBackendMode();
     testMultipleScenesInBackgroundMode();
     testMultipleScenesInRenderMode();
diff --git a/Examples/NonlinearSolver/nonlinearSolver.cpp b/Examples/NonlinearSolver/nonlinearSolver.cpp
index c8a94e2490573e1be1cc9490b0f078e1ae108513..71c250804749bfb6336dd526348d4fc41a32c4d0 100644
--- a/Examples/NonlinearSolver/nonlinearSolver.cpp
+++ b/Examples/NonlinearSolver/nonlinearSolver.cpp
@@ -19,16 +19,14 @@
 
 =========================================================================*/
 
+#include "imstkDirectLinearSolver.h"
+#include "imstkNew.h"
+#include "imstkNewtonSolver.h"
+
 #include <ios>
 #include <iostream>
-#include <vector>
 #include <iomanip>
 
-#include "imstkMath.h"
-#include "imstkNewtonSolver.h"
-#include "imstkDirectLinearSolver.h"
-#include "imstkNonLinearSolver.h"
-
 using namespace imstk;
 
 ///
@@ -74,13 +72,13 @@ main(int argc, char** argv)
 
     auto updateXold = [](void) {};
 
-    auto nlSystem = std::make_shared<NonLinearSystem<Matrixd>>(func, jac);
+    imstkNew<NonLinearSystem<Matrixd>> nlSystem(func, jac);
     nlSystem->setUnknownVector(x);
     nlSystem->setUpdateFunction(updateX);
     nlSystem->setUpdatePreviousStatesFunction(updateXold);
 
-    auto linSolver = std::make_shared<DirectLinearSolver<Matrixd>>();
-    auto nlSolver  = std::make_shared<NewtonSolver<Matrixd>>();
+    imstkNew<DirectLinearSolver<Matrixd>> linSolver;
+    imstkNew<NewtonSolver<Matrixd>>       nlSolver;
     nlSolver->setMaxIterations(100);
     nlSolver->setRelativeTolerance(1e-8);
     nlSolver->setAbsoluteTolerance(1e-10);
diff --git a/Examples/ObjectController/ObjectControllerExample.cpp b/Examples/ObjectController/ObjectControllerExample.cpp
index 1cc14e4dc36e8ab428d52425ac19be0e7d9fcf62..5d17119b8ac7785fe616a4625fdd22139ba7fdd0 100644
--- a/Examples/ObjectController/ObjectControllerExample.cpp
+++ b/Examples/ObjectController/ObjectControllerExample.cpp
@@ -19,20 +19,23 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkCube.h"
 #include "imstkCamera.h"
-#include "imstkLight.h"
 #include "imstkCollidingObject.h"
-#include "imstkHDAPIDeviceClient.h"
-#include "imstkHDAPIDeviceServer.h"
-#include "imstkSceneObjectController.h"
-#include "imstkCollisionGraph.h"
-#include "imstkDeviceTracker.h"
+#include "imstkCube.h"
+#include "imstkHapticDeviceClient.h"
+#include "imstkHapticDeviceManager.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObjectController.h"
+#include "imstkVTKViewer.h"
 
 // global variables
-const std::string phantomOmni1Name = "Phantom1";
+const std::string phantomOmni1Name = "Default Device";
 
 using namespace imstk;
 
@@ -43,48 +46,65 @@ using namespace imstk;
 int
 main()
 {
-#ifdef iMSTK_USE_OPENHAPTICS
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("ObjectController");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
 
-    // Device Client
-    auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name);
+    // Create Scene
+    imstkNew<Scene> scene("ObjectController");
 
     // Device Server
-    auto server = std::make_shared<HDAPIDeviceServer>();
-    server->addDeviceClient(client);
-    simManager->addModule(server);
+    imstkNew<HapticDeviceManager>       server;
+    std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name);
 
     // Object
-    auto geom = std::make_shared<Cube>();
-    geom->setPosition(0, 1, 0);
-    geom->setWidth(2);
-
-    auto object = std::make_shared<CollidingObject>("VirtualObject");
+    imstkNew<Cube>            geom(Vec3d(0.0, 1.0, 0.0), 2.0);
+    imstkNew<CollidingObject> object("VirtualObject");
     object->setVisualGeometry(geom);
     object->setCollidingGeometry(geom);
     scene->addSceneObject(object);
 
-    auto trackCtrl = std::make_shared<DeviceTracker>(client);
-    trackCtrl->setTranslationScaling(0.1);
-    auto controller = std::make_shared<SceneObjectController>(object, trackCtrl);
-    scene->addObjectController(controller);
+    imstkNew<SceneObjectController> controller(object, client);
+    controller->setTranslationScaling(0.1);
+    scene->addController(controller);
 
     // Update Camera position
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(0, 0, 10));
+    std::shared_ptr<Camera> cam = scene->getActiveCamera();
+    cam->setPosition(Vec3d(0.0, 0.0, 10.0));
     cam->setFocalPoint(geom->getPosition());
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
+    imstkNew<DirectionalLight> light("light");
+    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+    light->setIntensity(1.0);
     scene->addLight(light);
 
-    // Run
-    simManager->setActiveScene(scene);
-    simManager->start();
-#endif
+    //Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer 1");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager 1");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        viewer->addChildThread(server);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start the viewer and its children
+        viewer->start();
+    }
     return 0;
 }
diff --git a/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp b/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp
index 632019b2aaa2cf9b8f9506b6c88b0ca63c1102f5..d88f219f06a5f3624fefa059e486688421fc4db5 100644
--- a/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp
+++ b/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp
@@ -19,16 +19,17 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkCollidingObject.h"
 #include "imstkCamera.h"
-#include "imstkLight.h"
-#include "imstkSceneManager.h"
+#include "imstkCollidingObject.h"
 #include "imstkCube.h"
 #include "imstkDummyClient.h"
-#include "imstkDeviceTracker.h"
-#include "imstkSceneObjectController.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkNew.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObjectController.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -39,31 +40,30 @@ using namespace imstk;
 int
 main()
 {
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("ObjectControllerDummyClient");
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("ObjectControllerDummyClient");
 
     // Device Client
-    auto client = std::make_shared<DummyClient>("DummyClient");
+    imstkNew<DummyClient> client("DummyClient");
 
     // Object
-    auto geom = std::make_shared<Cube>();
-    geom->setPosition(0, 1, 0);
-    geom->setWidth(2);
+    imstkNew<Cube> geom;
+    geom->setPosition(0.0, 1.0, 0.0);
+    geom->setWidth(2.0);
 
-    auto object = std::make_shared<CollidingObject>("VirtualObject");
+    imstkNew<CollidingObject> object("VirtualObject");
     object->setVisualGeometry(geom);
     object->setCollidingGeometry(geom);
     scene->addSceneObject(object);
 
-    auto trackCtrl = std::make_shared<DeviceTracker>(client);
-    trackCtrl->setTranslationScaling(0.1);
-    auto controller = std::make_shared<SceneObjectController>(object, trackCtrl);
-    scene->addObjectController(controller);
+    imstkNew<SceneObjectController> controller(object, client);
+    controller->setTranslationScaling(0.1);
+    scene->addController(controller);
 
     // Supply translation to dummy client frame
     auto translateFunc =
-        [&client](Module* module)
+        [&client](Event*)
         {
             Vec3d p = client->getPosition() + Vec3d(1.0e-4, 0, 0);
             if (p.x() > 50.)
@@ -72,22 +72,31 @@ main()
             }
             client->setPosition(p);
         };
-    simManager->getSceneManager(scene)->setPostUpdateCallback(translateFunc);
 
     // Update Camera position
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(0, 0, 10));
-    cam->setFocalPoint(geom->getPosition());
+    scene->getActiveCamera()->setPosition(0.0, 0.0, 10.0);
+    scene->getActiveCamera()->setFocalPoint(geom->getPosition());
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
+    imstkNew<DirectionalLight> light("light");
+    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+    light->setIntensity(1.0);
     scene->addLight(light);
 
-    // Run
-    simManager->setActiveScene(scene);
-    simManager->start();
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        connect<Event>(sceneManager, EventType::PostUpdate, translateFunc);
+
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/Octree/BunnyMesh.cpp b/Examples/Octree/BunnyMesh.cpp
index 34ae07934852d15b2cb1c2e36f379fae34fd4c69..417538ef5baaaeb494c3a0daed1fc1f31086fdc9 100644
--- a/Examples/Octree/BunnyMesh.cpp
+++ b/Examples/Octree/BunnyMesh.cpp
@@ -23,6 +23,7 @@
 #include "imstkLogger.h"
 
 #include <array>
+
 using namespace imstk;
 
 std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>>
diff --git a/Examples/Octree/OctreeExample.cpp b/Examples/Octree/OctreeExample.cpp
index ddc8e70b2707ae28526316c6b06719da407138b0..1899a4d622f786c9c27f9d814b7d4c7239276147 100644
--- a/Examples/Octree/OctreeExample.cpp
+++ b/Examples/Octree/OctreeExample.cpp
@@ -19,25 +19,26 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkSceneObject.h"
-#include "imstkDebugRenderGeometry.h"
-#include "imstkAPIUtilities.h"
-#include "imstkLooseOctree.h"
-#include "imstkVTKViewer.h"
-#include "imstkTimer.h"
-#include "imstkLight.h"
-#include "imstkSurfaceMesh.h"
-#include "imstkSceneManager.h"
 #include "imstkCamera.h"
-#include "imstkVTKTextStatusManager.h"
-#include "imstkCollisionGraph.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkLooseOctree.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObject.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTimer.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKRenderDelegate.h"
 #include "imstkVTKRenderer.h"
+#include "imstkVTKTextStatusManager.h"
+#include "imstkVTKViewer.h"
 
-#include <thread>
-#include <chrono>
-#include <sstream>
+#include <vtkRenderWindow.h>
 
 using namespace imstk;
 
@@ -52,25 +53,23 @@ static std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> g_BunnyDa
 /// \brief Read a mesh, create a visual scene object and add to the scene
 ///
 std::shared_ptr<VisualObject>
-createMeshObject(const std::shared_ptr<imstk::Scene>& scene,
-                 const std::string&                   objectName,
-                 const Color&                         color)
+createMeshObject(const std::string& objectName,
+                 const Color&       color)
 {
     // Create a surface mesh for the bunny
-    auto meshObj = std::make_shared<SurfaceMesh>();
-    meshObj->initialize(g_BunnyData.first, g_BunnyData.second);
+    imstkNew<SurfaceMesh> surfMesh;
+    surfMesh->initialize(g_BunnyData.first, g_BunnyData.second);
 
     // Create a visiual model
-    auto visualModel = std::make_shared<VisualModel>(meshObj);
-    auto material    = std::make_shared<RenderMaterial>();
+    imstkNew<VisualModel>    visualModel(surfMesh.get());
+    imstkNew<RenderMaterial> material;
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
     material->setColor(color); // Wireframe color
-    material->setLineWidth(1);
+    material->setLineWidth(1.0);
     visualModel->setRenderMaterial(material);
 
-    auto visualObject = std::make_shared<VisualObject>(objectName);
+    imstkNew<VisualObject> visualObject(objectName);
     visualObject->addVisualModel(visualModel);
-    scene->addSceneObject(visualObject);
 
     return visualObject;
 }
@@ -105,20 +104,20 @@ getRandomColor()
 int
 main()
 {
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("Octree Example");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("Octree Example");
 
-    // Get the VTKViewer
-    std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false);
+    // Setup a viewer to render in its own thread
+    imstkNew<VTKViewer> viewer("Viewer");
+    viewer->setActiveScene(scene);
     viewer->setWindowTitle("Octree Example");
     viewer->getVtkRenderWindow()->SetSize(1920, 1080);
-    simManager->setViewer(viewer);
-    simManager->setActiveScene(scene); // Viewer has depedence on scene
 
     auto statusManager = viewer->getTextStatusManager();
-    statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30);
-    statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Orange);
+    statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 30);
+    statusManager->setStatusFontColor(VTKTextStatusManager::StatusType::Custom, Color::Orange);
 
     // Get VTK Renderer
     auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer());
@@ -131,7 +130,8 @@ main()
     std::vector<std::shared_ptr<SurfaceMesh>> triMeshes;
     for (unsigned int i = 0; i < NUM_MESHES; ++i)
     {
-        const auto sceneObj = createMeshObject(scene, "Mesh-" + std::to_string(triMeshes.size()), getRandomColor());
+        std::shared_ptr<SceneObject> sceneObj = createMeshObject("Mesh-" + std::to_string(triMeshes.size()), getRandomColor());
+        scene->addSceneObject(sceneObj);
         triMeshes.push_back(std::dynamic_pointer_cast<SurfaceMesh>(sceneObj->getVisualGeometry()));
     }
 
@@ -149,7 +149,7 @@ main()
     timer.start();
 
     // Create octree
-    LooseOctree octree(Vec3d(0, 0, 0), 100.0, 0.125, 2.0, "TestOctree");
+    LooseOctree octree(Vec3d(0.0, 0.0, 0.0), 100.0, 0.125, 2.0, "TestOctree");
 
     // Add all meshes to the octree
     for (const auto& mesh: triMeshes)
@@ -168,11 +168,11 @@ main()
     // Create debug geometry for the octree (render up to 8 levels, and render all non-empty nodes)
     const auto debugOctree = octree.getDebugGeometry(8, true);
 
-    const auto matDbgViz = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> matDbgViz;
     matDbgViz->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
     matDbgViz->setEdgeColor(Color::Green);
     matDbgViz->setLineWidth(1.0);
-    auto octreeVizDbgModel = std::make_shared<VisualModel>(debugOctree, matDbgViz);
+    imstkNew<VisualModel> octreeVizDbgModel(debugOctree, matDbgViz);
     scene->addDebugVisualModel(octreeVizDbgModel);
 
     // Data for animation
@@ -203,7 +203,7 @@ main()
     }
 
     auto updateFunc =
-        [&](Module*) {
+        [&](Event*) {
             // Move objects
             for (size_t i = 0; i < triMeshes.size(); ++i)
             {
@@ -249,29 +249,50 @@ main()
             // Pause for a while
             std::this_thread::sleep_for(std::chrono::milliseconds(100));
         };
-    simManager->getSceneManager(scene)->setPostUpdateCallback(updateFunc);
 
     // Set Camera configuration
-    auto cam = scene->getCamera();
+    auto cam = scene->getActiveCamera();
     cam->setPosition(Vec3d(0, 15, 50));
     cam->setFocalPoint(Vec3d(0, 0, 0));
 
     // Light
     {
-        auto light = std::make_shared<DirectionalLight>("Light 1");
-        light->setFocalPoint(Vec3d(-1, -1, -1));
+        imstkNew<DirectionalLight> light("Light 1");
+        light->setFocalPoint(Vec3d(-1.0, -1.0, -1.0));
         light->setIntensity(1);
         scene->addLight(light);
     }
     {
-        auto light = std::make_shared<DirectionalLight>("Light 2");
-        light->setFocalPoint(Vec3d(1, -1, -1));
-        light->setIntensity(1);
+        imstkNew<DirectionalLight> light("Light 2");
+        light->setFocalPoint(Vec3d(1.0, -1.0, -1.0));
+        light->setIntensity(1.0);
         scene->addLight(light);
     }
 
-    // Run
-    simManager->start(SimulationStatus::Paused);
+    // Run the simulation
+    {
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        connect<Event>(sceneManager, EventType::PostUpdate, updateFunc);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/OpenVRController/CMakeLists.txt b/Examples/OpenVRController/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3445445c7787261bba49b67bd2e52bdae52285d7
--- /dev/null
+++ b/Examples/OpenVRController/CMakeLists.txt
@@ -0,0 +1,34 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  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.
+#
+###########################################################################
+
+project(Example-OpenVRController)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+imstk_add_executable(${PROJECT_NAME} OpenVRControllerExample.cpp)
+
+#-----------------------------------------------------------------------------
+# Add the target to Examples folder
+#-----------------------------------------------------------------------------
+SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/OpenVR)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities)
\ No newline at end of file
diff --git a/Examples/OpenVRController/OpenVRControllerExample.cpp b/Examples/OpenVRController/OpenVRControllerExample.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..deeb899735f84b184350dbc00b94d3a63eb35bd6
--- /dev/null
+++ b/Examples/OpenVRController/OpenVRControllerExample.cpp
@@ -0,0 +1,199 @@
+/*=========================================================================
+
+   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 "imstkCamera.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMeshIO.h"
+#include "imstkNew.h"
+#include "imstkOpenVRDeviceClient.h"
+#include "imstkRenderMaterial.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObject.h"
+#include "imstkSceneObjectController.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKOpenVRViewer.h"
+
+using namespace imstk;
+
+std::shared_ptr<SceneObject>
+makeHandleObject()
+{
+    imstkNew<SceneObject> scalpelHandle("ScalpelHandle");
+    auto                  toolHandleMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/Scalpel_Handle.obj");
+    toolHandleMesh->translate(0.0, 0.0, 1.0, Geometry::TransformType::ApplyToData);
+    toolHandleMesh->rotate(Vec3d(0.0, 1.0, 0.0), 3.14, Geometry::TransformType::ApplyToData);
+    toolHandleMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.57, Geometry::TransformType::ApplyToData);
+    toolHandleMesh->scale(0.06, Geometry::TransformType::ApplyToData);
+
+    imstkNew<VisualModel>    toolHandleModel(toolHandleMesh);
+    imstkNew<RenderMaterial> material;
+    material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+    material->setShadingModel(RenderMaterial::ShadingModel::PBR);
+    material->setMetalness(0.9f);
+    material->setRoughness(0.2f);
+    material->addTexture(std::make_shared<Texture>(
+                iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/Scalpel_Albedo.png",
+                Texture::Type::Diffuse));
+    toolHandleModel->setRenderMaterial(material);
+
+    scalpelHandle->addVisualModel(toolHandleModel);
+
+    return scalpelHandle;
+}
+
+std::shared_ptr<SceneObject>
+makeBlade(std::string filename)
+{
+    imstkNew<SceneObject> scalpelBlade(filename);
+    auto                  blade10Mesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/" + filename + ".obj");
+    blade10Mesh->translate(0.0, 0.0, 1.0, Geometry::TransformType::ApplyToData);
+    blade10Mesh->rotate(Vec3d(0.0, 1.0, 0.0), 3.14, Geometry::TransformType::ApplyToData);
+    blade10Mesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.57, Geometry::TransformType::ApplyToData);
+    blade10Mesh->scale(0.06, Geometry::TransformType::ApplyToData);
+
+    imstkNew<VisualModel>    blade10Model(blade10Mesh);
+    imstkNew<RenderMaterial> material;
+    material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+    material->setShadingModel(RenderMaterial::ShadingModel::PBR);
+    material->setMetalness(0.9f);
+    material->setRoughness(0.2f);
+    material->addTexture(std::make_shared<Texture>(
+                iMSTK_DATA_ROOT "/Surgical Instruments/Scalpel/Scalpel_Albedo.png",
+                Texture::Type::Diffuse));
+    blade10Model->setRenderMaterial(material);
+
+    scalpelBlade->addVisualModel(blade10Model);
+    return scalpelBlade;
+}
+
+///
+/// \brief This example demonstrates rendering and controlling a SceneObject with OpenVR
+/// as well as swapping a tool
+///
+int
+main()
+{
+    // Write log to stdout and file
+    Logger::startLogger();
+
+    // Setup the scene
+    imstkNew<Scene> scene("OpenVRControllerExample");
+
+    std::shared_ptr<SceneObject> scalpelHandle = makeHandleObject();
+    scene->addSceneObject(scalpelHandle);
+
+    std::shared_ptr<SceneObject> scalpelBlade10 = makeBlade("Scalpel_Blade10");
+    scene->addSceneObject(scalpelBlade10);
+
+    std::shared_ptr<SceneObject> scalpelBlade15 = makeBlade("Scalpel_Blade15");
+    scene->addSceneObject(scalpelBlade15);
+    scalpelBlade15->getMasterGeometry()->setTranslation(0.2, 1.0, -0.8);
+
+    // Lights
+    imstkNew<DirectionalLight> dirLight("DirLight");
+    dirLight->setIntensity(4);
+    dirLight->setColor(Color(1.0, 0.95, 0.8));
+    dirLight->setCastsShadow(true);
+    dirLight->setShadowRange(1.5);
+    scene->addLight(dirLight);
+
+    {
+        // Add a module to run the viewer
+        imstkNew<VTKOpenVRViewer> viewer("VRViewer");
+        viewer->setActiveScene(scene);
+
+        // Add a module to run the scene
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager);         // Start/stop scene with the view
+
+        // Add a VR controller for the scalpel handle
+        imstkNew<SceneObjectController> controller1(scalpelHandle, viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER));
+        scene->addController(controller1);
+        // Add a VR controller for the scalpel blade
+        imstkNew<SceneObjectController> controller2(scalpelBlade10, viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER));
+        scene->addController(controller2);
+
+        // VRButtonPress emitted from viewer, recieve it in the scene that way the scene is not running whilst it is swapped
+        bool blade10InHand = true;
+        queueConnect<VRButtonEvent>(viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER), EventType::VRButtonPress, sceneManager,
+            [&](VRButtonEvent* e)
+        {
+            // When any button pressed, swap blade
+            // todo: distance metric not working
+            if (e->m_buttonState == BUTTON_PRESSED)
+            {
+                const Vec3d& posControl = viewer->getVRDeviceClient(OPENVR_RIGHT_CONTROLLER)->getPosition();
+                if (blade10InHand)
+                {
+                    // Swap to blade 15 only if it's close in space
+                    Vec3d min, max;
+                    scalpelBlade15->getMasterGeometry()->computeBoundingBox(min, max);
+                    const Vec3d posBlade = (min + max) * 0.5;
+                    const double dist    = (posControl - posBlade).norm();
+                    LOG(INFO) << "Dist: " << dist;
+                    if (dist < 2.0)
+                    {
+                        const Vec3d t = scalpelBlade15->getMasterGeometry()->getTranslation();
+                        const Mat3d r = scalpelBlade15->getMasterGeometry()->getRotation();
+
+                        // Set the new blade to move
+                        controller2->setControlledSceneObject(scalpelBlade15);
+                        blade10InHand = false;
+
+                        scalpelBlade10->getMasterGeometry()->setTranslation(t);
+                        scalpelBlade10->getMasterGeometry()->setRotation(r);
+                    }
+                }
+                else
+                {
+                    // Swap to blade 10 only if it's close in space
+                    Vec3d min, max;
+                    scalpelBlade10->getMasterGeometry()->computeBoundingBox(min, max);
+                    const Vec3d posBlade = (min + max) * 0.5;
+                    const double dist    = (posControl - posBlade).norm();
+                    LOG(INFO) << "Dist: " << dist;
+                    if (dist < 2.0)
+                    {
+                        const Vec3d t = scalpelBlade10->getMasterGeometry()->getTranslation();
+                        const Mat3d r = scalpelBlade10->getMasterGeometry()->getRotation();
+
+                        controller2->setControlledSceneObject(scalpelBlade10);
+                        blade10InHand = true;
+
+                        // Swap transforms of the blades
+                        scalpelBlade15->getMasterGeometry()->setTranslation(t);
+                        scalpelBlade15->getMasterGeometry()->setRotation(r);
+                    }
+                }
+            }
+                        });
+
+        // Start running
+        viewer->requestStatus(ThreadStatus::Running);
+        viewer->start();
+    }
+
+    return 0;
+}
\ No newline at end of file
diff --git a/Examples/PBD/PBDCloth/pbdClothExample.cpp b/Examples/PBD/PBDCloth/pbdClothExample.cpp
index 559dbe895d112603de365affedfcbf2546e54c2d..c1ef2d620fd52aa125d0258b2bcb89d77b22d196 100644
--- a/Examples/PBD/PBDCloth/pbdClothExample.cpp
+++ b/Examples/PBD/PBDCloth/pbdClothExample.cpp
@@ -19,14 +19,20 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkPbdModel.h"
-#include "imstkPbdObject.h"
-#include "imstkAPIUtilities.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkCamera.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkPbdModel.h"
+#include "imstkPbdObject.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -39,14 +45,13 @@ const int    nCols  = 16;
 ///
 /// \brief Creates cloth geometry
 ///
-static std::unique_ptr<SurfaceMesh>
+static std::shared_ptr<SurfaceMesh>
 makeClothGeometry(const double width,
                   const double height,
                   const int    nRows,
                   const int    nCols)
 {
-    // Create surface mesh
-    auto clothMesh = std::make_unique<SurfaceMesh>();
+    imstkNew<SurfaceMesh> clothMesh;
 
     StdVectorOfVec3d vertList;
     vertList.resize(nRows * nCols);
@@ -105,36 +110,36 @@ makeClothObj(const std::string& name,
              const int          nRows,
              const int          nCols)
 {
-    auto clothObj = std::make_shared<PbdObject>(name);
+    imstkNew<PbdObject> clothObj(name);
 
     // Setup the Geometry
-    std::shared_ptr<SurfaceMesh> clothMesh(std::move(makeClothGeometry(width, height, nRows, nCols)));
+    std::shared_ptr<SurfaceMesh> clothMesh(makeClothGeometry(width, height, nRows, nCols));
 
     // Setup the Parameters
-    auto pbdParams = std::make_shared<PBDModelConfig>();
-    pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1e2);
-    pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1e1);
+    imstkNew<PBDModelConfig> pbdParams;
+    pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1.0e2);
+    pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1.0e1);
     pbdParams->m_fixedNodeIds     = { 0, static_cast<size_t>(nCols) - 1 };
     pbdParams->m_uniformMassValue = width * height / ((double)nRows * (double)nCols);
-    pbdParams->m_gravity    = Vec3d(0, -9.8, 0);
+    pbdParams->m_gravity    = Vec3d(0.0, -9.8, 0.0);
     pbdParams->m_defaultDt  = 0.005;
     pbdParams->m_iterations = 5;
 
     // Setup the Model
-    auto pbdModel = std::make_shared<PbdModel>();
+    imstkNew<PbdModel> pbdModel;
     pbdModel->setModelGeometry(clothMesh);
     pbdModel->configure(pbdParams);
 
     // Setup the VisualModel
-    auto material = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> material;
     material->setBackFaceCulling(false);
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
 
-    auto clothVisualModel = std::make_shared<VisualModel>(clothMesh);
-    clothVisualModel->setRenderMaterial(material);
+    imstkNew<VisualModel> visualModel(clothMesh);
+    visualModel->setRenderMaterial(material);
 
     // Setup the Object
-    clothObj->addVisualModel(clothVisualModel);
+    clothObj->addVisualModel(visualModel);
     clothObj->setPhysicsGeometry(clothMesh);
     clothObj->setDynamicalModel(pbdModel);
 
@@ -148,34 +153,62 @@ makeClothObj(const std::string& name,
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("PBDCloth");
-
-    std::shared_ptr<PbdObject> clothObj = makeClothObj("Cloth", width, height, nRows, nCols);
-    scene->addSceneObject(clothObj);
-
-    // Light (white)
-    auto whiteLight = std::make_shared<DirectionalLight>("whiteLight");
-    whiteLight->setFocalPoint(Vec3d(5, -8, -5));
-    whiteLight->setIntensity(1.);
-    scene->addLight(whiteLight);
-
-    // Light (red)
-    auto colorLight = std::make_shared<SpotLight>("colorLight");
-    colorLight->setPosition(Vec3d(-5., -3., 5.));
-    colorLight->setFocalPoint(Vec3d(0., -5., 5.));
-    colorLight->setIntensity(100.);
-    colorLight->setColor(Color::Red);
-    colorLight->setSpotAngle(30);
-    scene->addLight(colorLight);
-
-    // Adjust camera
-    scene->getCamera()->setFocalPoint(0., -5., 5.);
-    scene->getCamera()->setPosition(-15., -5., 15.);
-
-    // Start
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    // Write log to stdout and file
+    Logger::startLogger();
+
+    // Setup a scene
+    imstkNew<Scene> scene("PBDCloth");
+    {
+        std::shared_ptr<PbdObject> clothObj = makeClothObj("Cloth", width, height, nRows, nCols);
+        scene->addSceneObject(clothObj);
+
+        // Light (white)
+        imstkNew<DirectionalLight> whiteLight("whiteLight");
+        whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+        whiteLight->setIntensity(1.0);
+        scene->addLight(whiteLight);
+
+        // Light (red)
+        imstkNew<SpotLight> colorLight("colorLight");
+        colorLight->setPosition(Vec3d(-5.0, -3.0, 5.0));
+        colorLight->setFocalPoint(Vec3d(0.0, -5.0, 5.0));
+        colorLight->setIntensity(100.);
+        colorLight->setColor(Color::Red);
+        colorLight->setSpotAngle(30.0);
+        scene->addLight(colorLight);
+
+        // Adjust camera
+        scene->getActiveCamera()->setFocalPoint(0.0, -5.0, 5.0);
+        scene->getActiveCamera()->setPosition(-15.0, -5.0, 25.0);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp b/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp
index 1ef3a0b62544fbe0968405332810a253dd61fcc1..78983daaf645b24ee675d3fceb72f4d0c933a652 100644
--- a/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp
+++ b/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp
@@ -21,16 +21,23 @@
 
 #include "imstkCamera.h"
 #include "imstkCollisionGraph.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
+#include "imstkLogger.h"
 #include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkObjectInteractionFactory.h"
 #include "imstkOneToOneMap.h"
 #include "imstkPbdModel.h"
 #include "imstkPbdObject.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
-#include "imstkSimulationManager.h"
+#include "imstkSceneManager.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkTetrahedralMesh.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 // Enable this macro to generate many dragons
 #define BIG_SCENE
@@ -40,102 +47,12 @@ using namespace imstk;
 ///
 /// \brief Generate a random color
 ///
-Color
-getRandomColor()
-{
-    Color color(0, 0, 0, 1);
-    while (true)
-    {
-        for (unsigned int i = 0; i < 3; ++i)
-        {
-            color.rgba[i] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
-        }
-        if (color.rgba[0] > 0.95
-            || color.rgba[1] > 0.95
-            || color.rgba[2] > 0.95)
-        {
-            break;
-        }
-    }
-    return color;
-}
-
-void
-generateDragon(const std::shared_ptr<imstk::Scene>& scene,
-               const Vec3d&                         translation,
-               std::shared_ptr<SurfaceMesh>&        surfMesh,
-               std::shared_ptr<PbdObject>&          deformableObj,
-               std::shared_ptr<PbdSolver>&          pbdSolver)
-{
-    // Load a sample mesh
-    auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
-    LOG_IF(FATAL, (!tetMesh)) << "Could not read mesh from file.";
-
-    auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh);
-    LOG_IF(FATAL, (!volTetMesh)) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!";
-
-    // Rotate a rando angle
-    volTetMesh->rotate(Vec3d(0, 1, 0), static_cast<double>(rand()), Geometry::TransformType::ApplyToData);
-
-    // Translate
-    volTetMesh->translate(translation, Geometry::TransformType::ApplyToData);
+Color getRandomColor();
 
-    // Trick to force update geometry postUpdateTransform
-    const auto positions = volTetMesh->getVertexPositions();
-    (void)positions;
-
-    static int count = -1;
-    ++count;
-    surfMesh = std::make_shared<SurfaceMesh>("Dragon-" + std::to_string(count));
-    volTetMesh->extractSurfaceMesh(surfMesh, true);
-
-    auto material = std::make_shared<RenderMaterial>();
-
-#if 0
-    // Wireframe color
-    material->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE);
-    material->setColor(getRandomColor()); // Wireframe color
-    material->setLineWidth(2);
-#else
-    material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
-    material->setColor(getRandomColor());
-#endif
-
-    auto surfMeshModel = std::make_shared<VisualModel>(surfMesh);
-    surfMeshModel->setRenderMaterial(material);
-
-    auto deformMapP2C = std::make_shared<OneToOneMap>(tetMesh, surfMesh);
-
-    deformableObj = std::make_shared<PbdObject>("Dragon-" + std::to_string(count));
-    deformableObj->addVisualModel(surfMeshModel);
-    deformableObj->setCollidingGeometry(surfMesh);
-    deformableObj->setPhysicsGeometry(volTetMesh);
-    deformableObj->setPhysicsToCollidingMap(deformMapP2C);
-
-    // Create model and object
-    auto pbdModel = std::make_shared<PbdModel>();
-    pbdModel->setModelGeometry(volTetMesh);
-
-    // configure model
-    auto pbdParams = std::make_shared<PBDModelConfig>();
-
-    // FEM constraint
-    pbdParams->m_femParams->m_YoungModulus = 1000.0;
-    pbdParams->m_femParams->m_PoissonRatio = 0.3;
-    pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK);
-
-    // Other parameters
-    pbdParams->m_uniformMassValue = 5.0;
-    pbdParams->m_gravity    = Vec3d(0, -1.0, 0);
-    pbdParams->m_defaultDt  = 0.01;
-    pbdParams->m_iterations = 20;
-    pbdParams->collisionParams->m_proximity = 0.5;
-
-    pbdModel->configure(pbdParams);
-    deformableObj->setDynamicalModel(pbdModel);
-
-    scene->addSceneObject(deformableObj);
-}
+void generateDragon(const std::shared_ptr<imstk::Scene>& scene,
+                    const Vec3d&                         translation,
+                    std::shared_ptr<SurfaceMesh>&        surfMesh,
+                    std::shared_ptr<PbdObject>&          deformableObj);
 
 ///
 /// \brief Create a surface mesh
@@ -151,39 +68,35 @@ std::shared_ptr<SurfaceMesh> createUniformSurfaceMesh(const double width, const
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("PbdCollision");
+    // Write log to stdout and file
+    Logger::startLogger();
 
-    // Get the VTKViewer
-    std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false);
-    viewer->setWindowTitle("PbdCollision");
-    viewer->getVtkRenderWindow()->SetSize(1920, 1080);
-    simManager->setViewer(viewer);
+    imstkNew<Scene> scene("PbdCollision");
 
-    auto floorMesh = createUniformSurfaceMesh(100.0, 100.0, 2, 2);
+    std::shared_ptr<SurfaceMesh> floorMesh = createUniformSurfaceMesh(100.0, 100.0, 2, 2);
 
-    auto materialFloor = std::make_shared<RenderMaterial>();
-    materialFloor->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    auto floorMeshModel = std::make_shared<VisualModel>(floorMesh);
-    floorMeshModel->setRenderMaterial(materialFloor);
+    imstkNew<RenderMaterial> floorMaterial;
+    floorMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+    imstkNew<VisualModel> floorMeshModel(floorMesh);
+    floorMeshModel->setRenderMaterial(floorMaterial);
 
-    auto floorObj = std::make_shared<PbdObject>("Floor");
+    imstkNew<PbdObject> floorObj("Floor");
     floorObj->setCollidingGeometry(floorMesh);
     floorObj->setVisualGeometry(floorMesh);
     floorObj->setPhysicsGeometry(floorMesh);
 
-    auto pbdModel2 = std::make_shared<PbdModel>();
-    pbdModel2->setModelGeometry(floorMesh);
+    imstkNew<PbdModel> pbdModel;
+    pbdModel->setModelGeometry(floorMesh);
 
     // configure model
-    auto pbdParams2 = std::make_shared<PBDModelConfig>();
-    pbdParams2->m_uniformMassValue = 0.0;
-    pbdParams2->collisionParams->m_proximity = 0.1;
-    pbdParams2->m_iterations = 0;
+    imstkNew<PBDModelConfig> pbdParams;
+    pbdParams->m_uniformMassValue = 0.0;
+    pbdParams->collisionParams->m_proximity = 0.1;
+    pbdParams->m_iterations = 0;
 
     // Set the parameters
-    pbdModel2->configure(pbdParams2);
-    floorObj->setDynamicalModel(pbdModel2);
+    pbdModel->configure(pbdParams);
+    floorObj->setDynamicalModel(pbdModel);
     scene->addSceneObject(floorObj);
 
 #ifdef BIG_SCENE
@@ -213,9 +126,8 @@ main()
             {
                 std::shared_ptr<SurfaceMesh> mesh;
                 std::shared_ptr<PbdObject>   pbdObj;
-                std::shared_ptr<PbdSolver>   solver;
                 Vec3d                        translation(shiftX + i * distanceXZ, minHeight + j * distanceY, k * distanceXZ);
-                generateDragon(scene, translation, mesh, pbdObj, solver);
+                generateDragon(scene, translation, mesh, pbdObj);
                 pbdObjs.push_back(pbdObj);
 
                 scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(pbdObj, floorObj,
@@ -234,30 +146,142 @@ main()
     }
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
+    imstkNew<DirectionalLight> light("light");
     light->setFocalPoint(Vec3d(5, -8, -5));
     light->setIntensity(1);
     scene->addLight(light);
 
     // Set Camera configuration
-    auto cam = scene->getCamera();
+    std::shared_ptr<Camera> cam = scene->getActiveCamera();
     cam->setPosition(Vec3d(0, 15, 30));
     cam->setFocalPoint(Vec3d(0, 0, 0));
 
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    {
+        // Add a module to run the viewer
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+        viewer->setWindowTitle("PbdCollision");
+        viewer->setSize(1920, 1080);
+
+        // Add a module to run the scene
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // Start/stop scene with the view
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
 
+Color
+getRandomColor()
+{
+    Color color(0.0, 0.0, 0.0, 1.0);
+    while (true)
+    {
+        for (unsigned int i = 0; i < 3; ++i)
+        {
+            color.rgba[i] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
+        }
+        if (color.rgba[0] > 0.95
+            || color.rgba[1] > 0.95
+            || color.rgba[2] > 0.95)
+        {
+            break;
+        }
+    }
+    return color;
+}
+
+void
+generateDragon(const std::shared_ptr<imstk::Scene>& scene,
+               const Vec3d&                         translation,
+               std::shared_ptr<SurfaceMesh>&        surfMesh,
+               std::shared_ptr<PbdObject>&          deformableObj)
+{
+    // Load a sample mesh
+    auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    LOG_IF(FATAL, (!tetMesh)) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!";
+
+    // Rotate a rando angle
+    tetMesh->rotate(Vec3d(0, 1, 0), static_cast<double>(rand()), Geometry::TransformType::ApplyToData);
+
+    // Translate
+    tetMesh->translate(translation, Geometry::TransformType::ApplyToData);
+
+    // Trick to force update geometry postUpdateTransform
+    const auto positions = tetMesh->getVertexPositions();
+    (void)positions;
+
+    static int count = -1;
+    ++count;
+    surfMesh = std::make_shared<SurfaceMesh>("Dragon-" + std::to_string(count));
+    tetMesh->extractSurfaceMesh(surfMesh, true);
+
+    imstkNew<RenderMaterial> material;
+#if 0
+    // Wireframe color
+    material->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE);
+    material->setColor(getRandomColor()); // Wireframe color
+    material->setLineWidth(2);
+#else
+    material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+    material->setColor(getRandomColor());
+#endif
+
+    imstkNew<VisualModel> surfMeshModel(surfMesh);
+    surfMeshModel->setRenderMaterial(material);
+
+    deformableObj = std::make_shared<PbdObject>("Dragon-" + std::to_string(count));
+    deformableObj->addVisualModel(surfMeshModel);
+    deformableObj->setCollidingGeometry(surfMesh);
+    deformableObj->setPhysicsGeometry(tetMesh);
+    deformableObj->setPhysicsToCollidingMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh));
+
+    // Create model and object
+    imstkNew<PbdModel> pbdModel;
+    pbdModel->setModelGeometry(tetMesh);
+
+    // configure model
+    imstkNew<PBDModelConfig> pbdParams;
+
+    // FEM constraint
+    pbdParams->m_femParams->m_YoungModulus = 1000.0;
+    pbdParams->m_femParams->m_PoissonRatio = 0.3;
+    pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK);
+
+    // Other parameters
+    pbdParams->m_uniformMassValue = 5.0;
+    pbdParams->m_gravity    = Vec3d(0, -1.0, 0);
+    pbdParams->m_defaultDt  = 0.01;
+    pbdParams->m_iterations = 20;
+    pbdParams->collisionParams->m_proximity = 0.5;
+
+    pbdModel->configure(pbdParams);
+    deformableObj->setDynamicalModel(pbdModel);
+
+    scene->addSceneObject(deformableObj);
+}
+
 std::shared_ptr<SurfaceMesh>
 createUniformSurfaceMesh(const double width, const double height, const size_t nRows, const size_t nCols)
 {
     // Build floor geometry
-    // const double width  = 100.0;
-    // const double height = 100.0;
-    // const size_t nRows  = 2;
-    // const size_t nCols  = 2;
     const double dy = width / static_cast<double>(nCols - 1);
     const double dx = height / static_cast<double>(nRows - 1);
 
@@ -287,7 +311,7 @@ createUniformSurfaceMesh(const double width, const double height, const size_t n
         }
     }
 
-    auto surfMesh = std::make_shared<SurfaceMesh>();
+    imstkNew<SurfaceMesh> surfMesh;
     surfMesh->initialize(vertList, triangles);
 
     return surfMesh;
diff --git a/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp b/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp
index 65a5343f8684602417e06675247e9ff405f11daa..8127569827271cb8d65be0c44159700962c8fa30 100644
--- a/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp
+++ b/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp
@@ -21,29 +21,30 @@
 
 #include "imstkCamera.h"
 #include "imstkCollisionGraph.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
+#include "imstkLogger.h"
 #include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkObjectInteractionFactory.h"
 #include "imstkOneToOneMap.h"
 #include "imstkPbdModel.h"
 #include "imstkPbdObject.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
-#include "imstkSimulationManager.h"
+#include "imstkSceneManager.h"
 #include "imstkSurfaceMesh.h"
-#include "imstkTaskGraphVizWriter.h"
+#include "imstkTetrahedralMesh.h"
 #include "imstkTetraTriangleMap.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
 // mesh file names
 const std::string surfMeshFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj";
 const std::string tetMeshFileName  = iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg";
-///
-/// \brief Create a surface mesh
-/// \param nRows number of vertices in x-direction
-/// \param nCols number of vertices in y-direction
-///
-std::shared_ptr<SurfaceMesh> createUniformSurfaceMesh(const double width, const double height, const size_t nRows, const size_t nCols);
 
 // parameters to play with
 const double youngModulus     = 1000.0;
@@ -52,6 +53,13 @@ const double timeStep         = 0.01;
 const double contactStiffness = 0.1;
 const int    maxIter = 5;
 
+///
+/// \brief Create a surface mesh
+/// \param nRows number of vertices in x-direction
+/// \param nCols number of vertices in y-direction
+///
+std::shared_ptr<SurfaceMesh> createUniformSurfaceMesh(const double width, const double height, const size_t nRows, const size_t nCols);
+
 ///
 /// \brief This example demonstrates the collision interaction
 /// using Position based dynamics
@@ -59,106 +67,131 @@ const int    maxIter = 5;
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("PbdCollisionOneDragon");
-    scene->getCamera()->setPosition(0, 3.0, 20.0);
-    scene->getCamera()->setFocalPoint(0.0, -10.0, 0.0);
-
-    // set up the meshes
-    auto highResSurfMesh = std::dynamic_pointer_cast<SurfaceMesh>(MeshIO::read(surfMeshFileName));
-    auto coarseTetMesh   = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(tetMeshFileName));
-    auto coarseSurfMesh  = std::make_shared<SurfaceMesh>();
-    coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true);
-
-    // set up maps
-    auto mapPhysicsToVisual    = std::make_shared<TetraTriangleMap>(coarseTetMesh, highResSurfMesh);
-    auto mapCollisionToPhysics = std::make_shared<OneToOneMap>(coarseTetMesh, coarseSurfMesh);
-
-    // set up visual model based on high res mesh
-    auto material = std::make_shared<RenderMaterial>();
-    material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
-    material->setLineWidth(0.5);
-    material->setEdgeColor(Color::Blue);
-    material->setShadingModel(RenderMaterial::ShadingModel::Phong);
-    auto surfMeshModel = std::make_shared<VisualModel>(highResSurfMesh);
-    surfMeshModel->setRenderMaterial(material);
-
-    // configure the deformable object
-    auto deformableObj = std::make_shared<PbdObject>("DeformableObj");
-    deformableObj->addVisualModel(surfMeshModel);
-    deformableObj->setCollidingGeometry(coarseSurfMesh);
-    deformableObj->setPhysicsGeometry(coarseTetMesh);
-    deformableObj->setPhysicsToCollidingMap(mapCollisionToPhysics);
-    deformableObj->setPhysicsToVisualMap(mapPhysicsToVisual);
-
-    // Create model and object
-    auto pbdModel = std::make_shared<PbdModel>();
-    pbdModel->setModelGeometry(coarseTetMesh);
-
-    // configure model
-    auto pbdParams = std::make_shared<PBDModelConfig>();
-
-    // FEM constraint
-    pbdParams->m_femParams->m_YoungModulus = youngModulus;
-    pbdParams->m_femParams->m_PoissonRatio = poissonRatio;
-    pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet,
-                                   PbdFEMConstraint::MaterialType::Corotation);
-
-    // Other parameters
-    // \todo use lumped mass
-    pbdParams->m_uniformMassValue = 1.0;
-
-    pbdParams->m_gravity    = Vec3d(0, -10.0, 0);
-    pbdParams->m_defaultDt  = timeStep;
-    pbdParams->m_iterations = maxIter;
-    pbdParams->collisionParams->m_proximity = 0.3;
-    pbdParams->collisionParams->m_stiffness = 0.1;
-
-    pbdModel->configure(pbdParams);
-    deformableObj->setDynamicalModel(pbdModel);
-
-    scene->addSceneObject(deformableObj);
-
-    // Build floor geometry
-    auto floorMesh = createUniformSurfaceMesh(100.0, 100.0, 2, 2);
-
-    auto materialFloor = std::make_shared<RenderMaterial>();
-    materialFloor->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    auto floorMeshModel = std::make_shared<VisualModel>(floorMesh);
-    floorMeshModel->setRenderMaterial(materialFloor);
-
-    auto floor = std::make_shared<PbdObject>("Floor");
-    floor->setCollidingGeometry(floorMesh);
-    floor->setVisualGeometry(floorMesh);
-    floor->setPhysicsGeometry(floorMesh);
-
-    auto pbdModel2 = std::make_shared<PbdModel>();
-    pbdModel2->setModelGeometry(floorMesh);
-
-    // configure model
-    auto pbdParams2 = std::make_shared<PBDModelConfig>();
-    pbdParams2->m_uniformMassValue = 0.0;
-    pbdParams2->m_iterations       = 0;
-    pbdParams2->collisionParams->m_proximity = -0.1;
-
-    // Set the parameters
-    pbdModel2->configure(pbdParams2);
-    floor->setDynamicalModel(pbdModel2);
-
-    scene->addSceneObject(floor);
-
-    // Collision
-    scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floor,
-        InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce));
-
-    // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
-    scene->addLight(light);
-
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    // Setup the scene
+    imstkNew<Scene> scene("PbdCollisionOneDragon");
+    {
+        scene->getActiveCamera()->setPosition(0, 3.0, 20.0);
+        scene->getActiveCamera()->setFocalPoint(0.0, -10.0, 0.0);
+
+        // set up the meshes
+        auto                  highResSurfMesh = MeshIO::read<SurfaceMesh>(surfMeshFileName);
+        auto                  coarseTetMesh   = MeshIO::read<TetrahedralMesh>(tetMeshFileName);
+        imstkNew<SurfaceMesh> coarseSurfMesh;
+        coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true);
+
+        // set up visual model based on high res mesh
+        imstkNew<RenderMaterial> material;
+        material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+        material->setLineWidth(0.5);
+        material->setEdgeColor(Color::Blue);
+        material->setShadingModel(RenderMaterial::ShadingModel::Phong);
+        imstkNew<VisualModel> surfMeshModel(highResSurfMesh);
+        surfMeshModel->setRenderMaterial(material);
+
+        // configure the deformable object
+        imstkNew<PbdObject> deformableObj("DeformableObj");
+        deformableObj->addVisualModel(surfMeshModel);
+        deformableObj->setCollidingGeometry(coarseSurfMesh);
+        deformableObj->setPhysicsGeometry(coarseTetMesh);
+        deformableObj->setPhysicsToCollidingMap(std::make_shared<OneToOneMap>(coarseTetMesh, coarseSurfMesh));
+        deformableObj->setPhysicsToVisualMap(std::make_shared<TetraTriangleMap>(coarseTetMesh, highResSurfMesh));
+
+        // Create model and object
+        imstkNew<PbdModel> pbdModel;
+        pbdModel->setModelGeometry(coarseTetMesh);
+
+        // configure model
+        imstkNew<PBDModelConfig> pbdParams;
+
+        // FEM constraint
+        pbdParams->m_femParams->m_YoungModulus = youngModulus;
+        pbdParams->m_femParams->m_PoissonRatio = poissonRatio;
+        pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet,
+            PbdFEMConstraint::MaterialType::Corotation);
+
+        // Other parameters
+        // \todo use lumped mass
+        pbdParams->m_uniformMassValue = 1.0;
+        pbdParams->m_gravity    = Vec3d(0, -10.0, 0);
+        pbdParams->m_defaultDt  = timeStep;
+        pbdParams->m_iterations = maxIter;
+        pbdParams->collisionParams->m_proximity = 0.3;
+        pbdParams->collisionParams->m_stiffness = 0.1;
+
+        pbdModel->configure(pbdParams);
+        deformableObj->setDynamicalModel(pbdModel);
+
+        scene->addSceneObject(deformableObj);
+
+        // Build floor geometry
+        auto floorMesh = createUniformSurfaceMesh(100.0, 100.0, 2, 2);
+
+        imstkNew<RenderMaterial> floorMaterial;
+        floorMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+        imstkNew<VisualModel> floorVisualModel(floorMesh);
+        floorVisualModel->setRenderMaterial(floorMaterial);
+
+        imstkNew<PbdObject> floorObj("Floor");
+        floorObj->setCollidingGeometry(floorMesh);
+        floorObj->setPhysicsGeometry(floorMesh);
+        floorObj->addVisualModel(floorVisualModel);
+
+        imstkNew<PbdModel> floorPbdModel;
+        floorPbdModel->setModelGeometry(floorMesh);
+
+        // configure model
+        imstkNew<PBDModelConfig> floorPbdParams;
+        floorPbdParams->m_uniformMassValue = 0.0;
+        floorPbdParams->m_iterations       = 0;
+        floorPbdParams->collisionParams->m_proximity = -0.1;
+
+        // Set the parameters
+        floorPbdModel->configure(floorPbdParams);
+        floorObj->setDynamicalModel(floorPbdModel);
+
+        scene->addSceneObject(floorObj);
+
+        // Collision
+        scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floorObj,
+            InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce));
+
+        // Light
+        imstkNew<DirectionalLight> light("Light");
+        light->setFocalPoint(Vec3d(5, -8, -5));
+        light->setIntensity(1);
+        scene->addLight(light);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
@@ -196,7 +229,7 @@ createUniformSurfaceMesh(const double width, const double height, const size_t n
         }
     }
 
-    auto surfMesh = std::make_shared<SurfaceMesh>();
+    imstkNew<SurfaceMesh> surfMesh;
     surfMesh->initialize(vertList, triangles);
     return surfMesh;
 }
diff --git a/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp b/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp
index 823992faad968ce755ba22ec7130c1cc3dc7b9e2..e513ebc6ce2fb7a257732394782166983b8a0723 100644
--- a/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp
+++ b/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp
@@ -21,27 +21,30 @@
 
 #include "imstkCamera.h"
 #include "imstkCollisionGraph.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
+#include "imstkLogger.h"
 #include "imstkMeshIO.h"
-#include "imstkMeshToMeshBruteForceCD.h"
-#include "imstkOneToOneMap.h"
-#include "imstkPBDCollisionHandling.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkObjectInteractionFactory.h"
 #include "imstkPbdModel.h"
 #include "imstkPbdObject.h"
-#include "imstkPbdSolver.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
-#include "imstkSimulationManager.h"
+#include "imstkSceneManager.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkTetrahedralMesh.h"
 #include "imstkTetraTriangleMap.h"
-#include "imstkObjectInteractionFactory.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
 ///
 /// \brief Creates a non-manifold top part of a staircase
 //
-static std::unique_ptr<SurfaceMesh>
+static std::shared_ptr<SurfaceMesh>
 buildStairs(int nSteps, double width, double height, double depth)
 {
     // Build stair geometry
@@ -90,7 +93,7 @@ buildStairs(int nSteps, double width, double height, double depth)
         triangles.push_back({ { (i + 1) * 4, (i + 1) * 4 + 1, i * 4 + 3 } });
     }
 
-    std::unique_ptr<SurfaceMesh> stairMesh = std::make_unique<SurfaceMesh>();
+    imstkNew<SurfaceMesh> stairMesh;
     stairMesh->initialize(vertList, triangles);
     return stairMesh;
 }
@@ -101,18 +104,18 @@ buildStairs(int nSteps, double width, double height, double depth)
 static std::shared_ptr<PbdObject>
 makeArmadilloPbdObject(const std::string& name)
 {
-    auto pbdObj = std::make_shared<PbdObject>(name);
+    imstkNew<PbdObject> pbdObj(name);
 
     // Read in the armadillo mesh
-    auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(iMSTK_DATA_ROOT "armadillo/armadillo_volume.vtk"));
+    auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "armadillo/armadillo_volume.vtk");
     tetMesh->scale(0.07, Geometry::TransformType::ApplyToData);
     tetMesh->rotate(Vec3d(1.0, 0.0, 0.0), 1.3, Geometry::TransformType::ApplyToData);
     tetMesh->translate(Vec3d(0.0f, 10.0f, 0.0f), Geometry::TransformType::ApplyToData);
-    auto surfMesh = std::make_shared<SurfaceMesh>();
+    imstkNew<SurfaceMesh> surfMesh;
     tetMesh->extractSurfaceMesh(surfMesh, true);
 
     // Setup the Parameters
-    auto pbdParams = std::make_shared<PBDModelConfig>();
+    imstkNew<PBDModelConfig> pbdParams;
     pbdParams->m_femParams->m_YoungModulus = 1000.0;
     pbdParams->m_femParams->m_PoissonRatio = 0.3;
     pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet,
@@ -125,14 +128,14 @@ makeArmadilloPbdObject(const std::string& name)
     pbdParams->collisionParams->m_stiffness = 0.1;
 
     // Setup the Model
-    auto pbdModel = std::make_shared<PbdModel>();
+    imstkNew<PbdModel> pbdModel;
     pbdModel->setModelGeometry(tetMesh);
     pbdModel->configure(pbdParams);
 
     // Setup the VisualModel
-    auto material = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> material;
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    auto surfMeshModel = std::make_shared<VisualModel>(surfMesh);
+    imstkNew<VisualModel> surfMeshModel(surfMesh.get());
     surfMeshModel->setRenderMaterial(material);
 
     // Setup the Object
@@ -148,31 +151,30 @@ makeArmadilloPbdObject(const std::string& name)
 static std::shared_ptr<PbdObject>
 makeStairsPbdObject(const std::string& name, int numSteps, double width, double height, double depth)
 {
-    auto stairObj = std::make_shared<PbdObject>(name);
+    imstkNew<PbdObject> stairObj(name);
 
-    std::shared_ptr<SurfaceMesh> stairMesh(std::move(buildStairs(numSteps, width, height, depth)));
+    std::shared_ptr<SurfaceMesh> stairMesh = buildStairs(numSteps, width, height, depth);
 
     // Setup the parameters
-    auto pbdParams = std::make_shared<PBDModelConfig>();
+    imstkNew<PBDModelConfig> pbdParams;
     pbdParams->m_uniformMassValue = 0.0;
     pbdParams->collisionParams->m_proximity = -0.1;
     pbdParams->m_iterations = 0;
 
     // Setup the model
-    auto pbdModel = std::make_shared<PbdModel>();
+    imstkNew<PbdModel> pbdModel;
     pbdModel->setModelGeometry(stairMesh);
     pbdModel->configure(pbdParams);
 
     // Setup the VisualModel
-    auto stairMaterial = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> stairMaterial;
     stairMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    auto stairMeshModel = std::make_shared<VisualModel>(stairMesh);
-    stairMeshModel->setRenderMaterial(stairMaterial);
+    imstkNew<VisualModel> visualModel(stairMesh);
+    visualModel->setRenderMaterial(stairMaterial);
 
-    stairObj->addVisualModel(stairMeshModel);
+    stairObj->addVisualModel(visualModel);
     stairObj->setDynamicalModel(pbdModel);
     stairObj->setCollidingGeometry(stairMesh);
-    stairObj->setVisualGeometry(stairMesh);
     stairObj->setPhysicsGeometry(stairMesh);
 
     return stairObj;
@@ -185,35 +187,64 @@ makeStairsPbdObject(const std::string& name, int numSteps, double width, double
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("PbdStairsCollision");
-    scene->getCamera()->setPosition(0.0, 0.0, -30.0);
-    scene->getCamera()->setFocalPoint(0.0, 0.0, 0.0);
-
-    // Create and add the dragon to the scene
-    auto pbdDragon1 = makeArmadilloPbdObject("PbdArmadillo1");
-    scene->addSceneObject(pbdDragon1);
-
-    auto stairObj = makeStairsPbdObject("PbdStairs", 12, 20.0, 10.0, 20.0);
-    scene->addSceneObject(stairObj);
-
-    // Collision
-    scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(pbdDragon1, stairObj,
-        InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce));
-
-    // Light
-    auto light = std::make_shared<DirectionalLight>("Light");
-    light->setFocalPoint(Vec3d(5.0, -8.0, 5.0));
-    light->setIntensity(1.0);
-    scene->addLight(light);
-
-    auto light2 = std::make_shared<DirectionalLight>("light 2");
-    light2->setFocalPoint(-Vec3d(5, -8, 5));
-    light2->setIntensity(1.2);
-    scene->addLight(light2);
-
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("PbdStairsCollision");
+    {
+        scene->getActiveCamera()->setPosition(0.0, 0.0, -30.0);
+        scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
+
+        // Create and add the dragon to the scene
+        auto pbdDragon1 = makeArmadilloPbdObject("Armadillo");
+        scene->addSceneObject(pbdDragon1);
+
+        auto stairObj = makeStairsPbdObject("PbdStairs", 12, 20.0, 10.0, 20.0);
+        scene->addSceneObject(stairObj);
+
+        // Collision
+        scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(pbdDragon1, stairObj,
+            InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce));
+
+        // Light
+        imstkNew<DirectionalLight> light("Light1");
+        light->setFocalPoint(Vec3d(5.0, -8.0, 5.0));
+        light->setIntensity(1.0);
+        scene->addLight(light);
+
+        imstkNew<DirectionalLight> light2("Light2");
+        light2->setFocalPoint(-Vec3d(5, -8, 5));
+        light2->setIntensity(1.2);
+        scene->addLight(light2);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp b/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp
index f309e978d20afc58bda4f09c26d13a7736df1a6a..a5ce8f84e09a5edf60dca48f3a7b2f2ccae57bdd 100644
--- a/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp
+++ b/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp
@@ -19,29 +19,30 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
+#include "imstkCamera.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
+#include "imstkLogger.h"
 #include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkPbdModel.h"
 #include "imstkPbdObject.h"
-#include "imstkOneToOneMap.h"
-#include "imstkAPIUtilities.h"
-#include "imstkTetraTriangleMap.h"
-#include "imstkSurfaceMesh.h"
-#include "imstkCamera.h"
-#include "imstkPlane.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
-
-#include <array>
-#include <string>
+#include "imstkSceneManager.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTetrahedralMesh.h"
+#include "imstkTetraTriangleMap.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
 ///
 /// \brief Create a PbdObject and add it to a \p scene
 ///
-std::shared_ptr<PbdObject> createAndAddPbdObject(std::shared_ptr<Scene> scene,
-                                                 const std::string&     tetMeshName);
+std::shared_ptr<PbdObject> createAndAddPbdObject(const std::string& tetMeshName);
 
 // mesh file names
 const std::string& tetMeshFileName = iMSTK_DATA_ROOT "textured_organs/heart_volume.vtk";
@@ -53,38 +54,62 @@ const std::string& tetMeshFileName = iMSTK_DATA_ROOT "textured_organs/heart_volu
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("PBDVolume");
-    scene->getCamera()->setPosition(0, 2.0, 15.0);
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("PBDVolume");
+    scene->getActiveCamera()->setPosition(0, 2.0, 15.0);
 
     // create and add a PBD object
-    createAndAddPbdObject(scene, tetMeshFileName);
+    scene->addSceneObject(createAndAddPbdObject(tetMeshFileName));
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
+    imstkNew<DirectionalLight> light("light");
     light->setFocalPoint(Vec3d(5, -8, -5));
     light->setIntensity(1.1);
     scene->addLight(light);
 
-    simManager->setActiveScene(scene);
-    simManager->getViewer()->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true);
-    simManager->start(SimulationStatus::Paused);
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+        viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
 
 std::shared_ptr<PbdObject>
-createAndAddPbdObject(std::shared_ptr<Scene> scene,
-                      const std::string&     tetMeshName)
+createAndAddPbdObject(const std::string& tetMeshName)
 {
-    auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(tetMeshName));
+    auto tetMesh = MeshIO::read<TetrahedralMesh>(tetMeshName);
     tetMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.3, Geometry::TransformType::ApplyToData);
-    auto surfMesh = std::make_shared<SurfaceMesh>();
+    imstkNew<SurfaceMesh> surfMesh;
     tetMesh->extractSurfaceMesh(surfMesh, true);
 
-    auto map = std::make_shared<TetraTriangleMap>(tetMesh, surfMesh);
-
-    auto material = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> material;
     material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
     material->setColor(Color(220. / 255.0, 100. / 255.0, 70. / 255.0));
     material->setMetalness(100.9f);
@@ -93,15 +118,15 @@ createAndAddPbdObject(std::shared_ptr<Scene> scene,
     material->setAmbientLightCoeff(50.);
     material->setShadingModel(RenderMaterial::ShadingModel::Phong);
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    auto surfMeshModel = std::make_shared<VisualModel>(surfMesh);
-    surfMeshModel->setRenderMaterial(material);
+    imstkNew<VisualModel> visualModel(surfMesh.get());
+    visualModel->setRenderMaterial(material);
 
-    auto deformableObj = std::make_shared<PbdObject>("DeformableObject");
-    auto pbdModel      = std::make_shared<PbdModel>();
+    imstkNew<PbdObject> deformableObj("DeformableObject");
+    imstkNew<PbdModel>  pbdModel;
     pbdModel->setModelGeometry(tetMesh);
 
-    // configure model
-    auto pbdParams = std::make_shared<PBDModelConfig>();
+    // Configure model
+    imstkNew<PBDModelConfig> pbdParams;
 
     // FEM constraint
     pbdParams->m_femParams->m_YoungModulus = 500.0;
@@ -120,11 +145,9 @@ createAndAddPbdObject(std::shared_ptr<Scene> scene,
     pbdModel->setTimeStepSizeType(imstk::TimeSteppingType::Fixed);
 
     deformableObj->setDynamicalModel(pbdModel);
-    deformableObj->addVisualModel(surfMeshModel);
+    deformableObj->addVisualModel(visualModel);
     deformableObj->setPhysicsGeometry(tetMesh);
-    deformableObj->setPhysicsToVisualMap(map); //assign the computed map
-
-    scene->addSceneObject(deformableObj);
+    deformableObj->setPhysicsToVisualMap(std::make_shared<TetraTriangleMap>(tetMesh, surfMesh));
 
     return deformableObj;
 }
diff --git a/Examples/PBD/PBDFluids/CMakeLists.txt b/Examples/PBD/PBDFluids/CMakeLists.txt
index af7b92b1d3e7c4248dfa9af5a01c42488bb823db..7a7f4b6925c227fdd45bc1a0ceeebcdc6a6b460a 100644
--- a/Examples/PBD/PBDFluids/CMakeLists.txt
+++ b/Examples/PBD/PBDFluids/CMakeLists.txt
@@ -35,4 +35,4 @@ SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/PBD)
 #-----------------------------------------------------------------------------
 # Link libraries to executable
 #-----------------------------------------------------------------------------
-target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities)
+target_link_libraries(${PROJECT_NAME} SimulationManager)
diff --git a/Examples/PBD/PBDFluids/PBDFluidsExample.cpp b/Examples/PBD/PBDFluids/PBDFluidsExample.cpp
index eb4639c3735215d94fecbaaba031851a7d1adb4d..79a40cbaca0650f4548a932ecb46f29b53b5a240 100644
--- a/Examples/PBD/PBDFluids/PBDFluidsExample.cpp
+++ b/Examples/PBD/PBDFluids/PBDFluidsExample.cpp
@@ -19,19 +19,23 @@
 
 =========================================================================*/
 
-#include "imstkAPIUtilities.h"
 #include "imstkCamera.h"
 #include "imstkCollisionGraph.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
+#include "imstkLogger.h"
 #include "imstkMeshIO.h"
-#include "imstkMeshToMeshBruteForceCD.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkObjectInteractionFactory.h"
-#include "imstkPBDCollisionHandling.h"
 #include "imstkPbdModel.h"
 #include "imstkPbdObject.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
-#include "imstkSimulationManager.h"
+#include "imstkSceneManager.h"
 #include "imstkSurfaceMesh.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -56,53 +60,73 @@ const std::string tetMeshFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.ve
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("PBDFluid");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
 
-    scene->getCamera()->setPosition(0, 10.0, 15.0);
+    imstkNew<Scene> scene("PBDFluid");
+    {
+        scene->getActiveCamera()->setPosition(0.0, 15.0, 20.0);
 
-    auto deformableObj      = createAndAddPbdObject(scene, tetMeshFileName);
-    auto floorMeshColliding = createCollidingSurfaceMesh();
-    auto floorMeshVisual    = std::make_shared<SurfaceMesh>();
-    floorMeshVisual->initialize(floorMeshColliding->getVertexPositions(), floorMeshColliding->getTrianglesVertices());
-    auto floorMeshPhysics = std::make_shared<SurfaceMesh>();
-    floorMeshPhysics->initialize(floorMeshColliding->getVertexPositions(), floorMeshColliding->getTrianglesVertices());
+        std::shared_ptr<PbdObject>   deformableObj      = createAndAddPbdObject(scene, tetMeshFileName);
+        std::shared_ptr<SurfaceMesh> floorMeshColliding = createCollidingSurfaceMesh();
 
-    auto floor = std::make_shared<PbdObject>("Floor");
-    floor->setCollidingGeometry(floorMeshColliding);
-    floor->setVisualGeometry(floorMeshVisual);
-    floor->setPhysicsGeometry(floorMeshPhysics);
+        imstkNew<PbdObject> floorObj("Floor");
+        floorObj->setCollidingGeometry(floorMeshColliding);
+        floorObj->setVisualGeometry(floorMeshColliding);
+        floorObj->setPhysicsGeometry(floorMeshColliding);
 
-    auto pbdModel2 = std::make_shared<PbdModel>();
-    pbdModel2->setModelGeometry(floorMeshPhysics);
+        imstkNew<PbdModel> pbdModel;
+        pbdModel->setModelGeometry(floorMeshColliding);
 
-    // Configure model
-    auto pbdParams2 = std::make_shared<PBDModelConfig>();
-    pbdParams2->m_uniformMassValue = 0.0;
-    pbdParams2->collisionParams->m_proximity = 0.1;
+        // Configure model
+        imstkNew<PBDModelConfig> pbdParams;
+        pbdParams->m_uniformMassValue = 0.0;
+        pbdParams->collisionParams->m_proximity = 0.1;
 
-    pbdModel2->configure(pbdParams2);
-    floor->setDynamicalModel(pbdModel2);
+        pbdModel->configure(pbdParams);
+        floorObj->setDynamicalModel(pbdModel);
 
-    scene->addSceneObject(floor);
+        scene->addSceneObject(floorObj);
 
-    // Collisions
-    scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floor,
-                                                                         InteractionType::PbdObjToPbdObjCollision,
-                                                                         CollisionDetection::Type::MeshToMeshBruteForce));
+        // Collisions
+        scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floorObj,
+            InteractionType::PbdObjToPbdObjCollision,
+            CollisionDetection::Type::MeshToMeshBruteForce));
 
-    // Light (white)
-    auto whiteLight = std::make_shared<DirectionalLight>("whiteLight");
-    whiteLight->setFocalPoint(Vec3d(5, -8, -5));
-    whiteLight->setIntensity(7);
-    scene->addLight(whiteLight);
+        // Light (white)
+        imstkNew<DirectionalLight> whiteLight("whiteLight");
+        whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+        whiteLight->setIntensity(7);
+        scene->addLight(whiteLight);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
 
-    // print UPS
-    scene->getConfig()->trackFPS = true;
-    apiutils::printUPS(simManager->getSceneManager(scene));
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
 
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
@@ -112,37 +136,37 @@ createAndAddPbdObject(std::shared_ptr<Scene> scene,
                       const std::string&     tetMeshName)
 {
     // Load a sample mesh
-    auto tetMesh = MeshIO::read(tetMeshName);
+    std::shared_ptr<PointSet> tetMesh = MeshIO::read(tetMeshName);
 
-    auto fluidMesh = std::make_shared<PointSet>();
+    imstkNew<PointSet> fluidMesh;
     fluidMesh->initialize(tetMesh->getInitialVertexPositions());
 
-    auto fluidVisualModel = std::make_shared<VisualModel>(fluidMesh);
+    imstkNew<VisualModel> fluidVisualModel(fluidMesh.get());
 
-    auto material1 = std::make_shared<RenderMaterial>();
-    material1->setDisplayMode(RenderMaterial::DisplayMode::Fluid);
-    material1->setVertexColor(Color::Red);
-    material1->setPointSize(12.);
-    fluidVisualModel->setRenderMaterial(material1);
+    imstkNew<RenderMaterial> material;
+    material->setDisplayMode(RenderMaterial::DisplayMode::Fluid);
+    material->setVertexColor(Color::Red);
+    material->setPointSize(0.5);
+    fluidVisualModel->setRenderMaterial(material);
 
-    auto deformableObj = std::make_shared<PbdObject>("Dragon");
+    imstkNew<PbdObject> deformableObj("Dragon");
     deformableObj->addVisualModel(fluidVisualModel);
     deformableObj->setCollidingGeometry(fluidMesh);
     deformableObj->setPhysicsGeometry(fluidMesh);
 
-    auto pbdModel = std::make_shared<PbdModel>();
+    imstkNew<PbdModel> pbdModel;
     pbdModel->setModelGeometry(fluidMesh);
 
     // Configure model
-    auto pbdParams = std::make_shared<PBDModelConfig>();
+    imstkNew<PBDModelConfig> pbdParams;
 
     // Constant density constraint with stiffness
     pbdParams->enableConstraint(PbdConstraint::Type::ConstantDensity, 1.0);
 
     // Other parameters
     pbdParams->m_uniformMassValue = 1.0;
-    pbdParams->m_gravity    = Vec3d(0, -9.8, 0);
-    pbdParams->m_defaultDt  = 0.01;
+    pbdParams->m_gravity    = Vec3d(0.0, -9.8, 0.0);
+    pbdParams->m_defaultDt  = 0.005;
     pbdParams->m_iterations = 2;
     pbdParams->collisionParams->m_proximity = 0.01;
 
@@ -263,7 +287,7 @@ createCollidingSurfaceMesh()
         }
     }
 
-    auto floorMeshColliding = std::make_shared<SurfaceMesh>();
+    imstkNew<SurfaceMesh> floorMeshColliding;
     floorMeshColliding->initialize(vertList, triangles);
     return floorMeshColliding;
 }
diff --git a/Examples/PBD/PBDString/CMakeLists.txt b/Examples/PBD/PBDString/CMakeLists.txt
index 19baab77243a56d243d6cda370571910867dd432..ebfc89726577b3c07b3037e56dffad62a5c853ac 100644
--- a/Examples/PBD/PBDString/CMakeLists.txt
+++ b/Examples/PBD/PBDString/CMakeLists.txt
@@ -31,4 +31,4 @@ SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/PBD)
 #-----------------------------------------------------------------------------
 # Link libraries to executable
 #-----------------------------------------------------------------------------
-target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities)
+target_link_libraries(${PROJECT_NAME} SimulationManager)
diff --git a/Examples/PBD/PBDString/pbdStringExample.cpp b/Examples/PBD/PBDString/pbdStringExample.cpp
index 2b3e9e8165f298b815bf2ecae5399072156cb977..1bb01d3baae3c425a7a807714a601c67fc2fed9b 100644
--- a/Examples/PBD/PBDString/pbdStringExample.cpp
+++ b/Examples/PBD/PBDString/pbdStringExample.cpp
@@ -20,12 +20,18 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLineMesh.h"
+#include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkPbdModel.h"
 #include "imstkPbdObject.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
 #include "imstkSceneManager.h"
-#include "imstkSimulationManager.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -36,7 +42,7 @@ static std::shared_ptr<LineMesh>
 makeStringGeometry(const Vec3d& pos, const size_t numVerts, const double stringLength)
 {
     // Create the geometry
-    std::shared_ptr<LineMesh> stringGeometry = std::make_shared<LineMesh>();
+    imstkNew<LineMesh> stringGeometry;
 
     StdVectorOfVec3d vertList;
     vertList.resize(numVerts);
@@ -72,14 +78,14 @@ makePbdString(
     const double       bendStiffness,
     const Color&       color)
 {
-    std::shared_ptr<PbdObject> stringObj = std::make_shared<PbdObject>(name);
+    imstkNew<PbdObject> stringObj(name);
 
     // Setup the Geometry
     std::shared_ptr<LineMesh> stringMesh = makeStringGeometry(pos, numVerts, stringLength);
 
     // Setup the Parameters
-    auto pbdParams = std::make_shared<PBDModelConfig>();
-    pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1e7);
+    imstkNew<PBDModelConfig> pbdParams;
+    pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1.0e7);
     pbdParams->enableConstraint(PbdConstraint::Type::Bend, bendStiffness);
     pbdParams->m_fixedNodeIds     = { 0 };
     pbdParams->m_uniformMassValue = 5.0;
@@ -88,19 +94,19 @@ makePbdString(
     pbdParams->m_iterations = 5;
 
     // Setup the Model
-    std::shared_ptr<PbdModel> pbdModel = std::make_shared<PbdModel>();
+    imstkNew<PbdModel> pbdModel;
     pbdModel->setModelGeometry(stringMesh);
     pbdModel->configure(pbdParams);
 
     // Setup the VisualModel
-    std::shared_ptr<RenderMaterial> material = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> material;
     material->setBackFaceCulling(false);
     material->setEdgeColor(color);
     material->setLineWidth(2.0f);
     material->setPointSize(6.0f);
     material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
 
-    std::shared_ptr<VisualModel> visualModel = std::make_shared<VisualModel>(stringMesh);
+    imstkNew<VisualModel> visualModel(stringMesh);
     visualModel->setRenderMaterial(material);
 
     // Setup the Object
@@ -156,8 +162,10 @@ const Color  endColor      = Color(0.0, 1.0, 0.0); // Color of last string
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("PBDString");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("PBDString");
 
     // Setup N separate strings with varying bend stiffnesses
     std::vector<std::shared_ptr<PbdObject>> pbdStringObjs =
@@ -168,14 +176,13 @@ main()
     }
 
     // Adjust the camera
-    scene->getCamera()->setFocalPoint(0.0, 0.0, 0.0);
-    scene->getCamera()->setPosition(0.0, 0.0, 15.0);
+    scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
+    scene->getActiveCamera()->setPosition(0.0, 0.0, 15.0);
 
     // Move the points every frame
     double t = 0.0;
-
-    auto movePoints =
-        [&pbdStringObjs, &t](Module* module)
+    auto   movePoints =
+        [&pbdStringObjs, &t](Event*)
         {
             for (unsigned int i = 0; i < pbdStringObjs.size(); i++)
             {
@@ -190,11 +197,35 @@ main()
             }
             t += dt;
         };
-    simManager->getSceneManager(scene)->setPostUpdateCallback(movePoints);
 
-    // Start
-    simManager->setActiveScene(scene);
-    simManager->start();
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        connect<Event>(sceneManager, EventType::PostUpdate, movePoints);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
\ No newline at end of file
diff --git a/Examples/RCM/CMakeLists.txt b/Examples/RCM/CMakeLists.txt
index 2ab018c8bc080f7c15440b132cc1d2d696fcb3d4..10814d1f326c1b66b7f90cadc02a73cca99537a4 100644
--- a/Examples/RCM/CMakeLists.txt
+++ b/Examples/RCM/CMakeLists.txt
@@ -21,7 +21,7 @@ project(Example-RCM)
 #-----------------------------------------------------------------------------
 # Create executable
 #-----------------------------------------------------------------------------
-imstk_add_executable(${PROJECT_NAME} RCM.cpp)
+imstk_add_executable(${PROJECT_NAME} RCM.cpp bandwidth.h)
 
 #-----------------------------------------------------------------------------
 # Add the target to Examples folder
diff --git a/Examples/RCM/RCM.cpp b/Examples/RCM/RCM.cpp
index aa24bce918650dc22dd22a7fb965103a30d4b2ef..925dde40158add3ad20858e4c7b0ab2e2e253a3a 100644
--- a/Examples/RCM/RCM.cpp
+++ b/Examples/RCM/RCM.cpp
@@ -19,14 +19,12 @@
 
 =========================================================================*/
 
-#include "imstkMeshIO.h"
-#include "imstkTetrahedralMesh.h"
+#include "bandwidth.h"
 #include "imstkGeometryUtilities.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkLogger.h"
-#include "bandwidth.h"
-
-#include <thread>
+#include "imstkMeshIO.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTetrahedralMesh.h"
 
 using namespace imstk;
 
@@ -44,9 +42,8 @@ void testRCM(const std::vector<ElemConn>& conn, const size_t numVerts);
 int
 main(int argc, char** argv)
 {
-    Logger& logger = Logger::getInstance();
-    logger.addFileSink("rcm-Example1", "./");
-    logger.addStdoutSink();
+    // Log to stdout and file
+    Logger::startLogger();
 
     // a 2D Cartesian mesh
     {
@@ -56,7 +53,7 @@ main(int argc, char** argv)
 
     // 3D mesh
     {
-        auto       tetMesh  = std::dynamic_pointer_cast<TetrahedralMesh>(MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg"));
+        auto       tetMesh  = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
         const auto numVerts = tetMesh->getNumVertices();
         std::cout << "Number of vertices = " << numVerts << std::endl;
         testRCM(tetMesh->getTetrahedraVertices(), numVerts);
@@ -64,7 +61,7 @@ main(int argc, char** argv)
 
     // a surface mesh cover
     {
-        auto surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj"));
+        auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
         auto tetMesh  = GeometryUtils::createTetrahedralMeshCover(surfMesh, 80, 40, 60);
         auto conn     = tetMesh->getTetrahedraVertices();
         auto numVerts = tetMesh->getNumVertices();
diff --git a/Examples/RCM/bandwidth.h b/Examples/RCM/bandwidth.h
index 3ddf6f1ed76733c427550bf7c88be31f745e5d99..52a1a7d2e0a01a7e0ee88447bbfc8b8bcf95ae9c 100644
--- a/Examples/RCM/bandwidth.h
+++ b/Examples/RCM/bandwidth.h
@@ -1,3 +1,29 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include <vector>
+#include <unordered_set>
+
 ///
 /// \brief Build the vertex-to-vertex connectivity of a map
 //
diff --git a/Examples/ReducedFEM/ReducedFEM.cpp b/Examples/ReducedFEM/ReducedFEM.cpp
index 5f8c9bfea57234fb6bf4274634e4df150266ec9e..4192ca9f1588ec591875cd89bd534a94ca965dca 100644
--- a/Examples/ReducedFEM/ReducedFEM.cpp
+++ b/Examples/ReducedFEM/ReducedFEM.cpp
@@ -19,111 +19,171 @@
 
 =========================================================================*/
 
-#include "imstkTimer.h"
-#include "imstkSimulationManager.h"
-#include "imstkDeformableObject.h"
+#include "imstkFeDeformableObject.h"
+#include "imstkRenderMaterial.h"
 #include "imstkBackwardEuler.h"
-#include "imstkNonLinearSystem.h"
-#include "imstkNewtonSolver.h"
-#include "imstkGaussSeidel.h"
 #include "imstkPlane.h"
 #include "imstkTetrahedralMesh.h"
 #include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkOneToOneMap.h"
-#include "imstkAPIUtilities.h"
-#include "imstkConjugateGradient.h"
 #include "imstkLight.h"
 #include "imstkCamera.h"
 #include "imstkReducedStVKBodyModel.h"
 #include "imstkReducedFeDeformableObject.h"
-#include "imstkCollisionGraph.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
+#include "imstkKeyboardSceneControl.h"
 
 using namespace imstk;
 
+std::shared_ptr<DynamicObject> createAndAddFEDeformable(std::shared_ptr<Scene> scene, std::shared_ptr<TetrahedralMesh> tetMesh);
+
+// enum to choose difference cases, currently asianDragon or heart
+enum Geom
+{
+    Dragon = 0,
+    Heart
+};
+
+struct Input
+{
+    std::string meshFileName;
+    std::string cubFileName;
+    std::string modesFileName;
+};
+
+Geom geom = Dragon;
+// const Geom geom = Heart;
+Input input;
+
 ///
 /// \brief This example demonstrates the soft body simulation
-/// using Finite elements
+/// using model order reduction (NOR)
 ///
 int
 main()
 {
-    // simManager and Scene
-    auto simConfig = std::make_shared<SimManagerConfig>();
-    simConfig->simulationMode = SimulationMode::Rendering;
-    auto simManager = std::make_shared<SimulationManager>(simConfig);
-    auto scene      = simManager->createNewScene("DeformableBodyFEM");
-    scene->getCamera()->setPosition(0, 2.0, 15.0);
-
-    // Load a tetrahedral mesh
-    // auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
-    auto tetMesh = MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    if (geom == Dragon)
+    {
+        input.meshFileName  = iMSTK_DATA_ROOT "asianDragon/asianDragon.veg";
+        input.cubFileName   = iMSTK_DATA_ROOT "asianDragon/asianDragon.cub";
+        input.modesFileName = iMSTK_DATA_ROOT "asianDragon/asianDragon.URendering.float";
+    }
+    else if (geom == Heart)
+    {
+        input.meshFileName  = iMSTK_DATA_ROOT "/heart/heart.veg";
+        input.cubFileName   = iMSTK_DATA_ROOT "heart/heart.cub";
+        input.modesFileName = iMSTK_DATA_ROOT "heart/heart.URendering.float";
+    }
+
+    // Construct the scene
+    imstkNew<SceneConfig> sceneConfig;
+    sceneConfig->taskParallelizationEnabled = false;
+    imstkNew<Scene> scene("ReducedFEM", sceneConfig);
+
+    {
+        std::shared_ptr<Camera> cam = scene->getActiveCamera();
+        cam->setPosition(0.0, 2.0, -25.0);
+        cam->setFocalPoint(0.0, 0.0, 0.0);
+
+        // Load a tetrahedral mesh
+        auto tetMesh = MeshIO::read<TetrahedralMesh>(input.meshFileName);
+        CHECK(tetMesh != nullptr) << "Could not read mesh from file.";
+
+        // Scene object 1: fe-FeDeformableObject
+        std::shared_ptr<DynamicObject> deformableObj = createAndAddFEDeformable(scene, tetMesh);
+
+        // Scene object 2: Plane
+        imstkNew<Plane> planeGeom;
+        planeGeom->setWidth(40);
+        planeGeom->setPosition(0, -6, 0);
+        imstkNew<CollidingObject> planeObj("Plane");
+        planeObj->setVisualGeometry(planeGeom);
+        planeObj->setCollidingGeometry(planeGeom);
+        scene->addSceneObject(planeObj);
+
+        // Light
+        imstkNew<DirectionalLight> light("light");
+        light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+        light->setIntensity(1);
+        scene->addLight(light);
+    }
 
-    CHECK(tetMesh != nullptr) << "Could not read mesh from file.";
-
-    // Extract the surface mesh
-    auto surfMesh   = std::make_shared<SurfaceMesh>();
-    auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh);
-
-    CHECK(volTetMesh != nullptr) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!";
-
-    volTetMesh->extractSurfaceMesh(surfMesh, true);
-
-    // Construct a map
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer 1");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager 1");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
-    // Construct one to one nodal map based on the above meshes
-    auto oneToOneNodalMap = std::make_shared<OneToOneMap>(tetMesh, surfMesh);
+    return 0;
+}
 
-    // Scene object 1: Dragon
+std::shared_ptr<DynamicObject>
+createAndAddFEDeformable(std::shared_ptr<Scene>           scene,
+                         std::shared_ptr<TetrahedralMesh> tetMesh)
+{
+    imstkNew<SurfaceMesh> surfMesh;
+    tetMesh->extractSurfaceMesh(surfMesh, true);
 
     // Configure dynamic model
-    auto dynaModel = std::make_shared<ReducedStVK>();
-
-    //dynaModel->configure(iMSTK_DATA_ROOT "/asianDragon/asianDragon.config");
-
-    auto config = std::make_shared<ReducedStVKConfig>();
-    // config->m_fixedNodeIds = { 51, 127, 178 };
-    config->m_cubicPolynomialFilename = iMSTK_DATA_ROOT "/asianDragon/asianDragon.cub";
-    config->m_modesFileName = iMSTK_DATA_ROOT "/asianDragon/asianDragon.URendering.float";
+    imstkNew<ReducedStVK>       dynaModel;
+    imstkNew<ReducedStVKConfig> config;
+    config->m_cubicPolynomialFilename = input.cubFileName;
+    config->m_modesFileName = input.modesFileName;
     dynaModel->configure(config);
+    //dynaModel->configure(iMSTK_DATA_ROOT "/asianDragon/asianDragon.config");
 
     dynaModel->setTimeStepSizeType(TimeSteppingType::Fixed);
-    dynaModel->setModelGeometry(volTetMesh);
-    auto timeIntegrator = std::make_shared<BackwardEuler>(0.01);// Create and add Backward Euler time integrator
+    dynaModel->setModelGeometry(tetMesh);
+    imstkNew<BackwardEuler> timeIntegrator(0.01); // Create and add Backward Euler time integrator
     dynaModel->setTimeIntegrator(timeIntegrator);
 
-    auto material = std::make_shared<RenderMaterial>();
-    material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    auto surfMeshModel = std::make_shared<VisualModel>(surfMesh);
-    surfMeshModel->setRenderMaterial(material);
+    imstkNew<RenderMaterial> mat;
+    mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+    mat->setPointSize(10.);
+    mat->setLineWidth(4.);
+    mat->setEdgeColor(Color::Orange);
+    imstkNew<VisualModel> surfMeshModel(surfMesh.get());
+    surfMeshModel->setRenderMaterial(mat);
 
-    // Scene Object
-    auto deformableObj = std::make_shared<ReducedFeDeformableObject>("Dragon");
+    // Scene object 1: Dragon
+    imstkNew<ReducedFeDeformableObject> deformableObj("Dragon");
     deformableObj->addVisualModel(surfMeshModel);
-    deformableObj->setPhysicsGeometry(volTetMesh);
-    deformableObj->setPhysicsToVisualMap(oneToOneNodalMap); //assign the computed map
+    deformableObj->setPhysicsGeometry(tetMesh);
+    // Map simulated geometry to visual
+    deformableObj->setPhysicsToVisualMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh));
     deformableObj->setDynamicalModel(dynaModel);
     scene->addSceneObject(deformableObj);
 
-    // Scene object 2: Plane
-    auto planeGeom = std::make_shared<Plane>();
-    planeGeom->setWidth(40);
-    planeGeom->setPosition(0, -6, 0);
-    auto planeObj = std::make_shared<CollidingObject>("Plane");
-    planeObj->setVisualGeometry(planeGeom);
-    planeObj->setCollidingGeometry(planeGeom);
-    scene->addSceneObject(planeObj);
-
-    // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
-    scene->addLight(light);
-
-    // Run the simulation
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
-
-    return 0;
+    return deformableObj;
 }
diff --git a/Examples/Rendering/RenderingExample.cpp b/Examples/Rendering/RenderingExample.cpp
index cf9dcf2a0d03bde879b8a8ffbb74805c562ded8d..4d3b7d2fc65e65783050173d5d99e0213e455a39 100644
--- a/Examples/Rendering/RenderingExample.cpp
+++ b/Examples/Rendering/RenderingExample.cpp
@@ -19,14 +19,21 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
 #include "imstkAPIUtilities.h"
-#include "imstkVisualObjectImporter.h"
-#include "imstkIBLProbe.h"
 #include "imstkCamera.h"
-#include "imstkMeshIO.h"
+#include "imstkIBLProbe.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObject.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -37,105 +44,127 @@ using namespace imstk;
 int
 main()
 {
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("Rendering");
-
-    // Add IBL Probe
-    auto globalIBLProbe = std::make_shared<IBLProbe>(
-        iMSTK_DATA_ROOT "/IBL/roomIrradiance.dds",
-        iMSTK_DATA_ROOT "/IBL/roomRadiance.dds",
-        iMSTK_DATA_ROOT "/IBL/roomBRDF.png");
-    scene->setGlobalIBLProbe(globalIBLProbe);
-
-    // Head mesh
+    imstkNew<Scene> scene("Rendering");
+    {
+        // Add IBL Probe
+        imstkNew<IBLProbe> globalIBLProbe(
+            iMSTK_DATA_ROOT "/IBL/roomIrradiance.dds",
+            iMSTK_DATA_ROOT "/IBL/roomRadiance.dds",
+            iMSTK_DATA_ROOT "/IBL/roomBRDF.png");
+        scene->setGlobalIBLProbe(globalIBLProbe);
+
+        // Head mesh
 #ifdef iMSTK_USE_Vulkan
-    auto headObject = VisualObjectImporter::importVisualObject(
-        "head", iMSTK_DATA_ROOT "/head/head_revised.obj",
-        iMSTK_DATA_ROOT "/head/", 1, Vec3d(0, 0, 0), "dds");
+        auto headObject = VisualObjectImporter::importVisualObject(
+            "head", iMSTK_DATA_ROOT "/head/head_revised.obj",
+            iMSTK_DATA_ROOT "/head/", 1, Vec3d(0, 0, 0), "dds");
 #else
-    /*auto headObject = VisualObjectImporter::importVisualObject(
-        "head",
-        iMSTK_DATA_ROOT "/head/head_revised.obj",
-        iMSTK_DATA_ROOT "/head/");*/
-
-    auto surfaceMesh = MeshIO::read(iMSTK_DATA_ROOT "/head/head_revised.obj");
-
-    auto material = std::make_shared<RenderMaterial>();
-    material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
-    material->setShadingModel(RenderMaterial::ShadingModel::PBR);
-    auto headDiffuseTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_BaseColor.png", Texture::Type::Diffuse);
-    auto headNormalTexture  = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_Normal.png", Texture::Type::Normal);
-    auto headAoTexture      = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_AO.png", Texture::Type::AmbientOcclusion);
-
-    material->addTexture(headDiffuseTexture);
-    material->addTexture(headNormalTexture);
-    material->addTexture(headAoTexture);
-
-    auto surfMeshModel = std::make_shared<VisualModel>(surfaceMesh);
-    surfMeshModel->setRenderMaterial(material);
-
-    auto headObject = std::make_shared<VisualObject>("head");
-    headObject->addVisualModel(surfMeshModel);
-
-    // Head material with textures
-    /* auto headNormalTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_Normal.jpg", Texture::Type::Normal);
-     auto headDiffuseTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_BaseColor.jpg", Texture::Type::Diffuse);
-     auto headMaterial      = headObject->getVisualModel()->getRenderMaterial();
-     headMaterial->setShadingModel(RenderMaterial::ShadingModel::PBR);
-     headMaterial->addTexture(headNormalTexture);
-     headMaterial->addTexture(headDiffuseTexture);*/
-
-    //headMaterial->addTexture(headDiffuseTexture);
+        /*auto headObject = VisualObjectImporter::importVisualObject(
+            "head",
+            iMSTK_DATA_ROOT "/head/head_revised.obj",
+            iMSTK_DATA_ROOT "/head/");*/
+
+        auto surfaceMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/head/head_revised.obj");
+
+        imstkNew<RenderMaterial> material;
+        material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+        material->setShadingModel(RenderMaterial::ShadingModel::PBR);
+        imstkNew<Texture> headDiffuseTexture(iMSTK_DATA_ROOT "head/HeadTexture_BaseColor.png", Texture::Type::Diffuse);
+        imstkNew<Texture> headNormalTexture(iMSTK_DATA_ROOT "head/HeadTexture_Normal.png", Texture::Type::Normal);
+        imstkNew<Texture> headAoTexture(iMSTK_DATA_ROOT "head/HeadTexture_AO.png", Texture::Type::AmbientOcclusion);
+
+        material->addTexture(headDiffuseTexture);
+        material->addTexture(headNormalTexture);
+        material->addTexture(headAoTexture);
+
+        imstkNew<VisualModel> surfMeshModel(surfaceMesh);
+        surfMeshModel->setRenderMaterial(material);
+
+        imstkNew<VisualObject> headObject("head");
+        headObject->addVisualModel(surfMeshModel);
+
+        // Head material with textures
+        /* auto headNormalTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_Normal.jpg", Texture::Type::Normal);
+         auto headDiffuseTexture = std::make_shared<Texture>(iMSTK_DATA_ROOT "head/HeadTexture_BaseColor.jpg", Texture::Type::Diffuse);
+         auto headMaterial      = headObject->getVisualModel()->getRenderMaterial();
+         headMaterial->setShadingModel(RenderMaterial::ShadingModel::PBR);
+         headMaterial->addTexture(headNormalTexture);
+         headMaterial->addTexture(headDiffuseTexture);*/
+
+        //headMaterial->addTexture(headDiffuseTexture);
 #endif
 
-    scene->addSceneObject(headObject);
+        scene->addSceneObject(headObject);
 
-    // Position camera
-    auto cam = scene->getCamera();
-    cam->setPosition(0, 0.25, 0.6);
-    cam->setFocalPoint(0, 0.25, 0);
+        // Position camera
+        scene->getActiveCamera()->setPosition(0.0, 0.25, 0.6);
+        scene->getActiveCamera()->setFocalPoint(0.0, 0.25, 0.0);
 
-    // Lights
-    auto directionalLight = std::make_shared<DirectionalLight>("DirectionalLight");
-    directionalLight->setIntensity(4);
-    directionalLight->setColor(Color(1.0, 0.95, 0.8));
-    directionalLight->setCastsShadow(true);
-    directionalLight->setShadowRange(1.5);
-    scene->addLight(directionalLight);
+        // Lights
+        imstkNew<DirectionalLight> dirLight("DirectionalLight");
+        dirLight->setIntensity(4.0);
+        dirLight->setColor(Color(1.0, 0.95, 0.8));
+        dirLight->setCastsShadow(true);
+        dirLight->setShadowRange(1.5);
+        scene->addLight(dirLight);
 
-    auto pointLight = std::make_shared<PointLight>("PointLight");
-    pointLight->setIntensity(0.1);
-    pointLight->setPosition(0.1, 0.2, 0.5);
-    scene->addLight(pointLight);
+        imstkNew<PointLight> pointLight("PointLight");
+        pointLight->setIntensity(0.1);
+        pointLight->setPosition(0.1, 0.2, 0.5);
+        scene->addLight(pointLight);
 
 #ifdef iMSTK_USE_Vulkan
-    // Sphere
-    auto sphereObj      = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Sphere, scene, "VisualSphere", 0.025);
-    auto sphereMaterial = std::make_shared<RenderMaterial>();
-    auto sphereMesh     = sphereObj->getVisualGeometry();
-    sphereMesh->translate(0.1, 0.2, 0.5);
-    sphereMaterial->setEmissivity(2);
-    sphereMaterial->setCastsShadows(false);
-    sphereObj->getVisualModel(0)->setRenderMaterial(sphereMaterial);
+        // Sphere
+        auto                     sphereObj = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Sphere, scene, "VisualSphere", 0.025);
+        imstkNew<RenderMaterial> sphereMaterial;
+        auto                     sphereMesh = sphereObj->getVisualGeometry();
+        sphereMesh->translate(0.1, 0.2, 0.5);
+        sphereMaterial->setEmissivity(2);
+        sphereMaterial->setCastsShadows(false);
+        sphereObj->getVisualModel(0)->setRenderMaterial(sphereMaterial);
 #endif
 
-    // Plane
-    auto planeObj      = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Plane, scene, "VisualPlane", 10);
-    auto planeMaterial = std::make_shared<RenderMaterial>();
-    planeMaterial->setColor(Color::LightGray);
-    planeObj->getVisualModel(0)->setRenderMaterial(planeMaterial);
+        // Plane
+        auto                     planeObj = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Plane, scene, "VisualPlane", 10);
+        imstkNew<RenderMaterial> planeMaterial;
+        planeMaterial->setColor(Color::LightGray);
+        planeObj->getVisualModel(0)->setRenderMaterial(planeMaterial);
 
 #ifdef iMSTK_USE_Vulkan
-    auto viewer = std::dynamic_pointer_cast<VulkanViewer>(simManager->getViewer());
-    viewer->setResolution(1000, 800);
-    viewer->disableVSync();
-    //viewer->enableFullscreen();
+        auto viewer = std::dynamic_pointer_cast<VulkanViewer>(simManager->getViewer());
+        viewer->setResolution(1000, 800);
+        viewer->disableVSync();
+        //viewer->enableFullscreen();
 #endif
-
-    // Run
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp b/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp
index 44c07c071ce9086dda1d72b8a90c7f8310a129a6..7dec42133fbf8fe747ba3d000d846cb208112311 100644
--- a/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp
+++ b/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp
@@ -19,47 +19,48 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkCollisionGraph.h"
-#include "imstkRigidObject.h"
-#include "imstkRigidBodyModel.h"
-#include "imstkSceneObject.h"
-#include "imstkTetrahedralMesh.h"
-#include "imstkLight.h"
 #include "imstkCamera.h"
 #include "imstkCube.h"
-#include "imstkPlane.h"
-#include "imstkSphere.h"
-#include "imstkMeshIO.h"
 #include "imstkIsometricMap.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkPlane.h"
+#include "imstkRenderMaterial.h"
+#include "imstkRigidBodyModel.h"
+#include "imstkRigidObject.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSphere.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTetrahedralMesh.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
 std::shared_ptr<imstk::RigidObject>
-addMeshRigidObject(const std::string& name, std::shared_ptr<Scene> scene, Vec3d pos)
+makeMeshRigidObject(const std::string& name, const Vec3d& pos)
 {
     // create cube object
-    auto meshObj = std::make_shared<RigidObject>(name);
+    imstkNew<RigidObject> meshObj(name);
 
     // Load a tetrahedral mesh
-    auto tetMesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
-
-    CHECK(tetMesh != nullptr) << "Could not read mesh from file.";
+    auto tetMesh = imstk::MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
 
     // Extract the surface mesh
-    auto surfMesh   = std::make_shared<SurfaceMesh>();
-    auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh);
+    imstkNew<SurfaceMesh> surfMesh;
 
-    CHECK(volTetMesh != nullptr) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!";
-
-    volTetMesh->scale(15., Geometry::TransformType::ApplyToData);
-    volTetMesh->translate(pos, Geometry::TransformType::ApplyToData);
-    volTetMesh->extractSurfaceMesh(surfMesh, true);
+    tetMesh->scale(15., Geometry::TransformType::ApplyToData);
+    tetMesh->translate(pos, Geometry::TransformType::ApplyToData);
+    tetMesh->extractSurfaceMesh(surfMesh, true);
 
     // add visual model
-    auto renderModel = std::make_shared<VisualModel>(surfMesh);
-    auto mat = std::make_shared<RenderMaterial>();
+    imstkNew<VisualModel>    renderModel(surfMesh.get());
+    imstkNew<RenderMaterial> mat;
     mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
     mat->setLineWidth(2.);
     mat->setColor(Color::Green);
@@ -67,36 +68,33 @@ addMeshRigidObject(const std::string& name, std::shared_ptr<Scene> scene, Vec3d
     meshObj->addVisualModel(renderModel);
 
     // add dynamic model
-    auto rigidModel = std::make_shared<RigidBodyModel>();
-    auto rigidProp  = std::make_shared<RigidBodyConfig>();
+    imstkNew<RigidBodyModel>  rigidModel;
+    imstkNew<RigidBodyConfig> rigidProp;
     rigidProp->m_rigidBodyType = RigidBodyType::Kinematic;
     rigidModel->configure(rigidProp);
     rigidModel->setModelGeometry(surfMesh);
     meshObj->setPhysicsGeometry(surfMesh);
     meshObj->setDynamicalModel(rigidModel);
 
-    // add cube to scene
-    scene->addSceneObject(meshObj);
     return meshObj;
 }
 
 std::shared_ptr<imstk::RigidObject>
-addCubeRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos, const bool isStatic = false)
+makeCubeRigidObject(std::string& name, const Vec3d& pos, const bool isStatic = false)
 {
-    // create cube object
-    auto cubeObj = std::make_shared<RigidObject>(name);
+    // Create cube object
+    imstkNew<RigidObject> cubeObj(name);
 
-    // Create Cube object
-    auto cubeGeom = std::make_shared<Cube>();
-    cubeGeom->setWidth(20.);
+    // Create cube geometry
+    imstkNew<Cube> cubeGeom;
+    cubeGeom->setWidth(20.0);
     cubeGeom->translate(pos);
 
-    // cube visual model
-    auto mesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
-    auto SurfaceMesh = std::dynamic_pointer_cast<imstk::SurfaceMesh>(mesh);
-    SurfaceMesh->scale(5., Geometry::TransformType::ApplyToData);
-    auto renderModel = std::make_shared<VisualModel>(cubeGeom);
-    auto mat = std::make_shared<RenderMaterial>();
+    // Create cube VisualModel
+    auto mesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
+    mesh->scale(5.0, Geometry::TransformType::ApplyToData);
+    imstkNew<VisualModel>    renderModel(cubeGeom.get());
+    imstkNew<RenderMaterial> mat;
     mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
     mat->setLineWidth(2.);
     mat->setColor(Color::Orange);
@@ -105,11 +103,11 @@ addCubeRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos, c
 
     auto rigidMap = std::make_shared<IsometricMap>();
     rigidMap->setMaster(cubeGeom);
-    rigidMap->setSlave(SurfaceMesh);
+    rigidMap->setSlave(mesh);
 
-    // cube dynamic model
-    auto rigidModel = std::make_shared<RigidBodyModel>();
-    auto rigidProp  = std::make_shared<RigidBodyConfig>();
+    // Create cube DynamicalModel
+    imstkNew<RigidBodyModel>  rigidModel;
+    imstkNew<RigidBodyConfig> rigidProp;
     rigidProp->m_dynamicFriction = 0.01;
     rigidProp->m_restitution     = 0.01;
     rigidProp->m_staticFriction  = 0.005;
@@ -118,93 +116,113 @@ addCubeRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos, c
     rigidModel->setModelGeometry(cubeGeom);
     cubeObj->setDynamicalModel(rigidModel);
 
-    //cubeObj->setPhysicsToVisualMap(rigidMap);
-
-    // add cube to scene
-    scene->addSceneObject(cubeObj);
     return cubeObj;
 }
 
-void
-addPlaneRigidObject(std::shared_ptr<Scene> scene)
+std::shared_ptr<RigidObject>
+makePlaneRigidObject()
 {
     // create plane object
-    auto planeObj = std::make_shared<RigidObject>("Plane");
+    imstkNew<RigidObject> planeObj("Plane");
 
-    auto planeGeom = std::make_shared<Plane>();
-    planeGeom->setWidth(400.);
+    imstkNew<Plane> planeGeom;
+    planeGeom->setWidth(400.0);
 
     // visual model
-    auto renderModel2 = std::make_shared<VisualModel>(planeGeom);
-    renderModel2->setRenderMaterial(std::make_shared<RenderMaterial>());
-    planeObj->addVisualModel(renderModel2);
+    imstkNew<VisualModel> renderModel(planeGeom.get());
+    renderModel->setRenderMaterial(std::make_shared<RenderMaterial>());
+    planeObj->addVisualModel(renderModel);
 
     // dynamic model
-    auto rigidModel2 = std::make_shared<RigidBodyModel>();
-    auto rigidProp2  = std::make_shared<RigidBodyConfig>();
-    rigidModel2->configure(rigidProp2);
-    rigidModel2->setModelGeometry(planeGeom);
-    planeObj->setDynamicalModel(rigidModel2);
+    imstkNew<RigidBodyModel>  rigidModel;
+    imstkNew<RigidBodyConfig> rigidProp;
+    rigidModel->configure(rigidProp);
+    rigidModel->setModelGeometry(planeGeom);
+    planeObj->setDynamicalModel(rigidModel);
 
-    scene->addSceneObject(planeObj);
+    return planeObj;
 }
 
-void
-addSphereRigidObject(std::shared_ptr<Scene> scene, Vec3d t = Vec3d(0., 0., 0.))
+std::shared_ptr<RigidObject>
+makeSphereRigidObject(const Vec3d& t = Vec3d(0.0, 0.0, 0.0))
 {
     // create cube object
-    auto sphereObj = std::make_shared<RigidObject>("Sphere");
+    imstkNew<RigidObject> sphereObj("Sphere");
 
     // Create Cube object
-    auto sphereGeom = std::make_shared<Sphere>();
-    sphereGeom->setRadius(10.);
+    imstkNew<Sphere> sphereGeom;
+    sphereGeom->setRadius(10.0);
     sphereGeom->translate(t);
 
     // cube visual model
-    auto renderModel = std::make_shared<VisualModel>(sphereGeom);
+    imstkNew<VisualModel> renderModel(sphereGeom.get());
     renderModel->setRenderMaterial(std::make_shared<RenderMaterial>());
     sphereObj->addVisualModel(renderModel);
 
     // cube dynamic model
-    auto rigidModel3 = std::make_shared<RigidBodyModel>();
-    auto rigidProp   = std::make_shared<RigidBodyConfig>();
+    imstkNew<RigidBodyModel>  rigidModel;
+    imstkNew<RigidBodyConfig> rigidProp;
     rigidProp->m_rigidBodyType = RigidBodyType::Dynamic;
-    rigidModel3->configure(rigidProp);
-    rigidModel3->setModelGeometry(sphereGeom);
-    sphereObj->setDynamicalModel(rigidModel3);
+    rigidModel->configure(rigidProp);
+    rigidModel->setModelGeometry(sphereGeom);
+    sphereObj->setDynamicalModel(rigidModel);
 
-    // add cube to scene
-    scene->addSceneObject(sphereObj);
+    return sphereObj;
 }
 
 int
 main()
 {
-    //simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("Rigid Body Dynamics");
+    // Write log to stdout and file
+    Logger::startLogger();
 
-    for (int i = 0; i < 1; ++i)
+    imstkNew<Scene> scene("Rigid Body Dynamics");
     {
-        addCubeRigidObject(std::string("cube_").append(std::to_string(i)), scene, Vec3d(0., 150. + i * 21, 0.));
+        for (int i = 0; i < 1; i++)
+        {
+            scene->addSceneObject(makeCubeRigidObject(std::string("cube_").append(std::to_string(i)), Vec3d(0.0, 150.0 + i * 21.0, 0.0)));
+        }
+
+        scene->addSceneObject(makePlaneRigidObject());
+        scene->addSceneObject(makeSphereRigidObject(Vec3d(0.0, 200.0, 0.0)));
+        scene->addSceneObject(makeMeshRigidObject(std::string("dragon"), Vec3d(0.0, 30.0, 0.0)));
+
+        // Set Camera configuration
+        scene->getActiveCamera()->setPosition(Vec3d(300.0, 300.0, 300.0));
+
+        // Light
+        imstkNew<DirectionalLight> light("light");
+        light->setIntensity(1.0);
+        scene->addLight(light);
     }
 
-    addPlaneRigidObject(scene);
-    addSphereRigidObject(scene, Vec3d(0., 200, 0.));
-    auto rigidObj = addMeshRigidObject(std::string("dragon"), scene, Vec3d(0., 30., 0.));
-
-    // Set Camera configuration
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(300, 300, 300));
-
-    // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setIntensity(1);
-    scene->addLight(light);
-
-    // Run
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/RigidBodyDynamics2/CMakeLists.txt b/Examples/RigidBodyDynamics2/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5c875c9edcdc43fe62f9b2f6e236847969060c43
--- /dev/null
+++ b/Examples/RigidBodyDynamics2/CMakeLists.txt
@@ -0,0 +1,34 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  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.
+#
+###########################################################################
+
+project(Example-RigidBodyDynamics2)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+imstk_add_executable(${PROJECT_NAME} RigidBodyDynamicsExample2.cpp)
+
+#-----------------------------------------------------------------------------
+# Add the target to Examples folder
+#-----------------------------------------------------------------------------
+SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} SimulationManager Filtering)
diff --git a/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp b/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dce0234dfa7d9aeeec9ef0fd0cfc53ae28d4fae6
--- /dev/null
+++ b/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp
@@ -0,0 +1,237 @@
+/*=========================================================================
+
+   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 "imstkCamera.h"
+#include "imstkCollisionGraph.h"
+#include "imstkCompositeImplicitGeometry.h"
+#include "imstkCube.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkImplicitGeometryToImageData.h"
+#include "imstkKeyboardDeviceClient.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkPlane.h"
+#include "imstkRbdConstraint.h"
+#include "imstkRenderMaterial.h"
+#include "imstkRigidBodyCH.h"
+#include "imstkRigidBodyModel2.h"
+#include "imstkRigidObject2.h"
+#include "imstkRigidObjectCollisionPair.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSphere.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkSurfaceMeshFlyingEdges.h"
+#include "imstkSurfaceMeshSubdivide.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
+
+using namespace imstk;
+using namespace imstk::expiremental;
+
+///
+/// \brief This example demonstrates a rigid body model. The rigid body model uses
+/// an implicit model to solve all bodies together. This means they all share a model.
+/// Also implements key controls in a lambda
+///
+int
+main()
+{
+    // Write log to stdout and file
+    Logger::startLogger();
+
+    imstkNew<Scene>        scene("Rigid Body Dynamics");
+    imstkNew<RigidObject2> cubeObj("Cube");
+    {
+        // This model is shared among interacting rigid bodies
+        imstkNew<RigidBodyModel2> rbdModel;
+        rbdModel->getConfig()->m_dt = 0.005;
+        rbdModel->getConfig()->m_maxNumIterations = 20;
+
+        // Create the first rbd, plane floor
+        imstkNew<RigidObject2> planeObj("Plane");
+        {
+            // Subtract the sphere from the plane to make a crater
+            imstkNew<Plane> planeGeom;
+            planeGeom->setWidth(40.0);
+            imstkNew<Sphere> sphereGeom;
+            sphereGeom->setRadius(25.0);
+            sphereGeom->setPosition(0.0, 10.0, 0.0);
+            imstkNew<CompositeImplicitGeometry> compGeom;
+            compGeom->addImplicitGeometry(planeGeom, CompositeImplicitGeometry::GeometryBoolType::Union);
+            compGeom->addImplicitGeometry(sphereGeom, CompositeImplicitGeometry::GeometryBoolType::Difference);
+
+            // Rasterize the SDF into an image
+            imstkNew<ImplicitGeometryToImageData> toImage;
+            toImage->setInputGeometry(compGeom);
+            Vec6d bounds;
+            bounds[0] = -20.0;
+            bounds[1] = 20.0;
+            bounds[2] = -20.0;
+            bounds[3] = 20.0;
+            bounds[4] = -20.0;
+            bounds[5] = 20.0;
+            toImage->setBounds(bounds);
+            toImage->setDimensions(Vec3i(80, 80, 80));
+            toImage->update();
+
+            // Extract surface
+            imstkNew<SurfaceMeshFlyingEdges> toSurfMesh;
+            toSurfMesh->setInputImage(toImage->getOutputImage());
+            toSurfMesh->update();
+
+            // Create the visual model
+            imstkNew<VisualModel> visualModel(toSurfMesh->getOutputMesh());
+
+            // Create the object
+            planeObj->addVisualModel(visualModel);
+            planeObj->setPhysicsGeometry(compGeom);
+            planeObj->setCollidingGeometry(compGeom);
+            planeObj->setDynamicalModel(rbdModel);
+            planeObj->getRigidBody()->m_isStatic = true;
+            planeObj->getRigidBody()->m_mass     = 100.0;
+
+            scene->addSceneObject(planeObj);
+        }
+
+        // Create surface mesh cube (so we can use pointset for point->implicit collision)
+        {
+            imstkNew<Cube> cubeGeom;
+            cubeGeom->setWidth(4.0);
+            std::shared_ptr<SurfaceMesh> surfMesh = GeometryUtils::toCubeSurfaceMesh(cubeGeom);
+
+            imstkNew<SurfaceMeshSubdivide> subdivide;
+            subdivide->setInputMesh(surfMesh);
+            subdivide->setNumberOfSubdivisions(1);
+            subdivide->update();
+
+            // Create the visual model
+            imstkNew<VisualModel>    visualModel(subdivide->getOutputMesh());
+            imstkNew<RenderMaterial> mat;
+            mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+            mat->setLineWidth(2.0);
+            mat->setColor(Color::Orange);
+            visualModel->setRenderMaterial(mat);
+
+            // Create the cube rigid object
+            cubeObj->setDynamicalModel(rbdModel);
+            cubeObj->setPhysicsGeometry(subdivide->getOutputMesh());
+            cubeObj->setCollidingGeometry(subdivide->getOutputMesh());
+            cubeObj->addVisualModel(visualModel);
+            cubeObj->getRigidBody()->m_mass    = 100.0;
+            cubeObj->getRigidBody()->m_initPos = Vec3d(0.0, 8.0, 0.0);
+            cubeObj->getRigidBody()->m_initOrientation = Quatd(Rotd(0.4, Vec3d(1.0, 0.0, 0.0)));
+            cubeObj->getRigidBody()->setInertiaFromPointSet(subdivide->getOutputMesh(), 0.001, true);
+
+            scene->addSceneObject(cubeObj);
+        }
+
+        auto rbdInteraction = std::make_shared<RigidObjectCollisionPair>(cubeObj, planeObj, CollisionDetection::Type::PointSetToImplicit);
+        std::dynamic_pointer_cast<RigidBodyCH>(rbdInteraction->getCollisionHandlingA())->setUseFriction(false);
+        scene->getCollisionGraph()->addInteraction(rbdInteraction);
+        scene->getActiveCamera()->setPosition(0.0, 40.0, 40.0);
+
+        // Light
+        imstkNew<DirectionalLight> light("light");
+        light->setIntensity(1.0);
+        scene->addLight(light);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        LOG(INFO) << "Cube Controls:";
+        LOG(INFO) << "----------------------------------------------------------------------";
+        LOG(INFO) << " | i - forward movement";
+        LOG(INFO) << " | j - left movement";
+        LOG(INFO) << " | l - right movement";
+        LOG(INFO) << " | k - backwards movement";
+        LOG(INFO) << " | u - rotate left";
+        LOG(INFO) << " | o - rotate right";
+
+        // Not perfectly thread safe movement lambda, ijkl movement instead of wasd because d is already used
+        std::shared_ptr<KeyboardDeviceClient> keyDevice = viewer->getKeyboardDevice();
+        const Vec3d                           dx = scene->getActiveCamera()->getPosition() - scene->getActiveCamera()->getFocalPoint();
+        connect<Event>(sceneManager, EventType::PreUpdate, [&](Event*)
+        {
+            Vec3d extForce  = Vec3d(0.0, 0.0, 0.0);
+            Vec3d extTorque = Vec3d(0.0, 0.0, 0.0);
+            // If w down, move forward
+            if (keyDevice->getButton('i') == KEY_PRESS)
+            {
+                extForce += Vec3d(0.0, 0.0, -40.0);
+            }
+            if (keyDevice->getButton('k') == KEY_PRESS)
+            {
+                extForce += Vec3d(0.0, 0.0, 40.0);
+            }
+            if (keyDevice->getButton('j') == KEY_PRESS)
+            {
+                extForce += Vec3d(-40.0, 0.0, 0.0);
+            }
+            if (keyDevice->getButton('l') == KEY_PRESS)
+            {
+                extForce += Vec3d(40.0, 0.0, 0.0);
+            }
+            if (keyDevice->getButton('u') == KEY_PRESS)
+            {
+                extTorque += Vec3d(0.0, 1.5, 0.0);
+            }
+            if (keyDevice->getButton('o') == KEY_PRESS)
+            {
+                extTorque += Vec3d(0.0, -1.5, 0.0);
+            }
+            *cubeObj->getRigidBody()->m_force  = extForce;
+            *cubeObj->getRigidBody()->m_torque = extTorque;
+            scene->getActiveCamera()->setFocalPoint(cubeObj->getRigidBody()->getPosition());
+            scene->getActiveCamera()->setPosition(cubeObj->getRigidBody()->getPosition() + dx);
+            });
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
+
+    return 0;
+}
diff --git a/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp b/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp
index ee7b4dbdd6b0c041a06dbb75009e51b438235827..ed6df35219da121c25c5dd32e838fb06fb7114e3 100644
--- a/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp
+++ b/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp
@@ -19,28 +19,29 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkSceneManager.h"
-#include "imstkSceneObject.h"
-#include "imstkTetrahedralMesh.h"
-#include "imstkSimulationManager.h"
-#include "imstkVirtualCouplingCH.h"
-#include "imstkHDAPIDeviceServer.h"
-#include "imstkHDAPIDeviceClient.h"
-#include "imstkSceneObjectController.h"
-#include "imstkPlane.h"
-#include "imstkSphere.h"
-#include "imstkRigidObject.h"
-#include "imstkRigidBodyModel.h"
-#include "imstkMeshIO.h"
+#include "imstkCamera.h"
 #include "imstkCube.h"
+#include "imstkHapticDeviceClient.h"
+#include "imstkHapticDeviceManager.h"
 #include "imstkIsometricMap.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
-#include "imstkCamera.h"
+#include "imstkLogger.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkPlane.h"
+#include "imstkRenderMaterial.h"
 #include "imstkRigidBodyModel.h"
-#include "imstkCollisionGraph.h"
-#include "imstkDeviceTracker.h"
+#include "imstkRigidObject.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObjectController.h"
+#include "imstkSphere.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTetrahedralMesh.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 // global variables
 const std::string phantomOmni1Name = "Default Device";
@@ -48,226 +49,237 @@ const std::string phantomOmni1Name = "Default Device";
 using namespace imstk;
 
 std::shared_ptr<imstk::RigidObject>
-addMeshRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos)
+makeMeshRigidObject(const std::string& name, const Vec3d& pos)
 {
     // create cube object
-    auto meshObj = std::make_shared<RigidObject>(name);
+    imstkNew<RigidObject> meshObj("name");
 
     // Load a tetrahedral mesh
-    auto tetMesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
     if (!tetMesh)
     {
         LOG(FATAL) << "Could not read mesh from file.";
     }
 
     // Extract the surface mesh
-    auto surfMesh   = std::make_shared<SurfaceMesh>();
-    auto volTetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(tetMesh);
-    if (!volTetMesh)
-    {
-        LOG(FATAL) << "Dynamic pointer cast from PointSet to TetrahedralMesh failed!";
-    }
-    volTetMesh->scale(15., Geometry::TransformType::ApplyToData);
-    volTetMesh->translate(pos, Geometry::TransformType::ApplyToData);
-    volTetMesh->extractSurfaceMesh(surfMesh, true);
-
-    // add visual model
-    auto renderModel = std::make_shared<VisualModel>(surfMesh);
-    auto mat = std::make_shared<RenderMaterial>();
-    mat->setDisplayMode(RenderMaterial::WireframeSurface);
-    mat->setLineWidth(2.);
+    imstkNew<SurfaceMesh> surfMesh;
+    tetMesh->scale(15.0, Geometry::TransformType::ApplyToData);
+    tetMesh->translate(pos, Geometry::TransformType::ApplyToData);
+    tetMesh->extractSurfaceMesh(surfMesh, true);
+
+    // Add visual model
+    imstkNew<VisualModel>    renderModel(surfMesh.get());
+    imstkNew<RenderMaterial> mat;
+    mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+    mat->setLineWidth(2.0);
     mat->setColor(Color::Green);
     renderModel->setRenderMaterial(mat);
     meshObj->addVisualModel(renderModel);
 
     // add dynamic model
-    auto rigidModel = std::make_shared<RigidBodyModel>();
-    auto rigidProp  = std::make_shared<RigidBodyConfig>();
-    rigidProp->m_rigidBodyType = RigidBodyType::Kinematic;
-    rigidModel->configure(rigidProp);
+    imstkNew<RigidBodyModel>  rigidModel;
+    imstkNew<RigidBodyConfig> rigidConfig;
+    rigidConfig->m_rigidBodyType = RigidBodyType::Kinematic;
+    rigidModel->configure(rigidConfig);
     rigidModel->setModelGeometry(surfMesh);
     meshObj->setPhysicsGeometry(surfMesh);
     meshObj->setDynamicalModel(rigidModel);
 
-    // add cube to scene
-    scene->addSceneObject(meshObj);
     return meshObj;
 }
 
 std::shared_ptr<imstk::RigidObject>
-addCubeRigidObject(std::string& name, std::shared_ptr<Scene> scene, Vec3d pos, const bool isStatic = false)
+makeCubeRigidObject(const std::string& name, const Vec3d& pos, const bool isStatic)
 {
     // create cube object
-    auto cubeObj = std::make_shared<RigidObject>(name);
+    imstkNew<RigidObject> cubeObj(name);
 
     // Create Cube object
-    auto cubeGeom = std::make_shared<Cube>();
-    cubeGeom->setWidth(20.);
-    cubeGeom->translate(pos);
+    imstkNew<Cube> cubeGeom(pos, 20.0);
 
     // cube visual model
-    auto mesh = imstk::MeshIO::read(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
-    auto SurfaceMesh = std::dynamic_pointer_cast<imstk::SurfaceMesh>(mesh);
-    SurfaceMesh->scale(5., Geometry::TransformType::ApplyToData);
-    auto renderModel = std::make_shared<VisualModel>(cubeGeom);
-    auto mat = std::make_shared<RenderMaterial>();
-    mat->setDisplayMode(RenderMaterial::Surface);
-    mat->setLineWidth(2.);
+    auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
+    surfMesh->scale(5., Geometry::TransformType::ApplyToData);
+    imstkNew<VisualModel>    renderModel(cubeGeom.get());
+    imstkNew<RenderMaterial> mat;
+    mat->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+    mat->setLineWidth(2.0);
     mat->setColor(Color::Orange);
     renderModel->setRenderMaterial(mat);
     cubeObj->addVisualModel(renderModel);
 
-    auto rigidMap = std::make_shared<IsometricMap>();
+    imstkNew<IsometricMap> rigidMap;
     rigidMap->setMaster(cubeGeom);
-    rigidMap->setSlave(SurfaceMesh);
+    rigidMap->setSlave(surfMesh);
 
     // cube dynamic model
-    auto rigidModel = std::make_shared<RigidBodyModel>();
-    auto rigidProp  = std::make_shared<RigidBodyConfig>();
-    rigidProp->m_rigidBodyType = RigidBodyType::Dynamic;
-    rigidModel->configure(rigidProp);
+    imstkNew<RigidBodyModel>  rigidModel;
+    imstkNew<RigidBodyConfig> rigidConfig;
+    rigidConfig->m_rigidBodyType = RigidBodyType::Dynamic;
+    rigidModel->configure(rigidConfig);
     rigidModel->setModelGeometry(cubeGeom);
     cubeObj->setDynamicalModel(rigidModel);
 
     cubeObj->setPhysicsToVisualMap(rigidMap);
 
-    // add cube to scene
-    scene->addSceneObject(cubeObj);
     return cubeObj;
 }
 
-void
-addPlaneRigidObject(std::shared_ptr<Scene> scene)
+std::shared_ptr<RigidObject>
+makePlaneRigidObject(const double width)
 {
     // create plane object
-    auto planeObj = std::make_shared<RigidObject>("Plane");
+    imstkNew<RigidObject> planeObj("Plane");
 
-    auto planeGeom = std::make_shared<Plane>();
-    planeGeom->setWidth(400.);
+    imstkNew<Plane> planeGeom;
+    planeGeom->setWidth(width);
 
     // visual model
-    auto renderModel2 = std::make_shared<VisualModel>(planeGeom);
-    renderModel2->setRenderMaterial(std::make_shared<RenderMaterial>());
-    planeObj->addVisualModel(renderModel2);
+    imstkNew<VisualModel> renderModel(planeGeom.get());
+    renderModel->setRenderMaterial(std::make_shared<RenderMaterial>());
+    planeObj->addVisualModel(renderModel);
 
     // dynamic model
-    auto rigidModel2 = std::make_shared<RigidBodyModel>();
-    auto rigidProp2  = std::make_shared<RigidBodyConfig>();
-    rigidProp2->m_rigidBodyType = RigidBodyType::Static;
-    rigidModel2->configure(rigidProp2);
-    rigidModel2->setModelGeometry(planeGeom);
-    planeObj->setDynamicalModel(rigidModel2);
-
-    scene->addSceneObject(planeObj);
+    imstkNew<RigidBodyModel>  rigidModel;
+    imstkNew<RigidBodyConfig> rigidConfig;
+    rigidConfig->m_rigidBodyType = RigidBodyType::Static;
+    rigidModel->configure(rigidConfig);
+    rigidModel->setModelGeometry(planeGeom);
+    planeObj->setDynamicalModel(rigidModel);
+
+    return planeObj;
 }
 
-void
-addSphereRigidObject(std::shared_ptr<Scene> scene, Vec3d t = Vec3d(0., 0., 0.))
+std::shared_ptr<RigidObject>
+makeSphereRigidObject(const Vec3d& t)
 {
     // create cube object
-    auto sphereObj = std::make_shared<RigidObject>("Sphere");
+    imstkNew<RigidObject> sphereObj("Sphere");
 
     // Create Cube object
-    auto sphereGeom = std::make_shared<Sphere>();
-    sphereGeom->setRadius(10.);
+    imstkNew<Sphere> sphereGeom;
+    sphereGeom->setRadius(10.0);
     sphereGeom->translate(t);
 
     // cube visual model
-    auto renderModel = std::make_shared<VisualModel>(sphereGeom);
+    imstkNew<VisualModel> renderModel(sphereGeom.get());
     renderModel->setRenderMaterial(std::make_shared<RenderMaterial>());
     sphereObj->addVisualModel(renderModel);
 
     // cube dynamic model
-    auto rigidModel3 = std::make_shared<RigidBodyModel>();
-    auto rigidProp   = std::make_shared<RigidBodyConfig>();
-    rigidProp->m_rigidBodyType = RigidBodyType::Dynamic;
-    rigidModel3->configure(rigidProp);
-    rigidModel3->setModelGeometry(sphereGeom);
-    sphereObj->setDynamicalModel(rigidModel3);
-
-    // add cube to scene
-    scene->addSceneObject(sphereObj);
+    imstkNew<RigidBodyModel>  rigidModel;
+    imstkNew<RigidBodyConfig> rigidConfig;
+    rigidConfig->m_rigidBodyType = RigidBodyType::Dynamic;
+    rigidModel->configure(rigidConfig);
+    rigidModel->setModelGeometry(sphereGeom);
+    sphereObj->setDynamicalModel(rigidModel);
+
+    return sphereObj;
 }
 
 int
 main()
 {
-    //simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("Rigid Body Dynamics");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
 
-    auto cubeObj = addCubeRigidObject(std::string("cube"), scene, Vec3d(0., 0., 0.));
+    // Create Scene
+    imstkNew<Scene> scene("ControlRB");
 
-    addPlaneRigidObject(scene);
-    //addSphereRigidObject(scene, Vec3d(0., 200, 0.));
-    auto rigidObj = addMeshRigidObject(std::string("dragon"), scene, Vec3d(0., 30., 0.));
+    std::shared_ptr<RigidObject> cubeObj = makeCubeRigidObject("cube", Vec3d(0.0, 0.0, 0.0), false);
+    scene->addSceneObject(cubeObj);
 
-    //-------------------------------------------------------------
+    std::shared_ptr<RigidObject> planeObj = makePlaneRigidObject(400.0);
+    scene->addSceneObject(planeObj);
+
+    //makeSphereRigidObject(Vec3d(0.0, 200.0, 0..0));
 
-    // Device clients
-    auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name);
+    std::shared_ptr<RigidObject> meshObj = makeMeshRigidObject("dragon", Vec3d(0.0, 30.0, 0.0));
+    scene->addSceneObject(meshObj);
+
+    //-------------------------------------------------------------
 
     // Device Server
-    auto server = std::make_shared<HDAPIDeviceServer>();
-    server->addDeviceClient(client);
-    simManager->addModule(server);
+    imstkNew<HapticDeviceManager>       server;
+    std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name);
 
     // Create a virtual coupling object
-    auto visualGeom = std::make_shared<Sphere>();
-    visualGeom->setRadius(5.);
-    auto obj         = std::make_shared<VisualObject>("VirtualCouplingObject");
-    auto material    = std::make_shared<RenderMaterial>();
-    auto visualModel = std::make_shared<VisualModel>(visualGeom);
+    imstkNew<Sphere>         visualGeom(Vec3d(0.0, 0.0, 0.0), 5.0);
+    imstkNew<VisualObject>   obj("virtualCouplingObject");
+    imstkNew<RenderMaterial> material;
+    imstkNew<VisualModel>    visualModel(visualGeom.get());
     visualModel->setRenderMaterial(material);
     obj->addVisualModel(visualModel);
     scene->addSceneObject(obj);
 
     // Device tracker
-    auto deviceTracker = std::make_shared<DeviceTracker>(client);
-    auto objController = std::make_shared<imstk::SceneObjectController>(obj, deviceTracker);
-    scene->addObjectController(objController);
+    imstkNew<SceneObjectController> controller(obj, client);
+    scene->addController(controller);
 
     //-----------------------------------------------------------------
+    std::shared_ptr<RigidBodyModel> rbdModel = cubeObj->getRigidBodyModel();
 
-    auto rbModel = std::dynamic_pointer_cast<RigidBodyModel>(cubeObj->getDynamicalModel());
-
-    if (!rbModel)
+    if (!rbdModel.get())
     {
-        addCubeRigidObject(std::string("cube"), scene, Vec3d(0., 40., 0.));
+        std::shared_ptr<RigidObject> cubeObj2 = makeCubeRigidObject("cube", Vec3d(0.0, 40.0, 0.0), false);
+        scene->addSceneObject(cubeObj2);
         // throw error
     }
-    auto prevCubePos = rbModel->getModelGeometry()->getTranslation();
-
-    auto forceFunc =
-        [&](Module* module)
-        {
-            auto devPos = deviceTracker->getPosition();
-            auto devQ   = deviceTracker->getRotation();
-            rbModel->getModelGeometry()->rotate(devQ);
-            auto cubeGeo      = std::dynamic_pointer_cast<Cube>(cubeObj->getPhysicsGeometry());
-            auto cubePos      = rbModel->getModelGeometry()->getTranslation();
-            auto cubeVelocity = (cubePos - prevCubePos) / 2;
-            auto damp  = -1000000 * cubeVelocity;
-            auto force = -1000 * (cubePos - devPos) + damp;
-            rbModel->addForce(force, Vec3d(0., 0., 0.));
-            prevCubePos = cubePos;
-        };
-    simManager->getSceneManager(scene)->setPreUpdateCallback(forceFunc);
-
-    //-------------------------------------------------------------------
 
     // Set Camera configuration
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(300, 300, 300));
+    scene->getActiveCamera()->setPosition(Vec3d(300.0, 300.0, 300.0));
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setIntensity(1);
+    imstkNew<DirectionalLight> light("light");
+    light->setIntensity(1.0);
     scene->addLight(light);
 
     // Run
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    //Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer 1");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager 1");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        viewer->addChildThread(server);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        Vec3d prevCubePos = rbdModel->getModelGeometry()->getTranslation();
+        connect<Event>(sceneManager, EventType::PostUpdate,
+            [&](Event*)
+        {
+            const auto devPos = controller->getPosition();
+            const auto devQ   = controller->getRotation();
+            rbdModel->getModelGeometry()->rotate(devQ);
+            auto cubeGeo = std::dynamic_pointer_cast<Cube>(cubeObj->getPhysicsGeometry());
+            const Vec3d cubePos      = rbdModel->getModelGeometry()->getTranslation();
+            const Vec3d cubeVelocity = (cubePos - prevCubePos) / 2.0;
+            const Vec3d damp  = -1000000 * cubeVelocity;
+            const Vec3d force = -1000 * (cubePos - devPos) + damp;
+            rbdModel->addForce(force, Vec3d(0.0, 0.0, 0.0));
+            prevCubePos = cubePos;
+            });
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
\ No newline at end of file
diff --git a/Examples/SPH-FEM-PBD/CMakeLists.txt b/Examples/SPH-FEM-PBD/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ba29ce91b42b06e1fba32118fab4cb9ba38ccefc
--- /dev/null
+++ b/Examples/SPH-FEM-PBD/CMakeLists.txt
@@ -0,0 +1,34 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  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.
+#
+###########################################################################
+
+project(Example-SPH-FEM-PBD)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+imstk_add_executable(${PROJECT_NAME} sphFemPbdExample.cpp)
+
+#-----------------------------------------------------------------------------
+# Add the target to Examples folder
+#-----------------------------------------------------------------------------
+SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} SimulationManager)
diff --git a/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp b/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..22d490fe57830fa3e1cc675f4e825653bb2f6f8b
--- /dev/null
+++ b/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp
@@ -0,0 +1,311 @@
+/*=========================================================================
+
+   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 "imstkBackwardEuler.h"
+#include "imstkCamera.h"
+#include "imstkFeDeformableObject.h"
+#include "imstkFEMDeformableBodyModel.h"
+#include "imstkImageData.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkOneToOneMap.h"
+#include "imstkPbdConstraint.h"
+#include "imstkPbdModel.h"
+#include "imstkPbdObject.h"
+#include "imstkRenderMaterial.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSPHModel.h"
+#include "imstkSPHObject.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTaskGraphVizWriter.h"
+#include "imstkTetrahedralMesh.h"
+#include "imstkTetraTriangleMap.h"
+#include "imstkViewer.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
+
+using namespace imstk;
+
+///
+/// \brief Generate a box-shape fluid object
+/// \param radius of SPH particles/used for spacing
+/// \param center of the SPH fluid box
+/// \param size of the SPH fluid box
+///
+std::shared_ptr<StdVectorOfVec3d>
+generateBoxShapeFluid(const double particleRadius, const Vec3d& boxCenter, const Vec3d& boxSize)
+{
+    double bounds[6] =
+    {
+        boxCenter.x() - boxSize.x() * 0.5,
+        boxCenter.x() + boxSize.x() * 0.5,
+        boxCenter.y() - boxSize.y() * 0.5,
+        boxCenter.y() + boxSize.y() * 0.5,
+        boxCenter.z() - boxSize.z() * 0.5,
+        boxCenter.z() + boxSize.z() * 0.5
+    };
+
+    const double spacing = 2.0 * particleRadius;
+    const Vec3i  dim     = {
+        static_cast<int>(boxSize.x() / spacing),
+        static_cast<int>(boxSize.y() / spacing),
+        static_cast<int>(boxSize.z() / spacing) };
+
+    imstkNew<StdVectorOfVec3d> particles;
+    particles->reserve(dim[0] * dim[1] * dim[2]);
+
+    for (double z = bounds[4]; z < bounds[5]; z += spacing)
+    {
+        for (double y = bounds[2]; y < bounds[3]; y += spacing)
+        {
+            for (double x = bounds[0]; x < bounds[1]; x += spacing)
+            {
+                particles->push_back(Vec3d(x, y, z));
+            }
+        }
+    }
+
+    return particles;
+}
+
+///
+/// \brief Generate an SPH Box Object
+/// \param name of the object
+/// \param radius of SPH particles
+/// \param shift/position of the fluid box
+/// \parma dimensions of the fluid box
+///
+std::shared_ptr<SPHObject>
+makeSPHBoxObject(const std::string& name, const double particleRadius, const Vec3d& boxShift, const Vec3d& boxSize)
+{
+    // Create the sph object
+    imstkNew<SPHObject> fluidObj(name);
+
+    // Setup the Geometry
+    std::shared_ptr<StdVectorOfVec3d> particles = generateBoxShapeFluid(particleRadius, boxShift, boxSize);
+    LOG(INFO) << "Number of particles: " << particles->size();
+    imstkNew<PointSet> fluidGeometry;
+    fluidGeometry->initialize(*particles);
+
+    // Setup the Parameters
+    imstkNew<SPHModelConfig> sphParams(particleRadius);
+    sphParams->m_bNormalizeDensity = true;
+    sphParams->m_kernelOverParticleRadiusRatio = 6.0;
+    sphParams->m_viscosityCoeff = 0.5;
+    sphParams->m_surfaceTensionStiffness = 5.0;
+
+    // Setup the Model
+    imstkNew<SPHModel> sphModel;
+    sphModel->setModelGeometry(fluidGeometry);
+    sphModel->configure(sphParams);
+    sphModel->setTimeStepSizeType(TimeSteppingType::RealTime);
+
+    // Setup the VisualModel
+    imstkNew<VisualModel>    fluidVisualModel(fluidGeometry.get());
+    imstkNew<RenderMaterial> fluidMaterial;
+    fluidMaterial->setDisplayMode(RenderMaterial::DisplayMode::Fluid);
+    fluidMaterial->setVertexColor(Color::Orange);
+    fluidMaterial->setPointSize(static_cast<double>(particleRadius));
+    fluidVisualModel->setRenderMaterial(fluidMaterial);
+
+    // Setup the Object
+    fluidObj->addVisualModel(fluidVisualModel);
+    fluidObj->setCollidingGeometry(fluidGeometry);
+    fluidObj->setDynamicalModel(sphModel);
+    fluidObj->setPhysicsGeometry(fluidGeometry);
+
+    return fluidObj;
+}
+
+///
+/// \brief Generate a Deformable object simulated with FEM
+/// \param name of the object
+/// \param position of the object
+///
+static std::shared_ptr<FeDeformableObject>
+makeFEDragonObject(const std::string& name, const Vec3d& position)
+{
+    // Create the sph object
+    imstkNew<FeDeformableObject> object(name);
+
+    // Setup the Geometry
+    auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    tetMesh->translate(position, Geometry::TransformType::ApplyToData);
+    imstkNew<SurfaceMesh> surfMesh;
+    tetMesh->extractSurfaceMesh(surfMesh, true);
+
+    // Setup the Parameters
+    imstkNew<FEMModelConfig> config;
+    config->m_fixedNodeIds = { 50, 126, 177 };
+
+    // Setup the Model
+    imstkNew<FEMDeformableBodyModel> dynaModel;
+    dynaModel->configure(config);
+    dynaModel->setTimeStepSizeType(TimeSteppingType::Fixed);
+    dynaModel->setModelGeometry(tetMesh);
+    imstkNew<BackwardEuler> timeIntegrator(0.01);
+    dynaModel->setTimeIntegrator(timeIntegrator);
+
+    // Setup the VisualModel
+    imstkNew<VisualModel>    surfMeshModel(surfMesh.get());
+    imstkNew<RenderMaterial> material;
+    material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+    surfMeshModel->setRenderMaterial(material);
+
+    // Setup the Object
+    object->addVisualModel(surfMeshModel);
+    object->setPhysicsGeometry(tetMesh);
+    object->setPhysicsToVisualMap(std::make_shared<OneToOneMap>(tetMesh, surfMesh));
+    object->setDynamicalModel(dynaModel);
+
+    return object;
+}
+
+///
+/// \brief Generate a Deformable object simulated with PBD
+/// \param name of the object
+/// \param position of the object
+///
+static std::shared_ptr<PbdObject>
+makePBDDragonObject(const std::string& name, const Vec3d& position)
+{
+    // Create the pbd object
+    imstkNew<PbdObject> pbdObj(name);
+
+    // Setup the Geometry (read dragon mesh)
+    auto highResSurfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
+    auto coarseTetMesh   = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    highResSurfMesh->translate(position, Geometry::TransformType::ApplyToData);
+    coarseTetMesh->translate(position, Geometry::TransformType::ApplyToData);
+    imstkNew<SurfaceMesh> coarseSurfMesh;
+    coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true);
+
+    // Setup the Parameters
+    imstkNew<PBDModelConfig> pbdParams;
+    pbdParams->m_femParams->m_YoungModulus = 1000.0;
+    pbdParams->m_femParams->m_PoissonRatio = 0.3;
+    pbdParams->m_fixedNodeIds = { 50, 126, 177 };
+    pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK);
+    pbdParams->m_uniformMassValue = 1.0;
+    pbdParams->m_gravity    = Vec3d(0, -9.8, 0);
+    pbdParams->m_defaultDt  = 0.01;
+    pbdParams->m_iterations = 10;
+    pbdParams->collisionParams->m_proximity = 0.3;
+    pbdParams->collisionParams->m_stiffness = 0.1;
+
+    // Setup the Model
+    imstkNew<PbdModel> model;
+    model->setModelGeometry(coarseTetMesh);
+    model->configure(pbdParams);
+
+    // Setup the VisualModel
+    imstkNew<RenderMaterial> material;
+    material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+    imstkNew<VisualModel> surfMeshModel(highResSurfMesh);
+    surfMeshModel->setRenderMaterial(material);
+
+    // Setup the Object
+    pbdObj->addVisualModel(surfMeshModel);
+    pbdObj->setCollidingGeometry(coarseSurfMesh);
+    pbdObj->setPhysicsGeometry(coarseTetMesh);
+    pbdObj->setPhysicsToCollidingMap(std::make_shared<OneToOneMap>(coarseTetMesh, coarseSurfMesh));
+    pbdObj->setPhysicsToVisualMap(std::make_shared<TetraTriangleMap>(coarseTetMesh, highResSurfMesh));
+    pbdObj->setDynamicalModel(model);
+
+    return pbdObj;
+}
+
+///
+/// \brief This example demonstrates 3 different models running at the same time
+///
+int
+main()
+{
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("SPH-FEM-PBD");
+
+    // Setup the scene
+    {
+        scene->getConfig()->taskTimingEnabled = true;
+        scene->getActiveCamera()->setPosition(0.0, 2.0, 25.0);
+
+        // Deformable Pbd Dragon
+        std::shared_ptr<PbdObject> pbdDragon = makePBDDragonObject("PBDDragon", Vec3d(-5.0, 0.0, 0.0));
+        scene->addSceneObject(pbdDragon);
+
+        // Deformable FEM dragon
+        std::shared_ptr<FeDeformableObject> feDragon = makeFEDragonObject("FEDragon", Vec3d(0.0, 0.0, 0.0));
+        scene->addSceneObject(feDragon);
+
+        // SPH fluid box overtop the dragon
+        std::shared_ptr<SPHObject> sphFluidBox = makeSPHBoxObject("Box", 0.1, Vec3d(5.0, 7.0, 0.0), Vec3d(3.0, 7.0, 3.0));
+        scene->addSceneObject(sphFluidBox);
+
+        // Light
+        imstkNew<DirectionalLight> light("light");
+        light->setDirection(0.0, -1.0, -1.0);
+        light->setIntensity(1);
+        scene->addLight(light);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+        viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
+
+    imstkNew<TaskGraphVizWriter> writer;
+    writer->setFileName("sphFemPbdInteractionTaskGraph.svg");
+    writer->setHighlightCriticalPath(true);
+    writer->setInput(scene->getTaskGraph());
+    writer->write();
+
+    return 0;
+}
diff --git a/Examples/SPHFluid/Fluid.hpp b/Examples/SPHFluid/Fluid.hpp
index ba3f7f7474367c3317df66bee530ace0474bc81f..54f5098971fef0f68c2e6f618eba83d085597a1d 100644
--- a/Examples/SPHFluid/Fluid.hpp
+++ b/Examples/SPHFluid/Fluid.hpp
@@ -19,11 +19,12 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkSPHObject.h"
-#include "imstkSPHModel.h"
 #include "imstkPointSet.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
+#include "imstkSPHObject.h"
+#include "imstkSPHModel.h"
+#include "imstkVisualModel.h"
 
 using namespace imstk;
 
@@ -157,7 +158,7 @@ initializeNonZeroVelocities(const size_t numParticles)
 }
 
 std::shared_ptr<SPHObject>
-generateFluid(const std::shared_ptr<Scene>& scene, const double particleRadius)
+generateFluid(const double particleRadius)
 {
     StdVectorOfVec3d particles;
     StdVectorOfVec3d initialVelocities;
@@ -186,26 +187,33 @@ generateFluid(const std::shared_ptr<Scene>& scene, const double particleRadius)
     LOG(INFO) << "Number of particles: " << particles.size();
 
     // Create a geometry object
-    auto fluidGeometry = std::make_shared<PointSet>();
-    fluidGeometry->initialize(particles);
+    imstkNew<PointSet> geometry;
+    geometry->initialize(particles);
 
     // Create a fluids object
-    auto fluidObj = std::make_shared<SPHObject>("Sphere");
+    imstkNew<SPHObject> fluidObj("Sphere");
 
     // Create a visual model
-    auto fluidVisualModel = std::make_shared<VisualModel>(fluidGeometry);
-    auto fluidMaterial    = std::make_shared<RenderMaterial>();
-    fluidMaterial->setDisplayMode(RenderMaterial::DisplayMode::Points);
-    fluidMaterial->setVertexColor(Color::Orange);
-    fluidMaterial->setPointSize(10.);
-    fluidVisualModel->setRenderMaterial(fluidMaterial);
+    imstkNew<VisualModel> visualModel(geometry.get());
+    imstkNew<RenderMaterial> material;
+    material->setDisplayMode(RenderMaterial::DisplayMode::Fluid);
+    material->setVertexColor(Color::Orange);
+    if (material->getDisplayMode() == RenderMaterial::DisplayMode::Fluid)
+    {
+        material->setPointSize(0.1);
+    }
+    else
+    {
+        material->setPointSize(15.0);
+    }
+    visualModel->setRenderMaterial(material);
 
     // Create a physics model
-    auto sphModel = std::make_shared<SPHModel>();
-    sphModel->setModelGeometry(fluidGeometry);
+    imstkNew<SPHModel> sphModel;
+    sphModel->setModelGeometry(geometry);
 
-    // configure model
-    auto sphParams = std::make_shared<SPHModelConfig>(particleRadius);
+    // Configure model
+    imstkNew<SPHModelConfig> sphParams(particleRadius);
     sphParams->m_bNormalizeDensity = true;
     if (SCENE_ID == 2)   // highly viscous fluid
     {
@@ -223,11 +231,10 @@ generateFluid(const std::shared_ptr<Scene>& scene, const double particleRadius)
     sphModel->setTimeStepSizeType(TimeSteppingType::RealTime);
 
     // Add the component models
-    fluidObj->addVisualModel(fluidVisualModel);
-    fluidObj->setCollidingGeometry(fluidGeometry);
+    fluidObj->addVisualModel(visualModel);
+    fluidObj->setCollidingGeometry(geometry);
     fluidObj->setDynamicalModel(sphModel);
-    fluidObj->setPhysicsGeometry(fluidGeometry); // TODO: Look into API duplication and resulting conflicts
-    scene->addSceneObject(fluidObj);
+    fluidObj->setPhysicsGeometry(geometry);
 
     return fluidObj;
 }
diff --git a/Examples/SPHFluid/SPHFluidExample.hpp b/Examples/SPHFluid/SPHFluidExample.hpp
index 9447fcb89f58f5c25f23f55f254e0ff54d68dcd5..77a3c2745765e0873725813e22132694be8337e9 100644
--- a/Examples/SPHFluid/SPHFluidExample.hpp
+++ b/Examples/SPHFluid/SPHFluidExample.hpp
@@ -19,20 +19,18 @@
 
 =========================================================================*/
 
-#include <string>
-
-#include "imstkSimulationManager.h"
+#include "imstkCamera.h"
+#include "imstkCollisionDetection.h"
+#include "imstkCollisionGraph.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkObjectInteractionFactory.h"
+#include "imstkSceneManager.h"
 #include "imstkSPHObject.h"
-#include "imstkAPIUtilities.h"
-#include "imstkPlane.h"
-#include "imstkSphere.h"
 #include "imstkVTKTextStatusManager.h"
-#include "imstkCollisionGraph.h"
-#include "imstkSceneManager.h"
-#include "imstkCamera.h"
-#include "imstkObjectInteractionFactory.h"
-#include "imstkCollisionDetection.h"
+#include "imstkVTKViewer.h"
 
 #include "Fluid.hpp"
 #include "Solid.hpp"
@@ -46,22 +44,16 @@ using namespace imstk;
 int
 main(int argc, char* argv[])
 {
-    // SimulationManager must be created first
-    auto simManager = std::make_shared<SimulationManager>();
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
 
-    int    threads        = -1;
     double particleRadius = 0.1;
 
     // Parse command line arguments
     for (int i = 1; i < argc; ++i)
     {
         auto param = std::string(argv[i]);
-        if (param.find("threads") == 0
-            && param.find_first_of("=") != std::string::npos)
-        {
-            threads = std::stoi(param.substr(param.find_first_of("=") + 1));
-        }
-        else if (param.find("radius") == 0
+        if (param.find("radius") == 0
                  && param.find_first_of("=") != std::string::npos)
         {
             particleRadius = std::stod(param.substr(param.find_first_of("=") + 1));
@@ -79,29 +71,17 @@ main(int argc, char* argv[])
         particleRadius = 0.08;
     }
 
-    // Set thread pool size (nthreads <= 0 means using all logical cores)
-    simManager->setThreadPoolSize(threads);
-
-    auto scene = simManager->createNewScene("SPH Fluid");
-
-    // Create the viewer
-    std::shared_ptr<VTKViewer> viewer = std::make_shared<VTKViewer>(simManager.get(), false);
-    viewer->setWindowTitle("SPH Fluid");
-    viewer->getVtkRenderWindow()->SetSize(1920, 1080);
-    auto statusManager = viewer->getTextStatusManager();
-    statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30);
-    statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Red);
-    simManager->setViewer(viewer);
+    imstkNew<Scene> scene("SPH Fluid");
 
     // Generate fluid and solid objects
-    auto fluidObj = generateFluid(scene, particleRadius);
-    auto solids   = generateSolids(scene);
+    std::shared_ptr<SPHObject> fluidObj                  = generateFluid(particleRadius);
+    std::vector<std::shared_ptr<CollidingObject>> solids = generateSolids();
 
-    simManager->getSceneManager(scene)->setPostUpdateCallback([&](Module*) {
-        statusManager->setCustomStatus("Number of particles: " +
-                                   std::to_string(fluidObj->getSPHModel()->getState().getNumParticles()) +
-                                        "\nNumber of solids: " + std::to_string(solids.size()));
-    });
+    scene->addSceneObject(fluidObj);
+    for (size_t i = 0; i < solids.size(); i++)
+    {
+        scene->addSceneObject(solids[i]);
+    }
 
     // Collision between fluid and solid objects
     std::shared_ptr<CollisionGraph> collisionGraph = scene->getCollisionGraph();
@@ -124,16 +104,53 @@ main(int argc, char* argv[])
     }
 
     // configure camera
-    scene->getCamera()->setPosition(0, 10.0, 15.0);
+    scene->getActiveCamera()->setPosition(-0.475, 8.116, -6.728);
 
     // configure light (white)
-    auto whiteLight = std::make_shared<DirectionalLight>("whiteLight");
-    whiteLight->setFocalPoint(Vec3d(5, -8, -5));
+    imstkNew<DirectionalLight> whiteLight("whiteLight");
+    whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
     whiteLight->setIntensity(1.5);
     scene->addLight(whiteLight);
 
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+        viewer->setWindowTitle("SPH Fluid");
+        viewer->setSize(1920, 1080);
+        auto statusManager = viewer->getTextStatusManager();
+        statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 30);
+        statusManager->setStatusFontColor(VTKTextStatusManager::StatusType::Custom, Color::Red);
+        connect<Event>(viewer, EventType::PostUpdate,
+            [&](Event*)
+            {
+                statusManager->setCustomStatus("Number of particles: " +
+                    std::to_string(fluidObj->getSPHModel()->getState().getNumParticles()) +
+                    "\nNumber of solids: " + std::to_string(solids.size()));
+            });
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/SPHFluid/Solid.hpp b/Examples/SPHFluid/Solid.hpp
index 8e9ce4ba917baf0b9009b436e06a0b6ee6842f12..5cb6cd919b7889d20910c80cbcbc9d9334af2357 100644
--- a/Examples/SPHFluid/Solid.hpp
+++ b/Examples/SPHFluid/Solid.hpp
@@ -27,7 +27,9 @@
 //#include "imstkGeometryUtilities.h"
 
 #include "imstkSimulationManager.h"
+
 #include "imstkPlane.h"
+#include "imstkRenderMaterial.h"
 #include "imstkSphere.h"
 
 using namespace imstk;
@@ -35,58 +37,55 @@ using namespace imstk;
 ///
 /// \brief Generate two planes and a solid sphere
 ///
-std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene1(const std::shared_ptr<Scene>& scene)
+std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene1()
 {
     std::vector<std::shared_ptr<CollidingObject>> solids;
 
     {
-        auto geometry = std::make_shared<Plane>();
-        geometry->setWidth(40);
-        geometry->setPosition(0, -6, 0);
-        geometry->setNormal(Vec3d(0, 1, -0.5));
+        imstkNew<Plane> geometry;
+        geometry->setWidth(40.0);
+        geometry->setPosition(0.0, -6.0, 0.0);
+        geometry->setNormal(Vec3d(0.0, 1.0, -0.5));
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material        = std::make_shared<RenderMaterial>();
+        imstkNew<VisualModel> visualModel(geometry.get());
+        imstkNew<RenderMaterial> material;
         material->setColor(Color::DarkGray);
         visualModel->setRenderMaterial(material);
 
-        auto obj = std::make_shared<CollidingObject>("Floor");
+        imstkNew<CollidingObject> obj("Floor");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
     {
-        auto geometry = std::make_shared<Plane>();
-        geometry->setWidth(40);
-        geometry->setPosition(0, -6, 0);
-        geometry->setNormal(Vec3d(0, 1, 1));
+        imstkNew<Plane> geometry;
+        geometry->setWidth(40.0);
+        geometry->setPosition(0.0, -6.0, 0.0);
+        geometry->setNormal(Vec3d(0.0, 1.0, 1.0));
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material = std::make_shared<RenderMaterial>();
+        imstkNew<VisualModel> visualModel(geometry.get());
+        imstkNew<RenderMaterial> material;
         material->setColor(Color::LightGray);
         visualModel->setRenderMaterial(material);
 
-        auto obj = std::make_shared<CollidingObject>("Back Plane");
+        imstkNew<CollidingObject> obj("Back Plane");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
     {
-        auto geometry = std::make_shared<Sphere>();
-        geometry->setRadius(2);
-        geometry->setPosition(0, -6, 0);
+        imstkNew<Sphere> geometry;
+        geometry->setRadius(2.0);
+        geometry->setPosition(0.0, -6.0, 0.0);
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material    = std::make_shared<RenderMaterial>();
+        imstkNew<VisualModel> visualModel(geometry.get());
+        imstkNew<RenderMaterial> material;
         material->setColor(Color::Red);
         visualModel->setRenderMaterial(material);
 
-        auto obj = std::make_shared<CollidingObject>("Sphere on Floor");
+        imstkNew<CollidingObject> obj("Sphere on Floor");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
 
@@ -96,42 +95,40 @@ std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene1(const std::sh
 ///
 /// \brief Generate two planes
 ///
-std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene2(const std::shared_ptr<Scene>& scene)
+std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene2()
 {
     std::vector<std::shared_ptr<CollidingObject>> solids;
 
     {
-        auto geometry = std::make_shared<Plane>();
-        geometry->setWidth(40);
-        geometry->setPosition(0, -6, 0);
-        geometry->setNormal(Vec3d(0, 1, -0.5));
+        imstkNew<Plane> geometry;
+        geometry->setWidth(40.0);
+        geometry->setPosition(0.0, -6.0, 0.0);
+        geometry->setNormal(Vec3d(0.0, 1.0, -0.5));
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material        = std::make_shared<RenderMaterial>();
+        imstkNew<VisualModel> visualModel(geometry.get());
+        imstkNew<RenderMaterial> material;
         material->setColor(Color::DarkGray);
         visualModel->setRenderMaterial(material);
 
-        auto obj = std::make_shared<CollidingObject>("Floor");
+        imstkNew<CollidingObject> obj("Floor");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
     {
-        auto geometry = std::make_shared<Plane>();
-        geometry->setWidth(40);
-        geometry->setPosition(0, -6, 0);
-        geometry->setNormal(Vec3d(0, 1, 1));
+        imstkNew<Plane> geometry;
+        geometry->setWidth(40.0);
+        geometry->setPosition(0.0, -6.0, 0.0);
+        geometry->setNormal(Vec3d(0.0, 1.0, 1.0));
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material        = std::make_shared<RenderMaterial>();
+        imstkNew<VisualModel> visualModel(geometry.get());
+        imstkNew<RenderMaterial> material;
         material->setColor(Color::LightGray);
         visualModel->setRenderMaterial(material);
 
-        auto obj = std::make_shared<CollidingObject>("Back Plane");
+        imstkNew<CollidingObject> obj("Back Plane");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
 
@@ -141,93 +138,83 @@ std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene2(const std::sh
 ///
 /// \brief Generate an open box by 5 planes: 1 floor and 4 walls
 ///
-std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene3(const std::shared_ptr<Scene>& scene)
+std::vector<std::shared_ptr<CollidingObject>> generateSolidsScene3()
 {
     std::vector<std::shared_ptr<CollidingObject>> solids;
 
+    imstkNew<RenderMaterial> lightGrayMat;
+    lightGrayMat->setColor(Color::LightGray);
+
     {
-        auto geometry = std::make_shared<Plane>();
-        geometry->setWidth(14);
-        geometry->setPosition(0, -6, 0);
-        geometry->setNormal(Vec3d(0, 1, 0));
+        imstkNew<Plane> geometry;
+        geometry->setWidth(14.0);
+        geometry->setPosition(0.0, -6.0, 0.0);
+        geometry->setNormal(Vec3d(0.0, 1.0, 0.0));
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material = std::make_shared<RenderMaterial>();
+        imstkNew<VisualModel> visualModel(geometry.get());
+        imstkNew<RenderMaterial> material;
         material->setColor(Color(0.2, 0.2, 0.2, 1.0));
         visualModel->setRenderMaterial(material);
 
-        auto obj = std::make_shared<CollidingObject>("Floor");
+        imstkNew<CollidingObject> obj("Floor");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
     {
-        auto geometry = std::make_shared<Plane>();
-        geometry->setWidth(14);
-        geometry->setPosition(0, 0, -7);
-        geometry->setNormal(Vec3d(0, 0, 1));
+        imstkNew<Plane> geometry;
+        geometry->setWidth(14.0);
+        geometry->setPosition(0.0, 0.0, -7.0);
+        geometry->setNormal(Vec3d(0.0, 0.0, 1.0));
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material = std::make_shared<RenderMaterial>();
-        material->setColor(Color::LightGray);
-        visualModel->setRenderMaterial(material);
+        imstkNew<VisualModel> visualModel(geometry.get());
+        visualModel->setRenderMaterial(lightGrayMat);
 
-        auto obj = std::make_shared<CollidingObject>("Back Wall");
+        imstkNew<CollidingObject> obj("Back Wall");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
     {
-        auto geometry = std::make_shared<Plane>();
-        geometry->setWidth(14);
-        geometry->setPosition(0, 0, 7);
-        geometry->setNormal(Vec3d(0, 0, -1));
+        imstkNew<Plane> geometry;
+        geometry->setWidth(14.0);
+        geometry->setPosition(0.0, 0.0, 7.0);
+        geometry->setNormal(Vec3d(0.0, 0.0, -1.0));
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material = std::make_shared<RenderMaterial>();
-        material->setColor(Color::LightGray);
-        visualModel->setRenderMaterial(material);
+        imstkNew<VisualModel> visualModel(geometry.get());
+        visualModel->setRenderMaterial(lightGrayMat);
 
-        auto obj = std::make_shared<CollidingObject>("Front Wall");
+        imstkNew<CollidingObject> obj("Front Wall");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
     {
-        auto geometry = std::make_shared<Plane>();
-        geometry->setWidth(14);
-        geometry->setPosition(7, 0, 0);
-        geometry->setNormal(Vec3d(-1, 0, 0));
+        imstkNew<Plane> geometry;
+        geometry->setWidth(14.0);
+        geometry->setPosition(7.0, 0.0, 0.0);
+        geometry->setNormal(Vec3d(-1.0, 0.0, 0.0));
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material = std::make_shared<RenderMaterial>();
-        material->setColor(Color::LightGray);
-        visualModel->setRenderMaterial(material);
+        imstkNew<VisualModel> visualModel(geometry.get());
+        visualModel->setRenderMaterial(lightGrayMat);
 
-        auto obj = std::make_shared<CollidingObject>("Left Wall");
+        imstkNew<CollidingObject> obj("Left Wall");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
     {
-        auto geometry = std::make_shared<Plane>();
-        geometry->setWidth(14);
-        geometry->setPosition(-7, 0, 0);
-        geometry->setNormal(Vec3d(1, 0, 0));
+        imstkNew<Plane> geometry;
+        geometry->setWidth(14.0);
+        geometry->setPosition(-7.0, 0.0, 0.0);
+        geometry->setNormal(Vec3d(1.0, 0.0, 0.0));
 
-        auto visualModel = std::make_shared<VisualModel>(geometry);
-        auto material = std::make_shared<RenderMaterial>();
-        material->setColor(Color::LightGray);
-        visualModel->setRenderMaterial(material);
+        imstkNew<VisualModel> visualModel(geometry.get());
+        visualModel->setRenderMaterial(lightGrayMat);
 
-        auto obj = std::make_shared<CollidingObject>("Right Wall");
+        imstkNew<CollidingObject> obj("Right Wall");
         obj->addVisualModel(visualModel);
         obj->setCollidingGeometry(geometry);
-        scene->addSceneObject(obj);
         solids.push_back(obj);
     }
 
@@ -287,9 +274,9 @@ std::vector<std::shared_ptr<CollidingObject>> generateSolids(const std::shared_p
     switch (SCENE_ID)
     {
     case 1:
-        return generateSolidsScene1(scene);
+        return generateSolidsScene1();
     case 2:
-        return generateSolidsScene2(scene);
+        return generateSolidsScene2();
     case 3:
         return generateSolidsScene3(scene);
     case 4:
diff --git a/Examples/SceneManagement/SceneManagementExample.cpp b/Examples/SceneManagement/SceneManagementExample.cpp
index f0c4668a32b388d3994f06cae739ec753519ccd0..07b55ee9dd7ede77d3c1a63746ebccb553003201 100644
--- a/Examples/SceneManagement/SceneManagementExample.cpp
+++ b/Examples/SceneManagement/SceneManagementExample.cpp
@@ -20,9 +20,10 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
-#include "imstkCollisionGraph.h"
+#include "imstkLogger.h"
+#include "imstkNew.h"
 #include "imstkScene.h"
-#include "imstkSimulationManager.h"
+#include "imstkSceneManager.h"
 
 using namespace imstk;
 
@@ -32,46 +33,49 @@ using namespace imstk;
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<SceneManager> sceneManager;
 
     // Scenes
     LOG(INFO) << "-- Test add scenes";
-    auto scene1 = std::make_shared<Scene>("scene1");
-    simManager->addScene(scene1);
-
-    simManager->createNewScene("scene2");
-    auto scene2 = simManager->getScene("scene2");
-
-    auto scene3 = simManager->createNewScene();
-    simManager->removeScene("Scene_3");
+    imstkNew<Scene> scene1("scene1");
+    scene1->initialize();
+    sceneManager->addScene(scene1);
+    imstkNew<Scene> scene2("scene2");
+    scene2->initialize();
+    sceneManager->addScene(scene2);
+
+    imstkNew<Scene> scene3("scene3");
+    scene3->initialize();
+    sceneManager->addScene(scene3);
+    sceneManager->removeScene("Scene3");
 
     // switch
     LOG(INFO) << "-- Test scene switch";
-    int delay = 5;
-    simManager->setActiveScene(scene1);
-    simManager->start();
+    int delay = 1;
+    sceneManager->setActiveScene(scene1);
+    sceneManager->start(false);
     std::this_thread::sleep_for(std::chrono::seconds(delay));
-    simManager->setActiveScene(scene2, false);
+    sceneManager->setActiveScene(scene2);
     std::this_thread::sleep_for(std::chrono::seconds(delay));
-    simManager->setActiveScene(scene1, true);
+    sceneManager->setActiveScene(scene1);
     std::this_thread::sleep_for(std::chrono::seconds(delay));
-    simManager->end();
+    sceneManager->stop(true);
 
     // pause/run
     LOG(INFO) << "-- Test simulation pause/run";
-    simManager->setActiveScene(scene2);
-    simManager->start();
+    sceneManager->setActiveScene(scene2);
+    sceneManager->start(false);
     std::this_thread::sleep_for(std::chrono::seconds(delay));
-    simManager->pause();
+    sceneManager->pause(true);
     std::this_thread::sleep_for(std::chrono::seconds(delay));
-    simManager->run();
+    sceneManager->resume(true);
     std::this_thread::sleep_for(std::chrono::seconds(delay));
-    simManager->pause();
+    sceneManager->pause(true);
     std::this_thread::sleep_for(std::chrono::seconds(delay));
-    simManager->end();
-
-    // Quit
-    while (simManager->getStatus() != SimulationStatus::Inactive) {}
+    sceneManager->stop(true);
 
     return 0;
 }
diff --git a/Examples/Screenshot/ScreenshotExample.cpp b/Examples/Screenshot/ScreenshotExample.cpp
index 9b88ed1ac828d23e7b2d9f4cca453a3d41cb9f6b..eabd59502c84462cfa6a53760fe3fbe934c27237 100644
--- a/Examples/Screenshot/ScreenshotExample.cpp
+++ b/Examples/Screenshot/ScreenshotExample.cpp
@@ -19,14 +19,22 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkSceneObject.h"
 #include "imstkCamera.h"
-#include "imstkLight.h"
 #include "imstkCube.h"
-#include "imstkSphere.h"
+#include "imstkKeyboardDeviceClient.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkPlane.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObject.h"
+#include "imstkSphere.h"
+#include "imstkViewer.h"
+#include "imstkVTKScreenCaptureUtility.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -36,77 +44,100 @@ using namespace imstk;
 int
 main()
 {
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto sceneTest  = simManager->createNewScene("ScreenShotUtility");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("ScreenShotUtility");
 
     // Plane
-    auto planeGeom = std::make_shared<Plane>();
-    planeGeom->setWidth(10);
-    auto planeObj = std::make_shared<VisualObject>("VisualPlane");
+    imstkNew<Plane> planeGeom;
+    planeGeom->setWidth(10.0);
+    imstkNew<VisualObject> planeObj("VisualPlane");
     planeObj->setVisualGeometry(planeGeom);
 
     // Cube
-    auto cubeGeom = std::make_shared<Cube>();
+    imstkNew<Cube> cubeGeom;
     cubeGeom->setWidth(0.5);
     cubeGeom->setPosition(1.0, -1.0, 0.5);
     // rotates could be replaced by cubeGeom->setOrientationAxis(1,1,1) (normalized inside)
     cubeGeom->rotate(UP_VECTOR, PI_4, Geometry::TransformType::ApplyToData);
     cubeGeom->rotate(RIGHT_VECTOR, PI_4, Geometry::TransformType::ApplyToData);
-    auto cubeObj = std::make_shared<VisualObject>("VisualCube");
+    imstkNew<VisualObject> cubeObj("VisualCube");
     cubeObj->setVisualGeometry(cubeGeom);
 
     // Sphere
-    auto sphereGeom = std::make_shared<Sphere>();
+    imstkNew<Sphere> sphereGeom;
     sphereGeom->setRadius(0.3);
-    sphereGeom->setPosition(0, 2, 0);
-    auto sphereObj = std::make_shared<VisualObject>("VisualSphere");
+    sphereGeom->setPosition(0.0, 2.0, 0.0);
+    imstkNew<VisualObject> sphereObj("VisualSphere");
     sphereObj->setVisualGeometry(sphereGeom);
 
     // Light (white)
-    auto whiteLight = std::make_shared<PointLight>("whiteLight");
-    whiteLight->setIntensity(100);
-    whiteLight->setPosition(Vec3d(5, 8, 5));
+    imstkNew<PointLight> whiteLight("whiteLight");
+    whiteLight->setIntensity(100.0);
+    whiteLight->setPosition(Vec3d(5.0, 8.0, 5.0));
 
     // Light (red)
-    auto colorLight = std::make_shared<SpotLight>("colorLight");
-    colorLight->setPosition(Vec3d(4, -3, 1));
-    colorLight->setFocalPoint(Vec3d(0, 0, 0));
-    colorLight->setIntensity(100);
+    imstkNew<SpotLight> colorLight("colorLight");
+    colorLight->setPosition(Vec3d(4.0, -3.0, 1.0));
+    colorLight->setFocalPoint(Vec3d(0.0, 0.0, 0.0));
+    colorLight->setIntensity(100.0);
     colorLight->setColor(Color::Red);
-    colorLight->setSpotAngle(15);
+    colorLight->setSpotAngle(15.0);
 
     // Add in scene
-    sceneTest->addSceneObject(planeObj);
-    sceneTest->addSceneObject(cubeObj);
-    sceneTest->addSceneObject(sphereObj);
-    sceneTest->addLight(whiteLight);
-    sceneTest->addLight(colorLight);
+    scene->addSceneObject(planeObj);
+    scene->addSceneObject(cubeObj);
+    scene->addSceneObject(sphereObj);
+    scene->addLight(whiteLight);
+    scene->addLight(colorLight);
 
     // Update Camera
-    auto cam1 = sceneTest->getCamera();
-    cam1->setPosition(Vec3d(-5.5, 2.5, 32));
-    cam1->setFocalPoint(Vec3d(1, 1, 0));
-
-#ifndef iMSTK_USE_Vulkan
-    auto viewer = simManager->getViewer();
-    auto screenShotUtility
-        = std::dynamic_pointer_cast<VTKScreenCaptureUtility>(viewer->getScreenCaptureUtility());
-    // Set up for screen shot
-    viewer->getScreenCaptureUtility()->setScreenShotPrefix("screenShot_");
-    // Create a call back on key press of 'b' to take the screen shot
-    viewer->setOnCharFunction('b', [&](InteractorStyle* c) -> bool
-    {
-        screenShotUtility->saveScreenShot();
-        return false;
-    });
-#endif
+    scene->getActiveCamera()->setPosition(Vec3d(-5.5, 2.5, 32.0));
+    scene->getActiveCamera()->setFocalPoint(Vec3d(1.0, 1.0, 0.0));
 
-    std::cout << "PRESS 'b' for taking screenshot" << std::endl;
+    LOG(INFO) << "PRESS 'b' for taking screenshots";
 
-    // Run
-    simManager->setActiveScene(sceneTest);
-    simManager->start(SimulationStatus::Paused);
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+        viewer->getScreenCaptureUtility()->setScreenShotPrefix("screenShot_");
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+
+            connect<KeyPressEvent>(viewer->getKeyboardDevice(), EventType::KeyPress,
+                [&](KeyPressEvent* e)
+            {
+                if (e->m_keyPressType == KEY_PRESS)
+                {
+                    if (e->m_key == 'b')
+                    {
+                        viewer->getScreenCaptureUtility()->saveScreenShot();
+                    }
+                }
+                });
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp b/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp
index 3ff84e15cf6c4167f315b502258cc0dbb10a52a6..7af639db83878b108031c25b9c53d3195e684028 100644
--- a/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp
+++ b/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp
@@ -19,28 +19,33 @@
 
 =========================================================================*/
 
-#include "imstkAPIUtilities.h"
 #include "imstkCamera.h"
 #include "imstkColorFunction.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
 #include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkPbdModel.h"
 #include "imstkPbdObject.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
-#include "imstkSimulationManager.h"
+#include "imstkSceneManager.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkTaskGraph.h"
 #include "imstkTaskGraphVizWriter.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
-static std::unique_ptr<SurfaceMesh>
+static std::shared_ptr<SurfaceMesh>
 makeClothGeometry(
     const double width, const double height, const int nRows, const int nCols)
 {
     // Create surface mesh
-    std::unique_ptr<SurfaceMesh> clothMesh = std::make_unique<SurfaceMesh>();
-    StdVectorOfVec3d             vertList;
+    imstkNew<SurfaceMesh> clothMesh;
+    StdVectorOfVec3d      vertList;
 
     vertList.resize(nRows * nCols);
     const double dy = width / (double)(nCols - 1);
@@ -93,10 +98,10 @@ makeClothObj(const std::string& name, double width, double height, int nRows, in
 {
     auto clothObj = std::make_shared<PbdObject>(name);
 
-    std::shared_ptr<SurfaceMesh> clothMesh(std::move(makeClothGeometry(width, height, nRows, nCols)));
+    std::shared_ptr<SurfaceMesh> clothMesh = makeClothGeometry(width, height, nRows, nCols);
 
     // Setup the Parameters
-    auto pbdParams = std::make_shared<PBDModelConfig>();
+    imstkNew<PBDModelConfig> pbdParams;
     pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1e2);
     pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1e1);
     pbdParams->m_fixedNodeIds     = { 0, static_cast<size_t>(nCols) - 1 };
@@ -106,12 +111,12 @@ makeClothObj(const std::string& name, double width, double height, int nRows, in
     pbdParams->m_iterations = 5;
 
     // Setup the Model
-    auto pbdModel = std::make_shared<PbdModel>();
+    imstkNew<PbdModel> pbdModel;
     pbdModel->setModelGeometry(clothMesh);
     pbdModel->configure(pbdParams);
 
     // Setup the VisualModel
-    auto material = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> material;
     material->setBackFaceCulling(false);
     material->setColor(Color::LightGray);
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
@@ -133,8 +138,10 @@ makeClothObj(const std::string& name, double width, double height, int nRows, in
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("PBDCloth");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("PBDCloth");
 
     const double               width    = 10.0;
     const double               height   = 10.0;
@@ -144,13 +151,13 @@ main()
     scene->addSceneObject(clothObj);
 
     // Adjust camera
-    scene->getCamera()->setFocalPoint(0, -5, 5);
-    scene->getCamera()->setPosition(-15., -5.0, 15.0);
+    scene->getActiveCamera()->setFocalPoint(0.0, -5.0, 5.0);
+    scene->getActiveCamera()->setPosition(-15.0, -5.0, 15.0);
 
     {
         // Setup some scalars
-        std::shared_ptr<SurfaceMesh>     clothGeometry = std::dynamic_pointer_cast<SurfaceMesh>(clothObj->getPhysicsGeometry());
-        std::shared_ptr<StdVectorOfReal> scalarsPtr    = std::make_shared<StdVectorOfReal>(clothGeometry->getNumVertices());
+        auto clothGeometry = std::dynamic_pointer_cast<SurfaceMesh>(clothObj->getPhysicsGeometry());
+        auto scalarsPtr    = std::make_shared<StdVectorOfReal>(clothGeometry->getNumVertices());
         std::fill_n(scalarsPtr->data(), scalarsPtr->size(), 0.0);
         clothGeometry->setScalars(scalarsPtr);
 
@@ -165,17 +172,19 @@ main()
         colorFunc->setRange(0.0, 2.0);
         material->setColorLookupTable(colorFunc);
 
+        // Adds a custom physics step to print out maximum velocity
         std::shared_ptr<PbdModel> pbdModel = clothObj->getPbdModel();
-        scene->setTaskGraphConfigureCallback([&](Scene* scene)
+        connect<Event>(scene, EventType::Configure,
+            [&](Event*)
         {
             // Get the graph
             std::shared_ptr<TaskGraph> graph = scene->getTaskGraph();
 
             // First write the graph before we make modifications, just to show the changes
-            TaskGraphVizWriter writer;
-            writer.setInput(graph);
-            writer.setFileName("taskGraphConfigureExampleOld.svg");
-            writer.write();
+            imstkNew<TaskGraphVizWriter> writer;
+            writer->setInput(graph);
+            writer->setFileName("taskGraphConfigureExampleOld.svg");
+            writer->write();
 
             // This node computes displacements and sets the color to the magnitude
             std::shared_ptr<TaskNode> computeVelocityScalars = std::make_shared<TaskNode>([&]()
@@ -193,20 +202,42 @@ main()
                 {
                     scalars[i] = velocities[i].norm();
                 }
-            }, "ComputeVelocityScalars");
+                    }, "ComputeVelocityScalars");
 
             // After IntegratePosition
             graph->insertAfter(clothObj->getUpdateGeometryNode(), computeVelocityScalars);
 
             // Write the modified graph
-            writer.setFileName("taskGraphConfigureExampleNew.svg");
-            writer.write();
-        });
+            writer->setFileName("taskGraphConfigureExampleNew.svg");
+            writer->write();
+            });
     }
 
-    // Start
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Paused);
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/Examples/TaskGraph/TaskGraph/taskGraphExample.cpp b/Examples/TaskGraph/TaskGraph/taskGraphExample.cpp
index c05cf60888a790e16c442768eef771f22410ca16..8ddaf56551729f561be9a3adadceb47f991d21d5 100644
--- a/Examples/TaskGraph/TaskGraph/taskGraphExample.cpp
+++ b/Examples/TaskGraph/TaskGraph/taskGraphExample.cpp
@@ -19,11 +19,12 @@
 
 =========================================================================*/
 
+#include "imstkNew.h"
 #include "imstkParallelFor.h"
 #include "imstkSequentialTaskGraphController.h"
 #include "imstkTaskGraph.h"
 #include "imstkTbbTaskGraphController.h"
-#include <iostream>
+#include "imstkLogger.h"
 
 using namespace imstk;
 
@@ -33,6 +34,8 @@ using namespace imstk;
 int
 main()
 {
+    Logger::startLogger();
+
     const bool runExampleInParallel = true;
 
     // Initialize some data arrays
@@ -58,17 +61,19 @@ main()
     int sumB = 0;
 
     // Now create a graph that computes results = sum_i(x_i + y_i) * sum_i(w_i * z_i)
-    std::shared_ptr<TaskGraph> graph = std::make_shared<TaskGraph>();
+    imstkNew<TaskGraph> graph;
 
     // Create and add the nodes
-    std::shared_ptr<TaskNode> addNode = graph->addFunction("Add Step", [&]()
+    std::shared_ptr<TaskNode> addNode = graph->addFunction("Add Step",
+        [&]()
     {
         for (int i = 0; i < countA; i++)
         {
             sumA += (x[i] + y[i]);
         }
         });
-    std::shared_ptr<TaskNode> multNode = graph->addFunction("Mult Step", [&]()
+    std::shared_ptr<TaskNode> multNode = graph->addFunction("Mult Step",
+        [&]()
     {
         for (int i = 0; i < countB; i++)
         {
@@ -97,11 +102,11 @@ main()
     controller->setTaskGraph(graph);
     if (!controller->initialize())
     {
-        std::cout << "TaskGraph failed to initialize" << std::endl;
+        LOG(FATAL) << "TaskGraph failed to initialize";
         return 1;
     }
     controller->execute();
-    std::cout << "Results: " << sumA + sumB << std::endl;
+    LOG(INFO) << "Results: " << sumA + sumB;
 
     return 0;
 }
diff --git a/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp b/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp
index e5f8032c118763301345c8f40e51c6e77f82bc4a..72a3d144c69a3e395ffda2aa499bc5b8ed31487f 100644
--- a/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp
+++ b/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp
@@ -19,15 +19,20 @@ limitations under the License.
 
 =========================================================================*/
 
-#include "imstkAPIUtilities.h"
 #include "imstkCamera.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLineMesh.h"
+#include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkPbdModel.h"
 #include "imstkPbdObject.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
 #include "imstkSceneManager.h"
-#include "imstkSimulationManager.h"
 #include "imstkTaskGraphVizWriter.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -38,7 +43,7 @@ static std::shared_ptr<LineMesh>
 makeStringGeometry(const Vec3d& pos, const size_t numVerts, const double stringLength)
 {
     // Create the geometry
-    std::shared_ptr<LineMesh> stringGeometry = std::make_shared<LineMesh>();
+    imstkNew<LineMesh> stringGeometry;
 
     StdVectorOfVec3d vertList;
     vertList.resize(numVerts);
@@ -74,13 +79,13 @@ makePbdString(
     const double       bendStiffness,
     const Color&       color)
 {
-    std::shared_ptr<PbdObject> stringObj = std::make_shared<PbdObject>(name);
+    imstkNew<PbdObject> stringObj(name);
 
     // Setup the Geometry
     std::shared_ptr<LineMesh> stringMesh = makeStringGeometry(pos, numVerts, stringLength);
 
     // Setup the Parameters
-    auto pbdParams = std::make_shared<PBDModelConfig>();
+    imstkNew<PBDModelConfig> pbdParams;
     pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1e7);
     pbdParams->enableConstraint(PbdConstraint::Type::Bend, bendStiffness);
     pbdParams->m_fixedNodeIds     = { 0 };
@@ -90,18 +95,18 @@ makePbdString(
     pbdParams->m_iterations = 5;
 
     // Setup the Model
-    std::shared_ptr<PbdModel> pbdModel = std::make_shared<PbdModel>();
+    imstkNew<PbdModel> pbdModel;
     pbdModel->setModelGeometry(stringMesh);
     pbdModel->configure(pbdParams);
 
     // Setup the VisualModel
-    std::shared_ptr<RenderMaterial> material = std::make_shared<RenderMaterial>();
+    imstkNew<RenderMaterial> material;
     material->setBackFaceCulling(false);
     material->setEdgeColor(color);
     material->setLineWidth(2.0f);
     material->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
 
-    std::shared_ptr<VisualModel> visualModel = std::make_shared<VisualModel>(stringMesh);
+    imstkNew<VisualModel> visualModel(stringMesh);
     visualModel->setRenderMaterial(material);
 
     // Setup the Object
@@ -158,27 +163,28 @@ const Color  endColor      = Color(0.0, 1.0, 0.0); // Color of last string
 int
 main()
 {
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("PBDString");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("PBDString");
     scene->getConfig()->taskTimingEnabled = true;
 
     // Setup N separate strings with varying bend stiffnesses
     std::vector<std::shared_ptr<PbdObject>> pbdStringObjs =
         makePbdStrings(numStrings, numVerts, stringSpacing, stringLength, startColor, endColor);
-    // Add them to the scene
+    // Add the string scene objects to the scene
     for (std::shared_ptr<PbdObject> obj : pbdStringObjs)
     {
         scene->addSceneObject(obj);
     }
 
     // Adjust the camera
-    scene->getCamera()->setFocalPoint(0.0, 0.0, 0.0);
-    scene->getCamera()->setPosition(0.0, 0.0, 15.0);
+    scene->getActiveCamera()->setPosition(0.0, 0.0, 15.0);
 
     // Move the points every frame
     double t = 0.0;
     auto   movePoints =
-        [&pbdStringObjs, &t](Module* module)
+        [&pbdStringObjs, &t](Event*)
         {
             for (unsigned int i = 0; i < pbdStringObjs.size(); i++)
             {
@@ -186,27 +192,51 @@ main()
                 const Vec3d               pos   = model->getCurrentState()->getVertexPosition(0);
                 // Move in circle, derivatives of parametric eq of circle
                 const Vec3d newPos = Vec3d(
-                pos.x() + -std::sin(t) * radius * dt,
-                pos.y(),
-                pos.z() + std::cos(t) * radius * dt);
+                    pos.x() + -std::sin(t) * radius * dt,
+                    pos.y(),
+                    pos.z() + std::cos(t) * radius * dt);
                 model->getCurrentState()->setVertexPosition(0, newPos);
             }
             t += dt;
         };
-    simManager->getSceneManager(scene)->setPostUpdateCallback(movePoints);
 
-    // Start
-    simManager->setActiveScene(scene);
-    simManager->start();
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        connect<Event>(sceneManager, EventType::PostUpdate, movePoints);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     // Write the graph, highlighting the critical path and putting the completion time in the name
-    TaskGraphVizWriter writer;
-    writer.setInput(scene->getTaskGraph());
-    writer.setFileName("taskGraphBenchmarkExample.svg");
-    writer.setHighlightCriticalPath(true);
-    writer.setWriteNodeComputeTimesColor(true);
-    writer.setWriteNodeComputeTimesText(true);
-    writer.write();
+    imstkNew<TaskGraphVizWriter> writer;
+    writer->setInput(scene->getTaskGraph());
+    writer->setFileName("taskGraphBenchmarkExample.svg");
+    writer->setHighlightCriticalPath(true);
+    writer->setWriteNodeComputeTimesColor(true);
+    writer->setWriteNodeComputeTimesText(true);
+    writer->write();
 
     return 0;
 }
diff --git a/Examples/Vessel/CMakeLists.txt b/Examples/Vessel/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..20f0c976deb06b7dec067492d1a9e25cef911220
--- /dev/null
+++ b/Examples/Vessel/CMakeLists.txt
@@ -0,0 +1,34 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  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.
+#
+###########################################################################
+
+project(Example-Vessel)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+imstk_add_executable(${PROJECT_NAME} vesselExample.cpp)
+
+#-----------------------------------------------------------------------------
+# Add the target to Examples folder
+#-----------------------------------------------------------------------------
+SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} SimulationManager Filtering)
diff --git a/Examples/Vessel/vesselExample.cpp b/Examples/Vessel/vesselExample.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b8ef58135b5fc2fe5b33f2cfe1af366a4176f7bf
--- /dev/null
+++ b/Examples/Vessel/vesselExample.cpp
@@ -0,0 +1,279 @@
+/*=========================================================================
+
+   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 "imstkCamera.h"
+#include "imstkCollisionGraph.h"
+#include "imstkDataArray.h"
+#include "imstkImageData.h"
+#include "imstkImageDistanceTransform.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkMeshIO.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkRenderMaterial.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSignedDistanceField.h"
+#include "imstkSPHModel.h"
+#include "imstkSPHObject.h"
+#include "imstkSphObjectCollisionPair.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkSurfaceMeshDistanceTransform.h"
+#include "imstkSurfaceMeshImageMask.h"
+#include "imstkViewer.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
+
+using namespace imstk;
+
+///
+/// \brief Generate a volume of fluid with the specified SurfaceMesh
+///
+static std::shared_ptr<StdVectorOfVec3d>
+generateFluidVolume(const double particleRadius, std::shared_ptr<SurfaceMesh> spawnSurfaceVolume)
+{
+    Vec3d minima, maxima;
+    spawnSurfaceVolume->computeBoundingBox(minima, maxima);
+
+    double      particleDiameter = particleRadius * 2.0;
+    const Vec3d size = (maxima - minima) + Vec3d(particleDiameter, particleDiameter, particleDiameter);
+    Vec3i       dim  = size.cwiseProduct(Vec3d(1.0 / particleDiameter, 1.0 / particleDiameter, 1.0 / particleDiameter)).cast<int>();
+
+    // Compute the binary mask
+    imstkNew<SurfaceMeshImageMask> makeBinaryMask;
+    makeBinaryMask->setInputMesh(spawnSurfaceVolume);
+    makeBinaryMask->setDimensions(dim[0], dim[1], dim[2]);
+    makeBinaryMask->update();
+
+    // Compute the DT (won't perfectly conform to surface as we used a binary mask)
+    imstkNew<ImageDistanceTransform> distTransformFromMask;
+    distTransformFromMask->setInputImage(makeBinaryMask->getOutputImage());
+    distTransformFromMask->update();
+
+    std::shared_ptr<DataArray<float>> scalarsPtr = std::dynamic_pointer_cast<DataArray<float>>(distTransformFromMask->getOutputImage()->getScalars());
+    const DataArray<float>&           scalars    = *scalarsPtr;
+    const Vec3i&                      dim1       = makeBinaryMask->getOutputImage()->getDimensions();
+    const Vec3d&                      spacing    = makeBinaryMask->getOutputImage()->getSpacing();
+    const Vec3d&                      shift      = makeBinaryMask->getOutputImage()->getOrigin() + spacing * 0.5;
+    const double                      threshold  = particleDiameter * 1.0; // How far from the boundary to accept particles
+
+    imstkNew<StdVectorOfVec3d> particles;
+    particles->reserve(dim1[0] * dim1[1] * dim1[2]);
+
+    int i = 0;
+    for (int z = 0; z < dim1[2]; z++)
+    {
+        for (int y = 0; y < dim1[1]; y++)
+        {
+            for (int x = 0; x < dim1[0]; x++, i++)
+            {
+                if (x > 1 && y > 1 && z > 1 && scalars[i] < -threshold)
+                {
+                    particles->push_back(Vec3d(x, y, z).cwiseProduct(spacing) + shift);
+                }
+            }
+        }
+    }
+    particles->shrink_to_fit();
+    return particles;
+}
+
+static std::shared_ptr<SPHObject>
+makeSPHObject(const std::string& name, const double particleRadius, const double particleSpacing)
+{
+    // Create the sph object
+    imstkNew<SPHObject> fluidObj(name);
+
+    // Setup the Geometry
+    auto spawnMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/femoralArteryCut.stl");
+    // By spacing them slightly closer we can induce larger compression at the start
+    std::shared_ptr<StdVectorOfVec3d> particles = generateFluidVolume(particleSpacing, spawnMesh);
+    LOG(INFO) << "Number of particles: " << particles->size();
+    imstkNew<PointSet> fluidGeometry;
+    fluidGeometry->initialize(*particles);
+
+    // Setup the Parameters
+    imstkNew<SPHModelConfig> sphParams(particleRadius);
+    sphParams->m_bNormalizeDensity = true;
+    sphParams->m_kernelOverParticleRadiusRatio = 6.0;
+    sphParams->m_viscosityCoeff = 0.8;
+    sphParams->m_surfaceTensionStiffness = 5.0;
+    sphParams->m_frictionBoundary = 0.1;
+
+    // Setup the Model
+    imstkNew<SPHModel> sphModel;
+    sphModel->setModelGeometry(fluidGeometry);
+    sphModel->configure(sphParams);
+    sphModel->setTimeStepSizeType(TimeSteppingType::RealTime);
+
+    // Setup the VisualModel
+    imstkNew<VisualModel>    fluidVisualModel(fluidGeometry.get());
+    imstkNew<RenderMaterial> fluidMaterial;
+    fluidMaterial->setDisplayMode(RenderMaterial::DisplayMode::Fluid);
+    fluidMaterial->setPointSize(particleRadius * 2.0f); // For fluids
+    fluidVisualModel->setRenderMaterial(fluidMaterial);
+
+    // Setup the Object
+    fluidObj->setDynamicalModel(sphModel);
+    fluidObj->addVisualModel(fluidVisualModel);
+    fluidObj->setCollidingGeometry(fluidGeometry);
+    fluidObj->setPhysicsGeometry(fluidGeometry);
+
+    return fluidObj;
+}
+
+static std::shared_ptr<CollidingObject>
+makeLegs(const std::string& name, const Vec3d& position)
+{
+    // Create the pbd object
+    imstkNew<CollidingObject> legsObj(name);
+
+    // Setup the Geometry (read dragon mesh)
+    auto legsMesh      = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/legsCutaway.stl");
+    auto bonesMesh     = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/legsBones.stl");
+    auto femoralMesh   = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/femoralArtery.stl");
+    auto collisionMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/legs/femoralArteryCut.stl");
+
+    // Setup the Legs VisualModel
+    imstkNew<VisualModel>    legsMeshModel(legsMesh);
+    imstkNew<RenderMaterial> legsMaterial;
+    legsMaterial->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+    legsMaterial->setOpacity(0.85f);
+    legsMaterial->setDiffuseColor(Color(0.8, 0.688, 0.396));
+    legsMeshModel->setRenderMaterial(legsMaterial);
+
+    // Setup the Bones VisualModel
+    imstkNew<VisualModel>    bonesMeshModel(bonesMesh);
+    imstkNew<RenderMaterial> bonesMaterial;
+    bonesMaterial->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+    bonesMaterial->setDiffuseColor(Color(0.538, 0.538, 0.538));
+    bonesMeshModel->setRenderMaterial(bonesMaterial);
+
+    // Setup the Femoral VisualModel
+    imstkNew<VisualModel>    femoralMeshModel(femoralMesh);
+    imstkNew<RenderMaterial> femoralMaterial;
+    femoralMaterial->setDisplayMode(RenderMaterial::DisplayMode::Surface);
+    femoralMaterial->setOpacity(0.2f);
+    femoralMaterial->setDiffuseColor(Color(0.8, 0.119, 0.180));
+    femoralMeshModel->setRenderMaterial(femoralMaterial);
+
+    // Setup the Object
+    legsObj->addVisualModel(legsMeshModel);
+    legsObj->addVisualModel(bonesMeshModel);
+    legsObj->addVisualModel(femoralMeshModel);
+
+    LOG(INFO) << "Computing SDF";
+    imstkNew<SurfaceMeshDistanceTransform> computeSdf;
+    computeSdf->setInputMesh(collisionMesh);
+    computeSdf->setDimensions(100, 100, 100);
+    Vec3d min, max;
+    collisionMesh->computeBoundingBox(min, max);
+    const Vec3d size = max - min;
+    Vec6d       bounds;
+    bounds[0] = min[0] - size[0] * 0.25;
+    bounds[1] = max[0] + size[0] * 0.25;
+    bounds[2] = min[1] - size[1] * 0.25;
+    bounds[3] = max[1] + size[1] * 0.25;
+    bounds[4] = min[2] - size[2] * 0.25;
+    bounds[5] = max[2] + size[2] * 0.25;
+    computeSdf->setBounds(bounds);
+    computeSdf->setUseBounds(true);
+    computeSdf->update();
+    LOG(INFO) << "SDF Complete";
+    legsObj->setCollidingGeometry(std::make_shared<SignedDistanceField>(computeSdf->getOutputImage()));
+
+    return legsObj;
+}
+
+///
+/// \brief This example demonstrates interaction simulates SPH fluid contained within
+/// an SDF vessel
+///
+int
+main()
+{
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    imstkNew<Scene> scene("Vessel");
+
+    // Setup the scene
+    {
+        //scene->getConfig()->taskTimingEnabled = true;
+
+        // Static Dragon object
+        std::shared_ptr<CollidingObject> legsObj = makeLegs("Vessel", Vec3d(0.0, 0.0, 0.0));
+        scene->addSceneObject(legsObj);
+
+        // Position the camera
+        const Vec6d& bounds = std::dynamic_pointer_cast<SignedDistanceField>(legsObj->getCollidingGeometry())->getBounds();
+        const Vec3d  center = (Vec3d(bounds[0], bounds[2], bounds[4]) + Vec3d(bounds[1], bounds[3], bounds[5])) * 0.5;
+        scene->getActiveCamera()->setPosition(3.25, 1.6, 3.38);
+        scene->getActiveCamera()->setFocalPoint(-2.05, 1.89, -1.32);
+        scene->getActiveCamera()->setViewUp(-0.66, 0.01, 0.75);
+
+        // SPH fluid box overtop the dragon
+        std::shared_ptr<SPHObject> sphObj = makeSPHObject("Fluid", 0.004, 0.0035);
+        scene->addSceneObject(sphObj);
+
+        // Interaction
+        imstkNew<SphObjectCollisionPair> collisionInteraction(sphObj, legsObj, CollisionDetection::Type::PointSetToImplicit);
+        scene->getCollisionGraph()->addInteraction(collisionInteraction);
+
+        // Light
+        imstkNew<DirectionalLight> light("light");
+        light->setDirection(0.0, 1.0, -1.0);
+        light->setIntensity(1.0);
+        scene->addLight(light);
+    }
+
+    // Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer");
+        viewer->setActiveScene(scene);
+        viewer->setBackgroundColors(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
+
+    return 0;
+}
diff --git a/Examples/VirtualCoupling/VirtualCouplingExample.cpp b/Examples/VirtualCoupling/VirtualCouplingExample.cpp
index a59c63db9860f6db1cfe48c6c89c9416a80b61ee..7d2253acb84c707cefc6c5211abb8503e9782786 100644
--- a/Examples/VirtualCoupling/VirtualCouplingExample.cpp
+++ b/Examples/VirtualCoupling/VirtualCouplingExample.cpp
@@ -19,21 +19,30 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
-#include "imstkVirtualCouplingCH.h"
-#include "imstkHDAPIDeviceServer.h"
-#include "imstkHDAPIDeviceClient.h"
-#include "imstkSceneObjectController.h"
-#include "imstkDeviceTracker.h"
+#include "imstkCamera.h"
+#include "imstkCDObjectFactory.h"
+#include "imstkCollidingObject.h"
+#include "imstkCollisionData.h"
 #include "imstkCollisionGraph.h"
+#include "imstkCollisionPair.h"
+#include "imstkHapticDeviceClient.h"
+#include "imstkHapticDeviceManager.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
-#include "imstkCamera.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
 #include "imstkPlane.h"
-#include "imstkSphere.h"
+#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObjectController.h"
+#include "imstkSphere.h"
+#include "imstkVirtualCouplingCH.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
 
 // global variables
-const std::string phantomOmni1Name = "Phantom1";
+const std::string phantomOmni1Name = "Default Device";
 
 using namespace imstk;
 
@@ -44,46 +53,35 @@ using namespace imstk;
 int
 main()
 {
-#ifndef iMSTK_USE_OPENHAPTICS
-    std::cout << "LaparoscopicToolController example needs haptic device to be enabled at build time" << std::endl;
-    return 1;
-#else if
-    // simManager and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("VirtualCoupling");
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    // Scene
+    imstkNew<Scene> scene("VirtualCoupling");
 
     // Create a plane in the scene
-    auto planeGeom = std::make_shared<Plane>();
-    planeGeom->setWidth(400);
-    planeGeom->setPosition(0.0, -50, 0.0);
-    auto planeObj = std::make_shared<CollidingObject>("Plane");
+    auto            planeGeom = std::make_shared<Plane>();
+    imstkNew<Plane> plane(Vec3d(0.0, -50.0, 0.0));
+    planeGeom->setWidth(400.0);
+    imstkNew<CollidingObject> planeObj("Plane");
     planeObj->setVisualGeometry(planeGeom);
     planeObj->setCollidingGeometry(planeGeom);
     scene->addSceneObject(planeObj);
 
     // Create the virtual coupling object controller
 
-    // Device clients
-    auto client = std::make_shared<HDAPIDeviceClient>(phantomOmni1Name);
-
     // Device Server
-    auto server = std::make_shared<HDAPIDeviceServer>();
-    server->addDeviceClient(client);
-    simManager->addModule(server);
-
-    // Device tracker
-    auto deviceTracker = std::make_shared<DeviceTracker>(client);
+    imstkNew<HapticDeviceManager>       server;
+    std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient(phantomOmni1Name);
 
     // Create a virtual coupling object
-    auto visualGeom = std::make_shared<Sphere>();
-    visualGeom->setRadius(20);
-    auto collidingGeom = std::make_shared<Sphere>();
-    collidingGeom->setRadius(20);
-    auto obj = std::make_shared<CollidingObject>("VirtualCouplingObject");
+    imstkNew<Sphere>          visualGeom(Vec3d(0.0, 0.0, 0.0), 20.0);
+    imstkNew<Sphere>          collidingGeom(Vec3d(0.0, 0.0, 0.0), 20.0);
+    imstkNew<CollidingObject> obj("VirtualCouplingObject");
     obj->setCollidingGeometry(collidingGeom);
 
-    auto material    = std::make_shared<RenderMaterial>();
-    auto visualModel = std::make_shared<VisualModel>(visualGeom);
+    imstkNew<RenderMaterial> material;
+    imstkNew<VisualModel>    visualModel(visualGeom.get());
     visualModel->setRenderMaterial(material);
     obj->addVisualModel(visualModel);
 
@@ -91,39 +89,64 @@ main()
     scene->addSceneObject(obj);
 
     // Create and add virtual coupling object controller in the scene
-    auto objController = std::make_shared<SceneObjectController>(obj, deviceTracker);
-    scene->addObjectController(objController);
+    imstkNew<SceneObjectController> controller(obj, client);
+    scene->addController(controller);
 
     {
         // Setup CD, and collision data
-        auto                                colData   = std::make_shared<CollisionData>();
+        imstkNew<CollisionData> colData;
+
         std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(CollisionDetection::Type::UnidirectionalPlaneToSphere,
-            planeObj, obj, colData);
+            planeObj->getCollidingGeometry(), obj->getCollidingGeometry(), colData);
 
         // Setup the handler
-        auto colHandler = std::make_shared<VirtualCouplingCH>(CollisionHandling::Side::B, colData, planeObj, obj);
+        imstkNew<VirtualCouplingCH> colHandler(CollisionHandling::Side::B, colData, obj);
         colHandler->setStiffness(5e-01);
         colHandler->setDamping(0.005);
 
-        auto pair = std::make_shared<CollisionPair>(planeObj, obj, colDetect, nullptr, colHandler);
-        scene->getCollisionGraph()->addInteractionPair(pair);
+        imstkNew<CollisionPair> pair(planeObj, obj, colDetect, nullptr, colHandler);
+        scene->getCollisionGraph()->addInteraction(pair);
     }
 
     // Camera
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(200, 200, 200));
-    cam->setFocalPoint(Vec3d(0, 0, 0));
+    scene->getActiveCamera()->setPosition(Vec3d(200, 200, 200));
+    scene->getActiveCamera()->setFocalPoint(Vec3d(0, 0, 0));
 
     // Light
-    auto light = std::make_shared<DirectionalLight>("light");
-    light->setFocalPoint(Vec3d(5, -8, -5));
-    light->setIntensity(1);
+    imstkNew<DirectionalLight> light("light");
+    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+    light->setIntensity(1.0);
     scene->addLight(light);
 
-    //Run
-    simManager->setActiveScene(scene);
-    simManager->start(SimulationStatus::Running);
+    //Run the simulation
+    {
+        // Setup a viewer to render in its own thread
+        imstkNew<VTKViewer> viewer("Viewer 1");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager 1");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+
+        viewer->addChildThread(server);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        // Start viewer running, scene as paused
+        sceneManager->requestStatus(ThreadStatus::Paused);
+        viewer->start();
+    }
 
     return 0;
-#endif
 }
diff --git a/Examples/VolumeRendering/CMakeLists.txt b/Examples/VolumeRendering/CMakeLists.txt
index db6393841ce748a029762a5e57238f2a50a660d4..dc3e9e015f50de8a6ff4b43bfd6ea6440622740f 100644
--- a/Examples/VolumeRendering/CMakeLists.txt
+++ b/Examples/VolumeRendering/CMakeLists.txt
@@ -36,4 +36,4 @@ SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples)
 #-----------------------------------------------------------------------------
 # Link libraries to executable
 #-----------------------------------------------------------------------------
-target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities)
+target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities Filtering)
diff --git a/Examples/VolumeRendering/VolumeRenderingExample.cpp b/Examples/VolumeRendering/VolumeRenderingExample.cpp
index 97e96ed9d5527c3da31378a4784be155fa2cfc97..b67ad55f671d44c16a2600c02674a033d3671ef5 100644
--- a/Examples/VolumeRendering/VolumeRenderingExample.cpp
+++ b/Examples/VolumeRendering/VolumeRenderingExample.cpp
@@ -9,7 +9,7 @@
    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
+	  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,
@@ -19,21 +19,21 @@
 
 =========================================================================*/
 
-// imstk
-#include "imstkAPIUtilities.h"
 #include "imstkCamera.h"
+#include "imstkImageData.h"
+#include "imstkKeyboardSceneControl.h"
 #include "imstkMeshIO.h"
-#include "imstkSimulationManager.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObject.h"
+#include "imstkVisualModel.h"
 #include "imstkVolumeRenderMaterial.h"
 #include "imstkVolumeRenderMaterialPresets.h"
-#include "imstkVTKTextStatusManager.h"
-#include "imstkSceneManager.h"
-#include "imstkScene.h"
 #include "imstkVTKRenderer.h"
-
-// STL
-#include <sstream>
-#include <string>
+#include "imstkVTKTextStatusManager.h"
+#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -44,35 +44,35 @@ int
 main()
 {
     // SDK and Scene
-    auto simManager = std::make_shared<SimulationManager>();
-    auto scene      = simManager->createNewScene("VolumeRendering");
-    simManager->setActiveScene(scene);
+    imstkNew<Scene> scene("VolumeRendering");
 
-    // Use MeshIO to read the image dataset
-    auto imageData = imstk::MeshIO::read(iMSTK_DATA_ROOT "skullVolume.nrrd");
     // Create a visual object in the scene for the volume
-    auto volumeObj = std::make_shared<imstk::VisualObject>("VisualVolume");
+    imstkNew<VisualObject> volumeObj("VisualVolume");
+    auto                   imageData = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "skullVolume.nrrd");
     volumeObj->setVisualGeometry(imageData);
     scene->addSceneObject(volumeObj);
 
     // Update Camera to position volume close to viewer
-    auto cam = scene->getCamera();
-    cam->setPosition(Vec3d(0, -200, -50));
-    cam->setFocalPoint(Vec3d(0, 0, -50));
+    auto cam = scene->getActiveCamera();
+    cam->setPosition(Vec3d(0.0, -200.0, -100.0));
+    cam->setFocalPoint(Vec3d(0.0, 0.0, -50.0));
     cam->setViewUp(Vec3d(0.02, 0.4, 0.9));
 
     int count = 0;
-    // Get VTK Renderer
-    auto viewer   = std::dynamic_pointer_cast<VTKViewer>(simManager->getViewer());
+
+    // Setup a viewer to render in its own thread
+    imstkNew<VTKViewer> viewer("Viewer");
+    viewer->setActiveScene(scene);
+
     auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer());
     renderer->updateBackground(Vec3d(0.3285, 0.3285, 0.6525), Vec3d(0.13836, 0.13836, 0.2748), true);
 
     auto statusManager = viewer->getTextStatusManager();
-    statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30);
-    statusManager->setStatusDisplayCorner(VTKTextStatusManager::Custom, VTKTextStatusManager::DisplayCorner::UpperLeft);
+    statusManager->setStatusFontSize(VTKTextStatusManager::StatusType::Custom, 30);
+    statusManager->setStatusDisplayCorner(VTKTextStatusManager::StatusType::Custom, VTKTextStatusManager::DisplayCorner::UpperLeft);
 
     auto updateFunc =
-        [&](Module*) {
+        [&](Event*) {
             if (count % 2)
             {
                 // Change the render material every other frame
@@ -101,9 +101,29 @@ main()
             // Delay to show the past frame
             std::this_thread::sleep_for(std::chrono::milliseconds(2000));
         };
-    simManager->getSceneManager(scene)->setPreUpdateCallback(updateFunc);
-    // Run
-    simManager->start();
+
+    // Run the simulation
+    {
+        // Setup a scene manager to advance the scene in its own thread
+        imstkNew<SceneManager> sceneManager("Scene Manager");
+        sceneManager->setActiveScene(scene);
+        viewer->addChildThread(sceneManager); // SceneManager will start/stop with viewer
+        connect<Event>(sceneManager, EventType::PostUpdate, updateFunc);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setViewer(viewer);
+            viewer->addControl(keyControl);
+        }
+
+        viewer->start();
+    }
 
     return 0;
 }
diff --git a/README.md b/README.md
index e2bc6473fe8d703593d6213b6b023c31095adbde..1657e989537780be5215d18cd2e8b0281d5ef6fc 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@
 - [CeMSIM-Rensselaer Polytechnic Institute](http://cemsim.rpi.edu/)
 - [University of Central Arkansas](http://sun0.cs.uca.edu/~thalic/virasim.html)
 
-####Funding support:
+### Funding support:
 This project is supported in part by the following grants [9R44OD018334](https://www.sbir.gov/sbirsearch/detail/1032259), [1R44EB019802](https://www.sbir.gov/sbirsearch/detail/1047037), [1R44AR075481](https://projectreporter.nih.gov/project_info_details.cfm?aid=9777225&icde=50531419) , [1R01EB025247](https://projectreporter.nih.gov/project_info_details.cfm?aid=9738646&icde=50531433), [2R44DK115332](https://projectreporter.nih.gov/project_info_details.cfm?aid=9843084&icde=50531443)
 
 Disclaimer: The content is solely the responsibility of the authors and does not necessarily represent the official views of the NIH and its institutes.
diff --git a/Source/Animation/Particles/imstkRenderParticleEmitter.cpp b/Source/Animation/Particles/imstkRenderParticleEmitter.cpp
index 0cf3c618e03203587e5126221bbb6b9eb36918cf..627dc6cc39a02512208893d722ce2693a7c614b3 100644
--- a/Source/Animation/Particles/imstkRenderParticleEmitter.cpp
+++ b/Source/Animation/Particles/imstkRenderParticleEmitter.cpp
@@ -20,22 +20,20 @@
 =========================================================================*/
 
 #include "imstkRenderParticleEmitter.h"
-#include "imstkColor.h"
 #include "imstkLogger.h"
+#include "imstkRenderParticles.h"
+#include "imstkTimer.h"
 
 namespace imstk
 {
 RenderParticleEmitter::RenderParticleEmitter(std::shared_ptr<Geometry>   geometry,
                                              const float                 time /*= 3000*/,
                                              RenderParticleEmitter::Mode mode /*= Mode::CONTINUOUS*/)
-    : AnimationModel(geometry)
+    : AnimationModel(geometry),
+    m_stopWatch(std::make_unique<StopWatch>()), m_time(time), m_emitTime(m_time), m_mode(mode)
 {
     this->setGeometry(geometry);
 
-    m_time     = time;
-    m_emitTime = m_time;
-    m_mode     = mode;
-
     RenderParticleKeyFrame startFrame;
     startFrame.m_color = Color::White;
     startFrame.m_time  = 0.0f;
@@ -165,11 +163,11 @@ RenderParticleEmitter::update()
 
     if (!m_started)
     {
-        m_stopWatch.start();
+        m_stopWatch->start();
         m_started = true;
     }
 
-    auto  time = m_stopWatch.getTimeElapsed();
+    auto  time = m_stopWatch->getTimeElapsed();
     float dt   = (float)(time - m_lastUpdateTime);
     m_lastUpdateTime = time;
 
diff --git a/Source/Animation/Particles/imstkRenderParticleEmitter.h b/Source/Animation/Particles/imstkRenderParticleEmitter.h
index 996e5c470970d09cf2278350450fbd23bdfe321e..33b789ea1c62d845969092ee61152759939f9dc7 100644
--- a/Source/Animation/Particles/imstkRenderParticleEmitter.h
+++ b/Source/Animation/Particles/imstkRenderParticleEmitter.h
@@ -23,13 +23,12 @@
 
 #include "imstkMath.h"
 #include "imstkAnimationModel.h"
-#include "imstkRenderParticles.h"
-#include "imstkTimer.h"
 #include "imstkColor.h"
 
 namespace imstk
 {
-//struct Color;
+struct RenderParticle;
+class StopWatch;
 
 ///
 /// \struct RenderParticleKeyFrame
@@ -191,7 +190,7 @@ protected:
     float m_time; ///< total time for particle system
     float m_emitTime;
 
-    StopWatch m_stopWatch;
+    std::unique_ptr<StopWatch> m_stopWatch;
 
     double m_lastUpdateTime = 0.0;
     bool   m_started = false;
diff --git a/Source/CollisionDetection/CollisionData/imstkCollisionData.h b/Source/CollisionDetection/CollisionData/imstkCollisionData.h
index 1ce677afb68837a364462647bc7c513bcb18d27a..8e49cd85a385f6fb3063e58899a5d878d6bec669 100644
--- a/Source/CollisionDetection/CollisionData/imstkCollisionData.h
+++ b/Source/CollisionDetection/CollisionData/imstkCollisionData.h
@@ -21,13 +21,12 @@
 
 #pragma once
 
-#include <array>
-#include <algorithm>
-
-#include "imstkMath.h"
 #include "imstkLogger.h"
+#include "imstkMath.h"
 #include "imstkParallelUtils.h"
 
+#include <array>
+
 namespace imstk
 {
 template<class DataElement>
@@ -111,6 +110,7 @@ struct PositionDirectionCollisionDataElement
     Vec3d posA;
     Vec3d posB;
     Vec3d dirAtoB;
+    uint32_t nodeIdx;
     double penetrationDepth;
 };
 class PositionDirectionCollisionData : public CollisionDataBase<PositionDirectionCollisionDataElement>
diff --git a/Source/CollisionDetection/CollisionDetection/imstkBidirectionalPlaneToSphereCD.h b/Source/CollisionDetection/CollisionDetection/imstkBidirectionalPlaneToSphereCD.h
index 7a8460f22a83b7bf7fe71617de3db8f68d09b39c..50063ed05f0474e8f80760d9ee1192bc507e571a 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkBidirectionalPlaneToSphereCD.h
+++ b/Source/CollisionDetection/CollisionDetection/imstkBidirectionalPlaneToSphereCD.h
@@ -27,7 +27,6 @@ namespace imstk
 {
 class Plane;
 class Sphere;
-class Geometry;
 struct CollisionData;
 
 ///
diff --git a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp
index f6999298191a1c413775e78ab8eb9f8504a16493..a29e86c6f131368b1880e0b6fbc7d4aed660ef72 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp
@@ -21,10 +21,9 @@
 
 #include "imstkCollisionDetection.h"
 #include "imstkCollisionData.h"
-#include "imstkTaskNode.h"
-#include "imstkLogger.h"
 #include "imstkOctreeBasedCD.h"
 #include "imstkSurfaceMesh.h"
+#include "imstkTaskNode.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.h b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.h
index a1be7c2f1761c7a040545f7c88f63c60ec538426..b2c17c752859db5e56575a17a5e023141b5bfc5e 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.h
+++ b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.h
@@ -46,12 +46,13 @@ public:
     ///
     enum class Type
     {
-        // Points to objects
+        // Points to analytical geometry
         PointSetToSphere,
         PointSetToPlane,
         PointSetToCapsule,
         PointSetToSpherePicking,
         PointSetToSurfaceMesh,
+        PointSetToImplicit,
 
         // Mesh to mesh (mesh to analytical object = mesh vertices to analytical object)
         SurfaceMeshToSurfaceMesh,
@@ -65,9 +66,6 @@ public:
         SphereToCylinder,
         SphereToSphere,
 
-        // Image based CD
-        SignedDistanceField,
-
         Custom
     };
 
diff --git a/Source/CollisionDetection/CollisionDetection/imstkCollisionUtils.h b/Source/CollisionDetection/CollisionDetection/imstkCollisionUtils.h
index 72652233599915cc63fccaf5e61fd03c4c2ae550..566a20a645b5c92ef70aea744db66ee307ffb7e7 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkCollisionUtils.h
+++ b/Source/CollisionDetection/CollisionDetection/imstkCollisionUtils.h
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "imstkMath.h"
+
 #include <algorithm>
 
 namespace imstk
diff --git a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e063b5404c85a2d61244a38b109b10f548970346
--- /dev/null
+++ b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp
@@ -0,0 +1,69 @@
+/*=========================================================================
+
+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 "imstkImplicitGeometryToPointSetCD.h"
+#include "imstkCollisionData.h"
+#include "imstkImplicitGeometry.h"
+#include "imstkMath.h"
+#include "imstkPointSet.h"
+
+#include "imstkSignedDistanceField.h"
+#include "imstkImageData.h"
+
+namespace imstk
+{
+ImplicitGeometryToPointSetCD::ImplicitGeometryToPointSetCD(std::shared_ptr<ImplicitGeometry> implicitGeomA,
+                                                           std::shared_ptr<PointSet>         pointSetB,
+                                                           std::shared_ptr<CollisionData>    colData) :
+    CollisionDetection(CollisionDetection::Type::PointSetToImplicit, colData),
+    m_implicitGeomA(implicitGeomA),
+    m_pointSetB(pointSetB)
+{
+    centralGrad.setFunction(m_implicitGeomA);
+    if (m_implicitGeomA->getType() == Geometry::Type::SignedDistanceField)
+    {
+        centralGrad.setDx(std::dynamic_pointer_cast<SignedDistanceField>(m_implicitGeomA)->getImage()->getSpacing());
+    }
+}
+
+void
+ImplicitGeometryToPointSetCD::computeCollisionData()
+{
+    m_colData->clearAll();
+
+    ParallelUtils::parallelFor(m_pointSetB->getVertexPositions().size(),
+        [&](const size_t idx)
+        {
+            const Vec3d& pt = m_pointSetB->getVertexPosition(idx);
+
+            const double signedDistance = m_implicitGeomA->getFunctionValue(pt);
+            if (signedDistance < 0.0)
+            {
+                PositionDirectionCollisionDataElement elem;
+                elem.dirAtoB = -centralGrad(pt).normalized(); // Contact Normal
+                elem.nodeIdx = static_cast<uint32_t>(idx);
+                elem.penetrationDepth = std::abs(signedDistance);
+                elem.posB = pt;
+                m_colData->PDColData.safeAppend(elem);
+            }
+        });
+}
+}
\ No newline at end of file
diff --git a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.h b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f35b03636607a052b9bdf2ff993f01ff9065f85
--- /dev/null
+++ b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.h
@@ -0,0 +1,61 @@
+/*=========================================================================
+
+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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkCollisionDetection.h"
+#include "imstkImplicitFunctionFiniteDifferenceFunctor.h"
+
+namespace imstk
+{
+class ImplicitGeometry;
+class PointSet;
+struct CollisionData;
+
+///
+/// \class ImplicitGeometryToPointSetCD
+///
+/// \brief ImplicitGeometry to PointSet collision detection.
+///
+class ImplicitGeometryToPointSetCD : public CollisionDetection
+{
+public:
+    ///
+    /// \brief
+    /// \param ImplicitGeometry
+    /// \param PointSet to test collision with
+    /// \param CollisionData to write too
+    ///
+    ImplicitGeometryToPointSetCD(std::shared_ptr<ImplicitGeometry> implicitGeomA,
+                                 std::shared_ptr<PointSet>         pointSetB,
+                                 std::shared_ptr<CollisionData>    colData);
+
+    ///
+    /// \brief Detect collision and compute collision data
+    ///
+    void computeCollisionData() override;
+
+private:
+    std::shared_ptr<ImplicitGeometry> m_implicitGeomA;
+    std::shared_ptr<PointSet>       m_pointSetB;
+    ImplicitFunctionCentralGradient centralGrad;
+};
+}
\ No newline at end of file
diff --git a/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp
index a59e0ab21367088465ab2bdec6a256b05f68c373..49901d296be6567bf1b6da08f3f063fe3939df36 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp
@@ -20,17 +20,10 @@
 =========================================================================*/
 
 #include "imstkMeshToMeshBruteForceCD.h"
-
-//#include "imstkCollidingObject.h"
 #include "imstkCollisionData.h"
-#include "imstkSurfaceMesh.h"
-#include "imstkPointSet.h"
-#include "imstkLineMesh.h"
-#include "imstkGeometry.h"
-//#include "imstkColor.h"
 #include "imstkCollisionUtils.h"
-
-#include <g3log/g3log.hpp>
+#include "imstkLineMesh.h"
+#include "imstkSurfaceMesh.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp
index f9ca5f77282f58085536a668014ee25c940d321b..d6fe6dcea7feaf8d93ba91602ea39a5cc0f0ddd7 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp
@@ -20,14 +20,12 @@
 =========================================================================*/
 
 #include "imstkNarrowPhaseCD.h"
-#include "imstkCollisionUtils.h"
-
-#include "imstkLogger.h"
+#include "imstkCapsule.h"
 #include "imstkCollisionData.h"
+#include "imstkCollisionUtils.h"
+#include "imstkCylinder.h"
 #include "imstkPlane.h"
 #include "imstkSphere.h"
-#include "imstkCapsule.h"
-#include "imstkCylinder.h"
 #include "imstkSurfaceMesh.h"
 
 namespace imstk
@@ -80,9 +78,12 @@ bidirectionalPlaneToSphere(Plane* const planeA, Sphere* const sphereB,
     Vec3d sphereBColPt = sphereBPos - dirAToB * r;
 
     // Set collisionData
-    colData->PDColData.safeAppend({ planeAColPt,
-                                    sphereBColPt,
-                                    dirAToB, penetrationDepth });
+    PositionDirectionCollisionDataElement elem;
+    elem.dirAtoB = dirAToB;
+    elem.penetrationDepth = penetrationDepth;
+    elem.posA = planeAColPt;
+    elem.posB = sphereBColPt;
+    colData->PDColData.safeAppend(elem);
 }
 
 void
@@ -124,9 +125,12 @@ unidirectionalPlaneToSphere(Plane* const plane, Sphere* const sphere,
     Vec3d sphereBColPt = sphereBPos - n * r;
 
     // Set collisionData
-    colData->PDColData.safeAppend({ planeAColPt,
-                                    sphereBColPt,
-                                    n, penetrationDepth });
+    PositionDirectionCollisionDataElement elem;
+    elem.dirAtoB = n;
+    elem.penetrationDepth = penetrationDepth;
+    elem.posA = planeAColPt;
+    elem.posB = sphereBColPt;
+    colData->PDColData.safeAppend(elem);
 }
 
 void
@@ -171,9 +175,12 @@ sphereToCylinder(Sphere* const sphere, Cylinder* const cylinder,
                           n * rCylinder;
 
     // Set collisionData
-    colData->PDColData.safeAppend({ sphereColPt,
-                                    cylinderColPt,
-                                    n, penetrationDepth });
+    PositionDirectionCollisionDataElement elem;
+    elem.dirAtoB = n;
+    elem.penetrationDepth = penetrationDepth;
+    elem.posA = sphereColPt;
+    elem.posB = cylinderColPt;
+    colData->PDColData.safeAppend(elem);
 }
 
 void
@@ -218,9 +225,12 @@ sphereToSphere(Sphere* const sphereA, Sphere* const sphereB,
     Vec3d sphereBColPt = sphereBPos - dirAToB * rB;
 
     // Set collisionData
-    colData->PDColData.safeAppend({ sphereAColPt,
-                                    sphereBColPt,
-                                    dirAToB, penetrationDepth });
+    PositionDirectionCollisionDataElement elem;
+    elem.dirAtoB = dirAToB;
+    elem.penetrationDepth = penetrationDepth;
+    elem.posA = sphereAColPt;
+    elem.posB = sphereBColPt;
+    colData->PDColData.safeAppend(elem);
 }
 
 void
diff --git a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.h b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.h
index bcb6b7c33575bd05968c8e07ec87b6448662dfb7..d3f937d6c58734bf4d8a8fa902346321042b3024 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.h
+++ b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.h
@@ -21,10 +21,10 @@
 
 #pragma once
 
-#include <memory>
-
 #include "imstkMath.h"
 
+#include <memory>
+
 namespace imstk
 {
 struct CollisionData;
diff --git a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp
index f290aec5f38e33d6bdf7dd25e88d5fc6f98d652f..cf9da3d9ededae4f4771c34dff4641bcdeb749d5 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp
@@ -20,15 +20,10 @@
 =========================================================================*/
 
 #include "imstkOctreeBasedCD.h"
-
-#include "imstkGeometry.h"
-#include "imstkPointSet.h"
-#include "imstkSurfaceMesh.h"
-
-// Collision detection headers
-#include "imstkNarrowPhaseCD.h"
 #include "imstkCollisionData.h"
 #include "imstkCollisionUtils.h"
+#include "imstkGeometry.h"
+#include "imstkNarrowPhaseCD.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.h b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.h
index 01778ee68451ed2a877b9e80313bce5d6931eecb..f39ab1b517b71330e8711314e053d33192fb5a16 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.h
+++ b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.h
@@ -71,7 +71,7 @@ public:
     ///
     void addCollisionPair(const std::shared_ptr<Geometry>& geom1, const std::shared_ptr<Geometry>& geom2,
                           const CollisionDetection::Type collisionType,
-                          const std::shared_ptr<CollisionData>& collisionData = std::make_shared<CollisionData>());
+                          const std::shared_ptr<CollisionData>& collisionData);
 
     ///
     /// \brief Get pairs of geometries from the added collision pairs
diff --git a/Source/CollisionDetection/CollisionDetection/imstkPointSetToCapsuleCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkPointSetToCapsuleCD.cpp
index 800d90bf313021274ccdb584277760ba44ebdacc..d2ae737d88e43163cb73fc6c686c41e94a5c5ca0 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkPointSetToCapsuleCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkPointSetToCapsuleCD.cpp
@@ -20,9 +20,8 @@
 =========================================================================*/
 
 #include "imstkPointSetToCapsuleCD.h"
-#include "imstkNarrowPhaseCD.h"
 #include "imstkCollisionData.h"
-#include "imstkParallelUtils.h"
+#include "imstkNarrowPhaseCD.h"
 #include "imstkPointSet.h"
 
 namespace imstk
diff --git a/Source/CollisionDetection/CollisionDetection/imstkPointSetToPlaneCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkPointSetToPlaneCD.cpp
index 9d6ca6638409550f16f41989d51037d326bd26e6..f27e80cafc974ea1b02ac384589c3868dfe4298e 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkPointSetToPlaneCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkPointSetToPlaneCD.cpp
@@ -20,9 +20,8 @@
 =========================================================================*/
 
 #include "imstkPointSetToPlaneCD.h"
-#include "imstkNarrowPhaseCD.h"
 #include "imstkCollisionData.h"
-#include "imstkParallelUtils.h"
+#include "imstkNarrowPhaseCD.h"
 #include "imstkPointSet.h"
 
 namespace imstk
diff --git a/Source/CollisionDetection/CollisionDetection/imstkPointSetToSphereCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkPointSetToSphereCD.cpp
index 6365dbd41fa06de876b2a17ed5342e0a68d45a01..3268060339e61c7c2306143436a48cdb807bbdf6 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkPointSetToSphereCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkPointSetToSphereCD.cpp
@@ -20,9 +20,8 @@
 =========================================================================*/
 
 #include "imstkPointSetToSphereCD.h"
-#include "imstkNarrowPhaseCD.h"
 #include "imstkCollisionData.h"
-#include "imstkParallelUtils.h"
+#include "imstkNarrowPhaseCD.h"
 #include "imstkPointSet.h"
 
 namespace imstk
diff --git a/Source/CollisionDetection/CollisionDetection/imstkPointSetToSurfaceMeshCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkPointSetToSurfaceMeshCD.cpp
index 81569e9d8c08569f472fa2ccbc5fc116b4a61cc7..60631ce7706c0465ea9ed87840fd0caefa2aa75e 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkPointSetToSurfaceMeshCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkPointSetToSurfaceMeshCD.cpp
@@ -20,10 +20,8 @@
 =========================================================================*/
 
 #include "imstkPointSetToSurfaceMeshCD.h"
-#include "imstkCollisionData.h"
-#include "imstkPointSet.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkOctreeBasedCD.h"
+#include "imstkSurfaceMesh.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionDetection/CollisionDetection/imstkSphereToCylinderCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkSphereToCylinderCD.cpp
index 7a741535575383e04b251abf8e4890a643f81d56..d854828691d127bf440125fe0d03d64cde001259 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkSphereToCylinderCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkSphereToCylinderCD.cpp
@@ -20,8 +20,8 @@
    =========================================================================*/
 
 #include "imstkSphereToCylinderCD.h"
-#include "imstkNarrowPhaseCD.h"
 #include "imstkCollisionData.h"
+#include "imstkNarrowPhaseCD.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionDetection/CollisionDetection/imstkSphereToSphereCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkSphereToSphereCD.cpp
index 027def93ffc03b59b9cfea645ac86a2c3ccaff2f..d446647d5a7c60a38b4c985a40523503d0afa72e 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkSphereToSphereCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkSphereToSphereCD.cpp
@@ -20,8 +20,8 @@
 =========================================================================*/
 
 #include "imstkSphereToSphereCD.h"
-#include "imstkNarrowPhaseCD.h"
 #include "imstkCollisionData.h"
+#include "imstkNarrowPhaseCD.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp
index 49ed12f5936fbb85171110419d46c7802de0d221..abf16ea123ab45427b8cf42a9bb009590b5143e1 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp
@@ -20,9 +20,9 @@
 =========================================================================*/
 
 #include "imstkSurfaceMeshToSurfaceMeshCCD.h"
+#include "DeformModel.h"
 #include "imstkCollisionData.h"
 #include "imstkSurfaceMesh.h"
-#include "DeformModel.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCD.cpp
index 7eebc044aef0b927637a3d5f09d19cc22b415dcc..da33e3a9f77354169f335825c3336dbd6c8843c1 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCD.cpp
@@ -20,10 +20,8 @@
 =========================================================================*/
 
 #include "imstkSurfaceMeshToSurfaceMeshCD.h"
-#include "imstkNarrowPhaseCD.h"
-#include "imstkCollisionData.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkOctreeBasedCD.h"
+#include "imstkSurfaceMesh.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.cpp
index afb078990007d1dccbb296f60d451370e703ba47..47de40b98f69b6d37f5d0055a60776f151eaa312 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.cpp
@@ -21,13 +21,8 @@
 
 #include "imstkTetraToTetraCD.h"
 #include "imstkCollisionData.h"
-#include "imstkMath.h"
-#include "imstkParallelUtils.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkTetrahedralMesh.h"
 
-//#include "DeformModel.h"
-
 namespace imstk
 {
 TetraToTetraCD::TetraToTetraCD(std::shared_ptr<TetrahedralMesh> meshA,
diff --git a/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.h b/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.h
index 9403bdb53d0a9fe1ede5de4ca2584345057a5e92..ff20c99589b1f99ab8188974e166295e80e2a5fc 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.h
+++ b/Source/CollisionDetection/CollisionDetection/imstkTetraToTetraCD.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkCollisionDetection.h"
 #include "imstkSpatialHashTableSeparateChaining.h"
 
diff --git a/Source/CollisionDetection/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp
index 05c82062aa4b25b55dde8db3fe729cf3cafb4548..44c7984e6427c97d6611f5ec4939d7a9ec267413 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp
@@ -20,8 +20,8 @@
    =========================================================================*/
 
 #include "imstkUnidirectionalPlaneToSphereCD.h"
-#include "imstkNarrowPhaseCD.h"
 #include "imstkCollisionData.h"
+#include "imstkNarrowPhaseCD.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionDetection/Testing/imstkOctreeBasedCDTest.cpp b/Source/CollisionDetection/Testing/imstkOctreeBasedCDTest.cpp
index 302a489fd75ca8c2cc41c6b1c6c6dd1bd64f32c4..fb8174927b1c88c413d52e03c3e899e4d7b8e47a 100644
--- a/Source/CollisionDetection/Testing/imstkOctreeBasedCDTest.cpp
+++ b/Source/CollisionDetection/Testing/imstkOctreeBasedCDTest.cpp
@@ -19,22 +19,16 @@
 
 =========================================================================*/
 
-#include "gtest/gtest.h"
-#include "gmock/gmock.h"
+#include <gtest/gtest.h>
 
-#include "imstkMath.h"
-#include "imstkSphere.h"
-#include "imstkPointSet.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkCollisionData.h"
 #include "imstkNarrowPhaseCD.h"
-
 #include "imstkOctreeBasedCD.h"
 #include "imstkPointSetToSurfaceMeshCD.h"
+#include "imstkSphere.h"
+#include "imstkSurfaceMesh.h"
 #include "imstkSurfaceMeshToSurfaceMeshCD.h"
 
-#include <iostream>
-#include <unordered_set>
 #include <unordered_map>
 
 using namespace imstk;
@@ -230,7 +224,7 @@ public:
         }
 
         // Detect penetration using octree
-        m_OctreeCD->addCollisionPair(pointset, mesh, CollisionDetection::Type::PointSetToSurfaceMesh);
+        m_OctreeCD->addCollisionPair(pointset, mesh, CollisionDetection::Type::PointSetToSurfaceMesh, std::make_shared<CollisionData>());
         m_OctreeCD->detectCollision();
         const auto collisionData = m_OctreeCD->getCollisionPairData(pointset->getGlobalIndex(), mesh->getGlobalIndex());
 #ifdef PRINT_DEBUG
@@ -335,7 +329,7 @@ public:
         }
 
         // Detect penetration using octree
-        m_OctreeCD->addCollisionPair(pointset, sphere, CollisionDetection::Type::PointSetToSphere);
+        m_OctreeCD->addCollisionPair(pointset, sphere, CollisionDetection::Type::PointSetToSphere, std::make_shared<CollisionData>());
         m_OctreeCD->detectCollision();
         const auto collisionData = m_OctreeCD->getCollisionPairData(pointset->getGlobalIndex(), sphere->getGlobalIndex());
 #ifdef PRINT_DEBUG
@@ -393,7 +387,7 @@ public:
         }
 
         // Detect collision using octree
-        m_OctreeCD->addCollisionPair(mesh, box, CollisionDetection::Type::SurfaceMeshToSurfaceMesh);
+        m_OctreeCD->addCollisionPair(mesh, box, CollisionDetection::Type::SurfaceMeshToSurfaceMesh, std::make_shared<CollisionData>());
         m_OctreeCD->detectCollision();
         collisionData = m_OctreeCD->getCollisionPairData(mesh->getGlobalIndex(), box->getGlobalIndex());
 #ifdef PRINT_DEBUG
diff --git a/Source/CollisionDetection/Testing/imstkTetraToTetraCDTest.cpp b/Source/CollisionDetection/Testing/imstkTetraToTetraCDTest.cpp
index 49536eb89ffde4edffe624c2ef54f9d191d881be..43df34ecb838e4f9436c762b584ac6f2f51e7003 100644
--- a/Source/CollisionDetection/Testing/imstkTetraToTetraCDTest.cpp
+++ b/Source/CollisionDetection/Testing/imstkTetraToTetraCDTest.cpp
@@ -20,9 +20,6 @@
 =========================================================================*/
 
 #include "gtest/gtest.h"
-#include "gmock/gmock.h"
-
-#include  <memory>
 
 #include "imstkCollisionData.h"
 #include "imstkMeshIO.h"
diff --git a/Source/CollisionDetection/imstkCDObjectFactory.cpp b/Source/CollisionDetection/imstkCDObjectFactory.cpp
index 668990d220005b1e0974f328ba32820441ed2c1e..1697264d87555976defde20676af24c5a45e35a3 100644
--- a/Source/CollisionDetection/imstkCDObjectFactory.cpp
+++ b/Source/CollisionDetection/imstkCDObjectFactory.cpp
@@ -21,14 +21,13 @@ limitations under the License.
 
 #include "imstkCDObjectFactory.h"
 #include "imstkCollisionData.h"
-#include "imstkOctreeBasedCD.h"
 
 // Points to objects
 #include "imstkPointSetToCapsuleCD.h"
 #include "imstkPointSetToPlaneCD.h"
 #include "imstkPointSetToSphereCD.h"
-#include "imstkPointSetToSpherePickingCD.h"
 #include "imstkPointSetToSurfaceMeshCD.h"
+#include "imstkImplicitGeometryToPointSetCD.h"
 
 // Mesh to mesh
 #include "imstkMeshToMeshBruteForceCD.h"
@@ -45,125 +44,165 @@ limitations under the License.
 // Geometry
 #include "imstkCapsule.h"
 #include "imstkCylinder.h"
-#include "imstkImageData.h"
+#include "imstkImplicitGeometry.h"
 #include "imstkPlane.h"
 #include "imstkSphere.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkTetrahedralMesh.h"
 
-#define IMSTK_CHECK_FOR_VALID_GEOMETRIES(obj1, obj2)                                           \
-    LOG_IF(FATAL, (obj1 == nullptr || obj2 == nullptr)) <<                                     \
-        "CollisionDetection::makeCollisionDetectionObject() error: " <<                        \
-        "Invalid object geometries were provided for the given collision detection type.\n" << \
-        "    Line: " << __LINE__ << ", File: " << __FILE__;
+#define IMSTK_CHECK_FOR_VALID_GEOMETRIES(obj1, obj2, Type1, Type2) \
+    checkValidGeometry<Type1, Type2>(obj1, obj2, #Type1, #Type2);
 
 namespace imstk
 {
+template<typename T1, typename T2>
+void
+checkValidGeometry(std::shared_ptr<Geometry> geom1, std::shared_ptr<Geometry> geom2, std::string t1TypeName, std::string t2TypeName)
+{
+    std::string errorMsg = "Invalid object geometries were provided for the collision detection type.\n";
+    bool        fail     = false;
+    if (std::dynamic_pointer_cast<T1>(geom1) == nullptr)
+    {
+        errorMsg += "Geometry 1 expected " + t1TypeName + " but got " + geom1->getTypeName() + ".\n";
+        fail      = true;
+    }
+    if (std::dynamic_pointer_cast<T2>(geom2) == nullptr)
+    {
+        errorMsg += "Geometry 2 expected " + t2TypeName + " but got " + geom2->getTypeName() + ".\n";
+        fail      = true;
+    }
+
+    if (fail)
+    {
+        LOG(FATAL) << errorMsg;
+    }
+}
+
 std::shared_ptr<CollisionDetection>
 makeCollisionDetectionObject(const CollisionDetection::Type type,
                              std::shared_ptr<Geometry>      collidingGeometryA,
                              std::shared_ptr<Geometry>      collidingGeometryB,
                              std::shared_ptr<CollisionData> colData)
 {
+    if (collidingGeometryA == nullptr)
+    {
+        LOG(FATAL) << "Collision Geometry A nullptr";
+    }
+    if (collidingGeometryB == nullptr)
+    {
+        LOG(FATAL) << "Collision Geometry B nullptr";
+    }
+
     switch (type)
     {
     // Points to objects
     case CollisionDetection::Type::PointSetToSphere:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, Sphere);
+
         auto pointset = std::dynamic_pointer_cast<PointSet>(collidingGeometryA);
         auto sphere   = std::dynamic_pointer_cast<Sphere>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, sphere)
         return std::make_shared<PointSetToSphereCD>(pointset, sphere, colData);
     }
     case CollisionDetection::Type::PointSetToPlane:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, Sphere);
+
         auto pointset = std::dynamic_pointer_cast<PointSet>(collidingGeometryA);
         auto plane    = std::dynamic_pointer_cast<Plane>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, plane)
         return std::make_shared<PointSetToPlaneCD>(pointset, plane, colData);
     }
     case CollisionDetection::Type::PointSetToCapsule:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, Capsule);
+
         auto pointset = std::dynamic_pointer_cast<PointSet>(collidingGeometryA);
         auto capsule  = std::dynamic_pointer_cast<Capsule>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, capsule)
         return std::make_shared<PointSetToCapsuleCD>(pointset, capsule, colData);
     }
-#if 0
-    case CollisionDetection::ype::PointSetToSpherePicking:
-    {
-        auto pointset = std::dynamic_pointer_cast<PointSet>(objA->getCollidingGeometry());
-        auto sphere   = std::dynamic_pointer_cast<Sphere>(objB->getCollidingGeometry());
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, sphere)
-        return std::make_shared<PointSetToSpherePickingCD>(pointset, sphere, colData);
-    }
-#endif
     case CollisionDetection::Type::PointSetToSurfaceMesh:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, SurfaceMesh);
+
         auto pointset = std::dynamic_pointer_cast<PointSet>(collidingGeometryA);
         auto triMesh  = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(pointset, triMesh)
         CollisionDetection::addCollisionPairToOctree(collidingGeometryA, collidingGeometryB, type, colData);
         return std::make_shared<PointSetToSurfaceMeshCD>(pointset, triMesh, colData);
     }
+    case CollisionDetection::Type::PointSetToImplicit:
+    {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, PointSet, ImplicitGeometry);
+
+        auto pointSet     = std::dynamic_pointer_cast<PointSet>(collidingGeometryA);
+        auto implicitGeom = std::dynamic_pointer_cast<ImplicitGeometry>(collidingGeometryB);
+        return std::make_shared<ImplicitGeometryToPointSetCD>(implicitGeom, pointSet, colData);
+    }
     // Mesh to mesh
     case CollisionDetection::Type::SurfaceMeshToSurfaceMesh:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, SurfaceMesh, SurfaceMesh);
+
         auto meshA = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryA);
         auto meshB = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(meshA, meshB)
         CollisionDetection::addCollisionPairToOctree(collidingGeometryA, collidingGeometryB, type, colData);
         return std::make_shared<SurfaceMeshToSurfaceMeshCD>(meshA, meshB, colData);
     }
     case CollisionDetection::Type::SurfaceMeshToSurfaceMeshCCD:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, SurfaceMesh, SurfaceMesh);
+
         auto meshA = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryA);
         auto meshB = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(meshA, meshB)
         return std::make_shared<SurfaceMeshToSurfaceMeshCCD>(meshA, meshB, colData);
     }
 
     case CollisionDetection::Type::VolumeMeshToVolumeMesh:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, TetrahedralMesh, TetrahedralMesh);
+
         auto tet1 = std::dynamic_pointer_cast<TetrahedralMesh>(collidingGeometryA);
         auto tet2 = std::dynamic_pointer_cast<TetrahedralMesh>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(tet1, tet2)
         return std::make_shared<TetraToTetraCD>(tet1, tet2, colData);
     }
 
     // Analytical object to analytical object
     case CollisionDetection::Type::UnidirectionalPlaneToSphere:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Plane, Sphere);
+
         auto plane  = std::dynamic_pointer_cast<Plane>(collidingGeometryA);
         auto sphere = std::dynamic_pointer_cast<Sphere>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(plane, sphere)
         return std::make_shared<UnidirectionalPlaneToSphereCD>(plane, sphere, colData);
     }
     case CollisionDetection::Type::BidirectionalPlaneToSphere:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Plane, Sphere);
+
         auto plane  = std::dynamic_pointer_cast<Plane>(collidingGeometryA);
         auto sphere = std::dynamic_pointer_cast<Sphere>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(plane, sphere)
         return std::make_shared<BidirectionalPlaneToSphereCD>(plane, sphere, colData);
     }
     case CollisionDetection::Type::SphereToSphere:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Sphere, Sphere);
+
         auto sphereA = std::dynamic_pointer_cast<Sphere>(collidingGeometryA);
         auto sphereB = std::dynamic_pointer_cast<Sphere>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(sphereA, sphereB)
         return std::make_shared<SphereToSphereCD>(sphereA, sphereB, colData);
     }
     case CollisionDetection::Type::SphereToCylinder:
     {
-        auto sphere   = std::dynamic_pointer_cast<Sphere>(collidingGeometryB);
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Cylinder, Sphere);
+
         auto cylinder = std::dynamic_pointer_cast<Cylinder>(collidingGeometryA);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(sphere, cylinder)
+        auto sphere   = std::dynamic_pointer_cast<Sphere>(collidingGeometryB);
         return std::make_shared<SphereToCylinderCD>(sphere, cylinder, colData);
     }
     case CollisionDetection::Type::MeshToMeshBruteForce:
     {
+        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, collidingGeometryB, Geometry, SurfaceMesh);
+
         auto meshB = std::dynamic_pointer_cast<SurfaceMesh>(collidingGeometryB);
-        IMSTK_CHECK_FOR_VALID_GEOMETRIES(collidingGeometryA, meshB)
         return std::make_shared<MeshToMeshBruteForceCD>(collidingGeometryA, meshB, colData);
     }
     default:
diff --git a/Source/CollisionHandling/imstkBoneDrillingCH.cpp b/Source/CollisionHandling/imstkBoneDrillingCH.cpp
index 04877d74a5ea42d9ad926e97c0b71391ec0281ab..f91f286a7238aa367a78269ba9ece57572ccd0bf 100644
--- a/Source/CollisionHandling/imstkBoneDrillingCH.cpp
+++ b/Source/CollisionHandling/imstkBoneDrillingCH.cpp
@@ -22,9 +22,6 @@
 #include "imstkBoneDrillingCH.h"
 #include "imstkCollidingObject.h"
 #include "imstkCollisionData.h"
-#include "imstkDeviceTracker.h"
-#include "imstkLogger.h"
-#include "imstkParallelUtils.h"
 #include "imstkTetrahedralMesh.h"
 
 namespace imstk
diff --git a/Source/CollisionHandling/imstkBoneDrillingCH.h b/Source/CollisionHandling/imstkBoneDrillingCH.h
index 476ec97701262e814ac24cd104313638e0a27f5e..baad5f7b40031a2ed95a6cd96ac33db5d5a5ec09 100644
--- a/Source/CollisionHandling/imstkBoneDrillingCH.h
+++ b/Source/CollisionHandling/imstkBoneDrillingCH.h
@@ -21,14 +21,12 @@
 
 #pragma once
 
-// imstk
 #include "imstkCollisionHandling.h"
 #include "imstkMath.h"
 
 namespace imstk
 {
 class CollidingObject;
-class DeviceTracker;
 struct CollisionData;
 
 ///
diff --git a/Source/CollisionHandling/imstkCollisionHandling.h b/Source/CollisionHandling/imstkCollisionHandling.h
index ea9e05a2d77e4617a022d7ab855cb7018585c0e0..ec367199aa9ba16ed09e25de9e508a37a0084887 100644
--- a/Source/CollisionHandling/imstkCollisionHandling.h
+++ b/Source/CollisionHandling/imstkCollisionHandling.h
@@ -50,7 +50,9 @@ public:
         NodalPicking,
         BoneDrilling,
         SPH,
-        PBD
+        PBD,
+        RBD,
+        LevelSet
     };
 
     ///
diff --git a/Source/CollisionHandling/imstkLevelSetCH.cpp b/Source/CollisionHandling/imstkLevelSetCH.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5cb2ba1504be93862fdb3fb62a3e6d0a158294ab
--- /dev/null
+++ b/Source/CollisionHandling/imstkLevelSetCH.cpp
@@ -0,0 +1,129 @@
+/*=========================================================================
+
+   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 "imstkLevelSetCH.h"
+#include "imstkCollisionData.h"
+#include "imstkLevelSetDeformableObject.h"
+#include "imstkLevelSetModel.h"
+#include "imstkImageData.h"
+#include "imstkRigidObject2.h"
+#include "imstkRbdConstraint.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+static double gaussianKernel[3][3][3] =
+{
+    {
+        { 1.0, 2.0, 1.0 },
+        { 2.0, 4.0, 2.0 },
+        { 1.0, 2.0, 1.0 }
+    },
+    {
+        { 2.0, 4.0, 2.0 },
+        { 4.0, 8.0, 4.0 },
+        { 2.0, 4.0, 2.0 }
+    },
+    {
+        { 1.0, 2.0, 1.0 },
+        { 2.0, 4.0, 2.0 },
+        { 1.0, 2.0, 1.0 }
+    }
+};
+
+LevelSetCH::LevelSetCH(const Side&                               side,
+                       const std::shared_ptr<CollisionData>      colData,
+                       std::shared_ptr<LevelSetDeformableObject> lvlSetObj,
+                       std::shared_ptr<RigidObject2>             rigidObj) :
+    CollisionHandling(Type::RBD, side, colData),
+    m_lvlSetObj(lvlSetObj),
+    m_rigidObj(rigidObj)
+{
+}
+
+void
+LevelSetCH::processCollisionData()
+{
+    std::shared_ptr<LevelSetModel> lvlSetModel = m_lvlSetObj->getLevelSetModel();
+    std::shared_ptr<ImageData>     grid = std::dynamic_pointer_cast<ImageData>(lvlSetModel->getModelGeometry());
+
+    //const Vec3i& dim = grid->getDimensions();
+    const Vec3d& invSpacing = grid->getInvSpacing();
+    const Vec3d& origin     = grid->getOrigin();
+
+    //if (m_useProportionalForce)
+    //{
+    //    // Apply impulses at points of contacts
+    //    PositionDirectionCollisionData& pdColData = m_colData->PDColData;
+    //    for (int i = 0; i < pdColData.getSize(); i++)
+    //    {
+    //        const Vec3d& pos = pdColData[i].posB;
+    //        const Vec3d& normal = pdColData[i].dirAtoB;
+    //        const Vec3i  coord = (pos - origin).cwiseProduct(invSpacing).cast<int>();
+
+    //        const double fN = normal.dot(m_rigidObj->getRigidBody()->getForce());
+    //        const double S = m_velocityScaling;
+
+    //        for (int z = 0; z < 3; z++)
+    //        {
+    //            for (int y = 0; y < 3; y++)
+    //            {
+    //                for (int x = 0; x < 3; x++)
+    //                {
+    //                    const Vec3i fCoord = coord + Vec3i(x - 1, y - 1, z - 1);
+    //                    /*float S = 0.05f *
+    //                            glm::max(
+    //                                    glm::dot(-glm::normalize(computeGrad(fCoords[0], fCoords[1], imgPtr, dim, spacing)),
+    //                                            glm::vec2(rigidObj->getForce())), 0.0f);*/
+    //                    lvlSetModel->addImpulse(fCoord, S * gaussianKernel[x][y][z]);
+    //                }
+    //            }
+    //        }
+    //    }
+    //}
+    //else
+    {
+        // Apply impulses at points of contacts
+        PositionDirectionCollisionData& pdColData = m_colData->PDColData;
+        for (int i = 0; i < pdColData.getSize(); i++)
+        {
+            const Vec3d& pos = pdColData[i].posB;
+            //const Vec3d& normal = pdColData[i].dirAtoB;
+            const Vec3i  coord = (pos - origin).cwiseProduct(invSpacing).cast<int>();
+            const double S     = m_velocityScaling;
+
+            for (int z = 0; z < 3; z++)
+            {
+                for (int y = 0; y < 3; y++)
+                {
+                    for (int x = 0; x < 3; x++)
+                    {
+                        const Vec3i fCoord = coord + Vec3i(x - 1, y - 1, z - 1);
+                        lvlSetModel->addImpulse(fCoord, S * gaussianKernel[x][y][z]);
+                    }
+                }
+            }
+        }
+    }
+}
+}
+}
\ No newline at end of file
diff --git a/Source/CollisionHandling/imstkLevelSetCH.h b/Source/CollisionHandling/imstkLevelSetCH.h
new file mode 100644
index 0000000000000000000000000000000000000000..32fd8327e6c2233aa7ae571aa5320f3310b7db0b
--- /dev/null
+++ b/Source/CollisionHandling/imstkLevelSetCH.h
@@ -0,0 +1,81 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkCollisionHandling.h"
+
+#include <vector>
+
+namespace imstk
+{
+class LevelSetDeformableObject;
+struct CollisionData;
+
+namespace expiremental
+{
+class RigidObject2;
+
+///
+/// \class LevelSetCH
+///
+/// \brief Applies impulses to the leveset given point direction constraints
+/// propotional to the force on the rigid object
+///
+class LevelSetCH : public CollisionHandling
+{
+public:
+    LevelSetCH(const Side&                               side,
+               const std::shared_ptr<CollisionData>      colData,
+               std::shared_ptr<LevelSetDeformableObject> lvlSetObj,
+               std::shared_ptr<RigidObject2>             rigidObj);
+
+    LevelSetCH() = delete;
+
+    virtual ~LevelSetCH() override = default;
+
+public:
+    ///
+    /// \brief Compute forces and velocities based on collision data
+    ///
+    void processCollisionData() override;
+
+    ///
+    /// \brief Set/Get Scale of the velocity used for the levelset, default 0.1
+    ///
+    double getLevelSetVelocityScaling() const { return m_velocityScaling; }
+    void setLevelSetVelocityScaling(const double velocityScaling) { m_velocityScaling = velocityScaling; }
+
+///
+/// \brief Set/Get whether the velocity used on the levelset should be proportional to the force of the rigid body
+/// along the normal of the levelset
+///
+/* void setUseProportionalVelocity(const bool useProportionalForce) { m_useProportionalForce = useProportionalForce; }
+    bool getUseProportionalVelocity() const { return m_useProportionalForce; }*/
+
+private:
+    std::shared_ptr<LevelSetDeformableObject> m_lvlSetObj = nullptr;
+    std::shared_ptr<RigidObject2> m_rigidObj = nullptr;
+    double m_velocityScaling = 0.002;
+    //bool m_useProportionalForce = false;
+};
+}
+}
\ No newline at end of file
diff --git a/Source/CollisionHandling/imstkPBDCollisionHandling.h b/Source/CollisionHandling/imstkPBDCollisionHandling.h
index 3935e0db3328f3f4c93a77482f7b6fbae6a81cbe..c2e4cfe2a31a1c341ce52b64289180dbe65b89a9 100644
--- a/Source/CollisionHandling/imstkPBDCollisionHandling.h
+++ b/Source/CollisionHandling/imstkPBDCollisionHandling.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkCollisionHandling.h"
 
 #include <vector>
diff --git a/Source/CollisionHandling/imstkPenaltyCH.cpp b/Source/CollisionHandling/imstkPenaltyCH.cpp
index 1e59fa12cbc584a16712229a5f7ccadb757da249..67543fb85a1a0756bb1aeb132e32291b35118ca2 100644
--- a/Source/CollisionHandling/imstkPenaltyCH.cpp
+++ b/Source/CollisionHandling/imstkPenaltyCH.cpp
@@ -20,12 +20,9 @@
 =========================================================================*/
 
 #include "imstkPenaltyCH.h"
-#include "imstkCollidingObject.h"
 #include "imstkCollisionData.h"
 #include "imstkFeDeformableObject.h"
 #include "imstkFEMDeformableBodyModel.h"
-#include "imstkLogger.h"
-#include "imstkParallelUtils.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionHandling/imstkPenaltyCH.h b/Source/CollisionHandling/imstkPenaltyCH.h
index a252c55181779efc1abf309010fb6c30e9093c4f..60575dd49e6516f464ddc8f88c2e62ac28904229 100644
--- a/Source/CollisionHandling/imstkPenaltyCH.h
+++ b/Source/CollisionHandling/imstkPenaltyCH.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkCollisionHandling.h"
 
 namespace imstk
diff --git a/Source/CollisionHandling/imstkPickingCH.cpp b/Source/CollisionHandling/imstkPickingCH.cpp
index 92f35e96a0543d4402b602db7208c97f6ababfc1..6b25b3cd64418f9a933469e3f546f30eaa5b405b 100644
--- a/Source/CollisionHandling/imstkPickingCH.cpp
+++ b/Source/CollisionHandling/imstkPickingCH.cpp
@@ -20,13 +20,12 @@ limitations under the License.
 =========================================================================*/
 
 #include "imstkPickingCH.h"
+#include "imstkCollisionData.h"
 #include "imstkFeDeformableObject.h"
-#include "imstkParallelUtils.h"
-#include "imstkPointSet.h"
 #include "imstkFEMDeformableBodyModel.h"
-#include "imstkTimeIntegrator.h"
-#include "imstkCollisionData.h"
 #include "imstkLinearProjectionConstraint.h"
+#include "imstkPointSet.h"
+#include "imstkTimeIntegrator.h"
 
 namespace imstk
 {
diff --git a/Source/CollisionHandling/imstkPickingCH.h b/Source/CollisionHandling/imstkPickingCH.h
index 2614dde37f9ad5adc8ec3e0feb8bce1919fdbf8e..5eed9f256712672d7f63da29ce3f3c481f418a4c 100644
--- a/Source/CollisionHandling/imstkPickingCH.h
+++ b/Source/CollisionHandling/imstkPickingCH.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkCollisionHandling.h"
 
 #include <vector>
diff --git a/Source/CollisionHandling/imstkRigidBodyCH.cpp b/Source/CollisionHandling/imstkRigidBodyCH.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e0abf8a4e8b48dad99ed6626e8111dd3baa2b386
--- /dev/null
+++ b/Source/CollisionHandling/imstkRigidBodyCH.cpp
@@ -0,0 +1,204 @@
+/*=========================================================================
+
+   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 "imstkRigidBodyCH.h"
+#include "imstkCollisionData.h"
+#include "imstkRbdContactConstraint.h"
+#include "imstkRbdFrictionConstraint.h"
+#include "imstkRigidBodyModel2.h"
+#include "imstkRigidObject2.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+RigidBodyCH::RigidBodyCH(const Side&                          side,
+                         const std::shared_ptr<CollisionData> colData,
+                         std::shared_ptr<RigidObject2>        rbdObjectA,
+                         std::shared_ptr<RigidObject2>        rbdObjectB,
+                         const double                         stiffness,
+                         const double                         frictionalCoefficient) :
+    CollisionHandling(Type::RBD, side, colData),
+    m_rbdObjectA(rbdObjectA),
+    m_rbdObjectB(rbdObjectB),
+    m_stiffness(stiffness),
+    m_frictionalCoefficient(frictionalCoefficient),
+    m_useFriction(frictionalCoefficient != 0.0)
+{
+    if (side == Side::AB && rbdObjectA == nullptr && rbdObjectB == nullptr)
+    {
+        LOG(WARNING) << "RigidBodyCH, side AB was specified but only one object given";
+        return;
+    }
+    if (side == Side::A && rbdObjectA == nullptr)
+    {
+        LOG(WARNING) << "RigidBodyCH, side A was specified but object A not given";
+        return;
+    }
+    if (side == Side::B && rbdObjectB == nullptr)
+    {
+        LOG(WARNING) << "RigidBodyCH, side B was specified but object B not given";
+        return;
+    }
+}
+
+void
+RigidBodyCH::processCollisionData()
+{
+    if (m_side == Side::A)
+    {
+        processA();
+    }
+    else if (m_side == Side::B)
+    {
+        processB();
+    }
+    else if (m_side == Side::AB)
+    {
+        std::shared_ptr<RigidBodyModel2> rbdModelA = m_rbdObjectA->getRigidBodyModel2();
+        std::shared_ptr<RigidBodyModel2> rbdModelB = m_rbdObjectB->getRigidBodyModel2();
+
+        // If the two bodies exist in separate models, add two one way constraints
+        if (rbdModelA != rbdModelB)
+        {
+            if (rbdModelA != nullptr)
+            {
+                processA();
+            }
+            if (rbdModelB != nullptr)
+            {
+                processB();
+            }
+        }
+        else
+        {
+            processAB();
+        }
+    }
+}
+
+void
+RigidBodyCH::processA()
+{
+    std::shared_ptr<RigidBodyModel2> rbdModelA = m_rbdObjectA->getRigidBodyModel2();
+    // Generate one-way constraints
+    PositionDirectionCollisionData& pdColData = m_colData->PDColData;
+    for (int i = 0; i < pdColData.getSize(); i++)
+    {
+        {
+            std::shared_ptr<RbdContactConstraint> contactConstraint =
+                std::make_shared<RbdContactConstraint>(
+                    m_rbdObjectA->getRigidBody(), nullptr,
+                    pdColData[i].dirAtoB.normalized(),
+                    pdColData[i].posB,
+                    pdColData[i].penetrationDepth,
+                    m_stiffness,
+                    RbdConstraint::Side::A);
+            contactConstraint->compute(rbdModelA->getTimeStep());
+            rbdModelA->addConstraint(contactConstraint);
+        }
+
+        if (m_useFriction)
+        {
+            std::shared_ptr<RbdFrictionConstraint> frictionConstraint =
+                std::make_shared<RbdFrictionConstraint>(
+                    m_rbdObjectA->getRigidBody(), nullptr,
+                    pdColData[i].posB,
+                    pdColData[i].dirAtoB.normalized(),
+                    pdColData[i].penetrationDepth,
+                    m_frictionalCoefficient,
+                    RbdConstraint::Side::A);
+            frictionConstraint->compute(rbdModelA->getTimeStep());
+            rbdModelA->addConstraint(frictionConstraint);
+        }
+    }
+}
+
+void
+RigidBodyCH::processB()
+{
+    std::shared_ptr<RigidBodyModel2> rbdModelB = m_rbdObjectB->getRigidBodyModel2();
+    // Generate one-way constraints
+    PositionDirectionCollisionData& pdColData = m_colData->PDColData;
+    for (int i = 0; i < pdColData.getSize(); i++)
+    {
+        std::shared_ptr<RbdContactConstraint> contactConstraint =
+            std::make_shared<RbdContactConstraint>(
+                nullptr, m_rbdObjectB->getRigidBody(),
+                pdColData[i].dirAtoB.normalized(),
+                pdColData[i].posB,
+                pdColData[i].penetrationDepth,
+                m_stiffness,
+                RbdConstraint::Side::B);
+        contactConstraint->compute(rbdModelB->getTimeStep());
+        rbdModelB->addConstraint(contactConstraint);
+
+        if (m_useFriction)
+        {
+            std::shared_ptr<RbdFrictionConstraint> frictionConstraint =
+                std::make_shared<RbdFrictionConstraint>(
+                    nullptr, m_rbdObjectB->getRigidBody(),
+                    pdColData[i].posB,
+                    pdColData[i].dirAtoB.normalized(),
+                    pdColData[i].penetrationDepth,
+                    m_frictionalCoefficient,
+                    RbdConstraint::Side::B);
+            frictionConstraint->compute(rbdModelB->getTimeStep());
+            rbdModelB->addConstraint(frictionConstraint);
+        }
+    }
+}
+
+void
+RigidBodyCH::processAB()
+{
+    // Generate one two-way constraint
+    std::shared_ptr<RigidBodyModel2> rbdModelAB = m_rbdObjectA->getRigidBodyModel2();
+    PositionDirectionCollisionData&  pdColData  = m_colData->PDColData;
+    for (int i = 0; i < pdColData.getSize(); i++)
+    {
+        std::shared_ptr<RbdContactConstraint> contactConstraint =
+            std::make_shared<RbdContactConstraint>(
+                m_rbdObjectA->getRigidBody(), m_rbdObjectB->getRigidBody(),
+                pdColData[i].dirAtoB.normalized(),
+                pdColData[i].posB,
+                pdColData[i].penetrationDepth,
+                m_stiffness);
+        contactConstraint->compute(rbdModelAB->getTimeStep());
+        rbdModelAB->addConstraint(contactConstraint);
+
+        if (m_useFriction)
+        {
+            std::shared_ptr<RbdFrictionConstraint> frictionConstraint =
+                std::make_shared<RbdFrictionConstraint>(
+                    m_rbdObjectA->getRigidBody(), m_rbdObjectB->getRigidBody(),
+                    pdColData[i].posB,
+                    pdColData[i].dirAtoB.normalized(),
+                    pdColData[i].penetrationDepth,
+                    m_frictionalCoefficient,
+                    RbdConstraint::Side::AB);
+            frictionConstraint->compute(rbdModelAB->getTimeStep());
+            rbdModelAB->addConstraint(frictionConstraint);
+        }
+    }
+}
+}
+}
\ No newline at end of file
diff --git a/Source/CollisionHandling/imstkRigidBodyCH.h b/Source/CollisionHandling/imstkRigidBodyCH.h
new file mode 100644
index 0000000000000000000000000000000000000000..87816827cf1fd19ed1886a1a86bbbb98720132c5
--- /dev/null
+++ b/Source/CollisionHandling/imstkRigidBodyCH.h
@@ -0,0 +1,80 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkCollisionHandling.h"
+
+#include <vector>
+
+namespace imstk
+{
+struct CollisionData;
+namespace expiremental
+{
+class RigidObject2;
+
+///
+/// \class RigidBodyContactHandler
+///
+/// \brief Creates rigid body contact and frictional constraints given
+/// collision data then adds them to the rigid body model, if rigid
+/// objects use differing models, one-way contacts are added to both.
+/// If only one rigid object is given, one-ways are used.
+///
+class RigidBodyCH : public CollisionHandling
+{
+public:
+    RigidBodyCH(const Side&                          side,
+                const std::shared_ptr<CollisionData> colData,
+                std::shared_ptr<RigidObject2>        rbdObjectA,
+                std::shared_ptr<RigidObject2>        rbdObjectB = nullptr,
+                const double                         stiffness = 0.0,
+                const double                         frictionalCoefficient = 0.8);
+
+    RigidBodyCH() = delete;
+
+    virtual ~RigidBodyCH() override = default;
+
+public:
+    ///
+    /// \brief Compute forces based on collision data
+    ///
+    void processCollisionData() override;
+
+    void setStiffness(double stiffness) { m_stiffness = stiffness; }
+    void setFriction(double frictionalCoefficient) { m_frictionalCoefficient = frictionalCoefficient; }
+    void setUseFriction(bool useFriction) { m_useFriction = useFriction; }
+
+protected:
+    void processA();
+    void processB();
+    void processAB();
+
+private:
+    std::shared_ptr<RigidObject2> m_rbdObjectA = nullptr;
+    std::shared_ptr<RigidObject2> m_rbdObjectB = nullptr;
+    double m_stiffness = 0.0;
+    double m_frictionalCoefficient = 0.8;
+    bool   m_useFriction = true;
+};
+}
+}
diff --git a/Source/CollisionHandling/imstkSPHCollisionHandling.cpp b/Source/CollisionHandling/imstkSPHCollisionHandling.cpp
index 99670ce38a06b5cb74183a108335ebe09ccb8034..8e068628b4dc0fe420bb63f714038afc52c32384 100644
--- a/Source/CollisionHandling/imstkSPHCollisionHandling.cpp
+++ b/Source/CollisionHandling/imstkSPHCollisionHandling.cpp
@@ -21,8 +21,7 @@
 
 #include "imstkSPHCollisionHandling.h"
 #include "imstkCollisionData.h"
-#include "imstkLogger.h"
-#include "imstkParallelUtils.h"
+#include "imstkImplicitGeometryToPointSetCD.h"
 #include "imstkSPHModel.h"
 #include "imstkSPHObject.h"
 
@@ -50,27 +49,23 @@ SPHCollisionHandling::processCollisionData()
         << "Invalid boundary friction coefficient (value must be in [0, 1])";
 #endif
 
-    auto& state = SPHModel->getState();
-    ParallelUtils::parallelFor(m_colData->MAColData.getSize(),
-        [&](const size_t idx)
+    SPHSimulationState&                   state = SPHModel->getState();
+    std::function<void(uint32_t, Vec3d&)> solve =
+        [&](const uint32_t pidx, const Vec3d& penetrationVector)
         {
-            const MeshToAnalyticalCollisionDataElement& cd = m_colData->MAColData[idx];
-            const uint32_t pidx = cd.nodeIdx; // Fluid particle index
-            Vec3d n = cd.penetrationVector;   // This vector should point into solid object
-
             // Correct particle position
-            state.getPositions()[pidx] -= n;
+            state.getPositions()[pidx] -= penetrationVector;
 
-            const auto nLengthSqr = n.squaredNorm();
+            const auto nLengthSqr = penetrationVector.squaredNorm();
             if (nLengthSqr < Real(1e-20)) // Normalize n
             {
                 return;                   // Too little penetration: ignore
             }
-            n /= std::sqrt(nLengthSqr);
+            const Vec3d n = penetrationVector / std::sqrt(nLengthSqr);
 
             // Correct particle velocity: slip boundary condition with friction
-            const auto oldVel = state.getVelocities()[pidx];
-            const auto vn     = oldVel.dot(n);
+            const Vec3d& oldVel = state.getVelocities()[pidx];
+            const double vn     = oldVel.dot(n);
 
             // If particle is escaping the boundary, ignore it
             if (vn > 0)
@@ -93,6 +88,41 @@ SPHCollisionHandling::processCollisionData()
 
                 state.getVelocities()[pidx] = correctedVel;
             }
-        });
+        };
+
+    // Solve analytical collision
+    for (int iter = 0; iter < m_iterations; iter++)
+    {
+        // Coming into this CH, CD has already been computed
+        if (iter != 0)
+        {
+            // Update the collision geometry
+            m_SPHObject->updateGeometries();
+            // Compute collision again
+            m_colDetect->computeCollisionData();
+        }
+
+        ParallelUtils::parallelFor(m_colData->MAColData.getSize(),
+            [&](const size_t idx)
+            {
+                // Because of const, make some extra copies
+                const MeshToAnalyticalCollisionDataElement& cd = m_colData->MAColData[idx];
+                const uint32_t pidx     = cd.nodeIdx;           // Fluid particle index
+                Vec3d penetrationVector = cd.penetrationVector; // This vector should point into solid object
+
+                solve(pidx, penetrationVector);
+            });
+        // Solve point/direction based collision
+        ParallelUtils::parallelFor(m_colData->PDColData.getSize(),
+            [&](const size_t idx)
+            {
+                // Because of const, make some extra copies
+                const PositionDirectionCollisionDataElement& cd = m_colData->PDColData[idx];
+                const uint32_t pidx     = cd.nodeIdx;                       // Fluid particle index
+                Vec3d penetrationVector = cd.dirAtoB * cd.penetrationDepth; // This vector should point into solid object
+
+                solve(pidx, penetrationVector);
+            });
+    }
 }
 } // end namespace imstk
diff --git a/Source/CollisionHandling/imstkSPHCollisionHandling.h b/Source/CollisionHandling/imstkSPHCollisionHandling.h
index e024c18d70375230690c0267cccf1c05a0c8e120..94aa1ee22d9f203d79ec0ebf51cce3c3cfb21815 100644
--- a/Source/CollisionHandling/imstkSPHCollisionHandling.h
+++ b/Source/CollisionHandling/imstkSPHCollisionHandling.h
@@ -20,13 +20,20 @@
 =========================================================================*/
 
 #pragma once
+
 #include "imstkCollisionHandling.h"
 
 namespace imstk
 {
+class ImplicitGeometryToPointSetCD;
 struct CollisionData;
 class SPHObject;
 
+///
+/// \class SPHCollisionHandling
+///
+/// \brief Supports SPH vs analytic and SPH vs Implicit Geometry
+///
 class SPHCollisionHandling : public CollisionHandling
 {
 public:
@@ -36,6 +43,13 @@ public:
 
     SPHCollisionHandling() = delete;
 
+    virtual ~SPHCollisionHandling() override = default;
+
+public:
+    void setNumberOfIterations(int iterations) { this->m_iterations = iterations; }
+
+    void setDetection(std::shared_ptr<ImplicitGeometryToPointSetCD> colDetect) { this->m_colDetect = colDetect; }
+
     ///
     /// \brief Compute forces based on collision data
     ///
@@ -43,5 +57,7 @@ public:
 
 private:
     std::shared_ptr<SPHObject> m_SPHObject = nullptr;
+    std::shared_ptr<ImplicitGeometryToPointSetCD> m_colDetect = nullptr;
+    int m_iterations = 1;
 };
 } // end namespace imstk
diff --git a/Source/CollisionHandling/imstkVirtualCouplingCH.cpp b/Source/CollisionHandling/imstkVirtualCouplingCH.cpp
index 375d2d4f576c35405c059de59b7cdc30dbd8afad..394d9c967209f60ed88b3ae4ff2c8954926ad251 100644
--- a/Source/CollisionHandling/imstkVirtualCouplingCH.cpp
+++ b/Source/CollisionHandling/imstkVirtualCouplingCH.cpp
@@ -20,12 +20,9 @@
 =========================================================================*/
 
 #include "imstkVirtualCouplingCH.h"
-
+#include "imstkAnalyticalGeometry.h"
 #include "imstkCollidingObject.h"
 #include "imstkCollisionData.h"
-#include "imstkAnalyticalGeometry.h"
-
-#include <g3log/g3log.hpp>
 
 namespace imstk
 {
diff --git a/Source/CollisionHandling/imstkVirtualCouplingCH.h b/Source/CollisionHandling/imstkVirtualCouplingCH.h
index 3ad40c87f577256666822a6c9362931296c99bad..6a8903f54e4c8132fc1818d5d50a9a32f107392a 100644
--- a/Source/CollisionHandling/imstkVirtualCouplingCH.h
+++ b/Source/CollisionHandling/imstkVirtualCouplingCH.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkCollisionHandling.h"
 #include "imstkMath.h"
 
diff --git a/Source/Common/Modules/imstkLoopThreadObject.cpp b/Source/Common/Modules/imstkLoopThreadObject.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d117ffedf60218ed1071d22528484e3b441da87d
--- /dev/null
+++ b/Source/Common/Modules/imstkLoopThreadObject.cpp
@@ -0,0 +1,167 @@
+/*=========================================================================
+
+   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 "imstkLoopThreadObject.h"
+#include "imstkLogger.h"
+#include "imstkMath.h"
+#include "imstkTimer.h"
+
+namespace imstk
+{
+LoopThreadObject::LoopThreadObject(std::string name, int loopDelay) :
+    ThreadObject(name),
+    m_frameCounter(std::make_shared<UPSCounter>()),
+    m_trackFPS(false),
+    m_loopDelay(loopDelay),
+    m_isInitialized(false)
+{
+}
+
+void
+LoopThreadObject::startThread()
+{
+    init();
+
+    // Keep active, wait for terminating call
+    std::chrono::steady_clock::time_point previous_t = std::chrono::steady_clock::now() - std::chrono::minutes(1);
+    std::chrono::steady_clock::time_point current_t;
+    long long                             elapsed;
+    while (m_status != ThreadStatus::Inactive)
+    {
+        if (m_requestedStatus == ThreadStatus::Inactive)
+        {
+            m_status = ThreadStatus::Inactive;
+        }
+        else if (m_requestedStatus == ThreadStatus::Paused)
+        {
+            m_status = ThreadStatus::Paused;
+        }
+        else if (m_requestedStatus == ThreadStatus::Running)
+        {
+            m_status = ThreadStatus::Running;
+        }
+
+        if (m_status == ThreadStatus::Running)
+        {
+            // Short path to run module if loop delay = 0
+            // (updating as fast as possible)
+            if (m_loopDelay < VERY_SMALL_EPSILON_D)
+            {
+                if (m_trackFPS)
+                {
+                    m_frameCounter->setStartPointOfUpdate();
+                }
+
+                update();
+
+                if (m_trackFPS)
+                {
+                    m_frameCounter->setEndPointOfUpdate();
+
+                    std::cout << "\r" << this->getName() << " running at "
+                              << m_frameCounter->getUPS() << " ups   " << std::flush;
+                }
+            }
+            else
+            {
+                // If forcing a frequency, wait until enough time elapsed
+                current_t = std::chrono::steady_clock::now();
+                elapsed   = std::chrono::duration_cast<std::chrono::milliseconds>(current_t - previous_t).count();
+                if (elapsed >= m_loopDelay)
+                {
+                    if (m_trackFPS)
+                    {
+                        m_frameCounter->setStartPointOfUpdate();
+                    }
+
+                    update();
+
+                    if (m_trackFPS)
+                    {
+                        m_frameCounter->setEndPointOfUpdate();
+                    }
+
+                    previous_t = current_t;
+                }
+            }
+        }
+    }
+}
+
+void
+LoopThreadObject::setLoopDelay(const double milliseconds)
+{
+    if (milliseconds < 0)
+    {
+        LOG(WARNING) << "Module::setLoopDelay error: delay must be positive.";
+        return;
+    }
+    m_loopDelay = milliseconds;
+}
+
+double
+LoopThreadObject::getFrequency() const
+{
+    if (m_loopDelay < VERY_SMALL_EPSILON_D)
+    {
+        LOG(WARNING) << "Module::getFrequency warning: loop delay is set to 0ms, "
+                     << "therefore not regulated by a frequency. Returning 0.";
+        return 0;
+    }
+    return 1000.0 / m_loopDelay;
+}
+
+void
+LoopThreadObject::setFrequency(const double f)
+{
+    if (f < 0)
+    {
+        LOG(WARNING) << "Module::setFrequency error: f must be positive, "
+                     << "or equal to 0 to run the module in a closed loop.";
+        return;
+    }
+    if (f < VERY_SMALL_EPSILON_D)
+    {
+        m_loopDelay = 0;
+        return;
+    }
+    m_loopDelay = 1000.0 / f;
+}
+
+unsigned int
+LoopThreadObject::getUPS() const
+{
+    if (m_status != ThreadStatus::Running)
+    {
+        return 0;
+    }
+
+    if (m_trackFPS)
+    {
+        return m_frameCounter->getUPS();
+    }
+    else
+    {
+        LOG(WARNING) << "Frame counter is not enabled!";
+        return 0;
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/Common/Modules/imstkLoopThreadObject.h b/Source/Common/Modules/imstkLoopThreadObject.h
new file mode 100644
index 0000000000000000000000000000000000000000..f8185b4973b243ad284a4e72d3dadbaa543ab543
--- /dev/null
+++ b/Source/Common/Modules/imstkLoopThreadObject.h
@@ -0,0 +1,133 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkThreadObject.h"
+
+namespace imstk
+{
+class UPSCounter;
+
+///
+/// \class LoopThreadObject
+///
+/// \brief A thread object that defines its own basic loop and update function
+/// Subclasses can define how to update
+/// ??
+///
+class LoopThreadObject : public ThreadObject
+{
+public:
+    LoopThreadObject(std::string name, int loopDelay = 0);
+    virtual ~LoopThreadObject() = default;
+
+public:
+    ///
+    /// \brief Get loop delay
+    ///
+    double getLoopDelay() const { return m_loopDelay; }
+
+    ///
+    /// \brief Set the loop delay
+    ///
+    void setLoopDelay(const double milliseconds);
+
+    ///
+    /// \brief Get loop delay
+    ///
+    double getFrequency() const;
+
+    ///
+    /// \brief Set the loop delay
+    ///
+    void setFrequency(const double f);
+
+    ///
+    /// \brief Enable frame count
+    ///
+    void enableFrameCount() { m_trackFPS = true; };
+    ///
+    /// \brief Disable frame count
+    ///
+    void disableFrameCount() { m_trackFPS = false; };
+
+    /// \return true is frame count is already enabled
+    bool isFrameCountEnabled() const { return m_trackFPS; };
+
+    ///
+    /// \brief Get the updates per second
+    /// ?? UPS write it out
+    ///
+    unsigned int getUPS() const;
+
+    ///
+    /// \brief Calls initThread on the thread object for subclasses to initialize
+    /// can only be called once
+    ///
+    void init()
+    {
+        if (!m_isInitialized)
+        {
+            initThread();
+            m_isInitialized = true;
+        }
+    }
+
+    ///
+    /// \brief Toggles the initialization flag so init can be called again
+    ///
+    void uninit()
+    {
+        m_isInitialized = false;
+    }
+
+public:
+    void update()
+    {
+        this->postEvent(Event(EventType::PostUpdate));
+        updateThread();
+        this->postEvent(Event(EventType::PreUpdate));
+    }
+
+protected:
+    ///
+    /// \brief Start the thread
+    ///
+    virtual void startThread() override;
+
+    ///
+    /// \brief Called right before thread is started
+    ///
+    virtual void initThread() { }
+
+    ///
+    /// \brief Update the thread ??
+    ///
+    virtual void updateThread() = 0;
+
+protected:
+    std::shared_ptr<UPSCounter> m_frameCounter;
+    double m_loopDelay;     ///> Loop delay
+    bool   m_trackFPS;      ///> Flag to enable/diable FPS tracking
+    bool   m_isInitialized; ///> Flag to avoid reinitialization
+};
+}
\ No newline at end of file
diff --git a/Source/Common/Modules/imstkThreadObject.cpp b/Source/Common/Modules/imstkThreadObject.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..db22f32ca56da834090296005d6a099f4ac2fe30
--- /dev/null
+++ b/Source/Common/Modules/imstkThreadObject.cpp
@@ -0,0 +1,227 @@
+/*=========================================================================
+
+   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 "imstkThreadObject.h"
+#include "imstkLogger.h"
+
+namespace imstk
+{
+ThreadObject::ThreadObject(std::string name, ThreadStatus status) :
+    m_name(name), m_requestedStatus(status), m_parent(nullptr)
+{
+}
+
+ThreadObject::~ThreadObject()
+{
+    // Stop if not yet
+    if (m_status != ThreadStatus::Inactive)
+    {
+        stop(true);
+    }
+}
+
+void
+ThreadObject::requestStatus(ThreadStatus status)
+{
+    // Copy the atomic
+    if (status == ThreadStatus::Inactive)
+    {
+        m_requestedStatus = ThreadStatus::Inactive;
+    }
+    else if (status == ThreadStatus::Paused)
+    {
+        m_requestedStatus = ThreadStatus::Paused;
+    }
+    else if (status == ThreadStatus::Running)
+    {
+        m_requestedStatus = ThreadStatus::Running;
+    }
+    // Children recieve their parents requests of status
+    for (size_t i = 0; i < m_children.size(); i++)
+    {
+        m_children[i]->requestStatus(status);
+    }
+}
+
+void
+ThreadObject::start(const bool sync)
+{
+    if (m_status != ThreadStatus::Inactive)
+    {
+        LOG(WARNING) << "Can not start '" << m_name << "'.\n"
+                     << "Thread already/still active.";
+        return;
+    }
+
+    this->postEvent(Event(EventType::Start, 5));
+
+    m_status = ThreadStatus::Running;
+
+    // Start all of it's children first (does not wait)
+    for (size_t i = 0; i < m_children.size(); i++)
+    {
+        //m_children[i]->requestStatus(m_status);
+        m_children[i]->start(false);
+    }
+
+    if (sync)
+    {
+        startThread();
+
+        m_status = ThreadStatus::Inactive;
+
+        // Stop all of it's children
+        for (size_t i = 0; i < m_children.size(); i++)
+        {
+            m_children[i]->stop(true);
+        }
+        this->postEvent(Event(EventType::End, 5));
+        m_requestedStatus = ThreadStatus::Running;
+    }
+    else
+    {
+        m_stlThread = std::thread(
+            [&]()
+            {
+                startThread();
+
+                m_status = ThreadStatus::Inactive;
+
+                // Stop all of it's children
+                for (size_t i = 0; i < m_children.size(); i++)
+                {
+                    m_children[i]->stop(true);
+                }
+                this->postEvent(Event(EventType::End, 5));
+                m_requestedStatus = ThreadStatus::Running;
+            });
+    }
+}
+
+void
+ThreadObject::stop(const bool sync)
+{
+    // Stop all of it's children first
+    for (size_t i = 0; i < m_children.size(); i++)
+    {
+        m_children[i]->stop(true);
+    }
+
+    this->postEvent(Event(EventType::End, 5));
+
+    stopThread();
+    if ((m_status == ThreadStatus::Inactive))
+    {
+        LOG(WARNING) << "Can not end '" << m_name << "'.\n" << "Thread already inactive.";
+        return;
+    }
+
+    m_requestedStatus = ThreadStatus::Inactive;
+
+    // If sync, wait until the module actually stops before returning from function
+    if (sync)
+    {
+        while (m_status != ThreadStatus::Inactive) {}
+
+        if (m_stlThread.joinable())
+        {
+            m_stlThread.join();
+        }
+    }
+}
+
+void
+ThreadObject::resume(const bool sync)
+{
+    if (m_status == ThreadStatus::Inactive)
+    {
+        return;
+    }
+
+    this->postEvent(Event(EventType::Resume, 5));
+
+    resumeThread();
+    if (m_status == ThreadStatus::Paused)
+    {
+        m_requestedStatus = ThreadStatus::Running;
+
+        // If sync, wait until the module actually pauses before returning from function
+        if (sync)
+        {
+            while (m_status != ThreadStatus::Running) {}
+        }
+    }
+}
+
+void
+ThreadObject::pause(const bool sync)
+{
+    if (m_status == ThreadStatus::Inactive)
+    {
+        return;
+    }
+
+    this->postEvent(Event(EventType::Pause, 5));
+
+    pauseThread();
+    if (m_status == ThreadStatus::Running)
+    {
+        m_requestedStatus = ThreadStatus::Paused;
+
+        // If sync, wait until the module actually pauses before returning from function
+        if (sync)
+        {
+            while (m_status != ThreadStatus::Paused) {}
+        }
+    }
+}
+
+void
+ThreadObject::addChildThread(std::shared_ptr<ThreadObject> childThreadObject)
+{
+    // If the module belongs to another parent
+    if (childThreadObject->m_parent != nullptr)
+    {
+        // Remove child, which should sync stop it
+        childThreadObject->m_parent->removeChildThread(childThreadObject);
+    }
+
+    m_children.push_back(childThreadObject);
+    childThreadObject->m_parent = this;
+
+    // Request the child have the parents status
+    // This may start it, pause it, start in pause, etc
+    //childThreadObject->requestStatus(m_status);
+}
+
+void
+ThreadObject::removeChildThread(std::shared_ptr<ThreadObject> childThreadObject)
+{
+    auto i = std::find(m_children.begin(), m_children.end(), childThreadObject);
+    if (i != m_children.end())
+    {
+        // Stop in sync
+        (*i)->stop(true);
+        m_children.erase(i);
+        childThreadObject->m_parent = nullptr;
+    }
+}
+}
diff --git a/Source/Common/Modules/imstkThreadObject.h b/Source/Common/Modules/imstkThreadObject.h
new file mode 100644
index 0000000000000000000000000000000000000000..4b6cf8137c41fbf2b9d8b9dcae6872977f01fae9
--- /dev/null
+++ b/Source/Common/Modules/imstkThreadObject.h
@@ -0,0 +1,148 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkEventObject.h"
+
+#include <string>
+#include <atomic>
+#include <thread>
+#include <vector>
+
+namespace imstk
+{
+///
+/// \brief Enumerations for the status of the thread
+///
+enum class ThreadStatus
+{
+    Running,
+    Paused,
+    Inactive
+};
+
+///
+/// \class ThreadObject
+///
+/// \brief Wraps Thread with an object oriented base class suited for real time,
+/// persistent threads ??
+///
+class ThreadObject : public EventObject
+{
+public:
+    virtual ~ThreadObject() override;
+
+protected:
+    ///
+    /// \brief Set status to launch into paused state
+    /// \param: Name of the thread
+    /// \param: Desired status when this starts
+    ///
+    ThreadObject(std::string name, ThreadStatus requestedStatus = ThreadStatus::Running);
+
+public:
+    ///
+    /// \brief Get the status of the thread
+    ///
+    ThreadStatus getStatus() const { return m_status; }
+
+    ///
+    /// \brief Get the name of the thread
+    ///
+    const std::string& getName() const { return m_name; }
+
+    ///
+    /// \brief An agglomeration of the start/stop/resume/pause calls
+    /// \param: Desired status
+    /// \param: When true, returns after status has changed to desired. When false, returns immediately
+    ///
+    void requestStatus(ThreadStatus status);
+
+public:
+    ///
+    /// \brief Start the thread and all its children
+    /// children are started before parents
+    /// \param sync: When true, returns after thread is complete. When false, returns immediately
+    ///
+    virtual void start(const bool sync = true);
+
+    ///
+    /// \brief End/terminate the thread
+    /// \param sync: When true, returns after stop complete (like a thread join).
+    /// When false, returns immediately
+    ///
+    virtual void stop(const bool sync = true);
+
+    ///
+    /// \brief Resume the thread
+    /// \param sync: When true, returns after resume. When false, returns immediately
+    ///
+    virtual void resume(const bool sync = false);
+
+    ///
+    /// \brief Pause the thread
+    /// \param sync: When true, returns after thread paused. When false, returns immediately
+    ///
+    virtual void pause(const bool sync = true);
+
+    ///
+    /// \brief Adds a child, this thread will start when *this* does
+    /// If *this* is already running, it will start immediately
+    /// If *this* is paused, it will start paused
+    ///
+    void addChildThread(std::shared_ptr<ThreadObject> childThreadObject);
+
+    ///
+    /// \brief Stops and then removes a child
+    ///
+    void removeChildThread(std::shared_ptr<ThreadObject> childThreadObject);
+
+protected:
+    ///
+    /// \brief Called when the thread starts
+    ///
+    virtual void startThread() { }
+
+    ///
+    /// \brief Called when the thread stops
+    ///
+    virtual void stopThread() { }
+
+    ///
+    /// \brief Called before the thread resumes
+    ///
+    virtual void resumeThread() { }
+
+    ///
+    /// \brief Called before the thread pauses
+    ///
+    virtual void pauseThread() { }
+
+protected:
+    std::atomic<ThreadStatus> m_status{ ThreadStatus::Inactive };         ///> Thread status
+    std::atomic<ThreadStatus> m_requestedStatus{ ThreadStatus::Running }; ///> Requested status
+    std::vector<std::shared_ptr<ThreadObject>> m_children;                ///> Child threads
+    ThreadObject* m_parent;                                               ///> Parent thread, may only have one (or none)
+    std::string   m_name;                                                 ///> Name of the thread
+    std::thread   m_stlThread;                                            ///> Used for the thread
+};
+}
\ No newline at end of file
diff --git a/Source/Common/Parallel/imstkParallelReduce.h b/Source/Common/Parallel/imstkParallelReduce.h
index f26c0e7e76887f3a5cea161458507805c3b4c54f..37142eb0ff510d283d13514b9443ed7995327bba 100644
--- a/Source/Common/Parallel/imstkParallelReduce.h
+++ b/Source/Common/Parallel/imstkParallelReduce.h
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "imstkMath.h"
+
 #include <tbb/tbb.h>
 
 #undef min
@@ -31,6 +32,44 @@ namespace imstk
 {
 namespace ParallelUtils
 {
+///
+/// \brief Private helper class, providing operator() using in std::parallel_reduce
+///  for finding range of a container with specified begin/end/operator[],operator++ functions
+///
+template<class ContainerType>
+class RangeFunctor
+{
+public:
+    RangeFunctor(const ContainerType& data) : m_Data(data) { }
+    RangeFunctor(RangeFunctor& pObj, tbb::split) : m_Data(pObj.m_Data) { }
+
+    // Prohibit copying
+    RangeFunctor() = delete;
+    RangeFunctor& operator=(const RangeFunctor&) = delete;
+
+    void operator()(const tbb::blocked_range<size_t>& r)
+    {
+        for (size_t i = r.begin(); i != r.end(); i++)
+        {
+            m_Max = m_Max > m_Data[i] ? m_Max : m_Data[i];
+            m_Min = m_Max < m_Data[i] ? m_Min : m_Data[i];
+        }
+    }
+
+    void join(RangeFunctor& pObj)
+    {
+        m_Max = m_Max > pObj.m_Max ? m_Max : pObj.m_Max;
+        m_Min = m_Min < pObj.m_Min ? m_Min : pObj.m_Min;
+    }
+
+    Vec2d getRange() const { return Vec2d(m_Min, m_Max); }
+
+private:
+    Real m_Min = std::numeric_limits<Real>::max();
+    Real m_Max = std::numeric_limits<Real>::min();
+    const ContainerType& m_Data;
+};
+
 ///
 /// \brief Private helper class, providing operator() using in std::parallel_reduce
 ///  for finding max L2 norm of an array of Vec3r
diff --git a/Source/Common/Parallel/imstkThreadManager.cpp b/Source/Common/Parallel/imstkThreadManager.cpp
index f242cc27b1a89efe0847044eec9d3a015a894dc9..1aba79875405219af47be5feae8471f1a61c6681 100644
--- a/Source/Common/Parallel/imstkThreadManager.cpp
+++ b/Source/Common/Parallel/imstkThreadManager.cpp
@@ -20,8 +20,7 @@
 =========================================================================*/
 
 #include "imstkThreadManager.h"
-
-#include <g3log/g3log.hpp>
+#include "imstkLogger.h"
 
 namespace imstk
 {
@@ -50,5 +49,11 @@ ThreadManager::setOptimalParallelism()
 {
     setThreadPoolSize(static_cast<size_t>(tbb::task_scheduler_init::default_num_threads()));
 }
+
+size_t
+ThreadManager::getThreadPoolSize()
+{
+    return s_tbbGlobalControl->active_value(tbb::global_control::max_allowed_parallelism);
+}
 }  // end namespace ParallelUtils
 }  // end namespace imstk
diff --git a/Source/Common/Parallel/imstkThreadManager.h b/Source/Common/Parallel/imstkThreadManager.h
index 256064b8fda970e4608015a554fdea7fedb915e7..263bef9a3f8768ed6925ddf373b9a80aded61de1 100644
--- a/Source/Common/Parallel/imstkThreadManager.h
+++ b/Source/Common/Parallel/imstkThreadManager.h
@@ -45,6 +45,11 @@ public:
     ///
     static void setOptimalParallelism();
 
+    ///
+    /// \brief Returns the size of the thread pool
+    ///
+    static size_t getThreadPoolSize();
+
 private:
     ///
     /// \brief Global variable for controlling maximum number of worker threads
diff --git a/Source/Common/TaskGraph/imstkSequentialTaskGraphController.cpp b/Source/Common/TaskGraph/imstkSequentialTaskGraphController.cpp
index f9cccef2ad552d2db107bf901b2b2783084f7fd5..f65496bbcfb8c1e9233fa9f86466d4f9fdce3e75 100644
--- a/Source/Common/TaskGraph/imstkSequentialTaskGraphController.cpp
+++ b/Source/Common/TaskGraph/imstkSequentialTaskGraphController.cpp
@@ -21,7 +21,6 @@
 
 #include "imstkSequentialTaskGraphController.h"
 #include "imstkTaskGraph.h"
-#include "imstkTaskNode.h"
 
 namespace imstk
 {
diff --git a/Source/Common/TaskGraph/imstkTaskGraph.cpp b/Source/Common/TaskGraph/imstkTaskGraph.cpp
index fd5cf84bd808accf3145a309904fcc89995932c1..1f0555a9d9e2aec4de776eac7d7c5fbe807759cc 100644
--- a/Source/Common/TaskGraph/imstkTaskGraph.cpp
+++ b/Source/Common/TaskGraph/imstkTaskGraph.cpp
@@ -21,9 +21,7 @@ limitations under the License.
 
 #include "imstkTaskGraph.h"
 #include "imstkLogger.h"
-#include "imstkTaskNode.h"
-#include <queue>
-#include <set>
+
 #include <stack>
 
 namespace imstk
diff --git a/Source/Common/TaskGraph/imstkTaskGraph.h b/Source/Common/TaskGraph/imstkTaskGraph.h
index 79c2d99c5a0e8a4176c6a085217c003dba877b12..3e7d00bd8e68059d42efe5685862966a95286c7a 100644
--- a/Source/Common/TaskGraph/imstkTaskGraph.h
+++ b/Source/Common/TaskGraph/imstkTaskGraph.h
@@ -22,6 +22,7 @@ limitations under the License.
 #pragma once
 
 #include "imstkTaskNode.h"
+
 #include <list>
 #include <memory>
 #include <unordered_map>
diff --git a/Source/Common/TaskGraph/imstkTaskGraphVizWriter.cpp b/Source/Common/TaskGraph/imstkTaskGraphVizWriter.cpp
index 2bd010b468cb5e2e5361d7661209c010c3fee0d8..768b3b9508bb7eb495e0c61994f5955343ec2e43 100644
--- a/Source/Common/TaskGraph/imstkTaskGraphVizWriter.cpp
+++ b/Source/Common/TaskGraph/imstkTaskGraphVizWriter.cpp
@@ -23,7 +23,6 @@ limitations under the License.
 #include "imstkLogger.h"
 #include "imstkTaskGraph.h"
 #include "imstkColor.h"
-#include <fstream>
 
 namespace imstk
 {
@@ -81,7 +80,7 @@ TaskGraphVizWriter::write()
         }
 
         file <<
-            "digraph imstkDependency\n"
+            "digraph imstkTaskGraph\n"
             "{\n"
             "style=filled;\n"
             "color=lightgrey;\n"
diff --git a/Source/Common/TaskGraph/imstkTaskNode.h b/Source/Common/TaskGraph/imstkTaskNode.h
index 10bdccb27e74e95685e4c6f8fcab976febf36ecb..90ed0c47ca99038eca2db318bfcd134e1e28994c 100644
--- a/Source/Common/TaskGraph/imstkTaskNode.h
+++ b/Source/Common/TaskGraph/imstkTaskNode.h
@@ -36,7 +36,7 @@ class TaskNode
 public:
     TaskNode() = default;
     TaskNode(std::function<void()> func, std::string name = "none", bool isCritical = false) :
-        m_func(func), m_name(name), m_isCritical(isCritical), m_computeTime(0.0)
+        m_name(name), m_isCritical(isCritical), m_computeTime(0.0), m_func(func)
     {
     }
 
diff --git a/Source/Common/TaskGraph/imstkTbbTaskGraphController.cpp b/Source/Common/TaskGraph/imstkTbbTaskGraphController.cpp
index 15581278657cd1de25eca99c46b5d7accbf8fec6..63fb4f6c0e2d391f2cc210ffd69686f6291c4533 100644
--- a/Source/Common/TaskGraph/imstkTbbTaskGraphController.cpp
+++ b/Source/Common/TaskGraph/imstkTbbTaskGraphController.cpp
@@ -21,6 +21,7 @@
 
 #include "imstkTbbTaskGraphController.h"
 #include "imstkTaskGraph.h"
+
 #include <tbb/tbb.h>
 
 namespace imstk
@@ -97,6 +98,7 @@ TbbTaskGraphController::execute()
     // Extra ref count on the final task
     finalTask->increment_ref_count();
     finalTask->spawn_and_wait_for_all(*startTask);
+
     finalTask->execute(); // Execute final task explicitly
     tbb::task::destroy(*finalTask);
 }
diff --git a/Source/Common/Testing/imstkModuleTest.cpp b/Source/Common/Testing/imstkModuleTest.cpp
index c86ed5936381f35294d14413aa70100d6f9f9d38..d8f41bff076bdce95c996c30bdc1e5b817074988 100644
--- a/Source/Common/Testing/imstkModuleTest.cpp
+++ b/Source/Common/Testing/imstkModuleTest.cpp
@@ -20,36 +20,28 @@
 =========================================================================*/
 
 #include "gtest/gtest.h"
-#include "gmock/gmock.h"
 #include <g3log/g3log.hpp>
 
-#include "imstkMath.h"
-#include "imstkModule.h"
-
-#include <thread>
-#include <chrono>
+#include "imstkLoopThreadObject.h"
 
 namespace imstk
 {
 ///
 /// \brief TODO
 ///
-class ModuleMock : public Module
+class LoopThreadObjectMock : public LoopThreadObject
 {
 public:
-
-    ModuleMock() : Module("modulemock") {}
-    ~ModuleMock() = default;
+    LoopThreadObjectMock() : LoopThreadObject("modulemock") { }
+    ~LoopThreadObjectMock() override = default;
 
     bool m_init    = false;
-    bool m_run     = false;
     bool m_cleanup = false;
 
 protected:
-
-    inline void initModule() final { m_init = true; }
-    inline void runModule() final { m_run = true; }
-    inline void cleanUpModule() final { m_cleanup = true; }
+    inline void initThread() override { m_init = true; }
+    inline void updateThread() override { }
+    inline void stopThread() override { m_cleanup = true; }
 };
 }
 
@@ -61,141 +53,90 @@ using namespace imstk;
 class imstkModuleTest : public ::testing::Test
 {
 protected:
-    ModuleMock m_module;
+    LoopThreadObjectMock m_threadObject;
 };
 
 TEST_F(imstkModuleTest, GetName)
 {
-    EXPECT_EQ(m_module.getName(), "modulemock");
+    EXPECT_EQ(m_threadObject.getName(), "modulemock");
 }
 
 TEST_F(imstkModuleTest, GetSetLoopDelay)
 {
-    m_module.setLoopDelay(2);
-    EXPECT_EQ(m_module.getLoopDelay(), 2);
+    m_threadObject.setLoopDelay(2);
+    EXPECT_EQ(m_threadObject.getLoopDelay(), 2);
 
-    m_module.setLoopDelay(0.003);
-    EXPECT_EQ(m_module.getLoopDelay(), 0.003);
+    m_threadObject.setLoopDelay(0.003);
+    EXPECT_EQ(m_threadObject.getLoopDelay(), 0.003);
 
-    m_module.setLoopDelay(400000000);
-    EXPECT_EQ(m_module.getLoopDelay(), 400000000);
+    m_threadObject.setLoopDelay(400000000);
+    EXPECT_EQ(m_threadObject.getLoopDelay(), 400000000);
 
-    m_module.setLoopDelay(0);
-    EXPECT_EQ(m_module.getLoopDelay(), 0);
+    m_threadObject.setLoopDelay(0);
+    EXPECT_EQ(m_threadObject.getLoopDelay(), 0);
 
-    m_module.setLoopDelay(-5);
-    EXPECT_GE(m_module.getLoopDelay(), 0);
+    m_threadObject.setLoopDelay(-5);
+    EXPECT_GE(m_threadObject.getLoopDelay(), 0);
 }
 
 TEST_F(imstkModuleTest, SetFrequency)
 {
-    m_module.setFrequency(60);
-    EXPECT_EQ(m_module.getLoopDelay(), 1000.0 / 60.0);
+    m_threadObject.setFrequency(60);
+    EXPECT_EQ(m_threadObject.getLoopDelay(), 1000.0 / 60.0);
 
-    m_module.setFrequency(0.003);
-    EXPECT_EQ(m_module.getLoopDelay(), 1000.0 / 0.003);
+    m_threadObject.setFrequency(0.003);
+    EXPECT_EQ(m_threadObject.getLoopDelay(), 1000.0 / 0.003);
 
-    m_module.setFrequency(400000000);
-    EXPECT_EQ(m_module.getLoopDelay(), 1000.0 / 400000000);
+    m_threadObject.setFrequency(400000000);
+    EXPECT_EQ(m_threadObject.getLoopDelay(), 1000.0 / 400000000);
 
-    m_module.setFrequency(0);
-    EXPECT_EQ(m_module.getLoopDelay(), 0);
+    m_threadObject.setFrequency(0);
+    EXPECT_EQ(m_threadObject.getLoopDelay(), 0);
 
-    m_module.setFrequency(-5);
-    EXPECT_GE(m_module.getLoopDelay(), 0);
+    m_threadObject.setFrequency(-5);
+    EXPECT_GE(m_threadObject.getLoopDelay(), 0);
 }
 
 TEST_F(imstkModuleTest, GetFrequency)
 {
-    m_module.setLoopDelay(2);
-    EXPECT_EQ(m_module.getFrequency(), 1000.0 / 2);
+    m_threadObject.setLoopDelay(2);
+    EXPECT_EQ(m_threadObject.getFrequency(), 1000.0 / 2);
 
-    m_module.setLoopDelay(0.003);
-    EXPECT_EQ(m_module.getFrequency(), 1000.0 / 0.003);
+    m_threadObject.setLoopDelay(0.003);
+    EXPECT_EQ(m_threadObject.getFrequency(), 1000.0 / 0.003);
 
-    m_module.setLoopDelay(400000000);
-    EXPECT_EQ(m_module.getFrequency(), 1000.0 / 400000000);
+    m_threadObject.setLoopDelay(400000000);
+    EXPECT_EQ(m_threadObject.getFrequency(), 1000.0 / 400000000);
 
-    m_module.setLoopDelay(0);
-    EXPECT_EQ(m_module.getFrequency(), 0);
+    m_threadObject.setLoopDelay(0);
+    EXPECT_EQ(m_threadObject.getFrequency(), 0);
 
-    m_module.setLoopDelay(-5);
-    EXPECT_GE(m_module.getFrequency(), 0);
+    m_threadObject.setLoopDelay(-5);
+    EXPECT_GE(m_threadObject.getFrequency(), 0);
 }
+
 TEST_F(imstkModuleTest, ControlModule)
 {
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive);
-
-    m_module.run();
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive);
-    ASSERT_FALSE(m_module.m_init);
-    ASSERT_FALSE(m_module.m_run);
-    ASSERT_FALSE(m_module.m_cleanup);
-
-    m_module.pause();
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive);
-    ASSERT_FALSE(m_module.m_init);
-    ASSERT_FALSE(m_module.m_run);
-    ASSERT_FALSE(m_module.m_cleanup);
-
-    m_module.end();
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive);
-    ASSERT_FALSE(m_module.m_init);
-    ASSERT_FALSE(m_module.m_run);
-    ASSERT_TRUE(m_module.m_cleanup);
-
-    auto t = std::thread([this] { m_module.start(); });
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Running);
-    ASSERT_TRUE(m_module.m_init);
-    ASSERT_TRUE(m_module.m_run);
-
-    m_module.pause();
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Paused);
-    m_module.m_run = false;
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
-    ASSERT_TRUE(m_module.m_init);
-    ASSERT_FALSE(m_module.m_run);
-
-    m_module.run();
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Running);
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
-    ASSERT_TRUE(m_module.m_init);
-    ASSERT_TRUE(m_module.m_run);
-
-    m_module.end();
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive);
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
-    ASSERT_TRUE(m_module.m_init);
-    ASSERT_TRUE(m_module.m_run);
-    ASSERT_TRUE(m_module.m_cleanup);
-
-    t.join();
-    m_module.m_init = m_module.m_run = m_module.m_cleanup = false;
-
-    t = std::thread([this] { m_module.start(); });
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Running);
-    ASSERT_TRUE(m_module.m_init);
-    ASSERT_TRUE(m_module.m_run);
-    ASSERT_FALSE(m_module.m_cleanup);
-
-    m_module.pause();
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Paused);
-    m_module.m_run = false;
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
-    ASSERT_TRUE(m_module.m_init);
-    ASSERT_FALSE(m_module.m_run);
-    ASSERT_FALSE(m_module.m_cleanup);
-
-    m_module.end();
-    ASSERT_EQ(m_module.getStatus(), ModuleStatus::Inactive);
-    std::this_thread::sleep_for(std::chrono::milliseconds(500));
-    ASSERT_TRUE(m_module.m_init);
-    ASSERT_FALSE(m_module.m_run);
-    ASSERT_TRUE(m_module.m_cleanup);
-
-    t.join();
+    ASSERT_EQ(m_threadObject.getStatus(), ThreadStatus::Inactive);
+
+    // Test start/stop/pause
+    ASSERT_FALSE(m_threadObject.m_init);
+
+    m_threadObject.start(false);
+    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    ASSERT_EQ(m_threadObject.getStatus(), ThreadStatus::Running);
+    ASSERT_TRUE(m_threadObject.m_init);
+    ASSERT_FALSE(m_threadObject.m_cleanup);
+
+    m_threadObject.pause(true);
+    ASSERT_EQ(m_threadObject.getStatus(), ThreadStatus::Paused);
+    ASSERT_TRUE(m_threadObject.m_init);
+    ASSERT_FALSE(m_threadObject.m_cleanup);
+
+    m_threadObject.stop(true);
+    ASSERT_EQ(m_threadObject.getStatus(), ThreadStatus::Inactive);
+    ASSERT_TRUE(m_threadObject.m_init);
+    ASSERT_TRUE(m_threadObject.m_cleanup);
 }
 
 ///
diff --git a/Source/Common/Utils/imstkTimer.cpp b/Source/Common/Utils/imstkTimer.cpp
index c2905cc25803fb07f2d38139a64b3f851f1c2e2a..4668e803dcf7f26895df6f98c1c2ffb6e8a9b731 100644
--- a/Source/Common/Utils/imstkTimer.cpp
+++ b/Source/Common/Utils/imstkTimer.cpp
@@ -20,6 +20,7 @@
 =========================================================================*/
 
 #include "imstkTimer.h"
+#include "imstkLogger.h"
 
 namespace imstk
 {
diff --git a/Source/Common/Utils/imstkTimer.h b/Source/Common/Utils/imstkTimer.h
index 4621c0cf55c9a2b982b11753e45c31588f5e4887..e175d696130daa47a14911a5c23e86f92b32f0ae 100644
--- a/Source/Common/Utils/imstkTimer.h
+++ b/Source/Common/Utils/imstkTimer.h
@@ -20,11 +20,9 @@
 =========================================================================*/
 
 #pragma once
-
-#include "imstkLogger.h"
-
 #include <chrono>
 #include <ctime>
+#include <memory>
 #include <string>
 #include <vector>
 
diff --git a/Source/Common/imstkAbstractDataArray.h b/Source/Common/imstkAbstractDataArray.h
new file mode 100644
index 0000000000000000000000000000000000000000..cf524566cafb923444d9b062e01507999ab6b02e
--- /dev/null
+++ b/Source/Common/imstkAbstractDataArray.h
@@ -0,0 +1,85 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkTypes.h"
+#include "imstkEventObject.h"
+
+namespace imstk
+{
+///
+/// \class AbstractDataArray
+///
+/// \brief This class serves as the base class of DataArray, for typeless use
+/// \todo: Component support, AOS/SOA design
+///
+class AbstractDataArray : public EventObject
+{
+// Users should not be able to construct
+protected:
+    AbstractDataArray() = default;
+
+    ///
+    /// \brief Ensure all observers are disconnected
+    ///
+    virtual ~AbstractDataArray() { };
+
+public:
+    ///
+    /// \brief Resizes the array, may reallocate
+    ///
+    virtual void resize(const size_t count) = 0;
+
+    ///
+    /// \brief Reserves a size for the array in memory, may reallocate
+    ///
+    virtual void reserve(const size_t count) = 0;
+
+    ///
+    /// \brief Returns the number of elements in the array
+    ///
+    virtual size_t size() const = 0;
+
+    ///
+    /// \brief Returns void pointer to data
+    ///
+    virtual void* getVoidPointer() = 0;
+
+    ///
+    /// \brief Returns the scalar type of this array
+    ///
+    inline const ScalarType getScalarType() { return m_scalarType; }
+
+public:
+    ///
+    /// \brief emits signal to all observers, informing them on the current address
+    /// in memory and size of array
+    ///
+    inline void modified() { this->postEvent(Event(EventType::Modified)); }
+
+protected:
+    void setType(const ScalarType type) { this->m_scalarType = type; }
+
+private:
+    ScalarType m_scalarType;
+};
+}
\ No newline at end of file
diff --git a/Source/Common/imstkColor.cpp b/Source/Common/imstkColor.cpp
index c36cece067b66a6428f97a8a2d24b25483a4f214..926019a2b76e5880601524bbc0f4a3cc74050a09 100644
--- a/Source/Common/imstkColor.cpp
+++ b/Source/Common/imstkColor.cpp
@@ -21,8 +21,8 @@
 
 #include "imstkColor.h"
 #include "imstkLogger.h"
+
 #include <iomanip>
-#include <sstream>
 
 namespace imstk
 {
@@ -47,10 +47,10 @@ Color Color::Marigold(0.9, 0.9, 0.4);
 
 Color::Color()
 {
-    rgba[0] = 0.8f;
-    rgba[1] = 0.8f;
-    rgba[2] = 0.8f;
-    rgba[3] = 1.0f;
+    rgba[0] = 0.8;
+    rgba[1] = 0.8;
+    rgba[2] = 0.8;
+    rgba[3] = 1.0;
 }
 
 Color::Color(const double r, const double g, const double b, const double a)
diff --git a/Source/Common/imstkColor.h b/Source/Common/imstkColor.h
index beb2ed911e2117e46e34d561b79019e7214a01b3..ea659e5c7137730e189e8cdc470b2fff78d130cd 100644
--- a/Source/Common/imstkColor.h
+++ b/Source/Common/imstkColor.h
@@ -24,7 +24,9 @@
 #include <iostream>
 
 /// \todo remove nameless union/struct in the future
+#ifdef WIN32
 #pragma warning(disable : 4201)
+#endif
 namespace imstk
 {
 ///
@@ -123,7 +125,9 @@ struct Color
     static Color Teal;
     static Color Marigold;
 };
+#ifdef WIN32
 #pragma warning(default : 4201)
+#endif
 
 ///
 /// \brief Multiplication operators
diff --git a/Source/Common/imstkColorFunction.h b/Source/Common/imstkColorFunction.h
index 3b3577b7ebfde9ee7bb24ab205cef81a162fdf0f..f011a7fe4c8b777261361e26c31b00fb01608f56 100644
--- a/Source/Common/imstkColorFunction.h
+++ b/Source/Common/imstkColorFunction.h
@@ -50,7 +50,7 @@ public:
     virtual ~ColorFunction() = default;
 
 public:
-    size_t getNumberOfColors() const { return m_table.size(); }
+    int getNumberOfColors() const { return static_cast<int>(m_table.size()); }
     const Color& getColor(int i) const { return m_table[i]; }
     const Vec2d& getRange() const { return m_range; }
     const ColorSpace& getColorSpace() const { return m_colorSpace; }
diff --git a/Source/Common/imstkDataArray.h b/Source/Common/imstkDataArray.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9da7d352d6bc4547428fc0a3ae06f7404afa7a7
--- /dev/null
+++ b/Source/Common/imstkDataArray.h
@@ -0,0 +1,101 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkAbstractDataArray.h"
+#include "imstkParallelReduce.h"
+
+#include <vector>
+
+namespace imstk
+{
+///
+/// \class DataArray
+///
+/// \brief This class serves as a wrapping to STL vector, it also provides modified callback
+/// \todo: Support tuples/components
+///
+template<class T>
+class DataArray : public AbstractDataArray
+{
+public:
+    using iterator       = typename std::vector<T>::iterator;
+    using const_iterator = typename std::vector<T>::const_iterator;
+
+public:
+    ///
+    /// \brief Constructs an empty data array
+    ///
+    DataArray() { setType(TypeTemplateMacro(T)); }
+
+    ///
+    /// \brief Constructs a data array with count elements
+    ///
+    DataArray(size_t count) : vec(count) { setType(TypeTemplateMacro(T)); }
+
+    ///
+    /// \brief Constructs from intializer list
+    ///
+    DataArray(std::initializer_list<T> list) : vec(list.begin(), list.end()) { setType(TypeTemplateMacro(T)); }
+
+public:
+    inline void resize(const size_t newCount) override { vec.resize(newCount); }
+
+    inline void push_back(const T& val) { vec.push_back(val); }
+    inline void push_back(const T&& val) { vec.push_back(val); }
+
+    inline void erase(const const_iterator& element) { vec.erase(element); }
+
+    inline void reserve(const size_t count) override { vec.reserve(count); }
+
+    inline size_t size() const override { return vec.size(); }
+
+    inline T* getPointer() { return vec.data(); }
+    inline void* getVoidPointer() override { return static_cast<void*>(vec.data()); }
+
+    inline T& operator[](const size_t pos) { return vec[pos]; }
+    inline const T& operator[](const size_t pos) const { return vec[pos]; }
+
+    ///
+    /// \brief Allow initialization from initializer list, ie: DataArray<int> arr = { 1, 2 }
+    ///
+    template<typename U>
+    DataArray<U>& operator=(std::initializer_list<U> list)
+    {
+        vec = std::vector<U>(list.begin(), list.end());
+        return *this;
+    }
+
+    ///
+    /// \brief Computes the scalar range
+    ///
+    inline Vec2d getScalarRange() const
+    {
+        ParallelUtils::RangeFunctor<std::vector<T>> pObj(vec);
+        tbb::parallel_reduce(tbb::blocked_range<size_t>(0, vec.size()), pObj);
+        return pObj.getRange();
+    }
+
+private:
+    std::vector<T> vec;
+};
+}
\ No newline at end of file
diff --git a/Source/Common/imstkDataLogger.cpp b/Source/Common/imstkDataLogger.cpp
index 9aff6685c21de47b0d0ce53718d02a5775a17158..97cf41665f50122db95a3b3d7a71a27d9b8b4b9e 100644
--- a/Source/Common/imstkDataLogger.cpp
+++ b/Source/Common/imstkDataLogger.cpp
@@ -21,7 +21,6 @@
 
 #include "imstkDataLogger.h"
 #include "imstkLogger.h"
-#include <cstring>
 
 namespace imstk
 {
diff --git a/Source/SceneEntities/Objects/imstkKinematicState.cpp b/Source/Common/imstkEventObject.cpp
similarity index 96%
rename from Source/SceneEntities/Objects/imstkKinematicState.cpp
rename to Source/Common/imstkEventObject.cpp
index 46860e82a45583ec9e4be6f776b714c9137a4aa2..caa249656518416a617770ba332fe5c8d62f4407 100644
--- a/Source/SceneEntities/Objects/imstkKinematicState.cpp
+++ b/Source/Common/imstkEventObject.cpp
@@ -19,6 +19,8 @@
 
 =========================================================================*/
 
+#include "imstkEventObject.h"
+
 namespace imstk
 {
-}
+}
\ No newline at end of file
diff --git a/Source/Common/imstkEventObject.h b/Source/Common/imstkEventObject.h
new file mode 100644
index 0000000000000000000000000000000000000000..8582fb7b82f241dd86325c680b0991a65f86e86c
--- /dev/null
+++ b/Source/Common/imstkEventObject.h
@@ -0,0 +1,438 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include <memory>
+//#include <tbb/concurrent_priority_queue.h>
+#include <tbb/concurrent_queue.h>
+#include <tbb/concurrent_unordered_map.h>
+
+namespace imstk
+{
+enum class EventType
+{
+    AnyEvent,
+    Start,
+    End,
+    Resume,
+    Pause,
+    Modified,
+    KeyPress,
+    VRButtonPress,
+    MouseEvent,
+    PreUpdate,
+    PostUpdate,
+    Configure
+    //?? add one for collision?
+};
+
+///
+/// \class Event
+///
+/// \brief Base class for events which contain a type, priority, and data
+/// priority defaults to 0 and uses a greater than comparator. Negatives are
+/// allowed.
+///
+class Event
+{
+public:
+    Event() : m_type(EventType::AnyEvent), m_priority(0) { }
+    Event(EventType type, int priority = 0) : m_type(type), m_priority(priority) { }
+    virtual ~Event() = default;
+
+public:
+    bool operator<(const Event& other) const
+    {
+        return m_priority < other.m_priority;
+    }
+
+    bool operator>(const Event& other) const
+    {
+        return m_priority > other.m_priority;
+    }
+
+public:
+    EventType m_type;
+    int       m_priority;
+};
+
+///
+/// \brief Stores everything needed to invoke an event
+/// ie: where and with what
+///
+class Command
+{
+public:
+    Command() : m_call(nullptr), m_event(nullptr) { }
+    Command(std::function<void(Event*)> call, Event* event) : m_call(call), m_event(event) { }
+
+public:
+    bool operator<(const Command& other) const
+    {
+        return *m_event > *other.m_event;
+    }
+
+public:
+    std::function<void(Event*)> m_call;
+    Event* m_event;
+};
+
+class EventObject;
+
+template<class T, class RecieverType>
+static void connect(EventObject*, EventType, RecieverType*, void (RecieverType::* func)(T*));
+template<class T>
+static void connect(EventObject*, EventType, std::function<void(T*)>);
+
+template<class T, class RecieverType>
+static void queueConnect(EventObject*, EventType, RecieverType*, void (RecieverType::* func)(T*));
+template<class T>
+static void queueConnect(EventObject*, EventType, EventObject*, std::function<void(T*)>);
+
+static void disconnect(EventObject*, EventObject*, EventType);
+
+///
+/// \class imstkEventObject
+///
+/// \brief imstkEventObject is the base abstract class for all objects in iMSTK that
+/// can recieve and emit events. It supports direct and queued observer functions.
+/// Direct observers recieve events immediately on the same thread
+/// This can either be posted on an object or be a function pointer
+/// Queued observers recieve events within their queue which they can process whenever
+/// they like.
+/// These can be connected with the connect/queuedConnect/disconnect functions
+/// \todo ThreadObject affinity
+///
+class EventObject
+{
+public:
+    using Observer = std::pair<EventObject*, std::function<void (Event*)>>;
+
+public:
+    virtual ~EventObject() = default;
+
+public:
+    ///
+    /// \brief Emits the event
+    /// Direct observers will be immediately called, in sync
+    /// Queued observers will receive the Command in their queue for later
+    /// execution, reciever must implement doEvent
+    ///
+    template<typename T>
+    void postEvent(const T& e)
+    {
+        // For every direct observer
+        for (std::list<Observer>::iterator i = directObservers[e.m_type].begin(); i != directObservers[e.m_type].end(); i++)
+        {
+            // We don't need an object (i->first) to call
+            // Call its function, if it exists, otherwise remove observer
+            if (i->second != nullptr)
+            {
+                i->second(new T(e));
+            }
+            else
+            {
+                i = directObservers[e.m_type].erase(i);
+            }
+        }
+
+        // For every queued observer
+        for (std::list<Observer>::iterator i = queuedObservers[e.m_type].begin(); i != queuedObservers[e.m_type].end(); i++)
+        {
+            // Both object and callback function must be present
+            // Push to its queue, if it exists, otherwise remote observer
+            if (i->first != nullptr && i->second != nullptr)
+            {
+                i->first->eventQueue.push(Command(i->second, new T(e)));
+            }
+            else
+            {
+                i = queuedObservers[e.m_type].erase(i);
+            }
+        }
+    }
+
+    ///
+    /// \brief Try to do an event from the priority queue
+    ///
+    void doEvent()
+    {
+        Command command;
+        if (eventQueue.try_pop(command))
+        {
+            command.m_call(command.m_event);
+            delete command.m_event;
+        }
+    }
+
+    ///
+    /// \brief Not thread safe, could run forever if events are constantly
+    /// being posted
+    /// \todo: need lock
+    ///
+    void doAllEvents()
+    {
+        while (!eventQueue.empty())
+        {
+            doEvent();
+        }
+        eventQueue.clear();
+    }
+
+    ///
+    /// \brief Pops all events and does the last one
+    ///
+    void doLastEvent()
+    {
+        Command command;
+        while (!eventQueue.empty())
+        {
+            eventQueue.try_pop(command);
+        }
+        if (command.m_call != nullptr)
+        {
+            command.m_call(command.m_event);
+            delete command.m_event;
+            eventQueue.clear();
+        }
+    }
+
+protected:
+    ///
+    /// \biref Constructor, object must be subclassed
+    ///
+    EventObject() = default;
+
+protected:
+    ///
+    /// \brief Removes all events from queue
+    /// cleans up copies of the event
+    ///
+    void clearEvents()
+    {
+        // Despite empty not being thread safe, it will
+        // still not be able to try_pop, which will only
+        // cause a short delay, whilst another thread is
+        // performing an push/pop from the queue
+        while (!eventQueue.empty())
+        {
+            Command command;
+            if (eventQueue.try_pop(command))
+            {
+                delete command.m_event;
+            }
+        }
+        eventQueue.clear();
+    }
+
+public:
+    template<class T, class RecieverType>
+    friend void connect(EventObject*, EventType, RecieverType*, void (RecieverType::* func)(T*));
+    template<typename T>
+    friend void connect(EventObject*, EventType, std::function<void(T*)>);
+
+    template<typename T, class RecieverType>
+    friend void queueConnect(EventObject*, EventType, RecieverType*, void (RecieverType::* func)(T*));
+    template<class T>
+    friend void queueConnect(EventObject*, EventType, EventObject*, std::function<void(T*)>);
+
+    friend void disconnect(EventObject*, EventObject*, EventType);
+
+private:
+    tbb::concurrent_queue<Command> eventQueue;
+    //tbb::concurrent_priority_queue<Command> eventQueue;
+    tbb::concurrent_unordered_map<EventType, std::list<Observer>> queuedObservers;
+    tbb::concurrent_unordered_map<EventType, std::list<Observer>> directObservers;
+};
+
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable: 4505)
+#endif
+///
+/// \brief Direct connection
+/// When sender emits eventType, func will be called immediately/synchronously/within the same thread
+/// Reciever function must be a member of reciever object
+///
+template<class T, class RecieverType>
+static void
+connect(EventObject* sender, EventType eventType,
+        RecieverType* reciever, void (RecieverType::* func)(T*))
+{
+    std::function<void(T*)> bindFunc = std::bind(func, reciever, std::placeholders::_1);
+    sender->directObservers[eventType].push_back(EventObject::Observer(nullptr, [ = ](Event* e) { bindFunc(static_cast<T*>(e)); }));
+}
+
+template<class T, class RecieverType>
+static void
+connect(std::shared_ptr<EventObject> sender, EventType eventType,
+        std::shared_ptr<EventObject> reciever, void (RecieverType::* func)(T*))
+{
+    connect<T>(sender.get(), eventType, reciever.get(), func);
+}
+
+template<class T, class RecieverType>
+static void
+connect(std::shared_ptr<EventObject> sender, EventType eventType,
+        RecieverType* reciever, void (RecieverType::* func)(T*))
+{
+    connect<T>(sender.get(), eventType, reciever, func);
+}
+
+template<class T, class RecieverType>
+static void
+connect(EventObject* sender, EventType eventType,
+        std::shared_ptr<RecieverType> reciever, void (RecieverType::* func)(T*))
+{
+    connect<T>(sender, eventType, reciever.get(), func);
+}
+
+///
+/// \brief Direct connection (static, no object required)
+/// When sender emits eventType, func will be called immediately/synchronously/within the same thread
+///
+template<class T>
+static void
+connect(EventObject* sender, EventType eventType,
+        std::function<void(T*)> func)
+{
+    sender->directObservers[eventType].push_back(EventObject::Observer(nullptr, [ = ](Event* e) { func(static_cast<T*>(e)); }));
+}
+
+template<class T>
+static void
+connect(std::shared_ptr<EventObject> sender, EventType eventType,
+        std::function<void(T*)> func)
+{
+    connect(sender.get(), eventType, func);
+}
+
+///
+/// \brief Queued connection
+/// When sender emits eventType, func will be queued to reciever in thread safe manner
+/// Reciever function must be member of reciever object
+///
+template<class T, class RecieverType>
+static void
+queueConnect(EventObject* sender, EventType type, RecieverType* reciever, void (RecieverType::* func)(T*))
+{
+    // \todo Concept check that the function exists on reciever obj
+    std::function<void(T*)> bindFunc = std::bind(func, reciever, std::placeholders::_1);
+    sender->queuedObservers[type].push_back(EventObject::Observer(reciever, [ = ](Event* e) { bindFunc(static_cast<T*>(e)); }));
+}
+
+template<class T, class RecieverType>
+static void
+queueConnect(std::shared_ptr<EventObject> sender, EventType type, std::shared_ptr<RecieverType> reciever, void (RecieverType::* func)(T*))
+{
+    queueConnect<T>(sender.get(), type, reciever.get(), func);
+}
+
+template<class T, class RecieverType>
+static void
+queueConnect(std::shared_ptr<EventObject> sender, EventType type, RecieverType* reciever, void (RecieverType::* func)(T*))
+{
+    queueConnect<T>(sender.get(), type, reciever, func);
+}
+
+template<class T, class RecieverType>
+static void
+queueConnect(EventObject* sender, EventType type, std::shared_ptr<RecieverType> reciever, void (RecieverType::* func)(T*))
+{
+    queueConnect<T>(sender, type, reciever.get(), func);
+}
+
+template<class T>
+static void
+queueConnect(EventObject* sender, EventType type, EventObject* reciever, std::function<void(T*)> func)
+{
+    sender->queuedObservers[type].push_back(EventObject::Observer(reciever, [ = ](Event* e) { func(static_cast<T*>(e)); }));
+}
+
+template<class T>
+static void
+queueConnect(std::shared_ptr<EventObject> sender, EventType type, std::shared_ptr<EventObject> reciever, std::function<void(T*)> func)
+{
+    queueConnect(sender.get(), type, reciever.get(), func);
+}
+
+template<class T>
+static void
+queueConnect(std::shared_ptr<EventObject> sender, EventType type, EventObject* reciever, std::function<void(T*)> func)
+{
+    queueConnect(sender.get(), type, reciever, func);
+}
+
+template<class T>
+static void
+queueConnect(EventObject* sender, EventType type, std::shared_ptr<EventObject> reciever, std::function<void(T*)> func)
+{
+    queueConnect(sender, type, reciever.get(), func);
+}
+
+///
+/// \brief Remove all connections of type
+/// \todo: It is not possible to tell if a function pointer
+/// is equal to another, without an using a handle, its impossible
+/// to remove
+///
+static void
+disconnect(EventObject* sender, EventObject* reciever, EventType eventType)
+{
+    if (sender->queuedObservers.find(eventType) == sender->queuedObservers.end())
+    {
+        return;
+    }
+    std::list<EventObject::Observer>::iterator i =
+        std::find_if(sender->queuedObservers[eventType].begin(), sender->queuedObservers[eventType].end(),
+            [&](const EventObject::Observer& observer) { return observer.first == reciever; });
+    if (i != sender->queuedObservers[eventType].end())
+    {
+        sender->queuedObservers[eventType].erase(i);
+    }
+}
+
+static void
+disconnect(std::shared_ptr<EventObject> sender, std::shared_ptr<EventObject> reciever, EventType eventType)
+{
+    disconnect(sender.get(), reciever.get(), eventType);
+}
+
+static void
+disconnect(std::shared_ptr<EventObject> sender, EventObject* reciever, EventType eventType)
+{
+    disconnect(sender.get(), reciever, eventType);
+}
+
+static void
+disconnect(EventObject* sender, std::shared_ptr<EventObject> reciever, EventType eventType)
+{
+    disconnect(sender, reciever.get(), eventType);
+}
+
+#ifdef WIN32
+#pragma warning(pop)
+#endif
+}
diff --git a/Source/Common/imstkLogger.cpp b/Source/Common/imstkLogger.cpp
index f8fb8252a4a7648645293b1c02bd97cc20a17860..8722036efcf539d853db999c2709ce3de5b0f394 100644
--- a/Source/Common/imstkLogger.cpp
+++ b/Source/Common/imstkLogger.cpp
@@ -18,6 +18,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 
 =========================================================================*/
+
 #include "imstkLogger.h"
 
 #ifdef WIN32
diff --git a/Source/Common/imstkLogger.h b/Source/Common/imstkLogger.h
index 3485c10d0c0f58bf8aec750a17ff75a05cf1960e..ff6778116bfd2f23bf8e8c031b3a27dfbd4772e0 100644
--- a/Source/Common/imstkLogger.h
+++ b/Source/Common/imstkLogger.h
@@ -20,12 +20,10 @@ limitations under the License.
 =========================================================================*/
 #pragma once
 
-#include "g3log/logmessage.hpp"
-#include "g3log/logworker.hpp"
-
 #include "imstkDataLogger.h"
 
-#include <memory>
+#include <g3log/logmessage.hpp>
+#include <g3log/logworker.hpp>
 
 namespace imstk
 {
@@ -77,7 +75,7 @@ class Logger
 {
 public:
     ///
-    /// \brief TODO
+    /// \brief Gets logger instances, creates if doesn't exist yet
     ///
     static Logger& getInstance()
     {
@@ -92,6 +90,18 @@ public:
         return instance;
     }
 
+    ///
+    /// \brief Starts logger with default sinks, use getInstance to
+    /// create a logger with no sinks
+    ///
+    static Logger& startLogger()
+    {
+        Logger& logger = Logger::getInstance();
+        logger.addFileSink("simulation");
+        logger.addStdoutSink();
+        return logger;
+    }
+
     // Disable copy & move constructors & assignments
     Logger(const Logger&) = delete;
     Logger& operator=(const Logger&) = delete;
@@ -107,7 +117,7 @@ public:
     ///
     /// \brief Add a sink that logs to file
     ///
-    std::unique_ptr<FileSinkHandle> addFileSink(const std::string& name, const std::string& path);
+    std::unique_ptr<FileSinkHandle> addFileSink(const std::string& name, const std::string& path = "./");
 
     ///
     /// \brief Add your own sink
diff --git a/Source/Common/imstkMath.h b/Source/Common/imstkMath.h
index 14af78127ddb95a4eec4e365f949308e54166061..fed99309ed902ad6667757fc1ef7919b27b7f07a 100644
--- a/Source/Common/imstkMath.h
+++ b/Source/Common/imstkMath.h
@@ -25,10 +25,14 @@
 
 #include <Eigen/Geometry>
 
+#ifdef WIN32
 #pragma warning( push )
 #pragma warning( disable : 4127 )
+#endif
 #include <Eigen/Sparse>
+#ifdef WIN32
 #pragma warning( pop )
+#endif
 
 #include <Eigen/StdVector>
 #include <vector>
@@ -61,12 +65,14 @@ using StdVectorOfVec4r = std::vector<Vec4r, Eigen::aligned_allocator<Vec4r>>;
 // 2D vector
 using Vec2f = Eigen::Vector2f;
 using Vec2d = Eigen::Vector2d;
+using Vec2i = Eigen::Matrix<int, 2, 1>;
 using StdVectorOfVec2f = std::vector<Vec2f, Eigen::aligned_allocator<Vec2f>>;
 using StdVectorOfVec2d = std::vector<Vec2d, Eigen::aligned_allocator<Vec2d>>;
 
 // 3D vector
 using Vec3f = Eigen::Vector3f;
 using Vec3d = Eigen::Vector3d;
+using Vec3i = Eigen::Matrix<int, 3, 1>;
 using StdVectorOfVec3f = std::vector<Vec3f, Eigen::aligned_allocator<Vec3f>>;
 using StdVectorOfVec3d = std::vector<Vec3d, Eigen::aligned_allocator<Vec3d>>;
 
@@ -76,6 +82,10 @@ using Vec4d = Eigen::Vector4d;
 using StdVectorOfVec4f = std::vector<Vec4f, Eigen::aligned_allocator<Vec4f>>;
 using StdVectorOfVec4d = std::vector<Vec4d, Eigen::aligned_allocator<Vec4d>>;
 
+// 6D vector
+using Vec6f = Eigen::Matrix<float, 6, 1>;
+using Vec6d = Eigen::Matrix<double, 6, 1>;
+
 // Dynamic size vector
 using Vectorf = Eigen::VectorXf;
 using Vectord = Eigen::VectorXd;
@@ -83,8 +93,10 @@ using StdVectorOfVectorf = std::vector<Vectorf, Eigen::aligned_allocator<Vectorf
 using StdVectorOfVectord = std::vector<Vectord, Eigen::aligned_allocator<Vectord>>;
 
 // Quaternion
-using Quatf = Eigen::Quaternion<float, Eigen::DontAlign>;
-using Quatd = Eigen::Quaternion<double, Eigen::DontAlign>;
+using Quatf = Eigen::Quaternion<float>;
+using Quatd = Eigen::Quaternion<double>;
+using StdVectorOfQuatf = std::vector<Quatf, Eigen::aligned_allocator<Quatf>>;
+using StdVectorOfQuatd = std::vector<Quatd, Eigen::aligned_allocator<Quatd>>;
 
 // Angle-Axis
 using Rotf = Eigen::AngleAxisf;
@@ -93,6 +105,7 @@ using Rotd = Eigen::AngleAxisd;
 // 3x3 Matrix
 using Mat3f = Eigen::Matrix3f;
 using Mat3d = Eigen::Matrix3d;
+using StdVectorOfMat3d = std::vector<Mat3d, Eigen::aligned_allocator<Mat3d>>;
 
 // 4x4 Matrix
 using Mat4f = Eigen::Matrix4f;
@@ -153,4 +166,4 @@ using AffineTransform3d = Eigen::Affine3d;
 #define MAX_F                std::numeric_limits<float>::max()
 #define MIN_F                std::numeric_limits<float>::min()
 #define VERY_SMALL_EPSILON_F std::numeric_limits<float>::epsilon()
-} // end namespace imstk
+}
diff --git a/Source/Common/imstkModule.cpp b/Source/Common/imstkModule.cpp
deleted file mode 100644
index fc5fe70333c4d3e981777539f1d2834351f40fdc..0000000000000000000000000000000000000000
--- a/Source/Common/imstkModule.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*=========================================================================
-
-   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 "imstkModule.h"
-#include "imstkMath.h"
-#include "imstkTimer.h"
-
-namespace imstk
-{
-Module::Module(const std::string& name, int loopDelay /*= 0*/) :
-    m_name(name),
-    m_frameCounter(std::make_shared<UPSCounter>()),
-    m_trackFPS(false),
-    m_loopDelay(loopDelay)
-{
-}
-
-void
-Module::start()
-{
-    if (m_status != ModuleStatus::Inactive)
-    {
-        LOG(WARNING) << "Can not start '" << m_name << "'.\n"
-                     << "Module already/still active.";
-        return;
-    }
-
-    // Init
-    m_status = ModuleStatus::Starting;
-    if (m_preInitCallback)
-    {
-        m_preInitCallback(this);
-    }
-
-    this->initModule();
-
-    if (m_postInitCallback)
-    {
-        m_postInitCallback(this);
-    }
-
-    m_status = ModuleStatus::Running;
-
-    // Keep active, wait for terminating call
-    std::chrono::steady_clock::time_point previous_t = std::chrono::steady_clock::now() - std::chrono::minutes(1);
-    std::chrono::steady_clock::time_point current_t;
-    long long                             elapsed;
-    while (m_status != ModuleStatus::Terminating)
-    {
-        if (m_status == ModuleStatus::Pausing)
-        {
-            m_status = ModuleStatus::Paused;
-        }
-        else if (m_status == ModuleStatus::Running)
-        {
-            // Short path to run module if loop delay = 0
-            // (updating as fast as possible)
-            if (m_loopDelay < VERY_SMALL_EPSILON_D)
-            {
-                if (m_trackFPS)
-                {
-                    m_frameCounter->setStartPointOfUpdate();
-                }
-
-                if (m_preUpdateCallback)
-                {
-                    m_preUpdateCallback(this);
-                }
-                this->runModule();
-                if (m_postUpdateCallback)
-                {
-                    m_postUpdateCallback(this);
-                }
-
-                if (m_trackFPS)
-                {
-                    m_frameCounter->setEndPointOfUpdate();
-
-                    std::cout << "\r" << this->getName() << " running at "
-                              << m_frameCounter->getUPS() << " ups   " << std::flush;
-                }
-                continue;
-            }
-
-            // If forcing a frequency, wait until enough time elapsed
-            current_t = std::chrono::steady_clock::now();
-            elapsed   = std::chrono::duration_cast<std::chrono::milliseconds>(current_t - previous_t).count();
-            if (elapsed >= m_loopDelay)
-            {
-                if (m_trackFPS)
-                {
-                    m_frameCounter->setStartPointOfUpdate();
-                }
-
-                if (m_preUpdateCallback)
-                {
-                    m_preUpdateCallback(this);
-                }
-                this->runModule();
-                if (m_postUpdateCallback)
-                {
-                    m_postUpdateCallback(this);
-                }
-
-                if (m_trackFPS)
-                {
-                    m_frameCounter->setEndPointOfUpdate();
-                }
-
-                previous_t = current_t;
-            }
-        }
-    }
-
-    m_status = ModuleStatus::Inactive;
-}
-
-void
-Module::run()
-{
-    if (m_status != ModuleStatus::Paused)
-    {
-        return;
-    }
-
-    m_status = ModuleStatus::Running;
-}
-
-void
-Module::pause()
-{
-    if (m_status == ModuleStatus::Running)
-    {
-        m_status = ModuleStatus::Pausing;
-
-        while (m_status != ModuleStatus::Paused) {}
-    }
-}
-
-void
-Module::end()
-{
-    // Cleanup
-    if (m_preCleanUpCallback)
-    {
-        m_preCleanUpCallback(this);
-    }
-
-    this->cleanUpModule();
-
-    if (m_postCleanUpCallback)
-    {
-        m_postCleanUpCallback(this);
-    }
-
-    if ((m_status == ModuleStatus::Inactive)
-        || (m_status == ModuleStatus::Terminating))
-    {
-        LOG(WARNING) << "Can not end '" << m_name << "'.\n"
-                     << "Module already inactive or terminating.";
-        return;
-    }
-
-    m_status = ModuleStatus::Terminating;
-
-    while (m_status != ModuleStatus::Inactive) {}
-}
-
-ModuleStatus
-Module::getStatus() const
-{
-    return m_status.load();
-}
-
-const std::string&
-Module::getName() const
-{
-    return m_name;
-}
-
-double
-Module::getLoopDelay() const
-{
-    return m_loopDelay;
-}
-
-void
-Module::setLoopDelay(const double milliseconds)
-{
-    if (milliseconds < 0)
-    {
-        LOG(WARNING) << "Module::setLoopDelay error: delay must be positive.";
-        return;
-    }
-    m_loopDelay = milliseconds;
-}
-
-double
-Module::getFrequency() const
-{
-    if (m_loopDelay < VERY_SMALL_EPSILON_D)
-    {
-        LOG(WARNING) << "Module::getFrequency warning: loop delay is set to 0ms, "
-                     << "therefore not regulated by a frequency. Returning 0.";
-        return 0;
-    }
-    return 1000.0 / m_loopDelay;
-}
-
-void
-Module::setFrequency(const double f)
-{
-    if (f < 0)
-    {
-        LOG(WARNING) << "Module::setFrequency error: f must be positive, "
-                     << "or equal to 0 to run the module in a closed loop.";
-        return;
-    }
-    if (f < VERY_SMALL_EPSILON_D)
-    {
-        m_loopDelay = 0;
-        return;
-    }
-    m_loopDelay = 1000.0 / f;
-}
-
-unsigned int
-Module::getUPS()
-{
-    if (m_status != ModuleStatus::Running)
-    {
-        return 0;
-    }
-
-    if (m_trackFPS)
-    {
-        return m_frameCounter->getUPS();
-    }
-    else
-    {
-        LOG(WARNING) << "Frame counter is not enabled!";
-        return 0;
-    }
-}
-}
diff --git a/Source/Common/imstkModule.h b/Source/Common/imstkModule.h
deleted file mode 100644
index 9344e78233746276285089187cbea69fff6cb921..0000000000000000000000000000000000000000
--- a/Source/Common/imstkModule.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/*=========================================================================
-
-   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.
-
-=========================================================================*/
-
-#pragma once
-
-#include <iostream>
-#include <atomic>
-#include <functional>
-#include <memory>
-
-namespace imstk
-{
-class UPSCounter;
-
-///
-/// \brief Enumerations for the status of the module
-///
-enum class ModuleStatus
-{
-    Starting,
-    Running,
-    Pausing,
-    Paused,
-    Terminating,
-    Inactive
-};
-
-///
-/// \class Module
-///
-/// \brief iMSTK module
-///
-class Module
-{
-using CallbackFunction = std::function<void (Module* module)>;
-
-public:
-    ///
-    /// \brief Constructor
-    ///
-    Module(const std::string& name, int loopDelay = 0);
-
-    ///
-    /// \brief Destructor
-    ///
-    virtual ~Module() = default;
-
-    ///
-    /// \brief Start the module
-    ///
-    void start();
-
-    ///
-    /// \brief Run module
-    ///
-    void run();
-
-    ///
-    /// \brief Pause the module
-    ///
-    void pause();
-
-    ///
-    /// \brief End the module
-    ///
-    void end();
-
-    ///
-    /// \brief Set callback function for initialization
-    ///
-    inline void setPreInitCallback(CallbackFunction foo) { m_preInitCallback = foo; }
-    inline void setPostInitCallback(CallbackFunction foo) { m_postInitCallback = foo; }
-    ///
-    /// \brief Set callback function for update
-    ///
-    inline void setPreUpdateCallback(CallbackFunction foo) { m_preUpdateCallback = foo; }
-    inline void setPostUpdateCallback(CallbackFunction foo) { m_postUpdateCallback = foo; }
-    ///
-    /// \brief Set callback function for cleanup
-    ///
-    inline void setPreCleanUpCallback(CallbackFunction foo) { m_preCleanUpCallback = foo; }
-    inline void setPostCleanUpCallback(CallbackFunction foo) { m_postCleanUpCallback = foo; }
-
-    ///
-    /// \brief Get the status of the module
-    ///
-    ModuleStatus getStatus() const;
-
-    ///
-    /// \brief Get the name of the module
-    ///
-    const std::string& getName() const;
-
-    ///
-    /// \brief Get loop delay
-    ///
-    double getLoopDelay() const;
-
-    ///
-    /// \brief Set the loop delay
-    ///
-    void setLoopDelay(const double milliseconds);
-
-    ///
-    /// \brief Get loop delay
-    ///
-    double getFrequency() const;
-
-    ///
-    /// \brief Set the loop delay
-    ///
-    void setFrequency(const double f);
-
-    ///
-    /// \brief Enable frame count
-    ///
-    void enableFrameCount() { m_trackFPS = true; };
-    ///
-    /// \brief Disable frame count
-    ///
-    void disableFrameCount() { m_trackFPS = false; };
-
-    /// \return true is frame count is already enabled
-    bool isFrameCountEnabled() const { return m_trackFPS; };
-
-    unsigned int getUPS();
-
-protected:
-
-    ///
-    /// \brief Initialize module
-    ///
-    virtual void initModule() = 0;
-
-    ///
-    /// \brief Run the module
-    ///
-    virtual void runModule() = 0;
-
-    ///
-    /// \brief Clean the module
-    ///
-    virtual void cleanUpModule() = 0;
-
-    CallbackFunction m_preInitCallback;                              ///> function callback preceding module initialization
-    CallbackFunction m_postInitCallback;                             ///> function callback following module initialization
-    CallbackFunction m_preUpdateCallback;                            ///> function callback preceding module update
-    CallbackFunction m_postUpdateCallback;                           ///> function callback following module update
-    CallbackFunction m_preCleanUpCallback;                           ///> function callback preceding module cleanup
-    CallbackFunction m_postCleanUpCallback;                          ///> function callback following module cleanup
-
-    std::atomic<ModuleStatus>   m_status { ModuleStatus::Inactive }; ///> Module status
-    std::shared_ptr<UPSCounter> m_frameCounter;
-
-    std::string m_name;      ///> Name of the module
-    double      m_loopDelay; ///> Loop delay
-    bool m_trackFPS;         ///> Flag to enable/diable FPS tracking
-};
-}
diff --git a/Source/Common/imstkNew.h b/Source/Common/imstkNew.h
new file mode 100644
index 0000000000000000000000000000000000000000..e9b7d218bb80e981ef811d191786e9624ca5619b
--- /dev/null
+++ b/Source/Common/imstkNew.h
@@ -0,0 +1,94 @@
+/*=========================================================================
+
+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.
+
+=========================================================================*/
+
+#pragma once
+
+#include <memory>
+
+namespace imstk
+{
+//template<typename T>
+//using imstkSmartPtr = std::shared_ptr<T>;
+//
+//template<typename T>
+//using imstkWeakPtr = std::weak_ptr<T>;
+//
+//template<typename T>
+//using imstkUniquePtr = std::unique_ptr<T>;
+
+///
+/// \class imstkNew
+///
+/// \brief std::shared_ptr<T> obj = std::make_shared<T>(); equivalent, convenience class
+/// for STL shared allocations. Cannot be used in overloaded polymorphic calls
+///
+template<class T>
+class imstkNew
+{
+public:
+    template<typename U>
+    friend class imstkNew;
+
+public:
+    imstkNew() : object(std::make_shared<T>()) { }
+
+    template<typename ... Args>
+    explicit imstkNew(Args&&... args) : object(std::make_shared<T>(std::forward<Args>(args)...)) { }
+
+    // Move, reference to old is removed
+    imstkNew(imstkNew&& obj) : object(obj.object) { obj.object = nullptr; }
+
+public:
+    T* operator->() const { return object.get(); }
+    T& operator*() const { return *static_cast<T*>(object); }
+
+    ///
+    /// \brief Returns the raw pointer
+    ///
+    T* getPtr() const { return object.get(); }
+
+    ///
+    /// \brief Returns const ref to STL smart pointer
+    ///
+    const std::shared_ptr<T>& get() const { return object; }
+
+    ///
+    /// \brief Implicit conversion
+    ///
+    operator std::shared_ptr<T>() const { return object; }
+
+    ///
+    /// \brief Hack for multiple implicit conversions, does not work with overloads though
+    /// as it won't know what to cast too
+    ///
+    template<typename U>
+    operator std::shared_ptr<U>() const
+    {
+        static_assert(std::is_base_of<U, T>::value, "Argument U type not compatible with imstkNew<T>'s T");
+        return std::dynamic_pointer_cast<U>(object);
+    }
+
+private:
+    imstkNew(const imstkNew<T>&)       = delete;
+    void operator=(const imstkNew<T>&) = delete;
+    std::shared_ptr<T> object;
+};
+}
\ No newline at end of file
diff --git a/Source/Common/imstkTypes.h b/Source/Common/imstkTypes.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c318dbd544c9244790c3d1e7498d2a1ad07971c
--- /dev/null
+++ b/Source/Common/imstkTypes.h
@@ -0,0 +1,108 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+#include <limits>
+
+namespace imstk
+{
+using ScalarType = unsigned char;
+#define IMSTK_VOID 0
+#define IMSTK_CHAR 1
+#define IMSTK_UNSIGNED_CHAR 2
+#define IMSTK_SHORT 3
+#define IMSTK_UNSIGNED_SHORT 4
+#define IMSTK_INT 5
+#define IMSTK_UNSIGNED_INT 6
+#define IMSTK_LONG 7
+#define IMSTK_UNSIGNED_LONG 8
+#define IMSTK_FLOAT 9
+#define IMSTK_DOUBLE 10
+#define IMSTK_LONG_LONG 11
+#define IMSTK_UNSIGNED_LONG_LONG 12
+
+#define IMSTK_CHAR_MAX std::numeric_limits<char>::max();
+#define IMSTK_CHAR_MIN std::numeric_limits<char>::min();
+#define IMSTK_UNSIGNED_CHAR_MAX std::numeric_limits<unsigned char>::max();
+#define IMSTK_UNSIGNED_CHAR_MIN std::numeric_limits<unsigned char>::min();
+#define IMSTK_SHORT_MAX std::numeric_limits<short>::max();
+#define IMSTK_SHORT_MIN std::numeric_limits<short>::min();
+#define IMSTK_UNSIGNED_SHORT_MAX std::numeric_limits<unsigned short>::max();
+#define IMSTK_UNSIGNED_SHORT_MIN std::numeric_limits<unsigned short>::min();
+#define IMSTK_INT_MAX std::numeric_limits<int>::max();
+#define IMSTK_INT_MIN std::numeric_limits<int>::min();
+#define IMSTK_UNSIGNED_INT_MAX std::numeric_limits<unsigned int>::max();
+#define IMSTK_UNSIGNED_INT_MIN std::numeric_limits<unsigned int>::min();
+#define IMSTK_LONG_MAX std::numeric_limits<long>::max();
+#define IMSTK_LONG_MIN std::numeric_limits<long>::min();
+#define IMSTK_UNSIGNED_LONG_MAX std::numeric_limits<unsigned long>::max();
+#define IMSTK_UNSIGNED_LONG_MIN std::numeric_limits<unsigned long>::min();
+#define IMSTK_FLOAT_MAX std::numeric_limits<float>::max();
+#define IMSTK_FLOAT_MIN std::numeric_limits<float>::min();
+#define IMSTK_DOUBLE_MAX std::numeric_limits<double>::max();
+#define IMSTK_DOUBLE_MIN std::numeric_limits<double>::min();
+#define IMSTK_LONG_LONG_MAX std::numeric_limits<long>::max();
+#define IMSTK_LONG_LONG_MIN std::numeric_limits<long>::min();
+#define IMSTK_UNSIGNED_LONG_LONG_MAX std::numeric_limits<unsigned long long>::max();
+#define IMSTK_UNSIGNED_LONG_LONG_MIN std::numeric_limits<unsigned long long>::min();
+
+///
+/// \brief Used to quiet compiler warnings of parameters not used
+///
+#define imstkNotUsed(x)
+
+// todo: Switch to template type lists
+///
+/// \brief Maps ScalarType type to templated function call
+///
+#define TemplateMacroCase(typeN, type, call) \
+case typeN: { using IMSTK_TT = type; call; }; break
+#define TemplateMacro(call)                                        \
+    TemplateMacroCase(IMSTK_CHAR, char, call);                     \
+    TemplateMacroCase(IMSTK_UNSIGNED_CHAR, unsigned char, call);   \
+    TemplateMacroCase(IMSTK_SHORT, short, call);                   \
+    TemplateMacroCase(IMSTK_UNSIGNED_SHORT, unsigned short, call); \
+    TemplateMacroCase(IMSTK_INT, int, call);                       \
+    TemplateMacroCase(IMSTK_UNSIGNED_INT, unsigned int, call);     \
+    TemplateMacroCase(IMSTK_LONG, long, call);                     \
+    TemplateMacroCase(IMSTK_UNSIGNED_LONG, unsigned long, call);   \
+    TemplateMacroCase(IMSTK_FLOAT, float, call);                   \
+    TemplateMacroCase(IMSTK_DOUBLE, double, call);                 \
+    TemplateMacroCase(IMSTK_LONG_LONG, long long, call);           \
+    TemplateMacroCase(IMSTK_UNSIGNED_LONG_LONG, unsigned long long, call)
+
+///
+/// \brief Returns scalar type given template
+///
+#define TypeTemplateMacro(templateType)                                              \
+    (std::is_same<templateType, char>::value ? IMSTK_CHAR :                          \
+     (std::is_same<templateType, unsigned char>::value ? IMSTK_UNSIGNED_CHAR :       \
+      (std::is_same<templateType, short>::value ? IMSTK_SHORT :                      \
+       (std::is_same<templateType, unsigned short>::value ? IMSTK_UNSIGNED_SHORT :   \
+        (std::is_same<templateType, int>::value ? IMSTK_INT :                        \
+         (std::is_same<templateType, unsigned int>::value ? IMSTK_UNSIGNED_INT :     \
+          (std::is_same<templateType, long>::value ? IMSTK_LONG :                    \
+           (std::is_same<templateType, unsigned long>::value ? IMSTK_UNSIGNED_LONG : \
+            (std::is_same<templateType, float>::value ? IMSTK_FLOAT :                \
+             (std::is_same<templateType, double>::value ? IMSTK_DOUBLE :             \
+              (std::is_same<templateType, long long>::value ? IMSTK_LONG_LONG :      \
+               (std::is_same<templateType, unsigned long long>::value ? IMSTK_UNSIGNED_LONG_LONG : 0))))))))))))
+}
\ No newline at end of file
diff --git a/Source/Constraint/CMakeLists.txt b/Source/Constraint/CMakeLists.txt
index df474dc4b0d6e0c0fc3f540bd351fe3b70751061..145b374948d7e8e88e1004899dbc27a4e1e08044 100644
--- a/Source/Constraint/CMakeLists.txt
+++ b/Source/Constraint/CMakeLists.txt
@@ -5,6 +5,7 @@ include(imstkAddLibrary)
 imstk_add_library( Constraints
   SUBDIR_LIST
     PbdConstraints
+    RigidBodyConstraints
   DEPENDS
     Common
     DataStructures
diff --git a/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp
index 6121b15e54634b7d15e52f26976341c327a21ed0..13482122b63ac5c6a098d8f4dc75041a48f748bc 100644
--- a/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp
+++ b/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp
@@ -72,6 +72,7 @@ PbdAreaConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPos
     n /= 2 * c;
     c -= m_restArea;
 
+    dcdx.resize(3);
     dcdx[0] = e1.cross(n);
     dcdx[1] = e2.cross(n);
     dcdx[2] = e0.cross(n);
diff --git a/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp
index dda274ce9101a8d8b14404fd0ee0bd6062378fa5..0cb65d8171b08cce21c41de5a9a6d5bc71dcb009 100644
--- a/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp
+++ b/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkPbdCollisionConstraint.h"
-#include "imstkLogger.h"
 
 namespace imstk
 {
diff --git a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp
index 03fe3fd841019825d024481ad38f58ffb441640d..114d976944b4e4e059688dfc2cec88301965a4d5 100644
--- a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp
+++ b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp
@@ -45,9 +45,9 @@ PbdConstantDensityConstraint::initConstraint(const StdVectorOfVec3d& initVertexP
 }
 
 void
-PbdConstantDensityConstraint::projectConstraint(const StdVectorOfReal&           currInvMasses,
-                                                const double                     dt,
-                                                const PbdConstraint::SolverType& type,
+PbdConstantDensityConstraint::projectConstraint(const StdVectorOfReal&           imstkNotUsed(currInvMasses),
+                                                const double                     imstkNotUsed(dt),
+                                                const PbdConstraint::SolverType& imstkNotUsed(type),
                                                 StdVectorOfVec3d&                currVertexPositions)
 {
     const size_t numParticles = currVertexPositions.size();
diff --git a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h
index 81f97b656f2a54f98b8c07ad9640af60e30f50e6..4c29262340b0d0791c2511f9a6085e3b13a7b8c6 100644
--- a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h
+++ b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h
@@ -21,8 +21,9 @@ limitations under the License.
 
 #pragma once
 
-#include "imstkPbdConstraint.h"
 #include "imstkNeighborSearch.h"
+#include "imstkPbdConstraint.h"
+#include "imstkTypes.h"
 
 namespace imstk
 {
@@ -64,9 +65,9 @@ public:
                            const PbdConstraint::SolverType& type,
                            StdVectorOfVec3d&                currVertexPositions) override;
 
-    bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions,
-                                 double&                 c,
-                                 StdVectorOfVec3d&       dcdx) const
+    bool computeValueAndGradient(const StdVectorOfVec3d& imstkNotUsed(currVertexPositions),
+                                 double&                 imstkNotUsed(c),
+                                 StdVectorOfVec3d&       imstkNotUsed(dcdx)) const
     {
         return true;
     }
diff --git a/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp
index d45e2edd87341aa2e7d24fe589cef5e3411168b4..574faf11b83be874be4f5b1fb3cecfeaa593cece 100644
--- a/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp
+++ b/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkPbdDihedralConstraint.h"
-#include <iostream>
 
 namespace  imstk
 {
diff --git a/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp
index 85986e9963e3690f7977c2f6e1854dd387c8b30f..5845b7f6a81c4db4c17b5367da6370b55f2e8b17 100644
--- a/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp
+++ b/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkPbdEdgeEdgeCollisionConstraint.h"
-#include "imstkLogger.h"
 
 namespace imstk
 {
diff --git a/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp
index 4763b2f29c6d5d94db7561aec5eac5eb262a230d..50ba72fd421ea887e597d1fdaece5dd0b4a329cd 100644
--- a/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp
+++ b/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp
@@ -20,8 +20,6 @@
 =========================================================================*/
 
 #include "imstkPbdFETetConstraint.h"
-#include "imstkLogger.h"
-#include <iostream>
 
 namespace  imstk
 {
@@ -166,13 +164,9 @@ PbdFEMTetConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexP
     {
         break;
     }
-
     default:
-    {
-        LOG(FATAL) << "Material type not supported ! \n";
         break;
     }
-    }
 
     Mat3d gradC = m_elementVolume * P * m_invRestMat.transpose();
     cval  = C;
diff --git a/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp
index 75b13a8d9e49a1a6ab776c8a3cd7b9e55464758a..2db3daa961a5a078f899c49b3b48e30646b0d09e 100644
--- a/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp
+++ b/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp
@@ -21,8 +21,6 @@
 
 #include "imstkPbdPointTriCollisionConstraint.h"
 
-#include "imstkLogger.h"
-
 namespace imstk
 {
 void
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..218dae0e4bda4b7b1e6920ec469a9f377fbee6b1
--- /dev/null
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp
@@ -0,0 +1,59 @@
+/*=========================================================================
+
+   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 "imstkRbdConstraint.h"
+#include "imstkPointSet.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+void
+RigidBody::setInertiaFromPointSet(std::shared_ptr<PointSet> pointset, const double scale, const bool useBoundingBoxOrigin)
+{
+    Mat3d results;
+    results.setZero();
+
+    Vec3d centroid = Vec3d(0.0, 0.0, 0.0);
+    if (useBoundingBoxOrigin)
+    {
+        Vec3d min, max;
+        pointset->computeBoundingBox(min, max);
+        centroid = (min + max) * 0.5;
+    }
+    const StdVectorOfVec3d& vertices = pointset->getVertexPositions(Geometry::DataType::PreTransform);
+    for (size_t i = 0; i < vertices.size(); i++)
+    {
+        const Vec3d r = vertices[i] - centroid;
+        results(0, 0) += r[1] * r[1] + r[2] * r[2];
+        results(1, 1) += r[0] * r[0] + r[2] * r[2];
+        results(2, 2) += r[0] * r[0] + r[1] * r[1];
+        results(1, 0) += -r[0] * r[1];
+        results(2, 0) += -r[0] * r[2];
+        results(2, 1) += -r[1] * r[2];
+    }
+    results(0, 2)    = results(2, 0);
+    results(0, 1)    = results(1, 0);
+    results(1, 2)    = results(2, 1);
+    m_intertiaTensor = results * m_mass * scale;
+}
+}
+}
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4728e0d94be95fca3a0372c33057b3f0c980532
--- /dev/null
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h
@@ -0,0 +1,118 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkMath.h"
+
+#include <memory>
+
+namespace imstk
+{
+class PointSet;
+
+namespace expiremental
+{
+///
+/// \brief Serves as a handle to the body
+///
+struct RigidBody
+{
+    public:
+        double m_mass;
+        Mat3d m_intertiaTensor;
+        Vec3d m_initPos = Vec3d(0.0, 0.0, 0.0);
+        Quatd m_initOrientation = Quatd(1.0, 0.0, 0.0, 0.0);
+        Vec3d m_initVelocity;
+        Vec3d m_initAngularVelocity;
+        Vec3d m_initForce;
+        Vec3d m_initTorque;
+        bool m_isStatic;
+
+        // Vec3d m_externalForce;
+        //RigidBodyState2* m_state; // A RigidBody can only belong to one state
+        Vec3d* m_pos;
+        Quatd* m_orientation;
+        Vec3d* m_velocity;
+        Vec3d* m_angularVelocity;
+        Vec3d* m_force;
+        Vec3d* m_torque;
+
+        const Vec3d& getPosition() const { return *m_pos; }
+        const Quatd& getOrientation() const { return *m_orientation; }
+        const Vec3d& getVelocity() const { return *m_velocity; }
+        const Vec3d& getAngularVelocity() const { return *m_angularVelocity; }
+        const Vec3d& getForce() const { return *m_force; }
+        const Vec3d& getTorque() const { return *m_torque; }
+
+        ///
+        /// \brief Convience function to set the inertia tensor based off provided geometry
+        /// assuming uniform mass at each point.
+        ///
+        void setInertiaFromPointSet(std::shared_ptr<PointSet> pointset, const double scale = 1.0, const bool useBoundingBoxOrigin = true);
+};
+
+///
+/// \class RbdConstraint
+///
+/// \brief Abstract class for rigid body constraints
+/// \todo: consider removing static flags and using sides in the interaction
+///
+class RbdConstraint
+{
+public:
+    enum class Side
+    {
+        A,
+        B,
+        AB
+    };
+
+protected:
+    RbdConstraint(std::shared_ptr<RigidBody> rbd1,
+                  std::shared_ptr<RigidBody> rbd2, const Side side) :
+        m_obj1(rbd1), m_obj2(rbd2), m_side(side)
+    {
+    }
+
+public:
+    virtual ~RbdConstraint() = default;
+
+public:
+    ///
+    /// \brief Compute constraint jacobian
+    ///
+    virtual void compute(double dt) = 0;
+
+public:
+    // Jacobian
+    Eigen::Matrix<double, 3, 4> J = Eigen::Matrix<double, 3, 4>::Zero();
+    double vu       = 0.0;
+    double range[2] = { 0.0, std::numeric_limits<double>::max() };
+
+    // Objects involved
+    std::shared_ptr<RigidBody> m_obj1 = nullptr;
+    std::shared_ptr<RigidBody> m_obj2 = nullptr;
+
+    Side m_side = Side::AB;
+};
+}
+}
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..045184d886863276a4d3c48656ff7e7e9f3116f8
--- /dev/null
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp
@@ -0,0 +1,55 @@
+/*=========================================================================
+
+   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 "imstkRbdContactConstraint.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+void
+RbdContactConstraint::compute(double dt)
+{
+    // Jacobian of contact
+    J = Eigen::Matrix<double, 3, 4>::Zero();
+    if ((m_side == Side::AB || m_side == Side::A) && !m_obj1->m_isStatic)
+    {
+        // Displacement from center of mass
+        const Vec3d r1 = m_contactPt - m_obj1->getPosition();
+        const Vec3d c  = r1.cross(-m_contactN);
+        J(0, 0) = -m_contactN[0]; J(0, 1) = c[0];
+        J(1, 0) = -m_contactN[1]; J(1, 1) = c[1];
+        J(2, 0) = -m_contactN[2]; J(2, 1) = c[2];
+    }
+    if ((m_side == Side::AB || m_side == Side::B) && !m_obj2->m_isStatic)
+    {
+        // Displacement from center of mass
+        const Vec3d r2 = m_contactPt - m_obj2->getPosition();
+        const Vec3d c  = r2.cross(m_contactN);
+        J(0, 2) = m_contactN[0]; J(0, 3) = c[0];
+        J(1, 2) = m_contactN[1]; J(1, 3) = c[1];
+        J(2, 2) = m_contactN[2]; J(2, 3) = c[2];
+    }
+
+    vu = m_contactDepth * m_beta / dt;
+}
+}
+};
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d295ebd1503f6df20fbb55c822dc33e32d7760e
--- /dev/null
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h
@@ -0,0 +1,65 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkRbdConstraint.h"
+
+#include <functional>
+
+namespace imstk
+{
+namespace expiremental
+{
+///
+/// \class RbdContactConstraint
+///
+/// \brief A hard rigid body constraint to prevent intersection
+///
+class RbdContactConstraint : public RbdConstraint
+{
+public:
+    RbdContactConstraint(
+        std::shared_ptr<RigidBody> obj1,
+        std::shared_ptr<RigidBody> obj2,
+        const Vec3d&               contactN,
+        const Vec3d&               contactPt,
+        const double               contactDepth,
+        const double               beta = 0.05,
+        const Side                 side = Side::AB) : RbdConstraint(obj1, obj2, side),
+        m_contactN(contactN), m_contactPt(contactPt),
+        m_contactDepth(contactDepth), m_beta(beta)
+    {
+    }
+
+    ~RbdContactConstraint() override = default;
+
+public:
+    void compute(double dt) override;
+
+private:
+    Vec3d  m_contactPt;
+    Vec3d  m_contactN;
+    double m_contactDepth;
+    double m_beta = 0.05;
+};
+}
+}
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6595d69ad7ad6264bb4c990af5b7441b33e3d536
--- /dev/null
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp
@@ -0,0 +1,64 @@
+/*=========================================================================
+
+   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 "imstkRbdDistanceConstraint.h"
+#include "imstkTypes.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+RbdDistanceConstraint::RbdDistanceConstraint(
+    std::shared_ptr<RigidBody> obj1,
+    std::shared_ptr<RigidBody> obj2,
+    const Vec3d& p1, const Vec3d& p2,
+    double dist,
+    const Side side) : RbdConstraint(obj1, obj2, side),
+    m_p1(p1), m_p2(p2), m_dist(dist)
+{
+}
+
+void
+RbdDistanceConstraint::compute(double imstkNotUsed(dt))
+{
+    J = Eigen::Matrix<double, 3, 4>::Zero();
+    if ((m_side == Side::AB || m_side == Side::A) && !m_obj1->m_isStatic)
+    {
+        // Displacement from center of mass
+        const Vec3d r1   = m_p1 - m_obj1->getPosition();
+        const Vec3d diff = m_p2 - m_p1;
+        const Vec3d c    = r1.cross(diff);
+        J(0, 0) = -diff[0]; J(0, 1) = -c[0];
+        J(1, 0) = -diff[1]; J(1, 1) = -c[1];
+        J(2, 0) = -diff[2]; J(2, 1) = -c[2];
+    }
+    if ((m_side == Side::AB || m_side == Side::B) && !m_obj2->m_isStatic)
+    {
+        const Vec3d r2   = m_p2 - m_obj2->getPosition();
+        const Vec3d diff = m_p2 - m_p1;
+        const Vec3d c    = r2.cross(diff);
+        J(0, 0) = diff[0]; J(0, 1) = c[0];
+        J(1, 0) = diff[1]; J(1, 1) = c[1];
+        J(2, 0) = diff[2]; J(2, 1) = c[2];
+    }
+}
+}
+}
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..208b69e7754ef2eb4dc7d8b3c182acf63d79fd35
--- /dev/null
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h
@@ -0,0 +1,56 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkRbdConstraint.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+///
+/// \class RbdDistanceConstraint
+///
+/// \brief A rigid body constraint to keep objects at a specified distance
+/// from each other given two local points on the bodies
+///
+class RbdDistanceConstraint : public RbdConstraint
+{
+public:
+    RbdDistanceConstraint(
+        std::shared_ptr<RigidBody> obj1,
+        std::shared_ptr<RigidBody> obj2,
+        const Vec3d& p1, const Vec3d& p2,
+        double dist,
+        const Side side = Side::AB);
+    ~RbdDistanceConstraint() override = default;
+
+public:
+    void compute(double dt) override;
+
+private:
+    Vec3d  m_p1   = Vec3d(0.0, 0.0, 0.0);
+    Vec3d  m_p2   = Vec3d(0.0, 0.0, 0.0);
+    double m_dist = 1.0;
+};
+}
+}
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7bd3962046bda1bbff112081e3a86a3d156840c1
--- /dev/null
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp
@@ -0,0 +1,100 @@
+/*=========================================================================
+
+   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 "imstkRbdFrictionConstraint.h"
+#include "imstkTypes.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+RbdFrictionConstraint::RbdFrictionConstraint(
+    std::shared_ptr<RigidBody> obj1,
+    std::shared_ptr<RigidBody> obj2,
+    const Vec3d&               contactNormal,
+    const Vec3d&               contactPt,
+    const double               contactDepth,
+    const double               frictionCoefficient,
+    const Side                 side) : RbdConstraint(obj1, obj2, side),
+    m_contactN(contactNormal), m_contactPt(contactPt),
+    m_contactDepth(contactDepth), m_frictionCoefficient(frictionCoefficient)
+{
+}
+
+void
+RbdFrictionConstraint::compute(double imstkNotUsed(dt))
+{
+    // Displacement from center of mass
+    //const Vec3d r1 = m_contactPt - m_obj1->getPosition();
+    //const Vec3d r2 = m_contactPt - m_obj2->getPosition();
+
+    // Jacobian of contact
+    J = Eigen::Matrix<double, 3, 4>::Zero();
+    if ((m_side == Side::AB || m_side == Side::A) && !m_obj1->m_isStatic)
+    {
+        const double vN   = m_contactN.dot(m_obj1->getVelocity());
+        const Vec3d  vTan = m_obj1->getVelocity() - vN * m_contactN;
+        const Vec3d  tan  = vTan.normalized();
+
+        // No angular friction
+        J(0, 0) = -tan[0]; J(0, 1) = 0.0;
+        J(1, 0) = -tan[1]; J(1, 1) = 0.0;
+        J(2, 0) = -tan[2]; J(2, 1) = 0.0;
+
+        const double fNMag = std::max(0.0, m_obj1->getForce().dot(-m_contactN));
+        const double fu    = m_frictionCoefficient * fNMag;
+        range[0] = -fu;
+        range[1] = fu;
+    }
+    if ((m_side == Side::AB || m_side == Side::B) && !m_obj2->m_isStatic)
+    {
+        const double vN   = m_contactN.dot(m_obj2->getVelocity());
+        const Vec3d  vTan = m_obj2->getVelocity() - vN * -m_contactN;
+        const Vec3d  tan  = vTan.normalized();
+
+        // No angular friction
+        J(0, 0) = tan[0]; J(0, 1) = 0.0;
+        J(1, 0) = tan[1]; J(1, 1) = 0.0;
+        J(2, 0) = tan[2]; J(2, 1) = 0.0;
+
+        // Get normal force
+        const double fNMag = std::max(0.0, m_obj2->getForce().dot(m_contactN));
+        const double fu    = m_frictionCoefficient * fNMag;
+        range[0] = -fu;
+        range[1] = fu;
+    }
+
+    /*if both? Kinda need two ranges
+    {
+        J(0, 0) = -tan[0]; J(0, 1) = -tan[1]; J(0, 2) = -tan[2];
+        J(1, 0) = 0.0;     J(1, 1) = 0.0;     J(1, 2) = 0.0;
+        J(2, 0) = tan[0];  J(2, 1) = tan[1];  J(2, 2) = tan[2];
+        J(3, 0) = 0.0;     J(3, 1) = 0.0;     J(3, 2) = 0.0;
+
+        const Vec3d  netForce = m_obj1->getForce() + m_obj2->getForce();
+        const double fNMag    = std::max(0.0, netForce.dot(m_contactN));
+        const double fu       = m_frictionCoefficient * fNMag;
+        range[0] = -fu;
+        range[1] = fu;
+    }*/
+}
+}
+};
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea914a6fd186e5661ceeca7353022ae04a059032
--- /dev/null
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h
@@ -0,0 +1,58 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkRbdConstraint.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+///
+/// \class RbdFrictionConstraint
+///
+/// \brief A rigid body constraint to apply friction
+///
+class RbdFrictionConstraint : public RbdConstraint
+{
+public:
+    RbdFrictionConstraint(
+        std::shared_ptr<RigidBody> obj1,
+        std::shared_ptr<RigidBody> obj2,
+        const Vec3d&               contactPt,
+        const Vec3d&               contactNormal,
+        const double               contactDepth,
+        const double               frictionCoefficient,
+        const Side                 side = Side::AB);
+    ~RbdFrictionConstraint() override = default;
+
+public:
+    void compute(double dt) override;
+
+private:
+    Vec3d  m_contactPt;
+    Vec3d  m_contactN;
+    double m_contactDepth;
+    double m_frictionCoefficient;
+};
+}
+}
\ No newline at end of file
diff --git a/Source/Controllers/CMakeLists.txt b/Source/Controllers/CMakeLists.txt
index f4071ef623e6c0b2f9d7ce8ce4d18f731201fd93..bac492accc26a51c22445059e6e0fe2960bb27cd 100644
--- a/Source/Controllers/CMakeLists.txt
+++ b/Source/Controllers/CMakeLists.txt
@@ -1,6 +1,7 @@
 #-----------------------------------------------------------------------------
 # Create target
 #-----------------------------------------------------------------------------
+
 include(imstkAddLibrary)
 imstk_add_library( Controllers
   DEPENDS
diff --git a/Source/Controllers/imstkCameraController.cpp b/Source/Controllers/imstkCameraController.cpp
index 5f2eabe19e2ea692e17e1370bcf8be53917c493b..eaa7be685b77439e76dcb80337370a091b23db49 100644
--- a/Source/Controllers/imstkCameraController.cpp
+++ b/Source/Controllers/imstkCameraController.cpp
@@ -20,32 +20,26 @@
 =========================================================================*/
 
 #include "imstkCameraController.h"
-#include "imstkMath.h"
 #include "imstkCamera.h"
 #include "imstkLogger.h"
 
-#include <utility>
-
 namespace imstk
 {
 CameraController::CameraController(std::shared_ptr<Camera>       camera,
                                    std::shared_ptr<DeviceClient> deviceClient) :
-    Module("Camera controller"),
-    m_camera(camera),
-    m_cameraTranslationOffset(WORLD_ORIGIN),
-    m_cameraRotationalOffset(Quatd::Identity()),
-    DeviceTracker(deviceClient)
+    TrackingDeviceControl(deviceClient),
+    m_camera(camera)
 {
 }
 
 void
-CameraController::runModule()
+CameraController::update()
 {
     if (!m_trackingDataUptoDate)
     {
         if (!updateTrackingData())
         {
-            LOG(WARNING) << "CameraController::runModule warning: could not update tracking info.";
+            LOG(WARNING) << "CameraController::runModule warning: could not update tracking info";
             return;
         }
     }
@@ -54,8 +48,8 @@ CameraController::runModule()
     Quatd r = getRotation();
 
     // Apply Offsets over the device pose
-    p  = p + m_cameraTranslationOffset;     // Offset the device position
-    r *= m_cameraRotationalOffset;          // Apply camera head rotation offset
+    p  = p + m_translationOffset;   // Offset the device position
+    r *= m_rotationOffset;          // Apply camera head rotation offset
 
     // Set camera info
     m_camera->setPosition(p);
@@ -68,9 +62,9 @@ CameraController::runModule()
 void
 CameraController::setOffsetUsingCurrentCameraPose()
 {
-    auto pos    = m_camera->getPosition();
-    auto viewUp = m_camera->getViewUp();
-    auto focus  = m_camera->getFocalPoint();
+    const auto pos    = m_camera->getPosition();
+    const auto focus  = m_camera->getFocalPoint();
+    auto       viewUp = m_camera->getViewUp();
 
     m_translationOffset = pos;
 
@@ -83,28 +77,4 @@ CameraController::setOffsetUsingCurrentCameraPose()
     rot.col(2)       = viewNormal;
     m_rotationOffset = Quatd(rot);
 }
-
-void
-CameraController::setCameraRotationOffset(const Quatd& r)
-{
-    m_cameraRotationalOffset = r;
-}
-
-void
-CameraController::setCameraTranslationOffset(const Vec3d& t)
-{
-    m_cameraTranslationOffset = t;
-}
-
-const Vec3d&
-CameraController::getCameraTranslationOffset() const
-{
-    return m_cameraTranslationOffset;
-}
-
-const Quatd&
-CameraController::getCameraRotationOffset() const
-{
-    return m_cameraRotationalOffset;
-}
-} // imstk
+}
\ No newline at end of file
diff --git a/Source/Controllers/imstkCameraController.h b/Source/Controllers/imstkCameraController.h
index 2e7272ba097eede43a09324ecd552fc4c4e72eec..908501f2e86ed5d7d21fca34c8bf38d918ffe1dc 100644
--- a/Source/Controllers/imstkCameraController.h
+++ b/Source/Controllers/imstkCameraController.h
@@ -21,8 +21,8 @@
 
 #pragma once
 
-#include "imstkModule.h"
-#include "imstkDeviceTracker.h"
+#include "imstkTrackingDeviceControl.h"
+#include "imstkLoopThreadObject.h"
 
 namespace imstk
 {
@@ -31,57 +31,27 @@ class Camera;
 ///
 /// \class CameraController
 ///
-/// \brief
+/// \brief \todo ??
 ///
-class CameraController : public Module, public DeviceTracker
+class CameraController : public TrackingDeviceControl
 {
 public:
-    ///
-    /// \brief TODO
-    ///
     CameraController(std::shared_ptr<Camera> camera, std::shared_ptr<DeviceClient> deviceClient);
+    virtual ~CameraController() = default;
 
-    ///
-    /// \brief
-    ///
-    ~CameraController() = default;
-
+public:
     ///
     /// \brief Set the offsets based on the current camera pose
     ///
     void setOffsetUsingCurrentCameraPose();
 
     ///
-    /// \brief Get/Set translation offset of the camera
-    ///
-    const Vec3d& getCameraTranslationOffset() const;
-    void setCameraTranslationOffset(const Vec3d& t);
-
-    ///
-    /// \brief Get/Set rotation offset of the camera
+    /// \brief Updates the view of the provided camera
     ///
-    const Quatd& getCameraRotationOffset() const;
-    void setCameraRotationOffset(const Quatd& r);
+    void update() override;
 
 protected:
-    ///
-    /// \brief TODO
-    ///
-    virtual void initModule() override {};
-
-    ///
-    /// \brief TODO
-    ///
-    virtual void runModule() override;
-
-    ///
-    /// \brief TODO
-    ///
-    void cleanUpModule() override {};
-
-    std::shared_ptr<Camera> m_camera;     ///< Camera controlled by the external device
 
-    Vec3d m_cameraTranslationOffset;      ///< Translation offset for the camera over tracking data
-    Quatd m_cameraRotationalOffset;       ///< camera head angle offset (in deg)
+    std::shared_ptr<Camera> m_camera; ///< Camera controlled by the external device
 };
 } // imstk
diff --git a/Source/Controllers/imstkDeviceControl.h b/Source/Controllers/imstkDeviceControl.h
new file mode 100644
index 0000000000000000000000000000000000000000..3571dc3781d5cc6233db95315d902f6ddc92deba
--- /dev/null
+++ b/Source/Controllers/imstkDeviceControl.h
@@ -0,0 +1,65 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkEventObject.h"
+
+#include <memory>
+
+namespace imstk
+{
+class DeviceClient;
+
+///
+/// \class DeviceControl
+///
+/// \brief While the DeviceClient provides quantities from the device, the control
+/// defines what to do with those quantities
+///
+class DeviceControl : public EventObject
+{
+protected:
+    DeviceControl() = default;
+    DeviceControl(std::shared_ptr<DeviceClient> device) : m_deviceClient(device) { }
+
+public:
+    virtual ~DeviceControl() = default;
+
+public:
+    std::shared_ptr<DeviceClient> getDevice() const { return m_deviceClient; }
+
+    virtual void setDevice(std::shared_ptr<DeviceClient> device) { m_deviceClient = device; }
+
+    ///
+    /// \brief Prints the controls
+    ///
+    virtual void printControls() { }
+
+    ///
+    /// \brief Updates the state of the control
+    ///
+    virtual void update() { }
+
+public:
+    std::shared_ptr<DeviceClient> m_deviceClient;
+};
+} // imstk
diff --git a/Source/Controllers/imstkKeyboardControl.cpp b/Source/Controllers/imstkKeyboardControl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9813fcfc1b3fea81cf8bbce45afbd31e19077d14
--- /dev/null
+++ b/Source/Controllers/imstkKeyboardControl.cpp
@@ -0,0 +1,64 @@
+/*=========================================================================
+
+   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 "imstkKeyboardControl.h"
+#include "imstkKeyboardDeviceClient.h"
+
+namespace imstk
+{
+KeyboardControl::KeyboardControl(std::shared_ptr<KeyboardDeviceClient> keyDevice) :
+    DeviceControl(keyDevice)
+{
+    setDevice(keyDevice);
+}
+
+void
+KeyboardControl::setDevice(std::shared_ptr<DeviceClient> device)
+{
+    // Remove old observer if it exists
+    if (m_keyboardDeviceClient != nullptr)
+    {
+        disconnect(m_keyboardDeviceClient, this, EventType::KeyPress);
+    }
+
+    // Set the new device
+    m_keyboardDeviceClient = std::dynamic_pointer_cast<KeyboardDeviceClient>(device);
+    DeviceControl::setDevice(device);
+
+    // Subscribe to the device clients events
+    connect(m_keyboardDeviceClient, EventType::KeyPress, this, &KeyboardControl::keyPressEvent);
+}
+
+void
+KeyboardControl::keyPressEvent(KeyPressEvent* keyPressEvent)
+{
+    // If the key was just pressed
+    if (keyPressEvent->m_keyPressType == KEY_PRESS)
+    {
+        OnKeyPress(keyPressEvent->m_key);
+    }
+    // If the key was just released
+    else if (keyPressEvent->m_keyPressType == KEY_RELEASE)
+    {
+        OnKeyRelease(keyPressEvent->m_key);
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/Controllers/imstkKeyboardControl.h b/Source/Controllers/imstkKeyboardControl.h
new file mode 100644
index 0000000000000000000000000000000000000000..390c9891e13958aa7321b56d32696b916a9cdf61
--- /dev/null
+++ b/Source/Controllers/imstkKeyboardControl.h
@@ -0,0 +1,63 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkDeviceControl.h"
+#include "imstkTypes.h"
+
+namespace imstk
+{
+class KeyboardDeviceClient;
+class KeyPressEvent;
+
+///
+/// \class KeyboardSceneController
+///
+/// \brief This is the base class for keyboard based controls
+/// You can construct this and observe it or subclass and override
+/// to implement controls.
+///
+class KeyboardControl : public DeviceControl
+{
+public:
+    KeyboardControl() { }
+    KeyboardControl(std::shared_ptr<KeyboardDeviceClient> keyDevice);
+    virtual ~KeyboardControl() override = default;
+
+public:
+    virtual void setDevice(std::shared_ptr<DeviceClient> device) override;
+
+public:
+    virtual void OnKeyPress(const char imstkNotUsed(key)) { }
+
+    virtual void OnKeyRelease(const char imstkNotUsed(key)) { }
+
+    ///
+    /// \brief Posts key press/release events
+    /// override to filter the event, or implement OnkeyDown/OnKeyUp
+    ///
+    virtual void keyPressEvent(KeyPressEvent* e);
+
+protected:
+    std::shared_ptr<KeyboardDeviceClient> m_keyboardDeviceClient;
+};
+}
diff --git a/Source/Controllers/imstkLaparoscopicToolController.cpp b/Source/Controllers/imstkLaparoscopicToolController.cpp
index f478a84817e5179a290b690b73fbb4afdadd82c1..1aacbc3cb9bddaacedaff70dbfdc90976e6e9fe5 100644
--- a/Source/Controllers/imstkLaparoscopicToolController.cpp
+++ b/Source/Controllers/imstkLaparoscopicToolController.cpp
@@ -23,52 +23,47 @@
 #include "imstkCollidingObject.h"
 #include "imstkDeviceClient.h"
 #include "imstkGeometry.h"
-#include "imstkSceneObject.h"
 #include "imstkLogger.h"
-#include "imstkMath.h"
-
-#include <utility>
 
 namespace imstk
 {
 LaparoscopicToolController::LaparoscopicToolController(
-    std::shared_ptr<SceneObject>   shaft,
-    std::shared_ptr<SceneObject>   upperJaw,
-    std::shared_ptr<SceneObject>   lowerJaw,
-    std::shared_ptr<DeviceTracker> trackingController) :
-    SceneObjectControllerBase(),
-    m_trackingController(trackingController),
+    std::shared_ptr<SceneObject>  shaft,
+    std::shared_ptr<SceneObject>  upperJaw,
+    std::shared_ptr<SceneObject>  lowerJaw,
+    std::shared_ptr<DeviceClient> trackingDevice) :
+    TrackingDeviceControl(trackingDevice),
     m_shaft(shaft),
     m_upperJaw(upperJaw),
     m_lowerJaw(lowerJaw),
     m_jawRotationAxis(Vec3d(0, 1., 0))
 {
-    m_trackingController->getDeviceClient()->setButtonsEnabled(true);
+    trackingDevice->setButtonsEnabled(true);
 }
 
 void
 LaparoscopicToolController::updateControlledObjects()
 {
-    if (!m_trackingController->isTrackerUpToDate())
+    if (!isTrackerUpToDate())
     {
-        if (!m_trackingController->updateTrackingData())
+        if (!updateTrackingData())
         {
             LOG(WARNING) << "LaparoscopicToolController::updateControlledObjects warning: could not update tracking info.";
             return;
         }
     }
 
-    Vec3d p = m_trackingController->getPosition();
-    Quatd r = m_trackingController->getRotation();
+    Vec3d p = getPosition();
+    Quatd r = getRotation();
 
     // Update jaw angles
-    if (m_trackingController->getDeviceClient()->getButton(0))
+    if (m_deviceClient->getButton(0))
     {
         m_jawAngle += m_change;
         m_jawAngle  = (m_jawAngle > m_maxJawAngle) ? m_maxJawAngle : m_jawAngle;
     }
 
-    if (m_trackingController->getDeviceClient()->getButton(1))
+    if (m_deviceClient->getButton(1))
     {
         m_jawAngle -= m_change;
         m_jawAngle  = (m_jawAngle < 0.0) ? 0.0 : m_jawAngle;
@@ -111,6 +106,6 @@ LaparoscopicToolController::applyForces()
         force += collidingObject->getForce();
     }
 
-    m_trackingController->getDeviceClient()->setForce(force);
+    m_deviceClient->setForce(force);
 }
 } // imstk
diff --git a/Source/Controllers/imstkLaparoscopicToolController.h b/Source/Controllers/imstkLaparoscopicToolController.h
index ad05a19728e25e2266a957b88e1700dead8af344..2c1e1c9c41d504478ec2cafe31863fbe9de52a16 100644
--- a/Source/Controllers/imstkLaparoscopicToolController.h
+++ b/Source/Controllers/imstkLaparoscopicToolController.h
@@ -21,8 +21,7 @@
 
 #pragma once
 
-#include "imstkSceneObjectControllerBase.h"
-#include "imstkDeviceTracker.h"
+#include "imstkTrackingDeviceControl.h"
 
 namespace imstk
 {
@@ -36,25 +35,23 @@ class SceneObject;
 /// The jaws open-close based on the buttons at present.
 /// This has to be replaced by potentiometer tracking in future.
 ///
-class LaparoscopicToolController : public SceneObjectControllerBase
+class LaparoscopicToolController : public TrackingDeviceControl
 {
 public:
     ///
     /// \brief Constructor
     ///
     LaparoscopicToolController(
-        std::shared_ptr<SceneObject>   shaft,
-        std::shared_ptr<SceneObject>   upperJaw,
-        std::shared_ptr<SceneObject>   lowerJaw,
-        std::shared_ptr<DeviceTracker> trackingController);
+        std::shared_ptr<SceneObject>  shaft,
+        std::shared_ptr<SceneObject>  upperJaw,
+        std::shared_ptr<SceneObject>  lowerJaw,
+        std::shared_ptr<DeviceClient> trackingDevice);
 
     LaparoscopicToolController() = delete; //not allowed for now
 
-    ///
-    /// \brief Destructor
-    ///
-    ~LaparoscopicToolController() = default;
+    ~LaparoscopicToolController() override = default;
 
+public:
     ///
     /// \brief Update controlled laparoscopic tool using latest tracking information
     ///
@@ -65,11 +62,6 @@ public:
     ///
     void applyForces() override;
 
-    ///
-    /// \brief Set the tracker to out-of-date
-    ///
-    inline void setTrackerToOutOfDate() override { m_trackingController->setTrackerToOutOfDate(); }
-
     ///
     /// \brief Set the maximum jaw angle
     ///
@@ -95,16 +87,7 @@ public:
     ///
     inline double getMaxJawAngle() const { return m_maxJawAngle; }
 
-    ///
-    /// \brief Get/Set tracking controller
-    ///
-    inline std::shared_ptr<DeviceTracker> getTrackingController() const { return m_trackingController; }
-    inline void setTrackingController(std::shared_ptr<DeviceTracker> controller) { m_trackingController = controller; }
-
 protected:
-
-    std::shared_ptr<DeviceTracker> m_trackingController; ///< Device tracker
-
     std::shared_ptr<SceneObject> m_shaft;                ///< Tool shaft
     std::shared_ptr<SceneObject> m_upperJaw;             ///< Tool upper jaw
     std::shared_ptr<SceneObject> m_lowerJaw;             ///< Tool lower jaw
diff --git a/Source/Controllers/imstkMouseControl.cpp b/Source/Controllers/imstkMouseControl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..497c40ecaca1657bb7bd7dc4fa12320b154e0ab2
--- /dev/null
+++ b/Source/Controllers/imstkMouseControl.cpp
@@ -0,0 +1,71 @@
+/*=========================================================================
+
+   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 "imstkMouseControl.h"
+#include "imstkMouseDeviceClient.h"
+
+namespace imstk
+{
+MouseControl::MouseControl(std::shared_ptr<MouseDeviceClient> mouseDevice) :
+    DeviceControl(mouseDevice)
+{
+    setDevice(mouseDevice);
+}
+
+void
+MouseControl::setDevice(std::shared_ptr<DeviceClient> device)
+{
+    // Remove old observer if it exists
+    if (m_mouseDeviceClient != nullptr)
+    {
+        disconnect(m_mouseDeviceClient, this, EventType::MouseEvent);
+    }
+
+    // Set the new device
+    m_mouseDeviceClient = std::dynamic_pointer_cast<MouseDeviceClient>(device);
+    DeviceControl::setDevice(device);
+
+    // Subscribe to the device clients events
+    connect(m_mouseDeviceClient, EventType::MouseEvent, this, &MouseControl::mouseEvent);
+}
+
+void
+MouseControl::mouseEvent(MouseEvent* e)
+{
+    switch (e->m_mouseActionType)
+    {
+    case MOUSE_PRESS:
+        OnButtonPress(e->m_buttonId);
+        break;
+    case MOUSE_RELEASE:
+        OnButtonRelease(e->m_buttonId);
+        break;
+    case MOUSE_SCROLL:
+        OnScroll(e->m_scrollDx);
+        break;
+    case MOUSE_MOVE:
+        OnMouseMove(m_mouseDeviceClient->getPos());
+    default:
+        break;
+    }
+    ;
+}
+}
\ No newline at end of file
diff --git a/Source/Controllers/imstkMouseControl.h b/Source/Controllers/imstkMouseControl.h
new file mode 100644
index 0000000000000000000000000000000000000000..13f4a33a20825db1d31dd374d22df45e76738dbf
--- /dev/null
+++ b/Source/Controllers/imstkMouseControl.h
@@ -0,0 +1,68 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkDeviceControl.h"
+#include "imstkMath.h"
+#include "imstkTypes.h"
+
+namespace imstk
+{
+class MouseDeviceClient;
+class MouseEvent;
+
+///
+/// \class MouseControl
+///
+/// \brief This is the base class for mouse based controls
+/// It can be constructed and observed or subclassed and overridden
+/// to implement controls.
+///
+class MouseControl : public DeviceControl
+{
+public:
+    MouseControl() = default;
+    MouseControl(std::shared_ptr<MouseDeviceClient> mouseDevice);
+    virtual ~MouseControl() override = default;
+
+public:
+    virtual void setDevice(std::shared_ptr<DeviceClient> device) override;
+
+public:
+    virtual void OnButtonPress(const int imstkNotUsed(key)) { }
+
+    virtual void OnButtonRelease(const int imstkNotUsed(key)) { }
+
+    virtual void OnScroll(const double imstkNotUsed(dx)) { }
+
+    virtual void OnMouseMove(const Vec2d& imstkNotUsed(pos)) { }
+
+    ///
+    /// \brief Posts key press/release events
+    /// override to filter the event, or implement OnkeyDown/OnKeyUp
+    ///
+    virtual void mouseEvent(MouseEvent* e);
+
+protected:
+    std::shared_ptr<MouseDeviceClient> m_mouseDeviceClient;
+};
+}
diff --git a/Source/Controllers/imstkRigidObjectController.cpp b/Source/Controllers/imstkRigidObjectController.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2eaf23f48c797b83e22938f03a65de0f44818e2d
--- /dev/null
+++ b/Source/Controllers/imstkRigidObjectController.cpp
@@ -0,0 +1,105 @@
+/*=========================================================================
+
+   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 "imstkRigidObjectController.h"
+#include "imstkCollidingObject.h"
+#include "imstkDeviceClient.h"
+#include "imstkGeometry.h"
+#include "imstkLogger.h"
+#include "imstkRbdConstraint.h"
+#include "imstkRigidObject2.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+RigidObjectController::RigidObjectController(std::shared_ptr<RigidObject2> rigidObject,
+                                             std::shared_ptr<DeviceClient> trackingDevice) :
+    SceneObjectController(rigidObject, trackingDevice),
+    m_rigidObject(rigidObject)
+{
+    /*m_currentPos = rigidObject->getRigidBody()->getPosition();
+    m_currentRot = rigidObject->getRigidBody()->getOrientation();*/
+}
+
+void
+RigidObjectController::updateControlledObjects()
+{
+    if (!isTrackerUpToDate())
+    {
+        if (!updateTrackingData())
+        {
+            LOG(WARNING) << "SceneObjectController::updateControlledObjects warning: could not update tracking info.";
+            return;
+        }
+    }
+
+    this->postEvent(Event(EventType::Modified));
+
+    // During initialization tracking may not be enabled for a time, in which case, freeze the thing
+    // or else extraneous forces may be applied towards uninitialized position (0, 0, 0) or gravity
+    // pull it down
+    if (!m_deviceClient->getTrackingEnabled())
+    {
+        (*m_rigidObject->getRigidBody()->m_pos) = m_rigidObject->getRigidBody()->m_initPos;
+        (*m_rigidObject->getRigidBody()->m_orientation) = m_rigidObject->getRigidBody()->m_initOrientation;
+        return;
+    }
+
+    // Apply virtual coupling
+    const Vec3d currPos    = m_rigidObject->getRigidBody()->getPosition();
+    const Vec3d desiredPos = getPosition();
+    {
+        const Vec3d diff = desiredPos - currPos;
+        //const double length = diff.norm();
+        //const Vec3d  dir    = diff.normalized();
+
+        const Vec3d fS = m_linearKs.cwiseProduct(diff);
+        const Vec3d fD = m_rigidObject->getRigidBody()->getVelocity() * -m_linearKd;
+
+        // Apply spring force and general damper
+        (*m_rigidObject->getRigidBody()->m_force) += (fS + fD);
+    }
+
+    const Quatd currOrientation    = m_rigidObject->getRigidBody()->getOrientation();
+    const Quatd desiredOrientation = getRotation();
+    {
+        // q gives the delta rotation that gets us from curr->desired
+        const Quatd dq = desiredOrientation * currOrientation.inverse();
+        // Get the rotation axes
+        Rotd angleAxes = Rotd(dq);
+        angleAxes.axis().normalize();
+
+        // Because the scale of the *magnitude* of the rotation done is controllable
+        // it doesn't matter if its exact, ksTheta can just be adjusted
+        (*m_rigidObject->getRigidBody()->m_torque) += (angleAxes.axis() * angleAxes.angle()).cwiseProduct(m_rotKs);
+    }
+}
+
+void
+RigidObjectController::applyForces()
+{
+    // Apply force back to device
+    m_deviceClient->setForce(m_rigidObject->getRigidBody()->getForce());
+    //m_deviceClient->setTorque();
+}
+}
+}
diff --git a/Source/Controllers/imstkRigidObjectController.h b/Source/Controllers/imstkRigidObjectController.h
new file mode 100644
index 0000000000000000000000000000000000000000..a5bba421ed7197cb26d9e78b15852583f6e074f4
--- /dev/null
+++ b/Source/Controllers/imstkRigidObjectController.h
@@ -0,0 +1,91 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkSceneObjectController.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+class RigidObject2;
+
+///
+/// \class RigidObjectController
+///
+/// \brief This class uses the provide device to control the provided rigid object via
+/// virtual coupling. That is, it applies forces+torques to the rigid body that will
+/// help move it to desired position/orientation
+///
+class RigidObjectController : public SceneObjectController
+{
+public:
+    ///
+    /// \brief Constructor
+    ///
+    RigidObjectController(std::shared_ptr<RigidObject2> rigidObject, std::shared_ptr<DeviceClient> trackingDevice);
+    RigidObjectController() = delete;
+
+    ///
+    /// \brief Destructor
+    ///
+    virtual ~RigidObjectController() override = default;
+
+public:
+    ///
+    /// \brief Set/Get the linear damping coefficient
+    ///
+    double getLinearKd() const { return m_linearKd; }
+    void setLinearKd(double kd) { m_linearKd = kd; }
+
+    ///
+    /// \brief Set/Get the linear spring coefficient
+    ///
+    const Vec3d& getLinearKs() const { return m_linearKs; }
+    void setLinearKs(const Vec3d& ks) { m_linearKs = ks; }
+
+    ///
+    /// \brief Set/Get the rotationl spring coefficient
+    ///
+    const Vec3d& getRotKs() const { return m_rotKs; }
+    void setRotationalKs(const Vec3d& ks) { m_rotKs = ks; }
+
+public:
+    ///
+    /// \brief Update controlled scene object using latest tracking information
+    ///
+    void updateControlledObjects() override;
+
+    ///
+    /// \brief Apply forces to the haptic device
+    ///
+    void applyForces() override;
+
+protected:
+    std::shared_ptr<RigidObject2> m_rigidObject;
+
+    double m_linearKd = 800.0;                                  ///> Damping coefficient, linear
+    Vec3d  m_linearKs = Vec3d(2000000.0, 2000000.0, 2000000.0); ///> Spring coefficient, linear
+    Vec3d  m_rotKs    = Vec3d(1000.0, 1000.0, 1000.0);          //.> Spring coefficient, rotational
+};
+}
+}
diff --git a/Source/Controllers/imstkSceneObjectController.cpp b/Source/Controllers/imstkSceneObjectController.cpp
index 1b6a94a8e151a4a2d0c8d20ad62bbec0f0306c62..0913ff36e4e2538321b39e9ffa9f5f9ba99ecb87 100644
--- a/Source/Controllers/imstkSceneObjectController.cpp
+++ b/Source/Controllers/imstkSceneObjectController.cpp
@@ -20,40 +20,48 @@
 =========================================================================*/
 
 #include "imstkSceneObjectController.h"
-#include "imstkDeviceTracker.h"
-#include "imstkSceneObject.h"
-#include "imstkDeviceClient.h"
 #include "imstkCollidingObject.h"
+#include "imstkDeviceClient.h"
 #include "imstkGeometry.h"
 #include "imstkLogger.h"
 
 namespace imstk
 {
-SceneObjectController::SceneObjectController(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<DeviceTracker> trackingController) :
-    m_trackingController(trackingController), m_sceneObject(sceneObject)
+SceneObjectController::SceneObjectController(std::shared_ptr<SceneObject>  sceneObject,
+                                             std::shared_ptr<DeviceClient> trackingDevice) :
+    TrackingDeviceControl(trackingDevice),
+    m_sceneObject(sceneObject)
 {
 }
 
 void
 SceneObjectController::updateControlledObjects()
 {
-    if (!m_trackingController->isTrackerUpToDate())
+    if (!isTrackerUpToDate())
     {
-        if (!m_trackingController->updateTrackingData())
+        if (!updateTrackingData())
         {
             LOG(WARNING) << "SceneObjectController::updateControlledObjects warning: could not update tracking info.";
             return;
         }
     }
 
-    if (m_updateCallback)
+    if (m_sceneObject == nullptr)
+    {
+        return;
+    }
+
+    if (!m_deviceClient->getTrackingEnabled())
     {
-        m_updateCallback(this);
+        return;
     }
 
-    // Update colliding geometry
-    m_sceneObject->getMasterGeometry()->setTranslation(m_trackingController->getPosition());
-    m_sceneObject->getMasterGeometry()->setRotation(m_trackingController->getRotation());
+    this->postEvent(Event(EventType::Modified));
+
+    // Update geometry
+    // \todo revisit this; what if we need to move a group of objects
+    m_sceneObject->getMasterGeometry()->setTranslation(getPosition());
+    m_sceneObject->getMasterGeometry()->setRotation(getRotation());
 }
 
 void
@@ -61,13 +69,7 @@ SceneObjectController::applyForces()
 {
     if (auto collidingObject = dynamic_cast<CollidingObject*>(m_sceneObject.get()))
     {
-        m_trackingController->getDeviceClient()->setForce(collidingObject->getForce());
+        m_deviceClient->setForce(collidingObject->getForce());
     }
 }
-
-void
-SceneObjectController::setTrackerToOutOfDate()
-{
-    m_trackingController->setTrackerToOutOfDate();
-}
-} // imstk
+}
\ No newline at end of file
diff --git a/Source/Controllers/imstkSceneObjectController.h b/Source/Controllers/imstkSceneObjectController.h
index 9a35ead4c5a8c8b873c513abc7c3ebd3e03b16d2..914430fb7dc5d6a1e599d48e5fdb5f88d597a593 100644
--- a/Source/Controllers/imstkSceneObjectController.h
+++ b/Source/Controllers/imstkSceneObjectController.h
@@ -21,74 +21,44 @@
 
 #pragma once
 
-#include "imstkSceneObjectControllerBase.h"
+#include "imstkTrackingDeviceControl.h"
 
-#include <memory>
 #include <functional>
 
 namespace imstk
 {
 class SceneObject;
-class DeviceTracker;
 
 ///
 /// \class SceneObjectController
 ///
-/// \brief This class implements once tracking controller controlling one scnene object
+/// \brief This class implements once tracking controller controlling one scene object
 ///
-class SceneObjectController : public SceneObjectControllerBase
+class SceneObjectController : public TrackingDeviceControl
 {
-using ControllerCallbackFunction = std::function<void (SceneObjectController* hdapiClient)>;
-
 public:
-    ///
-    /// \brief Constructor
-    ///
-    SceneObjectController(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<DeviceTracker> trackingController);
-
+    SceneObjectController(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<DeviceClient> trackingDevice);
     SceneObjectController() = delete;
+    virtual ~SceneObjectController() override = default;
 
-    ///
-    /// \brief Destructor
-    ///
-    ~SceneObjectController() = default;
-
+public:
     ///
     /// \brief Update controlled scene object using latest tracking information
     ///
     void updateControlledObjects() override;
 
     ///
-    /// \brief Apply forces to the haptic device
+    /// \brief Apply forces to the haptic-capable device
     ///
     void applyForces() override;
 
-    ///
-    /// \brief Sets the tracker to out-of-date
-    ///
-    void setTrackerToOutOfDate() override;
-
     ///
     /// \brief Get/Set controlled scene object
     ///
     inline std::shared_ptr<SceneObject> getControlledSceneObject() const { return m_sceneObject; }
     inline void setControlledSceneObject(std::shared_ptr<SceneObject> so) { m_sceneObject = so; }
 
-    ///
-    /// \brief Get/Set tracking controller
-    ///
-    inline std::shared_ptr<DeviceTracker> getTrackingController() const { return m_trackingController; }
-    inline void setTrackingController(std::shared_ptr<DeviceTracker> controller) { m_trackingController = controller; }
-
-    ///
-    /// \brief Setting custom behavior functions
-    ///
-    inline void setUpdateCallback(ControllerCallbackFunction foo) { m_updateCallback = foo; }
-
 protected:
-    std::shared_ptr<DeviceTracker> m_trackingController; ///< Device tracker
-    std::shared_ptr<SceneObject>   m_sceneObject;        ///< SceneObject controlled by the Tracker
-    //Callback functions
-    ControllerCallbackFunction m_updateCallback;         ///> function callback preceding module update
+    std::shared_ptr<SceneObject> m_sceneObject; ///< SceneObject controlled by the Tracker
 };
 } // imstk
diff --git a/Source/Controllers/imstkDeviceTracker.cpp b/Source/Controllers/imstkTrackingDeviceControl.cpp
similarity index 76%
rename from Source/Controllers/imstkDeviceTracker.cpp
rename to Source/Controllers/imstkTrackingDeviceControl.cpp
index 7ed271c3423f2a69460d42d0caea063041907a54..29407d62bbfd5205fa860fa7cb37eda5de440f4f 100644
--- a/Source/Controllers/imstkDeviceTracker.cpp
+++ b/Source/Controllers/imstkTrackingDeviceControl.cpp
@@ -19,24 +19,28 @@
 
 =========================================================================*/
 
-#include "imstkMath.h"
-#include "imstkDeviceTracker.h"
+#include "imstkTrackingDeviceControl.h"
 #include "imstkDeviceClient.h"
 #include "imstkLogger.h"
-
-#include <utility>
+#include "imstkMath.h"
 
 namespace imstk
 {
-DeviceTracker::DeviceTracker(std::shared_ptr<DeviceClient> deviceClient) :
-    m_deviceClient(deviceClient),
+TrackingDeviceControl::TrackingDeviceControl() :
+    m_translationOffset(WORLD_ORIGIN),
+    m_rotationOffset(Quatd::Identity())
+{
+}
+
+TrackingDeviceControl::TrackingDeviceControl(std::shared_ptr<DeviceClient> device) :
+    DeviceControl(device),
     m_translationOffset(WORLD_ORIGIN),
     m_rotationOffset(Quatd::Identity())
 {
 }
 
 bool
-DeviceTracker::updateTrackingData()
+TrackingDeviceControl::updateTrackingData()
 {
     if (m_deviceClient == nullptr)
     {
@@ -44,6 +48,8 @@ DeviceTracker::updateTrackingData()
         return false;
     }
 
+    m_deviceClient->update();
+
     // Retrieve device info
     m_currentPos = m_deviceClient->getPosition();
     m_currentRot = m_deviceClient->getOrientation();
@@ -83,62 +89,50 @@ DeviceTracker::updateTrackingData()
     return true;
 }
 
-std::shared_ptr<DeviceClient>
-DeviceTracker::getDeviceClient() const
-{
-    return m_deviceClient;
-}
-
-void
-DeviceTracker::setDeviceClient(std::shared_ptr<DeviceClient> deviceClient)
-{
-    m_deviceClient = deviceClient;
-}
-
 double
-DeviceTracker::getTranslationScaling() const
+TrackingDeviceControl::getTranslationScaling() const
 {
     return m_scaling;
 }
 
 void
-DeviceTracker::setTranslationScaling(double scaling)
+TrackingDeviceControl::setTranslationScaling(const double scaling)
 {
     m_scaling = scaling;
 }
 
 const Vec3d&
-DeviceTracker::getTranslationOffset() const
+TrackingDeviceControl::getTranslationOffset() const
 {
     return m_translationOffset;
 }
 
 void
-DeviceTracker::setTranslationOffset(const Vec3d& t)
+TrackingDeviceControl::setTranslationOffset(const Vec3d& t)
 {
     m_translationOffset = t;
 }
 
 const Quatd&
-DeviceTracker::getRotationOffset()
+TrackingDeviceControl::getRotationOffset()
 {
     return m_rotationOffset;
 }
 
 void
-DeviceTracker::setRotationOffset(const Quatd& r)
+TrackingDeviceControl::setRotationOffset(const Quatd& r)
 {
     m_rotationOffset = r;
 }
 
 unsigned char
-DeviceTracker::getInversionFlags()
+TrackingDeviceControl::getInversionFlags()
 {
     return m_invertFlags;
 }
 
 void
-DeviceTracker::setInversionFlags(unsigned char f)
+TrackingDeviceControl::setInversionFlags(const unsigned char f)
 {
     m_invertFlags = f;
 }
diff --git a/Source/Controllers/imstkDeviceTracker.h b/Source/Controllers/imstkTrackingDeviceControl.h
similarity index 69%
rename from Source/Controllers/imstkDeviceTracker.h
rename to Source/Controllers/imstkTrackingDeviceControl.h
index 6b6914f382766a01315448f7872137cf89c202f3..c887b5edd4cab5ba59084aa52e28b5e6a2208536 100644
--- a/Source/Controllers/imstkDeviceTracker.h
+++ b/Source/Controllers/imstkTrackingDeviceControl.h
@@ -21,25 +21,21 @@
 
 #pragma once
 
+#include "imstkDeviceControl.h"
 #include "imstkMath.h"
 
 namespace imstk
 {
-class DeviceClient;
-
 ///
-/// \class DeviceTracker
+/// \class TrackingDeviceControl
 ///
-/// \brief This class reports external device's position and orientation with a given offset
+/// \brief Base class for all DeviceControls that track
+/// something in space (position and orientation)
+/// ?? rename with 'spacial' in it?
 ///
-class DeviceTracker
+class TrackingDeviceControl : public DeviceControl
 {
 public:
-
-    ///
-    /// \enum
-    /// \brief TODO
-    ///
     enum InvertFlag
     {
         transX = 0x01,
@@ -50,32 +46,59 @@ public:
         rotZ = 0x20
     };
 
+public:
+    TrackingDeviceControl();
+    TrackingDeviceControl(std::shared_ptr<DeviceClient> device);
+    virtual ~TrackingDeviceControl() override = default;
+
+public:
     ///
-    /// \brief Constructor
+    /// \brief Update controlled scene objects using latest tracking information
+    /// \todo get rid of updateControlledObjects? replace with update (from DeviceControl)
     ///
-    explicit DeviceTracker(std::shared_ptr<DeviceClient> deviceClient);
+    virtual void updateControlledObjects() {}
 
     ///
-    /// \brief Destructor
+    /// \brief Apply forces to the haptic device
     ///
-    ~DeviceTracker() = default;
+    virtual void applyForces() {}
 
     ///
-    /// \brief Compute the world position and orientation
+    /// \brief Sets the tracking data to be out of date or up to date
     ///
-    bool updateTrackingData();
+    void setTrackerToOutOfDate() { m_trackingDataUptoDate = false; }
+    void setTrackerToUpToDate() { m_trackingDataUptoDate = true; }
 
     ///
-    /// \brief Get/Set the device client
+    /// \brief Returns true if the tracking data is already updated in current frame. Else, false.
+    ///
+    bool isTrackerUpToDate() const { return m_trackingDataUptoDate; }
+
+    ///
+    /// \brief Get the latest position
     ///
-    std::shared_ptr<DeviceClient> getDeviceClient() const;
-    void setDeviceClient(std::shared_ptr<DeviceClient> deviceClient);
+    const Vec3d& getPosition() const { return m_currentPos; };
+
+    ///
+    /// \brief Set the position of the tracker
+    ///
+    void setPosition(const Vec3d& pos) { this->m_currentPos = pos; }
+
+    ///
+    /// \brief Get the latest rotation
+    ///
+    const Quatd& getRotation() const { return m_currentRot; };
+
+    ///
+    /// \brief Set the orientation of the tracker
+    ///
+    void setRotation(const Quatd& orientation) { this->m_currentRot = orientation; }
 
     ///
     /// \brief Get/Set the current scaling factor
     ///
     double getTranslationScaling() const;
-    void setTranslationScaling(double scaling);
+    void setTranslationScaling(const double scaling);
 
     ///
     /// \brief Get/Set the translation offset
@@ -93,32 +116,14 @@ public:
     /// \brief Get/Set the inversion flags
     ///
     unsigned char getInversionFlags();
-    void setInversionFlags(unsigned char f);
-
-    ///
-    /// \brief Sets the tracking data to be out of date or up to date
-    ///
-    void setTrackerToOutOfDate() { m_trackingDataUptoDate = false; }
-    void setTrackerToUpToDate() { m_trackingDataUptoDate = true; }
+    void setInversionFlags(const unsigned char f);
 
     ///
-    /// \brief Returns true if the tracking data is already updated in current frame. Else, false.
-    ///
-    bool isTrackerUpToDate() const { return m_trackingDataUptoDate; }
-
-    ///
-    /// \brief Get the latest position
-    ///
-    const Vec3d& getPosition() { return m_currentPos; };
-
-    ///
-    /// \brief Get the latest rotation
+    /// \brief Compute the world position and orientation
     ///
-    const Quatd& getRotation() { return m_currentRot; };
+    bool updateTrackingData();
 
 protected:
-
-    std::shared_ptr<DeviceClient> m_deviceClient;          ///< Reports device tracking information
     double m_scaling = 1.0;                                ///< Scaling factor for physical to virtual translations
     Vec3d  m_translationOffset;                            ///< Translation concatenated to the device translation
     Quatd  m_rotationOffset;                               ///< Rotation concatenated to the device rotation
@@ -126,6 +131,6 @@ protected:
 
     Vec3d m_currentPos;
     Quatd m_currentRot;
-    bool  m_trackingDataUptoDate = false; ///< Keeps track of the device update in a given frame
+    bool  m_trackingDataUptoDate = false;
 };
 } // imstk
diff --git a/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp b/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp
index f012ed0a4fa139ec3d63e56a8ba7c6ca670a16d2..b87fee611f7e24502cf68205b62ed67569beba8d 100644
--- a/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp
+++ b/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp
@@ -20,15 +20,9 @@
 =========================================================================*/
 
 #include "gtest/gtest.h"
-#include "gmock/gmock.h"
 
-#include "imstkMath.h"
-#include "imstkPointSet.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkLooseOctree.h"
-#include "imstkParallelUtils.h"
-
-#include <queue>
 
 using namespace imstk;
 
diff --git a/Source/DataStructures/Testing/imstkNeighborSearchTest.cpp b/Source/DataStructures/Testing/imstkNeighborSearchTest.cpp
index f83dcd2c441b32ecb0142d114767b9347bf23772..81980ca5d8755bb720f2600258847e7d602391e3 100644
--- a/Source/DataStructures/Testing/imstkNeighborSearchTest.cpp
+++ b/Source/DataStructures/Testing/imstkNeighborSearchTest.cpp
@@ -20,9 +20,7 @@
 =========================================================================*/
 
 #include "gtest/gtest.h"
-#include "gmock/gmock.h"
 
-#include "imstkMath.h"
 #include "imstkSpatialHashTableSeparateChaining.h"
 #include "imstkGridBasedNeighborSearch.h"
 
diff --git a/Source/DataStructures/imstkGraph.cpp b/Source/DataStructures/imstkGraph.cpp
index 09705ed2981515b60406c28605df8b81a69bd336..f056435e7a46f5724ee72bb57db5099ba7e76ba4 100644
--- a/Source/DataStructures/imstkGraph.cpp
+++ b/Source/DataStructures/imstkGraph.cpp
@@ -19,17 +19,11 @@
 
 =========================================================================*/
 
-#include <algorithm>
-#include <numeric>
-#include <map>
-#include <climits>
-#undef min
-#undef max
-
 #include "imstkGraph.h"
+#include "imstkLogger.h"
 #include "imstkParallelUtils.h"
 
-#include <g3log/g3log.hpp>
+#include <numeric>
 
 namespace imstk
 {
diff --git a/Source/DataStructures/imstkGraph.h b/Source/DataStructures/imstkGraph.h
index 26ab939b2de0fb1ab8ba3ef7fa0d38f5d0a4a62a..75752ee7355f368dd36d8b9464ad5df0eea5af2f 100644
--- a/Source/DataStructures/imstkGraph.h
+++ b/Source/DataStructures/imstkGraph.h
@@ -22,10 +22,7 @@
 #pragma once
 
 #include <unordered_set>
-#include <iostream>
-#include <algorithm>
-
-#include "imstkMath.h"
+#include <vector>
 
 namespace imstk
 {
diff --git a/Source/DataStructures/imstkGridBasedNeighborSearch.cpp b/Source/DataStructures/imstkGridBasedNeighborSearch.cpp
index 56ebe4b307a6152c75bd519c42db2b69fbdf67de..20a1f90b8c957917d33bb13e43b5b3398a83fabf 100644
--- a/Source/DataStructures/imstkGridBasedNeighborSearch.cpp
+++ b/Source/DataStructures/imstkGridBasedNeighborSearch.cpp
@@ -21,7 +21,6 @@
 
 #include "imstkGridBasedNeighborSearch.h"
 #include "imstkParallelUtils.h"
-#include "imstkLogger.h"
 
 namespace imstk
 {
diff --git a/Source/DataStructures/imstkLooseOctree.cpp b/Source/DataStructures/imstkLooseOctree.cpp
index 0ef44a90ba33b6dedd8e77d4cbb2f009d2539022..1c24e579256a308128588fe6ab5732ceb49d514d 100644
--- a/Source/DataStructures/imstkLooseOctree.cpp
+++ b/Source/DataStructures/imstkLooseOctree.cpp
@@ -20,12 +20,9 @@
 =========================================================================*/
 
 #include "imstkLooseOctree.h"
-
-#include "imstkGeometry.h"
-#include "imstkPointSet.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkDebugRenderGeometry.h"
-//#include "imstkRenderMaterial.h"
+#include "imstkLogger.h"
+#include "imstkSurfaceMesh.h"
 
 namespace imstk
 {
diff --git a/Source/DataStructures/imstkLooseOctree.h b/Source/DataStructures/imstkLooseOctree.h
index d09a5cd64b896355ba7ffcfc52ccf84567d3c663..638ac6c65004ac29649d583e5b390750b41fac70 100644
--- a/Source/DataStructures/imstkLooseOctree.h
+++ b/Source/DataStructures/imstkLooseOctree.h
@@ -23,17 +23,13 @@
 
 #include "imstkMath.h"
 #include "imstkParallelUtils.h"
-#include "imstkLogger.h"
 
 #include <array>
-#include <cstdint>
-#include <climits>
-#include <memory>
-#include <unordered_map>
 #include <unordered_set>
-#include <vector>
 
+#ifdef WIN32
 #pragma warning(disable : 4201)
+#endif
 namespace imstk
 {
 class OctreeNode;
@@ -148,6 +144,26 @@ public:
     ///
     uint32_t getPrimitiveCount(const OctreePrimitiveType type) const { return m_PrimitiveCounts[type]; }
 
+    ///
+    /// \brief Get the bounds of the node
+    ///
+    const Vec6d getBounds()
+    {
+        Vec6d bounds;
+        bounds << m_LowerBound[0], m_UpperBound[0], m_LowerBound[1], m_UpperBound[1], m_LowerBound[2], m_UpperBound[2];
+        return bounds;
+    }
+
+    ///
+    /// \brief Get the loose bounds of the node
+    ///
+    const Vec6d getLooseBounds()
+    {
+        Vec6d bounds;
+        bounds << m_LowerExtendedBound[0], m_UpperExtendedBound[0], m_LowerExtendedBound[1], m_UpperExtendedBound[1], m_LowerExtendedBound[2], m_UpperExtendedBound[2];
+        return bounds;
+    }
+
     ///
     /// \brief Recursively clear primitive data (linked lists and counters)
     /// Note that the primitives are still exist in the octree primitive list, they are just removed from the node
@@ -535,6 +551,7 @@ protected:
 
     Real     m_MinWidth;                                         ///> Minimum width allowed for the tree nodes
     uint32_t m_MaxDepth;                                         ///> Max depth of the tree, which is computed based on m_MinWidth
+    bool     m_useMaxDepth;                                      ///> If on max depth specified by user will be used, otherwise maxdepth is based of minwidth
 
     OctreeNode* const m_pRootNode;                               ///> Root node, should not be reassigned throughout the existence of the tree
     OctreeNodeBlock*  m_pNodeBlockPoolHead = nullptr;            ///> The pool of tree nodes, storing pre-allocated nodes as a linked list
@@ -570,4 +587,6 @@ protected:
     bool m_bDrawNonEmptyParent = true;
 };
 } // end namespace imstk
+#ifdef WIN32
 #pragma warning(default : 4201)
+#endif
diff --git a/Source/DataStructures/imstkSpatialHashTableSeparateChaining.h b/Source/DataStructures/imstkSpatialHashTableSeparateChaining.h
index 84b4bafd4dfb7b33d5de20591b187d703e2782ed..501928348e6085f902e995925eb491d473caa73a 100644
--- a/Source/DataStructures/imstkSpatialHashTableSeparateChaining.h
+++ b/Source/DataStructures/imstkSpatialHashTableSeparateChaining.h
@@ -21,10 +21,10 @@
 
 #pragma once
 
-#include <unordered_set>
-
-#include "imstkMath.h"
 #include "imstkSpatialHashTable.h"
+#include "imstkMath.h"
+
+#include <unordered_set>
 
 namespace imstk
 {
diff --git a/Source/DataStructures/imstkUniformSpatialGrid.h b/Source/DataStructures/imstkUniformSpatialGrid.h
index 449ac7b76212a87e75026890b06bf19c1600476c..3ed8dbfa31861d56bf730e6f2178b7734934b25a 100644
--- a/Source/DataStructures/imstkUniformSpatialGrid.h
+++ b/Source/DataStructures/imstkUniformSpatialGrid.h
@@ -21,11 +21,11 @@
 
 #pragma once
 
-#include <array>
-
 #include "imstkMath.h"
 #include "imstkLogger.h"
 
+#include <array>
+
 namespace imstk
 {
 ///
diff --git a/Source/Devices/CMakeLists.txt b/Source/Devices/CMakeLists.txt
index 83e5e995fa7283bcf8e360a999df99158e1adf68..257f55e9a5ab7ed360a28a8097dc020920716f31 100644
--- a/Source/Devices/CMakeLists.txt
+++ b/Source/Devices/CMakeLists.txt
@@ -5,6 +5,12 @@
 list(APPEND Dependencies
   Common
   VRPN)
+  
+include(imstkAddLibrary)
+set(HAPTIC_DEVICE_LIBS)
+if(${PROJECT_NAME}_USE_OpenHaptics)
+  set(HAPTIC_DEVICE_LIBS OpenHapticsSDK)
+endif()
 
 list(APPEND ExclusionFiles "")
 if(${PROJECT_NAME}_USE_OpenHaptics)
@@ -12,17 +18,18 @@ if(${PROJECT_NAME}_USE_OpenHaptics)
     ${HAPTIC_DEVICE_LIBS})
 else()
   list(APPEND ExclusionFiles
-    imstkHDAPIDeviceClient.h
-    imstkHDAPIDeviceClient.cpp
-    imstkHDAPIDeviceServer.h
-    imstkHDAPIDeviceServer.cpp)
+    imstkHapticDeviceClient.h
+    imstkHapticDeviceClient.cpp
+    imstkHapticDeviceManager.h
+    imstkHapticDeviceManager.cpp)
 endif()
 
-include(imstkAddLibrary)
 set(HAPTIC_DEVICE_LIBS)
 if(${PROJECT_NAME}_USE_OpenHaptics)
   set(HAPTIC_DEVICE_LIBS OpenHapticsSDK)
 endif()
+
+include(imstkAddLibrary)
 imstk_add_library(Devices
   EXCLUDE_FILES
     ${ExclusionFiles}
diff --git a/Source/Devices/imstkDeviceClient.cpp b/Source/Devices/imstkDeviceClient.cpp
index 6f7f5db5c0dc0202420355f9ce1d4000fb934302..d1facf8c6e822472e937b8f2ed0584f11e348083 100644
--- a/Source/Devices/imstkDeviceClient.cpp
+++ b/Source/Devices/imstkDeviceClient.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkDeviceClient.h"
-
 #include "imstkLogger.h"
 
 namespace imstk
@@ -125,24 +124,6 @@ DeviceClient::getOrientation() const
     return m_orientation;
 }
 
-const std::map<size_t, bool>&
-DeviceClient::getButtons() const
-{
-    return m_buttons;
-}
-
-bool
-DeviceClient::getButton(size_t buttonId) const
-{
-    if (m_buttons.find(buttonId) == m_buttons.end())
-    {
-        LOG(WARNING) << "DeviceClient::getButton warning: button "
-                     << buttonId << " was not found in the buttons list.";
-        return false;
-    }
-    return m_buttons.at(buttonId);
-}
-
 const Vec3d&
 DeviceClient::getForce() const
 {
diff --git a/Source/Devices/imstkDeviceClient.h b/Source/Devices/imstkDeviceClient.h
index 2f9bc39e7b554a322f391ced0f0e7a88c62a8991..53b2989375de05bfa284e3f5e469116447edaa20 100644
--- a/Source/Devices/imstkDeviceClient.h
+++ b/Source/Devices/imstkDeviceClient.h
@@ -22,22 +22,29 @@
 #pragma once
 
 #include "imstkMath.h"
+#include "imstkEventObject.h"
+
+#include <unordered_map>
 
 namespace imstk
 {
 ///
 /// \class DeviceClient
-/// \brief Base class for any device client
 ///
-class DeviceClient
+/// \brief The device client's represents the device and provides
+/// an interface to acquire data from a device.
+/// It posts events the device may have as well as provides the state
+/// \todo HAVE AN ABSTRACK BASE CLASS FOR THE DEVICE CLIENT
+///
+class DeviceClient : public EventObject
 {
 public:
-
     ///
     /// \brief Destructor
     ///
-    virtual ~DeviceClient() {}
+    virtual ~DeviceClient() = default;
 
+public:
     ///
     /// \brief Get/Set the device IP
     ///
@@ -77,27 +84,33 @@ public:
     ///
     const Quatd& getOrientation() const;
 
-    ///
-    /// \brief Get the status of the device buttons
-    ///
-    const std::map<size_t, bool>& getButtons() const;
-
-    ///
-    /// \brief Get the status of a device button
-    ///
-    bool getButton(size_t buttonId) const;
-
     ///
     /// \brief Get/Set the device force
     ///
     const Vec3d& getForce() const;
     void setForce(Vec3d force);
 
-protected:
+    const std::unordered_map<int, int>& getButtons() const { return m_buttons; }
 
     ///
-    /// \brief Constructor
+    /// \brief Get the state of a button
+    /// returns 0 if can't find button
     ///
+    const int getButton(const int buttonId) const
+    {
+        if (m_buttons.find(buttonId) != m_buttons.end())
+        {
+            return m_buttons.at(buttonId);
+        }
+        else
+        {
+            return 0;
+        }
+    }
+
+    virtual void update() {}
+
+protected:
     DeviceClient(const std::string& name, const std::string& ip);
 
     std::string m_deviceName;                ///< Device Name
@@ -111,7 +124,8 @@ protected:
     Vec3d m_position;                        ///< Position of end effector
     Vec3d m_velocity;                        ///< Linear velocity of end effector
     Quatd m_orientation;                     ///< Orientation of the end effector
-    std::map<size_t, bool> m_buttons;        ///< Buttons: true = pressed/false = not pressed
     Vec3d m_force;                           ///< Force vector
+
+    std::unordered_map<int, int> m_buttons;
 };
 }
diff --git a/Source/Devices/imstkDummyClient.cpp b/Source/Devices/imstkDummyClient.cpp
index f40d7de11494c09709ad9595fc39dbbdc6573d22..64635c910e9a8a7bbbd1b5b59d9ed0d0ecb93431 100644
--- a/Source/Devices/imstkDummyClient.cpp
+++ b/Source/Devices/imstkDummyClient.cpp
@@ -19,10 +19,7 @@
 
 =========================================================================*/
 
-#include <map>
-
 #include "imstkDummyClient.h"
-
 #include "imstkLogger.h"
 
 namespace imstk
diff --git a/Source/Devices/imstkDummyClient.h b/Source/Devices/imstkDummyClient.h
index a21fcdeae125d2971f2552011880d24a80f75268..3027818028e87f82a3e2f92cdfd11e4eccc77d6a 100644
--- a/Source/Devices/imstkDummyClient.h
+++ b/Source/Devices/imstkDummyClient.h
@@ -23,6 +23,8 @@
 
 #include "imstkDeviceClient.h"
 
+#include <unordered_map>
+
 namespace imstk
 {
 ///
@@ -38,7 +40,7 @@ public:
     /// \brief Constructor/Destructor
     ///
     explicit DummyClient(const std::string& name) : DeviceClient(name, "localhost") {}
-    virtual ~DummyClient() {}
+    virtual ~DummyClient() override = default;
 
 protected:
 
@@ -84,5 +86,8 @@ public:
     /// \brief Set the button status if it exists
     ///
     void setButton(const unsigned int buttonId, const bool buttonStatus);
+
+protected:
+    std::unordered_map<int, bool> m_buttons;
 };
 }
diff --git a/Source/Devices/imstkHDAPIDeviceClient.cpp b/Source/Devices/imstkHapticDeviceClient.cpp
similarity index 81%
rename from Source/Devices/imstkHDAPIDeviceClient.cpp
rename to Source/Devices/imstkHapticDeviceClient.cpp
index 654e22acd62afa36e2c73b704e284351705c4e5b..beac639ef00c9643ed2429d57fbe4669256eb366 100644
--- a/Source/Devices/imstkHDAPIDeviceClient.cpp
+++ b/Source/Devices/imstkHapticDeviceClient.cpp
@@ -19,25 +19,27 @@
 
 =========================================================================*/
 
-#include "imstkHDAPIDeviceClient.h"
+#include "imstkHapticDeviceClient.h"
+#include "imstkLogger.h"
 
-#include <HDU/hduVector.h>
 #include <HDU/hduError.h>
-
-#include "imstkLogger.h"
+#include <HDU/hduVector.h>
 
 namespace imstk
 {
 void
-HDAPIDeviceClient::init()
+HapticDeviceClient::initialize()
 {
-    m_buttons = std::map<size_t, bool>{ { 0, false }, { 1, false }, { 2, false }, { 3, false } };
+    m_buttons[0] = 0;
+    m_buttons[1] = 0;
+    m_buttons[2] = 0;
+    m_buttons[3] = 0;
 
     //flush error stack
     HDErrorInfo errorFlush;
     while (HD_DEVICE_ERROR(errorFlush = hdGetError())) {}
 
-    // Open Device
+    // Initialize the device
     m_handle = hdInitDevice(this->getDeviceName().c_str());
 
     // If failed
@@ -53,31 +55,38 @@ HDAPIDeviceClient::init()
 }
 
 void
-HDAPIDeviceClient::run()
+HapticDeviceClient::update()
 {
     hdScheduleSynchronous(hapticCallback, this, HD_MAX_SCHEDULER_PRIORITY);
 }
 
 void
-HDAPIDeviceClient::cleanUp()
+HapticDeviceClient::disable()
 {
     hdDisableDevice(m_handle);
 }
 
 HDCallbackCode HDCALLBACK
-HDAPIDeviceClient::hapticCallback(void* pData)
+HapticDeviceClient::hapticCallback(void* pData)
 {
-    auto client = reinterpret_cast<HDAPIDeviceClient*>(pData);
-    auto handle = client->m_handle;
-    auto state  = client->m_state;
+    auto    client = static_cast<HapticDeviceClient*>(pData);
+    HHD     handle = client->m_handle;
+    HDstate state  = client->m_state;
+
+    if (handle == HD_BAD_HANDLE || handle == HD_INVALID_HANDLE)
+    {
+        return HD_CALLBACK_DONE;
+    }
 
     hdBeginFrame(handle);
+
     hdMakeCurrentDevice(handle);
     hdSetDoublev(HD_CURRENT_FORCE, client->m_force.data());
     hdGetDoublev(HD_CURRENT_POSITION, state.pos);
     hdGetDoublev(HD_CURRENT_VELOCITY, state.vel);
     hdGetDoublev(HD_CURRENT_TRANSFORM, state.trans);
     hdGetIntegerv(HD_CURRENT_BUTTONS, &state.buttons);
+
     hdEndFrame(handle);
 
     client->m_position << state.pos[0], state.pos[1], state.pos[2];
@@ -88,6 +97,8 @@ HDAPIDeviceClient::hapticCallback(void* pData)
     client->m_buttons[2]  = state.buttons & HD_DEVICE_BUTTON_3;
     client->m_buttons[3]  = state.buttons & HD_DEVICE_BUTTON_4;
 
+    client->m_trackingEnabled = true;
+
     return HD_CALLBACK_DONE;
 }
 } // imstk
diff --git a/Source/Devices/imstkHDAPIDeviceClient.h b/Source/Devices/imstkHapticDeviceClient.h
similarity index 69%
rename from Source/Devices/imstkHDAPIDeviceClient.h
rename to Source/Devices/imstkHapticDeviceClient.h
index 525054168d34ed7d5a03656e4a8360dc0513b68c..ed9b11ff57fcc49d9d4e8e6c58eb671e5c702056 100644
--- a/Source/Devices/imstkHDAPIDeviceClient.h
+++ b/Source/Devices/imstkHapticDeviceClient.h
@@ -27,8 +27,9 @@
 
 namespace imstk
 {
-struct HD_state
+struct HDstate
 {
+    // \todo pos are redundant?
     HDdouble pos[3];
     HDdouble vel[3];
     HDdouble trans[16];
@@ -38,35 +39,36 @@ struct HD_state
 ///
 /// \class HDAPIDeviceClient
 /// \brief Subclass of DeviceClient for phantom omni
+/// Holds and updates the data sync or on its own thread
+/// Holder of data
 ///
-class HDAPIDeviceClient : public DeviceClient
+class HapticDeviceClient : public DeviceClient
 {
+friend class HapticDeviceManager;
+
 public:
+    virtual ~HapticDeviceClient() {}
 
+protected:
     ///
-    /// \brief Constructor/Destructor
+    /// \brief Constructor/Destructor, only the DeviceManager can construct
     ///
-    explicit HDAPIDeviceClient(const std::string& name) : DeviceClient(name, "localhost") {}
-    virtual ~HDAPIDeviceClient() {}
-
-protected:
-
-    friend class HDAPIDeviceServer;
+    HapticDeviceClient(const std::string& name) : DeviceClient(name, "localhost"), m_handle(HD_INVALID_HANDLE) { }
 
     ///
     /// \brief Initialize the phantom omni device
     ///
-    void init();
+    void initialize();
 
     ///
     /// \brief Use callback to get tracking data from phantom omni
     ///
-    void run();
+    void update() override;
 
     ///
-    /// \brief Closes the phantom omni device
+    /// \brief Disables the phantom omni device
     ///
-    void cleanUp();
+    void disable();
 
 private:
     ///
@@ -74,7 +76,7 @@ private:
     ///
     static HDCallbackCode HDCALLBACK hapticCallback(void* pData);
 
-    HHD      m_handle; ///< device handle
-    HD_state m_state;  ///< device reading state
+    HHD     m_handle; ///< device handle
+    HDstate m_state;  ///< device reading state
 };
 }
diff --git a/Source/Devices/imstkHDAPIDeviceServer.cpp b/Source/Devices/imstkHapticDeviceManager.cpp
similarity index 68%
rename from Source/Devices/imstkHDAPIDeviceServer.cpp
rename to Source/Devices/imstkHapticDeviceManager.cpp
index 302d076e64a89ee3a20f9a7ab78a7050831ac009..08a45a5ea512b1b0f6c8711976164c3e76513d36 100644
--- a/Source/Devices/imstkHDAPIDeviceServer.cpp
+++ b/Source/Devices/imstkHapticDeviceManager.cpp
@@ -19,8 +19,8 @@
 
 =========================================================================*/
 
-#include "imstkHDAPIDeviceServer.h"
-#include "imstkHDAPIDeviceClient.h"
+#include "imstkHapticDeviceManager.h"
+#include "imstkHapticDeviceClient.h"
 
 #include <HD/hd.h>
 
@@ -28,38 +28,37 @@
 
 namespace imstk
 {
-void
-HDAPIDeviceServer::addDeviceClient(std::shared_ptr<HDAPIDeviceClient> client)
+std::shared_ptr<HapticDeviceClient>
+HapticDeviceManager::makeDeviceClient(const std::string& name)
 {
-    m_deviceClients.push_back(client);
+    auto deviceClient = std::shared_ptr<HapticDeviceClient>(new HapticDeviceClient(name));
+    m_deviceClients.push_back(deviceClient);
+    return deviceClient;
 }
 
 void
-HDAPIDeviceServer::initModule()
+HapticDeviceManager::initialize()
 {
     for (const auto& client : m_deviceClients)
     {
-        client->init();
+        client->initialize();
     }
-    hdStartScheduler();
 }
 
 void
-HDAPIDeviceServer::runModule()
+HapticDeviceManager::startThread()
 {
-    for (const auto& client : m_deviceClients)
-    {
-        client->run();
-    }
+    initialize();
+    hdStartScheduler();
 }
 
 void
-HDAPIDeviceServer::cleanUpModule()
+HapticDeviceManager::stopThread()
 {
     hdStopScheduler();
     for (const auto& client : m_deviceClients)
     {
-        client->cleanUp();
+        client->disable();
     }
 }
 } // imstk
diff --git a/Source/Devices/imstkHDAPIDeviceServer.h b/Source/Devices/imstkHapticDeviceManager.h
similarity index 57%
rename from Source/Devices/imstkHDAPIDeviceServer.h
rename to Source/Devices/imstkHapticDeviceManager.h
index 0638b75dbd28e17ffb7b8cbad52f868bb09b4202..bc6dda73210389f03eebf80a335ab3059eca4a01 100644
--- a/Source/Devices/imstkHDAPIDeviceServer.h
+++ b/Source/Devices/imstkHapticDeviceManager.h
@@ -24,54 +24,53 @@
 #include <vector>
 
 // imstk
-#include "imstkModule.h"
+#include "imstkThreadObject.h"
 
 namespace imstk
 {
-class HDAPIDeviceClient;
+class HapticDeviceClient;
 ///
 /// \class HDAPIDeviceServer
-/// \brief Devices server using HDAPI
+/// \brief Devices manager using HDAPI
+/// \todo add the frame rate option for the servo loop
 ///
-class HDAPIDeviceServer : public Module
+class HapticDeviceManager : public ThreadObject
 {
+friend HapticDeviceClient;
+
 public:
 
-    ///
-    /// \brief Constructor
-    ///
-    HDAPIDeviceServer() : Module("HDAPIDeviceServer")
-    {}
+    HapticDeviceManager() : ThreadObject("HapticDeviceManager") {}
 
     ///
     /// \brief Destructor
+    /// Stop the scheduler
     ///
-    virtual ~HDAPIDeviceServer() {}
+    virtual ~HapticDeviceManager() override = default;
 
     ///
-    /// \brief Add device client
+    /// \brief Create a haptic device client and add it to the internal list
     ///
-    void addDeviceClient(std::shared_ptr<HDAPIDeviceClient> client);
-
-protected:
+    std::shared_ptr<HapticDeviceClient> makeDeviceClient(const std::string& name);
 
     ///
-    /// \brief Initialize the server module
+    /// \brief Initialize the client devices and start the scheduler
     ///
-    void initModule() override;
+    void initialize();
 
+protected:
     ///
-    /// \brief Run the server module
+    /// \brief
     ///
-    void runModule() override;
+    void startThread() override;
 
     ///
-    /// \brief Clean the server module
+    /// \brief
     ///
-    void cleanUpModule() override;
+    void stopThread() override;
 
 private:
 
-    std::vector<std::shared_ptr<HDAPIDeviceClient>> m_deviceClients; ///< list of OpenHaptics
+    std::vector<std::shared_ptr<HapticDeviceClient>> m_deviceClients; ///< list of all the device clients
 };
 } // imstk
diff --git a/Source/Devices/imstkKeyboardDeviceClient.cpp b/Source/Devices/imstkKeyboardDeviceClient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b3c4e6a796574185e490145b0b301c97a3df745f
--- /dev/null
+++ b/Source/Devices/imstkKeyboardDeviceClient.cpp
@@ -0,0 +1,66 @@
+/*=========================================================================
+
+   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 "imstkKeyboardDeviceClient.h"
+
+namespace imstk
+{
+std::shared_ptr<KeyboardDeviceClient>
+KeyboardDeviceClient::New()
+{
+    return std::shared_ptr<KeyboardDeviceClient>(new KeyboardDeviceClient());
+}
+
+void
+KeyboardDeviceClient::emitKeyDown(char key)
+{
+    const int prevKeyState = m_buttons[key];
+    m_buttons[key] = KEY_PRESS;
+    if (prevKeyState != KEY_PRESS)
+    {
+        this->postEvent(KeyPressEvent(key, KEY_PRESS));
+    }
+}
+
+void
+KeyboardDeviceClient::emitKeyUp(char key)
+{
+    const int prevKeyState = m_buttons[key];
+    m_buttons[key] = KEY_RELEASE;
+    if (prevKeyState != KEY_RELEASE)
+    {
+        this->postEvent(KeyPressEvent(key, KEY_RELEASE));
+    }
+}
+
+bool
+KeyboardDeviceClient::isKeyDown(const char key) const
+{
+    if (m_buttons.find(key) != m_buttons.end())
+    {
+        return (m_buttons.at(key) == KEY_PRESS);
+    }
+    else
+    {
+        return false;
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/Devices/imstkKeyboardDeviceClient.h b/Source/Devices/imstkKeyboardDeviceClient.h
new file mode 100644
index 0000000000000000000000000000000000000000..07a3ddaf74f5409807ec960d405270e523b6b85d
--- /dev/null
+++ b/Source/Devices/imstkKeyboardDeviceClient.h
@@ -0,0 +1,89 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkDeviceClient.h"
+
+#include <unordered_map>
+
+namespace imstk
+{
+using KeyStateType = int;
+#define KEY_RELEASE 0
+#define KEY_PRESS 1
+
+class KeyPressEvent : public Event
+{
+public:
+    KeyPressEvent(const char key, const KeyStateType keyPressType) : Event(EventType::KeyPress, 1), m_key(key), m_keyPressType(keyPressType) { }
+    virtual ~KeyPressEvent() override = default;
+
+public:
+    KeyStateType m_keyPressType;
+    const char   m_key = -1;
+};
+
+///
+/// \class KeyboardDeviceClient
+///
+/// \brief This class provides the keyboard state it also posts events
+///
+class KeyboardDeviceClient : public DeviceClient
+{
+protected:
+    ///
+    /// This object is only creatable through its New method
+    ///
+    KeyboardDeviceClient() : DeviceClient("KeyboardDevice", "") { }
+
+    ///
+    /// This object is only creatable through this method
+    ///
+    static std::shared_ptr<KeyboardDeviceClient> New();
+
+public:
+    virtual ~KeyboardDeviceClient() override = default;
+
+    // Only these classes may provide this object
+    friend class VTKInteractorStyle;
+    friend class ConsoleThread;
+
+public:
+    const std::unordered_map<int, KeyStateType>& getKeyState() const { return m_buttons; }
+
+protected:
+    ///
+    /// \brief Post a key press
+    ///
+    void emitKeyDown(char key);
+
+    ///
+    /// \brief Post a key release
+    ///
+    void emitKeyUp(char key);
+
+    ///
+    /// \brief Returns true if key is currently down
+    ///
+    bool isKeyDown(const char key) const;
+};
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/imstkInteractorStyle.cpp b/Source/Devices/imstkMouseDeviceClient.cpp
similarity index 83%
rename from Source/SimulationManager/imstkInteractorStyle.cpp
rename to Source/Devices/imstkMouseDeviceClient.cpp
index 1dd332a987a536693c1c381ede0ef7ff5e8be179..e44c94380debfb356afb25b587a0140a4fc21a56 100644
--- a/Source/SimulationManager/imstkInteractorStyle.cpp
+++ b/Source/Devices/imstkMouseDeviceClient.cpp
@@ -19,8 +19,13 @@
 
 =========================================================================*/
 
-#include "imstkInteractorStyle.h"
+#include "imstkMouseDeviceClient.h"
 
 namespace imstk
 {
+std::shared_ptr<MouseDeviceClient>
+MouseDeviceClient::New()
+{
+    return std::shared_ptr<MouseDeviceClient>(new MouseDeviceClient());
+}
 }
\ No newline at end of file
diff --git a/Source/Devices/imstkMouseDeviceClient.h b/Source/Devices/imstkMouseDeviceClient.h
new file mode 100644
index 0000000000000000000000000000000000000000..3d177c8446857459c7c8739cf01a551399d12625
--- /dev/null
+++ b/Source/Devices/imstkMouseDeviceClient.h
@@ -0,0 +1,159 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkDeviceClient.h"
+
+#include <unordered_map>
+
+namespace imstk
+{
+using MouseActionType = int;
+#define MOUSE_RELEASE 0
+#define MOUSE_PRESS 1
+#define MOUSE_SCROLL 2
+#define MOUSE_MOVE 3
+
+using MouseButtonType = int;
+#define LEFT_BUTTON 0
+#define RIGHT_BUTTON 1
+#define MIDDLE_BUTTON 2
+
+class MouseEvent : public Event
+{
+public:
+    MouseEvent(const MouseActionType mouseActionType, const MouseButtonType buttonId) :
+        Event(EventType::MouseEvent, 1),
+        m_mouseActionType(mouseActionType), m_buttonId(buttonId), m_scrollDx(0.0)
+    {
+    }
+
+    MouseEvent(const MouseActionType mouseActionType, const double scrollDx) :
+        Event(EventType::MouseEvent, 1),
+        m_mouseActionType(mouseActionType), m_scrollDx(scrollDx), m_buttonId(0)
+    {
+    }
+
+    MouseEvent(const MouseActionType mouseActionType) :
+        Event(EventType::MouseEvent, 1),
+        m_mouseActionType(mouseActionType), m_scrollDx(0.0), m_buttonId(0)
+    {
+    }
+
+    virtual ~MouseEvent() override = default;
+
+public:
+    MouseActionType m_mouseActionType;
+    double m_scrollDx;          ///> Mouse scroll
+    MouseButtonType m_buttonId; ///> Button id
+};
+
+///
+/// \class KeyboardDeviceClient
+///
+/// \brief This class provides the keyboard state it also posts button events
+///
+class MouseDeviceClient : public DeviceClient
+{
+protected:
+    ///
+    /// This object is only creatable through its New method
+    ///
+    MouseDeviceClient() : DeviceClient("MouseDevice", ""),
+        m_pos(Vec2d(0.0, 0.0)), m_prevPos(Vec2d(0.0, 0.0)) { }
+
+    ///
+    /// This object is only creatable through this method
+    ///
+    static std::shared_ptr<MouseDeviceClient> New();
+
+public:
+    virtual ~MouseDeviceClient() override = default;
+
+    // Only the viewer is allowed to provide these objects
+    friend class VTKInteractorStyle;
+
+public:
+    ///
+    /// \brief Get the current position of the mouse
+    ///
+    const Vec2d& getPos() const { return m_pos; }
+
+    ///
+    /// \brief Get the previous position of the mouse
+    ///
+    const Vec2d& getPrevPos() const { return m_prevPos; }
+
+    ///
+    /// \brief Query if the button is down
+    ///
+    const bool isButtonDown(const MouseButtonType buttonId) const
+    {
+        if (m_buttons.find(buttonId) != m_buttons.end())
+        {
+            return m_buttons.at(buttonId) == MOUSE_PRESS;
+        }
+        else
+        {
+            return MOUSE_RELEASE;
+        }
+    }
+
+protected:
+    ///
+    /// \brief Update the mouse position
+    ///
+    void updateMousePos(const Vec2d& pos)
+    {
+        m_prevPos = m_pos;
+        m_pos     = pos;
+        this->postEvent(MouseEvent(MOUSE_MOVE));
+    }
+
+    ///
+    /// \brief Post a click down event
+    ///
+    void emitButtonPress(const MouseButtonType buttonId)
+    {
+        m_buttons[buttonId] = MOUSE_PRESS;
+        this->postEvent(MouseEvent(MOUSE_PRESS, buttonId));
+    }
+
+    ///
+    /// \brief Post a click release event
+    ///
+    void emitButtonRelease(const MouseButtonType buttonId)
+    {
+        m_buttons[buttonId] = MOUSE_RELEASE;
+        this->postEvent(MouseEvent(MOUSE_RELEASE, buttonId));
+    }
+
+    ///
+    /// \brief Post a mouse scroll event
+    ///
+    void emitScroll(const double dx) { this->postEvent(MouseEvent(MOUSE_SCROLL, dx)); }
+
+protected:
+    Vec2d m_prevPos;
+    Vec2d m_pos;
+};
+}
\ No newline at end of file
diff --git a/Source/Devices/imstkOpenVRDeviceClient.cpp b/Source/Devices/imstkOpenVRDeviceClient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6605e0a3d642b1822ac9ac07662b0f69f361c9ea
--- /dev/null
+++ b/Source/Devices/imstkOpenVRDeviceClient.cpp
@@ -0,0 +1,75 @@
+/*=========================================================================
+
+   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 "imstkOpenVRDeviceClient.h"
+
+namespace imstk
+{
+std::shared_ptr<OpenVRDeviceClient>
+OpenVRDeviceClient::New(VRDeviceType deviceType)
+{
+    return std::shared_ptr<OpenVRDeviceClient>(new OpenVRDeviceClient(deviceType));
+}
+
+void
+OpenVRDeviceClient::emitButtonTouched(const int buttonId)
+{
+    const int prevButtonState = m_buttons[buttonId];
+    m_buttons[buttonId] = BUTTON_TOUCHED;
+    if (prevButtonState != BUTTON_TOUCHED)
+    {
+        this->postEvent(VRButtonEvent(buttonId, BUTTON_TOUCHED));
+    }
+}
+
+void
+OpenVRDeviceClient::emitButtonUntouched(const int buttonId)
+{
+    const int prevButtonState = m_buttons[buttonId];
+    m_buttons[buttonId] = BUTTON_UNTOUCHED;
+    if (prevButtonState != BUTTON_UNTOUCHED)
+    {
+        this->postEvent(VRButtonEvent(buttonId, BUTTON_UNTOUCHED));
+    }
+}
+
+void
+OpenVRDeviceClient::emitButtonPress(const int buttonId)
+{
+    const int prevButtonState = m_buttons[buttonId];
+    m_buttons[buttonId] = BUTTON_PRESSED;
+    if (prevButtonState != BUTTON_PRESSED)
+    {
+        this->postEvent(VRButtonEvent(buttonId, BUTTON_PRESSED));
+    }
+}
+
+void
+OpenVRDeviceClient::emitButtonRelease(const int buttonId)
+{
+    const int prevButtonState = m_buttons[buttonId];
+    m_buttons[buttonId] = BUTTON_RELEASED;
+    if (prevButtonState != BUTTON_RELEASED)
+    {
+        this->postEvent(VRButtonEvent(buttonId, BUTTON_RELEASED));
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/Devices/imstkOpenVRDeviceClient.h b/Source/Devices/imstkOpenVRDeviceClient.h
new file mode 100644
index 0000000000000000000000000000000000000000..42aa17b13bc98771e690de7af136edae8f423bc4
--- /dev/null
+++ b/Source/Devices/imstkOpenVRDeviceClient.h
@@ -0,0 +1,110 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkDeviceClient.h"
+
+#include <unordered_map>
+
+class vtkInteractorStyleVR;
+
+namespace imstk
+{
+using VRDeviceType = int;
+#define OPENVR_LEFT_CONTROLLER 0
+#define OPENVR_RIGHT_CONTROLLER 1
+#define OPENVR_HMD 2
+
+using VRButtonStateType = int;
+#define BUTTON_RELEASED 0
+#define BUTTON_TOUCHED 1
+#define BUTTON_UNTOUCHED 2
+#define BUTTON_PRESSED 3
+
+class VRButtonEvent : public Event
+{
+public:
+    VRButtonEvent(const int button, const VRButtonStateType keyPressType) : Event(EventType::VRButtonPress, 1),
+        m_buttonState(keyPressType),
+        m_button(button)
+    {
+    }
+
+    virtual ~VRButtonEvent() override = default;
+
+public:
+    VRButtonStateType m_buttonState;
+    const int m_button = -1;
+};
+
+///
+/// \class OpenVRDeviceClient
+///
+/// \brief This class provides quantities for the specified VR device
+/// The devices creation is tied to the viewer. It is only acquirable
+/// from a VR viewer and exists on the viewers thread.
+///
+class OpenVRDeviceClient : public DeviceClient
+{
+protected:
+    ///
+    /// This object is only creatable through its New method
+    ///
+    OpenVRDeviceClient(VRDeviceType deviceType) : DeviceClient("OpenVRDevice", ""),
+        m_deviceType(deviceType) { }
+
+    ///
+    /// This object is only creatable through this method
+    ///
+    static std::shared_ptr<OpenVRDeviceClient> New(VRDeviceType deviceType);
+
+public:
+    virtual ~OpenVRDeviceClient() override = default;
+
+    // Only the viewer is allowed to provide these objects
+    friend class ::vtkInteractorStyleVR;
+
+public:
+    VRDeviceType getDeviceType() const { return m_deviceType; }
+
+    ///
+    /// \brief Set the current position and orientation
+    ///
+    void setPose(const Vec3d& pos, const Quatd& orientation)
+    {
+        m_trackingEnabled = true;
+        m_position    = pos;
+        m_orientation = orientation;
+    }
+
+protected:
+    ///
+    /// \brief Emit various button events
+    ///
+    void emitButtonTouched(const int buttonId);
+    void emitButtonUntouched(const int buttonId);
+    void emitButtonPress(const int buttonId);
+    void emitButtonRelease(const int buttonId);
+
+private:
+    VRDeviceType m_deviceType;
+};
+}
\ No newline at end of file
diff --git a/Source/Devices/imstkVRPNArduinoDeviceClient.cpp b/Source/Devices/imstkVRPNArduinoDeviceClient.cpp
index f496cd9b6f6b44a871c04fe3dcb9be961915709c..d6f61980b7ec5091ed7350ddcbdee34ec686a5a3 100644
--- a/Source/Devices/imstkVRPNArduinoDeviceClient.cpp
+++ b/Source/Devices/imstkVRPNArduinoDeviceClient.cpp
@@ -21,12 +21,10 @@
 
 #include "imstkVRPNArduinoDeviceClient.h"
 
-#include "imstkLogger.h"
-
 namespace imstk
 {
 void
-VRPNArduinoDeviceClient::initModule()
+VRPNArduinoDeviceClient::initThread()
 {
     auto fullDeviceIp = this->getName().c_str();
 
@@ -36,13 +34,13 @@ VRPNArduinoDeviceClient::initModule()
 }
 
 void
-VRPNArduinoDeviceClient::runModule()
+VRPNArduinoDeviceClient::updateThread()
 {
     m_vrpnAnalog->mainloop();
 }
 
 void
-VRPNArduinoDeviceClient::cleanUpModule()
+VRPNArduinoDeviceClient::stopThread()
 {
     //Module cleanup is causing TCP errors - seems to work fine without it
     //m_vrpnAnalog->unregister_change_handler(this, analogChangeHandler);
diff --git a/Source/Devices/imstkVRPNArduinoDeviceClient.h b/Source/Devices/imstkVRPNArduinoDeviceClient.h
index 728d2e53ddf06b86da07fa8b7cf7fc02d0d21272..dd51806eac111cf6bf403e6a4b4ac8a18781a311 100644
--- a/Source/Devices/imstkVRPNArduinoDeviceClient.h
+++ b/Source/Devices/imstkVRPNArduinoDeviceClient.h
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "imstkDeviceClient.h"
-#include "imstkModule.h"
+#include "imstkLoopThreadObject.h"
 
 #include <vrpn_Configure.h>
 #include <vrpn_Analog.h>
@@ -33,7 +33,7 @@ namespace imstk
 /// \class VRPNDeviceClient
 /// \brief Subclass of DeviceClient using VRPN
 ///
-class VRPNArduinoDeviceClient : public DeviceClient, public Module
+class VRPNArduinoDeviceClient : public DeviceClient, public LoopThreadObject
 {
 public:
 
@@ -42,7 +42,7 @@ public:
     ///
     VRPNArduinoDeviceClient(const std::string& deviceName, const std::string& ip) :
         DeviceClient(deviceName, ip),
-        Module(deviceName + "@" + ip),
+        LoopThreadObject(deviceName + "@" + ip),
         m_ypr(Vec3d::Zero()),
         m_accel(Vec3d::Zero()),
         m_roll(0) {}
@@ -50,8 +50,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    virtual ~VRPNArduinoDeviceClient()
-    {}
+    virtual ~VRPNArduinoDeviceClient() override = default;
 
     ///
     /// \brief Get YPR
@@ -72,17 +71,17 @@ protected:
     ///
     /// \brief Initialize device client module
     ///
-    void initModule() override;
+    void initThread() override;
 
     ///
     /// \brief Run the device client
     ///
-    void runModule() override;
+    void updateThread() override;
 
     ///
-    /// \brief Clean the device client module
+    /// \brief Clean the device client
     ///
-    void cleanUpModule() override;
+    void stopThread() override;
 
 private:
 
diff --git a/Source/Devices/imstkVRPNDeviceClient.cpp b/Source/Devices/imstkVRPNDeviceClient.cpp
index 0d5ced48ec561206056e51c4ba2089d402894064..c4c04d3ffd4171aec598ea046044f077a1bfa43e 100644
--- a/Source/Devices/imstkVRPNDeviceClient.cpp
+++ b/Source/Devices/imstkVRPNDeviceClient.cpp
@@ -20,13 +20,12 @@
 =========================================================================*/
 
 #include "imstkVRPNDeviceClient.h"
-
 #include "imstkLogger.h"
 
 namespace imstk
 {
 void
-VRPNDeviceClient::initModule()
+VRPNDeviceClient::initThread()
 {
     auto fullDeviceIp = this->getName().c_str();
 
@@ -47,7 +46,7 @@ VRPNDeviceClient::initModule()
 }
 
 void
-VRPNDeviceClient::runModule()
+VRPNDeviceClient::updateThread()
 {
     if (this->getTrackingEnabled())
     {
@@ -70,7 +69,7 @@ VRPNDeviceClient::runModule()
 }
 
 void
-VRPNDeviceClient::cleanUpModule()
+VRPNDeviceClient::stopThread()
 {
     m_vrpnTracker->unregister_change_handler(this, trackerChangeHandler);
     m_vrpnTracker->unregister_change_handler(this, velocityChangeHandler);
diff --git a/Source/Devices/imstkVRPNDeviceClient.h b/Source/Devices/imstkVRPNDeviceClient.h
index ef641fecab24939268b4dbebe387a26259c768b1..b58958ec17e3a627b59066a127dc7d12ccc8b78d 100644
--- a/Source/Devices/imstkVRPNDeviceClient.h
+++ b/Source/Devices/imstkVRPNDeviceClient.h
@@ -22,14 +22,14 @@
 #pragma once
 
 #include "imstkDeviceClient.h"
-#include "imstkModule.h"
+#include "imstkLoopThreadObject.h"
 
-// vrpn includes
 #include <vrpn_Configure.h>
 #include <vrpn_Tracker.h>
 #include <vrpn_Analog.h>
 #include <vrpn_Button.h>
 #include <vrpn_ForceDevice.h>
+#include <unordered_map>
 
 namespace imstk
 {
@@ -37,7 +37,7 @@ namespace imstk
 /// \class VRPNDeviceClient
 /// \brief Subclass of DeviceClient using VRPN
 ///
-class VRPNDeviceClient : public DeviceClient, public Module
+class VRPNDeviceClient : public DeviceClient, public LoopThreadObject
 {
 public:
 
@@ -46,30 +46,29 @@ public:
     ///
     VRPNDeviceClient(const std::string& deviceName, const std::string& ip) :
         DeviceClient(deviceName, ip),
-        Module(deviceName + "@" + ip)
+        LoopThreadObject(deviceName + "@" + ip)
     {}
 
     ///
     /// \brief Destructor
     ///
-    virtual ~VRPNDeviceClient()
-    {}
+    virtual ~VRPNDeviceClient() override = default;
 
 protected:
     ///
     /// \brief Initialize device client module
     ///
-    void initModule() override;
+    void initThread() override;
 
     ///
     /// \brief Run the device client
     ///
-    void runModule() override;
+    void updateThread() override;
 
     ///
-    /// \brief Clean the device client module
+    /// \brief Clean the device client
     ///
-    void cleanUpModule() override;
+    void stopThread() override;
 
 private:
 
@@ -120,5 +119,8 @@ private:
     std::shared_ptr<vrpn_Analog_Remote>      m_vrpnAnalog;      //!< VRPN position/orientation interface
     std::shared_ptr<vrpn_Button_Remote>      m_vrpnButton;      //!< VRPN button interface
     std::shared_ptr<vrpn_ForceDevice_Remote> m_vrpnForceDevice; //!< VRPN force interface
+
+public:
+    std::unordered_map<int, bool> m_buttons;
 };
 }
diff --git a/Source/Devices/imstkVRPNDeviceServer.cpp b/Source/Devices/imstkVRPNDeviceServer.cpp
index 61f56718ee10706d84a1f8ad0e33fb882c8506e2..670ea57d0de754da66f203dad5f8eef0bd703604 100644
--- a/Source/Devices/imstkVRPNDeviceServer.cpp
+++ b/Source/Devices/imstkVRPNDeviceServer.cpp
@@ -20,17 +20,16 @@
 =========================================================================*/
 
 #include "imstkVRPNDeviceServer.h"
+#include "imstkLogger.h"
 
-#include "vrpn_3DConnexion.h"
-#include "vrpn_Tracker_NovintFalcon.h"
-#include "vrpn_Tracker_OSVRHackerDevKit.h"
-#include "vrpn_Streaming_Arduino.h"
+#include <vrpn_3DConnexion.h>
+#include <vrpn_Streaming_Arduino.h>
+#include <vrpn_Tracker_NovintFalcon.h>
+#include <vrpn_Tracker_OSVRHackerDevKit.h>
 #ifdef VRPN_USE_PHANTOM_SERVER
-  #include "vrpn_Phantom.h"
+  #include <vrpn_Phantom.h>
 #endif
 
-#include "imstkLogger.h"
-
 namespace imstk
 {
 void
@@ -57,7 +56,7 @@ VRPNDeviceServer::addSerialDevice(const std::string& deviceName, DeviceType devi
 }
 
 void
-VRPNDeviceServer::initModule()
+VRPNDeviceServer::initThread()
 {
     std::string ip = m_machine + ":" + std::to_string(m_port);
     m_serverConnection = vrpn_create_server_connection(ip.c_str());
@@ -120,14 +119,14 @@ VRPNDeviceServer::initModule()
 }
 
 void
-VRPNDeviceServer::runModule()
+VRPNDeviceServer::updateThread()
 {
     m_serverConnection->mainloop();
     m_deviceConnections->mainloop();
 }
 
 void
-VRPNDeviceServer::cleanUpModule()
+VRPNDeviceServer::stopThread()
 {
     m_deviceConnections->clear();
     delete(m_deviceConnections);
diff --git a/Source/Devices/imstkVRPNDeviceServer.h b/Source/Devices/imstkVRPNDeviceServer.h
index ea36587b654fef45adb9f0f7af9aebd8e6466aa2..80d4689fc3f6163575dc95dc34349fe065fb3ab7 100644
--- a/Source/Devices/imstkVRPNDeviceServer.h
+++ b/Source/Devices/imstkVRPNDeviceServer.h
@@ -21,17 +21,14 @@
 
 #pragma once
 
-#include <vector>
+#include "imstkLoopThreadObject.h"
+
 #include <map>
 #include <string>
 
-// vrpn
 #include <vrpn_Connection.h>
 #include <vrpn_MainloopContainer.h>
 
-// imstk
-#include "imstkModule.h"
-
 namespace imstk
 {
 ///
@@ -51,7 +48,7 @@ enum class DeviceType
 /// \class VRPNDeviceServer
 /// \brief Devices server using VRPN
 ///
-class VRPNDeviceServer : public Module
+class VRPNDeviceServer : public LoopThreadObject
 {
 public:
 
@@ -61,13 +58,13 @@ public:
     VRPNDeviceServer(const std::string& machine = "localhost", int port = vrpn_DEFAULT_LISTEN_PORT_NO) :
         m_machine(machine),
         m_port(port),
-        Module(machine + ":" + std::to_string(port))
+        LoopThreadObject(machine + ":" + std::to_string(port))
     {}
 
     ///
     /// \brief Destructor
     ///
-    virtual ~VRPNDeviceServer() {}
+    virtual ~VRPNDeviceServer() override = default;
 
     ///
     /// \brief Add device
@@ -84,17 +81,17 @@ protected:
     ///
     /// \brief Initialize the server module
     ///
-    void initModule() override;
+    void initThread() override;
 
     ///
     /// \brief Run the server module
     ///
-    void runModule() override;
+    void updateThread() override;
 
     ///
     /// \brief Clean the server module
     ///
-    void cleanUpModule() override;
+    void stopThread() override;
 
 private:
 
diff --git a/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.cpp b/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.cpp
index f0e6c5046cf91fc045bb9d3844e9f35194f20ec4..ebf8ba01778d38c67dbb407bf451b844c3d77fbf 100644
--- a/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.cpp
+++ b/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.cpp
@@ -23,8 +23,7 @@
 
 #pragma warning( push )
 #pragma warning( disable : 4458 )
-//vega
-#include "corotationalLinearFEM.h"
+#include <corotationalLinearFEM.h>
 #pragma warning( pop )
 
 namespace imstk
diff --git a/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.h
index bd9337ba0e05a228bfef1e051b9c5148a7226f86..075e289d8cfdc990574e80c668f68fbf36243252 100644
--- a/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.h
+++ b/Source/DynamicalModels/InternalForceModel/imstkCorotationalFEMForceModel.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-//imstk
 #include "imstkInternalForceModel.h"
 
 namespace vega
diff --git a/Source/DynamicalModels/InternalForceModel/imstkInternalForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkInternalForceModel.h
index 09fc5adf65107e09dbf3493005538ac9c90f11da..fd438a6d7a8346e20859aa5a1d43da60fa3e3fdd 100644
--- a/Source/DynamicalModels/InternalForceModel/imstkInternalForceModel.h
+++ b/Source/DynamicalModels/InternalForceModel/imstkInternalForceModel.h
@@ -24,12 +24,15 @@
 #include "imstkMath.h"
 #include "imstkInternalForceModelTypes.h"
 
+#ifdef WIN32
 #pragma warning( push )
 #pragma warning( disable : 4458 )
 #pragma warning( disable : 4100 )
-//vega
-#include "forceModel.h"
+#endif
+#include <forceModel.h>
+#ifdef WIN32
 #pragma warning( pop )
+#endif
 
 namespace imstk
 {
@@ -45,7 +48,7 @@ public:
     ///
     /// \brief Constructor
     ///
-    InternalForceModel() {};
+    InternalForceModel() = default;
 
     ///
     /// \brief Destructor
diff --git a/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.cpp b/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cd89622445176b7cb502441abba5505157b67b65
--- /dev/null
+++ b/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.cpp
@@ -0,0 +1,74 @@
+/*= ========================================================================
+
+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 permissionsand
+limitations under the License.
+
+======================================================================== = */
+
+#include "imstkIsotropicHyperelasticFEMForceModel.h"
+#include "imstkLogger.h"
+
+#include <MooneyRivlinIsotropicMaterial.h>
+#include <neoHookeanIsotropicMaterial.h>
+#include <StVKIsotropicMaterial.h>
+
+namespace imstk
+{
+IsotropicHyperelasticFEForceModel::IsotropicHyperelasticFEForceModel(const HyperElasticMaterialType materialType,
+                                                                     std::shared_ptr<vega::VolumetricMesh> mesh,
+                                                                     const double inversionThreshold, const bool withGravity, const double gravity) : InternalForceModel()
+{
+    auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh);
+
+    const int    enableCompressionResistance = 1;
+    const double compressionResistance       = 500;
+    switch (materialType)
+    {
+    case HyperElasticMaterialType::StVK:
+        m_isotropicMaterial = std::make_shared<vega::StVKIsotropicMaterial>(
+            tetMesh.get(),
+            enableCompressionResistance,
+            compressionResistance);
+        break;
+
+    case HyperElasticMaterialType::NeoHookean:
+        m_isotropicMaterial = std::make_shared<vega::NeoHookeanIsotropicMaterial>(
+            tetMesh.get(),
+            enableCompressionResistance,
+            compressionResistance);
+        break;
+
+    case HyperElasticMaterialType::MooneyRivlin:
+        m_isotropicMaterial = std::make_shared<vega::MooneyRivlinIsotropicMaterial>(
+            tetMesh.get(),
+            enableCompressionResistance,
+            compressionResistance);
+        break;
+
+    default:
+        LOG(WARNING) << "Error: Invalid hyperelastic material type.";
+        break;
+    }
+
+    m_isotropicHyperelasticFEM = std::make_shared<vega::IsotropicHyperelasticFEM>(
+        tetMesh.get(),
+        m_isotropicMaterial.get(),
+        inversionThreshold,
+        withGravity,
+        gravity);
+}
+}
\ No newline at end of file
diff --git a/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.h
index 296976ae988746416e2da9bc8aa13b18b765ddf4..1c5dad668c433f2784e4da8c50c36b7c29328e5e 100644
--- a/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.h
+++ b/Source/DynamicalModels/InternalForceModel/imstkIsotropicHyperelasticFEMForceModel.h
@@ -21,20 +21,16 @@
 
 #pragma once
 
-#include <g3log/g3log.hpp>
-
-//imstk
 #include "imstkInternalForceModel.h"
 
-//vega
+#ifdef WIN32
 #pragma warning( push )
 #pragma warning( disable : 4458 )
-#include "isotropicHyperelasticFEM.h"
+#endif
+#include <isotropicHyperelasticFEM.h>
+#ifdef WIN32
 #pragma warning( pop )
-
-#include "StVKIsotropicMaterial.h"
-#include "neoHookeanIsotropicMaterial.h"
-#include "MooneyRivlinIsotropicMaterial.h"
+#endif
 
 namespace imstk
 {
@@ -53,46 +49,7 @@ public:
                                       std::shared_ptr<vega::VolumetricMesh> mesh,
                                       const double                          inversionThreshold,
                                       const bool                            withGravity = true,
-                                      const double                          gravity     = 10.0) : InternalForceModel()
-    {
-        auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh);
-
-        const int    enableCompressionResistance = 1;
-        const double compressionResistance       = 500;
-        switch (materialType)
-        {
-        case HyperElasticMaterialType::StVK:
-            m_isotropicMaterial = std::make_shared<vega::StVKIsotropicMaterial>(
-                    tetMesh.get(),
-                    enableCompressionResistance,
-                    compressionResistance);
-            break;
-
-        case HyperElasticMaterialType::NeoHookean:
-            m_isotropicMaterial = std::make_shared<vega::NeoHookeanIsotropicMaterial>(
-                    tetMesh.get(),
-                    enableCompressionResistance,
-                    compressionResistance);
-            break;
-
-        case HyperElasticMaterialType::MooneyRivlin:
-            m_isotropicMaterial = std::make_shared<vega::MooneyRivlinIsotropicMaterial>(
-                    tetMesh.get(),
-                    enableCompressionResistance,
-                    compressionResistance);
-            break;
-
-        default:
-            LOG(WARNING) << "Error: Invalid hyperelastic material type.";
-        }
-
-        m_isotropicHyperelasticFEM = std::make_shared<vega::IsotropicHyperelasticFEM>(
-            tetMesh.get(),
-            m_isotropicMaterial.get(),
-            inversionThreshold,
-            withGravity,
-            gravity);
-    }
+                                      const double                          gravity     = 10.0);
 
     ///
     /// \brief Constructor type that is not allowed
@@ -102,7 +59,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    virtual ~IsotropicHyperelasticFEForceModel() = default;
+    virtual ~IsotropicHyperelasticFEForceModel() override = default;
 
     ///
     /// \brief Get the internal force
diff --git a/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.cpp b/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b0e435f1f4aea1e679262e3e41e413bdbbd4db87
--- /dev/null
+++ b/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.cpp
@@ -0,0 +1,58 @@
+/*=========================================================================
+
+   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 "imstkLinearFEMForceModel.h"
+
+#include <StVKElementABCDLoader.h>
+#include <StVKStiffnessMatrix.h>
+#include <tetMesh.h>
+
+namespace imstk
+{
+LinearFEMForceModel::LinearFEMForceModel(std::shared_ptr<vega::VolumetricMesh> mesh,
+                                         const bool withGravity, const double gravity) : InternalForceModel()
+{
+    auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh);
+
+    vega::StVKElementABCD* precomputedIntegrals = vega::StVKElementABCDLoader::load(tetMesh.get());
+    m_stVKInternalForces = std::make_shared<vega::StVKInternalForces>(tetMesh.get(), precomputedIntegrals, withGravity, gravity);
+
+    auto stVKStiffnessMatrix = std::make_shared<vega::StVKStiffnessMatrix>(m_stVKInternalForces.get());
+
+    stVKStiffnessMatrix->GetStiffnessMatrixTopology(&m_stiffnessMatrixRawPtr);
+    std::shared_ptr<vega::SparseMatrix> m_stiffnessMatrix2(m_stiffnessMatrixRawPtr);
+    m_stiffnessMatrix = m_stiffnessMatrix2;
+
+    auto K = m_stiffnessMatrix.get();
+    stVKStiffnessMatrix->GetStiffnessMatrixTopology(&K);
+    double* zero = (double*)calloc(m_stiffnessMatrix->GetNumRows(), sizeof(double));
+    stVKStiffnessMatrix->ComputeStiffnessMatrix(zero, m_stiffnessMatrix.get());
+    free(zero);
+};
+
+LinearFEMForceModel::~LinearFEMForceModel()
+{
+    if (m_stiffnessMatrixRawPtr)
+    {
+        delete m_stiffnessMatrixRawPtr;
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.h
index 28ebf8c784f188a446bf5cea009800835c4a71ed..14c961ef644f383e0c9aaee404904059872cb4b9 100644
--- a/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.h
+++ b/Source/DynamicalModels/InternalForceModel/imstkLinearFEMForceModel.h
@@ -21,14 +21,13 @@
 
 #pragma once
 
-//imstk
 #include "imstkInternalForceModel.h"
-#include "imstkLogger.h"
 
-//vega
-#include "StVKInternalForces.h"
-#include "StVKStiffnessMatrix.h"
-#include "StVKElementABCDLoader.h"
+namespace vega
+{
+class StVKInternalForces;
+class VolumetricMesh;
+}
 
 namespace imstk
 {
@@ -44,37 +43,12 @@ public:
     /// \brief Constructor
     ///
     LinearFEMForceModel(std::shared_ptr<vega::VolumetricMesh> mesh,
-                        const bool                            withGravity = true,
-                        const double                          gravity     = -9.81) : InternalForceModel()
-    {
-        auto tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh);
-
-        vega::StVKElementABCD* precomputedIntegrals = vega::StVKElementABCDLoader::load(tetMesh.get());
-        m_stVKInternalForces = std::make_shared<vega::StVKInternalForces>(tetMesh.get(), precomputedIntegrals, withGravity, gravity);
-
-        auto stVKStiffnessMatrix = std::make_shared<vega::StVKStiffnessMatrix>(m_stVKInternalForces.get());
-
-        stVKStiffnessMatrix->GetStiffnessMatrixTopology(&m_stiffnessMatrixRawPtr);
-        std::shared_ptr<vega::SparseMatrix> m_stiffnessMatrix2(m_stiffnessMatrixRawPtr);
-        m_stiffnessMatrix = m_stiffnessMatrix2;
-
-        auto K = m_stiffnessMatrix.get();
-        stVKStiffnessMatrix->GetStiffnessMatrixTopology(&K);
-        double* zero = (double*)calloc(m_stiffnessMatrix->GetNumRows(), sizeof(double));
-        stVKStiffnessMatrix->ComputeStiffnessMatrix(zero, m_stiffnessMatrix.get());
-        free(zero);
-    };
+                        const bool withGravity = true, const double gravity = -9.81);
 
     ///
     /// \brief Destructor
     ///
-    virtual ~LinearFEMForceModel()
-    {
-        if (m_stiffnessMatrixRawPtr)
-        {
-            delete m_stiffnessMatrixRawPtr;
-        }
-    };
+    virtual ~LinearFEMForceModel() override;
 
     ///
     /// \brief Compute the internal force
@@ -85,8 +59,10 @@ public:
         m_stiffnessMatrix->MultiplyVector(data, internalForce.data());
     }
 
+#ifdef WIN32
 #pragma warning( push )
 #pragma warning( disable : 4100 )
+#endif
     ///
     /// \brief Get the tangent stiffness matrix
     /// \todo Clear warning C4100
@@ -96,7 +72,9 @@ public:
         InternalForceModel::updateValuesFromMatrix(m_stiffnessMatrix, tangentStiffnessMatrix.valuePtr());
     }
 
+#ifdef WIN32
 #pragma warning( pop )
+#endif
 
     ///
     /// \brief Get the tangent stiffness matrix topology
diff --git a/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.cpp b/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2e67ace5a7c201c3bb4d6d24d4aff050d452f57d
--- /dev/null
+++ b/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.cpp
@@ -0,0 +1,37 @@
+/*=========================================================================
+
+   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 "imstkStVKForceModel.h"
+
+#include <StVKElementABCDLoader.h>
+#include <tetMesh.h>
+
+namespace imstk
+{
+StVKForceModel::StVKForceModel(std::shared_ptr<vega::VolumetricMesh> mesh,
+                               const bool withGravity, const double gravity) : InternalForceModel()
+{
+    auto                   tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh);
+    vega::StVKElementABCD* precomputedIntegrals = vega::StVKElementABCDLoader::load(tetMesh.get());
+    m_stVKInternalForces      = std::make_shared<vega::StVKInternalForces>(tetMesh.get(), precomputedIntegrals, withGravity, gravity);
+    m_vegaStVKStiffnessMatrix = std::make_shared<vega::StVKStiffnessMatrix>(m_stVKInternalForces.get());
+}
+}
\ No newline at end of file
diff --git a/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.h b/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.h
index dbd5837d25874ecdab899c9cd8ac2b4c409b0b92..1f17a0f3ff09f1de5be09660943dda3b733e5db1 100644
--- a/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.h
+++ b/Source/DynamicalModels/InternalForceModel/imstkStVKForceModel.h
@@ -21,19 +21,15 @@
 
 #pragma once
 
-//imstk
 #include "imstkInternalForceModel.h"
-#include "imstkLogger.h"
 
-//vega
-#pragma warning( push )
-#pragma warning( disable : 4458 )
-#include "StVKInternalForces.h"
-#pragma warning( pop )
+#include <StVKStiffnessMatrix.h>
 
-#include "StVKStiffnessMatrix.h"
-#include "StVKElementABCDLoader.h"
-#include "tetMesh.h"
+namespace vega
+{
+class StVKInternalForces;
+class VolumetricMesh;
+}
 
 namespace imstk
 {
@@ -44,19 +40,12 @@ public:
     /// \brief Constructor
     ///
     StVKForceModel(std::shared_ptr<vega::VolumetricMesh> mesh,
-                   const bool                            withGravity = true,
-                   const double                          gravity     = 10.0) : InternalForceModel()
-    {
-        auto                   tetMesh = std::dynamic_pointer_cast<vega::TetMesh>(mesh);
-        vega::StVKElementABCD* precomputedIntegrals = vega::StVKElementABCDLoader::load(tetMesh.get());
-        m_stVKInternalForces      = std::make_shared<vega::StVKInternalForces>(tetMesh.get(), precomputedIntegrals, withGravity, gravity);
-        m_vegaStVKStiffnessMatrix = std::make_shared<vega::StVKStiffnessMatrix>(m_stVKInternalForces.get());
-    }
+                   const bool withGravity = true, const double gravity = 10.0);
 
     ///
     /// \brief Destructor
     ///
-    virtual ~StVKForceModel() = default;
+    virtual ~StVKForceModel() override = default;
 
     ///
     /// \brief Get the internal force
@@ -103,7 +92,6 @@ public:
     }
 
 protected:
-
     std::shared_ptr<vega::StVKInternalForces>  m_stVKInternalForces;
     std::shared_ptr<vega::SparseMatrix>        m_vegaTangentStiffnessMatrix;
     std::shared_ptr<vega::StVKStiffnessMatrix> m_vegaStVKStiffnessMatrix;
diff --git a/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h b/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h
index e4573a692aa4401690ac39d7448799941c3657cf..945fdf0a0162c75a6882cedaa2ed291757f6ba2a 100644
--- a/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h
@@ -21,12 +21,9 @@
 
 #pragma once
 
-#include "imstkVectorizedState.h"
 #include "imstkGeometry.h"
 
 #include <set>
-#include <string>
-#include <unordered_map>
 
 namespace imstk
 {
@@ -56,7 +53,7 @@ enum class TimeSteppingType
 };
 
 ///
-/// \class DynamicalModel
+/// \class AbstractDynamicalModel
 ///
 /// \brief Abstract class for mathematical model of the physics governing the dynamic object
 ///
@@ -102,6 +99,7 @@ public:
 
     ///
     /// \brief Update states
+    /// \todo: Fem specific, needs to be moved
     ///
     virtual void updateBodyStates(const Vectord& q, const StateUpdateType updateType = StateUpdateType::Displacement) = 0;
 
diff --git a/Source/DynamicalModels/ObjectModels/imstkDynamicalModel.h b/Source/DynamicalModels/ObjectModels/imstkDynamicalModel.h
index b1b79d3556403de0ca74a1e604586454ebea3100..36a7b9d9445fb42de4ccd75f8d432440f28f5a56 100644
--- a/Source/DynamicalModels/ObjectModels/imstkDynamicalModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkDynamicalModel.h
@@ -47,17 +47,17 @@ public:
     ///
     /// \brief Return the initial state of the problem
     ///
-    std::shared_ptr<StateType> getInitialState() { return m_initialState; }
+    std::shared_ptr<StateType> getInitialState() const { return m_initialState; }
 
     ///
     /// \brief Return the current state of the problem
     ///
-    std::shared_ptr<StateType> getCurrentState() { return m_currentState; }
+    std::shared_ptr<StateType> getCurrentState() const { return m_currentState; }
 
     ///
     /// \brief Return the previous state of the problem
     ///
-    std::shared_ptr<StateType> getPreviousState() { return m_previousState; }
+    std::shared_ptr<StateType> getPreviousState() const { return m_previousState; }
 
     ///
     /// \brief Reset the current state to the initial state
diff --git a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp
index 00c523e8bac8825ffcfe97c79632a2cdbe3bb178..86394d79785932610b28358cc486a9e31e2388a3 100644
--- a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp
@@ -19,32 +19,30 @@
 
 =========================================================================*/
 
-// std lib
-#include <fstream>
-
-//imstk
 #include "imstkFEMDeformableBodyModel.h"
 #include "imstkConjugateGradient.h"
 #include "imstkCorotationalFEMForceModel.h"
-#include "imstkInternalForceModel.h"
 #include "imstkIsotropicHyperelasticFEMForceModel.h"
 #include "imstkLinearFEMForceModel.h"
-#include "imstkMath.h"
-#include "imstkSolverBase.h"
+#include "imstkLogger.h"
+#include "imstkNewtonSolver.h"
 #include "imstkStVKForceModel.h"
 #include "imstkTaskGraph.h"
 #include "imstkTimeIntegrator.h"
 #include "imstkVegaMeshIO.h"
 #include "imstkVolumetricMesh.h"
+#include "imstkTypes.h"
 
-// vega
-#include "generateMassMatrix.h"
-#include "generateMeshGraph.h"
-
+#include <generateMassMatrix.h>
+#include <generateMeshGraph.h>
+#ifdef WIN32
 #pragma warning( push )
 #pragma warning( disable : 4458 )
-#include "configFile.h"
+#endif
+#include <configFile.h>
+#ifdef WIN32
 #pragma warning( pop )
+#endif
 
 namespace imstk
 {
@@ -521,7 +519,7 @@ FEMDeformableBodyModel::computeSemiImplicitSystemRHS(kinematicState&       state
 }
 
 void
-FEMDeformableBodyModel::computeImplicitSystemLHS(const kinematicState& stateAtT,
+FEMDeformableBodyModel::computeImplicitSystemLHS(const kinematicState& imstkNotUsed(stateAtT),
                                                  kinematicState&       newState,
                                                  const StateUpdateType updateType)
 {
@@ -530,9 +528,6 @@ FEMDeformableBodyModel::computeImplicitSystemLHS(const kinematicState& stateAtT,
     switch (updateType)
     {
     case StateUpdateType::DeltaVelocity:
-
-        stateAtT;// supress warning (state is not used in this update type hence can be ignored)
-
         this->updateMassMatrix();
         m_internalForceModel->getTangentStiffnessMatrix(newState.getQ(), m_K);
         this->updateDampingMatrix();
@@ -686,8 +681,10 @@ FEMDeformableBodyModel::updateBodyIntermediateStates(
 NonLinearSystem<SparseMatrixd>::VectorFunctionType
 FEMDeformableBodyModel::getFunction()
 {
+#ifdef WIN32
 #pragma warning( push )
 #pragma warning( disable : 4100 )
+#endif
 
     // Function to evaluate the nonlinear objective function given the current state
     return [&, this](const Vectord& q, const bool semiImplicit)->const Vectord&
@@ -701,15 +698,18 @@ FEMDeformableBodyModel::getFunction()
                }
                return m_Feff;
            };
-
+#ifdef WIN32
 #pragma warning( pop )
+#endif
 }
 
 NonLinearSystem<SparseMatrixd>::MatrixFunctionType
 FEMDeformableBodyModel::getFunctionGradient()
 {
+#ifdef WIN32
 #pragma warning( push )
 #pragma warning( disable : 4100 )
+#endif
     // Gradient of the nonlinear objective function given the current state
     return [&, this](const Vectord& q)->const SparseMatrixd&
            {
@@ -721,8 +721,9 @@ FEMDeformableBodyModel::getFunctionGradient()
                }
                return m_Keff;
            };
-
+#ifdef WIN32
 #pragma warning( pop )
+#endif
 }
 
 NonLinearSystem<SparseMatrixd>::UpdateFunctionType
diff --git a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h
index 97d0f58d9ddd234aed821f806921b2519edcae0b..08ccffb0b9f30fb96ba2e32dfa76900fe3885b7f 100644
--- a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h
@@ -21,14 +21,12 @@
 
 #pragma once
 
-// imstk
 #include "imstkDynamicalModel.h"
 #include "imstkInternalForceModelTypes.h"
+#include "imstkVectorizedState.h"
 #include "imstkNonLinearSystem.h"
-#include "imstkNewtonSolver.h"
 
-// vega
-#include "sparseMatrix.h"
+#include <sparseMatrix.h>
 
 namespace vega
 {
@@ -84,7 +82,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~FEMDeformableBodyModel();
+    ~FEMDeformableBodyModel() override;
 
 public:
     ///
diff --git a/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ce797b1b384de37bec7b2ed2994d8ae085e7f33b
--- /dev/null
+++ b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp
@@ -0,0 +1,275 @@
+/*=========================================================================
+
+   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 "imstkLevelSetModel.h"
+#include "imstkTaskGraph.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkLogger.h"
+#include "imstkSignedDistanceField.h"
+#include "imstkParallelFor.h"
+#include "imstkImplicitGeometry.h"
+#include "imstkDataArray.h"
+#include "imstkImageData.h"
+
+namespace imstk
+{
+LevelSetModel::LevelSetModel()
+{
+    // If given an image data
+    m_validGeometryTypes = {
+        Geometry::Type::ImageData,
+        Geometry::Type::SignedDistanceField
+    };
+
+    // By default the level set defines a function for evolving the distances, this can be removed in subclasses
+    m_evolveQuantitiesNodes.push_back(std::make_shared<TaskNode>(std::bind(&LevelSetModel::evolveDistanceField, this), "Evolve Distances"));
+    m_taskGraph->addNode(m_evolveQuantitiesNodes.back());
+    /// are all quantities evolved the same but with different force functions?
+}
+
+bool
+LevelSetModel::initialize()
+{
+    if (m_geometry == nullptr)
+    {
+        LOG(WARNING) << "Levelset missing geometry";
+        return false;
+    }
+
+    if (m_geometry->getType() == Geometry::Type::ImageData)
+    {
+        if (std::dynamic_pointer_cast<ImageData>(m_geometry)->getScalarType() != IMSTK_DOUBLE)
+        {
+            LOG(WARNING) << "Levelset only works with double image types";
+            return false;
+        }
+
+        m_mesh = std::make_shared<SignedDistanceField>(std::dynamic_pointer_cast<ImageData>(m_geometry));
+    }
+    else
+    {
+        m_mesh = std::dynamic_pointer_cast<ImplicitGeometry>(m_geometry);
+    }
+    forwardGrad.setFunction(m_mesh);
+    backwardGrad.setFunction(m_mesh);
+
+    // If dense update, we need a gradient image, which will store forward and backward gradient magnitudes
+    if (m_mesh->getType() == Geometry::Type::SignedDistanceField && !m_config->m_sparseUpdate)
+    {
+        auto sdfImage = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage();
+        gradientMagnitudes = std::make_shared<ImageData>();
+        gradientMagnitudes->allocate(IMSTK_DOUBLE, 2, sdfImage->getDimensions(), sdfImage->getSpacing(), sdfImage->getOrigin());
+    }
+
+    forwardGrad.setDx(Vec3i(1, 1, 1), std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage()->getSpacing());
+    backwardGrad.setDx(Vec3i(1, 1, 1), std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage()->getSpacing());
+    /*forwardGrad.setDx(std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage()->getSpacing());
+    backwardGrad.setDx(std::dynamic_pointer_cast<SignedDistanceField>(m_mesh)->getImage()->getSpacing());*/
+
+    return true;
+}
+
+void
+LevelSetModel::configure(std::shared_ptr<LevelSetModelConfig> config)
+{
+    LOG_IF(FATAL, (!this->getModelGeometry())) << "PbdModel::configure - Set PBD Model geometry before configuration!";
+
+    m_config = config;
+}
+
+void
+LevelSetModel::evolveDistanceField()
+{
+    auto         sdf       = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh);
+    auto         imageData = std::dynamic_pointer_cast<ImageData>(sdf->getImage());
+    double*      imgPtr    = static_cast<double*>(imageData->getVoidPointer());
+    const Vec3i& dim       = imageData->getDimensions();
+    //const Vec3d& spacing   = imageData->getSpacing();
+    //const Vec3d& origin    = imageData->getOrigin();
+    const double dt = m_config->m_dt;
+
+    if (m_config->m_sparseUpdate)
+    {
+        // Sparse update
+        if (nodesToUpdate.size() == 0)
+        {
+            return;
+        }
+
+        std::vector<std::tuple<size_t, Vec3i, double, Vec2d>> nodeUpdates;
+        nodeUpdates.reserve(nodesToUpdate.size());
+
+        // Compute gradients
+        for (std::unordered_map<size_t, std::tuple<Vec3i, double>>::iterator iter = nodesToUpdate.begin(); iter != nodesToUpdate.end(); iter++)
+        {
+            const size_t index  = iter->first;
+            const Vec3i& coords = std::get<0>(iter->second);
+            const double f      = std::get<1>(iter->second);
+
+            // Gradients
+            const Vec3d gradPos = forwardGrad(Vec3d(coords[0], coords[1], coords[2]));
+            const Vec3d gradNeg = backwardGrad(Vec3d(coords[0], coords[1], coords[2]));
+
+            const double posMag =
+                std::pow(std::max(gradNeg[0], 0.0), 2) + std::pow(std::min(gradPos[0], 0.0), 2) +
+                std::pow(std::max(gradNeg[1], 0.0), 2) + std::pow(std::min(gradPos[1], 0.0), 2) +
+                std::pow(std::max(gradNeg[2], 0.0), 2) + std::pow(std::min(gradPos[2], 0.0), 2);
+
+            const double negMag =
+                std::pow(std::min(gradNeg[0], 0.0), 2) + std::pow(std::max(gradPos[0], 0.0), 2) +
+                std::pow(std::min(gradNeg[1], 0.0), 2) + std::pow(std::max(gradPos[1], 0.0), 2) +
+                std::pow(std::min(gradNeg[2], 0.0), 2) + std::pow(std::max(gradPos[2], 0.0), 2);
+
+            nodeUpdates.push_back(std::tuple<size_t, Vec3i, double, Vec2d>(index, coords, f, Vec2d(negMag, posMag)));
+        }
+
+        // Update levelset
+        const double constantVel = m_config->m_constantVelocity;
+        for (size_t i = 0; i < nodeUpdates.size(); i++)
+        {
+            const size_t index = std::get<0>(nodeUpdates[i]);
+            //const Vec3i& coords = std::get<1>(nodeUpdates[i]);
+            const double vel = std::get<2>(nodeUpdates[i]) + constantVel;
+            const Vec2d& g   = std::get<3>(nodeUpdates[i]);
+
+            // If speed function positive use forward difference (posMag)
+            if (vel > 0.0)
+            {
+                imgPtr[index] += dt * vel * std::sqrt(g[0]);
+            }
+            // If speed function negative use backward difference (negMag)
+            else if (vel < 0.0)
+            {
+                imgPtr[index] += dt * vel * std::sqrt(g[1]);
+            }
+        }
+        if (nodesToUpdate.size() > 0)
+        {
+            imageData->modified();
+            nodesToUpdate.clear();
+        }
+    }
+    else
+    {
+        // Dense update
+        double* gradientMagPtr = static_cast<double*>(gradientMagnitudes->getScalars()->getVoidPointer());
+
+        // Compute gradients
+        ParallelUtils::parallelFor(dim[2],
+            [&](const int& z)
+            {
+                int i = z * dim[0] * dim[1];
+                for (int y = 0; y < dim[1]; y++)
+                {
+                    for (int x = 0; x < dim[0]; x++, i++)
+                    {
+                        // Center of voxel
+                        //const Vec3d pos = Vec3d(x, y, z).cwiseProduct(spacing) + shift;
+
+                        // Gradients
+                        const Vec3d gradPos = forwardGrad(Vec3d(x, y, z));
+                        const Vec3d gradNeg = backwardGrad(Vec3d(x, y, z));
+
+                        // neg
+                        gradientMagPtr[i * 2] =
+                            std::pow(std::min(gradNeg[0], 0.0), 2) + std::pow(std::max(gradPos[0], 0.0), 2) +
+                            std::pow(std::min(gradNeg[1], 0.0), 2) + std::pow(std::max(gradPos[1], 0.0), 2) +
+                            std::pow(std::min(gradNeg[2], 0.0), 2) + std::pow(std::max(gradPos[2], 0.0), 2);
+
+                        // pos
+                        gradientMagPtr[i * 2 + 1] =
+                            std::pow(std::max(gradNeg[0], 0.0), 2) + std::pow(std::min(gradPos[0], 0.0), 2) +
+                            std::pow(std::max(gradNeg[1], 0.0), 2) + std::pow(std::min(gradPos[1], 0.0), 2) +
+                            std::pow(std::max(gradNeg[2], 0.0), 2) + std::pow(std::min(gradPos[2], 0.0), 2);
+                    }
+                }
+               });
+
+        // Uniform advance
+        const double constantVel = m_config->m_constantVelocity;
+        ParallelUtils::parallelFor(dim[0] * dim[1] * dim[2],
+            [&](const int& i)
+            {
+                // If speed function positive use forward difference
+                if (constantVel > 0.0)
+                {
+                    imgPtr[i] += dt * constantVel * std::sqrt(gradientMagPtr[i * 2]);
+                }
+                // If speed function negative use backward difference
+                else if (constantVel < 0.0)
+                {
+                    imgPtr[i] += dt * constantVel * std::sqrt(gradientMagPtr[i * 2 + 1]);
+                }
+            });
+        imageData->modified();
+    }
+}
+
+void
+LevelSetModel::addImpulse(const Vec3i& coord, double f)
+{
+    auto         sdf       = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh);
+    auto         imageData = std::dynamic_pointer_cast<ImageData>(sdf->getImage());
+    const Vec3i& dim       = imageData->getDimensions();
+
+    if (coord[0] >= 0 && coord[0] < dim[0]
+        && coord[1] >= 0 && coord[1] < dim[1]
+        && coord[2] >= 0 && coord[2] < dim[2])
+    {
+        const size_t index = coord[0] + coord[1] * dim[0] + coord[2] * dim[0] * dim[1];
+        if (nodesToUpdate.count(index) > 0)
+        {
+            nodesToUpdate[index] = std::tuple<Vec3i, double>(coord, std::get<1>(nodesToUpdate[index]) + f);
+        }
+        else
+        {
+            nodesToUpdate[index] = std::tuple<Vec3i, double>(coord, f);
+        }
+    }
+}
+
+void
+LevelSetModel::setImpulse(const Vec3i& coord, double f)
+{
+    auto         sdf       = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh);
+    auto         imageData = std::dynamic_pointer_cast<ImageData>(sdf->getImage());
+    const Vec3i& dim       = imageData->getDimensions();
+
+    if (coord[0] >= 0 && coord[0] < dim[0]
+        && coord[1] >= 0 && coord[1] < dim[1]
+        && coord[2] >= 0 && coord[2] < dim[2])
+    {
+        const size_t index = coord[0] + coord[1] * dim[0] + coord[2] * dim[0] * dim[1];
+        nodesToUpdate[index] = std::tuple<Vec3i, double>(coord, f);
+    }
+}
+
+void
+LevelSetModel::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
+{
+    // Given no fields are interacting all quantities should be able to update in parallel
+    for (size_t i = 0; i < m_evolveQuantitiesNodes.size(); i++)
+    {
+        m_taskGraph->addEdge(source, m_evolveQuantitiesNodes[i]);
+        m_taskGraph->addEdge(m_evolveQuantitiesNodes[i], sink);
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.h b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.h
new file mode 100644
index 0000000000000000000000000000000000000000..1b82b53e428c91924497caf123a538c3b17d0ad6
--- /dev/null
+++ b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.h
@@ -0,0 +1,120 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkDynamicalModel.h"
+#include "imstkLevelSetState.h"
+#include "imstkImplicitFunctionFiniteDifferenceFunctor.h"
+
+#include <unordered_map>
+#include <tuple>
+
+namespace imstk
+{
+class ImageData;
+
+struct LevelSetModelConfig
+{
+    double m_dt = 0.001;             ///> Time step size
+    bool m_sparseUpdate = false;     ///> Only updates nodes that recieve force
+    bool m_useCurvature = false;
+    double m_k = 0.2;                // Curvature term
+    double m_constantVelocity = 0.0; // Constant velocity
+};
+
+///
+/// \class LevelSetModel
+///
+/// \brief This class implements a generic level set model, it requires both a forward
+/// and backward finite differencing method
+///
+class LevelSetModel : public DynamicalModel<LevelSetState>
+{
+public:
+    ///
+    /// \brief Constructor
+    ///
+    LevelSetModel();
+
+    ///
+    /// \brief Destructor
+    ///
+    virtual ~LevelSetModel() override = default;
+
+public:
+    ///
+    /// \brief Set the time step size
+    ///
+    virtual void setTimeStep(const Real timeStep) override { m_config->m_dt = timeStep; }
+
+    ///
+    /// \brief Returns the time step size
+    ///
+    virtual double getTimeStep() const override { return m_config->m_dt; }
+
+    ///
+    /// \brief Update body states given the newest update and the type of update
+    ///
+    virtual void updateBodyStates(const Vectord& /*q*/, const StateUpdateType /*updateType = stateUpdateType::displacement*/) override {}
+
+    ///
+    /// \brief Initialize the LevelSet model
+    ///
+    bool initialize() override;
+
+    ///
+    /// \brief Configure the model
+    ///
+    void configure(std::shared_ptr<LevelSetModelConfig> config);
+
+    virtual void evolveDistanceField();
+
+    void addImpulse(const Vec3i& coord, double f);
+    void setImpulse(const Vec3i& coord, double f);
+
+    std::shared_ptr<TaskNode> getQuantityEvolveNode(size_t i) const { return m_evolveQuantitiesNodes[i]; }
+
+protected:
+    ///
+    /// \brief Setup the task graph of the LSM
+    ///
+    void initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) override;
+
+protected:
+    std::shared_ptr<ImplicitGeometry> m_mesh = nullptr; ///> Geometry on which the levelset evolves with
+
+    std::vector<std::shared_ptr<TaskNode>> m_evolveQuantitiesNodes;
+
+    std::shared_ptr<LevelSetModelConfig> m_config;
+
+    std::unordered_map<size_t, std::tuple<Vec3i, double>> nodesToUpdate;
+
+    std::shared_ptr<ImageData> gradientMagnitudes = nullptr; ///> Gradient magnitude field when using dense
+
+    // I'm unable to use the more generic double/floating pt based version
+    // suspect floating point error
+    StructuredForwardGradient  forwardGrad;
+    StructuredBackwardGradient backwardGrad;
+    /*ImplicitFunctionForwardGradient  forwardGrad;
+    ImplicitFunctionBackwardGradient backwardGrad;*/
+};
+}
\ No newline at end of file
diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp
index a5a583654b712f1d1df16e669756a55adaa4e6d8..e95368d560fe689b565016ae2c1a86631c27a3c9 100644
--- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp
@@ -20,9 +20,10 @@
 =========================================================================*/
 
 #include "imstkPbdModel.h"
-#include "imstkGeometryUtilities.h"
 #include "imstkGraph.h"
 #include "imstkLineMesh.h"
+#include "imstkLogger.h"
+#include "imstkParallelUtils.h"
 #include "imstkPbdAreaConstraint.h"
 #include "imstkPbdBendConstraint.h"
 #include "imstkPbdConstantDensityConstraint.h"
@@ -35,15 +36,13 @@
 #include "imstkTaskGraph.h"
 #include "imstkTetrahedralMesh.h"
 
-#include <unordered_map>
-
 namespace imstk
 {
 PbdModel::PbdModel() : DynamicalModel(DynamicalModelType::PositionBasedDynamics),
-    m_constraints(std::make_shared<PBDConstraintVector>()),
-    m_partitionedConstraints(std::make_shared<std::vector<PBDConstraintVector>>()),
     m_mass(std::make_shared<StdVectorOfReal>()),
     m_invMass(std::make_shared<StdVectorOfReal>()),
+    m_constraints(std::make_shared<PBDConstraintVector>()),
+    m_partitionedConstraints(std::make_shared<std::vector<PBDConstraintVector>>()),
     m_parameters(std::make_shared<PBDModelConfig>())
 {
     m_validGeometryTypes = {
@@ -77,6 +76,19 @@ PBDModelConfig::enableFEMConstraint(PbdConstraint::Type type, PbdFEMConstraint::
     m_FEMConstraints.push_back({ type, material });
 }
 
+void
+PBDModelConfig::setSolverType(const PbdConstraint::SolverType& type)
+{
+    if (type == PbdConstraint::SolverType::GCD)
+    {
+        LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead";
+        m_solverType = PbdConstraint::SolverType::xPBD;
+        return;
+    }
+
+    m_solverType = type;
+}
+
 void
 PbdModel::configure(std::shared_ptr<PBDModelConfig> params)
 {
@@ -398,7 +410,6 @@ PbdModel::initializeBendConstraints(const double stiffness)
     // Create constraints
     const auto& lineMesh = std::static_pointer_cast<LineMesh>(m_mesh);
     const auto& elements = lineMesh->getLinesVertices();
-    const auto  nV       = lineMesh->getNumVertices();
 
     // Iterate sets of two segments
     for (size_t k = 0; k < elements.size() - 1; k++)
diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.h b/Source/DynamicalModels/ObjectModels/imstkPbdModel.h
index 691ad576ccbb71b76fd6e08cfdfaf8a8c7c5c5af..641797c75ed9dcb577a1acda8f5a3a78caaf068e 100644
--- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.h
@@ -25,7 +25,6 @@
 #include "imstkPbdCollisionConstraint.h"
 #include "imstkPbdFEMConstraint.h"
 #include "imstkPbdState.h"
-#include "imstkLogger.h"
 
 namespace imstk
 {
@@ -82,17 +81,7 @@ struct PBDModelConfig
     ///
     /// \brief Set the PBD solver type
     ///
-    void setSolverType(const PbdConstraint::SolverType& type)
-    {
-        if (type == PbdConstraint::SolverType::GCD)
-        {
-            LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead";
-            m_solverType = PbdConstraint::SolverType::xPBD;
-            return;
-        }
-
-        m_solverType = type;
-    }
+    void setSolverType(const PbdConstraint::SolverType& type);
 
     PbdConstraint::SolverType m_solverType = PbdConstraint::SolverType::xPBD;
 };
diff --git a/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.h b/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.h
index b8f55955b2676b86608c8d7bf861c99eedc82a9a..f11f092adf49d9e2b2069928c931b53b67cc7707 100644
--- a/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.h
@@ -24,6 +24,7 @@
 #include <memory>
 
 #include "imstkDynamicalModel.h"
+#include "imstkVectorizedState.h"
 #include "imstkNonLinearSystem.h"
 #include "imstkLogger.h"
 
@@ -366,4 +367,4 @@ protected:
 private:
     std::shared_ptr<TaskNode> m_solveNode = nullptr;
 };
-}  // namespace imstk
\ No newline at end of file
+}  // namespace imstk
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp
index 937c3da0647e8b440f3859e6aceeaec84d3a05f8..fe614262f424ed16543cb44430792911f3e1832f 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp
@@ -18,14 +18,13 @@
    limitations under the License.
 
 =========================================================================*/
+
 #include "imstkRigidBodyModel.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkCube.h"
-#include "imstkSphere.h"
+#include "imstkLogger.h"
 #include "imstkPlane.h"
-#include "physx/extensions/PxSimpleFactory.h"
-
-#include <g3log/g3log.hpp>
+#include "imstkSphere.h"
+#include "imstkSurfaceMesh.h"
 
 namespace imstk
 {
@@ -272,7 +271,7 @@ RigidBodyModel::createMesh()
     }
 }
 
-//TODO: Have to implement update physics geometry
+// \todo: Have to implement update physics geometry
 void
 RigidBodyModel::updatePhysicsGeometry()
 {
@@ -300,7 +299,7 @@ RigidBodyModel::updatePhysicsGeometry()
     m_force = Vec3d(0., 0., 0.);
 }
 
-//TODO: Have to implement update physics spring geometry
+// \todo: Have to implement update physics spring geometry
 void
 RigidBodyModel::addForce(const Vec3d& force, const Vec3d& pos, bool wakeup)
 {
@@ -312,16 +311,20 @@ RigidBodyModel::addForce(const Vec3d& force, const Vec3d& pos, bool wakeup)
         PxForceMode::eFORCE, wakeup);
 }
 
+#ifdef WIN32
 #pragma warning( push )
 #pragma warning( disable : 4100 )
-//TODO updating body states as in
+#endif
+// \todo: updating body states as in
 void
 RigidBodyModel::updateBodyStates(const Vectord& q, const StateUpdateType updateType /* = stateUpdateType::displacement*/)
 {
     LOG(WARNING) << "RigidBodyModel::updateBodyStates Not implemented!";
 }
 
+#ifdef WIN32
 #pragma warning( pop )
+#endif
 
 void
 RigidBodyModel::configure(const std::shared_ptr<RigidBodyConfig> matProperty)
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h
index 89a90ee285d6e7c003d07992c8954ce009e621bd..150d68af45029f25df6ed0db2963859d5f75c50e 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h
@@ -67,7 +67,7 @@ public:
             Geometry::Type::SurfaceMesh
         };
     };
-    ~RigidBodyModel() = default;
+    virtual ~RigidBodyModel() override = default;
 
     ///
     /// \brief Initialize the physx dynamic model
@@ -77,7 +77,7 @@ public:
     ///
     /// \brief Configure the model
     ///
-    // TODO: Setting of mass and gravity has to happen somewhere.
+    // \todo: Setting of mass and gravity has to happen somewhere.
     void configure(const std::shared_ptr<RigidBodyConfig> matProperty);
 
     ///
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6af881aaef48cd6a84a41d172f46e4e0c42d8f4f
--- /dev/null
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp
@@ -0,0 +1,387 @@
+/*=========================================================================
+
+   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 "imstkRigidBodyModel2.h"
+#include "imstkParallelFor.h"
+#include "imstkProjectedGaussSeidelSolver.h"
+#include "imstkRbdConstraint.h"
+#include "imstkTaskGraph.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+RigidBodyModel2::RigidBodyModel2() :
+    m_config(std::make_shared<RigidBodyModel2Config>()),
+    m_pgsSolver(std::make_shared<ProjectedGaussSeidelSolver<double>>())
+{
+    m_computeTentativeVelocities = std::make_shared<TaskNode>(
+        std::bind(&RigidBodyModel2::computeTentativeVelocities, this), "RigidBodyModel_ComputeTentativeVelocities");
+    m_solveNode     = std::make_shared<TaskNode>(std::bind(&RigidBodyModel2::solveConstraints, this), "RigidBodyModel_Solve");
+    m_integrateNode = std::make_shared<TaskNode>(std::bind(&RigidBodyModel2::integrate, this), "RigidBodyModel_Integrate");
+
+    m_taskGraph->addNode(m_computeTentativeVelocities);
+    m_taskGraph->addNode(m_solveNode);
+    m_taskGraph->addNode(m_integrateNode);
+}
+
+std::shared_ptr<RigidBody>
+RigidBodyModel2::addRigidBody()
+{
+    m_bodies.push_back(std::make_shared<RigidBody>());
+    m_modified = true;
+    return m_bodies.back();
+}
+
+void
+RigidBodyModel2::removeRigidBody(std::shared_ptr<RigidBody> rbd)
+{
+    std::vector<std::shared_ptr<RigidBody>>::iterator bodyIter = std::find(m_bodies.begin(), m_bodies.end(), rbd);
+    if (bodyIter != m_bodies.end())
+    {
+        m_bodies.erase(bodyIter);
+    }
+    m_modified = true;
+}
+
+bool
+RigidBodyModel2::initialize()
+{
+    // Only run initialize if a body has been added/removed
+    if (!m_modified)
+    {
+        return true;
+    }
+
+    // Compute the initial state
+    std::shared_ptr<RigidBodyState2> state = std::make_shared<RigidBodyState2>();
+    state->resize(m_bodies.size());
+    std::vector<bool>& isStatic  = state->getIsStatic();
+    StdVectorOfReal&   invMasses = state->getInvMasses();
+    StdVectorOfMat3d&  invInteriaTensors = state->getInvIntertiaTensors();
+    StdVectorOfVec3d&  positions           = state->getPositions();
+    StdVectorOfQuatd&  orientations        = state->getOrientations();
+    StdVectorOfVec3d&  velocities          = state->getVelocities();
+    StdVectorOfVec3d&  angularVelocities   = state->getAngularVelocities();
+    StdVectorOfVec3d&  tentativeVelocities = state->getTentatveVelocities();
+    StdVectorOfVec3d&  tentativeAngularVelocities = state->getTentativeAngularVelocities();
+    StdVectorOfVec3d&  forces  = state->getForces();
+    StdVectorOfVec3d&  torques = state->getTorques();
+
+    m_Minv = Eigen::SparseMatrix<double>(m_bodies.size() * 6, m_bodies.size() * 6);
+    std::vector<Eigen::Triplet<double>> mInvTriplets;
+    mInvTriplets.reserve((9 + 3) * m_bodies.size());
+    for (size_t i = 0; i < m_bodies.size(); i++)
+    {
+        RigidBody& body = *m_bodies[i];
+
+        // Set the intial state
+        isStatic[i]  = body.m_isStatic;
+        invMasses[i] = (body.m_mass == 0.0) ? 0.0 : 1.0 / body.m_mass;
+        invInteriaTensors[i] = body.m_intertiaTensor.inverse();         // Is there any easy way to check invertible
+        positions[i]           = body.m_initPos;
+        orientations[i]        = body.m_initOrientation;
+        velocities[i]          = body.m_initVelocity;
+        angularVelocities[i]   = body.m_initAngularVelocity;
+        tentativeVelocities[i] = body.m_initVelocity;
+        tentativeAngularVelocities[i] = body.m_initAngularVelocity;
+        forces[i]  = body.m_initForce;
+        torques[i] = body.m_initTorque;
+
+        // Link it up with the state
+        body.m_pos = &positions[i];
+        body.m_orientation     = &orientations[i];
+        body.m_velocity        = &velocities[i];
+        body.m_angularVelocity = &angularVelocities[i];
+        body.m_force  = &forces[i];
+        body.m_torque = &torques[i];
+        m_locations[m_bodies[i].get()] = static_cast<StorageIndex>(i);
+
+        if (!body.m_isStatic)
+        {
+            // invMass expanded to 3x3 matrix
+            const double invMass     = invMasses[i];
+            const Mat3d& invInvertia = invInteriaTensors[i];
+            int          index       = static_cast<int>(i * 6);
+            mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass));
+            index++;
+            mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass));
+            index++;
+            mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass));
+            index++;
+            for (unsigned int c = 0; c < 3; c++)
+            {
+                for (unsigned int r = 0; r < 3; r++)
+                {
+                    mInvTriplets.push_back(Eigen::Triplet<double>(index + r, index + c, invInvertia(c, r)));
+                }
+            }
+        }
+    }
+    m_Minv.setFromTriplets(mInvTriplets.begin(), mInvTriplets.end());
+
+    // Copy to initial state
+    m_initialState  = std::make_shared<RigidBodyState2>(*state);
+    m_currentState  = state;
+    m_previousState = std::make_shared<RigidBodyState2>(*state);
+    m_modified      = false;
+
+    return true;
+}
+
+void
+RigidBodyModel2::configure(std::shared_ptr<RigidBodyModel2Config> config)
+{
+    m_config = config;
+}
+
+void
+RigidBodyModel2::computeTentativeVelocities()
+{
+    const double            dt = m_config->m_dt;
+    const StdVectorOfReal&  invMasses = getCurrentState()->getInvMasses();
+    const StdVectorOfMat3d& invInteriaTensors   = getCurrentState()->getInvIntertiaTensors();
+    StdVectorOfVec3d&       tentativeVelocities = getCurrentState()->getTentatveVelocities();
+    StdVectorOfVec3d&       tentativeAngularVelocities = getCurrentState()->getTentativeAngularVelocities();
+    StdVectorOfVec3d&       forces  = getCurrentState()->getForces();
+    StdVectorOfVec3d&       torques = getCurrentState()->getTorques();
+    const Vec3d&            fG      = m_config->m_gravity;
+
+    // Sum gravity to the forces
+    ParallelUtils::parallelFor(forces.size(), [&forces, &fG](const size_t& i)
+            {
+                forces[i] += fG;
+        });
+
+    // Compute the desired velocites, later we will solve for the proper velocities,
+    // adjusted for the constraints
+    ParallelUtils::parallelFor(tentativeVelocities.size(), [&](const size_t& i)
+            {
+                tentativeVelocities[i] += forces[i] * invMasses[i] * dt;
+                tentativeAngularVelocities[i] += invInteriaTensors[i] * torques[i] * dt;
+        });
+}
+
+void
+RigidBodyModel2::solveConstraints()
+{
+    // Solves the current constraints of the system, then discards them
+    if (m_constraints.size() == 0)
+    {
+        return;
+    }
+
+    std::shared_ptr<RigidBodyState2> state    = getCurrentState();
+    const std::vector<bool>&         isStatic = state->getIsStatic();
+    const StdVectorOfVec3d&          tentativeVelocities = state->getTentatveVelocities();
+    const StdVectorOfVec3d&          tentativeAngularVelocities = state->getTentativeAngularVelocities();
+    StdVectorOfVec3d&                forces  = state->getForces();
+    StdVectorOfVec3d&                torques = state->getTorques();
+
+    Eigen::VectorXd F;
+    Eigen::VectorXd V    = Eigen::VectorXd(state->size() * 6);
+    Eigen::VectorXd Fext = Eigen::VectorXd(state->size() * 6);
+
+    // Fill the forces and tenative velocities vectors
+    StorageIndex j = 0;
+    for (size_t i = 0; i < state->size(); i++)
+    {
+        if (!isStatic[i])
+        {
+            const Vec3d& velocity = tentativeVelocities[i];
+            const Vec3d& angularVelocity = tentativeAngularVelocities[i];
+            const Vec3d& force  = forces[i];
+            const Vec3d& torque = torques[i];
+            Fext(j) = force[0];
+            V(j)    = velocity[0];
+            j++;
+            Fext(j) = force[1];
+            V(j)    = velocity[1];
+            j++;
+            Fext(j) = force[2];
+            V(j)    = velocity[2];
+            j++;
+            Fext(j) = torque[0];
+            V(j)    = angularVelocity[0];
+            j++;
+            Fext(j) = torque[1];
+            V(j)    = angularVelocity[1];
+            j++;
+            Fext(j) = torque[2];
+            V(j)    = angularVelocity[2];
+            j++;
+        }
+        else
+        {
+            for (StorageIndex k = 0; k < 6; k++)
+            {
+                Fext(j + k) = 0.0;
+                V(j + k)    = 0.0;
+            }
+            j += 6;
+        }
+    }
+
+    // Now construct the sparse jacobian matrix for every constraint (object vs constraint)
+    Eigen::SparseMatrix<double>         J(m_constraints.size(), state->size() * 6);
+    Eigen::VectorXd                     Vu(m_constraints.size());    // Push Factor
+    Eigen::MatrixXd                     cu(m_constraints.size(), 2); // Mins and maxes
+    std::vector<Eigen::Triplet<double>> JTriplets;
+    JTriplets.reserve(m_constraints.size() * 12);
+    j = 0;
+    for (std::list<std::shared_ptr<RbdConstraint>>::iterator iter = m_constraints.begin(); iter != m_constraints.end(); iter++)
+    {
+        std::shared_ptr<RbdConstraint> constraint = *iter;
+        Vu(j) = constraint->vu;
+
+        // Object 1
+        StorageIndex k = 0;
+        if (constraint->m_obj1 != nullptr)
+        {
+            const StorageIndex obj1Location = m_locations[constraint->m_obj1.get()];
+            const StorageIndex start1       = obj1Location * 6;
+            for (StorageIndex c = 0; c < 2; c++)
+            {
+                for (StorageIndex r = 0; r < 3; r++)
+                {
+                    JTriplets.push_back(Eigen::Triplet<double>(j, start1 + k, constraint->J(r, c)));
+                    k++;
+                }
+            }
+        }
+
+        // Object 2
+        if (constraint->m_obj2 != nullptr)
+        {
+            const StorageIndex obj2Location = m_locations[constraint->m_obj2.get()];
+            const StorageIndex start2       = obj2Location * 6;
+            k = 0;
+            for (StorageIndex c = 2; c < 4; c++)
+            {
+                for (StorageIndex r = 0; r < 3; r++)
+                {
+                    JTriplets.push_back(Eigen::Triplet<double>(j, start2 + k, constraint->J(r, c)));
+                    k++;
+                }
+            }
+        }
+
+        cu(j, 0) = constraint->range[0];
+        cu(j, 1) = constraint->range[1];
+        j++;
+    }
+    J.setFromTriplets(JTriplets.begin(), JTriplets.end());
+
+    const double                dt = m_config->m_dt;
+    Eigen::SparseMatrix<double> A  = J * m_Minv * J.transpose();
+    Eigen::VectorXd             b  = Vu / dt - J * (V / dt + m_Minv * Fext);
+
+    /* std::cout << "Minv: " << std::endl << m_Minv.toDense() << std::endl;
+     std::cout << "J: " << std::endl << J.toDense() << std::endl;
+     std::cout << "A: " << std::endl << A.toDense() << std::endl;
+     std::cout << std::endl;
+     std::cout << "Vu: " << std::endl << Vu << std::endl;
+     std::cout << "V: " << std::endl << V << std::endl;
+     std::cout << "b: " << std::endl << b << std::endl;*/
+
+    m_pgsSolver->setA(&A);
+    //pgsSolver.setGuess(F); // Not using warm starting
+    m_pgsSolver->setMaxIterations(m_config->m_maxNumIterations);
+    F = J.transpose() * m_pgsSolver->solve(b, cu);
+
+    // Apply back
+    j = 0;
+    for (size_t i = 0; i < state->size(); i++, j += 6)
+    {
+        forces[i]  += Vec3d(F(j), F(j + 1), F(j + 2));
+        torques[i] += Vec3d(F(j + 3), F(j + 4), F(j + 5));
+    }
+
+    //std::cout << std::endl << "Forces/Torques: " << F << std::endl;
+
+    m_constraints.clear();
+}
+
+void
+RigidBodyModel2::integrate()
+{
+    // Just a basic symplectic euler
+    const double dt = m_config->m_dt;
+    const double velocityDamping = m_config->m_velocityDamping;
+    const double angularVelocityDamping = m_config->m_angularVelocityDamping;
+
+    const std::vector<bool>& isStatic = getCurrentState()->getIsStatic();
+
+    const StdVectorOfReal&  invMasses = getCurrentState()->getInvMasses();
+    const StdVectorOfMat3d& invInteriaTensors = getCurrentState()->getInvIntertiaTensors();
+
+    StdVectorOfVec3d& positions    = getCurrentState()->getPositions();
+    StdVectorOfQuatd& orientations = getCurrentState()->getOrientations();
+
+    StdVectorOfVec3d& velocities = getCurrentState()->getVelocities();
+    StdVectorOfVec3d& angularVelocities = getCurrentState()->getAngularVelocities();
+
+    StdVectorOfVec3d& tentativeVelocities = getCurrentState()->getTentatveVelocities();
+    StdVectorOfVec3d& tentativeAngularVelocities = getCurrentState()->getTentativeAngularVelocities();
+
+    StdVectorOfVec3d& forces  = getCurrentState()->getForces();
+    StdVectorOfVec3d& torques = getCurrentState()->getTorques();
+
+    ParallelUtils::parallelFor(positions.size(), [&](const size_t& i)
+            {
+                if (!isStatic[i])
+                {
+                    velocities[i] += forces[i] * invMasses[i] * dt;
+                    velocities[i] *= velocityDamping;
+                    angularVelocities[i] += invInteriaTensors[i] * torques[i] * dt;
+                    angularVelocities[i] *= angularVelocityDamping;
+                    positions[i] += velocities[i] * dt;
+                    {
+                        const Quatd q = Quatd(0.0,
+                        angularVelocities[i][0],
+                        angularVelocities[i][1],
+                        angularVelocities[i][2]) * orientations[i];
+                        orientations[i].x() += q.x() * dt;
+                        orientations[i].y() += q.y() * dt;
+                        orientations[i].z() += q.z() * dt;
+                        orientations[i].w() += q.w() * dt;
+                        orientations[i].normalize();
+                    }
+                }
+
+                // Reset
+                forces[i]  = Vec3d(0.0, 0.0, 0.0);
+                torques[i] = Vec3d(0.0, 0.0, 0.0);
+                tentativeVelocities[i] = velocities[i];
+                tentativeAngularVelocities[i] = angularVelocities[i];
+        });
+}
+
+void
+RigidBodyModel2::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
+{
+    m_taskGraph->addEdge(source, m_computeTentativeVelocities);
+    m_taskGraph->addEdge(m_computeTentativeVelocities, m_solveNode);
+    m_taskGraph->addEdge(m_solveNode, m_integrateNode);
+    m_taskGraph->addEdge(m_integrateNode, sink);
+}
+}
+}
\ No newline at end of file
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h
new file mode 100644
index 0000000000000000000000000000000000000000..debed6f82a9d1800d588f3af5b2c6bd0cfe70f41
--- /dev/null
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h
@@ -0,0 +1,156 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkDynamicalModel.h"
+#include "imstkRigidBodyState2.h"
+
+#include <list>
+#include <unordered_map>
+
+namespace imstk
+{
+template<typename ScalarType>
+class ProjectedGaussSeidelSolver;
+
+namespace expiremental
+{
+class RbdConstraint;
+struct RigidBody;
+
+struct RigidBodyModel2Config
+{
+    double m_dt     = 0.001; ///> Time step size
+    Vec3d m_gravity = Vec3d(0.0, -9.8, 0.0);
+    unsigned int m_maxNumIterations = 10;
+    double m_velocityDamping = 0.99;
+    double m_angularVelocityDamping = 0.99;
+};
+
+///
+/// \class RigidBodyModel2
+///
+/// \brief This class implements a constraint based rigid body linear system
+/// with pgs solver
+///
+class RigidBodyModel2 : public DynamicalModel<RigidBodyState2>
+{
+public:
+    using StorageIndex = Eigen::SparseMatrix<double>::StorageIndex;
+
+public:
+    ///
+    /// \brief Constructor
+    ///
+    RigidBodyModel2();
+
+    ///
+    /// \brief Destructor
+    ///
+    virtual ~RigidBodyModel2() override = default;
+
+public:
+    ///
+    /// \brief Set the time step size
+    ///
+    virtual void setTimeStep(const Real timeStep) override { m_config->m_dt = timeStep; }
+
+    ///
+    /// \brief Returns the time step size
+    ///
+    virtual double getTimeStep() const override { return m_config->m_dt; }
+
+    std::shared_ptr<RigidBodyModel2Config> getConfig() const { return m_config; }
+
+    ///
+    /// \brief Adds a body to the system, must call initialize for changes to effect
+    /// returns its reference
+    ///
+    std::shared_ptr<RigidBody> addRigidBody();
+
+    ///
+    /// \brief Adds a constraint to be solved
+    ///
+    void addConstraint(std::shared_ptr<RbdConstraint> constraint) { m_constraints.push_back(constraint); }
+
+    ///
+    /// \brief Removes a body from the system, must call initialize for changes to effect
+    ///
+    void removeRigidBody(std::shared_ptr<RigidBody> body);
+
+    ///
+    /// \todo: remove
+    ///
+    virtual void updateBodyStates(const Vectord& /*q*/, const StateUpdateType /*updateType = stateUpdateType::displacement*/) override {}
+
+    ///
+    /// \brief Initialize the RigidBody model
+    ///
+    bool initialize() override;
+
+    ///
+    /// \brief Configure the model
+    ///
+    void configure(std::shared_ptr<RigidBodyModel2Config> config);
+
+    ///
+    /// \brief Computes the velocities
+    ///
+    void computeTentativeVelocities();
+
+    ///
+    /// \brief Solve the current constraints of the model, then discards
+    ///
+    void solveConstraints();
+
+    ///
+    /// \brief Integrate the model state
+    ///
+    void integrate();
+
+    std::shared_ptr<TaskNode> getComputeTentativeVelocitiesNode() const { return m_computeTentativeVelocities; }
+    std::shared_ptr<TaskNode> getSolveNode() const { return m_solveNode; }
+    std::shared_ptr<TaskNode> getIntegrateNode() const { return m_integrateNode; }
+
+protected:
+    ///
+    /// \brief Setup the task graph of the LSM
+    ///
+    void initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) override;
+
+protected:
+    std::shared_ptr<RigidBodyModel2Config> m_config;
+
+    std::shared_ptr<TaskNode> m_computeTentativeVelocities;
+    std::shared_ptr<TaskNode> m_solveNode;
+    std::shared_ptr<TaskNode> m_integrateNode;
+
+protected:
+    std::shared_ptr<ProjectedGaussSeidelSolver<double>> m_pgsSolver;
+    Eigen::SparseMatrix<double> m_Minv;
+    std::list<std::shared_ptr<RbdConstraint>>    m_constraints;
+    std::vector<std::shared_ptr<RigidBody>>      m_bodies;
+    std::unordered_map<RigidBody*, StorageIndex> m_locations;
+    bool m_modified = true;
+};
+}
+}
\ No newline at end of file
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.cpp b/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.cpp
index f886a8c61ca3382ebe78543e98fa0d70e9fcebcd..d6289fa4a50367bbcff730ee689816c85e950574 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.cpp
@@ -18,9 +18,9 @@
    limitations under the License.
 
 =========================================================================*/
-#include "imstkRigidBodyWorld.h"
 
-#include <g3log/g3log.hpp>
+#include "imstkRigidBodyWorld.h"
+#include "imstkLogger.h"
 
 #define MAX_CONTACTS_PER_BODY 16
 
@@ -34,7 +34,7 @@ RigidBodyWorld::RigidBodyWorld()
     m_Physics    = PxCreatePhysics(PX_PHYSICS_VERSION, *m_Foundation, PxTolerancesScale(), true, m_Pvd);
     m_Cooking    = PxCreateCooking(PX_PHYSICS_VERSION, *m_Foundation, PxCookingParams(PxTolerancesScale()));
 
-    // TODO: move this into a separate structure that user can supply
+    // \todo: move this into a separate structure that user can supply
     PxSceneDesc sceneDesc(m_Physics->getTolerancesScale());
     sceneDesc.gravity       = PxVec3(0.0f, -9.81f, 0.0f);
     m_Dispatcher            = PxDefaultCpuDispatcherCreate(2);
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.h b/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.h
index f822c55ce3604a4e30f015d47df73a052b7b2224..2a1b9bb6ef36e17b1514e034edbbb3b0a43eab80 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.h
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyWorld.h
@@ -19,12 +19,14 @@
 
 =========================================================================*/
 
-#ifndef imstkRigidBodyWorld_h
-#define imstkRigidBodyWorld_h
+#pragma once
+
+#include "imstkDynamicalModel.h"
+#include "imstkRigidBodyState.h"
 
 #define PhysX_RELEASE(x)        if (x) { x->release(); x = NULL; }
 
-#include "physx/PxConfig.h"
+#include <physx/PxConfig.h>
 #if !defined(NDEBUG) && !defined(_DEBUG)
 // PhysX tests for _DEBUG preprocessor definition in a debug build
 // On Windows, MSVC defines this automatically
@@ -32,20 +34,11 @@
   # define _DEBUG 1
   # define imstkPxPhysXAPI_DEBUG
 #endif
-#include "physx/PxPhysicsAPI.h"
+#include <physx/PxPhysicsAPI.h>
 #ifdef imstkPxPhysXAPI_DEBUG
   #undef _DEBUG
   #undef imstkPxPhysXAPI_DEBUG
 #endif
-#include "physx/extensions/PxDefaultErrorCallback.h"
-
-#include "imstkDynamicalModel.h"
-#include "imstkRigidBodyState.h"
-#include "imstkSurfaceMesh.h"
-
-//#include "../snippets/snippetcommon/SnippetPrint.h"
-//#include "../snippets/snippetcommon/SnippetPVD.h"
-//#include "../snippets/snippetutils/SnippetUtils.h"
 
 namespace imstk
 {
@@ -105,5 +98,3 @@ private:
     RigidBodyWorld();
 };
 } // imstk
-
-#endif // imstkRigidBodyWorld_h
diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHKernels.h b/Source/DynamicalModels/ObjectModels/imstkSPHKernels.h
index 0fcde0a84740196a07b7fde4e9acf799e712cd65..352b4f32431e5d2f70b4bda6331124bfd67c6906 100644
--- a/Source/DynamicalModels/ObjectModels/imstkSPHKernels.h
+++ b/Source/DynamicalModels/ObjectModels/imstkSPHKernels.h
@@ -21,11 +21,8 @@
 
 #pragma once
 
-#include <cmath>
-#include <cassert>
-
 #include "imstkMath.h"
-#include <g3log/g3log.hpp>
+#include "imstkLogger.h"
 
 namespace imstk
 {
@@ -54,10 +51,14 @@ public:
         m_radius  = radius;
         m_radius2 = m_radius * m_radius;
 
+#ifdef WIN32
 #pragma warning(push)
 #pragma warning(disable:4127)
+#endif
         if (N == 2)
+#ifdef WIN32
 #pragma warning(pop)
+#endif
         {
             m_k = Real(4.0) / (PI * std::pow(m_radius, 8));
             m_l = -Real(24.0) / (PI * std::pow(m_radius, 8));
@@ -163,10 +164,14 @@ public:
         m_radius  = radius;
         m_radius2 = m_radius * m_radius;
 
+#ifdef WIN32
 #pragma warning(push)
 #pragma warning(disable:4127)
+#endif
         if (N == 2)
+#ifdef WIN32
 #pragma warning(pop)
+#endif
         {
             const auto radius5 = std::pow(m_radius, 5);
             m_k = Real(10.0) / (PI * radius5);
@@ -252,10 +257,14 @@ public:
         m_radius  = radius;
         m_radius2 = m_radius * m_radius;
 
+#ifdef WIN32
 #pragma warning(push)
 #pragma warning(disable:4127)
+#endif
         CHECK(N != 2) << "Unimplemented function";
+#ifdef WIN32
 #pragma warning(pop)
+#endif
 
         m_k  = Real(32.0) / (PI * std::pow(m_radius, 9));
         m_c  = std::pow(m_radius, 6) / Real(64.0);
diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp b/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp
index 890c114aed0abfd0b61a3f6ba273146ca34a9f3b..95f4ae6f9bafc41eb2bae8b06f2f9c6705a3ea48 100644
--- a/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp
@@ -20,7 +20,6 @@ limitations under the License.
 =========================================================================*/
 
 #include "imstkSPHModel.h"
-#include "imstkLogger.h"
 #include "imstkParallelUtils.h"
 #include "imstkPointSet.h"
 #include "imstkTaskGraph.h"
@@ -130,6 +129,11 @@ SPHModel::SPHModel() : DynamicalModel<SPHKinematicState>(DynamicalModelType::Smo
         {
             moveParticles(getTimeStep());
         });
+    //m_computePositionNode =
+    //    m_taskGraph->addFunction("SPHModel_ComputePositions", [&]()
+    //    {
+    //        moveParticles(getTimeStep());
+    //        });
 }
 
 bool
@@ -207,6 +211,7 @@ SPHModel::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskN
     m_taskGraph->addEdge(m_integrateNode, m_updateVelocityNode);
     m_taskGraph->addEdge(m_updateVelocityNode, m_moveParticlesNode);
     m_taskGraph->addEdge(m_moveParticlesNode, sink);
+
 }
 
 void
diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHModel.h b/Source/DynamicalModels/ObjectModels/imstkSPHModel.h
index 7ca4d3ca2c8159af3858b32ef37401acb8c164c6..9982b805c02cf5d0588367c603052986a3db44cf 100644
--- a/Source/DynamicalModels/ObjectModels/imstkSPHModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkSPHModel.h
@@ -31,7 +31,6 @@
 
 namespace imstk
 {
-class ComputeNode;
 class PointSet;
 
 ///
@@ -302,7 +301,6 @@ protected:
     std::shared_ptr<TaskNode> m_updateVelocityNode   = nullptr;
     std::shared_ptr<TaskNode> m_computeViscosityNode = nullptr;
     std::shared_ptr<TaskNode> m_moveParticlesNode    = nullptr;
-
     std::shared_ptr<TaskNode> m_normalizeDensityNode       = nullptr;
     std::shared_ptr<TaskNode> m_collectNeighborDensityNode = nullptr;
 
diff --git a/Source/Rendering/imstkRenderer.cpp b/Source/DynamicalModels/ObjectStates/imstkLevelSetState.cpp
similarity index 80%
rename from Source/Rendering/imstkRenderer.cpp
rename to Source/DynamicalModels/ObjectStates/imstkLevelSetState.cpp
index 92afd991bd943ef0352de759c5342ffe3fe0d3a9..1ef13b6f12d8d02c303615e4262d1b49fc173818 100644
--- a/Source/Rendering/imstkRenderer.cpp
+++ b/Source/DynamicalModels/ObjectStates/imstkLevelSetState.cpp
@@ -19,20 +19,17 @@
 
 =========================================================================*/
 
-#include "imstkRenderer.h"
+#include "imstkLevelSetState.h"
 
 namespace imstk
 {
 void
-Renderer::setMode(const Renderer::Mode mode, const bool enableVR)
+LevelSetState::initialize(std::shared_ptr<ImplicitGeometry> geometry)
 {
-    m_VrEnabled   = enableVR;
-    m_currentMode = mode;
 }
 
-const Renderer::Mode&
-Renderer::getMode()
+void
+LevelSetState::setState(std::shared_ptr<LevelSetState> rhs)
 {
-    return m_currentMode;
 }
 }
\ No newline at end of file
diff --git a/Source/DynamicalModels/ObjectStates/imstkLevelSetState.h b/Source/DynamicalModels/ObjectStates/imstkLevelSetState.h
new file mode 100644
index 0000000000000000000000000000000000000000..bbdd016141a4e521a16863759a7ef16f517d48d4
--- /dev/null
+++ b/Source/DynamicalModels/ObjectStates/imstkLevelSetState.h
@@ -0,0 +1,58 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkImplicitGeometry.h"
+
+namespace imstk
+{
+class ImplicitGeometry;
+
+///
+/// \class LevelSetState
+///
+/// \brief Generic definition of the state of the levelset via ImplicitGeometry
+/// The state gives a set of implicit geometries, each of which represent the state
+/// of a quantity on the levelset. Each implicit geometry then gives the signed function value
+/// and gradient of the quantity. Usually this would be distances, but one may also evolve densities
+/// or even heat on any domain
+///
+class LevelSetState : public ImplicitGeometry
+{
+public:
+    ///
+    /// \brief Default constructor/destructor
+    ///
+    LevelSetState() = default;
+    virtual ~LevelSetState() override = default;
+
+    ///
+    /// \brief Initialize the pbd state
+    ///
+    void initialize(std::shared_ptr<ImplicitGeometry> geometry);
+
+    ///
+    /// \brief Set the state to a given one
+    ///
+    void setState(std::shared_ptr<LevelSetState> rhs);
+};
+} // imstk
diff --git a/Source/DynamicalModels/ObjectStates/imstkPbdState.cpp b/Source/DynamicalModels/ObjectStates/imstkPbdState.cpp
index 13c84c079c919daf9bc67d76a1d167534e89e937..f411988badc3cc601158d8f1189d18c49571fb66 100644
--- a/Source/DynamicalModels/ObjectStates/imstkPbdState.cpp
+++ b/Source/DynamicalModels/ObjectStates/imstkPbdState.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkPbdState.h"
-#include "imstkPointSet.h"
 
 namespace imstk
 {
diff --git a/Source/DynamicalModels/ObjectStates/imstkRigidBodyState.h b/Source/DynamicalModels/ObjectStates/imstkRigidBodyState.h
index b67ce30c98cce95d020b5a7b7080949d4f3efad8..d2ac882dd9a08345ee2c58635fb92ba3769b82dc 100644
--- a/Source/DynamicalModels/ObjectStates/imstkRigidBodyState.h
+++ b/Source/DynamicalModels/ObjectStates/imstkRigidBodyState.h
@@ -21,10 +21,6 @@
 
 #pragma once
 
-#include <Eigen/Dense>
-#include <memory>
-#include <vector>
-
 #include "imstkMath.h"
 
 namespace imstk
diff --git a/Source/DynamicalModels/ObjectStates/imstkRigidBodyState2.h b/Source/DynamicalModels/ObjectStates/imstkRigidBodyState2.h
new file mode 100644
index 0000000000000000000000000000000000000000..327f1610b06c84f615cf427abffa1a6738543468
--- /dev/null
+++ b/Source/DynamicalModels/ObjectStates/imstkRigidBodyState2.h
@@ -0,0 +1,116 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkMath.h"
+
+namespace imstk
+{
+///
+/// \class RigidBodyState2
+///
+/// \brief Kinematic state of rigid bodies within a system
+///
+class RigidBodyState2
+{
+public:
+    void resize(const size_t size)
+    {
+        m_invMasses.resize(size);
+        m_invIntertiaTensors.resize(size);
+        m_positions.resize(size);
+        m_orientations.resize(size);
+        m_velocities.resize(size);
+        m_angularVelocities.resize(size);
+        m_tentativeVelocities.resize(size);
+        m_tentativeAngularVelocities.resize(size);
+        m_forces.resize(size);
+        m_torques.resize(size);
+        m_isStatic.resize(size);
+    }
+
+    size_t size() const { return m_invMasses.size(); }
+
+    const std::vector<bool>& getIsStatic() const { return m_isStatic; }
+    std::vector<bool>& getIsStatic() { return m_isStatic; }
+
+    const StdVectorOfReal& getInvMasses() const { return m_invMasses; }
+    StdVectorOfReal& getInvMasses() { return m_invMasses; }
+    const StdVectorOfMat3d& getInvIntertiaTensors() const { return m_invIntertiaTensors; }
+    StdVectorOfMat3d& getInvIntertiaTensors() { return m_invIntertiaTensors; }
+
+    const StdVectorOfVec3d& getPositions() const { return m_positions; }
+    StdVectorOfVec3d& getPositions() { return m_positions; }
+    const StdVectorOfQuatd& getOrientations() const { return m_orientations; }
+    StdVectorOfQuatd& getOrientations() { return m_orientations; }
+
+    const StdVectorOfVec3d& getVelocities() const { return m_velocities; }
+    StdVectorOfVec3d& getVelocities() { return m_velocities; }
+    const StdVectorOfVec3d& getAngularVelocities() const { return m_angularVelocities; }
+    StdVectorOfVec3d& getAngularVelocities() { return m_angularVelocities; }
+
+    const StdVectorOfVec3d& getTentatveVelocities() const { return m_tentativeVelocities; }
+    StdVectorOfVec3d& getTentatveVelocities() { return m_tentativeVelocities; }
+    const StdVectorOfVec3d& getTentativeAngularVelocities() const { return m_tentativeAngularVelocities; }
+    StdVectorOfVec3d& getTentativeAngularVelocities() { return m_tentativeAngularVelocities; }
+
+    const StdVectorOfVec3d& getForces() const { return m_forces; }
+    StdVectorOfVec3d& getForces() { return m_forces; }
+    const StdVectorOfVec3d& getTorques() const { return m_torques; }
+    StdVectorOfVec3d& getTorques() { return m_torques; }
+
+    ///
+    /// \brief Set the state to a given one, copies
+    ///
+    void setState(std::shared_ptr<RigidBodyState2> state)
+    {
+        m_invMasses = state->getInvMasses();
+        m_invIntertiaTensors = state->getInvIntertiaTensors();
+
+        m_positions    = state->getPositions();
+        m_orientations = state->getOrientations();
+
+        m_velocities = state->getVelocities();
+        m_angularVelocities = state->getAngularVelocities();
+
+        m_forces  = state->getForces();
+        m_torques = state->getTorques();
+    }
+
+private:
+    StdVectorOfReal  m_invMasses;
+    StdVectorOfMat3d m_invIntertiaTensors;
+
+    StdVectorOfVec3d m_positions;
+    StdVectorOfQuatd m_orientations;
+
+    StdVectorOfVec3d m_velocities;
+    StdVectorOfVec3d m_angularVelocities;
+    StdVectorOfVec3d m_tentativeVelocities; ///> Tentative velocities for mid update
+    StdVectorOfVec3d m_tentativeAngularVelocities;
+
+    StdVectorOfVec3d m_forces;
+    StdVectorOfVec3d m_torques;
+
+    std::vector<bool> m_isStatic;
+};
+} // imstk
\ No newline at end of file
diff --git a/Source/DynamicalModels/TimeIntegrators/imstkNewmarkBeta.h b/Source/DynamicalModels/TimeIntegrators/imstkNewmarkBeta.h
index 596d01ef4bfcf8374633f79e77219e63ddb1f036..3733fcde5cedc3db6f3fdea52f6541da09a7f7d8 100644
--- a/Source/DynamicalModels/TimeIntegrators/imstkNewmarkBeta.h
+++ b/Source/DynamicalModels/TimeIntegrators/imstkNewmarkBeta.h
@@ -22,7 +22,6 @@
 #pragma once
 
 #include "imstkTimeIntegrator.h"
-#include "imstkLogger.h"
 
 namespace imstk
 {
diff --git a/Source/Filtering/CMakeLists.txt b/Source/Filtering/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..adffa7aa0c2a7edc280b7812ac1b98353dab960c
--- /dev/null
+++ b/Source/Filtering/CMakeLists.txt
@@ -0,0 +1,16 @@
+#-----------------------------------------------------------------------------
+# Create target
+#-----------------------------------------------------------------------------
+file(GLOB hFiles *.h)
+file(GLOB cppFiles *cpp)
+
+include(imstkAddLibrary)
+imstk_add_library( Filtering
+  H_FILES
+    ${hFiles}
+  CPP_FILES
+    ${cppFiles}
+  DEPENDS
+    Geometry
+    DataStructures
+    ${VTK_LIBRARIES})
diff --git a/Source/Filtering/imstkAppendMesh.cpp b/Source/Filtering/imstkAppendMesh.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..18b0109bc065e3888b18161272dbfdcaed696aac
--- /dev/null
+++ b/Source/Filtering/imstkAppendMesh.cpp
@@ -0,0 +1,69 @@
+/*=========================================================================
+
+   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 "imstkAppendMesh.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkLogger.h"
+#include "imstkSurfaceMesh.h"
+
+#include <vtkAppendPolyData.h>
+
+namespace imstk
+{
+AppendMesh::AppendMesh()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<SurfaceMesh>());
+}
+
+void
+AppendMesh::addInputMesh(std::shared_ptr<SurfaceMesh> inputMesh)
+{
+    setNumberOfInputPorts(getNumberOfInputPorts() + 1);
+    setInput(inputMesh, getNumberOfInputPorts() - 1);
+}
+
+std::shared_ptr<SurfaceMesh>
+AppendMesh::getOutputMesh() const
+{
+    return std::static_pointer_cast<SurfaceMesh>(getOutput(0));
+}
+
+void
+AppendMesh::requestUpdate()
+{
+    vtkNew<vtkAppendPolyData> filter;
+    for (int i = 0; i < getNumberOfInputPorts(); i++)
+    {
+        std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
+        if (inputMesh == nullptr)
+        {
+            LOG(WARNING) << "Input " << i << " invalid";
+            return;
+        }
+        filter->AddInputData(GeometryUtils::copyToVtkPolyData(inputMesh));
+    }
+    filter->Update();
+
+    setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput()));
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkAppendMesh.h b/Source/Filtering/imstkAppendMesh.h
new file mode 100644
index 0000000000000000000000000000000000000000..16c940a30b3f650bc72e4cfcfb37b548ee6fadbd
--- /dev/null
+++ b/Source/Filtering/imstkAppendMesh.h
@@ -0,0 +1,47 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class SurfaceMesh;
+
+///
+/// \class CleanMesh
+///
+/// \brief This filter appends two SurfaceMeshes, no topological connections are made
+///
+class AppendMesh : public GeometryAlgorithm
+{
+public:
+    AppendMesh();
+    virtual ~AppendMesh() override = default;
+
+public:
+    void addInputMesh(std::shared_ptr<SurfaceMesh> inputMesh);
+    std::shared_ptr<SurfaceMesh> getOutputMesh() const;
+
+protected:
+    void requestUpdate() override;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkCleanMesh.cpp b/Source/Filtering/imstkCleanMesh.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a0629b1723d8a8edf5dc4151cd98f6a738d2ddde
--- /dev/null
+++ b/Source/Filtering/imstkCleanMesh.cpp
@@ -0,0 +1,91 @@
+/*=========================================================================
+
+   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 "imstkCleanMesh.h"
+#include "imstkLineMesh.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkLogger.h"
+#include "imstkGeometryUtilities.h"
+
+#include <vtkCleanPolyData.h>
+
+namespace imstk
+{
+CleanMesh::CleanMesh()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<SurfaceMesh>());
+}
+
+std::shared_ptr<SurfaceMesh>
+CleanMesh::getOutputMesh() const
+{
+    return std::dynamic_pointer_cast<SurfaceMesh>(getOutput(0));
+}
+
+void
+CleanMesh::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh)
+{
+    setInput(inputMesh, 0);
+}
+
+void
+CleanMesh::requestUpdate()
+{
+    std::shared_ptr<PointSet> inputMesh = std::dynamic_pointer_cast<PointSet>(getInput(0));
+    if (inputMesh == nullptr)
+    {
+        LOG(WARNING) << "No inputMesh to clean";
+        return;
+    }
+    vtkSmartPointer<vtkPolyData> inputMeshVtk = nullptr;
+    if (inputMesh->getType() == Geometry::Type::LineMesh)
+    {
+        inputMeshVtk = GeometryUtils::copyToVtkPolyData(std::dynamic_pointer_cast<LineMesh>(inputMesh));
+    }
+    else if (inputMesh->getType() == Geometry::Type::SurfaceMesh)
+    {
+        inputMeshVtk = GeometryUtils::copyToVtkPolyData(std::dynamic_pointer_cast<SurfaceMesh>(inputMesh));
+    }
+    else
+    {
+        LOG(WARNING) << "Unsupported mesh type";
+        return;
+    }
+
+    vtkNew<vtkCleanPolyData> filter;
+    filter->SetInputData(inputMeshVtk);
+    filter->SetTolerance(m_Tolerance);
+    filter->SetAbsoluteTolerance(m_AbsoluteTolerance);
+    filter->SetToleranceIsAbsolute(m_UseAbsolute);
+    filter->Update();
+
+    if (inputMesh->getType() == Geometry::Type::LineMesh)
+    {
+        setOutput(GeometryUtils::copyToLineMesh(filter->GetOutput()));
+    }
+    else if (inputMesh->getType() == Geometry::Type::SurfaceMesh)
+    {
+        setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput()));
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkCleanMesh.h b/Source/Filtering/imstkCleanMesh.h
new file mode 100644
index 0000000000000000000000000000000000000000..d62ba3a12292d37b2e8d92852b02c1810c4fcf0c
--- /dev/null
+++ b/Source/Filtering/imstkCleanMesh.h
@@ -0,0 +1,77 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class SurfaceMesh;
+
+///
+/// \class CleanMesh
+///
+/// \brief This filter can merge duplicate points and cells, it only works with
+/// LineMesh and SurfaceMesh. It accepts a tolerance as a fraction of the length
+/// of bounding box of the input data or an absolute tolerance
+///
+class CleanMesh : public GeometryAlgorithm
+{
+public:
+    CleanMesh();
+    virtual ~CleanMesh() override = default;
+
+public:
+    std::shared_ptr<SurfaceMesh> getOutputMesh() const;
+
+    ///
+    /// \brief Required input, port 0
+    ///
+    void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh);
+
+    imstkGetMacro(Tolerance, double);
+    imstkGetMacro(AbsoluteTolerance, double);
+    imstkGetMacro(UseAbsolute, bool);
+
+    ///
+    /// \brief Set the tolerance for point merging, fraction of bounding box length
+    ///
+    void setTolerance(const double tolerance)
+    {
+        this->m_Tolerance = tolerance;
+        m_UseAbsolute     = false;
+    }
+
+    void setAbsoluteTolerance(const double tolerance)
+    {
+        this->m_AbsoluteTolerance = tolerance;
+        m_UseAbsolute = true;
+    }
+
+protected:
+    void requestUpdate() override;
+
+private:
+    double m_Tolerance = 0.0;
+    double m_AbsoluteTolerance = 1.0;
+    bool   m_UseAbsolute       = false;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkExtractEdges.cpp b/Source/Filtering/imstkExtractEdges.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e710ca0013008d5bbb9d05ef1d4947e45fc0a9c4
--- /dev/null
+++ b/Source/Filtering/imstkExtractEdges.cpp
@@ -0,0 +1,72 @@
+/*=========================================================================
+
+   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 "imstkExtractEdges.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkLineMesh.h"
+#include "imstkLogger.h"
+#include "imstkSurfaceMesh.h"
+
+#include <vtkExtractEdges.h>
+#include <vtkTriangleFilter.h>
+
+namespace imstk
+{
+ExtractEdges::ExtractEdges()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<LineMesh>());
+}
+
+void
+ExtractEdges::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh)
+{
+    setInput(inputMesh, 0);
+}
+
+std::shared_ptr<LineMesh>
+ExtractEdges::getOutputMesh() const
+{
+    return std::static_pointer_cast<LineMesh>(getOutput(0));
+}
+
+void
+ExtractEdges::requestUpdate()
+{
+    std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
+    if (inputMesh == nullptr)
+    {
+        LOG(WARNING) << "No inputMesh to extract edges from";
+        return;
+    }
+
+    vtkNew<vtkExtractEdges> extractEdges;
+    extractEdges->SetInputData(GeometryUtils::copyToVtkPolyData(inputMesh));
+    extractEdges->Update();
+
+    vtkNew<vtkTriangleFilter> triangleFilter;
+    triangleFilter->SetInputData(extractEdges->GetOutput());
+    triangleFilter->Update();
+
+    setOutput(GeometryUtils::copyToLineMesh(triangleFilter->GetOutput()));
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkExtractEdges.h b/Source/Filtering/imstkExtractEdges.h
new file mode 100644
index 0000000000000000000000000000000000000000..4867b95c0d19f07d1812777f214150b74ca4aa73
--- /dev/null
+++ b/Source/Filtering/imstkExtractEdges.h
@@ -0,0 +1,49 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class LineMesh;
+class SurfaceMesh;
+
+///
+/// \class ExtractEdges
+///
+/// \brief This filter extracts the edges of a SurfaceMesh producing a LineMesh
+///
+class ExtractEdges : public GeometryAlgorithm
+{
+public:
+    ExtractEdges();
+    virtual ~ExtractEdges() override = default;
+
+public:
+    std::shared_ptr<LineMesh> getOutputMesh() const;
+
+    void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh);
+
+protected:
+    void requestUpdate() override;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkGeometryAlgorithm.cpp b/Source/Filtering/imstkGeometryAlgorithm.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f556e8ab08a0f7da58ad352e931fa4b6fe50bd29
--- /dev/null
+++ b/Source/Filtering/imstkGeometryAlgorithm.cpp
@@ -0,0 +1,73 @@
+/*=========================================================================
+
+   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 "imstkGeometryAlgorithm.h"
+#include "imstkLogger.h"
+
+namespace imstk
+{
+void
+GeometryAlgorithm::setInput(std::shared_ptr<Geometry> inputGeometry, size_t port)
+{
+    if (m_inputs.count(port) == 0)
+    {
+        LOG(WARNING) << "Tried to set input " << port << " on filter with " << m_NumberOfInputPorts << " ports";
+    }
+    m_inputs[port] = inputGeometry;
+}
+
+void
+GeometryAlgorithm::setOutput(std::shared_ptr<Geometry> outputGeometry, size_t port)
+{
+    if (m_outputs.count(port) == 0)
+    {
+        LOG(WARNING) << "Tried to set output " << port << " on filter with " << m_NumberOfOutputPorts << " ports";
+    }
+    m_outputs[port] = outputGeometry;
+}
+
+void
+GeometryAlgorithm::setNumberOfInputPorts(size_t numPorts)
+{
+    this->m_NumberOfInputPorts = numPorts;
+    // Add entries in the map for it
+    for (size_t i = 0; i < numPorts; i++)
+    {
+        if (m_inputs.count(i) == 0)
+        {
+            m_inputs[i] = nullptr;
+        }
+    }
+}
+
+void
+GeometryAlgorithm::setNumberOfOutputPorts(size_t numPorts)
+{
+    this->m_NumberOfOutputPorts = numPorts;
+    // Add entries in the map for it
+    for (size_t i = 0; i < numPorts; i++)
+    {
+        if (m_outputs.count(i) == 0)
+        {
+            m_outputs[i] = nullptr;
+        }
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkGeometryAlgorithm.h b/Source/Filtering/imstkGeometryAlgorithm.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c7ba088b58ae7630316426a1581d4ecc4eba8c2
--- /dev/null
+++ b/Source/Filtering/imstkGeometryAlgorithm.h
@@ -0,0 +1,108 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+
+#define imstkSetMacro(name, dataType)       \
+    virtual void set ## name(dataType _arg) \
+    {                                       \
+        if (this->m_ ## name != _arg)       \
+        {                                   \
+            this->m_ ## name = _arg;        \
+        }                                   \
+    }
+#define imstkGetMacro(name, dataType) \
+    virtual dataType get ## name() { return this->m_ ## name; }
+
+namespace imstk
+{
+class Geometry;
+
+// Base class for geometry algorithms
+class GeometryAlgorithm
+{
+protected:
+    GeometryAlgorithm() = default;
+
+public:
+    GeometryAlgorithm(const GeometryAlgorithm&)  = delete;
+    GeometryAlgorithm(const GeometryAlgorithm&&) = delete;
+    virtual ~GeometryAlgorithm() = default;
+
+public:
+    ///
+    /// \brief Returns input geometry given port, returns nullptr if doesn't exist
+    ///
+    std::shared_ptr<Geometry> getInput(size_t port = 0) const { return (m_inputs.count(port) == 0) ? nullptr : m_inputs.at(port); }
+    ///
+    /// \brief Returns output geometry given port, returns nullptr if doesn't exist
+    ///
+    std::shared_ptr<Geometry> getOutput(size_t port = 0) const { return m_outputs.count(port) == 0 ? nullptr : m_outputs.at(port); }
+
+    ///
+    /// \brief Set the input at the port
+    ///
+    void setInput(std::shared_ptr<Geometry> inputGeometry, size_t port = 0);
+
+protected:
+    ///
+    /// \brief Set the output at the port
+    ///
+    void setOutput(std::shared_ptr<Geometry> inputGeometry, size_t port = 0);
+
+    imstkGetMacro(NumberOfInputPorts, size_t);
+    imstkGetMacro(NumberOfOutputPorts, size_t);
+
+    ///
+    /// \brief Sets the amount of input ports
+    ///
+    void setNumberOfInputPorts(size_t numPorts);
+
+    ///
+    /// \brief Sets the amount of output ports
+    ///
+    void setNumberOfOutputPorts(size_t numPorts);
+
+public:
+    //void modified() { this->m_modified = true; }
+
+    void update()
+    {
+        //if (m_modified)
+        //{
+        requestUpdate();
+        //}
+        //m_modified = false;
+    }
+
+protected:
+    virtual void requestUpdate() = 0;
+
+private:
+    std::unordered_map<size_t, std::shared_ptr<Geometry>> m_inputs;
+    std::unordered_map<size_t, std::shared_ptr<Geometry>> m_outputs;
+    //bool m_modified = true;
+    size_t m_NumberOfInputPorts  = 1;
+    size_t m_NumberOfOutputPorts = 1;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkImageDistanceTransform.cpp b/Source/Filtering/imstkImageDistanceTransform.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..48aaeceab3a948707e14dcc5d3498d358260a950
--- /dev/null
+++ b/Source/Filtering/imstkImageDistanceTransform.cpp
@@ -0,0 +1,127 @@
+/*=========================================================================
+
+   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 "imstkImageDistanceTransform.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkImageData.h"
+#include "imstkLogger.h"
+
+#include <vtkImageCast.h>
+#include <vtkImageData.h>
+#include <vtkImageEuclideanDistance.h>
+#include <vtkImageMathematics.h>
+#include <vtkImageShiftScale.h>
+
+namespace imstk
+{
+ImageDistanceTransform::ImageDistanceTransform()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<ImageData>(), 0);
+}
+
+std::shared_ptr<ImageData>
+ImageDistanceTransform::getOutputImage() const
+{
+    return std::dynamic_pointer_cast<ImageData>(getOutput(0));
+}
+
+void
+ImageDistanceTransform::setInputImage(std::shared_ptr<ImageData> refImage)
+{
+    setInput(refImage, 0);
+}
+
+void
+ImageDistanceTransform::requestUpdate()
+{
+    std::shared_ptr<ImageData> imageInput = std::dynamic_pointer_cast<ImageData>(getInput(0));
+
+    if (imageInput == nullptr)
+    {
+        LOG(WARNING) << "Missing input image data";
+        return;
+    }
+
+    vtkSmartPointer<vtkImageData> imageInputVtk = GeometryUtils::coupleVtkImageData(imageInput);
+
+    // Compute the inner distance
+    vtkSmartPointer<vtkImageEuclideanDistance> innerDistanceFilter = vtkSmartPointer<vtkImageEuclideanDistance>::New();
+    innerDistanceFilter->SetInputData(imageInputVtk);
+    innerDistanceFilter->ConsiderAnisotropyOn();
+    innerDistanceFilter->SetAlgorithmToSaito();
+    innerDistanceFilter->SetDimensionality(3);
+    innerDistanceFilter->Update();
+    vtkSmartPointer<vtkImageCast> innerCastFilter = vtkSmartPointer<vtkImageCast>::New();
+    innerCastFilter->SetInputData(innerDistanceFilter->GetOutput());
+    innerCastFilter->SetOutputScalarTypeToFloat();
+    innerCastFilter->Update();
+    vtkSmartPointer<vtkImageMathematics> innerSqrtFilter = vtkSmartPointer<vtkImageMathematics>::New();
+    innerSqrtFilter->SetInput1Data(innerCastFilter->GetOutput());
+    innerSqrtFilter->SetOperationToSquareRoot();
+    innerSqrtFilter->Update();
+
+    // Invert the input mask to compute the outer distance transform
+    double*                             range = imageInputVtk->GetScalarRange();
+    vtkSmartPointer<vtkImageShiftScale> invertFilter = vtkSmartPointer<vtkImageShiftScale>::New();
+    invertFilter->SetInputData(imageInputVtk);
+    invertFilter->SetShift(-range[1]);
+    invertFilter->SetScale(-1.0);
+    invertFilter->Update();
+
+    // Compute the outer distance
+    vtkSmartPointer<vtkImageEuclideanDistance> outerDistanceFilter = vtkSmartPointer<vtkImageEuclideanDistance>::New();
+    outerDistanceFilter->SetInputData(invertFilter->GetOutput());
+    outerDistanceFilter->ConsiderAnisotropyOn();
+    outerDistanceFilter->SetAlgorithmToSaito();
+    outerDistanceFilter->SetDimensionality(3);
+    outerDistanceFilter->Update();
+    vtkSmartPointer<vtkImageCast> outerCastFilter = vtkSmartPointer<vtkImageCast>::New();
+    outerCastFilter->SetInputData(outerDistanceFilter->GetOutput());
+    outerCastFilter->SetOutputScalarTypeToFloat();
+    outerCastFilter->Update();
+    vtkSmartPointer<vtkImageMathematics> outerSqrtFilter = vtkSmartPointer<vtkImageMathematics>::New();
+    outerSqrtFilter->SetInput1Data(outerCastFilter->GetOutput());
+    outerSqrtFilter->SetOperationToSquareRoot();
+    outerSqrtFilter->Update();
+
+    // Inner distance should be negative
+    vtkSmartPointer<vtkImageData> innerImage = innerSqrtFilter->GetOutput();
+    if (!m_UseUnsigned)
+    {
+        vtkSmartPointer<vtkImageShiftScale> negFilter = vtkSmartPointer<vtkImageShiftScale>::New();
+        negFilter->SetInputData(innerSqrtFilter->GetOutput());
+        negFilter->SetScale(-1.0);
+        negFilter->Update();
+        innerImage = negFilter->GetOutput();
+    }
+
+    // Finally combine the negative and positive
+    vtkSmartPointer<vtkImageMathematics> addImageFilter = vtkSmartPointer<vtkImageMathematics>::New();
+    addImageFilter->SetInput1Data(outerSqrtFilter->GetOutput());
+    addImageFilter->SetInput2Data(innerImage);
+    addImageFilter->SetOperationToAdd();
+    addImageFilter->Update();
+
+    setOutput(GeometryUtils::copyToImageData(addImageFilter->GetOutput()));
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkImageDistanceTransform.h b/Source/Filtering/imstkImageDistanceTransform.h
new file mode 100644
index 0000000000000000000000000000000000000000..1064c96395a282e168d56559ecb0d00a050a6704
--- /dev/null
+++ b/Source/Filtering/imstkImageDistanceTransform.h
@@ -0,0 +1,57 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class ImageData;
+
+///
+/// \class ImageDistanceTransform
+///
+/// \brief This filter generates a signed or unsigned distance transform from a binary mask
+///
+class ImageDistanceTransform : public GeometryAlgorithm
+{
+public:
+    ImageDistanceTransform();
+    virtual ~ImageDistanceTransform() override = default;
+
+public:
+    std::shared_ptr<ImageData> getOutputImage() const;
+
+    ///
+    /// \brief Required input, port 0
+    ///
+    void setInputImage(std::shared_ptr<ImageData> refImage);
+
+    imstkGetMacro(UseUnsigned, bool);
+    imstkSetMacro(UseUnsigned, bool);
+
+protected:
+    void requestUpdate() override;
+
+private:
+    bool m_UseUnsigned = false;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkImageGradient.cpp b/Source/Filtering/imstkImageGradient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9738f77fe22512c189364be79e63e55d8dc32e2
--- /dev/null
+++ b/Source/Filtering/imstkImageGradient.cpp
@@ -0,0 +1,77 @@
+/*=========================================================================
+
+   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 "imstkImageGradient.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkImageData.h"
+#include "imstkLogger.h"
+
+#include <vtkImageData.h>
+#include <vtkImageGradient.h>
+#include <vtkImageGradientMagnitude.h>
+
+namespace imstk
+{
+ImageGradient::ImageGradient()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<PointSet>());
+}
+
+void
+ImageGradient::setInputImage(std::shared_ptr<ImageData> inputImage)
+{
+    setInput(inputImage, 0);
+}
+
+void
+ImageGradient::requestUpdate()
+{
+    std::shared_ptr<ImageData> inputImage = std::dynamic_pointer_cast<ImageData>(getInput(0));
+    if (inputImage == nullptr)
+    {
+        LOG(WARNING) << "No input to compute gradients";
+        return;
+    }
+    if (inputImage->getNumComponents() != 1)
+    {
+        LOG(WARNING) << "Can only compute gradient on single channel image";
+        return;
+    }
+    vtkSmartPointer<vtkImageData> inputImageVtk = GeometryUtils::coupleVtkImageData(inputImage);
+    if (m_ComputeMagnitude)
+    {
+        vtkNew<vtkImageGradientMagnitude> gradientMagnitude;
+        gradientMagnitude->SetInputData(inputImageVtk);
+        gradientMagnitude->Update();
+        setOutput(GeometryUtils::copyToImageData(gradientMagnitude->GetOutput()));
+    }
+    else
+    {
+        vtkNew<vtkImageGradient> gradients;
+        gradients->SetInputData(inputImageVtk);
+        gradients->SetHandleBoundaries(true);
+        gradients->Update();
+        setOutput(GeometryUtils::copyToImageData(gradients->GetOutput()));
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkImageGradient.h b/Source/Filtering/imstkImageGradient.h
new file mode 100644
index 0000000000000000000000000000000000000000..61a44de2d4152f004ca19a4031d5a7b594bb571f
--- /dev/null
+++ b/Source/Filtering/imstkImageGradient.h
@@ -0,0 +1,58 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class ImageData;
+
+///
+/// \class ImageGradient
+///
+/// \brief This filter computes the gradient or magnitude using sobels kernel over an image
+///
+class ImageGradient : public GeometryAlgorithm
+{
+public:
+    ImageGradient();
+    virtual ~ImageGradient() override = default;
+
+public:
+    ///
+    /// \brief Required input, port 0
+    ///
+    void setInputImage(std::shared_ptr<ImageData> inputImage);
+
+    ///
+    /// \brief If on, a single channel magnitude image is output, if off, a 3 component gradient is produced
+    ///
+    imstkSetMacro(ComputeMagnitude, bool);
+    imstkGetMacro(ComputeMagnitude, bool);
+
+protected:
+    void requestUpdate() override;
+
+private:
+    bool m_ComputeMagnitude;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkImageResample.cpp b/Source/Filtering/imstkImageResample.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1f6261c431574397f2cd3a5ba432f555a93841b1
--- /dev/null
+++ b/Source/Filtering/imstkImageResample.cpp
@@ -0,0 +1,71 @@
+/*=========================================================================
+
+   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 "imstkImageResample.h"
+#include "imstkDataArray.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkImageData.h"
+#include "imstkLogger.h"
+#include "imstkParallelFor.h"
+#include <vtkImageData.h>
+#include <vtkImageResample.h>
+#include <vtkSmartPointer.h>
+
+namespace imstk
+{
+ImageResample::ImageResample()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<ImageData>());
+}
+
+std::shared_ptr<ImageData>
+ImageResample::getOutputImage() const
+{
+    return std::dynamic_pointer_cast<ImageData>(getOutput(0));
+}
+
+void
+ImageResample::setInputImage(std::shared_ptr<ImageData> inputData)
+{
+    setInput(inputData, 0);
+}
+
+void
+ImageResample::requestUpdate()
+{
+    std::shared_ptr<ImageData> inputImage = std::dynamic_pointer_cast<ImageData>(getInput(0));
+    if (inputImage == nullptr)
+    {
+        LOG(WARNING) << "No inputImage to resample";
+        return;
+    }
+
+    vtkNew<vtkImageResample> resample;
+    resample->SetInputData(GeometryUtils::copyToVtkImageData(inputImage));
+    resample->SetInterpolationModeToLinear();
+    resample->SetOutputExtent(0, m_Dimensions[0] - 1, 0, m_Dimensions[1] - 1, 0, m_Dimensions[2] - 1);
+    resample->Update();
+
+    setOutput(GeometryUtils::copyToImageData(resample->GetOutput()));
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkImageResample.h b/Source/Filtering/imstkImageResample.h
new file mode 100644
index 0000000000000000000000000000000000000000..725f3eca26052648ed7e7d9ec4c58b9fe268bde2
--- /dev/null
+++ b/Source/Filtering/imstkImageResample.h
@@ -0,0 +1,57 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+#include "imstkMath.h"
+
+namespace imstk
+{
+class ImageData;
+
+///
+/// \class ImageResample
+///
+/// \brief Trilinearly Resamples a 3d image to different dimensions
+///
+class ImageResample : public GeometryAlgorithm
+{
+public:
+    ImageResample();
+
+    virtual ~ImageResample() override = default;
+
+public:
+    std::shared_ptr<ImageData> getOutputImage() const;
+
+    void setInputImage(std::shared_ptr<ImageData> inputData);
+
+    imstkGetMacro(Dimensions, const Vec3i&);
+
+    imstkSetMacro(Dimensions, const Vec3i&);
+
+protected:
+    void requestUpdate() override;
+
+private:
+    Vec3i m_Dimensions;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkImplicitGeometryToImageData.cpp b/Source/Filtering/imstkImplicitGeometryToImageData.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b1f43c4828ca9dfb68def9849ee8edcc41c5819e
--- /dev/null
+++ b/Source/Filtering/imstkImplicitGeometryToImageData.cpp
@@ -0,0 +1,91 @@
+/*=========================================================================
+
+   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 "imstkImplicitGeometryToImageData.h"
+#include "imstkImageData.h"
+#include "imstkLogger.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkImplicitGeometry.h"
+#include "imstkDataArray.h"
+
+namespace imstk
+{
+ImplicitGeometryToImageData::ImplicitGeometryToImageData()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<ImageData>());
+}
+
+std::shared_ptr<ImageData>
+ImplicitGeometryToImageData::getOutputImage() const
+{
+    return std::dynamic_pointer_cast<ImageData>(getOutput(0));
+}
+
+void
+ImplicitGeometryToImageData::setInputGeometry(std::shared_ptr<ImplicitGeometry> inputGeometry)
+{
+    setInput(inputGeometry, 0);
+}
+
+void
+ImplicitGeometryToImageData::requestUpdate()
+{
+    std::shared_ptr<ImplicitGeometry> inputGeometry = std::dynamic_pointer_cast<ImplicitGeometry>(getInput(0));
+    if (inputGeometry == nullptr)
+    {
+        LOG(WARNING) << "No inputGeometry to rasterize";
+        return;
+    }
+
+    if (m_Dimensions[0] == 0 || m_Dimensions[1] == 0 || m_Dimensions[2] == 0)
+    {
+        LOG(WARNING) << "Dimensions must be non-zero";
+        return;
+    }
+
+    const Vec3d size    = Vec3d(m_Bounds[1] - m_Bounds[0], m_Bounds[3] - m_Bounds[2], m_Bounds[5] - m_Bounds[4]);
+    const Vec3d spacing = size.cwiseQuotient(m_Dimensions.cast<double>());
+    const Vec3d origin  = Vec3d(m_Bounds[0], m_Bounds[2], m_Bounds[4]);
+    const Vec3d shift   = origin + spacing * 0.5;
+
+    std::shared_ptr<ImageData> outputImage = std::make_shared<ImageData>();
+    outputImage->allocate(IMSTK_DOUBLE, 1, m_Dimensions, spacing, origin);
+    DataArray<double>& scalars = *std::dynamic_pointer_cast<DataArray<double>>(outputImage->getScalars());
+    double*            imgPtr  = scalars.getPointer();
+
+    int i = 0;
+    for (int z = 0; z < m_Dimensions[2]; z++)
+    {
+        for (int y = 0; y < m_Dimensions[1]; y++)
+        {
+            for (int x = 0; x < m_Dimensions[0]; x++, i++)
+            {
+                const Vec3d pos = Vec3d(x, y, z).cwiseProduct(spacing) + shift;
+                imgPtr[i] = inputGeometry->getFunctionValue(pos);
+            }
+        }
+    }
+
+    setOutput(outputImage);
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkImplicitGeometryToImageData.h b/Source/Filtering/imstkImplicitGeometryToImageData.h
new file mode 100644
index 0000000000000000000000000000000000000000..77c399849b72d7447bc891991646439f3f3e71dc
--- /dev/null
+++ b/Source/Filtering/imstkImplicitGeometryToImageData.h
@@ -0,0 +1,64 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+#include "imstkMath.h"
+
+namespace imstk
+{
+class ImageData;
+class ImplicitGeometry;
+
+///
+/// \class ImplicitGeometryToImageData
+///
+/// \brief This filter rasterizes an implicit function to image of
+/// specified dimensions and bounds
+///
+class ImplicitGeometryToImageData : public GeometryAlgorithm
+{
+public:
+    ImplicitGeometryToImageData();
+    virtual ~ImplicitGeometryToImageData() override = default;
+
+public:
+    std::shared_ptr<ImageData> getOutputImage() const;
+
+    ///
+    /// \brief Required input, port 0
+    ///
+    void setInputGeometry(std::shared_ptr<ImplicitGeometry> inputGeometry);
+
+    imstkGetMacro(Dimensions, const Vec3i&);
+    imstkGetMacro(Bounds, const Vec6d&);
+
+    imstkSetMacro(Dimensions, const Vec3i&);
+    imstkSetMacro(Bounds, const Vec6d&);
+
+protected:
+    void requestUpdate() override;
+
+private:
+    Vec3i m_Dimensions;
+    Vec6d m_Bounds;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkQuadricDecimate.cpp b/Source/Filtering/imstkQuadricDecimate.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..38facf819d512705607aa0cc5c81b51260a419ca
--- /dev/null
+++ b/Source/Filtering/imstkQuadricDecimate.cpp
@@ -0,0 +1,64 @@
+/*=========================================================================
+
+   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 "imstkQuadricDecimate.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkLogger.h"
+#include "imstkGeometryUtilities.h"
+
+#include <vtkQuadricDecimation.h>
+
+namespace imstk
+{
+QuadricDecimate::QuadricDecimate() :
+    m_VolumePreserving(true), m_TargetReduction(0.6)
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<SurfaceMesh>());
+}
+
+void
+QuadricDecimate::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh)
+{
+    setInput(inputMesh, 0);
+}
+
+void
+QuadricDecimate::requestUpdate()
+{
+    std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
+    if (inputMesh == nullptr)
+    {
+        LOG(WARNING) << "No inputMesh to clean";
+        return;
+    }
+    vtkSmartPointer<vtkPolyData> inputMeshVtk = GeometryUtils::copyToVtkPolyData(std::dynamic_pointer_cast<SurfaceMesh>(inputMesh));
+
+    vtkNew<vtkQuadricDecimation> filter;
+    filter->SetInputData(inputMeshVtk);
+    filter->SetVolumePreservation(m_VolumePreserving);
+    filter->SetTargetReduction(m_TargetReduction);
+    filter->Update();
+
+    setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput()));
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkQuadricDecimate.h b/Source/Filtering/imstkQuadricDecimate.h
new file mode 100644
index 0000000000000000000000000000000000000000..6bb4d3ff28ee6dbb942178003c2231405d808479
--- /dev/null
+++ b/Source/Filtering/imstkQuadricDecimate.h
@@ -0,0 +1,66 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class SurfaceMesh;
+
+///
+/// \class CleanMesh
+///
+/// \brief This filter reduces a SurfaceMesh
+///
+class QuadricDecimate : public GeometryAlgorithm
+{
+public:
+    QuadricDecimate();
+    virtual ~QuadricDecimate() override = default;
+
+public:
+    ///
+    /// \brief Required input, port 0
+    ///
+    void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh);
+
+    imstkGetMacro(VolumePreserving, bool);
+    imstkGetMacro(TargetReduction, double);
+
+    ///
+    /// \brief Set whether to preserve volume or not, default on
+    ///
+    imstkSetMacro(VolumePreserving, bool);
+
+    ///
+    /// \brief Set the target reduction ratio
+    ///
+    imstkSetMacro(TargetReduction, double);
+
+protected:
+    void requestUpdate() override;
+
+private:
+    bool   m_VolumePreserving;
+    double m_TargetReduction;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSelectEnclosedPoints.cpp b/Source/Filtering/imstkSelectEnclosedPoints.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c90178cd8cba24da3aa0a3f5a0505645769d6920
--- /dev/null
+++ b/Source/Filtering/imstkSelectEnclosedPoints.cpp
@@ -0,0 +1,109 @@
+/*=========================================================================
+
+   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 "imstkSelectEnclosedPoints.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkLogger.h"
+#include "imstkSurfaceMesh.h"
+
+#include <vtkPolyData.h>
+#include <vtkSelectEnclosedPoints.h>
+
+namespace imstk
+{
+SelectEnclosedPoints::SelectEnclosedPoints()
+{
+    setNumberOfInputPorts(2);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<PointSet>());
+}
+
+void
+SelectEnclosedPoints::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh)
+{
+    setInput(inputMesh, 0);
+}
+
+void
+SelectEnclosedPoints::setInputPoints(std::shared_ptr<PointSet> inputPts)
+{
+    setInput(inputPts, 1);
+}
+
+std::shared_ptr<PointSet>
+SelectEnclosedPoints::getOutputPoints() const
+{
+    return std::static_pointer_cast<PointSet>(getOutput(0));
+}
+
+void
+SelectEnclosedPoints::requestUpdate()
+{
+    std::shared_ptr<SurfaceMesh> inputSurfaceMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
+    std::shared_ptr<PointSet>    inputPointSet    = std::dynamic_pointer_cast<PointSet>(getInput(1));
+    m_IsInsideMask = nullptr;
+
+    if (inputSurfaceMesh == nullptr || inputPointSet == nullptr)
+    {
+        LOG(WARNING) << "Missing inputs";
+        return;
+    }
+
+    vtkNew<vtkSelectEnclosedPoints> filter;
+    filter->SetInputData(GeometryUtils::copyToVtkPointSet(inputPointSet));
+    filter->SetSurfaceData(GeometryUtils::copyToVtkPolyData(inputSurfaceMesh));
+    filter->SetTolerance(m_Tolerance);
+    filter->SetInsideOut(m_InsideOut);
+    filter->Update();
+
+    vtkSmartPointer<vtkPointSet> vtkResults = vtkPointSet::SafeDownCast(filter->GetOutput());
+
+    if (m_UsePruning)
+    {
+        StdVectorOfVec3d points;
+        points.reserve(vtkResults->GetNumberOfPoints());
+        for (vtkIdType i = 0; i < vtkResults->GetNumberOfPoints(); i++)
+        {
+            if (filter->IsInside(i))
+            {
+                double pt[3];
+                vtkResults->GetPoint(i, pt);
+                points.push_back(Vec3d(pt[0], pt[1], pt[2]));
+            }
+        }
+        points.shrink_to_fit();
+
+        std::shared_ptr<PointSet> results = std::make_shared<PointSet>();
+        results->setInitialVertexPositions(points);
+        results->setVertexPositions(points);
+        setOutput(results, 0);
+    }
+    else
+    {
+        m_IsInsideMask = std::make_shared<DataArray<unsigned char>>(vtkResults->GetNumberOfPoints());
+        DataArray<unsigned char>& mask = *m_IsInsideMask;
+        for (vtkIdType i = 0; i < vtkResults->GetNumberOfPoints(); i++)
+        {
+            mask[i] = filter->IsInside(i);
+        }
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSelectEnclosedPoints.h b/Source/Filtering/imstkSelectEnclosedPoints.h
new file mode 100644
index 0000000000000000000000000000000000000000..f92beb590b88efe902610a20f19f5f07ef3a3198
--- /dev/null
+++ b/Source/Filtering/imstkSelectEnclosedPoints.h
@@ -0,0 +1,66 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+#include "imstkDataArray.h"
+
+namespace imstk
+{
+class PointSet;
+class SurfaceMesh;
+
+///
+/// \class CleanMesh
+///
+/// \brief This filter will select the points within a surfacemesh. It can
+/// either prune or return the mask
+///
+class SelectEnclosedPoints : public GeometryAlgorithm
+{
+public:
+    SelectEnclosedPoints();
+    virtual ~SelectEnclosedPoints() override = default;
+
+public:
+    void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh);
+    void setInputPoints(std::shared_ptr<PointSet> inputPoints);
+    std::shared_ptr<PointSet> getOutputPoints() const;
+
+    imstkGetMacro(UsePruning, bool);
+    imstkGetMacro(Tolerance, double);
+    imstkGetMacro(InsideOut, bool);
+    imstkGetMacro(IsInsideMask, std::shared_ptr<DataArray<unsigned char>>);
+
+    imstkSetMacro(UsePruning, bool);
+    imstkSetMacro(Tolerance, double);
+    imstkSetMacro(InsideOut, bool);
+
+protected:
+    void requestUpdate() override;
+
+private:
+    bool   m_UsePruning = true;
+    double m_Tolerance  = 0.0;
+    bool   m_InsideOut  = false;
+    std::shared_ptr<DataArray<unsigned char>> m_IsInsideMask = nullptr;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp b/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..373eeca50ea254941d9054ffbd5f120ac49d8e02
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp
@@ -0,0 +1,250 @@
+/*=========================================================================
+
+   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 "imstkSurfaceMeshDistanceTransform.h"
+#include "imstkDataArray.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkImageData.h"
+#include "imstkLogger.h"
+#include "imstkLooseOctree.h"
+#include "imstkParallelUtils.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTimer.h"
+#include "imstkSurfaceMeshImageMask.h"
+#include <stack>
+#include <vtkDistancePolyDataFilter.h>
+#include <vtkImageData.h>
+#include <vtkImplicitPolyDataDistance.h>
+#include <vtkOctreePointLocator.h>
+#include <vtkPointData.h>
+#include <vtkPolyData.h>
+#include <vtkSelectEnclosedPoints.h>
+
+namespace imstk
+{
+//static bool neighborNotEqual(const Vec3i& pt, const Vec3i& dim, const float val, const float* imgPtr)
+//{
+//    const Vec3i ptc = pt.cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1));
+//    const Vec3i minima = (pt - Vec3i(1, 1, 1)).cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1));
+//    const Vec3i maxima = (pt + Vec3i(1, 1, 1)).cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1));
+//
+//    const size_t xIndex1 = ImageData::getScalarIndex(minima[0], ptc[1], ptc[2], dim, 1);
+//    const size_t xIndex2 = ImageData::getScalarIndex(maxima[0], ptc[1], ptc[2], dim, 1);
+//    const size_t yIndex1 = ImageData::getScalarIndex(ptc[0], minima[1], ptc[2], dim, 1);
+//    const size_t yIndex2 = ImageData::getScalarIndex(ptc[0], maxima[1], ptc[2], dim, 1);
+//    const size_t zIndex1 = ImageData::getScalarIndex(ptc[0], ptc[1], minima[2], dim, 1);
+//    const size_t zIndex2 = ImageData::getScalarIndex(ptc[0], ptc[1], maxima[2], dim, 1);
+//
+//    if (imgPtr[xIndex1] != val)
+//        return true;
+//    if (imgPtr[xIndex2] != val)
+//        return true;
+//    if (imgPtr[yIndex1] != val)
+//        return true;
+//    if (imgPtr[yIndex2] != val)
+//        return true;
+//    if (imgPtr[zIndex1] != val)
+//        return true;
+//    if (imgPtr[zIndex2] == val)
+//        return true;
+//    return false;
+//}
+
+//// Narrow band is WIP, it works but is slow
+//static void
+//computeNarrowBandedDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<SurfaceMesh> surfMesh, double bandwidth)
+//{
+//    // Rasterize a mask from the polygon
+//    std::shared_ptr<SurfaceMeshImageMask> imageMask = std::make_shared<SurfaceMeshImageMask>();
+//    imageMask->setInputMesh(surfMesh);
+//    imageMask->setReferenceImage(imageData);
+//    imageMask->update();
+//
+//    DataArray<float>& inputScalars = *std::dynamic_pointer_cast<DataArray<float>>(imageMask->getOutputImage()->getScalars());
+//    float* inputImgPtr = inputScalars.getPointer();
+//    DataArray<float>& outputScalars = *std::dynamic_pointer_cast<DataArray<float>>(imageData->getScalars());
+//    float* outputImgPtr = outputScalars.getPointer();
+//
+//    vtkSmartPointer<vtkPolyData> inputPolyData = GeometryUtils::copyToVtkPolyData(surfMesh);
+//    vtkSmartPointer<vtkImplicitPolyDataDistance> polyDataDist = vtkSmartPointer<vtkImplicitPolyDataDistance>::New();
+//    polyDataDist->SetInput(inputPolyData);
+//    std::fill_n(outputImgPtr, outputScalars.size(), VTK_FLOAT_MIN);
+//
+//    // Iterate the image testing for boundary pixels (ie any 0 adjacent to a 1)
+//    const Vec3i& dim = imageData->getDimensions();
+//    const Vec3d shift = imageData->getOrigin() + imageData->getSpacing() * 0.5;
+//    const Vec3d& spacing = imageData->getSpacing();
+//    int i = 0;
+//    for (int z = 0; z < dim[2]; z++)
+//    {
+//        for (int y = 0; y < dim[1]; y++)
+//        {
+//            for (int x = 0; x < dim[0]; x++, i++)
+//            {
+//                const float val = inputImgPtr[i];
+//                const Vec3i pt = Vec3i(x, y, z);
+//                if (neighborNotEqual(pt, dim, val, inputImgPtr))
+//                {
+//                    const Vec3d pos = pt.cast<double>().cwiseProduct(spacing) + shift;
+//                    const float dist = polyDataDist->FunctionValue(pos.data());
+//                    //printf("%f\n", dist);
+//                    outputImgPtr[i] = dist;
+//                }
+//                else if (val == 0.0f)
+//                {
+//                    outputImgPtr[i] = VTK_FLOAT_MIN;
+//                }
+//            }
+//        }
+//    }
+//}
+
+static void
+computeFullDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<SurfaceMesh> surfMesh)
+{
+    // Get the optimal number of threads
+    const size_t numThreads = ParallelUtils::ThreadManager::getThreadPoolSize();
+
+    const Vec3i& dim     = imageData->getDimensions();
+    const Vec3d  spacing = imageData->getSpacing();
+    const Vec3d  shift   = imageData->getOrigin() + spacing * 0.5;
+
+    DataArray<double>& scalars = *static_cast<DataArray<double>*>(imageData->getScalars().get());
+
+    // Split the work up along z using thread count to avoid making too many octtrees (may not be most optimal)
+    ParallelUtils::parallelFor(numThreads, [&](const size_t& i)
+        {
+            // Separate polygons used to avoid race conditions
+            vtkSmartPointer<vtkPolyData> inputPolyData = GeometryUtils::copyToVtkPolyData(surfMesh);
+            vtkSmartPointer<vtkImplicitPolyDataDistance> polyDataDist = vtkSmartPointer<vtkImplicitPolyDataDistance>::New();
+            polyDataDist->SetInput(inputPolyData);
+            for (int z = static_cast<int>(i); z < dim[2]; z += static_cast<int>(numThreads))
+            {
+                int j = z * dim[0] * dim[1];
+                for (int y = 0; y < dim[1]; y++)
+                {
+                    for (int x = 0; x < dim[0]; x++, j++)
+                    {
+                        double pos[3] = { x* spacing[0] + shift[0], y * spacing[1] + shift[1], z * spacing[2] + shift[2] };
+                        scalars[j]    = polyDataDist->FunctionValue(pos);
+                    }
+                }
+            }
+        });
+
+    // Sequential implementation
+    /*vtkSmartPointer<vtkPolyData> inputPolyData = GeometryUtils::copyToVtkPolyData(surfMesh);
+    vtkSmartPointer<vtkImplicitPolyDataDistance> polyDataDist = vtkSmartPointer<vtkImplicitPolyDataDistance>::New();
+    polyDataDist->SetInput(inputPolyData);
+    int j = 0;
+    for (int z = 0; z < dim[2]; z++)
+    {
+        for (int y = 0; y < dim[1]; y++)
+        {
+            for (int x = 0; x < dim[0]; x++, j++)
+            {
+                double pos[3] = { x * spacing[0] + shift[0], y * spacing[1] + shift[1], z * spacing[2] + shift[2] };
+                scalars[j] = polyDataDist->FunctionValue(pos);
+            }
+        }
+    }*/
+}
+
+SurfaceMeshDistanceTransform::SurfaceMeshDistanceTransform()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<ImageData>(), 0);
+}
+
+void
+SurfaceMeshDistanceTransform::setInputMesh(std::shared_ptr<SurfaceMesh> mesh)
+{
+    setInput(mesh, 0);
+}
+
+std::shared_ptr<ImageData>
+SurfaceMeshDistanceTransform::getOutputImage()
+{
+    return std::dynamic_pointer_cast<ImageData>(getOutput());
+}
+
+void
+SurfaceMeshDistanceTransform::requestUpdate()
+{
+    std::shared_ptr<SurfaceMesh> inputSurfaceMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
+    std::shared_ptr<ImageData>   outputImageData  = std::dynamic_pointer_cast<ImageData>(getOutput(0));
+
+    if (inputSurfaceMesh == nullptr)
+    {
+        LOG(WARNING) << "Missing input surface mesh";
+        return;
+    }
+
+    if (m_Dimensions[0] == 0 || m_Dimensions[1] == 0 || m_Dimensions[2] == 0)
+    {
+        LOG(WARNING) << "Dimensions not set";
+        return;
+    }
+
+    // Allocate an image for it
+    Vec3d min;
+    Vec3d max;
+    inputSurfaceMesh->computeBoundingBox(min, max);
+    double bounds[6];
+    if (m_UseBounds)
+    {
+        bounds[0] = m_Bounds[0];
+        bounds[1] = m_Bounds[1];
+        bounds[2] = m_Bounds[2];
+        bounds[3] = m_Bounds[3];
+        bounds[4] = m_Bounds[4];
+        bounds[5] = m_Bounds[5];
+    }
+    else
+    {
+        bounds[0] = min[0];
+        bounds[1] = max[0];
+        bounds[2] = min[1];
+        bounds[3] = max[1];
+        bounds[4] = min[2];
+        bounds[5] = max[2];
+    }
+    Vec3d size    = Vec3d(bounds[1] - bounds[0], bounds[3] - bounds[2], bounds[5] - bounds[4]);
+    Vec3d spacing = size.cwiseQuotient(m_Dimensions.cast<double>());
+    Vec3d origin  = Vec3d(bounds[0], bounds[2], bounds[4]);
+    outputImageData->allocate(IMSTK_DOUBLE, 1, m_Dimensions, spacing, origin);
+
+    /* StopWatch timer;
+     timer.start();*/
+
+    /*if (NarrowBanded)
+    {
+        computeNarrowBandedDT(outputImageData, inputSurfaceMesh, NarrowBandWidth);
+    }
+    else*/
+    {
+        computeFullDT(outputImageData, inputSurfaceMesh);
+    }
+
+    //printf("time: %f\n", timer.getTimeElapsed());
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshDistanceTransform.h b/Source/Filtering/imstkSurfaceMeshDistanceTransform.h
new file mode 100644
index 0000000000000000000000000000000000000000..726110c019b4b012d1767ecadc5fed1185bd04ef
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshDistanceTransform.h
@@ -0,0 +1,92 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+#include "imstkMath.h"
+
+namespace imstk
+{
+class ImageData;
+class SurfaceMesh;
+
+///
+/// \class SurfaceMeshDistanceTransform
+///
+/// \brief This filter computes brute force signed distance field by computing the nearest
+/// point in one dataset to the other
+///
+class SurfaceMeshDistanceTransform : public GeometryAlgorithm
+{
+public:
+    SurfaceMeshDistanceTransform();
+    virtual ~SurfaceMeshDistanceTransform() override = default;
+
+public:
+    ///
+    /// \brief Required input, port 0
+    ///
+    void setInputMesh(std::shared_ptr<SurfaceMesh> surfMesh);
+
+    std::shared_ptr<ImageData> getOutputImage();
+
+    imstkGetMacro(Dimensions, const Vec3i&);
+    imstkGetMacro(Bounds, const Vec6d&);
+    imstkGetMacro(UseBounds, bool);
+    //imstkGetMacro(NarrowBanded, bool);
+    //imstkGetMacro(NarrowBandWidth, double);
+
+    ///
+    /// \brief Dimensions of distance transform to fill
+    ///
+    imstkSetMacro(Dimensions, const Vec3i&);
+
+    ///
+    /// \brief Optionally one may specify bounds, if not specified
+    /// bounds of the input SurfaceMesh is used
+    ///
+    imstkSetMacro(Bounds, const Vec6d&);
+
+    imstkSetMacro(UseBounds, bool);
+
+    ///
+    /// \brief If on, will compute only a narrow banded transform
+    ///
+    //imstkSetMacro(NarrowBanded, bool);
+
+    ///
+    /// \brief Width of the band
+    ///
+    //imstkSetMacro(NarrowBandWidth, double);
+
+    void setDimensions(int dimX, int dimY, int dimZ) { setDimensions(Vec3i(dimX, dimY, dimZ)); }
+
+protected:
+    void requestUpdate() override;
+
+private:
+    Vec3i m_Dimensions = Vec3i(0, 0, 0);
+    Vec6d m_Bounds;
+    bool  m_UseBounds = false;
+    //bool   m_NarrowBanded = false;
+    //double m_NarrowBandWidth = 1.0;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp b/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a2878882e0fc827ee0549a05a4385dd69d255852
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp
@@ -0,0 +1,69 @@
+/*=========================================================================
+
+   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 "imstkSurfaceMeshFlyingEdges.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkImageData.h"
+#include "imstkLogger.h"
+#include "imstkSurfaceMesh.h"
+
+#include <vtkFlyingEdges3D.h>
+#include <vtkImageData.h>
+
+namespace imstk
+{
+SurfaceMeshFlyingEdges::SurfaceMeshFlyingEdges()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<SurfaceMesh>());
+}
+
+void
+SurfaceMeshFlyingEdges::setInputImage(std::shared_ptr<ImageData> inputImage)
+{
+    setInput(inputImage, 0);
+}
+
+std::shared_ptr<SurfaceMesh>
+SurfaceMeshFlyingEdges::getOutputMesh() const
+{
+    return std::dynamic_pointer_cast<SurfaceMesh>(getOutput(0));
+}
+
+void
+SurfaceMeshFlyingEdges::requestUpdate()
+{
+    std::shared_ptr<ImageData> inputImage = std::dynamic_pointer_cast<ImageData>(getInput(0));
+    if (inputImage == nullptr)
+    {
+        LOG(WARNING) << "No inputImage to extract isosurface from";
+        return;
+    }
+
+    vtkNew<vtkFlyingEdges3D> filter;
+    filter->SetInputData(GeometryUtils::coupleVtkImageData(inputImage));
+    filter->SetValue(0, m_IsoValue);
+    filter->Update();
+
+    setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput()));
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshFlyingEdges.h b/Source/Filtering/imstkSurfaceMeshFlyingEdges.h
new file mode 100644
index 0000000000000000000000000000000000000000..df2c6475a473aa6dfd10e18e76f792a2d45e14c0
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshFlyingEdges.h
@@ -0,0 +1,62 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class ImageData;
+class SurfaceMesh;
+
+///
+/// \class SurfaceMeshFlyingEdges
+///
+/// \brief This filter extracts a single isocontour from an imstkImageData
+///
+class SurfaceMeshFlyingEdges : public GeometryAlgorithm
+{
+public:
+    SurfaceMeshFlyingEdges();
+    virtual ~SurfaceMeshFlyingEdges() override = default;
+
+public:
+    ///
+    /// \brief Required input, port 0
+    ///
+    void setInputImage(std::shared_ptr<ImageData> inputImage);
+
+    std::shared_ptr<SurfaceMesh> getOutputMesh() const;
+
+    imstkGetMacro(IsoValue, double);
+
+    ///
+    /// \brief Get the value at which the surface should be produced
+    ///
+    imstkSetMacro(IsoValue, double);
+
+protected:
+    void requestUpdate() override;
+
+private:
+    double m_IsoValue = 0.0;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshImageMask.cpp b/Source/Filtering/imstkSurfaceMeshImageMask.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ea1dc12b74cb0abe4d8c100dbbc25cc8ecb65a0
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshImageMask.cpp
@@ -0,0 +1,148 @@
+/*=========================================================================
+
+   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 "imstkSurfaceMeshImageMask.h"
+#include "imstkCleanMesh.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkImageData.h"
+#include "imstkLogger.h"
+#include "imstkSurfaceMesh.h"
+
+#include <vtkImageData.h>
+#include <vtkImageStencil.h>
+#include <vtkPolyData.h>
+#include <vtkPolyDataToImageStencil.h>
+
+namespace imstk
+{
+SurfaceMeshImageMask::SurfaceMeshImageMask()
+{
+    setNumberOfInputPorts(2);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<ImageData>(), 0);
+}
+
+void
+SurfaceMeshImageMask::setReferenceImage(std::shared_ptr<ImageData> refImage)
+{
+    setInput(refImage, 1);
+}
+
+void
+SurfaceMeshImageMask::setInputMesh(std::shared_ptr<SurfaceMesh> mesh)
+{
+    setInput(mesh, 0);
+}
+
+std::shared_ptr<ImageData>
+SurfaceMeshImageMask::getOutputImage() const
+{
+    return std::static_pointer_cast<ImageData>(getOutput(0));
+}
+
+void
+SurfaceMeshImageMask::requestUpdate()
+{
+    std::shared_ptr<SurfaceMesh> surfMeshInput = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
+    std::shared_ptr<ImageData>   refImageInput = std::dynamic_pointer_cast<ImageData>(getInput(1));
+
+    if (surfMeshInput == nullptr)
+    {
+        LOG(WARNING) << "Missing input surface mesh";
+        return;
+    }
+
+    Vec3d spacing;
+    int   extent[6];
+    Vec3d origin;
+    if (refImageInput != nullptr)
+    {
+        spacing = refImageInput->getSpacing();
+
+        origin = refImageInput->getOrigin();
+
+        const Vec3i& dim = refImageInput->getDimensions();
+        extent[0] = 0;
+        extent[1] = dim[0];
+        extent[2] = 0;
+        extent[3] = dim[1];
+        extent[4] = 0;
+        extent[5] = dim[2];
+    }
+    else
+    {
+        if (m_Dimensions[0] == -1 || m_Dimensions[1] == -1 || m_Dimensions[2] == -1)
+        {
+            LOG(WARNING) << "No reference image or desired image dimensions.";
+            return;
+        }
+        Vec3d min;
+        Vec3d max;
+        surfMeshInput->computeBoundingBox(min, max);
+
+        Vec3d size = max - min;
+
+        // Compute spacing required for given dimension
+        spacing = size.cwiseQuotient(m_Dimensions.cast<double>());
+
+        // Increase bounds by px length
+        min -= spacing * m_BorderExtent;
+        max += spacing * m_BorderExtent;
+
+        size = max - min;
+
+        extent[0] = 0;
+        extent[1] = (m_Dimensions[0] + m_BorderExtent) - 1;
+        extent[2] = 0;
+        extent[3] = (m_Dimensions[1] + m_BorderExtent) - 1;
+        extent[4] = 0;
+        extent[5] = (m_Dimensions[2] + m_BorderExtent) - 1;
+
+        origin = min - m_BorderExtent * spacing;
+    }
+
+    // Allocate a new white image
+    vtkNew<vtkImageData> baseImage;
+    baseImage->SetSpacing(spacing.data());
+    baseImage->SetExtent(extent);
+    baseImage->SetOrigin(origin.data());
+    baseImage->AllocateScalars(VTK_FLOAT, 1);
+    int* dim = baseImage->GetDimensions();
+    std::fill_n(static_cast<float*>(baseImage->GetScalarPointer()), dim[0] * dim[1] * dim[2], 1.0f);
+
+    // Creates a new image mask from this polygon using a reference mask
+    vtkNew<vtkPolyDataToImageStencil> poly2Stencil;
+    poly2Stencil->SetInputData(GeometryUtils::copyToVtkPolyData(surfMeshInput));
+    poly2Stencil->SetOutputOrigin(origin.data());
+    poly2Stencil->SetOutputSpacing(spacing.data());
+    poly2Stencil->SetOutputWholeExtent(extent);
+    poly2Stencil->Update();
+    vtkNew<vtkImageStencil> imgStencil;
+    imgStencil->SetInputData(baseImage);
+    imgStencil->SetStencilData(poly2Stencil->GetOutput());
+    imgStencil->ReverseStencilOff();
+    imgStencil->SetBackgroundValue(0.0);
+    imgStencil->Update();
+
+    // Set the output
+    setOutput(GeometryUtils::copyToImageData(imgStencil->GetOutput()));
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshImageMask.h b/Source/Filtering/imstkSurfaceMeshImageMask.h
new file mode 100644
index 0000000000000000000000000000000000000000..f5f7b6c8398ffeb4559c900384f9b6ca98e96957
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshImageMask.h
@@ -0,0 +1,79 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+#include "imstkMath.h"
+
+namespace imstk
+{
+class ImageData;
+class SurfaceMesh;
+
+///
+/// \class ImagePolyDataMask
+///
+/// \brief This filter generates a binary mask from input surface mesh. Optionally
+/// one may provide a reference image for which to use its spacing, origin, dimensions
+/// It can also work with some geometry that is non-manifold, but results are ambiguous
+///
+class SurfaceMeshImageMask : public GeometryAlgorithm
+{
+public:
+    SurfaceMeshImageMask();
+    virtual ~SurfaceMeshImageMask() override = default;
+
+public:
+    ///
+    /// \brief Optional input, used for information (dimensions, spacing, etc)
+    ///
+    void setReferenceImage(std::shared_ptr<ImageData> refImage);
+    void setInputMesh(std::shared_ptr<SurfaceMesh> mesh);
+    std::shared_ptr<ImageData> getOutputImage() const;
+
+    imstkGetMacro(BorderExtent, int);
+    imstkGetMacro(Dimensions, const Vec3i&);
+
+    ///
+    /// \brief Adds a border around the generated image of pixel amount
+    /// border exists outside of bounds
+    ///
+    imstkSetMacro(BorderExtent, int);
+
+    ///
+    /// \brief The dimensions of the image to generate
+    ///
+    imstkSetMacro(Dimensions, const Vec3i&);
+
+    ///
+    /// \brief The dimensions of the image to generate
+    ///
+    void setDimensions(int dimX, int dimY, int dimZ) { setDimensions(Vec3i(dimX, dimY, dimZ)); }
+
+protected:
+    void requestUpdate() override;
+
+private:
+    Vec3i m_Dimensions    = Vec3i(-1, -1, -1);
+    int   m_BorderExtent  = 1;
+    bool  m_CheckManifold = true;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshSmoothen.cpp b/Source/Filtering/imstkSurfaceMeshSmoothen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8d628bcccb0ffc4b2b8d993d563d0e5bd0352b7f
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshSmoothen.cpp
@@ -0,0 +1,67 @@
+/*=========================================================================
+
+   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 "imstkSurfaceMeshSmoothen.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkLogger.h"
+#include "imstkSurfaceMesh.h"
+
+#include <vtkSmoothPolyDataFilter.h>
+
+namespace imstk
+{
+SurfaceMeshSmoothen::SurfaceMeshSmoothen()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<SurfaceMesh>());
+}
+
+void
+SurfaceMeshSmoothen::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh)
+{
+    setInput(inputMesh, 0);
+}
+
+void
+SurfaceMeshSmoothen::requestUpdate()
+{
+    std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
+    if (inputMesh == nullptr)
+    {
+        LOG(WARNING) << "No inputMesh to smoothen";
+        return;
+    }
+
+    vtkNew<vtkSmoothPolyDataFilter> filter;
+    filter->SetInputData(GeometryUtils::copyToVtkPolyData(inputMesh));
+    filter->SetNumberOfIterations(m_NumberOfIterations);
+    filter->SetRelaxationFactor(m_RelaxationFactor);
+    filter->SetConvergence(m_Convergence);
+    filter->SetFeatureAngle(m_FeatureAngle);
+    filter->SetEdgeAngle(m_EdgeAngle);
+    filter->SetFeatureEdgeSmoothing(m_FeatureEdgeSmoothing);
+    filter->SetBoundarySmoothing(m_BoundarySmoothing);
+    filter->Update();
+
+    setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput()));
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshSmoothen.h b/Source/Filtering/imstkSurfaceMeshSmoothen.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f59bd37b45a2b9e947e9ff059d80fa7cde827ac
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshSmoothen.h
@@ -0,0 +1,75 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class SurfaceMesh;
+
+///
+/// \class SurfaceMeshSmoothen
+///
+/// \brief This filter smoothes the input SurfaceMesh currently only laplacian
+/// smoothing is provided
+///
+class SurfaceMeshSmoothen : public GeometryAlgorithm
+{
+public:
+    SurfaceMeshSmoothen();
+    virtual ~SurfaceMeshSmoothen() override = default;
+
+public:
+    imstkGetMacro(NumberOfIterations, int);
+    imstkGetMacro(RelaxationFactor, double);
+    imstkGetMacro(Convergence, double);
+    imstkGetMacro(FeatureAngle, double);
+    imstkGetMacro(EdgeAngle, double);
+    imstkGetMacro(FeatureEdgeSmoothing, bool);
+    imstkGetMacro(BoundarySmoothing, bool);
+
+    ///
+    /// \brief Required input, port 0
+    ///
+    void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh);
+
+    imstkSetMacro(NumberOfIterations, int);
+    imstkSetMacro(RelaxationFactor, double);
+    imstkSetMacro(Convergence, double);
+    imstkSetMacro(FeatureAngle, double);
+    imstkSetMacro(EdgeAngle, double);
+    imstkSetMacro(FeatureEdgeSmoothing, bool);
+    imstkSetMacro(BoundarySmoothing, bool);
+
+protected:
+    void requestUpdate() override;
+
+private:
+    int    m_NumberOfIterations = 20;
+    double m_RelaxationFactor   = 0.01;
+    double m_Convergence  = 0.0;
+    double m_FeatureAngle = 45.0;
+    double m_EdgeAngle    = 15.0;
+    bool   m_FeatureEdgeSmoothing = false;
+    bool   m_BoundarySmoothing    = true;
+};
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshSubdivide.cpp b/Source/Filtering/imstkSurfaceMeshSubdivide.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e3726b7d1e18bc8fe7a36a7935aabaaafbef48a7
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshSubdivide.cpp
@@ -0,0 +1,83 @@
+/*=========================================================================
+
+   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 "imstkSurfaceMeshSubdivide.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkLogger.h"
+
+#include <vtkButterflySubdivisionFilter.h>
+#include <vtkLinearSubdivisionFilter.h>
+#include <vtkLoopSubdivisionFilter.h>
+
+namespace imstk
+{
+SurfaceMeshSubdivide::SurfaceMeshSubdivide()
+{
+    setNumberOfInputPorts(1);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<SurfaceMesh>());
+}
+
+std::shared_ptr<SurfaceMesh>
+SurfaceMeshSubdivide::getOutputMesh()
+{
+    return std::dynamic_pointer_cast<SurfaceMesh>(getOutput(0));
+}
+
+void
+SurfaceMeshSubdivide::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh)
+{
+    setInput(inputMesh, 0);
+}
+
+void
+SurfaceMeshSubdivide::requestUpdate()
+{
+    std::shared_ptr<SurfaceMesh> inputMesh = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
+
+    if (inputMesh == nullptr)
+    {
+        LOG(WARNING) << "Missing required SurfaceMesh input";
+        return;
+    }
+
+    vtkSmartPointer<vtkSubdivisionFilter> filter = nullptr;
+    if (m_SubdivisionType == Type::BUTTERFLY)
+    {
+        filter = vtkSmartPointer<vtkButterflySubdivisionFilter>::New();
+    }
+    else if (m_SubdivisionType == Type::LOOP)
+    {
+        filter = vtkSmartPointer<vtkLoopSubdivisionFilter>::New();
+    }
+    else
+    {
+        filter = vtkSmartPointer<vtkLinearSubdivisionFilter>::New();
+    }
+
+    filter->SetInputData(GeometryUtils::copyToVtkPolyData(inputMesh));
+    filter->SetNumberOfSubdivisions(m_NumberOfSubdivisions);
+    filter->Update();
+
+    setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput()));
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshSubdivide.h b/Source/Filtering/imstkSurfaceMeshSubdivide.h
new file mode 100644
index 0000000000000000000000000000000000000000..8f4cd6f0fbe252c7658c5ddda0bca1ed0d90175d
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshSubdivide.h
@@ -0,0 +1,67 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class SurfaceMesh;
+
+///
+/// \class SubdivideSurfaceMesh
+///
+/// \brief This filter subidivdes the triangles of a SurfaceMesh into more
+/// smaller triangles
+/// \todo: test with LineMesh
+///
+class SurfaceMeshSubdivide : public GeometryAlgorithm
+{
+public:
+    enum class Type
+    {
+        LINEAR,
+        LOOP,
+        BUTTERFLY
+    };
+
+public:
+    SurfaceMeshSubdivide();
+    virtual ~SurfaceMeshSubdivide() override = default;
+
+public:
+    std::shared_ptr<SurfaceMesh> getOutputMesh();
+
+    void setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh);
+
+    imstkGetMacro(SubdivisionType, Type);
+    imstkGetMacro(NumberOfSubdivisions, int);
+    imstkSetMacro(SubdivisionType, Type);
+    imstkSetMacro(NumberOfSubdivisions, int);
+
+protected:
+    void requestUpdate() override;
+
+private:
+    Type m_SubdivisionType      = Type::LINEAR;
+    int  m_NumberOfSubdivisions = 1;
+};
+}
\ No newline at end of file
diff --git a/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp b/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp
index b0fbb0da50ca990cd1044b886c31ff1db9151b9d..55a61d8c2fac2773dd6d61241af12f624aee7ae1 100644
--- a/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp
+++ b/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp
@@ -20,13 +20,13 @@
 =========================================================================*/
 
 #include "imstkAnalyticalGeometry.h"
-#include "imstkMath.h"
 #include "imstkLogger.h"
 
 namespace imstk
 {
-AnalyticalGeometry::AnalyticalGeometry(Type type, const std::string& name) : Geometry(type, name),
-    m_position(WORLD_ORIGIN), m_positionPostTransform(WORLD_ORIGIN), m_orientationAxis(UP_VECTOR), m_orientationAxisPostTransform(UP_VECTOR)
+AnalyticalGeometry::AnalyticalGeometry(Type type, const std::string& name) : ImplicitGeometry(type, name),
+    m_position(WORLD_ORIGIN), m_positionPostTransform(WORLD_ORIGIN),
+    m_orientationAxis(UP_VECTOR), m_orientationAxisPostTransform(UP_VECTOR)
 {
 }
 
diff --git a/Source/Geometry/Analytic/imstkAnalyticalGeometry.h b/Source/Geometry/Analytic/imstkAnalyticalGeometry.h
index a58fccc6e0287646ee0d7fac81cb48b1ab137802..905ce45a5da4c31bb12218e715410ceffd14968b 100644
--- a/Source/Geometry/Analytic/imstkAnalyticalGeometry.h
+++ b/Source/Geometry/Analytic/imstkAnalyticalGeometry.h
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include "imstkGeometry.h"
+#include "imstkImplicitGeometry.h"
 
 namespace imstk
 {
@@ -30,10 +30,9 @@ namespace imstk
 ///
 /// \brief Base class for any analytical geometrical representation
 ///
-class AnalyticalGeometry : public Geometry
+class AnalyticalGeometry : public ImplicitGeometry
 {
 public:
-
     ///
     /// \brief Print
     ///
@@ -54,8 +53,9 @@ public:
     Vec3d getOrientationAxis(DataType type = DataType::PostTransform);
     void setOrientationAxis(const Vec3d axis);
 
-protected:
+    double getFunctionValue(const Vec3d& imstkNotUsed(pos)) const override { return 0.0; }
 
+protected:
     explicit AnalyticalGeometry(Type type, const std::string& name = std::string(""));
 
     ///
diff --git a/Source/Geometry/Analytic/imstkCapsule.cpp b/Source/Geometry/Analytic/imstkCapsule.cpp
index 5d2a69a21074bf587f20714e80eb51ccd91e6ad0..266fd3e508dd614e0739e28a37db74df1caaaeaf 100644
--- a/Source/Geometry/Analytic/imstkCapsule.cpp
+++ b/Source/Geometry/Analytic/imstkCapsule.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkCapsule.h"
-
 #include "imstkLogger.h"
 
 namespace imstk
diff --git a/Source/Geometry/Analytic/imstkCapsule.h b/Source/Geometry/Analytic/imstkCapsule.h
index 7191995f1a2b9827e7a95d06dfaaf7475e6578ef..51749ed2f1d5f94fd54ee8b7f074773be4c9181b 100644
--- a/Source/Geometry/Analytic/imstkCapsule.h
+++ b/Source/Geometry/Analytic/imstkCapsule.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkAnalyticalGeometry.h"
 
 namespace imstk
@@ -72,6 +71,10 @@ public:
 protected:
     friend class VTKCapsuleRenderDelegate;
 
+    // Hide these unimplemented functions
+    using AnalyticalGeometry::getFunctionValue;
+    //using AnalyticalGeometry::getFunctionGrad;
+
     void applyScaling(const double s) override;
     void updatePostTransformData() const override;
 
diff --git a/Source/Geometry/Analytic/imstkCube.h b/Source/Geometry/Analytic/imstkCube.h
index 7291f976957a6e29526da84f07ede79d90c5efde..0ea7bc9e4906a0d7d2020c9762aeb5c1e05e2c92 100644
--- a/Source/Geometry/Analytic/imstkCube.h
+++ b/Source/Geometry/Analytic/imstkCube.h
@@ -25,6 +25,8 @@
 
 namespace imstk
 {
+class Cube;
+
 ///
 /// \class Cube
 ///
@@ -33,8 +35,13 @@ namespace imstk
 class Cube : public AnalyticalGeometry
 {
 public:
-
-    explicit Cube(const std::string& name = std::string("")) : AnalyticalGeometry(Type::Cube, name) {}
+    explicit Cube(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double width = 1.0, const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0),
+                  const std::string& name = std::string("")) : AnalyticalGeometry(Type::Cube, name)
+    {
+        setPosition(pos);
+        setOrientationAxis(orientationAxis);
+        setWidth(width);
+    }
 
     ///
     /// \brief Print the cube info
@@ -56,6 +63,17 @@ public:
     ///
     void setWidth(const double w);
 
+    ///
+    /// \brief Returns signed distance to surface at pos
+    /// \todo Doesn't support orientation yet
+    ///
+    double getFunctionValue(const Vec3d& pos) const override
+    {
+        // Make it so that only negatives are within the cube, ie: position so cube's maxima is at origin
+        const Vec3d d = (pos.cwiseAbs() - m_position) - Vec3d(m_width, m_width, m_width) * 0.5;
+        return std::min(std::max(d[0], std::max(d[1], d[2])), 0.0) + d.cwiseMax(0.0).norm();
+    }
+
 protected:
     friend class VTKCubeRenderDelegate;
 
diff --git a/Source/Geometry/Analytic/imstkCylinder.cpp b/Source/Geometry/Analytic/imstkCylinder.cpp
index 06370c6775c07f2c77d44aa561fb4d6267967f31..887385d3d746242eef1524ec97248cf7ffdfad93 100644
--- a/Source/Geometry/Analytic/imstkCylinder.cpp
+++ b/Source/Geometry/Analytic/imstkCylinder.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkCylinder.h"
-
 #include "imstkLogger.h"
 
 namespace imstk
diff --git a/Source/Geometry/Analytic/imstkCylinder.h b/Source/Geometry/Analytic/imstkCylinder.h
index d3f160faec2811a05088ff2745ed927516a9af81..f3835662bb087a905ffb60fbc393ffd13627fb9e 100644
--- a/Source/Geometry/Analytic/imstkCylinder.h
+++ b/Source/Geometry/Analytic/imstkCylinder.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkAnalyticalGeometry.h"
 
 namespace imstk
@@ -37,7 +36,16 @@ public:
     ///
     /// \brief Constructor
     ///
-    Cylinder(const std::string& name = std::string("")) : AnalyticalGeometry(Type::Cylinder, name) {}
+    explicit Cylinder(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 1.0, const double length = 1.0,
+                      const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0), const std::string& name = std::string("")) :
+        AnalyticalGeometry(Type::Cylinder, name)
+    {
+        setPosition(pos);
+        setOrientationAxis(orientationAxis);
+        setRadius(radius);
+        setLength(length);
+        updatePostTransformData();
+    }
 
     ///
     /// \brief Print the cylinder info
@@ -72,6 +80,10 @@ public:
 protected:
     friend class VTKCylinderRenderDelegate;
 
+    // Hide these unimplemented functions
+    using AnalyticalGeometry::getFunctionValue;
+    //using AnalyticalGeometry::getFunctionGrad;
+
     void applyScaling(const double s) override;
     void updatePostTransformData() const override;
 
diff --git a/Source/Geometry/Analytic/imstkPlane.h b/Source/Geometry/Analytic/imstkPlane.h
index 724913d5b638149766abd86ad4337b272480937d..13c1dad36fcc997f2374e9b729e3d21f2b9bffad 100644
--- a/Source/Geometry/Analytic/imstkPlane.h
+++ b/Source/Geometry/Analytic/imstkPlane.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkAnalyticalGeometry.h"
 
 namespace imstk
@@ -37,7 +36,14 @@ public:
     ///
     /// \brief Constructor
     ///
-    Plane(const std::string& name = std::string("")) : AnalyticalGeometry(Type::Plane, name) {}
+    explicit Plane(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const Vec3d& normal = Vec3d(0.0, 1.0, 0.0),
+                   const std::string& name = std::string("")) :
+        AnalyticalGeometry(Type::Plane, name)
+    {
+        setPosition(pos);
+        setNormal(normal.normalized());
+        updatePostTransformData();
+    }
 
     ///
     /// \brief Print the plane info
@@ -70,6 +76,16 @@ public:
     ///
     void setWidth(const double w);
 
+    ///
+    /// \brief Returns signed distance to surface at pos
+    ///
+    double getFunctionValue(const Vec3d& pos) const override { return m_orientationAxis.dot(pos - m_position); }
+
+///
+/// \brief Returns gradient of signed distance field at pos
+///
+//virtual Vec3d getFunctionGrad(const Vec3d& imstkNotUsed(pos), const Vec3d& dx) const override { return dx.cwiseProduct(m_orientationAxis); }
+
 protected:
     friend class VTKPlaneRenderDelegate;
 
diff --git a/Source/Geometry/Analytic/imstkSphere.cpp b/Source/Geometry/Analytic/imstkSphere.cpp
index bd99d22168af7c02251a5d112300cf7f9a176481..d9f71893380bc94756db215c3b1a1cf1fbe04161 100644
--- a/Source/Geometry/Analytic/imstkSphere.cpp
+++ b/Source/Geometry/Analytic/imstkSphere.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkSphere.h"
-
 #include "imstkLogger.h"
 
 namespace imstk
@@ -32,12 +31,6 @@ Sphere::print() const
     LOG(INFO) << "Radius: " << m_radius;
 }
 
-double
-Sphere::getVolume() const
-{
-    return 4.0 / 3.0 * PI * m_radius * m_radius * m_radius;
-}
-
 double
 Sphere::getRadius(DataType type /* = DataType::PostTransform */)
 {
@@ -81,12 +74,6 @@ Sphere::computeBoundingBox(Vec3d& lowerCorner, Vec3d& upperCorner, const double
     }
 }
 
-void
-Sphere::applyScaling(const double s)
-{
-    this->setRadius(m_radius * s);
-}
-
 void
 Sphere::updatePostTransformData() const
 {
diff --git a/Source/Geometry/Analytic/imstkSphere.h b/Source/Geometry/Analytic/imstkSphere.h
index 0ee237edea41e04b4c8c3833d95339ef9a3366dc..fad674237f7f6bc6e62c94bf0b5ae48bbc7262bf 100644
--- a/Source/Geometry/Analytic/imstkSphere.h
+++ b/Source/Geometry/Analytic/imstkSphere.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkAnalyticalGeometry.h"
 
 namespace imstk
@@ -37,7 +36,12 @@ public:
     ///
     /// \brief Constructor
     ///
-    Sphere(const std::string& name = std::string("")) : AnalyticalGeometry(Type::Sphere, name) {}
+    explicit Sphere(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 1.0, const std::string& name = std::string("")) :
+        AnalyticalGeometry(Type::Sphere, name)
+    {
+        setPosition(pos);
+        setRadius(radius);
+    }
 
     ///
     /// \brief Print the sphere info
@@ -47,7 +51,7 @@ public:
     ///
     /// \brief Returns the volume of the sphere
     ///
-    double getVolume() const override;
+    double getVolume() const override { return 4.0 / 3.0 * PI * m_radius * m_radius * m_radius; }
 
     ///
     /// \brief Returns the radius of the sphere
@@ -64,10 +68,20 @@ public:
     ///
     virtual void computeBoundingBox(Vec3d& lowerCorner, Vec3d& upperCorner, const double paddingPercent = 0.0) const override;
 
+    ///
+    /// \brief Returns signed distance to surface given position
+    ///
+    double getFunctionValue(const Vec3d& pos) const override { return (pos - m_position).norm() - m_radius; }
+
+///
+/// \brief Returns analytical gradient of distances given position
+///
+//Vec3d getFunctionGrad(const Vec3d& pos, const Vec3d& dx) const override { return 2.0 * (pos - m_position).cwiseProduct(dx); }
+
 protected:
     friend class VTKSphereRenderDelegate;
 
-    void applyScaling(const double s) override;
+    void applyScaling(const double s) override { this->setRadius(m_radius * s); }
     void updatePostTransformData() const override;
 
     double m_radius = 1.0;                      ///> Radius of the sphere
diff --git a/Source/Geometry/CMakeLists.txt b/Source/Geometry/CMakeLists.txt
index d3eb93e9a206193c0108dc7755c6dc3b7f400c3f..08fd2950ae190bed849b024f7eb7be26193137cc 100644
--- a/Source/Geometry/CMakeLists.txt
+++ b/Source/Geometry/CMakeLists.txt
@@ -4,9 +4,8 @@
 include(imstkAddLibrary)
 imstk_add_library( Geometry
   DEPENDS
-    Common    
-    ${VTK_LIBRARIES}
-  )
+    Common
+    ${VTK_LIBRARIES})
 
 #-----------------------------------------------------------------------------
 # Testing
diff --git a/Source/Geometry/Decal/imstkDecal.cpp b/Source/Geometry/Decal/imstkDecal.cpp
index 2b0d5d09f4ffc3195ad75781670688a2427d412c..fd0167584037cc9f4e1a6d46258a0bec65df418a 100644
--- a/Source/Geometry/Decal/imstkDecal.cpp
+++ b/Source/Geometry/Decal/imstkDecal.cpp
@@ -21,7 +21,11 @@
 
 #include "imstkDecal.h"
 #include "imstkLogger.h"
-#include "imstkMath.h"
+
+#pragma warning( push )
+#pragma warning( disable : 4201 )
+#include <glm/gtc/matrix_transform.hpp>
+#pragma warning( pop )
 
 namespace imstk
 {
diff --git a/Source/Geometry/Decal/imstkDecal.h b/Source/Geometry/Decal/imstkDecal.h
index e8c50d5cbb2b60666a69fc79309ddf0138d5bb3b..1f789e8d155aadfca4d04cc6c0994fa6783351f8 100644
--- a/Source/Geometry/Decal/imstkDecal.h
+++ b/Source/Geometry/Decal/imstkDecal.h
@@ -20,13 +20,12 @@
 =========================================================================*/
 
 #pragma once
+
 #include "imstkAnalyticalGeometry.h"
 
 #pragma warning( push )
 #pragma warning( disable : 4201 )
-#include "glm/glm.hpp"
-#include "glm/gtc/matrix_transform.hpp"
-#include "glm/gtc/quaternion.hpp"
+#include <glm/glm.hpp>
 #pragma warning( pop )
 
 namespace imstk
@@ -55,6 +54,10 @@ public:
 protected:
     friend class VulkanDecalRenderDelegate;
 
+    // Hide these functions
+    using AnalyticalGeometry::getFunctionValue;
+    //using AnalyticalGeometry::getFunctionGrad;
+
     void applyScaling(const double s) override;
 
     glm::vec3 m_dimensions;
diff --git a/Source/Geometry/Decal/imstkDecalPool.cpp b/Source/Geometry/Decal/imstkDecalPool.cpp
index 7c496a5191b751e65620cb2d25bf53a510d43ab3..2b50adadf5d005e3a6e0c4f3fc000fa4b6ac6bdf 100644
--- a/Source/Geometry/Decal/imstkDecalPool.cpp
+++ b/Source/Geometry/Decal/imstkDecalPool.cpp
@@ -20,6 +20,7 @@
 =========================================================================*/
 
 #include "imstkDecalPool.h"
+#include "imstkDecal.h"
 #include "imstkLogger.h"
 
 namespace imstk
diff --git a/Source/Geometry/Decal/imstkDecalPool.h b/Source/Geometry/Decal/imstkDecalPool.h
index 35c4ec5e3dd3eb4b8af5a5ae2ab2b4beb68009ef..dd317ae7d2f8f3867b5fd76cdac93a221f03f0d3 100644
--- a/Source/Geometry/Decal/imstkDecalPool.h
+++ b/Source/Geometry/Decal/imstkDecalPool.h
@@ -20,16 +20,19 @@
 =========================================================================*/
 
 #pragma once
-
-#include <queue>
+#include "imstkGeometry.h"
 #include <array>
+#include <queue>
 
-#include "imstkDecal.h"
-#include "imstkGeometry.h"
-//#include "imstkRenderMaterial.h"
+#pragma warning( push )
+#pragma warning( disable : 4201 )
+#include "glm/glm.hpp"
+#pragma warning( pop )
 
 namespace imstk
 {
+class Decal;
+
 class DecalPool : public Geometry
 {
 public:
diff --git a/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.cpp b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c9211f24b75ee5876e38a54ddae068c44a2d18ee
--- /dev/null
+++ b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.cpp
@@ -0,0 +1,50 @@
+/*=========================================================================
+
+   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 "imstkCompositeImplicitGeometry.h"
+
+namespace imstk
+{
+double
+CompositeImplicitGeometry::getFunctionValue(const Vec3d& pos) const
+{
+    // Initialize everything to outside
+    double distA = std::numeric_limits<double>::max();
+    for (auto i = geometries.begin(); i != geometries.end(); i++)
+    {
+        const GeometryBoolPair& pair  = *i;
+        double                  distB = pair.first->getFunctionValue(pos);
+        switch (pair.second)
+        {
+        case GeometryBoolType::Difference:
+            distA = std::max(distA, -distB);
+            break;
+        case GeometryBoolType::Intersection:
+            distA = std::max(distA, distB);
+            break;
+        case GeometryBoolType::Union:
+            distA = std::min(distA, distB);
+            break;
+        }
+    }
+    return distA;
+}
+}
\ No newline at end of file
diff --git a/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h
new file mode 100644
index 0000000000000000000000000000000000000000..7ebd9cc43fa16ad71e5788c8d75cdf8296ef9753
--- /dev/null
+++ b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h
@@ -0,0 +1,61 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkImplicitGeometry.h"
+
+namespace imstk
+{
+///
+/// \class ImplicitGeometry
+///
+/// \brief Class that can represent the geometry of multiple implicit geometries as boolean functions
+/// One may supply it with multiple implicit geometries and the operation they would like
+///
+class CompositeImplicitGeometry : public ImplicitGeometry
+{
+public:
+    enum class GeometryBoolType
+    {
+        Intersection,
+        Difference,
+        Union
+    };
+
+    using GeometryBoolPair = std::pair<std::shared_ptr<ImplicitGeometry>, GeometryBoolType>;
+
+public:
+    CompositeImplicitGeometry(std::string name    = "") : ImplicitGeometry(Type::CompositeImplicitGeometry, name) { }
+    virtual ~CompositeImplicitGeometry() override = default;
+
+public:
+    ///
+    /// \brief Returns signed distance to surface at pos
+    ///
+    virtual double getFunctionValue(const Vec3d& pos) const override;
+
+    void addImplicitGeometry(std::shared_ptr<ImplicitGeometry> geometry, const GeometryBoolType type) { geometries.push_back(GeometryBoolPair(geometry, type)); }
+
+protected:
+    std::list<GeometryBoolPair> geometries;
+};
+}
diff --git a/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h b/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd345ad460ca7323c2de55588ceee3c4ba469ed0
--- /dev/null
+++ b/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h
@@ -0,0 +1,168 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkImplicitGeometry.h"
+#include "imstkSignedDistanceField.h"
+
+namespace imstk
+{
+///
+/// \brief Base struct for gradient functors
+///
+struct ImplicitFunctionGradient
+{
+    public:
+        virtual Vec3d operator()(const Vec3d& pos) const = 0;
+
+        virtual void setDx(const Vec3d& dx)
+        {
+            this->m_dx    = dx;
+            this->m_invDx = Vec3d(1.0 / dx[0], 1.0 / dx[1], 1.0 / dx[2]);
+        }
+
+        const Vec3d& getDx() const { return m_dx; }
+
+        void setFunction(std::shared_ptr<ImplicitGeometry> func) { this->m_func = func; }
+
+    protected:
+        std::shared_ptr<ImplicitGeometry> m_func;
+        Vec3d m_dx    = Vec3d(1.0, 1.0, 1.0);
+        Vec3d m_invDx = Vec3d(1.0, 1.0, 1.0);
+};
+
+///
+/// \brief Gradient given by central finite differences
+///
+struct ImplicitFunctionCentralGradient : public ImplicitFunctionGradient
+{
+    public:
+        Vec3d operator()(const Vec3d& pos) const override
+        {
+            const ImplicitGeometry& funcRef = *m_func;
+            return Vec3d(
+            funcRef.getFunctionValue(Vec3d(pos[0] + m_dx[0], pos[1], pos[2])) - funcRef.getFunctionValue(Vec3d(pos[0] - m_dx[0], pos[1], pos[2])),
+            funcRef.getFunctionValue(Vec3d(pos[0], pos[1] + m_dx[1], pos[2])) - funcRef.getFunctionValue(Vec3d(pos[0], pos[1] - m_dx[1], pos[2])),
+            funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2] + m_dx[2])) - funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2] - m_dx[2]))).cwiseProduct(m_invDx) * 0.5;
+        }
+};
+
+///
+/// \brief Gradient given by forward finite differences
+///
+struct ImplicitFunctionForwardGradient : public ImplicitFunctionGradient
+{
+    public:
+        Vec3d operator()(const Vec3d& pos) const override
+        {
+            const ImplicitGeometry& funcRef      = *m_func;
+            const double            centralValue = funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2]));
+            const double            maxValueX    = funcRef.getFunctionValue(Vec3d(pos[0] + m_dx[0], pos[1], pos[2]));
+            const double            maxValueY    = funcRef.getFunctionValue(Vec3d(pos[0], pos[1] + m_dx[1], pos[2]));
+            const double            maxValueZ    = funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2] + m_dx[2]));
+            return Vec3d(
+            maxValueX - centralValue,
+            maxValueY - centralValue,
+            maxValueZ - centralValue).cwiseProduct(m_invDx);
+        }
+};
+
+///
+/// \brief Gradient given by backward finite differences
+///
+struct ImplicitFunctionBackwardGradient : public ImplicitFunctionGradient
+{
+    public:
+        Vec3d operator()(const Vec3d& pos) const override
+        {
+            const ImplicitGeometry& funcRef      = *m_func;
+            const double            centralValue = funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2]));
+            const double            minValueX    = funcRef.getFunctionValue(Vec3d(pos[0] - m_dx[0], pos[1], pos[2]));
+            const double            minValueY    = funcRef.getFunctionValue(Vec3d(pos[0], pos[1] - m_dx[1], pos[2]));
+            const double            minValueZ    = funcRef.getFunctionValue(Vec3d(pos[0], pos[1], pos[2] - m_dx[2]));
+            return Vec3d(
+            centralValue - minValueX,
+            centralValue - minValueY,
+            centralValue - minValueZ).cwiseProduct(m_invDx);
+        }
+};
+
+///
+/// \brief Gradient given by forward finite differences
+///
+struct StructuredForwardGradient : public ImplicitFunctionGradient
+{
+    public:
+        Vec3d operator()(const Vec3d& pos) const override
+        {
+            const SignedDistanceField& funcRef      = *static_cast<SignedDistanceField*>(m_func.get());
+            const double               centralValue = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2])));
+            const double               maxValueX    = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0] + m_dxi[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2])));
+            const double               maxValueY    = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1] + m_dxi[1]), static_cast<int>(pos[2])));
+            const double               maxValueZ    = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2] + m_dxi[2])));
+            return Vec3d(
+            maxValueX - centralValue,
+            maxValueY - centralValue,
+            maxValueZ - centralValue).cwiseProduct(m_invDx);
+        }
+
+        void setDx(const Vec3i& dx, const Vec3d& dxs)
+        {
+            m_dxi = dx;
+            ImplicitFunctionGradient::setDx(dxs.cwiseProduct(m_dxi.cast<double>()));
+        }
+
+    protected:
+        using ImplicitFunctionGradient::setDx;
+        Vec3i m_dxi;
+};
+
+///
+/// \brief Gradient given by backward finite differences
+///
+struct StructuredBackwardGradient : public ImplicitFunctionGradient
+{
+    public:
+        Vec3d operator()(const Vec3d& pos) const override
+        {
+            const SignedDistanceField& funcRef      = *static_cast<SignedDistanceField*>(m_func.get());
+            const double               centralValue = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2])));
+            const double               minValueX    = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0] - m_dxi[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2])));
+            const double               minValueY    = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1] - m_dxi[1]), static_cast<int>(pos[2])));
+            const double               minValueZ    = funcRef.getFunctionValueCoord(Vec3i(static_cast<int>(pos[0]), static_cast<int>(pos[1]), static_cast<int>(pos[2] - m_dxi[2])));
+            return Vec3d(
+            centralValue - minValueX,
+            centralValue - minValueY,
+            centralValue - minValueZ).cwiseProduct(m_invDx);
+        }
+
+        void setDx(const Vec3i& dx, const Vec3d& dxs)
+        {
+            m_dxi = dx;
+            ImplicitFunctionGradient::setDx(dxs);
+        }
+
+    protected:
+        using ImplicitFunctionGradient::setDx;
+        Vec3i m_dxi;
+};
+}
\ No newline at end of file
diff --git a/Source/Controllers/imstkSceneObjectControllerBase.h b/Source/Geometry/Implicit/imstkImplicitGeometry.h
similarity index 61%
rename from Source/Controllers/imstkSceneObjectControllerBase.h
rename to Source/Geometry/Implicit/imstkImplicitGeometry.h
index fb590c6340ad916149850e32f47242ff66c8ce11..808edc58932fa149274a3bd2fc2fc3f173ea685c 100644
--- a/Source/Controllers/imstkSceneObjectControllerBase.h
+++ b/Source/Geometry/Implicit/imstkImplicitGeometry.h
@@ -21,35 +21,28 @@
 
 #pragma once
 
+#include "imstkGeometry.h"
+
 namespace imstk
 {
 ///
-/// \class SceneObjectControllerBase
+/// \class ImplicitGeometry
 ///
-/// \brief Base class for all the scene object controllers
+/// \brief Defines implicit geometry with an implicit function
+/// Implicit functions must be decoupled from geometry
 ///
-class SceneObjectControllerBase
+class ImplicitGeometry : public Geometry
 {
 public:
-    ///
-    /// \brief Constructor/Destructor
-    ///
-    SceneObjectControllerBase()  = default;
-    ~SceneObjectControllerBase() = default;
+    virtual ~ImplicitGeometry() override = default;
 
-    ///
-    /// \brief Update controlled scene objects using latest tracking information
-    ///
-    virtual void updateControlledObjects() = 0;
-
-    ///
-    /// \brief Apply forces to the haptic device
-    ///
-    virtual void applyForces() = 0;
+protected:
+    ImplicitGeometry(Type geomType, std::string name = "") : Geometry(geomType, name) { }
 
+public:
     ///
-    /// \brief
+    /// \brief Returns function value given position
     ///
-    virtual void setTrackerToOutOfDate() = 0;
+    virtual double getFunctionValue(const Vec3d& pos) const = 0;
 };
-} // imstk
+}
diff --git a/Source/Geometry/Implicit/imstkSignedDistanceField.cpp b/Source/Geometry/Implicit/imstkSignedDistanceField.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bda126dc518a3687eb082e9ba46628e0746331ad
--- /dev/null
+++ b/Source/Geometry/Implicit/imstkSignedDistanceField.cpp
@@ -0,0 +1,114 @@
+/*=========================================================================
+
+   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 "imstkSignedDistanceField.h"
+#include "imstkDataArray.h"
+#include "imstkImageData.h"
+#include "imstkLogger.h"
+
+namespace imstk
+{
+///
+/// \brief Accepts structured coordinates (ie: pre int cast, [0, dim)) so it can do interpolation
+/// origin should be image origin + spacing/2
+///
+template<typename T>
+static T
+trilinearSample(const Vec3d& structuredPt, T* imgPtr, const Vec3i& dim, const int numComps, const int comp)
+{
+    // minima of voxel, clamped to bounds
+    const Vec3i s1 = structuredPt.cast<int>().cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1));
+
+    // maxima of voxel, clamped to bounds
+    const Vec3i s2 = (structuredPt.cast<int>() + Vec3i(1, 1, 1)).cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1));
+
+    const size_t index000 = ImageData::getScalarIndex(s1.x(), s1.y(), s1.z(), dim, numComps) + comp;
+    const size_t index100 = ImageData::getScalarIndex(s2.x(), s1.y(), s1.z(), dim, numComps) + comp;
+    const size_t index110 = ImageData::getScalarIndex(s2.x(), s2.y(), s1.z(), dim, numComps) + comp;
+    const size_t index010 = ImageData::getScalarIndex(s1.x(), s2.y(), s1.z(), dim, numComps) + comp;
+    const size_t index001 = ImageData::getScalarIndex(s1.x(), s1.y(), s2.z(), dim, numComps) + comp;
+    const size_t index101 = ImageData::getScalarIndex(s2.x(), s1.y(), s2.z(), dim, numComps) + comp;
+    const size_t index111 = ImageData::getScalarIndex(s2.x(), s2.y(), s2.z(), dim, numComps) + comp;
+    const size_t index011 = ImageData::getScalarIndex(s1.x(), s2.y(), s2.z(), dim, numComps) + comp;
+
+    const double val000 = static_cast<double>(imgPtr[index000]);
+    const double val100 = static_cast<double>(imgPtr[index100]);
+    const double val110 = static_cast<double>(imgPtr[index110]);
+    const double val010 = static_cast<double>(imgPtr[index010]);
+
+    const double val001 = static_cast<double>(imgPtr[index001]);
+    const double val101 = static_cast<double>(imgPtr[index101]);
+    const double val111 = static_cast<double>(imgPtr[index111]);
+    const double val011 = static_cast<double>(imgPtr[index011]);
+
+    // Interpolants
+    //const Vec3d t = s2.cast<double>() - structuredPt;
+    const Vec3d t = structuredPt - s2.cast<double>();
+
+    // Interpolate along x
+    const double ax = val000 + (val100 - val000) * t[0];
+    const double bx = val010 + (val110 - val010) * t[0];
+
+    const double dx = val001 + (val101 - val001) * t[0];
+    const double ex = val011 + (val111 - val011) * t[0];
+
+    // Interpolate along y
+    const double cy = ax + (bx - ax) * t[1];
+    const double fy = dx + (ex - dx) * t[1];
+
+    // Interpolate along z
+    const double gz = cy + (fy - cy) * t[2];
+
+    return static_cast<T>(gz);
+}
+
+SignedDistanceField::SignedDistanceField(std::shared_ptr<ImageData> imageData, std::string name) :
+    ImplicitGeometry(Type::SignedDistanceField, name),
+    m_imageDataSdf(imageData)
+{
+    m_invSpacing = m_imageDataSdf->getInvSpacing();
+    m_bounds     = m_imageDataSdf->getBounds();
+    m_shift      = m_imageDataSdf->getOrigin() - m_imageDataSdf->getSpacing() * 0.5;
+
+    if (m_imageDataSdf->getScalarType() != IMSTK_DOUBLE)
+    {
+        LOG(WARNING) << "SignedDistanceField requires double input image";
+        return;
+    }
+
+    m_scalars = std::dynamic_pointer_cast<DataArray<double>>(m_imageDataSdf->getScalars());
+}
+
+double
+SignedDistanceField::getFunctionValue(const Vec3d& pos) const
+{
+    // origin at center of first voxel
+    const Vec3d structuredPt = (pos - m_shift).cwiseProduct(m_invSpacing);
+    return trilinearSample(structuredPt, m_scalars->getPointer(), m_imageDataSdf->getDimensions(), 1, 0);
+}
+
+double
+SignedDistanceField::getFunctionValueCoord(const Vec3i& coord) const
+{
+    const Vec3i clampedCoord = coord.cwiseMin(m_imageDataSdf->getDimensions() - Vec3i(1, 1, 1)).cwiseMax(0);
+    return (*m_scalars)[m_imageDataSdf->getScalarIndex(clampedCoord)];
+}
+}
\ No newline at end of file
diff --git a/Source/Geometry/Implicit/imstkSignedDistanceField.h b/Source/Geometry/Implicit/imstkSignedDistanceField.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a52e200e905821f3ffb6ea6faf899b6937dd029
--- /dev/null
+++ b/Source/Geometry/Implicit/imstkSignedDistanceField.h
@@ -0,0 +1,75 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkImplicitGeometry.h"
+
+namespace imstk
+{
+class ImageData;
+template<typename T> class DataArray;
+
+///
+/// \class SignedDistanceField
+///
+/// \brief Structured field of signed distances implemented with ImageData
+///
+class SignedDistanceField : public ImplicitGeometry
+{
+public:
+    ///
+    /// \brief Initialize with an image data SDF
+    ///
+    SignedDistanceField(std::shared_ptr<ImageData> imageData, std::string name = "");
+    virtual ~SignedDistanceField() override = default;
+
+public:
+    ///
+    /// \brief Returns signed distance to surface at pos, returns clamped/nearest if out of bounds
+    ///
+    double getFunctionValue(const Vec3d& pos) const override;
+
+    ///
+    /// \brief Returns signed distance to surface at coordinate
+    ///
+    double getFunctionValueCoord(const Vec3i& coord) const;
+
+    ///
+    /// \brief Returns the bounds of the field
+    ///
+    const Vec6d& getBounds() const { return m_bounds; }
+
+    ///
+    /// \brief Get the SDF as a float image
+    ///
+    std::shared_ptr<ImageData> getImage() const { return m_imageDataSdf; }
+
+protected:
+    std::shared_ptr<ImageData> m_imageDataSdf;
+
+    Vec3d m_invSpacing;
+    Vec6d m_bounds;
+    Vec3d m_shift;
+
+    std::shared_ptr<DataArray<double>> m_scalars;
+};
+}
\ No newline at end of file
diff --git a/Source/Geometry/Mesh/imstkHexahedralMesh.cpp b/Source/Geometry/Mesh/imstkHexahedralMesh.cpp
index 42666b8e3a18d11e4bad6afebf2aabc15fa773ab..5e373edb5b0c21b5816e046f26d49b314032db06 100644
--- a/Source/Geometry/Mesh/imstkHexahedralMesh.cpp
+++ b/Source/Geometry/Mesh/imstkHexahedralMesh.cpp
@@ -23,8 +23,6 @@
 #include "imstkSurfaceMesh.h"
 #include "imstkLogger.h"
 
-#include <array>
-
 namespace imstk
 {
 void
diff --git a/Source/Geometry/Mesh/imstkImageData.cpp b/Source/Geometry/Mesh/imstkImageData.cpp
index 9e286d43266ac385bedcd5b5a108036c693cb832..851a2cc971e61a790f358c7bc271b134c1be7c0f 100644
--- a/Source/Geometry/Mesh/imstkImageData.cpp
+++ b/Source/Geometry/Mesh/imstkImageData.cpp
@@ -20,123 +20,167 @@
 =========================================================================*/
 
 #include "imstkImageData.h"
-
-// vtk
-#include "vtkImageReslice.h"
-#include "vtkTransform.h"
-#include <vtkImageData.h>
+#include "imstkLogger.h"
+#include "imstkDataArray.h"
 
 namespace imstk
 {
+template<typename FROM_TYPE, typename TO_TYPE>
+static void
+castArray(std::shared_ptr<DataArray<FROM_TYPE>> fromArray, std::shared_ptr<DataArray<TO_TYPE>> toArray)
+{
+    const DataArray<FROM_TYPE>& fromArrayRef = *fromArray;
+    DataArray<TO_TYPE>&         toArrayRef   = *toArray;
+    const size_t                numVals      = fromArray->size();
+    for (size_t i = 0; i < numVals; i++)
+    {
+        toArrayRef[i] = static_cast<TO_TYPE>(fromArrayRef[i]);
+    }
+}
+
+template<typename FROM_TYPE>
+static void
+castImage(std::shared_ptr<AbstractDataArray> fromScalars, std::shared_ptr<ImageData> toImage)
+{
+    const ScalarType toType = toImage->getScalars()->getScalarType();
+    switch (toType)
+    {
+        TemplateMacro(castArray(
+            std::dynamic_pointer_cast<DataArray<FROM_TYPE>>(fromScalars),
+            std::dynamic_pointer_cast<DataArray<IMSTK_TT>>(toImage->getScalars())); );
+    default:
+        LOG(WARNING) << "Unknown scalar type";
+        break;
+    }
+    ;
+}
+
 ImageData::ImageData(const std::string& name)
     : PointSet(Geometry::Type::ImageData, name),
-    m_dataTransform(vtkSmartPointer<vtkTransform>::New())
+    m_scalarArray(nullptr)
 {
 }
 
 void
 ImageData::print() const
 {
-    Geometry::print();
+    PointSet::print();
+    LOG(INFO) << "Scalar Type: " << static_cast<int>(m_scalarArray->getScalarType());
+    LOG(INFO) << "Number of Components" << m_numComps;
+    LOG(INFO) << "Dimensions: " << m_dims[0] << ", " << m_dims[1] << ", " << m_dims[2];
+    LOG(INFO) << "Spacing: " << m_spacing[0] << ", " << m_spacing[1] << ", " << m_spacing[2];
+    LOG(INFO) << "Origin: " << m_origin[0] << ", " << m_origin[1] << ", " << m_origin[2];
+    LOG(INFO) << "Bounds: ";
+    LOG(INFO) << "\t" << m_bounds[0] << ", " << m_bounds[1];
+    LOG(INFO) << "\t" << m_bounds[2] << ", " << m_bounds[3];
+    LOG(INFO) << "\t" << m_bounds[4] << ", " << m_bounds[5];
 }
 
 double
 ImageData::getVolume() const
 {
-    if (!this->m_data)
+    if (m_scalarArray == nullptr)
     {
         return 0.0;
     }
 
-    double bounds[6];
-    this->m_data->GetBounds(bounds);
-    return ((bounds[1] - bounds[0]) *
-            (bounds[3] - bounds[2]) *
-            (bounds[5] - bounds[4]));
+    return (m_dims[0] * m_spacing.x()) *
+           (m_dims[1] * m_spacing.y()) *
+           (m_dims[2] * m_spacing.z());
 }
 
-void
-ImageData::initialize(vtkImageData* im)
+void*
+ImageData::getVoidPointer()
 {
-    this->clear();
-    if (im)
-    {
-        this->m_data = vtkSmartPointer<vtkImageData>::New();
-        this->m_data->DeepCopy(im);
-    }
+    return m_scalarArray->getVoidPointer();
 }
 
-void
-ImageData::clear()
+std::shared_ptr<ImageData>
+ImageData::cast(ScalarType toType)
 {
-    if (this->m_data)
+    // Create image of new type
+    std::shared_ptr<ImageData> results = std::make_shared<ImageData>();
+    results->allocate(toType, m_numComps, m_dims, m_spacing, m_origin);
+    switch (m_scalarArray->getScalarType())
     {
-        this->m_data = nullptr;
+        TemplateMacro(castImage<IMSTK_TT>(m_scalarArray, results); );
+    default:
+        LOG(WARNING) << "Unknown scalar type";
+        break;
     }
-    this->m_dataTransform->Identity();
-    this->m_transformApplied = true;
-    this->m_dataModified     = true;
+    ;
+    return results;
 }
 
-vtkImageData*
-ImageData::getData(DataType type)
+const ScalarType
+ImageData::getScalarType() const
 {
-    if (type == DataType::PostTransform)
-    {
-        this->updatePostTransformData();
-    }
-    return this->m_data;
+    return m_scalarArray->getScalarType();
 }
 
 void
-ImageData::applyTranslation(const Vec3d t)
+ImageData::setScalars(std::shared_ptr<AbstractDataArray> scalars, const int numComps, int* dim)
 {
-    this->m_dataTransform->Translate(t[0], t[1], t[2]);
-
-    this->m_dataModified     = true;
-    this->m_transformApplied = false;
+    CHECK(scalars != nullptr);
+    if (dim[0] * dim[1] * dim[2] * numComps != scalars->size())
+    {
+        LOG(WARNING) << "Scalars don't align";
+    }
+    m_scalarArray = scalars;
+    m_dims[0]     = dim[0];
+    m_dims[1]     = dim[1];
+    m_dims[2]     = dim[2];
+    m_numComps    = numComps;
 }
 
 void
-ImageData::applyScaling(const double s)
+ImageData::allocate(const ScalarType type, const int numComps, const Vec3i& dims, const Vec3d& spacing, const Vec3d& origin)
 {
-    this->m_dataTransform->Scale(s, s, s);
-
-    this->m_dataModified     = true;
-    this->m_transformApplied = false;
+    m_dims   = dims;
+    m_origin = origin;
+    setSpacing(spacing);
+    m_numComps = numComps;
+    const size_t numVals = static_cast<size_t>(dims[0] * dims[1] * dims[2] * numComps);
+    switch (type)
+    {
+        TemplateMacro(m_scalarArray = std::make_shared<DataArray<IMSTK_TT>>(numVals); );
+    default:
+        LOG(WARNING) << "Tried to allocate unknown scalar type";
+        break;
+    }
+    // When allocation is done, post modified on the image
+    connect<Event>(m_scalarArray, EventType::Modified, [&](Event*) { this->postEvent(Event(EventType::Modified)); });
 }
 
 void
-ImageData::applyRotation(const Mat3d r)
+ImageData::computePoints()
 {
-    vtkNew<vtkMatrix4x4> mat;
-    for (int i = 0; i < 3; ++i)
+    StdVectorOfVec3d vertices(m_dims[0] * m_dims[1] * m_dims[2]);
+    const Vec3d      shift = m_origin + m_spacing * 0.5;
+    int              i     = 0;
+    for (int z = 0; z < m_dims[2]; z++)
     {
-        for (int j = 0; j < 3; ++j)
+        for (int y = 0; y < m_dims[1]; y++)
         {
-            mat->SetElement(i, j, r(i, j));
+            for (int x = 0; x < m_dims[0]; x++, i++)
+            {
+                vertices[i] = Vec3d(x, y, z).cwiseProduct(m_spacing) + shift;
+            }
         }
     }
-    this->m_dataTransform->Concatenate(mat);
-
-    this->m_dataModified     = true;
-    this->m_transformApplied = false;
+    setInitialVertexPositions(vertices);
+    setVertexPositions(vertices);
 }
 
 void
-ImageData::updatePostTransformData() const
+ImageData::clear()
 {
-    if (m_transformApplied || !this->m_data)
+    if (this->m_scalarArray != nullptr)
     {
-        return;
+        this->m_scalarArray = nullptr;
     }
-
-    vtkNew<vtkImageReslice> reslice;
-    reslice->SetInputData(this->m_data);
-    reslice->SetResliceTransform(this->m_dataTransform);
-    reslice->SetInterpolationModeToLinear();
-    reslice->Update();
-    this->m_data->DeepCopy(reslice->GetOutput());
+    //this->m_dataTransform->Identity();
     this->m_transformApplied = true;
+    this->m_dataModified     = true;
 }
 } // imstk
diff --git a/Source/Geometry/Mesh/imstkImageData.h b/Source/Geometry/Mesh/imstkImageData.h
index 2ac99e47d4ce38a6d2518db962cf959d4f96bf0d..7ef38853a26098235fb61d8acdb83e1f39e36d2d 100644
--- a/Source/Geometry/Mesh/imstkImageData.h
+++ b/Source/Geometry/Mesh/imstkImageData.h
@@ -21,23 +21,17 @@
 
 #pragma once
 
-// imstk
 #include "imstkPointSet.h"
-
-// vtk
-#include "vtkSmartPointer.h"
-
-// forward declarations
-class vtkTransform;
-class vtkImageData;
-class vtkTransform;
+#include "imstkTypes.h"
 
 namespace imstk
 {
+class AbstractDataArray;
+
 ///
 /// \class ImageData
 ///
-/// \brief Class to represent 2D and 3D image data (i.e. structured points)
+/// \brief Class to represent 1, 2, or 3D image data (i.e. structured points)
 ///
 class ImageData : public PointSet
 {
@@ -47,6 +41,12 @@ public:
     ///
     ImageData(const std::string& name = std::string(""));
 
+    ///
+    /// \brief Destructor
+    ///
+    virtual ~ImageData() override = default;
+
+public:
     ///
     /// \brief Print the image data info
     ///
@@ -58,32 +58,122 @@ public:
     double getVolume() const override;
 
     ///
-    /// \brief Initialize to an existing image data
+    /// \brief Returns the dimensions of the image
     ///
-    void initialize(vtkImageData* im);
+    const Vec3i& getDimensions() const { return m_dims; }
 
     ///
-    /// \brief Clear the data
+    /// \brief Returns the number of components of the image
     ///
-    void clear() override;
+    int getNumComponents() const { return m_numComps; }
 
     ///
-    /// \brief Return the underlying data
+    /// \brief Returns a pointer to the underlying storage of the image
     ///
-    vtkImageData* getData(DataType type = DataType::PostTransform);
+    void* getVoidPointer();
 
-protected:
-    friend class VTKImageDataRenderDelegate;
+    ///
+    /// \brief Returns index of data in scalar array given structured image coordinate, does no bounds checking
+    ///
+    inline size_t getScalarIndex(int x, int y, int z = 0) { return getScalarIndex(x, y, z, m_dims, m_numComps); }
+    inline size_t getScalarIndex(const Vec3i& imgCoord) { return getScalarIndex(imgCoord[0], imgCoord[1], imgCoord[2], m_dims, m_numComps); }
+
+    ///
+    /// \brief Returns index of data in scalar array given structured image coordinate, dimensions, and number of components
+    /// does no bounds checking
+    ///
+    inline static size_t getScalarIndex(int x, int y, int z, const Vec3i& dims, int numComps) { return (x + dims[0] * (y + z * dims[1])) * numComps; }
+
+    std::shared_ptr<ImageData> cast(ScalarType type);
+
+    ///
+    /// \brief Returns the origin of the image
+    ///
+    const Vec3d& getOrigin() const { return m_origin; }
+
+    ///
+    /// \brief Returns the spacing of the image
+    ///
+    const Vec3d& getSpacing() const { return m_spacing; }
+
+    ///
+    /// \brief Returns inv spacing of the image
+    ///
+    const Vec3d& getInvSpacing() const { return m_invSpacing; }
+
+    ///
+    /// \brief Returns the scalar type of the image
+    ///
+    const ScalarType getScalarType() const;
+
+    ///
+    /// \brief Returns bounds of the image (voxel to voxel)
+    ///
+    const Vec6d& getBounds()
+    {
+        const Vec3d size = Vec3d(
+            m_spacing.x() * m_dims[0],
+            m_spacing.y() * m_dims[1],
+            m_spacing.z() * m_dims[2]);
+
+        m_bounds[0] = m_origin.x();
+        m_bounds[1] = m_origin.x() + size.x();
+        m_bounds[2] = m_origin.y();
+        m_bounds[3] = m_origin.y() + size.y();
+        m_bounds[4] = m_origin.z();
+        m_bounds[5] = m_origin.z() + size.z();
+
+        return m_bounds;
+    }
+
+    ///
+    /// \brief Returns point data scalars
+    ///
+    std::shared_ptr<AbstractDataArray> getScalars() const { return m_scalarArray; }
 
-    vtkSmartPointer<vtkImageData> m_data;            ///> ImageData
-    vtkSmartPointer<vtkTransform> m_dataTransform;
+    ///
+    /// \brief Sets the scalars
+    ///
+    void setScalars(std::shared_ptr<AbstractDataArray> scalars, const int numComps, int* dim);
 
-    void applyTranslation(const Vec3d t) override;
+    ///
+    /// \brief Sets the origin of the image
+    ///
+    void setOrigin(const Vec3d& origin) { m_origin = origin; }
 
-    void applyRotation(const Mat3d r) override;
+    ///
+    /// \brief Sets the spacing between pixels/voxels of the image
+    ///
+    void setSpacing(const Vec3d& spacing)
+    {
+        m_spacing    = spacing;
+        m_invSpacing = Vec3d(1.0 / spacing[0], 1.0 / spacing[1], 1.0 / spacing[2]);
+    }
 
-    void applyScaling(const double s) override;
+    ///
+    /// \brief Allocate image by type
+    ///
+    void allocate(const ScalarType type, const int numComps, const Vec3i& dims, const Vec3d& spacing = Vec3d(1.0, 1.0, 1.0), const Vec3d& origin = Vec3d(0.0, 0.0, 0.0));
+
+    ///
+    /// \brief Generates points in the geometry from the ImageData (center of each voxel)
+    ///
+    void computePoints();
+
+    ///
+    /// \brief Clear the data
+    ///
+    void clear() override;
+
+protected:
+    friend class VTKImageDataRenderDelegate;
 
-    void updatePostTransformData() const override;
+    std::shared_ptr<AbstractDataArray> m_scalarArray = nullptr;
+    Vec3i m_dims       = Vec3i(0, 0, 0);
+    int   m_numComps   = 1;
+    Vec3d m_origin     = Vec3d(0.0, 0.0, 0.0);
+    Vec3d m_spacing    = Vec3d(1.0, 1.0, 1.0);
+    Vec3d m_invSpacing = Vec3d(1.0, 1.0, 1.0);
+    Vec6d m_bounds;
 };
 } // imstk
diff --git a/Source/Geometry/Mesh/imstkLineMesh.h b/Source/Geometry/Mesh/imstkLineMesh.h
index 00e472e62b0dd4171deae1e5475836e34a45fd58..ed17cbb2d5b58cd2d80e3562d7a69b9722a56929 100644
--- a/Source/Geometry/Mesh/imstkLineMesh.h
+++ b/Source/Geometry/Mesh/imstkLineMesh.h
@@ -21,9 +21,8 @@
 
 #pragma once
 
-#include <array>
-
 #include "imstkPointSet.h"
+#include <array>
 
 namespace imstk
 {
diff --git a/Source/Geometry/Mesh/imstkPointSet.cpp b/Source/Geometry/Mesh/imstkPointSet.cpp
index 4f0bd8530460c6a091f1d8e928bf34934dd6be10..ede30ae3359862e1491da97e73ec8b813d7337c9 100644
--- a/Source/Geometry/Mesh/imstkPointSet.cpp
+++ b/Source/Geometry/Mesh/imstkPointSet.cpp
@@ -218,6 +218,18 @@ PointSet::getPointDataArray(const std::string& arrayName) const
     return &(it->second);
 }
 
+StdVectorOfVectorf*
+PointSet::getPointDataArray(const std::string& arrayName)
+{
+    auto it = m_pointDataMap.find(arrayName);
+    if (it == m_pointDataMap.end())
+    {
+        LOG(WARNING) << "No array with such name holds any point data.";
+        return nullptr;
+    }
+    return &(it->second);
+}
+
 bool
 PointSet::hasPointDataArray(const std::string& arrayName) const
 {
diff --git a/Source/Geometry/Mesh/imstkPointSet.h b/Source/Geometry/Mesh/imstkPointSet.h
index 79c6e4b320edea8a309c6c826702a5e6b22a486d..91387a27afe3f9ae8b07898cfaf8744652afd87a 100644
--- a/Source/Geometry/Mesh/imstkPointSet.h
+++ b/Source/Geometry/Mesh/imstkPointSet.h
@@ -138,6 +138,11 @@ public:
     ///
     const StdVectorOfVectorf* getPointDataArray(const std::string& arrayName) const;
 
+    ///
+    /// \brief Get a specific data array. If the array name cannot be found, nullptr is returned.
+    ///
+    StdVectorOfVectorf* getPointDataArray(const std::string& arrayName);
+
     ///
     /// \brief Check if a specific data array exists.
     ///
diff --git a/Source/Geometry/Mesh/imstkSurfaceMesh.cpp b/Source/Geometry/Mesh/imstkSurfaceMesh.cpp
index b3063fb8004b5e854e3f2a83b8b34c65afc080b9..1a8e10273a2bfbf20a05d174669989afb9f9a1ac 100644
--- a/Source/Geometry/Mesh/imstkSurfaceMesh.cpp
+++ b/Source/Geometry/Mesh/imstkSurfaceMesh.cpp
@@ -22,8 +22,7 @@
 #include "imstkSurfaceMesh.h"
 #include "imstkTimer.h"
 #include "imstkParallelUtils.h"
-
-//#include "imstkGraph.h"
+#include "imstkLogger.h"
 
 namespace imstk
 {
@@ -83,9 +82,9 @@ SurfaceMesh::print() const
 double
 SurfaceMesh::getVolume() const
 {
-    // TODO
-    // 1. Check for water tightness
-    // 2. Compute volume based on signed distance
+    /// \todo:
+    /// 1. Check for water tightness
+    /// 2. Compute volume based on signed distance
 
     LOG(WARNING) << "SurfaceMesh::getVolume error: not implemented.";
     return 0.0;
@@ -150,7 +149,8 @@ SurfaceMesh::computeTrianglesNormals()
         m_triangleNormals.at(triangleId) = ((p1 - p0).cross(p2 - p0)).normalized();
     }
 
-    bool                      hasUVs = this->hasPointDataArray(m_defaultTCoords);
+    // TCoords must be named (or else it will pick up any array without a name)
+    bool                      hasUVs = m_defaultTCoords == "" ? false : this->hasPointDataArray(m_defaultTCoords);
     const StdVectorOfVectorf* UVs    = nullptr;
 
     if (hasUVs)
@@ -207,12 +207,13 @@ SurfaceMesh::computeVertexNormals()
 
     // Correct for UV seams
     Vec3d normal, tangent;
-    bool  hasUVs = this->hasPointDataArray(m_defaultTCoords);
+    // TCoords must be named (or else it will pick up any array without a name)
+    bool hasUVs = m_defaultTCoords == "" ? false : this->hasPointDataArray(m_defaultTCoords);
 
-    if (hasUVs)
+    /*if (hasUVs)
     {
         auto UVs = this->getPointDataArray(m_defaultTCoords);
-    }
+    }*/
 
     for (size_t vertexId = 0; vertexId < m_vertexNormals.size(); ++vertexId)
     {
@@ -598,8 +599,8 @@ void
 SurfaceMesh::setLoadFactor(double loadFactor)
 {
     m_loadFactor      = loadFactor;
-    m_maxNumVertices  = (size_t)(m_originalNumVertices * m_loadFactor);
-    m_maxNumTriangles = (size_t)(m_originalNumTriangles * m_loadFactor);
+    m_maxNumVertices  = static_cast<size_t>(m_originalNumVertices * m_loadFactor);
+    m_maxNumTriangles = static_cast<size_t>(m_originalNumTriangles * m_loadFactor);
     m_trianglesVertices.reserve(m_maxNumTriangles);
     m_vertexNormals.reserve(m_maxNumVertices);
     m_vertexTangents.reserve(m_maxNumVertices);
@@ -631,9 +632,43 @@ SurfaceMesh::directionalScale(double s_x, double s_y, double s_z)
                 m_initialVertexPositions[i].y() = s_y * m_initialVertexPositions[i].y();
                 m_vertexPositions[i].z() = s_z * m_vertexPositions[i].z();
                 m_initialVertexPositions[i].z() = s_z * m_initialVertexPositions[i].z();
-      });
-        m_dataModified     = true;
+            });
+        m_dataModified = true;
         m_transformApplied = false;
     }
 }
+
+SurfaceMesh::deepCopy(std::shared_ptr<SurfaceMesh> srcMesh)
+{
+    this->m_trianglesVertices       = srcMesh->m_trianglesVertices;
+    this->m_vertexNeighborTriangles = srcMesh->m_vertexNeighborTriangles;
+    this->m_vertexNeighborVertices  = srcMesh->m_vertexNeighborVertices;
+    this->m_triangleNormals      = srcMesh->m_triangleNormals;
+    this->m_triangleTangents     = srcMesh->m_triangleTangents;
+    this->m_vertexNormals        = srcMesh->m_vertexNormals;
+    this->m_vertexTangents       = srcMesh->m_vertexTangents;
+    this->m_UVSeamVertexGroups   = srcMesh->m_UVSeamVertexGroups;
+    this->m_defaultTCoords       = srcMesh->m_defaultTCoords;
+    this->m_originalNumTriangles = srcMesh->m_originalNumTriangles;
+    this->m_maxNumTriangles      = srcMesh->m_maxNumTriangles;
+
+    this->m_initialVertexPositions = srcMesh->m_initialVertexPositions;
+    this->m_vertexPositions = srcMesh->m_vertexPositions;
+    this->m_vertexPositionsPostTransform = srcMesh->m_vertexPositionsPostTransform;
+    this->m_pointDataMap        = srcMesh->m_pointDataMap;
+    this->m_topologyChanged     = srcMesh->m_topologyChanged;
+    this->m_loadFactor          = srcMesh->m_loadFactor;
+    this->m_maxNumVertices      = srcMesh->m_maxNumVertices;
+    this->m_originalNumVertices = srcMesh->m_originalNumVertices;
+
+    this->m_type = srcMesh->m_type;
+    this->m_name = srcMesh->m_name;
+    this->m_geometryIndex     = srcMesh->m_geometryIndex;
+    this->m_dataModified      = srcMesh->m_dataModified;
+    this->m_transformModified = srcMesh->m_transformModified;
+    this->m_transformApplied  = srcMesh->m_transformApplied;
+    this->m_transform = srcMesh->m_transform;
+    this->m_scaling   = srcMesh->m_scaling;
+}
+
 }  // namespace imstk
diff --git a/Source/Geometry/Mesh/imstkSurfaceMesh.h b/Source/Geometry/Mesh/imstkSurfaceMesh.h
index b6bc85b9a26161a64fb0554fd6a218840b55b33c..68fa61e4f742ba4fa3fdb318e5dfe4aa5c969fc1 100644
--- a/Source/Geometry/Mesh/imstkSurfaceMesh.h
+++ b/Source/Geometry/Mesh/imstkSurfaceMesh.h
@@ -20,14 +20,10 @@
 =========================================================================*/
 
 #pragma once
-
-// std library
+#include "imstkPointSet.h"
 #include <array>
 #include <set>
 
-// imstk
-#include "imstkPointSet.h"
-
 namespace imstk
 {
 ///
@@ -218,9 +214,13 @@ public:
     void directionalScale(const double s_x, const double s_y, const double s_z);
 
 protected:
-
     friend class VTKSurfaceMeshRenderDelegate;
 
+    /// \brief Copy the contents of one SurfaceMesh to the other
+    /// \todo: generalize base classes and implement for every geometry
+    ///
+    void deepCopy(std::shared_ptr<SurfaceMesh> srcMesh);
+
     ///
     /// \brief Get vertex normals
     ///
diff --git a/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp b/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp
index 28ec30178c8d9e6a291a97588b53ef8cdd1ae4b2..5903707283663dbe86f7dec0cde8f92101b70881 100644
--- a/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp
+++ b/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp
@@ -21,7 +21,6 @@
 
 #include "imstkTetrahedralMesh.h"
 #include "imstkSurfaceMesh.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkLogger.h"
 
 namespace imstk
diff --git a/Source/Geometry/Mesh/imstkVolumetricMesh.cpp b/Source/Geometry/Mesh/imstkVolumetricMesh.cpp
index c05f409b2a3975b615d12c9f014bfe6e2ffa4a02..163a29305ec95a0533992378bd313a2c08c1d339 100644
--- a/Source/Geometry/Mesh/imstkVolumetricMesh.cpp
+++ b/Source/Geometry/Mesh/imstkVolumetricMesh.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkVolumetricMesh.h"
-#include "imstkSurfaceMesh.h"
 #include "imstkLogger.h"
 
 namespace imstk
diff --git a/Source/Geometry/Mesh/imstkVolumetricMesh.h b/Source/Geometry/Mesh/imstkVolumetricMesh.h
index 6b383f7cf1d8d49cd6fe69519998079c1f8cdda6..7ad12819c363af8ff59467fb2f13bedbc10d5d15 100644
--- a/Source/Geometry/Mesh/imstkVolumetricMesh.h
+++ b/Source/Geometry/Mesh/imstkVolumetricMesh.h
@@ -22,7 +22,6 @@
 #pragma once
 
 #include "imstkPointSet.h"
-
 #include <memory>
 
 namespace imstk
diff --git a/Source/Geometry/Particles/imstkRenderParticles.cpp b/Source/Geometry/Particles/imstkRenderParticles.cpp
index 44940b52bbbe5aed0349a1b7f2e240b6151ec96d..91abd01cfb15b61d36c6840114ff2808fee572c3 100644
--- a/Source/Geometry/Particles/imstkRenderParticles.cpp
+++ b/Source/Geometry/Particles/imstkRenderParticles.cpp
@@ -20,7 +20,7 @@
 =========================================================================*/
 
 #include "imstkRenderParticles.h"
-#include "imstkTimer.h"
+#include "imstkLogger.h"
 
 namespace imstk
 {
@@ -93,19 +93,19 @@ RenderParticles::getMaxNumParticles()
 }
 
 void
-RenderParticles::applyTranslation(const Vec3d t)
+RenderParticles::applyTranslation(const Vec3d imstkNotUsed(t))
 {
     LOG(WARNING) << "applyTranslation Not implemented!";
 }
 
 void
-RenderParticles::applyRotation(const Mat3d r)
+RenderParticles::applyRotation(const Mat3d imstkNotUsed(r))
 {
     LOG(WARNING) << "applyRotation Not implemented!";
 }
 
 void
-RenderParticles::applyScaling(const double s)
+RenderParticles::applyScaling(const double imstkNotUsed(s))
 {
     LOG(WARNING) << "applyScaling Not implemented!";
 }
diff --git a/Source/Geometry/Particles/imstkRenderParticles.h b/Source/Geometry/Particles/imstkRenderParticles.h
index 7199f0ff7b31d356f25ca7179d4986f542f0216c..45ec493781f699544f7c4c732327f0aa3ca1e697 100644
--- a/Source/Geometry/Particles/imstkRenderParticles.h
+++ b/Source/Geometry/Particles/imstkRenderParticles.h
@@ -21,15 +21,14 @@
 
 #pragma once
 
+#include "imstkGeometry.h"
+#include "imstkMath.h"
+
 #pragma warning( push )
 #pragma warning( disable : 4201 )
-#include "glm/glm.hpp"
+#include <glm/glm.hpp>
 #pragma warning( pop )
 
-#include "imstkGeometry.h"
-#include "imstkMath.h"
-//#include "imstkColor.h"
-
 namespace imstk
 {
 ///
diff --git a/Source/Geometry/Testing/imstkCubeTest.cpp b/Source/Geometry/Testing/imstkCubeTest.cpp
index d317df1e162c2936b73a697c6f4800825427eff3..e1b384c1b67dafff2155376db690a5ef95c7f533 100644
--- a/Source/Geometry/Testing/imstkCubeTest.cpp
+++ b/Source/Geometry/Testing/imstkCubeTest.cpp
@@ -20,10 +20,9 @@
 =========================================================================*/
 
 #include "gtest/gtest.h"
-#include "gmock/gmock.h"
 
-#include "imstkMath.h"
 #include "imstkCube.h"
+
 using namespace imstk;
 
 class imstkCubeTest : public ::testing::Test
diff --git a/Source/Geometry/Testing/imstkGeometryTest.cpp b/Source/Geometry/Testing/imstkGeometryTest.cpp
index 834996391ea245cf21b063d00f178ca4390350ba..db4679aacbde24f7ac0e0b6892b56e3dc79c9729 100644
--- a/Source/Geometry/Testing/imstkGeometryTest.cpp
+++ b/Source/Geometry/Testing/imstkGeometryTest.cpp
@@ -20,9 +20,7 @@
 =========================================================================*/
 
 #include "gtest/gtest.h"
-#include "gmock/gmock.h"
 
-#include "imstkMath.h"
 #include "imstkPlane.h"
 
 using namespace imstk;
diff --git a/Source/Geometry/Testing/imstkPlaneTest.cpp b/Source/Geometry/Testing/imstkPlaneTest.cpp
index 7d50d6a08e453defd0b1097e88570919103f79ac..579de4a2a641496671b715dc5a445961645e8630 100644
--- a/Source/Geometry/Testing/imstkPlaneTest.cpp
+++ b/Source/Geometry/Testing/imstkPlaneTest.cpp
@@ -20,10 +20,9 @@
 =========================================================================*/
 
 #include "gtest/gtest.h"
-#include "gmock/gmock.h"
 
-#include "imstkMath.h"
 #include "imstkPlane.h"
+
 using namespace imstk;
 
 ///
diff --git a/Source/Geometry/Testing/imstkSphereTest.cpp b/Source/Geometry/Testing/imstkSphereTest.cpp
index 38fc48c358fba5aee70cff0bbd183cc2683d1791..48de88d1dec9241842a6b3a584ba1b038e96999a 100644
--- a/Source/Geometry/Testing/imstkSphereTest.cpp
+++ b/Source/Geometry/Testing/imstkSphereTest.cpp
@@ -20,10 +20,9 @@
 =========================================================================*/
 
 #include "gtest/gtest.h"
-#include "gmock/gmock.h"
 
-#include "imstkMath.h"
 #include "imstkSphere.h"
+
 using namespace imstk;
 
 ///
diff --git a/Source/Geometry/imstkGeometry.cpp b/Source/Geometry/imstkGeometry.cpp
index 3d56ecfde0073d3ff0e6595053ef4994330ff866..ee75622b96510f6ee15d18747210519ba0fb6644 100644
--- a/Source/Geometry/imstkGeometry.cpp
+++ b/Source/Geometry/imstkGeometry.cpp
@@ -203,6 +203,12 @@ Geometry::setRotation(const Mat3d m)
     m_transformApplied   = false;
 }
 
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+#define GLM_ENABLE_EXPERIMENTAL
+#include <glm/gtx/matrix_decompose.hpp>
+#include <glm/gtx/quaternion.hpp>
+
 void
 Geometry::setRotation(const Quatd q)
 {
@@ -243,6 +249,7 @@ Geometry::getType() const
 const std::string
 Geometry::getTypeName() const
 {
+    // /todo: create an actual object factory
     switch (m_type)
     {
     case Type::Plane: return "Plane";
@@ -259,6 +266,8 @@ Geometry::getTypeName() const
     case Type::DecalPool: return "DecalPool";
     case Type::RenderParticles: return "RenderParticles";
     case Type::ImageData: return "ImageData";
+    case Type::SignedDistanceField: return "SignedDistanceField";
+    case Type::CompositeImplicitGeometry: return "CompositeImplicitGeometry";
     default:
         LOG(FATAL) << "Mesh type to string has not been completely implemented";
         return "";
diff --git a/Source/Geometry/imstkGeometry.h b/Source/Geometry/imstkGeometry.h
index 038dc8bffa68e05b9b26b1272379b0a803153bb7..af11def3f15739c555a161fd37e40c2c54ff56b9 100644
--- a/Source/Geometry/imstkGeometry.h
+++ b/Source/Geometry/imstkGeometry.h
@@ -21,7 +21,9 @@
 
 #pragma once
 
+#include "imstkEventObject.h"
 #include "imstkMath.h"
+#include "imstkTypes.h"
 
 #include <tbb/concurrent_unordered_set.h>
 
@@ -36,7 +38,7 @@ class SpinLock;
 /// \class Geometry
 /// \brief Base class for any geometrical representation
 ///
-class Geometry
+class Geometry : public EventObject
 {
 public:
     ///
@@ -57,7 +59,9 @@ public:
         Decal,
         DecalPool,
         RenderParticles,
-        ImageData
+        ImageData,
+        SignedDistanceField,
+        CompositeImplicitGeometry
     };
 
     ///
@@ -90,7 +94,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    virtual ~Geometry();
+    virtual ~Geometry() override;
 
     ///
     /// \brief Print
@@ -100,10 +104,11 @@ public:
     ///
     /// \brief Returns the volume of the geometry (if valid)
     ///
-    virtual double getVolume() const = 0;
+    virtual double getVolume() const { return 0.0; };
 
     ///
     /// \brief Compute the bounding box for the geometry
+    /// \todo Padding should not be here
     ///
     virtual void computeBoundingBox(Vec3d& lowerCorner, Vec3d& upperCorner, const double paddingPercent = 0.0) const;
 
@@ -181,6 +186,13 @@ public:
     ///
     static uint32_t getTotalNumberGeometries() { return s_NumGeneratedGegometries; }
 
+    ///
+    /// \brief Post modified event
+    ///
+    void modified() { this->postEvent(Event(EventType::Modified)); }
+
+    virtual void updatePostTransformData() const { }
+
 protected:
     ///
     /// \brief Get a unique ID for the new generated geometry object
@@ -204,20 +216,20 @@ protected:
     friend class VulkanRenderDelegate;
     friend class VulkanRenderer;
 
-    virtual void applyTranslation(const Vec3d t) = 0;
-    virtual void applyRotation(const Mat3d r)    = 0;
-    virtual void applyScaling(const double s)    = 0;
-    virtual void updatePostTransformData() const = 0;
+    virtual void applyTranslation(const Vec3d imstkNotUsed(t)) { }
+    virtual void applyRotation(const Mat3d imstkNotUsed(r)) { }
+    virtual void applyScaling(const double imstkNotUsed(s)) { }
 
     Type m_type;                 ///> Type of geometry
     std::string m_name;          ///> Unique name for each geometry
     uint32_t    m_geometryIndex; ///> Unique ID assigned to each geometry upon construction
 
-    bool m_dataModified      = false;
     bool m_transformModified = false;
     mutable bool m_transformApplied = true;
 
     RigidTransform3d m_transform; ///> Transformation matrix
     double m_scaling = 1.0;
+
+    bool m_dataModified = true;
 };
 } //imstk
diff --git a/Source/Geometry/imstkGeometryUtilities.cpp b/Source/Geometry/imstkGeometryUtilities.cpp
index 7ee553d0f0da636cea10168ab2c19244020fd950..6a7508325e324abdd755527645776a55ae4f4458 100644
--- a/Source/Geometry/imstkGeometryUtilities.cpp
+++ b/Source/Geometry/imstkGeometryUtilities.cpp
@@ -20,33 +20,197 @@
 =========================================================================*/
 
 #include "imstkGeometryUtilities.h"
+#include "imstkDataArray.h"
 #include "imstkHexahedralMesh.h"
+#include "imstkImageData.h"
 #include "imstkLineMesh.h"
-#include "imstkPointSet.h"
+#include "imstkLogger.h"
+#include "imstkParallelUtils.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkTetrahedralMesh.h"
+#include "imstkCube.h"
+#include "imstkSphere.h"
 
 #include <vtkAppendPolyData.h>
-#include <vtkCleanPolyData.h>
-#include <vtkDataSet.h>
-#include <vtkPolyData.h>
-#include <vtkPointSet.h>
-#include <vtkExtractEdges.h>
-#include <vtkLinearSubdivisionFilter.h>
-#include <vtkLoopSubdivisionFilter.h>
+#include <vtkCharArray.h>
+#include <vtkCubeSource.h>
+#include <vtkDoubleArray.h>
+#include <vtkFeatureEdges.h>
+#include <vtkFloatArray.h>
+#include <vtkImageData.h>
+#include <vtkMassProperties.h>
 #include <vtkPointData.h>
-#include <vtkSelectEnclosedPoints.h>
-#include <vtkSmoothPolyDataFilter.h>
+#include <vtkShortArray.h>
+#include <vtkSphereSource.h>
+#include <vtkTransform.h>
+#include <vtkTransformFilter.h>
 #include <vtkTriangleFilter.h>
-#include <vtkUnstructuredGrid.h>
 #include <vtkUnsignedCharArray.h>
+#include <vtkUnsignedIntArray.h>
+#include <vtkUnsignedLongArray.h>
+#include <vtkUnsignedShortArray.h>
+#include <vtkUnstructuredGrid.h>
+
+static vtkSmartPointer<vtkDataArray>
+makeVtkDataArray(unsigned char type)
+{
+    vtkSmartPointer<vtkDataArray> arr = nullptr;
+    switch (type)
+    {
+    case VTK_CHAR:
+        arr = vtkSmartPointer<vtkCharArray>::New();
+        break;
+    case VTK_UNSIGNED_CHAR:
+        arr = vtkSmartPointer<vtkUnsignedCharArray>::New();
+        break;
+    case VTK_SHORT:
+        arr = vtkSmartPointer<vtkShortArray>::New();
+        break;
+    case VTK_UNSIGNED_SHORT:
+        arr = vtkSmartPointer<vtkUnsignedShortArray>::New();
+        break;
+    case VTK_INT:
+        arr = vtkSmartPointer<vtkIntArray>::New();
+        break;
+    case VTK_UNSIGNED_INT:
+        arr = vtkSmartPointer<vtkUnsignedIntArray>::New();
+        break;
+    case VTK_FLOAT:
+        arr = vtkSmartPointer<vtkFloatArray>::New();
+        break;
+    case VTK_DOUBLE:
+        arr = vtkSmartPointer<vtkDoubleArray>::New();
+        break;
+    case VTK_LONG_LONG:
+        arr = vtkSmartPointer<vtkLongLongArray>::New();
+        break;
+    case VTK_UNSIGNED_LONG_LONG:
+        arr = vtkSmartPointer<vtkUnsignedLongArray>::New();
+        break;
+    default:
+        LOG(WARNING) << "Unknown scalar type";
+        break;
+    }
+    ;
+    return arr;
+}
 
 #include <vtkFloatArray.h>
 
 namespace imstk
 {
+vtkSmartPointer<vtkDataArray>
+GeometryUtils::coupleVtkDataArray(std::shared_ptr<AbstractDataArray> imstkArray)
+{
+    CHECK(imstkArray != nullptr) << "AbstractDataArray provided is not valid!";
+    CHECK(imstkArray->getVoidPointer() != nullptr) << "AbstractDataArray data provided is not valid!";
+
+    // Create corresponding data array
+    vtkSmartPointer<vtkDataArray> arr = makeVtkDataArray(imstkToVtkScalarType[imstkArray->getScalarType()]);
+    arr->SetVoidArray(imstkArray->getVoidPointer(), imstkArray->size(), 1);
+
+    return arr;
+}
+
+vtkSmartPointer<vtkImageData>
+GeometryUtils::coupleVtkImageData(std::shared_ptr<ImageData> imageData)
+{
+    CHECK(imageData != nullptr) << "ImageData provided is not valid!";
+
+    // VTK puts center of min voxel at origin of world space, we put min of bot voxel at origin
+    std::shared_ptr<AbstractDataArray> arr    = imageData->getScalars();
+    vtkSmartPointer<vtkDataArray>      vtkArr = coupleVtkDataArray(arr);
+
+    vtkSmartPointer<vtkImageData> imageDataVtk = vtkSmartPointer<vtkImageData>::New();
+    imageDataVtk->SetDimensions(imageData->getDimensions().data());
+    imageDataVtk->SetSpacing(imageData->getSpacing().data());
+    const Vec3d vtkOrigin = imageData->getOrigin() + imageData->getSpacing() * 0.5;
+    imageDataVtk->SetOrigin(vtkOrigin.data());
+    imageDataVtk->SetNumberOfScalarComponents(imageData->getNumComponents(), imageDataVtk->GetInformation());
+    imageDataVtk->SetScalarType(imstkToVtkScalarType[arr->getScalarType()], imageDataVtk->GetInformation());
+    imageDataVtk->GetPointData()->SetScalars(vtkArr);
+    return imageDataVtk;
+}
+
+vtkSmartPointer<vtkDataArray>
+GeometryUtils::copyToVtkDataArray(std::shared_ptr<AbstractDataArray> imstkArray, int numComps)
+{
+    CHECK(imstkArray != nullptr) << "AbstractDataArray provided is not valid!";
+
+    // Create resulting data array
+    vtkSmartPointer<vtkDataArray> arr = makeVtkDataArray(imstkToVtkScalarType[imstkArray->getScalarType()]);
+    arr->SetNumberOfComponents(numComps);
+    arr->SetNumberOfValues(imstkArray->size());
+    switch (imstkArray->getScalarType())
+    {
+        TemplateMacro(std::copy_n(static_cast<IMSTK_TT*>(imstkArray->getVoidPointer()), imstkArray->size(), static_cast<IMSTK_TT*>(arr->GetVoidPointer(0))); );
+    default:
+        LOG(WARNING) << "Unknown scalar type";
+        break;
+    }
+
+    return arr;
+}
+
+std::shared_ptr<AbstractDataArray>
+GeometryUtils::copyToDataArray(vtkSmartPointer<vtkDataArray> vtkArray)
+{
+    CHECK(vtkArray != nullptr) << "vtkDataArray provided is not valid!";
+
+    std::shared_ptr<AbstractDataArray> arr = nullptr;
+
+    // Create and copy the array
+    switch (vtkToImstkScalarType[vtkArray->GetDataType()])
+    {
+        TemplateMacro(arr = std::make_shared<DataArray<IMSTK_TT>>(vtkArray->GetNumberOfValues());
+            std::copy_n(static_cast<IMSTK_TT*>(vtkArray->GetVoidPointer(0)), vtkArray->GetNumberOfValues(), static_cast<IMSTK_TT*>(arr->getVoidPointer())); );
+    default:
+        LOG(WARNING) << "Unknown scalar type";
+        break;
+    }
+    return arr;
+}
+
+std::unique_ptr<ImageData>
+GeometryUtils::copyToImageData(vtkSmartPointer<vtkImageData> vtkImage)
+{
+    CHECK(vtkImage != nullptr) << "vtkImageData provided is not valid!";
+
+    double*     spacingPtr = vtkImage->GetSpacing();
+    const Vec3d spacing    = Vec3d(spacingPtr[0], spacingPtr[1], spacingPtr[2]);
+    // vtk origin is not bounds and vtk origin is not actual origin
+    double* bounds = vtkImage->GetBounds();
+    // image data origin starts at center of first voxel
+    const Vec3d origin = Vec3d(bounds[0], bounds[2], bounds[4]) - spacing * 0.5;
+
+    std::unique_ptr<ImageData> imageData = std::make_unique<ImageData>();
+    imageData->setScalars(copyToDataArray(vtkImage->GetPointData()->GetScalars()),
+        vtkImage->GetNumberOfScalarComponents(), vtkImage->GetDimensions());
+    imageData->setSpacing(spacing);
+    imageData->setOrigin(origin);
+    return imageData;
+}
+
+vtkSmartPointer<vtkImageData>
+GeometryUtils::copyToVtkImageData(std::shared_ptr<ImageData> imageData)
+{
+    CHECK(imageData != nullptr) << "ImageData provided is not valid!";
+
+    // Our image data does not use vtk extents
+    const Vec3i& dim = imageData->getDimensions();
+
+    vtkSmartPointer<vtkImageData> imageDataVtk = vtkSmartPointer<vtkImageData>::New();
+    imageDataVtk->SetSpacing(imageData->getSpacing().data());
+    const Vec3d vtkOrigin = imageData->getOrigin() + imageData->getSpacing() * 0.5;
+    imageDataVtk->SetOrigin(vtkOrigin.data());
+    imageDataVtk->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1);
+    imageDataVtk->AllocateScalars(imstkToVtkScalarType[imageData->getScalarType()], imageData->getNumComponents());
+    imageDataVtk->GetPointData()->SetScalars(copyToVtkDataArray(imageData->getScalars(), imageData->getNumComponents()));
+    return imageDataVtk;
+}
+
 std::unique_ptr<PointSet>
-GeometryUtils::convertVtkPointSetToPointSet(const vtkSmartPointer<vtkPointSet> vtkMesh)
+GeometryUtils::copyToPointSet(vtkSmartPointer<vtkPointSet> vtkMesh)
 {
     CHECK(vtkMesh != nullptr) << "vtkPolyData provided is not valid!";
 
@@ -68,7 +232,7 @@ GeometryUtils::convertVtkPointSetToPointSet(const vtkSmartPointer<vtkPointSet> v
 }
 
 std::unique_ptr<SurfaceMesh>
-GeometryUtils::convertVtkPolyDataToSurfaceMesh(const vtkSmartPointer<vtkPolyData> vtkMesh)
+GeometryUtils::copyToSurfaceMesh(vtkSmartPointer<vtkPolyData> vtkMesh)
 {
     CHECK(vtkMesh != nullptr) << "vtkPolyData provided is not valid!";
 
@@ -102,7 +266,7 @@ GeometryUtils::convertVtkPolyDataToSurfaceMesh(const vtkSmartPointer<vtkPolyData
 }
 
 std::unique_ptr<LineMesh>
-GeometryUtils::convertVtkPolyDataToLineMesh(const vtkSmartPointer<vtkPolyData> vtkMesh)
+GeometryUtils::copyToLineMesh(vtkSmartPointer<vtkPolyData> vtkMesh)
 {
     CHECK(vtkMesh != nullptr) << "vtkPolyData provided is not valid!";
 
@@ -127,7 +291,7 @@ GeometryUtils::convertVtkPolyDataToLineMesh(const vtkSmartPointer<vtkPolyData> v
 }
 
 vtkSmartPointer<vtkPointSet>
-GeometryUtils::convertPointSetToVtkPointSet(const std::shared_ptr<PointSet> imstkMesh)
+GeometryUtils::copyToVtkPointSet(std::shared_ptr<PointSet> imstkMesh)
 {
     vtkNew<vtkPoints> points;
     copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get());
@@ -138,7 +302,7 @@ GeometryUtils::convertPointSetToVtkPointSet(const std::shared_ptr<PointSet> imst
 }
 
 vtkSmartPointer<vtkPolyData>
-GeometryUtils::convertLineMeshToVtkPolyData(const std::shared_ptr<LineMesh> imstkMesh)
+GeometryUtils::copyToVtkPolyData(std::shared_ptr<LineMesh> imstkMesh)
 {
     vtkNew<vtkPoints> points;
     copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get());
@@ -153,7 +317,7 @@ GeometryUtils::convertLineMeshToVtkPolyData(const std::shared_ptr<LineMesh> imst
 }
 
 vtkSmartPointer<vtkPolyData>
-GeometryUtils::convertSurfaceMeshToVtkPolyData(const std::shared_ptr<SurfaceMesh> imstkMesh)
+GeometryUtils::copyToVtkPolyData(std::shared_ptr<SurfaceMesh> imstkMesh)
 {
     vtkNew<vtkPoints> points;
     copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get());
@@ -169,7 +333,7 @@ GeometryUtils::convertSurfaceMeshToVtkPolyData(const std::shared_ptr<SurfaceMesh
 }
 
 vtkSmartPointer<vtkUnstructuredGrid>
-GeometryUtils::convertTetrahedralMeshToVtkUnstructuredGrid(const std::shared_ptr<TetrahedralMesh> imstkMesh)
+GeometryUtils::copyToVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> imstkMesh)
 {
     vtkNew<vtkPoints> points;
     copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get());
@@ -205,7 +369,7 @@ GeometryUtils::convertTetrahedralMeshToVtkUnstructuredGrid(const std::shared_ptr
 }
 
 vtkSmartPointer<vtkUnstructuredGrid>
-GeometryUtils::convertHexahedralMeshToVtkUnstructuredGrid(const std::shared_ptr<HexahedralMesh> imstkMesh)
+GeometryUtils::copyToVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> imstkMesh)
 {
     vtkNew<vtkPoints> points;
     copyVerticesToVtk(imstkMesh->getVertexPositions(), points.Get());
@@ -220,7 +384,7 @@ GeometryUtils::convertHexahedralMeshToVtkUnstructuredGrid(const std::shared_ptr<
 }
 
 std::unique_ptr<VolumetricMesh>
-GeometryUtils::convertVtkUnstructuredGridToVolumetricMesh(vtkSmartPointer<vtkUnstructuredGrid> vtkMesh)
+GeometryUtils::copyToVolumetricMesh(vtkSmartPointer<vtkUnstructuredGrid> vtkMesh)
 {
     CHECK(vtkMesh != nullptr) << "vtkUnstructuredGrid provided is not valid!";
 
@@ -327,8 +491,12 @@ GeometryUtils::copyPointDataFromVtk(vtkPointData* const pointData, std::map<std:
 
     for (int i = 0; i < pointData->GetNumberOfArrays(); ++i)
     {
-        vtkDataArray*      array       = pointData->GetArray(i);
-        std::string        name        = array->GetName();
+        vtkDataArray* array = pointData->GetArray(i);
+        std::string   name  = "";
+        if (array->GetName() != NULL)
+        {
+            name = array->GetName();
+        }
         int                nbrOfComp   = array->GetNumberOfComponents();
         vtkIdType          nbrOfTuples = array->GetNumberOfTuples();
         StdVectorOfVectorf data;
@@ -347,126 +515,66 @@ GeometryUtils::copyPointDataFromVtk(vtkPointData* const pointData, std::map<std:
     }
 }
 
-std::unique_ptr<SurfaceMesh>
-GeometryUtils::combineSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh1, std::shared_ptr<SurfaceMesh> surfaceMesh2)
+std::shared_ptr<SurfaceMesh>
+GeometryUtils::toCubeSurfaceMesh(std::shared_ptr<Cube> cube)
 {
-    vtkNew<vtkAppendPolyData> filter;
-    filter->AddInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh1));
-    filter->AddInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh2));
-    filter->Update();
-
-    return convertVtkPolyDataToSurfaceMesh(filter->GetOutput());
+    vtkNew<vtkCubeSource> cubeSource;
+    cubeSource->SetCenter(cube->getPosition(Geometry::DataType::PreTransform).data());
+    cubeSource->SetXLength(cube->getWidth());
+    cubeSource->SetYLength(cube->getWidth());
+    cubeSource->SetZLength(cube->getWidth());
+    cubeSource->Update();
+
+    Mat4d mat;
+    mat.setIdentity();
+    mat.block<3, 3>(0, 0) = cube->getRotation();
+
+    vtkNew<vtkTransform> transform;
+    transform->SetMatrix(mat.data());
+
+    vtkNew<vtkTransformFilter> transformCube;
+    transformCube->SetInputData(cubeSource->GetOutput());
+    transformCube->SetTransform(transform);
+    transformCube->Update();
+    vtkNew<vtkTriangleFilter> triangulate;
+    triangulate->SetInputData(transformCube->GetOutput());
+    triangulate->Update();
+    return copyToSurfaceMesh(triangulate->GetOutput());
 }
 
-std::unique_ptr<LineMesh>
-GeometryUtils::surfaceMeshToLineMesh(std::shared_ptr<SurfaceMesh> surfaceMesh)
+std::shared_ptr<SurfaceMesh>
+GeometryUtils::toUVSphereSurfaceMesh(std::shared_ptr<Sphere> sphere,
+                                     const unsigned int phiDivisions, const unsigned int thetaDivisions)
 {
-    vtkNew<vtkExtractEdges> filter;
-    filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh));
-    filter->Update();
-
-    vtkNew<vtkTriangleFilter> triangleFilter;
-    triangleFilter->SetInputData(filter->GetOutput());
-    triangleFilter->Update();
-
-    return convertVtkPolyDataToLineMesh(triangleFilter->GetOutput());
+    vtkNew<vtkSphereSource> sphereSource;
+    sphereSource->SetCenter(sphere->getPosition(Geometry::DataType::PreTransform).data());
+    sphereSource->SetRadius(sphere->getRadius());
+    sphereSource->SetPhiResolution(phiDivisions);
+    sphereSource->SetThetaResolution(thetaDivisions);
+    sphereSource->Update();
+
+    return copyToSurfaceMesh(sphereSource->GetOutput());
 }
 
-std::unique_ptr<SurfaceMesh>
-GeometryUtils::cleanSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh)
+int
+GeometryUtils::getOpenEdgeCount(std::shared_ptr<SurfaceMesh> surfMesh)
 {
-    vtkNew<vtkCleanPolyData> filter;
-    filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh));
-    filter->Update();
-    return convertVtkPolyDataToSurfaceMesh(filter->GetOutput());
+    vtkNew<vtkFeatureEdges> checkClosed;
+    checkClosed->SetInputData(GeometryUtils::copyToVtkPolyData(surfMesh));
+    checkClosed->FeatureEdgesOff();
+    checkClosed->BoundaryEdgesOn();
+    checkClosed->NonManifoldEdgesOn();
+    checkClosed->Update();
+    return checkClosed->GetOutput()->GetNumberOfCells();
 }
 
-std::unique_ptr<PointSet>
-GeometryUtils::getEnclosedPoints(std::shared_ptr<SurfaceMesh> surfaceMesh, std::shared_ptr<PointSet> pointSet, bool insideOut)
+double
+GeometryUtils::getVolume(std::shared_ptr<SurfaceMesh> surfMesh)
 {
-    vtkNew<vtkSelectEnclosedPoints> filter;
-    filter->SetInputData(convertPointSetToVtkPointSet(pointSet));
-    filter->SetSurfaceData(convertSurfaceMeshToVtkPolyData(surfaceMesh));
-    filter->SetTolerance(0.0);
-    filter->SetInsideOut(insideOut);
-    filter->Update();
-    vtkSmartPointer<vtkPointSet> vtkResults = vtkPointSet::SafeDownCast(filter->GetOutput());
-
-    StdVectorOfVec3d points;
-    points.reserve(vtkResults->GetNumberOfPoints());
-    for (vtkIdType i = 0; i < vtkResults->GetNumberOfPoints(); i++)
-    {
-        if (filter->IsInside(i))
-        {
-            double pt[3];
-            vtkResults->GetPoint(i, pt);
-            points.push_back(Vec3d(pt[0], pt[1], pt[2]));
-        }
-    }
-    points.shrink_to_fit();
-
-    std::unique_ptr<PointSet> results = std::make_unique<PointSet>();
-    results->setInitialVertexPositions(points);
-    results->setVertexPositions(points);
-    return results;
-}
-
-void
-GeometryUtils::testEnclosedPoints(std::vector<bool>& results, std::shared_ptr<SurfaceMesh> surfaceMesh, std::shared_ptr<PointSet> pointSet, const bool insideOut)
-{
-    vtkNew<vtkSelectEnclosedPoints> filter;
-    filter->SetInputData(convertPointSetToVtkPointSet(pointSet));
-    filter->SetSurfaceData(convertSurfaceMeshToVtkPolyData(surfaceMesh));
-    filter->SetTolerance(0.0);
-    filter->SetInsideOut(insideOut);
-    filter->Update();
-    vtkUnsignedCharArray* arr = vtkUnsignedCharArray::SafeDownCast(filter->GetOutput()->GetPointData()->GetArray("SelectedPoints"));
-
-    results.resize(arr->GetNumberOfValues());
-    for (vtkIdType i = 0; i < arr->GetNumberOfValues(); i++)
-    {
-        results[i] = (arr->GetValue(i) ? true : false);
-    }
-}
-
-std::unique_ptr<SurfaceMesh>
-GeometryUtils::smoothSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh,
-                                 const smoothPolydataConfig&  c)
-{
-    vtkNew<vtkSmoothPolyDataFilter> filter;
-    filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh));
-    filter->SetNumberOfIterations(c.numberOfIterations);
-    filter->SetRelaxationFactor(c.relaxationFactor);
-    filter->SetConvergence(c.convergence);
-    filter->SetFeatureAngle(c.featureAngle);
-    filter->SetEdgeAngle(c.edgeAngle);
-    filter->SetFeatureEdgeSmoothing(c.featureEdgeSmoothing);
-    filter->SetBoundarySmoothing(c.boundarySmoothing);
-    filter->Update();
-
-    return convertVtkPolyDataToSurfaceMesh(filter->GetOutput());
-}
-
-std::unique_ptr<SurfaceMesh>
-GeometryUtils::linearSubdivideSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, const int numSubdivisions)
-{
-    vtkNew<vtkLinearSubdivisionFilter> filter;
-    filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh));
-    filter->SetNumberOfSubdivisions(numSubdivisions);
-    filter->Update();
-
-    return convertVtkPolyDataToSurfaceMesh(filter->GetOutput());
-}
-
-std::unique_ptr<SurfaceMesh>
-GeometryUtils::loopSubdivideSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, const int numSubdivisions)
-{
-    vtkNew<vtkLoopSubdivisionFilter> filter;
-    filter->SetInputData(convertSurfaceMeshToVtkPolyData(surfaceMesh));
-    filter->SetNumberOfSubdivisions(numSubdivisions);
-    filter->Update();
-
-    return convertVtkPolyDataToSurfaceMesh(filter->GetOutput());
+    vtkNew<vtkMassProperties> massProps;
+    massProps->SetInputData(copyToVtkPolyData(surfMesh));
+    massProps->Update();
+    return massProps->GetVolume();
 }
 
 namespace // anonymous namespace
@@ -864,7 +972,7 @@ markPointsInsideAndOut(std::vector<bool>&      isInside,
 
 ///
 /// \brief Given a set of uniformly spaced points, mark them as inside (true) and outside.
-/// It makes uses of ray-tracing but skips points based on the nearest distance between current point and the surface.
+/// It makes uses of ray-casting but skips points based on the nearest distance between current point and the surface.
 ///
 /// \param surfaceMesh a \ref SurfaceMesh
 /// \param coords a set of points to be tested
@@ -872,8 +980,6 @@ markPointsInsideAndOut(std::vector<bool>&      isInside,
 /// \param ny number of points in y-direction
 /// \param nz number of points in z-direction
 ///
-/// \note this function cannot be const because PointSet::computeBoundingBox, called inside, is not.
-///
 void
 markPointsInsideAndOut(std::vector<bool>&      isInside,
                        const SurfaceMesh&      surfaceMesh,
diff --git a/Source/Geometry/imstkGeometryUtilities.h b/Source/Geometry/imstkGeometryUtilities.h
index bfccaac1e99d30411354d339cc664e2db40ade31..9679eecd85098b3e572b72705729c34322b616b5 100644
--- a/Source/Geometry/imstkGeometryUtilities.h
+++ b/Source/Geometry/imstkGeometryUtilities.h
@@ -21,20 +21,21 @@
 
 #pragma once
 
-#include "imstkLogger.h"
 #include "imstkMath.h"
-#include "imstkParallelUtils.h"
-
-#include "vtkSmartPointer.h"
-
+#include "imstkTypes.h"
 #include <memory>
 #include <numeric>
 #include <queue>
-#include <unordered_set>
 #include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vtkSmartPointer.h>
+#include <vtkType.h>
 
+class vtkDataArray;
 class vtkCellArray;
 class vtkPolyData;
+class vtkImageData;
 class vtkPointData;
 class vtkPoints;
 class vtkPointSet;
@@ -42,6 +43,8 @@ class vtkUnstructuredGrid;
 
 namespace imstk
 {
+class AbstractDataArray;
+class ImageData;
 class HexahedralMesh;
 class LineMesh;
 class PointSet;
@@ -49,52 +52,113 @@ class SurfaceMesh;
 class TetrahedralMesh;
 class VolumetricMesh;
 
+class Cube;
+class Sphere;
+
+///
+/// \brief Contains a set of free functions for processing geometry
+/// also contains a set of conversion and coupling functions for VTK
+///
 namespace GeometryUtils
 {
+static std::unordered_map<int, ScalarType> vtkToImstkScalarType =
+{
+    { VTK_VOID, IMSTK_VOID },
+    { VTK_CHAR, IMSTK_CHAR },
+    { VTK_UNSIGNED_CHAR, IMSTK_UNSIGNED_CHAR },
+    { VTK_SHORT, IMSTK_SHORT },
+    { VTK_UNSIGNED_SHORT, IMSTK_UNSIGNED_SHORT },
+    { VTK_INT, IMSTK_INT },
+    { VTK_UNSIGNED_INT, IMSTK_UNSIGNED_INT },
+    { VTK_LONG, IMSTK_LONG },
+    { VTK_UNSIGNED_LONG, IMSTK_UNSIGNED_LONG },
+    { VTK_FLOAT, IMSTK_FLOAT },
+    { VTK_DOUBLE, IMSTK_DOUBLE },
+    { VTK_LONG_LONG, IMSTK_LONG_LONG },
+    { VTK_UNSIGNED_LONG_LONG, IMSTK_UNSIGNED_LONG_LONG }
+};
+static std::unordered_map<ScalarType, int> imstkToVtkScalarType =
+{
+    { IMSTK_VOID, VTK_VOID },
+    { IMSTK_CHAR, VTK_CHAR },
+    { IMSTK_UNSIGNED_CHAR, VTK_UNSIGNED_CHAR },
+    { IMSTK_SHORT, VTK_SHORT },
+    { IMSTK_UNSIGNED_SHORT, VTK_UNSIGNED_SHORT },
+    { IMSTK_INT, VTK_INT },
+    { IMSTK_UNSIGNED_INT, VTK_UNSIGNED_INT },
+    { IMSTK_LONG, VTK_LONG },
+    { IMSTK_UNSIGNED_LONG, VTK_UNSIGNED_LONG },
+    { IMSTK_FLOAT, VTK_FLOAT },
+    { IMSTK_DOUBLE, VTK_DOUBLE },
+    { IMSTK_LONG_LONG, VTK_LONG_LONG },
+    { IMSTK_UNSIGNED_LONG_LONG, VTK_UNSIGNED_LONG_LONG }
+};
+
+///
+/// \brief Coupling functions, these create vtk data objects that point to our data objects
+/// thus no copying is done here.
+///
+vtkSmartPointer<vtkDataArray> coupleVtkDataArray(std::shared_ptr<AbstractDataArray> imstkArray);
+vtkSmartPointer<vtkImageData> coupleVtkImageData(std::shared_ptr<ImageData> imstkImageData);
+
+///
+/// \brief Copy functions, these copy to/from vtk data objects
+///
+vtkSmartPointer<vtkDataArray> copyToVtkDataArray(std::shared_ptr<AbstractDataArray> imstkArray, int numComps = 1);
+std::shared_ptr<AbstractDataArray> copyToDataArray(vtkSmartPointer<vtkDataArray> vtkArray);
+
+std::unique_ptr<ImageData> copyToImageData(vtkSmartPointer<vtkImageData> imageDataVtk);
+vtkSmartPointer<vtkImageData> copyToVtkImageData(std::shared_ptr<ImageData> imageData);
+
 ///
 /// \brief Converts vtk polydata into a imstk point set
 ///
-std::unique_ptr<PointSet> convertVtkPointSetToPointSet(const vtkSmartPointer<vtkPointSet> vtkMesh);
+std::unique_ptr<PointSet> copyToPointSet(vtkSmartPointer<vtkPointSet> vtkMesh);
 
 ///
 /// \brief Converts vtk polydata into a imstk surface mesh
 ///
-std::unique_ptr<SurfaceMesh> convertVtkPolyDataToSurfaceMesh(const vtkSmartPointer<vtkPolyData> vtkMesh);
+std::unique_ptr<SurfaceMesh> copyToSurfaceMesh(vtkSmartPointer<vtkPolyData> vtkMesh);
 
 ///
 /// \brief Converts vtk polydata into a imstk surface mesh
 ///
-std::unique_ptr<LineMesh> convertVtkPolyDataToLineMesh(const vtkSmartPointer<vtkPolyData> vtkMesh);
+std::unique_ptr<LineMesh> copyToLineMesh(vtkSmartPointer<vtkPolyData> vtkMesh);
 
 ///
 /// \brief Get imstk volumetric mesh given vtkUnstructuredGrid as input
 ///
-std::unique_ptr<VolumetricMesh> convertVtkUnstructuredGridToVolumetricMesh(const vtkSmartPointer<vtkUnstructuredGrid> vtkMesh);
+std::unique_ptr<VolumetricMesh> copyToVolumetricMesh(vtkSmartPointer<vtkUnstructuredGrid> vtkMesh);
+
+///
+/// \brief Smart copy will try to tell the type of the input mesh to convert to imstk
+///
+//std::shared_ptr<PointSet> smartCopyToVtkPolyData(vtkSmartPointer<vtkPointSet> vtkMesh);
 
 ///
 /// \brief Converts imstk point set into a vtk polydata
 ///
-vtkSmartPointer<vtkPointSet> convertPointSetToVtkPointSet(const std::shared_ptr<PointSet> imstkMesh);
+vtkSmartPointer<vtkPointSet> copyToVtkPointSet(std::shared_ptr<PointSet> imstkMesh);
 
 ///
 /// \brief Converts imstk line mesh into a vtk polydata
 ///
-vtkSmartPointer<vtkPolyData> convertLineMeshToVtkPolyData(const std::shared_ptr<LineMesh> imstkMesh);
+vtkSmartPointer<vtkPolyData> copyToVtkPolyData(std::shared_ptr<LineMesh> imstkMesh);
 
 ///
 /// \brief Converts imstk surface mesh into a vtk polydata
 ///
-vtkSmartPointer<vtkPolyData> convertSurfaceMeshToVtkPolyData(const std::shared_ptr<SurfaceMesh> imstkMesh);
+vtkSmartPointer<vtkPolyData> copyToVtkPolyData(std::shared_ptr<SurfaceMesh> imstkMesh);
 
 ///
 /// \brief Converts imstk tetrahedral mesh into a vtk unstructured grid
 ///
-vtkSmartPointer<vtkUnstructuredGrid> convertTetrahedralMeshToVtkUnstructuredGrid(const std::shared_ptr<TetrahedralMesh> imstkMesh);
+vtkSmartPointer<vtkUnstructuredGrid> copyToVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> imstkMesh);
 
 ///
 /// \brief Converts imstk hexahedral mesh into a vtk unstructured grid
 ///
-vtkSmartPointer<vtkUnstructuredGrid> convertHexahedralMeshToVtkUnstructuredGrid(const std::shared_ptr<HexahedralMesh> imstkMesh);
+vtkSmartPointer<vtkUnstructuredGrid> copyToVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> imstkMesh);
 
 ///
 /// \brief Copy from vtk points to a imstk vertices array (StdVectorOfVec3d)
@@ -124,79 +188,34 @@ void copyCellsFromVtk(vtkCellArray* vtkCells, std::vector<std::array<size_t, dim
 void copyPointDataFromVtk(vtkPointData* const pointData, std::map<std::string, StdVectorOfVectorf>& dataMap);
 
 ///
-/// \brief Combines two input surface meshes
-/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkAppendPolyData.html#details">vtkAppendPolyData</a> class
-/// for more details
-///
-///
-std::unique_ptr<SurfaceMesh> combineSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh1, std::shared_ptr<SurfaceMesh> surfaceMesh2);
-
-///
-/// \brief Converts an imstk SurfaceMesh to a LineMesh, removing duplicate edges. Cell indices not preserved
+/// \brief Produces SurfaceMesh cube from imstkCube
 ///
-std::unique_ptr<LineMesh> surfaceMeshToLineMesh(std::shared_ptr<SurfaceMesh> surfaceMesh);
+std::shared_ptr<SurfaceMesh> toCubeSurfaceMesh(std::shared_ptr<Cube> cube);
 
 ///
-/// \brief Removes duplicate edges & points in poly data
-/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkCleanPolyData.html#details">vtkCleanPolyData</a> class
-/// for more details
+/// \brief UV sphere from imstkSphere
 ///
-std::unique_ptr<SurfaceMesh> cleanSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh);
+std::shared_ptr<SurfaceMesh> toUVSphereSurfaceMesh(std::shared_ptr<Sphere> sphere,
+                                                   const unsigned int phiDivisions, const unsigned int thetaDivisions);
 
 ///
-/// \brief Returns points in pointSet within the provided surfaceMesh
-/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkSelectEnclosedPoints.html#details">vtkSelectEnclosedPoints</a> class
-/// for more details
+/// \brief Returns the number of open edges, use to tell if manifold (==0)
 ///
-std::unique_ptr<PointSet> getEnclosedPoints(std::shared_ptr<SurfaceMesh> surfaceMesh, std::shared_ptr<PointSet> pointSet, const bool insideOut = false);
+int getOpenEdgeCount(std::shared_ptr<SurfaceMesh> surfMesh);
 
 ///
-/// \brief Returns array indicating if point is enclosed or not
-/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkSelectEnclosedPoints.html#details">vtkSelectEnclosedPoints</a> class
-/// for more details
-///
-void testEnclosedPoints(std::vector<bool>& results, std::shared_ptr<SurfaceMesh> surfaceMesh, std::shared_ptr<PointSet> pointSet, const bool insideOut = false);
-
+/// \brief Returns if the surface is closed or not
 ///
-/// \brief Reverse the winding of a SurfaceMesh
-/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkSelectEnclosedPoints.html#details">vtkSelectEnclosedPoints</a> class
-///
-
-///
-/// \brief Config for smooth polydata filter
-///
-struct smoothPolydataConfig
+inline bool
+isClosed(std::shared_ptr<SurfaceMesh> surfMesh)
 {
-    int numberOfIterations  = 20;
-    double relaxationFactor = 0.01;
-    double convergence      = 0.0;
-    double featureAngle     = 45.0;
-    double edgeAngle = 15.0;
-    bool featureEdgeSmoothing = false;
-    bool boundarySmoothing    = true;
-};
-
-///
-/// \brief Smooths a SurfaceMesh using laplacian smoothening
-/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkSmoothPolyDataFilter.html#details">vtkSmoothPolyDataFilter</a>
-/// for more details
-///
-std::unique_ptr<SurfaceMesh> smoothSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh,
-                                               const smoothPolydataConfig&  c);
-
-///
-/// \brief Sub-divdes a SurfaceMesh using linear subdivision
-/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkLinearSubdivisionFilter.html#details">vtk linear subdivision</a>
-/// for more details
-///
-std::unique_ptr<SurfaceMesh> linearSubdivideSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, const int numSubdivisions = 1);
+    return getOpenEdgeCount(surfMesh) == 0;
+}
 
 ///
-/// \brief Sub-divides an input imstk SurfaceMesh using loop subdivision algorithm
-/// Refer <a href="https://vtk.org/doc/nightly/html/classvtkLoopSubdivisionFilter.html#details">vtk loop subdivision</a>
-/// for more details
+/// \brief Returns volume estimate of closed SurfaceMesh
 ///
-std::unique_ptr<SurfaceMesh> loopSubdivideSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, const int numSubdivisions = 1);
+double getVolume(std::shared_ptr<SurfaceMesh> surfMesh);
 
 ///
 /// \brief Create a tetrahedral mesh based on a uniform Cartesian mesh
diff --git a/Source/GeometryMappers/imstkIsometricMap.h b/Source/GeometryMappers/imstkIsometricMap.h
index adf7f454a9527c17a58bc57350751a1c08263818..f097b17fb7d5d9243942cbf249c1168e7b2c6c89 100644
--- a/Source/GeometryMappers/imstkIsometricMap.h
+++ b/Source/GeometryMappers/imstkIsometricMap.h
@@ -47,7 +47,7 @@ public:
     /// \brief Constructor
     ///
     IsometricMap(std::shared_ptr<Geometry> master, std::shared_ptr<Geometry> slave) :
-        GeometryMap(GeometryMap::Type::Isometric),
+        GeometryMap(master, slave, GeometryMap::Type::Isometric),
         m_rigidTransform(RigidTransform3d::Identity())
     {}
 
diff --git a/Source/GeometryMappers/imstkOneToOneMap.cpp b/Source/GeometryMappers/imstkOneToOneMap.cpp
index 2a8a92b7ce2b2db342e9445654f18c4b0a70158e..3cc0e056c36f9ffdc24d01e58c5013eb31a6d152 100644
--- a/Source/GeometryMappers/imstkOneToOneMap.cpp
+++ b/Source/GeometryMappers/imstkOneToOneMap.cpp
@@ -24,10 +24,6 @@
 #include "imstkLogger.h"
 #include "imstkPointSet.h"
 
-#undef min
-#undef max
-#include <climits>
-
 namespace imstk
 {
 void
diff --git a/Source/GeometryMappers/imstkOneToOneMap.h b/Source/GeometryMappers/imstkOneToOneMap.h
index 8982eb7a48779fef2b895427e4032fe3e12ef2cc..c3e4f507d59b1f5f7b977e5415c9bba9d9bb93a2 100644
--- a/Source/GeometryMappers/imstkOneToOneMap.h
+++ b/Source/GeometryMappers/imstkOneToOneMap.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk
 #include "imstkGeometryMap.h"
 
 namespace imstk
diff --git a/Source/GeometryMappers/imstkTetraTriangleMap.cpp b/Source/GeometryMappers/imstkTetraTriangleMap.cpp
index b34db1489be385a716ec13373e5d4ce525271b3f..ffbc0e6e4f2db1ab4ab46e537471d48a41cabe9b 100644
--- a/Source/GeometryMappers/imstkTetraTriangleMap.cpp
+++ b/Source/GeometryMappers/imstkTetraTriangleMap.cpp
@@ -20,9 +20,10 @@
 =========================================================================*/
 
 #include "imstkTetraTriangleMap.h"
-#include "imstkSurfaceMesh.h"
-#include "imstkParallelUtils.h"
 #include "imstkLogger.h"
+#include "imstkParallelUtils.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkTetrahedralMesh.h"
 
 namespace imstk
 {
diff --git a/Source/GeometryMappers/imstkTetraTriangleMap.h b/Source/GeometryMappers/imstkTetraTriangleMap.h
index 8a75db015172c551e10cc6739d127e8370f86a28..1d1c3fa438ad24a63f9baed27105282714a96ca2 100644
--- a/Source/GeometryMappers/imstkTetraTriangleMap.h
+++ b/Source/GeometryMappers/imstkTetraTriangleMap.h
@@ -21,11 +21,8 @@
 
 #pragma once
 
-#include <limits>
-
-// imstk
 #include "imstkGeometryMap.h"
-#include "imstkTetrahedralMesh.h"
+#include <array>
 
 namespace imstk
 {
@@ -106,9 +103,9 @@ protected:
     ///
     size_t findClosestTetrahedron(const Vec3d& pos) const;
 
-    std::vector<TetrahedralMesh::WeightsArray> m_verticesWeights; ///> weights
+    std::vector<std::array<double, 4>> m_verticesWeights; ///> weights
 
-    std::vector<size_t> m_verticesEnclosingTetraId;               ///> Enclosing tetrahedra to interpolate the weights upon
+    std::vector<size_t> m_verticesEnclosingTetraId;       ///> Enclosing tetrahedra to interpolate the weights upon
 
     std::vector<Vec3d> m_bBoxMin;
     std::vector<Vec3d> m_bBoxMax;
diff --git a/Source/MeshIO/imstkAssimpMeshIO.cpp b/Source/MeshIO/imstkAssimpMeshIO.cpp
index 642d604dd8aee4fd8e352455784d6ab6b435e16d..1a2c14e22824cc6b03ede7c96e6b65c88bc90645 100644
--- a/Source/MeshIO/imstkAssimpMeshIO.cpp
+++ b/Source/MeshIO/imstkAssimpMeshIO.cpp
@@ -21,12 +21,13 @@
 
 #include "imstkAssimpMeshIO.h"
 #include "imstkLogger.h"
+#include "imstkMeshIO.h"
+#include "imstkSurfaceMesh.h"
 
-// assimp
-#include "assimp/Importer.hpp"
-#include "assimp/mesh.h"
-#include "assimp/scene.h"
-#include "assimp/postprocess.h"
+#include <assimp/Importer.hpp>
+#include <assimp/mesh.h>
+#include <assimp/postprocess.h>
+#include <assimp/scene.h>
 
 namespace imstk
 {
diff --git a/Source/MeshIO/imstkAssimpMeshIO.h b/Source/MeshIO/imstkAssimpMeshIO.h
index c921416be9fc5dd54a77c72ef5bcb1417d9cde27..7b720f72a1d3d3c4ffa0d87ae8e30c2bb3c0c41f 100644
--- a/Source/MeshIO/imstkAssimpMeshIO.h
+++ b/Source/MeshIO/imstkAssimpMeshIO.h
@@ -21,13 +21,14 @@
 
 #pragma once
 
-#include "imstkSurfaceMesh.h"
 #include "imstkMeshIO.h"
 
 struct aiMesh;
 
 namespace imstk
 {
+class SurfaceMesh;
+
 ///
 /// \class AssimpMeshIO
 ///
diff --git a/Source/MeshIO/imstkMSHMeshIO.cpp b/Source/MeshIO/imstkMSHMeshIO.cpp
index aaa879f956e8c18d51db46fcf617b3481a365d0a..f04fde53caf0c880faaf3cdc2d648d97211242c4 100644
--- a/Source/MeshIO/imstkMSHMeshIO.cpp
+++ b/Source/MeshIO/imstkMSHMeshIO.cpp
@@ -19,19 +19,12 @@
 
 =========================================================================*/
 
-#include <fstream>
-#include <iostream>
-#include <algorithm>
-#include <array>
-
 #include "imstkMSHMeshIO.h"
-#include "imstkTetrahedralMesh.h"
 #include "imstkHexahedralMesh.h"
-#include "imstkVolumetricMesh.h"
-
-#include "tetMesh.h"
-
 #include "imstkLogger.h"
+#include "imstkTetrahedralMesh.h"
+
+#include <fstream>
 
 namespace imstk
 {
diff --git a/Source/MeshIO/imstkMeshIO.cpp b/Source/MeshIO/imstkMeshIO.cpp
index 5245897c0764daf0571efd3b2e616ab5d8829c20..7938980bb812787fa2b42000f588ae163be7cf86 100644
--- a/Source/MeshIO/imstkMeshIO.cpp
+++ b/Source/MeshIO/imstkMeshIO.cpp
@@ -19,21 +19,16 @@
 
 =========================================================================*/
 
-#include <sys/stat.h>
-
 #include "imstkMeshIO.h"
-#include "imstkVTKMeshIO.h"
 #include "imstkAssimpMeshIO.h"
-#include "imstkVegaMeshIO.h"
+#include "imstkLogger.h"
 #include "imstkMSHMeshIO.h"
-//#include "imstkColor.h"
-
 #include "imstkSurfaceMesh.h"
-#include "imstkLineMesh.h"
 #include "imstkTetrahedralMesh.h"
-#include "imstkHexahedralMesh.h"
+#include "imstkVegaMeshIO.h"
+#include "imstkVTKMeshIO.h"
 
-#include "imstkLogger.h"
+#include <sys/stat.h>
 
 namespace imstk
 {
@@ -59,6 +54,7 @@ MeshIO::read(const std::string& filePath)
     case MeshFileType::STL:
     case MeshFileType::PLY:
     case MeshFileType::NRRD:
+    case MeshFileType::NII:
     case MeshFileType::DCM:
         return VTKMeshIO::read(filePath, meshType);
         break;
@@ -166,6 +162,10 @@ MeshIO::getFileType(const std::string& filePath)
     {
         meshType = MeshFileType::NRRD;
     }
+    else if (extString == "nii" || extString == "NII")
+    {
+        meshType = MeshFileType::NII;
+    }
     else
     {
         LOG(FATAL) << "MeshIO::getFileType error: unknown file extension";
@@ -183,6 +183,8 @@ MeshIO::write(const std::shared_ptr<imstk::PointSet> imstkMesh, const std::strin
     case MeshFileType::VEG:
         return VegaMeshIO::write(imstkMesh, filePath, meshType);
         break;
+    case MeshFileType::NII:
+    case MeshFileType::NRRD:
     case MeshFileType::VTU:
     case MeshFileType::VTK:
     case MeshFileType::VTP:
diff --git a/Source/MeshIO/imstkMeshIO.h b/Source/MeshIO/imstkMeshIO.h
index 7269d1f72f57f4356703074246d27e263932a95c..889ac9de5bf270d9d8b0af2ad44d795cb46640ee 100644
--- a/Source/MeshIO/imstkMeshIO.h
+++ b/Source/MeshIO/imstkMeshIO.h
@@ -21,11 +21,13 @@
 
 #pragma once
 
-// imstk
-#include "imstkPointSet.h"
+#include <memory>
+#include <string>
 
 namespace imstk
 {
+class PointSet;
+
 ///
 /// \brief Enumeration the mesh file type
 ///
@@ -44,7 +46,8 @@ enum MeshFileType
     VEG,
     MSH,
     NRRD,
-    DCM
+    DCM,
+    NII
 };
 
 ///
@@ -55,7 +58,6 @@ enum MeshFileType
 class MeshIO
 {
 public:
-
     ///
     /// \brief Constructor
     ///
@@ -71,6 +73,9 @@ public:
     ///
     static std::shared_ptr<PointSet> read(const std::string& filePath);
 
+    template<typename T>
+    static std::shared_ptr<T> read(const std::string& filePath) { return std::dynamic_pointer_cast<T>(read(filePath)); }
+
     ///
     /// \brief Write external file
     ///
diff --git a/Source/MeshIO/imstkVTKMeshIO.cpp b/Source/MeshIO/imstkVTKMeshIO.cpp
index 80b1363fe5b821d4fc52665b3a39a7551eae4cf1..2356f502bd41d4231a2cf92171910f1d93ba84d4 100644
--- a/Source/MeshIO/imstkVTKMeshIO.cpp
+++ b/Source/MeshIO/imstkVTKMeshIO.cpp
@@ -21,32 +21,32 @@
 
 #include "imstkVTKMeshIO.h"
 #include "imstkGeometryUtilities.h"
-
-#include "vtkDICOMImageReader.h"
-#include "vtkFloatArray.h"
-#include "vtkGenericDataObjectReader.h"
-#include "vtkGenericDataObjectWriter.h"
-#include "vtkNrrdReader.h"
-#include "vtkOBJReader.h"
-#include "vtkPLYReader.h"
-#include "vtkPLYWriter.h"
-#include "vtkPolyDataWriter.h"
-#include "vtkSmartPointer.h"
-#include "vtkSTLReader.h"
-#include "vtkSTLWriter.h"
-#include "vtkTriangleFilter.h"
-#include "vtkXMLPolyDataReader.h"
-#include "vtkXMLPolyDataWriter.h"
-#include "vtkXMLUnstructuredGridReader.h"
-#include "vtkXMLUnstructuredGridWriter.h"
-
-#include "imstkSurfaceMesh.h"
+#include "imstkHexahedralMesh.h"
+#include "imstkImageData.h"
 #include "imstkLineMesh.h"
+#include "imstkLogger.h"
+#include "imstkSurfaceMesh.h"
 #include "imstkTetrahedralMesh.h"
-#include "imstkHexahedralMesh.h"
 
-//#include "imstkColor.h"
-#include "imstkLogger.h"
+#include <vtkDICOMImageReader.h>
+#include <vtkGenericDataObjectReader.h>
+#include <vtkGenericDataObjectWriter.h>
+#include <vtkImageData.h>
+#include <vtkNIFTIImageReader.h>
+#include <vtkNIFTIImageWriter.h>
+#include <vtkNrrdReader.h>
+#include <vtkOBJReader.h>
+#include <vtkPLYReader.h>
+#include <vtkPLYWriter.h>
+#include <vtkPolyDataWriter.h>
+#include <vtkSTLReader.h>
+#include <vtkSTLWriter.h>
+#include <vtkTriangleFilter.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkXMLPolyDataReader.h>
+#include <vtkXMLPolyDataWriter.h>
+#include <vtkXMLUnstructuredGridReader.h>
+#include <vtkXMLUnstructuredGridWriter.h>
 
 namespace imstk
 {
@@ -87,6 +87,10 @@ VTKMeshIO::read(const std::string& filePath, MeshFileType meshType)
     {
         return VTKMeshIO::readVtkImageData<vtkNrrdReader>(filePath);
     }
+    case MeshFileType::NII:
+    {
+        return VTKMeshIO::readVtkImageDataNIFTI(filePath);
+    }
     default:
     {
         LOG(FATAL) << "VTKMeshIO::read error: file type not supported";
@@ -98,7 +102,20 @@ VTKMeshIO::read(const std::string& filePath, MeshFileType meshType)
 bool
 VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& filePath, const MeshFileType meshType)
 {
-    if (auto vMesh = std::dynamic_pointer_cast<VolumetricMesh>(imstkMesh))
+    if (auto imgMesh = std::dynamic_pointer_cast<ImageData>(imstkMesh))
+    {
+        switch (meshType)
+        {
+        case MeshFileType::NII:
+        {
+            return VTKMeshIO::writeVtkImageDataNIFTI(imgMesh, filePath);
+        }
+        default:
+            LOG(WARNING) << "VTKMeshIO::write error: file type not supported for volumetric mesh.";
+            return false;
+        }
+    }
+    else if (auto vMesh = std::dynamic_pointer_cast<VolumetricMesh>(imstkMesh))
     {
         switch (meshType)
         {
@@ -129,7 +146,6 @@ VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& f
             {
                 return false;
             }
-            break;
 
         default:
             LOG(WARNING) << "VTKMeshIO::write error: file type not supported for volumetric mesh.";
@@ -194,12 +210,12 @@ VTKMeshIO::readVtkGenericFormatData(const std::string& filePath)
 
     if (vtkSmartPointer<vtkPolyData> vtkMesh = reader->GetPolyDataOutput())
     {
-        return GeometryUtils::convertVtkPolyDataToSurfaceMesh(vtkMesh);
+        return GeometryUtils::copyToSurfaceMesh(vtkMesh);
     }
 
     if (vtkUnstructuredGrid* vtkMesh = reader->GetUnstructuredGridOutput())
     {
-        return GeometryUtils::convertVtkUnstructuredGridToVolumetricMesh(vtkMesh);
+        return GeometryUtils::copyToVolumetricMesh(vtkMesh);
     }
 
     LOG(FATAL) << "VTKMeshIO::readVtkGenericFormatData error: could not read with VTK reader.";
@@ -219,14 +235,34 @@ VTKMeshIO::readVtkPolyData(const std::string& filePath)
     triFilter->Update();
 
     vtkSmartPointer<vtkPolyData> vtkMesh = triFilter->GetOutput();
-    return GeometryUtils::convertVtkPolyDataToSurfaceMesh(vtkMesh);
+    return GeometryUtils::copyToSurfaceMesh(vtkMesh);
+}
+
+template<typename WriterType>
+bool
+VTKMeshIO::writeVtkImageData(const std::shared_ptr<ImageData> imstkMesh, const std::string& filePath)
+{
+    vtkSmartPointer<vtkImageData> vtkMesh = GeometryUtils::copyToVtkImageData(imstkMesh);
+    if (!vtkMesh)
+    {
+        return false;
+    }
+
+    int* dim    = vtkMesh->GetDimensions();
+    auto writer = vtkSmartPointer<WriterType>::New();
+    writer->SetFileDimensionality(3);
+    writer->SetInputData(vtkMesh);
+    writer->SetFileName(filePath.c_str());
+    writer->Write();
+
+    return true;
 }
 
 template<typename WriterType>
 bool
 VTKMeshIO::writeVtkPolyData(std::shared_ptr<SurfaceMesh> imstkMesh, const std::string& filePath)
 {
-    vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::convertSurfaceMeshToVtkPolyData(imstkMesh);
+    vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::copyToVtkPolyData(imstkMesh);
     if (!vtkMesh)
     {
         return false;
@@ -244,7 +280,7 @@ template<typename WriterType>
 bool
 VTKMeshIO::writeVtkPolyData(std::shared_ptr<LineMesh> imstkMesh, const std::string& filePath)
 {
-    vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::convertLineMeshToVtkPolyData(imstkMesh);
+    vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::copyToVtkPolyData(imstkMesh);
     if (!vtkMesh)
     {
         return false;
@@ -262,7 +298,7 @@ template<typename WriterType>
 bool
 VTKMeshIO::writeVtkPointSet(const std::shared_ptr<PointSet> imstkMesh, const std::string& filePath)
 {
-    vtkSmartPointer<vtkPointSet> vtkMesh = GeometryUtils::convertPointSetToVtkPointSet(imstkMesh);
+    vtkSmartPointer<vtkPointSet> vtkMesh = GeometryUtils::copyToVtkPointSet(imstkMesh);
     if (!vtkMesh)
     {
         return false;
@@ -285,20 +321,7 @@ VTKMeshIO::readVtkUnstructuredGrid(const std::string& filePath)
     reader->Update();
 
     vtkSmartPointer<vtkUnstructuredGrid> vtkMesh = reader->GetOutput();
-    return GeometryUtils::convertVtkUnstructuredGridToVolumetricMesh(vtkMesh);
-}
-
-template<typename ReaderType>
-std::shared_ptr<ImageData>
-VTKMeshIO::readVtkImageData(const std::string& filePath)
-{
-    auto reader = vtkSmartPointer<ReaderType>::New();
-    reader->SetFileName(filePath.c_str());
-    reader->Update();
-
-    auto imageData = std::make_shared<ImageData>();
-    imageData->initialize(reader->GetOutput());
-    return imageData;
+    return GeometryUtils::copyToVolumetricMesh(vtkMesh);
 }
 
 std::shared_ptr<ImageData>
@@ -317,8 +340,8 @@ VTKMeshIO::readVtkImageDataDICOM(const std::string& filePath)
     reader->SetDirectoryName(filePath.c_str());
     reader->Update();
 
-    auto imageData = std::make_shared<ImageData>();
-    imageData->initialize(reader->GetOutput());
+    std::shared_ptr<ImageData> imageData(
+        std::move(GeometryUtils::copyToImageData(reader->GetOutput())));
     return imageData;
 }
 
@@ -326,7 +349,7 @@ template<typename WriterType>
 bool
 VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> tetMesh, const std::string& filePath)
 {
-    auto vtkMesh = GeometryUtils::convertTetrahedralMeshToVtkUnstructuredGrid(tetMesh);
+    auto vtkMesh = GeometryUtils::copyToVtkUnstructuredGrid(tetMesh);
 
     if (!vtkMesh)
     {
@@ -346,7 +369,7 @@ template<typename WriterType>
 bool
 VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> hMesh, const std::string& filePath)
 {
-    auto vtkMesh = GeometryUtils::convertHexahedralMeshToVtkUnstructuredGrid(hMesh);
+    auto vtkMesh = GeometryUtils::copyToVtkUnstructuredGrid(hMesh);
 
     if (!vtkMesh)
     {
@@ -361,4 +384,56 @@ VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> hMesh, const
 
     return true;
 }
+
+///
+/// \brief Reads vtk image data
+///
+template<typename ReaderType>
+std::shared_ptr<ImageData>
+VTKMeshIO::readVtkImageData(const std::string& filePath)
+{
+    auto reader = vtkSmartPointer<ReaderType>::New();
+    reader->SetFileName(filePath.c_str());
+    reader->Update();
+
+    std::shared_ptr<ImageData> imageData(std::move(GeometryUtils::copyToImageData(reader->GetOutput())));
+    return imageData;
+}
+
+///
+/// \brief Reads nifti/nii format image data
+///
+std::shared_ptr<ImageData>
+VTKMeshIO::readVtkImageDataNIFTI(const std::string& filePath)
+{
+    auto reader = vtkSmartPointer<vtkNIFTIImageReader>::New();
+    reader->SetFileName(filePath.c_str());
+    reader->SetFileDimensionality(3);
+    reader->Update();
+
+    std::shared_ptr<ImageData> imageData(std::move(GeometryUtils::copyToImageData(reader->GetOutput())));
+    return imageData;
+}
+
+///
+/// \brief Write nifti/nii format image data
+///
+bool
+VTKMeshIO::writeVtkImageDataNIFTI(std::shared_ptr<ImageData> imageData, const std::string& filePath)
+{
+    // Copy instead of couple for thread safety
+    auto vtkMesh = GeometryUtils::copyToVtkImageData(imageData);
+    if (!vtkMesh)
+    {
+        LOG(WARNING) << "VTKMeshIO::writeVtkImageDataNIFTI error: conversion unsuccessful";
+        return false;
+    }
+
+    auto writer = vtkSmartPointer<vtkNIFTIImageWriter>::New();
+    writer->SetFileName(filePath.c_str());
+    writer->SetFileDimensionality(3);
+    writer->SetInputData(vtkMesh);
+    writer->Update();
+    return true;
+}
 } // imstk
diff --git a/Source/MeshIO/imstkVTKMeshIO.h b/Source/MeshIO/imstkVTKMeshIO.h
index 08d53279b01139c19e23ff9d77e2d0bdae4e115f..92dbafda083db45a22578d26af6d9a24ba05707f 100644
--- a/Source/MeshIO/imstkVTKMeshIO.h
+++ b/Source/MeshIO/imstkVTKMeshIO.h
@@ -21,24 +21,17 @@
 
 #pragma once
 
-#include <memory>
-
-#include "vtkUnstructuredGrid.h"
-#include "vtkPolyData.h"
-#include "vtkPoints.h"
-#include "vtkCellArray.h"
-#include "vtkPointData.h"
-
 #include "imstkMeshIO.h"
-#include "imstkImageData.h"
 
 namespace imstk
 {
-class SurfaceMesh;
+class HexahedralMesh;
+class ImageData;
 class LineMesh;
+class SurfaceMesh;
 class TetrahedralMesh;
-class HexahedralMesh;
 class VolumetricMesh;
+
 ///
 /// \class VTKMeshIO
 ///
@@ -82,6 +75,12 @@ protected:
     template<typename ReaderType>
     static std::shared_ptr<SurfaceMesh> readVtkPolyData(const std::string& filePath);
 
+    ///
+    /// \brief Writes the given image data to given file path using the provided writer type
+    ///
+    template<typename WriterType>
+    static bool writeVtkImageData(const std::shared_ptr<ImageData> imstkMesh, const std::string& filePath);
+
     ///
     /// \brief Writes the given surface mesh to given file path using the provided writer type
     ///
@@ -124,5 +123,15 @@ protected:
     /// \brief TODO
     ///
     static std::shared_ptr<ImageData> readVtkImageDataDICOM(const std::string& filePath);
+
+    ///
+    /// \brief Reads nifti/nii format image data
+    ///
+    static std::shared_ptr<ImageData> readVtkImageDataNIFTI(const std::string& filePath);
+
+    ///
+    /// \brief Write nifti/nii format image data
+    ///
+    static bool writeVtkImageDataNIFTI(std::shared_ptr<ImageData> imageData, const std::string& filePath);
 };
 } // imstk
diff --git a/Source/MeshIO/imstkVegaMeshIO.cpp b/Source/MeshIO/imstkVegaMeshIO.cpp
index 98a61e6f3e72dc0847740115163438cdfd751bc9..1a6378e010dae82d4810e264df53d7a121c843e2 100644
--- a/Source/MeshIO/imstkVegaMeshIO.cpp
+++ b/Source/MeshIO/imstkVegaMeshIO.cpp
@@ -20,20 +20,12 @@
 =========================================================================*/
 
 #include "imstkVegaMeshIO.h"
-#include "imstkMeshIO.h"
-#include "imstkTetrahedralMesh.h"
 #include "imstkHexahedralMesh.h"
-#include "imstkVolumetricMesh.h"
-
 #include "imstkLogger.h"
+#include "imstkTetrahedralMesh.h"
 
-// Vega
-#include "volumetricMeshLoader.h"
-#include "volumetricMesh.h"
-
-#include "tetMesh.h"
-
-#include <array>
+#include <tetMesh.h>
+#include <volumetricMeshLoader.h>
 
 namespace imstk
 {
diff --git a/Source/MeshIO/imstkVegaMeshIO.h b/Source/MeshIO/imstkVegaMeshIO.h
index 8e53f8d8c2e2ee2830fe83f55f14c1ce4e422605..ce72784a6fde14598b24f52b2fd8ca3ceddc6d5a 100644
--- a/Source/MeshIO/imstkVegaMeshIO.h
+++ b/Source/MeshIO/imstkVegaMeshIO.h
@@ -21,6 +21,7 @@
 
 #pragma once
 
+#include "imstkMath.h"
 #include "imstkMeshIO.h"
 
 namespace vega
diff --git a/Source/Rendering/CMakeLists.txt b/Source/Rendering/CMakeLists.txt
index 52326e9f6b34ee402083b3232cf2c138efc7b713..36387f380b457a8d4f3d73c04f339ab1b391577d 100644
--- a/Source/Rendering/CMakeLists.txt
+++ b/Source/Rendering/CMakeLists.txt
@@ -20,7 +20,7 @@ set(VTK_H_FILES
     VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h 
     VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h   
     VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h
-	VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h)
+	  VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h)
 
 set(VTK_CPP_FILES
     VTKRenderer/imstkVTKRenderer.cpp
@@ -96,10 +96,8 @@ if( NOT iMSTK_USE_Vulkan )
     VTKRenderer/RenderDelegate)
   set(RENDERING_DEPENDENCIES
     #GUIOverlay
-    Materials)
-  if (iMSTK_ENABLE_VR)
-    list(APPEND RENDERING_DEPENDENCIES openvr)
-  endif()
+    Materials
+    openvr)
 else()
   set(RENDERING_H_FILES ${VULKAN_H_FILES})
   set(RENDERING_CPP_FILES ${VULKAN_CPP_FILES})
@@ -109,7 +107,8 @@ else()
     VulkanRenderer/PostProcessing)
   set(RENDERING_DEPENDENCIES
     GUIOverlay
-    Materials)
+    Materials
+    openvr)
   set(RENDERING_LIBRARIES
     ${Vulkan}
     glfw
@@ -122,7 +121,6 @@ imstk_add_library( Rendering
     imstkRenderer.h
     ${RENDERING_H_FILES}
   CPP_FILES
-    imstkRenderer.cpp
     ${RENDERING_CPP_FILES}
   SUBDIR_LIST
     ${RENDERING_SUBDIR}
diff --git a/Source/Rendering/Materials/imstkRenderMaterial.cpp b/Source/Rendering/Materials/imstkRenderMaterial.cpp
index 63bedfd6292b7d239b2b06534a35f4b5c32a43a8..a5def361aa3c5a3cb45af85a502e23c020184fbf 100644
--- a/Source/Rendering/Materials/imstkRenderMaterial.cpp
+++ b/Source/Rendering/Materials/imstkRenderMaterial.cpp
@@ -20,7 +20,7 @@
 =========================================================================*/
 
 #include "imstkRenderMaterial.h"
-#include "imstkTexture.h"
+#include "imstkLogger.h"
 
 namespace imstk
 {
diff --git a/Source/Rendering/Materials/imstkRenderMaterial.h b/Source/Rendering/Materials/imstkRenderMaterial.h
index 7dae67f758dfb0ea52c9ff2730a66f42fbc4b792..a479958016126892dd10050d66756750a9cea374 100644
--- a/Source/Rendering/Materials/imstkRenderMaterial.h
+++ b/Source/Rendering/Materials/imstkRenderMaterial.h
@@ -22,7 +22,9 @@
 #pragma once
 
 #include "imstkColor.h"
-#include "imstkTextureManager.h"
+#include "imstkTexture.h"
+
+#include <vector>
 
 namespace imstk
 {
@@ -44,7 +46,8 @@ public:
         Points,
         WireframeSurface,
         VolumeRendering,
-        Fluid               ///< Renders a set of points using a screen-space fluid renderer
+        Fluid,               ///< Renders a set of points using a screen-space fluid renderer
+        Image
     };
 
     /// surface shading model. Defaults to Phong
@@ -65,11 +68,11 @@ public:
         MinimumIntensity
     };
 
-    ///
-    /// \brief Constructor
-    ///
+public:
     RenderMaterial();
+    virtual ~RenderMaterial() = default;
 
+public:
     ///
     /// \brief Get/Set display mode
     ///
@@ -89,9 +92,12 @@ public:
     void setLineWidth(const float width);
 
     ///
-    /// \brief Get/Set point size
+    /// \brief Get/Set point radius
     ///
     float getPointSize() const;
+    ///
+    /// \brief Get/Set point radius
+    ///
     void setPointSize(const float size);
 
     ///
diff --git a/Source/Rendering/Materials/imstkTexture.h b/Source/Rendering/Materials/imstkTexture.h
index 19ec07e6a925afdc4e4654e486fd7ff15528e23a..9b6942838d654d61a1d71ad2ca7068772fdebffd 100644
--- a/Source/Rendering/Materials/imstkTexture.h
+++ b/Source/Rendering/Materials/imstkTexture.h
@@ -24,8 +24,6 @@
 #include <string>
 #include <memory>
 
-#include "imstkLogger.h"
-
 namespace imstk
 {
 ///
@@ -77,7 +75,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    virtual ~Texture() {}
+    virtual ~Texture() = default;
 
     ///
     /// \brief Get type
diff --git a/Source/Rendering/Materials/imstkTextureDelegate.h b/Source/Rendering/Materials/imstkTextureDelegate.h
index 62440771dc4071628ddc02ee66aa9a084d01949e..15b93eb4dd2b1f9aa438f2eabcbaca6ca71e77c1 100644
--- a/Source/Rendering/Materials/imstkTextureDelegate.h
+++ b/Source/Rendering/Materials/imstkTextureDelegate.h
@@ -21,10 +21,12 @@
 
 #pragma once
 
-#include "imstkTexture.h"
+#include <memory>
 
 namespace imstk
 {
+class Texture;
+
 ///
 /// \class TextureDelegate
 ///
@@ -32,12 +34,15 @@ namespace imstk
 ///
 class TextureDelegate
 {
+public:
+    virtual ~TextureDelegate() = default;
+
 protected:
     ///
     /// \brief Constructor
     /// \param texture The texture
     ///
-    TextureDelegate() {}
+    TextureDelegate() { }
 
     ///
     /// \brief Abstract function to load textures
diff --git a/Source/Rendering/Materials/imstkTextureManager.h b/Source/Rendering/Materials/imstkTextureManager.h
index 01c0fde8bb3e621f74f9fda539ff75cd90e1d2fa..af367581c1373b9d0816d809902a6d182b6295b8 100644
--- a/Source/Rendering/Materials/imstkTextureManager.h
+++ b/Source/Rendering/Materials/imstkTextureManager.h
@@ -24,6 +24,8 @@
 #include "imstkTexture.h"
 #include "imstkTextureDelegate.h"
 
+#include <map>
+
 namespace imstk
 {
 template<class T>
@@ -43,7 +45,7 @@ protected:
     ///
     /// \brief Constructor
     ///
-    TextureManager() {}
+    TextureManager() = default;
 
     std::map<std::shared_ptr<Texture>, std::shared_ptr<T>> m_textureMap;
 };
diff --git a/Source/Rendering/Materials/imstkVolumeRenderMaterial.cpp b/Source/Rendering/Materials/imstkVolumeRenderMaterial.cpp
index 57d30a1f11f1af586b29acd1334f1073f2273828..23670d98dd106d6a8245032371935ae25eb3a16a 100644
--- a/Source/Rendering/Materials/imstkVolumeRenderMaterial.cpp
+++ b/Source/Rendering/Materials/imstkVolumeRenderMaterial.cpp
@@ -21,12 +21,15 @@
 
 #include "imstkVolumeRenderMaterial.h"
 
-// imstk
 #include <vtkVolumeProperty.h>
 
 namespace imstk
 {
-vtkVolumeProperty*
+VolumeRenderMaterial::VolumeRenderMaterial() : m_property(vtkSmartPointer<vtkVolumeProperty>::New())
+{
+}
+
+vtkSmartPointer<vtkVolumeProperty>
 VolumeRenderMaterial::getVolumeProperty()
 {
     return this->m_property;
diff --git a/Source/Rendering/Materials/imstkVolumeRenderMaterial.h b/Source/Rendering/Materials/imstkVolumeRenderMaterial.h
index e2c6d7f519620644d9782871c8bb9e2915c9e735..fb61676b4a8ba90c4adf157edf8c3fc24056672d 100644
--- a/Source/Rendering/Materials/imstkVolumeRenderMaterial.h
+++ b/Source/Rendering/Materials/imstkVolumeRenderMaterial.h
@@ -21,26 +21,27 @@
 
 #pragma once
 
-// imstk
 #include "imstkRenderMaterial.h"
 
-// vtk
-#include <vtkNew.h>
+#include <vtkSmartPointer.h>
 
-// forward declarations
 class vtkVolumeProperty;
 
 namespace imstk
 {
 class VolumeRenderMaterial : public RenderMaterial
 {
+public:
+    VolumeRenderMaterial();
+    ~VolumeRenderMaterial() override = default;
+
 public:
     ///
-    /// \brief Set/Get the volume property
+    /// \brief Get the volume property
     ///
-    vtkVolumeProperty* getVolumeProperty();
+    vtkSmartPointer<vtkVolumeProperty> getVolumeProperty();
 
 protected:
-    vtkNew<vtkVolumeProperty> m_property;
+    vtkSmartPointer<vtkVolumeProperty> m_property;
 };
 }
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
index 6b272614f57f0814426b433e216271410f1fe4eb..260b339113d22bbd1352ce848537a218848ea301 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
@@ -21,7 +21,10 @@
 
 #include "imstkVTKCapsuleRenderDelegate.h"
 #include "imstkCapsule.h"
+#include "imstkVisualModel.h"
+
 #include <vtkCapsuleSource.h>
+#include <vtkTransform.h>
 #include <vtkTransformPolyDataFilter.h>
 
 namespace imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h
index 16f192958f7e1717195bd4bc8ffd822b08d58a45..f1c15f5b551306ca36ffb846842da970f42b2f68 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h
@@ -43,7 +43,7 @@ public:
     ///
     /// \brief destructor
     ///
-    ~VTKCapsuleRenderDelegate() = default;
+    virtual ~VTKCapsuleRenderDelegate() override = default;
 
     ///
     /// \brief Update capsule source based on the capsule geometry
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
index 2ca51a5a5f6bb5d65897d0c32e6a514da2879939..6a5ba86c207fd488dcaea8a20fa91dc7515e61bc 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
@@ -21,9 +21,11 @@
 
 #include "imstkVTKCubeRenderDelegate.h"
 #include "imstkCube.h"
+#include "imstkVisualModel.h"
 
-#include "vtkTransformPolyDataFilter.h"
-#include "vtkCubeSource.h"
+#include <vtkCubeSource.h>
+#include <vtkTransform.h>
+#include <vtkTransformPolyDataFilter.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h
index 9b43993fe10699ee78b5755eef14760bb4d9593a..95b5da6803119bd8930ed03e71a0c8cf6a026545 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h
@@ -43,7 +43,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKCubeRenderDelegate() = default;
+    virtual ~VTKCubeRenderDelegate() override = default;
 
     ///
     /// \brief Update cube source based on the cube geometry
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
index c438c8c784bbd0868cfc7c771ae4b3b20cab1618..d0a1f16f4adbf1d14984f1f6a8e8a75e1882af99 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
@@ -21,9 +21,11 @@
 
 #include "imstkVTKCylinderRenderDelegate.h"
 #include "imstkCylinder.h"
+#include "imstkVisualModel.h"
 
-#include <vtkTransformPolyDataFilter.h>
 #include <vtkCylinderSource.h>
+#include <vtkTransform.h>
+#include <vtkTransformPolyDataFilter.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h
index 97cb70ca671ab412f8a0afc211f723eb91052547..9e6ca1cba5c539b49bf5847fda00190413f956a7 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h
@@ -44,7 +44,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKCylinderRenderDelegate() = default;
+    virtual ~VTKCylinderRenderDelegate() override = default;
 
     ///
     /// \brief Update cylinder source based on the cylinder geometry
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.cpp
index 077c6721bd820e18ebbcfb814ea2b136bddb5cdb..9f7b2f1ae98be74ae9cc5387f12bf783e9693846 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.cpp
@@ -21,15 +21,13 @@
 
 #include "imstkVTKFluidRenderDelegate.h"
 #include "imstkPointSet.h"
+#include "imstkVisualModel.h"
+#include "imstkRenderMaterial.h"
 
-#include <vtkOpenGLPolyDataMapper.h>
 #include <vtkOpenGLFluidMapper.h>
 #include <vtkVertexGlyphFilter.h>
 #include <vtkTrivialProducer.h>
-#include <vtkSphereSource.h>
 #include <vtkDoubleArray.h>
-#include <vtkGlyph3D.h>
-#include <vtkVersion.h>
 #include <vtkVolume.h>
 
 namespace imstk
@@ -61,18 +59,18 @@ VTKFluidRenderDelegate::VTKFluidRenderDelegate(std::shared_ptr<VisualModel> visu
     fluidMapper->SetInputData(pointsPolydata);
 
     // set some fluid rendering properties
-    fluidMapper->SetParticleRadius(0.03f * 6.0f);
+    fluidMapper->SetParticleRadius(m_visualModel->getRenderMaterial()->getPointSize());
     fluidMapper->SetSurfaceFilterIterations(3);
     fluidMapper->SetSurfaceFilterRadius(5);
     fluidMapper->SetSurfaceFilterMethod(vtkOpenGLFluidMapper::FluidSurfaceFilterMethod::NarrowRange);
     fluidMapper->SetDisplayMode(vtkOpenGLFluidMapper::FluidDisplayMode::TransparentFluidVolume);
-    fluidMapper->SetAttenuationColor(0.8f, 0.2f, 0.15f);
-    fluidMapper->SetAttenuationScale(1.0f);
-    fluidMapper->SetOpaqueColor(0.0f, 0.0f, 0.9f);
+    fluidMapper->SetAttenuationColor(0.1f, 0.9f, 0.9f);
+    fluidMapper->SetAttenuationScale(16.0f);
+    fluidMapper->SetOpaqueColor(0.9f, 0.1f, 0.1f);
     fluidMapper->SetParticleColorPower(0.1f);
     fluidMapper->SetParticleColorScale(0.57f);
     fluidMapper->SetAdditionalReflection(0.0f);
-    fluidMapper->SetRefractiveIndex(1.33f);
+    fluidMapper->SetRefractiveIndex(1.5f);
     fluidMapper->SetRefractionScale(0.07f);
 
     m_volume->SetMapper(fluidMapper);
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h
index 6cb2fd54416547a87ae04df1d4279e71beb9690d..d673e0a2dcd64e2c8e6c0ee46498ce599ba3b88d 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKFluidRenderDelegate.h
@@ -45,7 +45,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKFluidRenderDelegate() = default;
+    virtual ~VTKFluidRenderDelegate() override = default;
 
     ///
     /// \brief Update polydata source based on the mesh geometry
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp
index 2f8b69cdd1d5b60bd04641455fca7f8288d20700..d2a603855e026b8b62c38d619b7761316df64c38 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp
@@ -21,13 +21,12 @@
 
 #include "imstkVTKHexahedralMeshRenderDelegate.h"
 #include "imstkHexahedralMesh.h"
+#include "imstkVisualModel.h"
 
-#include <vtkUnstructuredGrid.h>
+#include <vtkActor.h>
 #include <vtkDataSetMapper.h>
 #include <vtkDoubleArray.h>
-#include <vtkCellArray.h>
-#include <vtkProperty.h>
-#include <vtkPoints.h>
+#include <vtkUnstructuredGrid.h>
 
 #include <array>
 
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h
index 3ef1e9eeb673d84fd47903c93976bd83334bb2ba..2dca4112d6d3174dfd9261bbc0097d44c9adc54f 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h
@@ -45,7 +45,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKHexahedralMeshRenderDelegate() = default;
+    virtual ~VTKHexahedralMeshRenderDelegate() override = default;
 
     ///
     /// \brief Update unstructured grid source based on the hexahedral mesh
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.cpp
index e74d0266953a31a42d527978c4b078e122c33abe..134459f13bd17a2a98f94e234c6f835b9320c376 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.cpp
@@ -20,15 +20,16 @@
 =========================================================================*/
 
 #include "imstkVTKImageDataRenderDelegate.h"
-#include "imstkVolumeRenderMaterial.h"
+#include "imstkGeometryUtilities.h"
 #include "imstkImageData.h"
+#include "imstkVisualModel.h"
+#include "imstkDataArray.h"
 
 #include <vtkGPUVolumeRayCastMapper.h>
-#include <vtkColorTransferFunction.h>
-#include <vtkPiecewiseFunction.h>
-#include <vtkTrivialProducer.h>
-#include <vtkVolumeProperty.h>
 #include <vtkImageData.h>
+#include <vtkTrivialProducer.h>
+#include <vtkPointData.h>
+#include <vtkDataArray.h>
 
 namespace imstk
 {
@@ -38,28 +39,64 @@ VTKImageDataRenderDelegate::VTKImageDataRenderDelegate(std::shared_ptr<VisualMod
     m_isMesh        = false;
     m_modelIsVolume = true;
 
-    auto imageData = std::static_pointer_cast<ImageData>(m_visualModel->getGeometry());
-    if (imageData->getData())
-    {
-        auto tp = vtkSmartPointer<vtkTrivialProducer>::New();
-        tp->SetOutput(imageData->getData());
-        this->setUpMapper(tp->GetOutputPort(), m_visualModel);
+    auto imageData = std::dynamic_pointer_cast<ImageData>(m_visualModel->getGeometry());
+    m_scalarArray = imageData->getScalars();
 
-        this->updateActorPropertiesVolumeRendering();// check if this is needed once more!
-    }
+    // Couple the imstkImageData with vtkImageData
+    imageDataVtk = GeometryUtils::coupleVtkImageData(imageData);
+
+    vtkNew<vtkTrivialProducer> tp;
+    tp->SetOutput(imageDataVtk);
+    this->setUpMapper(tp->GetOutputPort(), m_visualModel);
+
+    this->updateActorPropertiesVolumeRendering(); // check if this is needed once more!
+
+    // When image is modified, queue an event to this object that calls imageDataModified
+    queueConnect<Event>(imageData, EventType::Modified, this, &VTKImageDataRenderDelegate::imageDataModified);
 }
 
 void
 VTKImageDataRenderDelegate::updateDataSource()
 {
+    // Handle any queued events
+    // \todo: Eventually move this to renderdelegate base class
+    doLastEvent();
+}
+
+void
+VTKImageDataRenderDelegate::imageDataModified(Event* imstkNotUsed(e))
+{
+    // Here we utilize something similar to double buffering
+    // We primarily use a single shared buffer until the moment
+    // it is reallocated
     auto imageData = std::static_pointer_cast<ImageData>(m_visualModel->getGeometry());
 
-    if (!imageData->m_dataModified)
+    // If our handle is not up to date, update it
+    if (m_scalarArray != imageData->getScalars())
     {
-        return;
+        // Update our handle
+        m_scalarArray = imageData->getScalars();
+
+        // Update vtk data array pointer to this new handle, this will cause existing array to deallocate assuming no
+        // one else is referencing it
+        imageDataVtk->GetPointData()->GetScalars()->SetVoidArray(m_scalarArray->getVoidPointer(), m_scalarArray->size(), 1);
+
+        // Update information (currently can't handle type changes or number of components)
+        const Vec3i& dim = imageData->getDimensions();
+        imageDataVtk->SetDimensions(dim.data());
+        imageDataVtk->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1);
+        const Vec3d vtkOrigin = imageData->getOrigin() + imageData->getSpacing() * 0.5;
+        imageDataVtk->SetOrigin(vtkOrigin.data());
+        imageDataVtk->SetSpacing(imageData->getSpacing().data());
     }
 
-    // TODO: Any transforms/modifications?
-    imageData->m_dataModified = false;
+    // Always post modified on VTK data, when modified is recieved
+    m_volumeMapper->GetInput()->Modified();
+
+    // \todo: transforms
+    if (imageData->m_transformModified)
+    {
+        imageData->m_transformModified = false;
+    }
 }
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h
index 710f7c525acf5f358c535be1fae23382f1c7c9aa..4ea6e363ea09109e5fa4f7e63bc9440369e74240 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h
@@ -23,9 +23,11 @@
 
 #include "imstkVTKRenderDelegate.h"
 
+class vtkImageData;
+
 namespace imstk
 {
-class ImageData;
+class AbstractDataArray;
 
 ///
 /// \class VTKImageDataRenderDelegate
@@ -43,11 +45,18 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKImageDataRenderDelegate() = default;
+    virtual ~VTKImageDataRenderDelegate() override = default;
 
+public:
     ///
     /// \brief Update render delegate source based on the internal data
     ///
     void updateDataSource() override;
+
+    void imageDataModified(Event* e);
+
+protected:
+    std::shared_ptr<AbstractDataArray> m_scalarArray;
+    vtkSmartPointer<vtkImageData>      imageDataVtk;
 };
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
index 2b5711c251eb0bd780884792d9b99f0a507f138b..3bc430b9e685bbba249cea1570da89a3d98d9aae 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
@@ -21,18 +21,12 @@
 
 #include "imstkVTKLineMeshRenderDelegate.h"
 #include "imstkLineMesh.h"
+#include "imstkVisualModel.h"
 
-#include <vtkUnsignedCharArray.h>
-#include <vtkTrivialProducer.h>
-#include <vtkPolyDataMapper.h>
 #include <vtkDoubleArray.h>
-#include <vtkFloatArray.h>
-#include <vtkLineSource.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkPolyData.h>
-#include <vtkPoints.h>
 #include <vtkLine.h>
+#include <vtkLineSource.h>
+#include <vtkTrivialProducer.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h
index 6edc6691e5291cef3cbdc662ace87526bc56bf72..ebe334e20406be1284bfa4d19e035308b61d40dd 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h
@@ -42,6 +42,8 @@ public:
     ///
     explicit VTKLineMeshRenderDelegate(std::shared_ptr<VisualModel> visualModel);
 
+    virtual ~VTKLineMeshRenderDelegate() override = default;
+
     ///
     /// \brief Update line source based on the line mesh
     ///
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
index 9bb2022a183f12bf8a34af114c96b59386b34a48..5c28d9fb4a777ffc6a16b0bda288460acd1fcded 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
@@ -21,9 +21,11 @@
 
 #include "imstkVTKPlaneRenderDelegate.h"
 #include "imstkPlane.h"
+#include "imstkVisualModel.h"
 
-#include <vtkTransformPolyDataFilter.h>
 #include <vtkPlaneSource.h>
+#include <vtkTransform.h>
+#include <vtkTransformPolyDataFilter.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h
index 2a7c252c1daad17eb7008047aa7694a28bb4bea8..d17422df97cc829904d44cd0257332ab5f3a60c6 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h
@@ -45,7 +45,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKPlaneRenderDelegate() = default;
+    virtual ~VTKPlaneRenderDelegate() override = default;
 
     ///
     /// \brief Update plane source based on the plane geometry
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp
index 7f42f69982d92f090d604db744986c45fe8c0cc0..43cfabf34e1ff2fa62459370a035b2454cb49f86 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp
@@ -21,15 +21,16 @@
 
 #include "imstkVTKPointSetRenderDelegate.h"
 #include "imstkPointSet.h"
+#include "imstkVisualModel.h"
 
-#include <vtkOpenGLPolyDataMapper.h>
-#include <vtkVertexGlyphFilter.h>
-#include <vtkTrivialProducer.h>
-#include <vtkSphereSource.h>
 #include <vtkDoubleArray.h>
 #include <vtkPointData.h>
 #include <vtkGlyph3D.h>
+#include <vtkOpenGLPolyDataMapper.h>
+#include <vtkSphereSource.h>
+#include <vtkTrivialProducer.h>
 #include <vtkVersion.h>
+#include <vtkVertexGlyphFilter.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h
index 6adafff6c087fa21620efe54761d913c78f014be..15813dde415244cee7bde9f4d7c7a36f461657ad 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h
@@ -46,7 +46,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKPointSetRenderDelegate() = default;
+    virtual ~VTKPointSetRenderDelegate() override = default;
 
     ///
     /// \brief Update polydata source based on the mesh geometry
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
index 999a091d8bd02a29bc1fbad1cf917cde43091cb9..01562d1cd168b7aab04033390d3e33fa290a09d4 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
@@ -20,57 +20,65 @@
 =========================================================================*/
 
 #include "imstkVTKRenderDelegate.h"
-
+#include "imstkDebugRenderGeometry.h"
+#include "imstkGeometry.h"
 #include "imstkLogger.h"
+#include "imstkVisualModel.h"
+#include "imstkVolumeRenderMaterial.h"
 
-#include "imstkPlane.h"
-#include "imstkSphere.h"
-#include "imstkCapsule.h"
-#include "imstkCylinder.h"
-#include "imstkCube.h"
-#include "imstkPointSet.h"
-#include "imstkSurfaceMesh.h"
-#include "imstkLineMesh.h"
-#include "imstkTetrahedralMesh.h"
-#include "imstkHexahedralMesh.h"
-#include "imstkVTKdebugTrianglesRenderDelegate.h"
+// Debug render delegates
 #include "imstkVTKdebugLinesRenderDelegate.h"
 #include "imstkVTKdebugPointsRenderDelegate.h"
-#include "imstkVolumeRenderMaterial.h"
+#include "imstkVTKdebugTrianglesRenderDelegate.h"
 #include "imstkColorFunction.h"
 
 // VTK render delegates
-#include "imstkVTKTetrahedralMeshRenderDelegate.h"
+#include "imstkVTKCapsuleRenderDelegate.h"
+#include "imstkVTKCubeRenderDelegate.h"
+#include "imstkVTKCylinderRenderDelegate.h"
+#include "imstkVTKFluidRenderDelegate.h"
 #include "imstkVTKHexahedralMeshRenderDelegate.h"
-#include "imstkVTKSurfaceMeshRenderDelegate.h"
 #include "imstkVTKImageDataRenderDelegate.h"
 #include "imstkVTKLineMeshRenderDelegate.h"
-#include "imstkVTKCylinderRenderDelegate.h"
+#include "imstkVTKPlaneRenderDelegate.h"
 #include "imstkVTKPointSetRenderDelegate.h"
-#include "imstkVTKCapsuleRenderDelegate.h"
 #include "imstkVTKSphereRenderDelegate.h"
-#include "imstkVTKPlaneRenderDelegate.h"
-#include "imstkVTKFluidRenderDelegate.h"
-#include "imstkVTKCubeRenderDelegate.h"
+#include "imstkVTKSurfaceMeshRenderDelegate.h"
+#include "imstkVTKTetrahedralMeshRenderDelegate.h"
 
-#include <vtkOpenGLVertexBufferObject.h>
-#include <vtkTriangleMeshPointNormals.h>
-#include <vtkOpenGLPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkAlgorithmOutput.h>
+#include <vtkColorTransferFunction.h>
+#include <vtkGPUVolumeRayCastMapper.h>
+#include <vtkImageData.h>
+#include <vtkImageReader2.h>
 #include <vtkImageReader2Factory.h>
+#include <vtkOpenGLPolyDataMapper.h>
+#include <vtkOpenGLVertexBufferObject.h>
 #include <vtkPolyDataNormals.h>
-#include <vtkImageReader2.h>
-#include <vtkTransform.h>
-#include <vtkImageData.h>
+#include <vtkProperty.h>
 #include <vtkTexture.h>
+#include <vtkTransform.h>
 #include <vtkVolume.h>
-#include <vtkVector.h>
-#include <vtkProp3D.h>
-#include <vtkActor.h>
-#include <vtkColorTransferFunction.h>
-#include <vtkNew.h>
+#include <vtkVolumeProperty.h>
 
 namespace imstk
 {
+VTKRenderDelegate::VTKRenderDelegate() :
+    m_transform(vtkSmartPointer<vtkTransform>::New()),
+    m_volumeMapper(vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New()),
+    m_volume(vtkSmartPointer<vtkVolume>::New()),
+    m_modelIsVolume(false),
+    m_actor(vtkSmartPointer<vtkActor>::New()),
+    m_mapper(vtkSmartPointer<vtkOpenGLPolyDataMapper>::New())
+{
+    m_actor->SetMapper(m_mapper);        // remove this as a default since it could be volume mapper?
+    m_actor->SetUserTransform(m_transform);
+    m_volume->SetMapper(m_volumeMapper); // remove this as a default?
+    /*m_volumeMapper->SetAutoAdjustSampleDistances(false);
+    m_volumeMapper->SetSampleDistance(0.01);*/
+}
+
 std::shared_ptr<VTKRenderDelegate>
 VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
 {
@@ -136,7 +144,14 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
         }
         case Geometry::Type::ImageData:
         {
-            return std::make_shared<VTKImageDataRenderDelegate>(visualModel);
+            if (visualModel->getRenderMaterial()->getDisplayMode() == RenderMaterial::DisplayMode::Points)
+            {
+                return std::make_shared<VTKPointSetRenderDelegate>(visualModel);
+            }
+            else
+            {
+                return std::make_shared<VTKImageDataRenderDelegate>(visualModel);
+            }
         }
         default:
         {
@@ -176,7 +191,7 @@ void
 VTKRenderDelegate::setUpMapper(vtkAlgorithmOutput*                source,
                                const std::shared_ptr<VisualModel> vizModel)
 {
-    if (auto imData = vtkImageData::SafeDownCast(source->GetProducer()->GetOutputDataObject(0)))
+    if (vtkImageData::SafeDownCast(source->GetProducer()->GetOutputDataObject(0)))
     {
         m_volumeMapper->SetInputConnection(source);
         m_modelIsVolume = true;
@@ -520,8 +535,8 @@ VTKRenderDelegate::updateActorPropertiesMesh()
         }
     }
 
-    /* actorProperty->SetBackfaceCulling(material->getBackfaceCulling());
-     actorProperty->SetOpacity(material->getOpacity());*/
+    //actorProperty->SetBackfaceCulling(material->getBackfaceCulling());
+    actorProperty->SetOpacity(material->getOpacity());
 
     // Material state is now up-to-date
     material->m_stateModified = false;
@@ -541,7 +556,7 @@ VTKRenderDelegate::updateActorPropertiesVolumeRendering()
         return;
     }
 
-    if (VolumeRenderMaterial* volumeMat = dynamic_cast<VolumeRenderMaterial*>(material.get()))
+    if (auto volumeMat = std::dynamic_pointer_cast<VolumeRenderMaterial>(material))
     {
         switch (volumeMat->getBlendMode())
         {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h
index 8205c7794b21f753aac195ad1caac9b3ae5c1f63..5569064b5958b131a02a16a61f4202f4f0762b90 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h
@@ -21,32 +21,34 @@
 
 #pragma once
 
-#include "imstkGeometry.h"
-#include "imstkRenderMaterial.h"
-#include "imstkVTKTextureDelegate.h"
-#include "imstkTextureManager.h"
-#include "imstkDebugRenderGeometry.h"
-#include "imstkVisualModel.h"
+#include "imstkEventObject.h"
 
 #include <vtkSmartPointer.h>
-#include <vtkAlgorithmOutput.h>
-#include <vtkActor.h>
-#include <vtkOpenGLPolyDataMapper.h>
-#include <vtkTransform.h>
-#include <vtkProperty.h>
-#include <vtkGPUVolumeRayCastMapper.h>
-#include <vtkVolume.h>
+#include <memory>
+
+class vtkActor;
+class vtkAlgorithmOutput;
+class vtkGPUVolumeRayCastMapper;
+class vtkOpenGLPolyDataMapper;
+class vtkProp3D;
+class vtkTransform;
+class vtkTexture;
+class vtkVolume;
 
 namespace imstk
 {
+class Texture;
+class VisualModel;
+
 ///
 /// \class VTKRenderDelegate
 ///
 /// \brief Base class for VTK render delegates
 ///
-class VTKRenderDelegate
+class VTKRenderDelegate : public EventObject
 {
 public:
+    virtual ~VTKRenderDelegate() override = default;
 
     ///
     /// \brief Instantiate proper render delegate
@@ -106,20 +108,7 @@ protected:
     ///
     /// \brief Default constructor (protected)
     ///
-    VTKRenderDelegate() :
-        m_actor(vtkSmartPointer<vtkActor>::New()),
-        m_mapper(vtkSmartPointer<vtkOpenGLPolyDataMapper>::New()),
-        m_transform(vtkSmartPointer<vtkTransform>::New()),
-        m_volumeMapper(vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New()),
-        m_volume(vtkSmartPointer<vtkVolume>::New()),
-        m_modelIsVolume(false)               // remove?
-    {
-        m_actor->SetMapper(m_mapper);        // remove this as a default since it could be volume mapper?
-        m_actor->SetUserTransform(m_transform);
-        m_volume->SetMapper(m_volumeMapper); // remove this as a default?
-    }
-
-    virtual ~VTKRenderDelegate() = default;
+    VTKRenderDelegate();
 
     vtkSmartPointer<vtkTransform> m_transform;
 
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
index 5945315c8c4e278c58db541b3ebf3ea383a9589b..163f4bf136d8ab3b9a9a8a43d1081387372056c5 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
@@ -21,9 +21,11 @@
 
 #include "imstkVTKSphereRenderDelegate.h"
 #include "imstkSphere.h"
+#include "imstkVisualModel.h"
 
-#include <vtkTransformPolyDataFilter.h>
 #include <vtkSphereSource.h>
+#include <vtkTransform.h>
+#include <vtkTransformPolyDataFilter.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h
index 59b8af5b5f5b574815eb7bfef6584022de264f37..9443a268ad3a2d6cb953adeeb0d355c98f8178fa 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h
@@ -44,7 +44,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKSphereRenderDelegate() = default;
+    virtual ~VTKSphereRenderDelegate() override = default;
 
     ///
     /// \brief Update sphere source based on the sphere geometry
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
index fe701e9537a5ab206d7ba6581951873603f5d70a..09ab58aec4f3ecf4a01588c0c53cb32035572688 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
@@ -20,26 +20,22 @@
 =========================================================================*/
 
 #include "imstkVTKSurfaceMeshRenderDelegate.h"
-#include "imstkVTKTextureDelegate.h"
-#include "imstkTextureManager.h"
+#include "imstkLogger.h"
+#include "imstkRenderMaterial.h"
 #include "imstkSurfaceMesh.h"
+#include "imstkTextureManager.h"
+#include "imstkVisualModel.h"
 
-#include <vtkPolyData.h>
-#include <vtkPolyDataNormals.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkPoints.h>
-#include <vtkTrivialProducer.h>
+#include <vtkActor.h>
 #include <vtkDoubleArray.h>
-#include <vtkCellArray.h>
 #include <vtkFloatArray.h>
+#include <vtkOpenGLPolyDataMapper.h>
 #include <vtkPointData.h>
-#include <vtkImageReader2Factory.h>
-#include <vtkImageReader2.h>
-#include <vtkTexture.h>
+#include <vtkPolyData.h>
 #include <vtkProperty.h>
-#include <vtkOpenGLPolyDataMapper.h>
+#include <vtkTexture.h>
+#include <vtkTrivialProducer.h>
 #include <vtkVersion.h>
-#include <vtkPolyDataTangents.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h
index ec36afd94ac2ac6e2fcf48110038f74700ddaa49..7a2bff20c168e1756161f818698b1f77b241587e 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h
@@ -21,7 +21,9 @@
 
 #pragma once
 
+#include "imstkTextureManager.h"
 #include "imstkVTKRenderDelegate.h"
+#include "imstkVTKTextureDelegate.h"
 
 class vtkDoubleArray;
 
@@ -45,7 +47,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKSurfaceMeshRenderDelegate() = default;
+    virtual ~VTKSurfaceMeshRenderDelegate() override = default;
 
     ///
     /// \brief Update polydata source based on the surface mesh geometry
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp
index 82ea6aeeef273082a789cf7b3ff3fcb301378099..56fdaee77703064aa2bff8bbc46936b75c3314ac 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp
@@ -21,19 +21,12 @@
 
 #include "imstkVTKTetrahedralMeshRenderDelegate.h"
 #include "imstkTetrahedralMesh.h"
+#include "imstkVisualModel.h"
 
-#include <vtkUnstructuredGrid.h>
+#include <vtkActor.h>
 #include <vtkDataSetMapper.h>
 #include <vtkDoubleArray.h>
-#include <vtkFloatArray.h>
-#include <vtkCellArray.h>
-#include <vtkPointData.h>
-#include <vtkProperty.h>
-#include <vtkPolyData.h>
-#include <vtkPoints.h>
-#include <vtkNew.h>
-
-#include <array>
+#include <vtkUnstructuredGrid.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h
index a19fda48873e1db5a4c817b5b85b1a8cc5f9cb46..6ac0059584ec03dd23cca094d3349a886e066648 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h
@@ -46,7 +46,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKTetrahedralMeshRenderDelegate() = default;
+    virtual ~VTKTetrahedralMeshRenderDelegate() override = default;
 
     ///
     /// \brief Update unstructured grid source based on the tetrahedral mesh
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.cpp
index 56c2f3206eb07982b147f8ba464fc91cede4f589..d0482ab637a1a5a2050ae68f07e3a31f86289883 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.cpp
@@ -20,19 +20,13 @@
 =========================================================================*/
 
 #include "imstkVTKdebugLinesRenderDelegate.h"
-#include "imstkSurfaceMesh.h"
+#include "imstkDebugRenderGeometry.h"
+#include "imstkVisualModel.h"
 
-#include <vtkOpenGLPolyDataMapper.h>
-#include <vtkTrivialProducer.h>
-#include <vtkPolyDataMapper.h>
+#include <thread>
 #include <vtkDoubleArray.h>
-#include <vtkFloatArray.h>
-#include <vtkCellArray.h>
-#include <vtkPointData.h>
 #include <vtkPolyData.h>
-#include <vtkProperty.h>
-#include <vtkPoints.h>
-#include <vtkLine.h>
+#include <vtkTrivialProducer.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h
index a1657018fda131871b19d9c62158297055326a02..c05c642b25cc18d7047e163e278c4c7edf96db87 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugLinesRenderDelegate.h
@@ -44,6 +44,8 @@ public:
     ///
     explicit VTKdbgLinesRenderDelegate(std::shared_ptr<VisualModel> visualModel);
 
+    virtual ~VTKdbgLinesRenderDelegate() override = default;
+
     ///
     /// \brief Update polydata source based on the surface mesh geometry
     ///
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.cpp
index a4965abf37b66b86ac08fa35260eb21c10d9783f..44a606300a4b6c178d6df52c33557f9d44530001 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.cpp
@@ -20,22 +20,12 @@
 =========================================================================*/
 
 #include "imstkVTKdebugPointsRenderDelegate.h"
-#include "imstkSurfaceMesh.h"
+#include "imstkDebugRenderGeometry.h"
+#include "imstkVisualModel.h"
 
-#include <vtkOpenGLPolyDataMapper.h>
 #include <vtkVertexGlyphFilter.h>
-#include <vtkTrivialProducer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkSphereSource.h>
 #include <vtkDoubleArray.h>
-#include <vtkFloatArray.h>
-#include <vtkCellArray.h>
-#include <vtkPointData.h>
-#include <vtkPolyData.h>
-#include <vtkPolyLine.h>
-#include <vtkProperty.h>
-#include <vtkGlyph3D.h>
-#include <vtkPoints.h>
+#include <thread>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h
index 66d2ab131de269efd89f964761470803409dcbd2..b351ad7f286f7cee8acd2d6332eb2a0f658d03aa 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugPointsRenderDelegate.h
@@ -44,6 +44,8 @@ public:
     ///
     explicit VTKdbgPointsRenderDelegate(std::shared_ptr<VisualModel> visualModel);
 
+    virtual ~VTKdbgPointsRenderDelegate() override = default;
+
     ///
     /// \brief Update polydata source based on the surface mesh geometry
     ///
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.cpp
index 144aba82292715187138a139c2b4964130e20d85..ce1bbaec2d3e22bab0f8cc4cac9bb77fa11f2543 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.cpp
@@ -20,15 +20,13 @@
 =========================================================================*/
 
 #include "imstkVTKdebugTrianglesRenderDelegate.h"
+#include "imstkDebugRenderGeometry.h"
+#include "imstkVisualModel.h"
 
-#include <vtkTrivialProducer.h>
-#include <vtkPolyDataMapper.h>
+#include <thread>
 #include <vtkDoubleArray.h>
-#include <vtkFloatArray.h>
-#include <vtkCellArray.h>
-#include <vtkPointData.h>
 #include <vtkPolyData.h>
-#include <vtkProperty.h>
+#include <vtkTrivialProducer.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.h
index 69539c58a6213227fcd92fffdc183c20470ca6f7..45f0adbf5f6ef52334d8638c2a459d0ee35287c8 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKdebugTrianglesRenderDelegate.h
@@ -23,8 +23,10 @@
 
 #include "imstkVTKRenderDelegate.h"
 
-class vtkDoubleArray;
 class vtkCellArray;
+class vtkDoubleArray;
+class vtkPoints;
+class vtkPolyData;
 
 namespace imstk
 {
@@ -44,6 +46,8 @@ public:
     ///
     explicit VTKdbgTrianglesRenderDelegate(std::shared_ptr<VisualModel> visualModel);
 
+    virtual ~VTKdbgTrianglesRenderDelegate() override = default;
+
     ///
     /// \brief Update polydata source based on the surface mesh geometry
     ///
diff --git a/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp
index fef99d9167f28b46497dd8377b25d0b4a2b1f684..f78311672e68459943f7892adc0e9f3b68cd526b 100644
--- a/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp
+++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp
@@ -20,51 +20,53 @@
 =========================================================================*/
 
 #include "imstkVTKRenderer.h"
-
+#include "imstkCamera.h"
+#include "imstkDebugRenderGeometry.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
 #include "imstkScene.h"
 #include "imstkSceneObject.h"
-#include "imstkCamera.h"
-#include "imstkVTKRenderDelegate.h"
+#include "imstkVisualModel.h"
 #include "imstkVTKSurfaceMeshRenderDelegate.h"
-#include "imstkLight.h"
 
-#include <vtkLightActor.h>
-#include <vtkCameraActor.h>
-#include <vtkAxesActor.h>
-#include <vtkCullerCollection.h>
 #include <vtkAxesActor.h>
 #include <vtkCamera.h>
-#include <vtkProp.h>
+#include <vtkCameraActor.h>
+#include <vtkCullerCollection.h>
 #include <vtkLight.h>
+#include <vtkLightActor.h>
 #include <vtkRenderer.h>
-#include <vtkRenderWindow.h>
 
 #include <vtkAxis.h>
 #include <vtkChartXY.h>
 #include <vtkContextActor.h>
 #include <vtkContextScene.h>
 #include <vtkDoubleArray.h>
-#include <vtkIntArray.h>
 #include <vtkPlotBar.h>
 #include <vtkStringArray.h>
 #include <vtkTable.h>
 #include <vtkTextProperty.h>
 
+#include <vtkOpenVRRenderer.h>
+#include <vtkOpenVRCamera.h>
+#include <vtkOpenVRRenderWindow.h>
+#include <vtkOpenVRRenderWindowInteractor.h>
+#include <vtkInteractorStyle3D.h>
+
 namespace imstk
 {
-VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) : m_scene(scene)
+VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) :
+    m_scene(scene)
 {
     // create m_vtkRenderer depending on enableVR
     if (!enableVR)
     {
         m_vtkRenderer = vtkSmartPointer<vtkRenderer>::New();
     }
-#ifdef iMSTK_ENABLE_VR
     else
     {
         m_vtkRenderer = vtkSmartPointer<vtkOpenVRRenderer>::New();
     }
-#endif
 
     this->updateRenderDelegates();
 
@@ -149,40 +151,24 @@ VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) : m_
     // Global Axis
     m_AxesActor = vtkSmartPointer<vtkAxesActor>::New();
     m_AxesActor->SetShaftType(vtkAxesActor::CYLINDER_SHAFT);
-    m_AxesActor->SetAxisLabels(false);
+    m_AxesActor->SetAxisLabels(true);
     m_debugVtkActors.push_back(m_AxesActor);
 
     // Camera and camera actor
     if (!enableVR)
     {
-        m_sceneVtkCamera = vtkSmartPointer<vtkCamera>::New();
+        m_Camera = vtkSmartPointer<vtkCamera>::New();
     }
-#ifdef iMSTK_ENABLE_VR
     else
     {
-        m_sceneVtkCamera = vtkSmartPointer<vtkOpenVRCamera>::New();
+        m_Camera = vtkSmartPointer<vtkOpenVRCamera>::New();
     }
-#endif
-    this->updateSceneCamera(scene->getCamera());
+
+    updateCamera();
     vtkNew<vtkCameraActor> camActor;
-    camActor->SetCamera(m_sceneVtkCamera);
+    camActor->SetCamera(m_Camera);
     m_debugVtkActors.push_back(camActor);
 
-    // Debug camera
-    if (!enableVR)
-    {
-        m_defaultVtkCamera = m_vtkRenderer->GetActiveCamera();
-        m_vtkRenderer->ResetCamera();
-    }
-#ifdef iMSTK_ENABLE_VR
-    else
-    {
-        // in VR mode, we keep m_defaultVtkCamera as the HMD camera
-        // => Do not change the active Camera
-        m_defaultVtkCamera = vtkSmartPointer<vtkOpenVRCamera>::New();
-        m_vtkRenderer->SetActiveCamera(m_defaultVtkCamera);
-    }
-#endif
     ///TODO : based on scene properties
     // Customize background colors
 
@@ -198,26 +184,6 @@ VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) : m_
         m_vtkRenderer->RemoveCuller(culler);
     }
 
-    // set camera pos
-#ifdef iMSTK_ENABLE_VR
-    if (enableVR)
-    {
-        m_cams.resize(2);
-
-        // save debug camera m_camPos[0]
-        m_cams[0] = vtkSmartPointer<vtkOpenVRCamera>::New();
-        m_cams[0]->SetPosition(m_defaultVtkCamera->GetPosition());
-        m_cams[0]->SetViewUp(0.0, 1.0, 0.0);
-        m_cams[0]->SetDistance(10.0); // room scale factor
-
-        // save scene camera m_camPos[1]
-        m_cams[1] = vtkSmartPointer<vtkOpenVRCamera>::New();
-        m_cams[1]->SetPosition(m_sceneVtkCamera->GetPosition());
-        m_cams[1]->SetViewUp(0.0, 1.0, 0.0);
-        m_cams[1]->SetDistance(1.0); // room scale factor of 1 meter
-    }
-#endif
-
     {
         // Add the benchmarking chart
         m_timeTableChart = vtkSmartPointer<vtkChartXY>::New();
@@ -256,32 +222,21 @@ VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) : m_
         m_timeTable->AddColumn(labels);
         m_timeTablePlot->SetInputData(m_timeTable, 0, 1);
 
+        m_timeTableChart->GetAxis(vtkAxis::BOTTOM)->GetLabelProperties()->SetColor(1.0, 1.0, 1.0);
         vtkAxis* axisY = m_timeTableChart->GetAxis(vtkAxis::LEFT);
-        //axisY->SetRange(xIndices->GetRange());
+        axisY->GetLabelProperties()->SetColor(1.0, 1.0, 1.0);
+        axisY->SetGridVisible(false);
         axisY->SetCustomTickPositions(xIndices, labels);
     }
 }
 
-vtkSmartPointer<vtkRenderer>
-VTKRenderer::getVtkRenderer() const
-{
-    return m_vtkRenderer;
-}
-
 void
 VTKRenderer::setMode(const Renderer::Mode mode, const bool enableVR)
 {
-#ifdef iMSTK_ENABLE_VR
-    vtkOpenVRRenderWindow* renWin = nullptr;
     if (enableVR)
     {
-        renWin = vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderer->GetRenderWindow());
-        if (!renWin || !m_vtkRenderer)
-        {
-            return;
-        }
+        return;
     }
-#endif
     if (mode == Mode::Empty && m_currentMode != Mode::Empty)
     {
         this->removeActors(m_objectVtkActors);
@@ -291,11 +246,6 @@ VTKRenderer::setMode(const Renderer::Mode mode, const bool enableVR)
         {
             this->removeActors(m_debugVtkActors);
         }
-        // do not change active camera in VR
-        if (!enableVR)
-        {
-            m_vtkRenderer->SetActiveCamera(m_defaultVtkCamera);
-        }
     }
     else if (mode == Mode::Debug && m_currentMode != Mode::Debug)
     {
@@ -309,19 +259,6 @@ VTKRenderer::setMode(const Renderer::Mode mode, const bool enableVR)
                 m_vtkRenderer->AddLight(light);
             }
         }
-        // do not change active camera in VR
-        if (!enableVR)
-        {
-            m_vtkRenderer->SetActiveCamera(m_defaultVtkCamera);
-            m_vtkRenderer->ResetCamera();
-        }
-#ifdef iMSTK_ENABLE_VR
-        else // go to debug position camera
-        {    // apply debug camera
-            static_cast<vtkOpenVRCamera*>(m_vtkRenderer->GetActiveCamera())->DeepCopy(m_cams[0]);
-            m_vtkRenderer->ResetCameraClippingRange();
-        }
-#endif
     }
     else if (mode == Mode::Simulation && m_currentMode != Mode::Simulation)
     {
@@ -336,29 +273,12 @@ VTKRenderer::setMode(const Renderer::Mode mode, const bool enableVR)
         else if (m_currentMode == Mode::Debug)
         {
             this->removeActors(m_debugVtkActors);
-
-#ifdef iMSTK_ENABLE_VR
-            // save last debug position camera
-            if (enableVR)
-            {
-                static_cast<vtkOpenVRCamera*>(m_vtkRenderer->GetActiveCamera())->DeepCopy(m_cams[0]);
-            }
-#endif
-        }
-        // do not change active camera in VR
-        if (!enableVR)
-        {
-            m_vtkRenderer->SetActiveCamera(m_sceneVtkCamera);
         }
-#ifdef iMSTK_ENABLE_VR
-        else // go to Predefined sceneVtkCamera position
-        {    // apply scene camera
-            static_cast<vtkOpenVRCamera*>(m_vtkRenderer->GetActiveCamera())->DeepCopy(m_cams[1]);
-        }
-#endif
-        m_vtkRenderer->ResetCameraClippingRange();
     }
 
+    // Reset the camera
+    m_Camera = vtkSmartPointer<vtkCamera>::New();
+
     Renderer::setMode(mode, enableVR);
 }
 
@@ -465,18 +385,24 @@ VTKRenderer::getTimeTableVisibility() const
 }
 
 void
-VTKRenderer::updateSceneCamera(std::shared_ptr<Camera> imstkCam)
+VTKRenderer::updateCamera()
 {
-    // Get imstk Camera info
-    const auto p = imstkCam->getPosition();
-    const auto f = imstkCam->getFocalPoint();
-    const auto v = imstkCam->getViewUp();
-
-    // Update vtk Camera
-    m_sceneVtkCamera->SetPosition(p[0], p[1], p[2]);
-    m_sceneVtkCamera->SetFocalPoint(f[0], f[1], f[2]);
-    m_sceneVtkCamera->SetViewUp(v[0], v[1], v[2]);
-    m_sceneVtkCamera->SetViewAngle(imstkCam->getFieldOfView());
+    std::shared_ptr<Camera> cam = m_scene->getActiveCamera();
+    getVtkRenderer()->SetActiveCamera(m_Camera);
+
+    // Update the camera to obtain corrected view/proj matrices
+    cam->update();
+
+    // Get the view matrix
+    const Mat4d& invView = cam->getInvView();
+
+    const double eyePos[3]  = { invView(0, 3), invView(1, 3), invView(2, 3) };
+    const double forward[3] = { invView(0, 2), invView(1, 2), invView(2, 2) };
+    const double up[3]      = { invView(0, 1), invView(1, 1), invView(2, 1) };
+    m_Camera->SetPosition(eyePos);
+    m_Camera->SetFocalPoint(eyePos[0] - forward[0], eyePos[1] - forward[1], eyePos[2] - forward[2]);
+    m_Camera->SetViewUp(up[0], up[1], up[2]);
+    m_Camera->SetViewAngle(cam->getFieldOfView());
 }
 
 void
diff --git a/Source/Rendering/VTKRenderer/imstkVTKRenderer.h b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h
index 8e619b29e5efb23c18639ed1ba9c8e4dee3a2d59..6d2e7c112c534027b5c6bcb5db162ff12797a629 100644
--- a/Source/Rendering/VTKRenderer/imstkVTKRenderer.h
+++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h
@@ -22,18 +22,10 @@
 #pragma once
 
 #include "imstkRenderer.h"
-#include "imstkVTKTextureDelegate.h"
 #include "imstkTextureManager.h"
+#include "imstkVTKTextureDelegate.h"
 
 #include <vtkSmartPointer.h>
-#ifdef iMSTK_ENABLE_VR
-#include <vtkOpenVRRenderer.h>
-#include <vtkOpenVRCamera.h>
-#include <vtkOpenVRRenderWindow.h>
-#include <vtkOpenVRRenderWindowInteractor.h>
-#include <vtkInteractorStyle3D.h>
-#endif
-
 #include <unordered_map>
 
 class vtkAxesActor;
@@ -41,6 +33,7 @@ class vtkCamera;
 class vtkChartXY;
 class vtkContextActor;
 class vtkLight;
+class vtkOpenVRCamera;
 class vtkPlotBar;
 class vtkProp;
 class vtkRenderer;
@@ -51,29 +44,21 @@ namespace imstk
 class Scene;
 class Camera;
 class VTKRenderDelegate;
-//class TextureManager;
 
 ///
 /// \class VTKRenderer
 ///
-/// \brief
+/// \brief Wraps a vtkRenderer
 ///
 class VTKRenderer : public Renderer
 {
 public:
-    ///
-    /// \brief Constructor
-    ///
     VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR);
+    virtual ~VTKRenderer() override = default;
 
+public:
     ///
-    /// \brief Default destructor
-    ///
-    ~VTKRenderer() = default;
-
-    ///
-    /// \brief Set/Get the rendering mode which defined the
-    /// visibility of the renderer actors and the default camera
+    /// \brief Set the rendering mode to display debug actors or not
     ///
     void setMode(const Mode mode, const bool enableVR) override;
 
@@ -114,9 +99,9 @@ public:
     bool getTimeTableVisibility() const;
 
     ///
-    /// \brief Updates the scene camera's position and orientation
+    /// \brief Updates the camera
     ///
-    void updateSceneCamera(std::shared_ptr<Camera> imstkCam);
+    void updateCamera();
 
     ///
     /// \brief Updates the render delegates
@@ -131,7 +116,7 @@ public:
     ///
     /// \brief Returns VTK renderer
     ///
-    vtkSmartPointer<vtkRenderer> getVtkRenderer() const;
+    vtkSmartPointer<vtkRenderer> getVtkRenderer() const { return m_vtkRenderer; }
 
     ///
     /// \brief Update background colors
@@ -152,9 +137,8 @@ protected:
 protected:
     vtkSmartPointer<vtkRenderer> m_vtkRenderer;
 
-    // cameras
-    vtkSmartPointer<vtkCamera> m_defaultVtkCamera;
-    vtkSmartPointer<vtkCamera> m_sceneVtkCamera;
+    // Camera
+    vtkSmartPointer<vtkCamera> m_Camera;
 
     // lights
     std::vector<vtkSmartPointer<vtkLight>> m_vtkLights;
@@ -172,9 +156,6 @@ protected:
     std::shared_ptr<Scene> m_scene;
 
     TextureManager<VTKTextureDelegate> m_textureManager;
-#ifdef iMSTK_ENABLE_VR
-    std::vector<vtkSmartPointer<vtkOpenVRCamera>> m_cams;
-#endif
 
     vtkSmartPointer<vtkChartXY>      m_timeTableChart;
     vtkSmartPointer<vtkContextActor> m_timeTableChartActor;
diff --git a/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp b/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp
index 513a666ae652c964de2e40317765466d725aa67b..ba8451518defd0a29e6a22143d33531b33fe5365 100644
--- a/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp
@@ -20,13 +20,13 @@
 =========================================================================*/
 
 #include "imstkVTKTextureDelegate.h"
+#include "imstkLogger.h"
+#include "imstkTexture.h"
 
+#include <vtkImageFlip.h>
 #include <vtkImageReader2Factory.h>
 #include <vtkPNGReader.h>
-#include <vtkImageReader2.h>
-#include <vtkImageFlip.h>
 #include <vtkTexture.h>
-#include <vtkImageCast.h>
 
 namespace imstk
 {
diff --git a/Source/Rendering/imstkRenderer.h b/Source/Rendering/imstkRenderer.h
index d675dc15120bd76035bb4344901e91c06c1f39d7..c53d28f13bfe7f0666374df95761465d16b3e66e 100644
--- a/Source/Rendering/imstkRenderer.h
+++ b/Source/Rendering/imstkRenderer.h
@@ -52,17 +52,23 @@ public:
         Simulation
     };
 
-    Renderer() : m_config(std::make_shared<rendererConfig>()) {}
+    Renderer() : m_config(std::make_shared<rendererConfig>()) { }
+    virtual ~Renderer() = default;
 
+public:
     ///
     /// \brief Set rendering mode
     ///
-    virtual void setMode(const Renderer::Mode mode, const bool enableVR);
+    virtual void setMode(const Renderer::Mode mode, const bool enableVR)
+    {
+        m_VrEnabled   = enableVR;
+        m_currentMode = mode;
+    }
 
     ///
     /// \brief Get rendering mode
     ///
-    virtual const Renderer::Mode& getMode();
+    virtual const Renderer::Mode& getMode() const { return m_currentMode; }
 
     ///
     /// \brief Update background colors
@@ -71,7 +77,7 @@ public:
 
 protected:
     bool m_VrEnabled = false;
-    Renderer::Mode m_currentMode = Renderer::Mode::Empty;
+    Renderer::Mode m_currentMode = Renderer::Mode::Simulation;
 
     std::shared_ptr<rendererConfig> m_config;
 };
diff --git a/Source/Scene/imstkCollisionGraph.cpp b/Source/Scene/imstkCollisionGraph.cpp
index 6805e2faa8b2f64aa9d9dab2681bdf7f4978a515..dee076f0a5ef6b52698f041da96b6cb31bfef0b5 100644
--- a/Source/Scene/imstkCollisionGraph.cpp
+++ b/Source/Scene/imstkCollisionGraph.cpp
@@ -20,9 +20,7 @@
 =========================================================================*/
 
 #include "imstkCollisionGraph.h"
-#include "imstkLogger.h"
 #include "imstkObjectInteractionPair.h"
-#include "imstkSceneObject.h"
 
 namespace imstk
 {
diff --git a/Source/Scene/imstkCollisionGraph.h b/Source/Scene/imstkCollisionGraph.h
index a547067b0cacd57181f4b5559789ed1560bc3354..474b87fbade93b2a9a53cc9888c09ac15a2d0e8f 100644
--- a/Source/Scene/imstkCollisionGraph.h
+++ b/Source/Scene/imstkCollisionGraph.h
@@ -49,7 +49,7 @@ public:
     ///
     /// \brief Default destructor
     ///
-    ~CollisionGraph() = default;
+    virtual ~CollisionGraph() = default;
 
 public:
     ///
diff --git a/Source/Scene/imstkCollisionPair.cpp b/Source/Scene/imstkCollisionPair.cpp
index ae296795d07cf8366e02c4d56b8fea12adc381e9..704bf103ade4348aea11d91d21f0011ce2ef513e 100644
--- a/Source/Scene/imstkCollisionPair.cpp
+++ b/Source/Scene/imstkCollisionPair.cpp
@@ -21,10 +21,8 @@ limitations under the License.
 
 #include "imstkCollisionPair.h"
 #include "imstkCollidingObject.h"
-#include "imstkCollisionData.h"
-#include "imstkDynamicObject.h"
-#include "imstkInteractionPair.h"
-#include "imstkLogger.h"
+#include "imstkCollisionDetection.h"
+#include "imstkCollisionHandling.h"
 #include "imstkTaskGraph.h"
 
 namespace imstk
diff --git a/Source/Scene/imstkCollisionPair.h b/Source/Scene/imstkCollisionPair.h
index 41147bbc5bb57e1887c394c372c61ca14b73a927..73732c90ffc703c24384c45babfa93893ff71ddc 100644
--- a/Source/Scene/imstkCollisionPair.h
+++ b/Source/Scene/imstkCollisionPair.h
@@ -21,21 +21,22 @@ limitations under the License.
 
 #pragma once
 
-#include "imstkCollisionDetection.h"
-#include "imstkCollisionHandling.h"
 #include "imstkObjectInteractionPair.h"
 
 namespace imstk
 {
 struct CollisionData;
 class CollidingObject;
+class CollisionDetection;
+class CollisionHandling;
 
 ///
 /// \class CollisionPair
 ///
 /// \brief CollisionPair is a specialization of InteractionPair that adds Handler functions.
 /// The handler functions precede the interaction node/step as their own computational node/step.
-/// The handler functions may be a singular handler node or two separate concurrent nodes.
+/// The handler functions may be a singular handler node (that handles both AB concurrently) or
+/// two separate concurrent nodes.
 ///
 class CollisionPair : public ObjectInteractionPair
 {
@@ -57,7 +58,7 @@ public:
                   std::shared_ptr<CollisionDetection> cd,
                   std::shared_ptr<CollisionHandling> chAB);
 
-    ~CollisionPair() = default;
+    virtual ~CollisionPair() override = default;
 
 public:
     /// \brief TODO
diff --git a/Source/Scene/imstkInteractionPair.h b/Source/Scene/imstkInteractionPair.h
index f2b5337f1c306174a5f03b30d65648b7d74afad5..585bba397924de58261c2c42101784a6416ee2bf 100644
--- a/Source/Scene/imstkInteractionPair.h
+++ b/Source/Scene/imstkInteractionPair.h
@@ -31,7 +31,9 @@ class TaskNode;
 ///
 /// \class InteractionPair
 ///
-/// \brief This class defines an interaction between nodes
+/// \brief This class defines an interaction between 2 sets of nodes
+/// Given a set of input and output nodes, the interactionFunction will be
+/// inserted
 ///
 class InteractionPair
 {
@@ -47,6 +49,12 @@ public:
     const Inputs& getTaskNodeInputs() const { return m_taskNodeInputs; }
     const Outputs& getTaskNodeOutputs() const { return m_taskNodeOutputs; }
 
+public:
+    ///
+    /// \brief Modifies the computational graph
+    ///
+    void compute();
+
 protected:
     Inputs  m_taskNodeInputs;                        ///> The interacting nodes
     Outputs m_taskNodeOutputs;                       ///> The interacting nodes
diff --git a/Source/Scene/imstkObjectInteractionFactory.cpp b/Source/Scene/imstkObjectInteractionFactory.cpp
index 0541f7448cf2c45a0df711427f2ffe55c8a857d3..34b4fc302311904e70c426cd03f89fc47fb91d72 100644
--- a/Source/Scene/imstkObjectInteractionFactory.cpp
+++ b/Source/Scene/imstkObjectInteractionFactory.cpp
@@ -22,15 +22,13 @@ limitations under the License.
 #include "imstkObjectInteractionFactory.h"
 #include "imstkBoneDrillingCH.h"
 #include "imstkCDObjectFactory.h"
-#include "imstkCollidingObject.h"
 #include "imstkCollisionData.h"
-#include "imstkCollisionDetection.h"
 #include "imstkFeDeformableObject.h"
-#include "imstkLogger.h"
 #include "imstkPbdObject.h"
 #include "imstkPbdObjectCollisionPair.h"
 #include "imstkPenaltyCH.h"
 #include "imstkPickingCH.h"
+#include "imstkImplicitGeometryToPointSetCD.h"
 #include "imstkSPHCollisionHandling.h"
 #include "imstkSPHObject.h"
 
@@ -61,7 +59,7 @@ makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr
     //}
     else if (intType == InteractionType::SphObjToCollidingObjCollision && isType<SPHObject>(obj1))
     {
-        // Setup CD, and collision data
+        // Setup CD and collision data
         std::shared_ptr<CollisionData>      colData   = std::make_shared<CollisionData>();
         std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData);
 
@@ -71,9 +69,19 @@ makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr
 
         results = std::make_shared<CollisionPair>(obj1, obj2, colDetect, colHandler, nullptr);
     }
+    else if (intType == InteractionType::SphObjToCollidingObjSDFCollision && isType<SPHObject>(obj1))
+    {
+        // Setup CD and collision data
+        std::shared_ptr<CollisionData>      colData   = std::make_shared<CollisionData>();
+        std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData);
+
+        // Setup the handler
+        std::shared_ptr<SPHCollisionHandling> colHandler = std::make_shared<SPHCollisionHandling>(CollisionHandling::Side::B, colData, std::dynamic_pointer_cast<SPHObject>(obj1));
+        results = std::make_shared<CollisionPair>(obj2, obj1, colDetect, colHandler, nullptr);
+    }
     else if (intType == InteractionType::FemObjToCollidingObjNodalPicking && isType<FeDeformableObject>(obj1))
     {
-        // Setup CD, and collision data
+        // Setup CD and collision data
         std::shared_ptr<CollisionData>      colData   = std::make_shared<CollisionData>();
         std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData);
 
@@ -85,7 +93,7 @@ makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr
     }
     else if (intType == InteractionType::FemObjToCollidingObjPenaltyForce && isType<FeDeformableObject>(obj1))
     {
-        // Setup CD, and collision data
+        // Setup CD and collision data
         std::shared_ptr<CollisionData>      colData   = std::make_shared<CollisionData>();
         std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData);
 
@@ -93,9 +101,9 @@ makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr
         std::shared_ptr<PenaltyCH> colHandler =
             std::make_shared<PenaltyCH>(CollisionHandling::Side::A, colData, obj1);
     }
-    else if (intType == InteractionType::FemObjToCollidingObjBoneDrilling && isType<FeDeformableObject>(obj1))
+    else if (intType == InteractionType::CollidingObjToCollidingObjBoneDrilling)
     {
-        // Setup CD, and collision data
+        // Setup CD and collision data
         std::shared_ptr<CollisionData>      colData   = std::make_shared<CollisionData>();
         std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), colData);
 
diff --git a/Source/Scene/imstkObjectInteractionFactory.h b/Source/Scene/imstkObjectInteractionFactory.h
index fa6fb32090c3f062e1372d315537655df493be31..aea3117e39e69d6359b6140d41e24f666af0f4e5 100644
--- a/Source/Scene/imstkObjectInteractionFactory.h
+++ b/Source/Scene/imstkObjectInteractionFactory.h
@@ -22,11 +22,11 @@ limitations under the License.
 #pragma once
 
 #include "imstkCollisionDetection.h"
-#include "imstkObjectInteractionPair.h"
 
 namespace imstk
 {
 class CollidingObject;
+class ObjectInteractionPair;
 
 // Predefined standard/types of interaction from imstk
 enum class InteractionType
@@ -35,6 +35,7 @@ enum class InteractionType
 
     PbdObjToCollidingObjCollision,
     SphObjToCollidingObjCollision,
+    SphObjToCollidingObjSDFCollision,
     FemObjToCollidingObjCollision,
     //RigidObjToCollidingObjCollision,
 
@@ -43,13 +44,14 @@ enum class InteractionType
     FemObjToCollidingObjPenaltyForce,
     FemObjToCollidingObjBoneDrilling,
     FemObjToCollidingObjNodalPicking,
+    SphObjToPhysiologyObjCoupling,
+    CollidingObjToCollidingObjBoneDrilling
 
-    SphObjToPhysiologyObjCoupling
 };
 
 ///
 /// \brief Factory for InteractionPairs, returns nullptr and logs warning if failed
 ///
-extern std::shared_ptr<ObjectInteractionPair> makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr<CollidingObject> obj2,
-                                                                        InteractionType intType, CollisionDetection::Type cdType);
+std::shared_ptr<ObjectInteractionPair> makeObjectInteractionPair(std::shared_ptr<CollidingObject> obj1, std::shared_ptr<CollidingObject> obj2,
+                                                                 InteractionType intType, CollisionDetection::Type cdType);
 }
diff --git a/Source/Scene/imstkPbdObjectCollisionPair.h b/Source/Scene/imstkPbdObjectCollisionPair.h
index fb476aeef6de4a26cfbd49af7a9b9378e649eff5..3c44d115e29ba38610aad1f69ffb00555e7b5cbc 100644
--- a/Source/Scene/imstkPbdObjectCollisionPair.h
+++ b/Source/Scene/imstkPbdObjectCollisionPair.h
@@ -22,6 +22,7 @@ limitations under the License.
 #pragma once
 
 #include "imstkCollisionPair.h"
+#include "imstkCollisionDetection.h"
 
 namespace imstk
 {
@@ -39,6 +40,8 @@ public:
     PbdObjectCollisionPair(std::shared_ptr<PbdObject> obj1, std::shared_ptr<PbdObject> obj2,
                            CollisionDetection::Type cdType = CollisionDetection::Type::MeshToMeshBruteForce);
 
+    virtual ~PbdObjectCollisionPair() override = default;
+
     void apply() override;
 
 private:
diff --git a/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp b/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5b61f1e31a435ab0b088671c527e755fd8cc137e
--- /dev/null
+++ b/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp
@@ -0,0 +1,62 @@
+/*=========================================================================
+
+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 "imstkRigidObjectCollidingCollisionPair.h"
+#include "imstkCDObjectFactory.h"
+#include "imstkCollisionData.h"
+#include "imstkRigidBodyCH.h"
+#include "imstkRigidBodyModel2.h"
+#include "imstkRigidObject2.h"
+#include "imstkTaskGraph.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+RigidObjectCollidingCollisionPair::RigidObjectCollidingCollisionPair(
+    std::shared_ptr<RigidObject2> obj1, std::shared_ptr<CollidingObject> obj2,
+    CollisionDetection::Type cdType, const double stiffness, const double frictionalCoefficient) :
+    CollisionPair(obj1, obj2)
+{
+    std::shared_ptr<RigidBodyModel2> rbdModel = obj1->getRigidBodyModel2();
+
+    if (rbdModel == nullptr)
+    {
+        LOG(WARNING) << "RigidCollidingObjectCollisionPair, could not create";
+        return;
+    }
+
+    // Define where collision interaction happens
+    m_taskNodeInputs.first.push_back(rbdModel->getComputeTentativeVelocitiesNode());
+    m_taskNodeInputs.second.push_back(obj2->getTaskGraph()->getSource());
+
+    m_taskNodeOutputs.first.push_back(rbdModel->getSolveNode());
+    m_taskNodeOutputs.second.push_back(obj2->getUpdateNode());
+
+    // Setup the CD
+    m_colData = std::make_shared<CollisionData>();
+    setCollisionDetection(makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), m_colData));
+
+    // Setup the handlers for each side
+    setCollisionHandlingA(std::make_shared<RigidBodyCH>(CollisionHandling::Side::A, m_colData, obj1, nullptr, stiffness, frictionalCoefficient));
+}
+}
+}
\ No newline at end of file
diff --git a/Source/Scene/imstkRigidObjectCollidingCollisionPair.h b/Source/Scene/imstkRigidObjectCollidingCollisionPair.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c61116f33092e17aefc0df68fa80d1beff2ef7d
--- /dev/null
+++ b/Source/Scene/imstkRigidObjectCollidingCollisionPair.h
@@ -0,0 +1,47 @@
+/*=========================================================================
+
+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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkCollisionPair.h"
+#include "imstkCollisionDetection.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+class RigidObject2;
+
+///
+/// \class RigidObjectCollidingCollisionPair
+///
+/// \brief This class defines a collision interaction between two RigidObjects
+///
+class RigidObjectCollidingCollisionPair : public CollisionPair
+{
+public:
+    RigidObjectCollidingCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<CollidingObject> obj2,
+                                      CollisionDetection::Type cdType, const double stiffness = 0.0, const double frictionalCoefficient = 0.8);
+
+    virtual ~RigidObjectCollidingCollisionPair() override = default;
+};
+}
+}
\ No newline at end of file
diff --git a/Source/Scene/imstkRigidObjectCollisionPair.cpp b/Source/Scene/imstkRigidObjectCollisionPair.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..949733b0a25383ed9fd26151e5e580dea48d934c
--- /dev/null
+++ b/Source/Scene/imstkRigidObjectCollisionPair.cpp
@@ -0,0 +1,91 @@
+/*=========================================================================
+
+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 "imstkRigidObjectCollisionPair.h"
+#include "imstkCDObjectFactory.h"
+#include "imstkCollisionData.h"
+#include "imstkRigidBodyCH.h"
+#include "imstkRigidObject2.h"
+#include "imstkTaskGraph.h"
+#include "imstkRigidBodyModel2.h"
+#include "imstkLogger.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+RigidObjectCollisionPair::RigidObjectCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<RigidObject2> obj2,
+                                                   CollisionDetection::Type cdType) : CollisionPair(obj1, obj2)
+{
+    std::shared_ptr<RigidBodyModel2> model1 = obj1->getRigidBodyModel2();
+    std::shared_ptr<RigidBodyModel2> model2 = obj2->getRigidBodyModel2();
+
+    if (model1 == nullptr || model2 == nullptr)
+    {
+        LOG(WARNING) << "RigidObjectCollisionPair, could not create";
+        return;
+    }
+
+    // Here we use RigidBodyCH which generates constraints for the rigid body model
+    // This step is done *after* tentative velocities have been computed but *before*
+    // constraints and new velocities are solved.
+
+    // Define where collision interaction happens
+    m_taskNodeInputs.first.push_back(model1->getComputeTentativeVelocitiesNode());
+    m_taskNodeInputs.second.push_back(model2->getComputeTentativeVelocitiesNode());
+
+    m_taskNodeOutputs.first.push_back(model1->getSolveNode());
+    m_taskNodeOutputs.second.push_back(model2->getSolveNode());
+
+    // Setup the CD
+    m_colData = std::make_shared<CollisionData>();
+    setCollisionDetection(makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), m_colData));
+
+    // Setup the handler
+    CollisionHandling::Side side = CollisionHandling::Side::AB;
+    // If both objects use the same model, we need only add one two-way constraint to the system
+    if (model1 == model2)
+    {
+        side = CollisionHandling::Side::AB;
+    }
+    else
+    {
+        LOG(WARNING) << "RigidObjectCollisionPair, specified RigidObjects have differing models, one-way constraints not supported yet";
+        return;
+    }
+    std::shared_ptr<RigidBodyCH> ch = std::make_shared<RigidBodyCH>(side, m_colData, obj1, obj2);
+    setCollisionHandlingAB(ch);
+}
+
+void
+RigidObjectCollisionPair::apply()
+{
+    // Do the normal insertions
+    CollisionPair::apply();
+
+    // But then also insert one above the CD for updating the collision geometry
+    /*m_objects.first->getTaskGraph()->insertBefore(m_colDetect->getTaskNode(),
+        std::make_shared<TaskNode>(std::bind(&DynamicObject::updatePhysicsGeometry, m_objects.first), "UpdateGeometry"));
+    m_objects.second->getTaskGraph()->insertBefore(m_colDetect->getTaskNode(),
+        std::make_shared<TaskNode>(std::bind(&DynamicObject::updatePhysicsGeometry, m_objects.first), "UpdateGeometry"));*/
+}
+}
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.h b/Source/Scene/imstkRigidObjectCollisionPair.h
similarity index 50%
rename from Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.h
rename to Source/Scene/imstkRigidObjectCollisionPair.h
index 93d561e6427841905aab1dad4cfb393141df4cee..29cf8bf4c3f5017e4fb5126d31611e5860df91a3 100644
--- a/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.h
+++ b/Source/Scene/imstkRigidObjectCollisionPair.h
@@ -21,51 +21,32 @@ limitations under the License.
 
 #pragma once
 
-#include <functional>
-#include <vtkCommand.h>
+#include "imstkCollisionPair.h"
+#include "imstkCollisionDetection.h"
 
 namespace imstk
 {
-class SimulationManager;
-
-/// \brief TODO
-class OpenVRCommand : public vtkCommand
+namespace expiremental
+{
+class RigidObject2;
+
+///
+/// \class RigidObjectObjectCollisionPair
+///
+/// \brief This class defines a collision interaction between two RigidObjects
+/// This involves a RigidObjCH which will generate 2 way or 1 way constraints for the RigidBodyModel/s
+/// depending on which system they belong too
+///
+class RigidObjectCollisionPair : public CollisionPair
 {
 public:
-    static OpenVRCommand* New()
-    {
-        return new OpenVRCommand;
-    }
-
-    ///
-    /// \brief Set the simulation manager
-    ///
-    void SetSimulationManager(SimulationManager* manager = nullptr)
-    {
-        m_simManager = manager;
-    }
-
-    ///
-    /// \brief TODO
-    ///
-    virtual void Execute(
-        vtkObject*    caller,
-        unsigned long eventId,
-        void*         callData) override;
+    RigidObjectCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<RigidObject2> obj2,
+                             CollisionDetection::Type cdType);
 
-protected:
+    virtual ~RigidObjectCollisionPair() override = default;
 
-    ///
-    /// \brief Constructor
-    ///
-    OpenVRCommand()
-    {}
-
-    ///
-    /// \brief Destructor
-    ///
-    virtual ~OpenVRCommand() = default;
-
-    SimulationManager* m_simManager = nullptr; ///> SimulationManager owning the current simulation being interacted with
+public:
+    void apply() override;
 };
-} // imstk
+}
+}
\ No newline at end of file
diff --git a/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..063d902210648454b0cbfed3b224b8fe81b5ccad
--- /dev/null
+++ b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp
@@ -0,0 +1,72 @@
+/*=========================================================================
+
+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 "imstkRigidObjectLevelSetCollisionPair.h"
+#include "imstkCDObjectFactory.h"
+#include "imstkCollisionData.h"
+#include "imstkLevelSetCH.h"
+#include "imstkLevelSetDeformableObject.h"
+#include "imstkLevelSetModel.h"
+#include "imstkRigidBodyCH.h"
+#include "imstkRigidBodyModel2.h"
+#include "imstkRigidObject2.h"
+#include "imstkTaskGraph.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+RigidObjectLevelSetCollisionPair::RigidObjectLevelSetCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<LevelSetDeformableObject> obj2) :
+    CollisionPair(obj1, obj2)
+{
+    std::shared_ptr<RigidBodyModel2> rbdModel    = obj1->getRigidBodyModel2();
+    std::shared_ptr<LevelSetModel>   lvlSetModel = obj2->getLevelSetModel();
+
+    if (rbdModel == nullptr || lvlSetModel == nullptr)
+    {
+        LOG(WARNING) << "RigidObjectCollisionPair, could not create";
+        return;
+    }
+
+    // Graph of explicit interaction
+    // [compute tentative velocities]  [lvlSetSource]
+    //                           [CD]
+    //     [Add rigid constraints]    [Apply impulses]
+    //       [Solve rbd system]       [Evolve levelset]
+    // Here the CH's adds constraints to the system on the LHS, and impulses to the levelset RHS
+
+    // Define where collision interaction happens
+    m_taskNodeInputs.first.push_back(rbdModel->getComputeTentativeVelocitiesNode());
+    m_taskNodeInputs.second.push_back(lvlSetModel->getTaskGraph()->getSource());
+
+    m_taskNodeOutputs.first.push_back(rbdModel->getSolveNode());
+    m_taskNodeOutputs.second.push_back(lvlSetModel->getQuantityEvolveNode(0));
+
+    // Setup the CD
+    m_colData = std::make_shared<CollisionData>();
+    setCollisionDetection(makeCollisionDetectionObject(CollisionDetection::Type::PointSetToImplicit, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), m_colData));
+
+    // Setup the handlers for each side
+    setCollisionHandlingA(std::make_shared<RigidBodyCH>(CollisionHandling::Side::A, m_colData, obj1, nullptr, 0.0, 0.0));
+    setCollisionHandlingB(std::make_shared<LevelSetCH>(CollisionHandling::Side::B, m_colData, obj2, obj1));
+}
+}
+}
\ No newline at end of file
diff --git a/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h
new file mode 100644
index 0000000000000000000000000000000000000000..8bd6b806ea860a53d29ce2148c895174f73be104
--- /dev/null
+++ b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h
@@ -0,0 +1,48 @@
+/*=========================================================================
+
+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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkCollisionPair.h"
+#include "imstkCollisionDetection.h"
+
+namespace imstk
+{
+class LevelSetDeformableObject;
+
+namespace expiremental
+{
+class RigidObject2;
+
+///
+/// \class RigidObjectObjectCollisionPair
+///
+/// \brief This class defines a collision interaction between a RigidObject
+/// and levelset.
+///
+class RigidObjectLevelSetCollisionPair : public CollisionPair
+{
+public:
+    RigidObjectLevelSetCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<LevelSetDeformableObject> obj2);
+    virtual ~RigidObjectLevelSetCollisionPair() override = default;
+};
+}
+}
\ No newline at end of file
diff --git a/Source/Scene/imstkScene.cpp b/Source/Scene/imstkScene.cpp
index b7c06707d772bc16a32a57038f702ccef30960da..31180413a3a86d54ccdddc966b01225e1c2e94d0 100644
--- a/Source/Scene/imstkScene.cpp
+++ b/Source/Scene/imstkScene.cpp
@@ -22,46 +22,45 @@
 #include "imstkScene.h"
 #include "imstkCamera.h"
 #include "imstkCameraController.h"
-#include "imstkCollidingObject.h"
+#include "imstkCollisionDetection.h"
 #include "imstkCollisionGraph.h"
 #include "imstkCollisionPair.h"
 #include "imstkDebugRenderGeometry.h"
 #include "imstkFeDeformableObject.h"
-#include "imstkDynamicObject.h"
 #include "imstkFEMDeformableBodyModel.h"
-#include "imstkInteractionPair.h"
 #include "imstkLight.h"
+#include "imstkLogger.h"
 #include "imstkParallelUtils.h"
-#include "imstkPbdObject.h"
 #include "imstkRigidBodyWorld.h"
-#include "imstkSceneObject.h"
-#include "imstkSceneObjectControllerBase.h"
 #include "imstkSequentialTaskGraphController.h"
 #include "imstkTaskGraph.h"
 #include "imstkTaskGraphVizWriter.h"
 #include "imstkTbbTaskGraphController.h"
 #include "imstkTimer.h"
+#include "imstkTrackingDeviceControl.h"
+#include "imstkVisualModel.h"
 
 namespace imstk
 {
 Scene::Scene(const std::string& name, std::shared_ptr<SceneConfig> config) :
-    m_name(name),
-    m_camera(std::make_shared<Camera>()),
+    m_activeCamera(nullptr),
+    m_computeTimesLock(std::make_shared<ParallelUtils::SpinLock>()),
     m_collisionGraph(std::make_shared<CollisionGraph>()),
     m_config(config),
-    m_taskGraph(std::make_shared<TaskGraph>("Scene_" + name + "_Source", "Scene_" + name + "_Sink")),
-    computeTimesLock(std::make_shared<ParallelUtils::SpinLock>())
+    m_name(name),
+    m_taskGraph(std::make_shared<TaskGraph>("Scene_" + name + "_Source", "Scene_" + name + "_Sink"))
 {
-}
+    std::shared_ptr<Camera> defaultCam = std::make_shared<Camera>();
+    defaultCam->setPosition(0.0, 2.0, -15.0);
+    defaultCam->setFocalPoint(0.0, 0.0, 0.0);
 
-Scene::~Scene()
-{
-    // Join Camera Controllers
-    for (auto camController : m_cameraControllers)
-    {
-        camController->end();
-        m_threadMap.at(camController->getName()).join();
-    }
+    std::shared_ptr<Camera> debugCam = std::make_shared<Camera>();
+    debugCam->setPosition(0.0, 4.0, -30.0);
+    debugCam->setFocalPoint(0.0, 0.0, 0.0);
+
+    m_cameras["default"] = defaultCam;
+    m_cameras["debug"]   = debugCam;
+    setActiveCamera("default");
 }
 
 bool
@@ -77,11 +76,8 @@ Scene::initialize()
     // Build the compute graph
     buildTaskGraph();
 
-    // Opportunity for external configuration
-    if (m_postTaskGraphConfigureCallback != nullptr)
-    {
-        m_postTaskGraphConfigureCallback(this);
-    }
+    // Opportunity for user configuration
+    this->postEvent(Event(EventType::Configure));
 
     // Then init
     initTaskGraph();
@@ -98,6 +94,7 @@ Scene::buildTaskGraph()
 
     // Clear the compute graph of all nodes/edges except source+sink
     m_taskGraph->clear();
+    m_taskGraph->addEdge(m_taskGraph->getSource(), m_taskGraph->getSink());
 
     // Setup all SceneObject compute graphs (and segment the rigid bodies)
     std::list<std::shared_ptr<SceneObject>> rigidBodies;
@@ -140,7 +137,7 @@ Scene::buildTaskGraph()
         auto physXUpdate = m_taskGraph->addFunction("PhysXUpdate", [&]()
             {
                 auto physxScene = RigidBodyWorld::getInstance()->m_Scene;
-                // TODO: update the time step, split into two steps, collide and advance
+                // \todo: update the time step, split into two steps, collide and advance
                 physxScene->simulate(RigidBodyWorld::getInstance()->getTimeStep());
                 physxScene->fetchResults(true);
             });
@@ -196,22 +193,23 @@ Scene::initTaskGraph()
     m_taskGraphController->initialize();
 }
 
-void
-Scene::launchModules()
-{
-    // Start Camera Controller (asynchronous)
-    for (auto camController : m_cameraControllers)
-    {
-        m_threadMap[camController->getName()] = std::thread([camController] { camController->start(); });
-    }
-}
-
 bool
 Scene::isObjectRegistered(const std::string& sceneObjectName) const
 {
     return m_sceneObjectsMap.find(sceneObjectName) != m_sceneObjectsMap.end();
 }
 
+void
+Scene::setEnableTaskTiming(bool enabled)
+{
+    m_config->taskTimingEnabled = enabled;
+    // If user wants to benchmark, tell all the nodes to time themselves
+    for (std::shared_ptr<TaskNode> node : m_taskGraph->getNodes())
+    {
+        node->m_enableTiming = m_config->taskTimingEnabled;
+    }
+}
+
 const std::vector<std::shared_ptr<SceneObject>>
 Scene::getSceneObjects() const
 {
@@ -225,12 +223,6 @@ Scene::getSceneObjects() const
     return v;
 }
 
-const std::vector<std::shared_ptr<SceneObjectControllerBase>>
-Scene::getSceneObjectControllers() const
-{
-    return m_objectControllers;
-}
-
 std::shared_ptr<SceneObject>
 Scene::getSceneObject(const std::string& sceneObjectName) const
 {
@@ -365,45 +357,9 @@ Scene::removeLight(const std::string& lightName)
 }
 
 void
-Scene::setGlobalIBLProbe(std::shared_ptr<IBLProbe> newIBLProbe)
-{
-    m_globalIBLProbe = newIBLProbe;
-}
-
-std::shared_ptr<IBLProbe>
-Scene::getGlobalIBLProbe()
-{
-    return m_globalIBLProbe;
-}
-
-const std::string&
-Scene::getName() const
-{
-    return m_name;
-}
-
-std::shared_ptr<Camera>
-Scene::getCamera() const
-{
-    return m_camera;
-}
-
-std::shared_ptr<CollisionGraph>
-Scene::getCollisionGraph() const
-{
-    return m_collisionGraph;
-}
-
-void
-Scene::addObjectController(std::shared_ptr<SceneObjectControllerBase> controller)
-{
-    m_objectControllers.push_back(controller);
-}
-
-void
-Scene::addCameraController(std::shared_ptr<CameraController> camController)
+Scene::addController(std::shared_ptr<TrackingDeviceControl> controller)
 {
-    m_cameraControllers.push_back(camController);
+    m_trackingControllers.push_back(controller);
 }
 
 void
@@ -452,7 +408,7 @@ Scene::advance(const double dt)
     }
 
     // Update objects controlled by the device controllers
-    for (auto controller : this->getSceneObjectControllers())
+    for (auto controller : this->getControllers())
     {
         controller->updateControlledObjects();
     }
@@ -463,13 +419,13 @@ Scene::advance(const double dt)
     m_taskGraphController->execute();
 
     // Apply updated forces on device
-    for (auto controller : this->getSceneObjectControllers())
+    for (auto controller : this->getControllers())
     {
         controller->applyForces();
     }
 
     // Set the trackers of the scene object controllers to out-of-date
-    for (auto controller : this->getSceneObjectControllers())
+    for (auto controller : this->getControllers())
     {
         controller->setTrackerToOutOfDate();
     }
@@ -523,12 +479,12 @@ Scene::getElapsedTime(const std::string& stepName) const
 void
 Scene::lockComputeTimes()
 {
-    computeTimesLock->lock();
+    m_computeTimesLock->lock();
 }
 
 void
 Scene::unlockComputeTimes()
 {
-    computeTimesLock->unlock();
+    m_computeTimesLock->unlock();
 }
 } // imstk
diff --git a/Source/Scene/imstkScene.h b/Source/Scene/imstkScene.h
index 227d2a578229d2a24211a595384cfdfb03fe471d..bfb90c28d763a078b74c8bff16b3b51b72bce4d3 100644
--- a/Source/Scene/imstkScene.h
+++ b/Source/Scene/imstkScene.h
@@ -21,8 +21,9 @@
 
 #pragma once
 
+#include "imstkEventObject.h"
+
 #include <atomic>
-#include <functional>
 #include <string>
 #include <thread>
 #include <unordered_map>
@@ -36,9 +37,9 @@ class CollisionGraph;
 class IBLProbe;
 class Light;
 class SceneObject;
-class SceneObjectControllerBase;
 class TaskGraph;
 class TaskGraphController;
+class TrackingDeviceControl;
 class VisualModel;
 
 namespace ParallelUtils { class SpinLock; }
@@ -79,21 +80,14 @@ struct SceneConfig
 ///
 /// \brief
 ///
-class Scene
+class Scene : public EventObject
 {
 template<class T>
 using NamedMap = std::unordered_map<std::string, std::shared_ptr<T>>;
 
 public:
-    ///
-    /// \brief Constructor
-    ///
     explicit Scene(const std::string& name, std::shared_ptr<SceneConfig> config = std::make_shared<SceneConfig>());
-
-    ///
-    /// \brief Destructor
-    ///
-    ~Scene();
+    virtual ~Scene() override = default;
 
 public:
     ///
@@ -111,11 +105,6 @@ public:
     ///
     void initTaskGraph();
 
-    ///
-    /// \brief Launch camera controller and other scene specific modules that need to run independently
-    ///
-    void launchModules();
-
     ///
     /// \brief Reset the scene
     ///
@@ -137,6 +126,12 @@ public:
     ///
     bool isObjectRegistered(const std::string& sceneObjectName) const;
 
+    ///
+    /// \brief If true, tasks will be time and a table produced
+    /// every scene advance of the times
+    ///
+    void setEnableTaskTiming(bool enabled);
+
     ///
     /// \brief Return a vector of shared pointers to the scene objects
     /// NOTE: A separate list might be efficient as this is called runtime
@@ -152,7 +147,7 @@ public:
     ///
     /// \brief Get the scene object controllers
     ///
-    const std::vector<std::shared_ptr<SceneObjectControllerBase>> getSceneObjectControllers() const;
+    const std::vector<std::shared_ptr<TrackingDeviceControl>> getControllers() const { return m_trackingControllers; }
 
     ///
     /// \brief Get a scene object of a specific name
@@ -194,13 +189,13 @@ public:
     ///
     /// \brief Add/remove lights from the scene
     ///
-    void setGlobalIBLProbe(std::shared_ptr<IBLProbe> newIBLProbe);
-    std::shared_ptr<IBLProbe> getGlobalIBLProbe();
+    void setGlobalIBLProbe(std::shared_ptr<IBLProbe> newIBLProbe) { m_globalIBLProbe = newIBLProbe; }
+    std::shared_ptr<IBLProbe> getGlobalIBLProbe() { return m_globalIBLProbe; }
 
     ///
     /// \brief Get the name of the scene
     ///
-    const std::string& getName() const;
+    const std::string& getName() const { return m_name; }
 
     ///
     /// \brief Get the computational graph of the scene
@@ -210,22 +205,67 @@ public:
     ///
     /// \brief Get the camera for the scene
     ///
-    std::shared_ptr<Camera> getCamera() const;
+    std::shared_ptr<Camera> getActiveCamera() const { return m_activeCamera; }
 
     ///
-    /// \brief Return the collision graph
+    /// \brief Get the name of the camera, if it exists
     ///
-    std::shared_ptr<CollisionGraph> getCollisionGraph() const;
+    std::string getCameraName(std::shared_ptr<Camera> cam) const
+    {
+        auto i = std::find_if(m_cameras.begin(), m_cameras.end(),
+            [&cam](const NamedMap<Camera>::value_type& j) { return j.second == cam; });
+        if (i != m_cameras.end())
+        {
+            return i->first;
+        }
+        else
+        {
+            return "";
+        }
+    }
 
     ///
-    /// \brief Add objects controllers
+    /// \brief Get camera by name
     ///
-    void addObjectController(std::shared_ptr<SceneObjectControllerBase> controller);
+    std::shared_ptr<Camera> getCamera(std::string name) const
+    {
+        auto i = m_cameras.find(name);
+        if (i != m_cameras.end())
+        {
+            return i->second;
+        }
+        else
+        {
+            return nullptr;
+        }
+    }
+
+    ///
+    /// \brief Set the camera for the scene
+    ///
+    void addCamera(std::string name, std::shared_ptr<Camera> cam) { m_cameras[name] = cam; }
+
+    ///
+    /// \brief Set the active camera by name
+    ///
+    void setActiveCamera(std::string name)
+    {
+        auto i = m_cameras.find(name);
+        if (i != m_cameras.end())
+        {
+            m_activeCamera = m_cameras[name];
+        }
+    }
+
+    ///
+    /// \brief Return the collision graph
+    ///
+    std::shared_ptr<CollisionGraph> getCollisionGraph() const { return m_collisionGraph; }
 
     ///
     /// \brief Add objects controllers
     ///
-    void addCameraController(std::shared_ptr<CameraController> camController);
+    void addController(std::shared_ptr<TrackingDeviceControl> controller);
 
     ///
     /// \brief
@@ -263,11 +303,6 @@ public:
     ///
     void unlockComputeTimes();
 
-    ///
-    /// \brief Called after compute graph is built, but before initialized
-    ///
-    void setTaskGraphConfigureCallback(std::function<void(Scene*)> callback) { this->m_postTaskGraphConfigureCallback = callback; }
-
     ///
     /// \brief Get the configuration
     ///
@@ -283,18 +318,17 @@ protected:
     NamedMap<Light>           m_lightsMap;
     std::shared_ptr<IBLProbe> m_globalIBLProbe = nullptr;
 
-    std::shared_ptr<Camera> m_camera = std::make_shared<Camera>();
+    NamedMap<Camera> m_cameras;
+    std::shared_ptr<Camera> m_activeCamera;
 
-    std::shared_ptr<CollisionGraph> m_collisionGraph = nullptr;
-    std::vector<std::shared_ptr<SceneObjectControllerBase>> m_objectControllers; ///> List of object controllers
-    std::vector<std::shared_ptr<CameraController>> m_cameraControllers;          ///> List of camera controllers
-    std::unordered_map<std::string, std::thread>   m_threadMap;                  ///>
+    std::shared_ptr<CollisionGraph> m_collisionGraph;
+    std::vector<std::shared_ptr<TrackingDeviceControl>> m_trackingControllers; ///> List of object controllers
 
-    std::shared_ptr<TaskGraph> m_taskGraph = nullptr;                            ///> Computational graph
-    std::shared_ptr<TaskGraphController> m_taskGraphController   = nullptr;      ///> Controller for the computational graph
+    std::shared_ptr<TaskGraph> m_taskGraph;                                    ///> Computational graph
+    std::shared_ptr<TaskGraphController> m_taskGraphController   = nullptr;    ///> Controller for the computational graph
     std::function<void(Scene*)> m_postTaskGraphConfigureCallback = nullptr;
 
-    std::shared_ptr<ParallelUtils::SpinLock> computeTimesLock = nullptr;
+    std::shared_ptr<ParallelUtils::SpinLock> m_computeTimesLock;
     std::unordered_map<std::string, double>  m_nodeComputeTimes; ///> Map of ComputeNode names to elapsed times for benchmarking
 
     double m_fps = 0.0;
diff --git a/Source/Scene/imstkSphObjectCollisionPair.cpp b/Source/Scene/imstkSphObjectCollisionPair.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c684ff84384b54887e6b5d4b6e789a2e9b5ac6e0
--- /dev/null
+++ b/Source/Scene/imstkSphObjectCollisionPair.cpp
@@ -0,0 +1,64 @@
+/*=========================================================================
+
+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 "imstkSphObjectCollisionPair.h"
+#include "imstkCDObjectFactory.h"
+#include "imstkCollisionData.h"
+#include "imstkImplicitGeometryToPointSetCD.h"
+#include "imstkSPHCollisionHandling.h"
+#include "imstkSPHModel.h"
+#include "imstkSPHObject.h"
+#include "imstkTaskGraph.h"
+#include "imstkImplicitGeometry.h"
+
+namespace imstk
+{
+// Pbd Collision will be tested before any step of pbd, then resolved after the solve steps of the two objects
+SphObjectCollisionPair::SphObjectCollisionPair(std::shared_ptr<SPHObject> obj1, std::shared_ptr<CollidingObject> obj2,
+                                               CollisionDetection::Type cdType) : CollisionPair(obj1, obj2)
+{
+    std::shared_ptr<Geometry>         colGeometry  = obj2->getCollidingGeometry();
+    std::shared_ptr<ImplicitGeometry> implicitGeom = std::dynamic_pointer_cast<ImplicitGeometry>(colGeometry);
+    if (implicitGeom == nullptr)
+    {
+        LOG(WARNING) << "Geometry, " << colGeometry->getName() << " not an ImplicitGeometry";
+        return;
+    }
+
+    std::shared_ptr<SPHModel> dynaModel = obj1->getSPHModel();
+
+    // Collision should happen after positions and velocities are computed
+    m_taskNodeInputs.first.push_back(obj1->getUpdateGeometryNode());
+    m_taskNodeInputs.second.push_back(obj2->getUpdateNode());
+
+    m_taskNodeOutputs.first.push_back(obj1->getTaskGraph()->getSink());
+    m_taskNodeOutputs.second.push_back(obj2->getTaskGraph()->getSink());
+
+    // Setup the CD
+    m_colData = std::make_shared<CollisionData>();
+    setCollisionDetection(makeCollisionDetectionObject(cdType, obj1->getCollidingGeometry(), obj2->getCollidingGeometry(), m_colData));
+
+    // Setup the handler
+    std::shared_ptr<SPHCollisionHandling> ch = std::make_shared<SPHCollisionHandling>(CollisionHandling::Side::B, m_colData, obj1);
+    ch->setDetection(std::dynamic_pointer_cast<ImplicitGeometryToPointSetCD>(getCollisionDetection()));
+    setCollisionHandlingB(ch);
+}
+}
\ No newline at end of file
diff --git a/Source/Scene/imstkSphObjectCollisionPair.h b/Source/Scene/imstkSphObjectCollisionPair.h
new file mode 100644
index 0000000000000000000000000000000000000000..a25548008fcd68fa5fb8fd9352875b7f3d8ded4a
--- /dev/null
+++ b/Source/Scene/imstkSphObjectCollisionPair.h
@@ -0,0 +1,44 @@
+/*=========================================================================
+
+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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkCollisionPair.h"
+#include "imstkCollisionDetection.h"
+
+namespace imstk
+{
+class SPHObject;
+
+///
+/// \class SphObjectCollisionPair
+///
+/// \brief This class defines where collision should happen bsetween an SphObject and colliding object
+///
+class SphObjectCollisionPair : public CollisionPair
+{
+public:
+    SphObjectCollisionPair(std::shared_ptr<SPHObject> obj1, std::shared_ptr<CollidingObject> obj2,
+                           CollisionDetection::Type cdType = CollisionDetection::Type::PointSetToImplicit);
+
+    virtual ~SphObjectCollisionPair() override = default;
+};
+}
\ No newline at end of file
diff --git a/Source/SceneEntities/Camera/imstkCamera.cpp b/Source/SceneEntities/Camera/imstkCamera.cpp
deleted file mode 100644
index c095a5da4f2bc1dadfe013b442583bdc9234525b..0000000000000000000000000000000000000000
--- a/Source/SceneEntities/Camera/imstkCamera.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*=========================================================================
-
-   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 <memory>
-
-#include "imstkCamera.h"
-
-#include <g3log/g3log.hpp>
-
-namespace imstk
-{
-const Vec3d&
-Camera::getPosition() const
-{
-    return m_position;
-}
-
-void
-Camera::setPosition(const Vec3d& p)
-{
-    m_position = p;
-}
-
-void
-Camera::setPosition(const double& x,
-                    const double& y,
-                    const double& z)
-{
-    m_position = Vec3d(x, y, z);
-}
-
-const Vec3d&
-Camera::getFocalPoint() const
-{
-    return m_focalPoint;
-}
-
-void
-Camera::setFocalPoint(const Vec3d& p)
-{
-    m_focalPoint = p;
-}
-
-void
-Camera::setFocalPoint(const double& x,
-                      const double& y,
-                      const double& z)
-{
-    m_focalPoint = Vec3d(x, y, z);
-}
-
-const Vec3d&
-Camera::getViewUp() const
-{
-    return m_viewUp;
-}
-
-void
-Camera::setViewUp(const Vec3d& v)
-{
-    m_viewUp = v;
-}
-
-void
-Camera::setViewUp(const double& x,
-                  const double& y,
-                  const double& z)
-{
-    m_viewUp = Vec3d(x, y, z).normalized();
-}
-
-const double&
-Camera::getFieldOfView() const
-{
-    return m_fieldOfView;
-}
-
-void
-Camera::setFieldOfView(const double& fov)
-{
-    m_fieldOfView = fov;
-}
-} // imstk
diff --git a/Source/SceneEntities/Camera/imstkCamera.h b/Source/SceneEntities/Camera/imstkCamera.h
index 382157205a9f89e8b1d2c7c13b9fe9d0f562f919..68c661357c67abe04074d88dddcc8ad6ba9a157a 100644
--- a/Source/SceneEntities/Camera/imstkCamera.h
+++ b/Source/SceneEntities/Camera/imstkCamera.h
@@ -9,7 +9,7 @@
    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
+	  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,
@@ -21,90 +21,206 @@
 
 #pragma once
 
-#include <string>
-#include <memory>
-
 #include "imstkMath.h"
 
 namespace imstk
 {
+///
+/// \brief Produces a transform pointing forward towards target from position, oriented by up
+///
+static Mat4d
+lookAt(const Vec3d& pos, const Vec3d& target, const Vec3d& up)
+{
+    Mat4d results = Mat4d::Identity();
+    Mat3d R;
+    R.col(2) = (pos - target).normalized();
+    R.col(0) = up.cross(R.col(2)).normalized();
+    R.col(1) = R.col(2).cross(R.col(0));
+    results.topLeftCorner<3, 3>()  = R.transpose();
+    results.topRightCorner<3, 1>() = -R.transpose() * pos;
+    results(3, 3) = 1.0;
+
+    return results;
+}
+
+///
+/// \brief Produces a perpsective transformation matrix
+///
+//static Mat4d
+//perspective(const double fovY, const double aspect, const double nearZ, const double farZ)
+//{
+//    Mat4d results;
+//    results.setZero();
+//    const double theta  = fovY * 0.5;
+//    const double range  = (farZ - nearZ);
+//    const double invTan = 1.0 / tan(theta);
+//
+//    results(0, 0) = invTan / aspect;
+//    results(1, 1) = invTan;
+//    results(2, 2) = -(nearZ + farZ) / range;
+//    results(3, 2) = -1.0;
+//    results(2, 3) = -2.0 * nearZ * farZ / range;
+//    return results;
+//}
+
 ///
 /// \class Camera
 ///
-/// \brief Generic camera class
+/// \brief The base camera class defines a lookat camera
 ///
 class Camera
 {
 public:
+    Camera() = default;
+    virtual ~Camera() = default;
+
+public:
+    ///
+    /// \brief Get camera view matrix
+    /// \returns Camera view matrix reference
+    ///
+    Mat4d& getView() { return m_view; }
+
+    ///
+    /// \brief Get the inverse view matrix
+    ///
+    const Mat4d& getInvView() { return m_invView; }
+
+    ///
+    /// \brief Set the camera view matrix
+    ///
+    void setView(const Mat4d& view)
+    {
+        m_viewModified = false;
+        m_view = view;
+    }
+
+    ///
+    /// \brief Get camera projection matrix
     ///
-    /// \brief Default contructor
+    //const Mat4d& getProj() { return m_proj; }
+
+    ///
+    /// \brief Set camera projection matrix
     ///
-    Camera() {}
+    //void setProj(const Mat4d& proj) { m_proj = proj; }
 
     ///
-    /// \brief Default destructor
+    /// \brief Gets the field of view
+    /// \returns vertical field of view in degrees
+    ///
+    const double getFieldOfView() const { return m_fieldOfView; }
+
     ///
-    ~Camera() = default;
+    /// \brief Sets the field of view
+    /// \param vertical field of view in degrees
+    ///
+    void setFieldOfView(const double fov)
+    {
+        m_fieldOfView = fov;
+        //m_projModified = true;
+    }
+
+    virtual void update()
+    {
+        if (m_viewModified)
+        {
+            m_view         = lookAt(m_position, m_focalPoint, m_viewUp);
+            m_invView      = m_view.inverse();
+            m_viewModified = false;
+        }
+        /*if (m_projModified)
+        {
+            m_proj = perspective();
+        }*/
+    }
 
+public:
     ///
     /// \brief Gets the camera position
     /// \returns camera position
     ///
-    const Vec3d& getPosition() const;
+    const Vec3d& getPosition() const { return m_position; }
 
     ///
     /// \brief Sets the camera position
     ///
-    void setPosition(const Vec3d& p);
-    void setPosition(const double& x,
-                     const double& y,
-                     const double& z);
+    void setPosition(const Vec3d& pos)
+    {
+        m_position     = pos;
+        m_viewModified = true;
+    }
+
+    void setPosition(const double x,
+                     const double y,
+                     const double z)
+    {
+        setPosition(Vec3d(x, y, z));
+    }
 
     ///
     /// \brief Returns the focal point
     ///        The focal point is the point that the camera points to
     /// \returns Focal point position
     ///
-    const Vec3d& getFocalPoint() const;
+    const Vec3d& getFocalPoint() const { return m_focalPoint; }
 
     ///
     /// \brief Sets the focal point
     ///
-    void setFocalPoint(const Vec3d& p);
-    void setFocalPoint(const double& x,
-                       const double& y,
-                       const double& z);
+    void setFocalPoint(const Vec3d& focalPt)
+    {
+        m_focalPoint   = focalPt;
+        m_viewModified = true;
+    }
+
+    void setFocalPoint(const double x,
+                       const double y,
+                       const double z)
+    {
+        setFocalPoint(Vec3d(x, y, z));
+    }
 
     ///
     /// \brief Get the up vector
     /// \returns up vector of camera
     ///
-    const Vec3d& getViewUp() const;
+    const Vec3d& getViewUp() const { return m_viewUp; }
 
     ///
     /// \brief Set the up vector
     ///
-    void setViewUp(const Vec3d& v);
-    void setViewUp(const double& x,
-                   const double& y,
-                   const double& z);
-    ///
-    /// \brief Gets the field of view
-    /// \returns vertical field of view in degrees
-    ///
-    const double& getFieldOfView() const;
+    void setViewUp(const Vec3d& up)
+    {
+        m_viewUp       = up.normalized();
+        m_viewModified = true;
+    }
 
-    ///
-    /// \brief Sets the field of view
-    /// params fov vertical field of view in degrees
-    ///
-    void setFieldOfView(const double& fov);
+    void setViewUp(const double x,
+                   const double y,
+                   const double z)
+    {
+        setViewUp(Vec3d(x, y, z));
+    }
 
 protected:
+    // Base camera values
+    Mat4d m_view    = Mat4d::Identity(); ///> Actual view matrix used
+    Mat4d m_invView = Mat4d::Identity(); ///> Inverse is often needed so we maintain it
+    //Mat4d m_proj;
+    bool m_viewModified = true;
+//bool  m_projModified = true;
 
-    Vec3d  m_position    = Vec3d(0, 2, 5);          ///> camera position
-    Vec3d  m_focalPoint  = WORLD_ORIGIN;            ///> camera focal point
-    Vec3d  m_viewUp      = UP_VECTOR;               ///> camera up vector
-    double m_fieldOfView = 60;                      ///> field of view in degrees
+protected:
+    // Base projection parameters
+    double m_fieldOfView = 40.0; ///> field of view in degrees
+    double m_nearZ       = 0.01; ///> near plane of the camera
+    double m_farZ = 1000.0;      ///> far plane of the camera
+
+protected:
+    // Lookat camera parameters
+    Vec3d m_position   = Vec3d(0, 2, 5); ///> camera position
+    Vec3d m_focalPoint = WORLD_ORIGIN;   ///> camera focal point
+    Vec3d m_viewUp     = UP_VECTOR;      ///> camera up vector
 };
-} // imstk
+}
diff --git a/Source/SceneEntities/Lights/imstkIBLProbe.cpp b/Source/SceneEntities/Lights/imstkIBLProbe.cpp
index de9840747232300769f5ec58f4daa3f0f2a57a2b..9c8b5e1c67ed6602a3d373478a66608111211916 100644
--- a/Source/SceneEntities/Lights/imstkIBLProbe.cpp
+++ b/Source/SceneEntities/Lights/imstkIBLProbe.cpp
@@ -20,9 +20,23 @@
 =========================================================================*/
 
 #include "imstkIBLProbe.h"
+#include "imstkTexture.h"
 
 namespace imstk
 {
+IBLProbe::IBLProbe(std::string irradianceCubemapPath,
+                   std::string radianceCubemapPath, std::string brdfLUTPath) :
+    m_irradianceCubemapPath(irradianceCubemapPath),
+    m_radianceCubemapPath(radianceCubemapPath),
+    m_brdfLUTPath(brdfLUTPath),
+    m_irradianceCubemapTexture(std::make_shared<Texture>(irradianceCubemapPath,
+            Texture::Type::IrradianceCubeMap)),
+    m_radianceCubemapTexture(std::make_shared<Texture>(radianceCubemapPath,
+            Texture::Type::RadianceCubeMap)),
+    m_brdfLUTTexture(std::make_shared<Texture>(brdfLUTPath, Texture::Type::BRDF_LUT))
+{
+}
+
 std::shared_ptr<Texture>
 IBLProbe::getIrradianceCubemapTexture()
 {
diff --git a/Source/SceneEntities/Lights/imstkIBLProbe.h b/Source/SceneEntities/Lights/imstkIBLProbe.h
index e1ad0ed9b04f21044be0ec6d9b75f4673a7b750c..e456b53c60233a0411c53d444143d49bb33f0e5f 100644
--- a/Source/SceneEntities/Lights/imstkIBLProbe.h
+++ b/Source/SceneEntities/Lights/imstkIBLProbe.h
@@ -21,12 +21,13 @@
 
 #pragma once
 
+#include <memory>
 #include <string>
 
-#include "imstkTexture.h"
-
 namespace imstk
 {
+class Texture;
+
 ///
 /// \class IBLProbe
 ///
@@ -48,16 +49,7 @@ public:
     /// \param brdfLUTPath path to BRDF LUT (shouldn't be .dds)
     ///
     IBLProbe(std::string irradianceCubemapPath,
-             std::string radianceCubemapPath,
-             std::string brdfLUTPath) :
-        m_irradianceCubemapPath(irradianceCubemapPath),
-        m_radianceCubemapPath(radianceCubemapPath),
-        m_brdfLUTPath(brdfLUTPath),
-        m_irradianceCubemapTexture(std::make_shared<Texture>(irradianceCubemapPath,
-                           Texture::Type::IrradianceCubeMap)),
-        m_radianceCubemapTexture(std::make_shared<Texture>(radianceCubemapPath,
-                           Texture::Type::RadianceCubeMap)),
-        m_brdfLUTTexture(std::make_shared<Texture>(brdfLUTPath, Texture::Type::BRDF_LUT)) {}
+             std::string radianceCubemapPath, std::string brdfLUTPath);
 
     /// \brief TODO
     std::shared_ptr<Texture> getIrradianceCubemapTexture();
diff --git a/Source/SceneEntities/Lights/imstkLight.cpp b/Source/SceneEntities/Lights/imstkLight.cpp
index 4f522a8407c608217b42366ddc241f8ad4d2c806..ee9dea0c8b1828510ff7dae9051579f3b64c91d6 100644
--- a/Source/SceneEntities/Lights/imstkLight.cpp
+++ b/Source/SceneEntities/Lights/imstkLight.cpp
@@ -20,8 +20,7 @@
 =========================================================================*/
 
 #include "imstkLight.h"
-
-#include <g3log/g3log.hpp>
+#include "imstkLogger.h"
 
 namespace imstk
 {
diff --git a/Source/SceneEntities/Lights/imstkLight.h b/Source/SceneEntities/Lights/imstkLight.h
index 1d46b74e8c3f07d9deb5fcc3c5ac31d9919e5ae4..c0e5d65878a4f973642124a9d8dd3343804f189a 100644
--- a/Source/SceneEntities/Lights/imstkLight.h
+++ b/Source/SceneEntities/Lights/imstkLight.h
@@ -21,13 +21,12 @@
 
 #pragma once
 
-#include <string>
-
-// imstk
 #include "imstkMath.h"
 #include "imstkColor.h"
 #include "imstkSceneEntity.h"
 
+#include <string>
+
 namespace imstk
 {
 ///
@@ -48,6 +47,8 @@ enum class LightType
 class Light : public SceneEntity
 {
 public:
+    virtual ~Light() override = default;
+
     ///
     /// \brief Returns the type of light (see imstk::LightType)
     ///
@@ -113,11 +114,10 @@ public:
     ///
     /// \brief Set the light name
     ///
-    void setName(const std::string& name) { m_name = name; };
-    void setName(const std::string&& name) { m_name = std::move(name); };
+    void setName(std::string name) { m_name = name; };
 
 protected:
-    explicit Light(const std::string& name, const LightType& type) : m_name(name), m_type(type), SceneEntity() {};
+    explicit Light(const std::string& name, const LightType& type) : SceneEntity(), m_name(name), m_type(type) {};
 
     // properties with defaults
     float m_intensity   = 1.;
@@ -150,6 +150,8 @@ public:
         this->setFocalPoint(-1, -1, -1);
     };
 
+    virtual ~DirectionalLight() override = default;
+
     ///
     /// \brief Turn shadows on
     ///
@@ -159,13 +161,19 @@ public:
     /// \brief Center point for shadow projection
     /// Sets the shadow map center to this position
     ///
-    void setShadowCenter(Vec3d center) { m_shadowCenter = Vec3f((float)center[0], (float)center[1], (float)center[2]); };
+    void setShadowCenter(const Vec3d& center) { m_shadowCenter = center.cast<float>(); };
 
     ///
     /// \brief Range for shadows
     /// A smaller range results in a denser shadow map
     ///
-    void setShadowRange(const double range) { m_shadowRange = (float)range; };
+    void setShadowRange(const double range) { m_shadowRange = static_cast<float>(range); };
+
+    ///
+    /// \brief Direction of the light
+    ///
+    void setDirection(const Vec3d& dir) { setFocalPoint(dir); }
+    void setDirection(const double x, const double y, const double z) { setFocalPoint(Vec3d(x, y, z)); }
 
 protected:
     friend class VulkanRenderer;
@@ -194,6 +202,8 @@ public:
     ///
     explicit PointLight(const std::string& name, const LightType& type = LightType::Point) : Light(name, type) {};
 
+    virtual ~PointLight() override = default;
+
     ///
     /// \brief Get the cone angle
     ///
@@ -244,6 +254,8 @@ public:
         m_coneAngle = 10.;
     };
 
+    virtual ~SpotLight() override = default;
+
     ///
     /// \brief Get the spotlight angle in degrees
     ///
diff --git a/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp b/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp
index 3e138b610210623a8ee4770ec5c2505c62c26389..0092ed0bc1db2dda11fa78f193d038b6ce18b402 100644
--- a/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp
+++ b/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp
@@ -20,17 +20,15 @@
 =========================================================================*/
 
 #include "imstkVisualObjectImporter.h"
+#include "imstkAssimpMeshIO.h"
+#include "imstkLogger.h"
 #include "imstkRenderMaterial.h"
-
-#include "assimp/Importer.hpp"
-#include "assimp/mesh.h"
-#include "assimp/scene.h"
-#include "assimp/postprocess.h"
-
+#include "imstkSceneObject.h"
 #include "imstkSurfaceMesh.h"
-#include "imstkAssimpMeshIO.h"
+#include "imstkVisualModel.h"
 
-#include "imstkLogger.h"
+#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
 
 namespace imstk
 {
diff --git a/Source/SceneEntities/Loader/imstkVisualObjectImporter.h b/Source/SceneEntities/Loader/imstkVisualObjectImporter.h
index e6579f26bfbabd38666cebc0c9603443390e1cef..c3a5fc390c19b6625e98da9f42e313dfe9a729c2 100644
--- a/Source/SceneEntities/Loader/imstkVisualObjectImporter.h
+++ b/Source/SceneEntities/Loader/imstkVisualObjectImporter.h
@@ -21,18 +21,13 @@
 
 #pragma once
 
-#include <memory>
-#include <fstream>
-#include <string>
-#include <initializer_list>
-
 #include "imstkTexture.h"
-#include "imstkSceneObject.h"
 #include "imstkMath.h"
 
 namespace imstk
 {
 class RenderMaterial;
+class SceneObject;
 
 ///
 /// \class VisualObjectImporter
@@ -60,7 +55,7 @@ public:
     /// textures are converted to production-ready formats such as .dds.
     /// \returns Visual object
     ///
-    static std::shared_ptr<VisualObject> importVisualObject(
+    static std::shared_ptr<SceneObject> importVisualObject(
         const std::string& objName,
         const std::string& modelFilePath,
         const std::string& textureFolderPath,
diff --git a/Source/SceneEntities/Objects/imstkAnimationObject.cpp b/Source/SceneEntities/Objects/imstkAnimationObject.cpp
index 05f3e455a3958da2bcbaf91fb25917162d819819..a6c408129c89a7cdc7b3d6873bb33d7ab4564e72 100644
--- a/Source/SceneEntities/Objects/imstkAnimationObject.cpp
+++ b/Source/SceneEntities/Objects/imstkAnimationObject.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkAnimationObject.h"
-#include "imstkAnimationModel.h"
 
 namespace imstk
 {
diff --git a/Source/SceneEntities/Objects/imstkCollidingObject.cpp b/Source/SceneEntities/Objects/imstkCollidingObject.cpp
index 39560d82a9fa651b6f45a80af711a34de92c39bd..b6b93acaf3943a0a1f28fd62b2a136b00df08bfc 100644
--- a/Source/SceneEntities/Objects/imstkCollidingObject.cpp
+++ b/Source/SceneEntities/Objects/imstkCollidingObject.cpp
@@ -40,14 +40,14 @@ CollidingObject::initialize()
     return true;
 }
 
-const std::shared_ptr<Geometry>&
+std::shared_ptr<Geometry>
 CollidingObject::getCollidingGeometry() const
 {
     return m_collidingGeometry;
 }
 
 void
-CollidingObject::setCollidingGeometry(const std::shared_ptr<Geometry>& geometry)
+CollidingObject::setCollidingGeometry(std::shared_ptr<Geometry> geometry)
 {
     m_collidingGeometry = geometry;
 }
diff --git a/Source/SceneEntities/Objects/imstkCollidingObject.h b/Source/SceneEntities/Objects/imstkCollidingObject.h
index abdbf60e11a6ee6a70953ab2bb464f63b94520e5..a757fabb195ee5584fac7b3508c259cb881047ed 100644
--- a/Source/SceneEntities/Objects/imstkCollidingObject.h
+++ b/Source/SceneEntities/Objects/imstkCollidingObject.h
@@ -23,7 +23,6 @@
 
 #include "imstkSceneObject.h"
 #include "imstkMath.h"
-#include <unordered_map>
 
 namespace imstk
 {
@@ -50,8 +49,8 @@ public:
     ///
     /// \brief
     ///
-    const std::shared_ptr<Geometry>& getCollidingGeometry() const;
-    void setCollidingGeometry(const std::shared_ptr<Geometry>& geometry);
+    std::shared_ptr<Geometry> getCollidingGeometry() const;
+    void setCollidingGeometry(std::shared_ptr<Geometry> geometry);
 
     ///
     /// \brief Get the master geometry
diff --git a/Source/SceneEntities/Objects/imstkDynamicObject.cpp b/Source/SceneEntities/Objects/imstkDynamicObject.cpp
index c6bf8e64caa458d01b2e9b98fd575f00602f7335..9dc6f2d00db19fda3b56a9cf4f5cca0a5a5abb9e 100644
--- a/Source/SceneEntities/Objects/imstkDynamicObject.cpp
+++ b/Source/SceneEntities/Objects/imstkDynamicObject.cpp
@@ -42,12 +42,7 @@ DynamicObject::getNumOfDOF() const
 void
 DynamicObject::updateGeometries()
 {
-    m_dynamicalModel->updatePhysicsGeometry();
-
-    if (m_physicsToCollidingGeomMap)
-    {
-        m_physicsToCollidingGeomMap->apply();
-    }
+    updatePhysicsGeometry();
 
     if (m_updateVisualFromPhysicsGeometry)
     {
diff --git a/Source/SceneEntities/Objects/imstkDynamicObject.h b/Source/SceneEntities/Objects/imstkDynamicObject.h
index 58a6bb7930dc3030c91312c81c700b06106f8181..a08060780349f008bbdf4ddeb0be55c845416fb6 100644
--- a/Source/SceneEntities/Objects/imstkDynamicObject.h
+++ b/Source/SceneEntities/Objects/imstkDynamicObject.h
@@ -84,7 +84,7 @@ public:
     ///
     /// \brief Update only the physics geometry and apply collision map
     ///
-    void updatePhysicsGeometry();
+    virtual void updatePhysicsGeometry();
 
     ///
     /// \brief Initialize the scene object
@@ -98,7 +98,7 @@ public:
 
 protected:
     ///
-    /// \brief Setup connectivity of compute graph
+    /// \brief Setup connectivity of task graph
     ///
     virtual void initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) override;
 
diff --git a/Source/SceneEntities/Objects/imstkFeDeformableObject.cpp b/Source/SceneEntities/Objects/imstkFeDeformableObject.cpp
index d49510a0a844bf161759b65d0e48874f1c08a1db..ef34448492e5faed86276541a79eda0b5728d071 100644
--- a/Source/SceneEntities/Objects/imstkFeDeformableObject.cpp
+++ b/Source/SceneEntities/Objects/imstkFeDeformableObject.cpp
@@ -40,4 +40,11 @@ FeDeformableObject::initialize()
 
     return true;
 }
+
+std::shared_ptr<FEMDeformableBodyModel>
+FeDeformableObject::getFEMModel()
+{
+    m_femModel = std::dynamic_pointer_cast<FEMDeformableBodyModel>(m_dynamicalModel);
+    return m_femModel;
+}
 } // imstk
diff --git a/Source/SceneEntities/Objects/imstkFeDeformableObject.h b/Source/SceneEntities/Objects/imstkFeDeformableObject.h
index 26c2fbc7475063dc9a7e12d04bb718d9732c2eea..1cef4ac8e665a9428d971e9ed5862bde9eadfdcd 100644
--- a/Source/SceneEntities/Objects/imstkFeDeformableObject.h
+++ b/Source/SceneEntities/Objects/imstkFeDeformableObject.h
@@ -21,10 +21,6 @@
 
 #pragma once
 
-#include <memory>
-#include <string>
-
-// imstk
 #include "imstkDynamicObject.h"
 #include "imstkMath.h"
 
@@ -51,7 +47,7 @@ public:
     ///
     bool initialize() override;
 
-    std::shared_ptr<FEMDeformableBodyModel> getFEMModel() const { return m_femModel; }
+    std::shared_ptr<FEMDeformableBodyModel> getFEMModel();
 
 protected:
     std::shared_ptr<FEMDeformableBodyModel> m_femModel = nullptr;
diff --git a/Source/Solvers/imstkLinearSolver.cpp b/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.cpp
similarity index 57%
rename from Source/Solvers/imstkLinearSolver.cpp
rename to Source/SceneEntities/Objects/imstkLevelSetDeformableObject.cpp
index 88e14c0714b70b29a5bec3aec7dade6a5a6f3e51..53297f534a40d3b696e8bea9b087fdf98814a058 100644
--- a/Source/Solvers/imstkLinearSolver.cpp
+++ b/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.cpp
@@ -19,29 +19,33 @@
 
 =========================================================================*/
 
-#include "imstkLinearSolver.h"
+#include "imstkLevelSetDeformableObject.h"
 #include "imstkLogger.h"
+#include "imstkPbdModel.h"
+#include "imstkLevelSetModel.h"
 
 namespace imstk
 {
-//template<typename SystemMatrixType>
-//LinearSolver<SystemMatrixType>::LinearSolver() : m_linearSystem(nullptr)
-//{
-//
-//}
-
-//template<typename SystemMatrixType>
-//void
-//LinearSolver<SystemMatrixType>::setSystem(std::shared_ptr<LinearSystem<SystemMatrixType>> newSystem)
-//{
-//    m_linearSystem.reset();
-//    m_linearSystem = newSystem;
-//}
-//
-//template<typename SystemMatrixType>
-//std::shared_ptr<LinearSystem<SystemMatrixType>>
-//LinearSolver<SystemMatrixType>::getSystem() const
-//{
-//    return m_linearSystem;
-//}
-} //imstk
\ No newline at end of file
+std::shared_ptr<LevelSetModel>
+LevelSetDeformableObject::getLevelSetModel()
+{
+    m_levelSetModel = std::dynamic_pointer_cast<LevelSetModel>(m_dynamicalModel);
+    return m_levelSetModel;
+}
+
+bool
+LevelSetDeformableObject::initialize()
+{
+    m_levelSetModel = std::dynamic_pointer_cast<LevelSetModel>(m_dynamicalModel);
+    if (m_levelSetModel == nullptr)
+    {
+        LOG(FATAL) << "Dynamics pointer cast failure in LevelSetDeformableObject::initialize()";
+        return false;
+    }
+
+    DynamicObject::initialize();
+    m_levelSetModel->initialize();
+
+    return true;
+}
+}
\ No newline at end of file
diff --git a/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.h b/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8aa41d18c77ae15f1571f3311cb3e639573b62e
--- /dev/null
+++ b/Source/SceneEntities/Objects/imstkLevelSetDeformableObject.h
@@ -0,0 +1,62 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkDynamicObject.h"
+
+namespace imstk
+{
+class LevelSetModel;
+
+///
+/// \class PbdObject
+///
+/// \brief Base class for scene objects that move and/or deform under position
+/// based dynamics formulation, implements the PbdModel and PbdSolver
+///
+class LevelSetDeformableObject : public DynamicObject
+{
+public:
+    explicit LevelSetDeformableObject(const std::string& name) : DynamicObject(name)
+    {
+        m_type = SceneObject::Type::LevelSetDeformable;
+    }
+
+    LevelSetDeformableObject() = delete;
+
+    virtual ~LevelSetDeformableObject() override = default;
+
+public:
+    ///
+    /// \biref Get the Pbd model of the object
+    ///
+    std::shared_ptr<LevelSetModel> getLevelSetModel();
+
+    ///
+    /// \brief Initialize the pbd scene object
+    ///
+    bool initialize() override;
+
+protected:
+    std::shared_ptr<LevelSetModel> m_levelSetModel = nullptr;  ///> PBD mathematical model
+};
+} // imstk
diff --git a/Source/SceneEntities/Objects/imstkPbdObject.cpp b/Source/SceneEntities/Objects/imstkPbdObject.cpp
index 731aa243662478c8d175300cbc08b51910aef344..c0b25eb9042469af3e8ae341927e84b7ae21fb24 100644
--- a/Source/SceneEntities/Objects/imstkPbdObject.cpp
+++ b/Source/SceneEntities/Objects/imstkPbdObject.cpp
@@ -30,7 +30,7 @@ PbdObject::getPbdModel()
 {
     m_pbdModel = std::dynamic_pointer_cast<PbdModel>(m_dynamicalModel);
     return m_pbdModel;
-};
+}
 
 bool
 PbdObject::initialize()
diff --git a/Source/SceneEntities/Objects/imstkPbdObject.h b/Source/SceneEntities/Objects/imstkPbdObject.h
index 0ee18a27ce575a4c5a19b7b5e4d9139fa2964722..d48cae4ca3d4a3e5983e5463ce2ff082d27236ca 100644
--- a/Source/SceneEntities/Objects/imstkPbdObject.h
+++ b/Source/SceneEntities/Objects/imstkPbdObject.h
@@ -43,7 +43,7 @@ public:
 
     PbdObject() = delete;
 
-    ~PbdObject() override = default;
+    virtual ~PbdObject() override = default;
 
 public:
     ///
diff --git a/Source/SceneEntities/Objects/imstkRigidObject.cpp b/Source/SceneEntities/Objects/imstkRigidObject.cpp
index fa2ebba781ae404919be4cf353ecb80b111c0cd0..887861a650ced49cbc5098fd463742d533222722 100644
--- a/Source/SceneEntities/Objects/imstkRigidObject.cpp
+++ b/Source/SceneEntities/Objects/imstkRigidObject.cpp
@@ -46,4 +46,11 @@ RigidObject::addForce(const Vec3d& force, const Vec3d& pos, bool wakeup)
 {
     m_rigidBodyModel->addForce(force, pos, wakeup);
 }
+
+std::shared_ptr<RigidBodyModel>
+RigidObject::getRigidBodyModel()
+{
+    m_rigidBodyModel = std::dynamic_pointer_cast<RigidBodyModel>(m_dynamicalModel);
+    return m_rigidBodyModel;
+}
 } // imstk
diff --git a/Source/SceneEntities/Objects/imstkRigidObject.h b/Source/SceneEntities/Objects/imstkRigidObject.h
index eb24b27f24ab84c3a3ec4b9f9703d5ffd29efca8..8383495bfedcfbefe83a11972d1962be37cf6b32 100644
--- a/Source/SceneEntities/Objects/imstkRigidObject.h
+++ b/Source/SceneEntities/Objects/imstkRigidObject.h
@@ -40,7 +40,7 @@ public:
         m_type = Type::Rigid;
     }
 
-    ~RigidObject() = default;
+    virtual ~RigidObject() = default;
 
 public:
     ///
@@ -53,7 +53,7 @@ public:
     ///
     void addForce(const Vec3d& force, const Vec3d& pos, bool wakeup = true);
 
-    std::shared_ptr<RigidBodyModel> getRigidBodyModel() const { return m_rigidBodyModel; }
+    std::shared_ptr<RigidBodyModel> getRigidBodyModel();
 
 protected:
     std::shared_ptr<RigidBodyModel> m_rigidBodyModel;
diff --git a/Source/SceneEntities/Objects/imstkRigidObject2.cpp b/Source/SceneEntities/Objects/imstkRigidObject2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c907f9e6039090901c5b0c75506f94cf163e6f26
--- /dev/null
+++ b/Source/SceneEntities/Objects/imstkRigidObject2.cpp
@@ -0,0 +1,77 @@
+/*=========================================================================
+
+   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 "imstkRigidObject2.h"
+#include "imstkLogger.h"
+#include "imstkRbdConstraint.h"
+#include "imstkRigidBodyModel2.h"
+#include "imstkPointSet.h"
+
+namespace imstk
+{
+namespace expiremental
+{
+bool
+RigidObject2::initialize()
+{
+    m_rigidBodyModel2 = std::dynamic_pointer_cast<RigidBodyModel2>(m_dynamicalModel);
+    if (m_rigidBodyModel2 == nullptr)
+    {
+        LOG(FATAL) << "Dynamics pointer cast failure in RigidObject2::initialize()";
+        return false;
+    }
+
+    DynamicObject::initialize();
+    m_rigidBodyModel2->initialize();
+
+    updateGeometries();
+    m_physicsGeometry->updatePostTransformData();
+
+    return true;
+}
+
+std::shared_ptr<RigidBodyModel2>
+RigidObject2::getRigidBodyModel2()
+{
+    m_rigidBodyModel2 = std::dynamic_pointer_cast<RigidBodyModel2>(m_dynamicalModel);
+    return m_rigidBodyModel2;
+}
+
+void
+RigidObject2::setDynamicalModel(std::shared_ptr<AbstractDynamicalModel> dynaModel)
+{
+    m_rigidBodyModel2 = std::dynamic_pointer_cast<RigidBodyModel2>(dynaModel);
+    m_dynamicalModel  = dynaModel;
+    m_rigidBody       = m_rigidBodyModel2->addRigidBody();
+}
+
+void
+RigidObject2::updatePhysicsGeometry()
+{
+    // Apply the transform back to the geometry
+    m_physicsGeometry->setTranslation(m_rigidBody->getPosition());
+    m_physicsGeometry->setRotation(m_rigidBody->getOrientation());
+    m_physicsGeometry->updatePostTransformData();
+
+    DynamicObject::updatePhysicsGeometry();
+}
+}
+} // imstk
diff --git a/Source/SceneEntities/Objects/imstkRigidObject2.h b/Source/SceneEntities/Objects/imstkRigidObject2.h
new file mode 100644
index 0000000000000000000000000000000000000000..1a65255404a033e587fdc74827046cbc1dc70909
--- /dev/null
+++ b/Source/SceneEntities/Objects/imstkRigidObject2.h
@@ -0,0 +1,82 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkDynamicObject.h"
+
+namespace imstk
+{
+class PointSet;
+namespace expiremental
+{
+class RigidBodyModel2;
+struct RigidBody;
+
+///
+/// \class RigidObject2
+///
+/// \brief Scene objects that are governed by rigid body dynamics
+///
+class RigidObject2 : public DynamicObject
+{
+public:
+    explicit RigidObject2(const std::string& name) : DynamicObject(name)
+    {
+        m_type = Type::Rigid2;
+    }
+
+    virtual ~RigidObject2() = default;
+
+public:
+    ///
+    /// \brief Initialize the rigid scene object
+    ///
+    bool initialize() override;
+
+    ///
+    /// \brief Add local force at a position relative to object
+    ///
+    //void addForce(const Vec3d& force, const Vec3d& pos, bool wakeup = true);
+
+    std::shared_ptr<RigidBodyModel2> getRigidBodyModel2();
+
+    ///
+    /// \brief Returns body in the model
+    ///
+    std::shared_ptr<RigidBody> getRigidBody() const { return m_rigidBody; }
+
+    ///
+    /// \brief Sets the model, and creates the body within the model
+    ///
+    void setDynamicalModel(std::shared_ptr<AbstractDynamicalModel> dynaModel) override;
+
+    ///
+    /// \brief Updates the physics geometry of the object
+    ///
+    void updatePhysicsGeometry() override;
+
+protected:
+    std::shared_ptr<RigidBodyModel2> m_rigidBodyModel2;
+    std::shared_ptr<RigidBody>       m_rigidBody; ///> Gives the actual body within the model
+};
+}
+} // imstk
\ No newline at end of file
diff --git a/Source/SceneEntities/Objects/imstkSPHObject.cpp b/Source/SceneEntities/Objects/imstkSPHObject.cpp
index b18f3e5a37136a983624a12b0df2d99298277675..33f8d209ceb32460d9a088582fee12ed2666ab74 100644
--- a/Source/SceneEntities/Objects/imstkSPHObject.cpp
+++ b/Source/SceneEntities/Objects/imstkSPHObject.cpp
@@ -52,4 +52,11 @@ SPHObject::initialize()
 
     return true;
 }
+
+std::shared_ptr<SPHModel>
+SPHObject::getSPHModel()
+{
+    m_SPHModel = std::dynamic_pointer_cast<SPHModel>(m_dynamicalModel);
+    return m_SPHModel;
+}
 } // end namespace imstk
diff --git a/Source/SceneEntities/Objects/imstkSPHObject.h b/Source/SceneEntities/Objects/imstkSPHObject.h
index e2d150ed5a840f5f782acf904bf7c48035a16565..99d71291f0787dbe80a2dc293dbdfd4d2ef55977 100644
--- a/Source/SceneEntities/Objects/imstkSPHObject.h
+++ b/Source/SceneEntities/Objects/imstkSPHObject.h
@@ -42,16 +42,16 @@ public:
 
 public:
     ///
-    /// \brief Initialize the SPH scene object
+    /// \brief Get the SPH model of the object
     ///
-    bool initialize() override;
+    std::shared_ptr<SPHModel> getSPHModel();
 
     std::shared_ptr<SPHModel> getDynamicalSPHModel();
 
     ///
-    /// \brief Get the SPH model of the object
+    /// \brief Initialize the SPH scene object
     ///
-    std::shared_ptr<SPHModel> getSPHModel() const { assert(m_SPHModel); return m_SPHModel; }
+    bool initialize() override;
 
 protected:
     std::shared_ptr<SPHModel> m_SPHModel = nullptr;
diff --git a/Source/SceneEntities/Objects/imstkSceneObject.cpp b/Source/SceneEntities/Objects/imstkSceneObject.cpp
index 34aaad5cdab3eb2bb8f9127175c61946f598b847..36850d6da68b57a536745445d3797d9c11f180da 100644
--- a/Source/SceneEntities/Objects/imstkSceneObject.cpp
+++ b/Source/SceneEntities/Objects/imstkSceneObject.cpp
@@ -21,6 +21,7 @@
 
 #include "imstkSceneObject.h"
 #include "imstkTaskGraph.h"
+#include "imstkVisualModel.h"
 
 namespace imstk
 {
diff --git a/Source/SceneEntities/Objects/imstkSceneObject.h b/Source/SceneEntities/Objects/imstkSceneObject.h
index fd1bb82685b31327a1b5118199daf7d95b336830..46c9c115bf766e7aba856d8df1b88ff604799e90 100644
--- a/Source/SceneEntities/Objects/imstkSceneObject.h
+++ b/Source/SceneEntities/Objects/imstkSceneObject.h
@@ -21,14 +21,15 @@
 
 #pragma once
 
-#include "imstkVisualModel.h"
 #include "imstkSceneEntity.h"
 
+#include <memory>
 #include <string>
 #include <vector>
 
 namespace imstk
 {
+class VisualModel;
 class DeviceClient;
 class Geometry;
 class TaskGraph;
@@ -49,11 +50,13 @@ public:
         Animation,
         Colliding,
         Rigid,
+        Rigid2,
         FEMDeformable,
         ReducedFEMDeformable,
         Pbd,
         SPH,
-        Physiology
+        Physiology,
+        LevelSetDeformable
     };
 
     ///
@@ -64,7 +67,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    virtual ~SceneObject() = default;
+    virtual ~SceneObject() override = default;
 
 public:
     ///
diff --git a/Source/SceneEntities/Objects/imstkVisualModel.cpp b/Source/SceneEntities/Objects/imstkVisualModel.cpp
index 9ec3c859847206d902339a212c9002ada003887b..68530b3188092b325f13eb9dda3a1415b5ac5c38 100644
--- a/Source/SceneEntities/Objects/imstkVisualModel.cpp
+++ b/Source/SceneEntities/Objects/imstkVisualModel.cpp
@@ -20,9 +20,7 @@
 =========================================================================*/
 
 #include "imstkVisualModel.h"
-#include "imstkGeometry.h"
 #include "imstkRenderMaterial.h"
-#include "imstkDebugRenderGeometry.h"
 
 namespace imstk
 {
diff --git a/Source/SceneEntities/imstkSceneEntity.h b/Source/SceneEntities/imstkSceneEntity.h
index 4ab41d5d82069300f9489eb4dc349993adfe8003..625737f212c6c71082960648362b767437fee8a3 100644
--- a/Source/SceneEntities/imstkSceneEntity.h
+++ b/Source/SceneEntities/imstkSceneEntity.h
@@ -34,6 +34,8 @@ using EntityID = unsigned long;
 class SceneEntity
 {
 public:
+    virtual ~SceneEntity() = default;
+
     ///
     /// \brief Get ID (ALWAYS query the ID in your code, DO NOT hardcode it)
     /// \returns ID of entity
diff --git a/Source/SimulationManager/CMakeLists.txt b/Source/SimulationManager/CMakeLists.txt
index 446ecf2392c6ae2c918a6c4337904169e7dbf542..291c0b51dc709ca0fae76181e5d35b8b02756ae5 100644
--- a/Source/SimulationManager/CMakeLists.txt
+++ b/Source/SimulationManager/CMakeLists.txt
@@ -6,29 +6,33 @@ set(VTK_H_FILES
     VTKRenderer/imstkVTKTextStatusManager.h
     VTKRenderer/imstkVTKInteractorStyle.h
     VTKRenderer/imstkVTKScreenCaptureUtility.h
+    VTKRenderer/imstkAbstractVTKViewer.h
+    VTKRenderer/imstkVTKOpenVRViewer.h
     VTKRenderer/imstkVTKViewer.h
-    VTKRenderer/imstkOpenVRCommand.h)
+    VTKRenderer/imstkVTKInteractorStyleVR.h)
 
 set(VTK_CPP_FILES
     VTKRenderer/imstkVTKTextStatusManager.cpp
     VTKRenderer/imstkVTKInteractorStyle.cpp
     VTKRenderer/imstkVTKScreenCaptureUtility.cpp
+    VTKRenderer/imstkAbstractVTKViewer.cpp
+    VTKRenderer/imstkVTKOpenVRViewer.cpp
     VTKRenderer/imstkVTKViewer.cpp
-    VTKRenderer/imstkOpenVRCommand.cpp)
+    VTKRenderer/imstkVTKInteractorStyleVR.cpp)
 
 set(VULKAN_H_FILES
     VulkanRenderer/imstkVulkanInteractorStyle.h
     VulkanRenderer/imstkVulkanInteractorStyleFreeCamera.h
-    VulkanRenderer/imstkVulkanInteractorStyleVR.h
     VulkanRenderer/imstkVulkanScreenCaptureUtility.h
-    VulkanRenderer/imstkVulkanViewer.h)
+    VulkanRenderer/imstkVulkanViewer.h
+    VulkanRenderer/imstkVulkanInteractorStyleVR.h)
 
 set(VULKAN_CPP_FILES
     VulkanRenderer/imstkVulkanInteractorStyle.cpp
     VulkanRenderer/imstkVulkanInteractorStyleFreeCamera.cpp
-    VulkanRenderer/imstkVulkanInteractorStyleVR.cpp
     VulkanRenderer/imstkVulkanScreenCaptureUtility.cpp
-    VulkanRenderer/imstkVulkanViewer.cpp)
+    VulkanRenderer/imstkVulkanViewer.cpp
+    VulkanRenderer/imstkVulkanInteractorStyleVR.cpp)
 
 if( NOT iMSTK_USE_Vulkan )
   set(SIMULATIONMANAGER_H_FILES ${VTK_H_FILES})
@@ -43,20 +47,23 @@ else()
 endif()
 
 include(imstkAddLibrary)
-imstk_add_library( SimulationManager
+imstk_add_library(SimulationManager
   H_FILES
+    imstkConsoleThread.h
+    imstkInteractorStyle.h
+    imstkKeyboardSceneControl.h
+    imstkMouseSceneControl.h
     imstkSceneManager.h
-    imstkSimulationManager.h
-    imstkViewer.h
     imstkScreenCaptureUtility.h
-    imstkInteractorStyle.h
+    imstkViewer.h
     ${SIMULATIONMANAGER_H_FILES}
   CPP_FILES
+    imstkConsoleThread.cpp
+    imstkKeyboardSceneControl.cpp
+    imstkMouseSceneControl.cpp
     imstkSceneManager.cpp
-    imstkSimulationManager.cpp
-    imstkViewer.cpp
     imstkScreenCaptureUtility.cpp
-    imstkInteractorStyle.cpp
+    imstkViewer.cpp
     ${SIMULATIONMANAGER_CPP_FILES}
   SUBDIR_LIST
     ${SIMULATIONMANAGER_SUBDIR}
diff --git a/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.cpp b/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c516f5f5e3a45efb546b9ee581e83a1b4a2927b7
--- /dev/null
+++ b/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.cpp
@@ -0,0 +1,168 @@
+/*=========================================================================
+
+   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 "imstkAbstractVTKViewer.h"
+#include "imstkLogger.h"
+#include "imstkScene.h"
+#include "imstkVTKInteractorStyle.h"
+#include "imstkVTKRenderer.h"
+
+#include <vtkCallbackCommand.h>
+#include <vtkRenderer.h>
+#include <vtkRenderWindow.h>
+#include <vtkRenderWindowInteractor.h>
+#include <vtkCallbackCommand.h>
+
+namespace imstk
+{
+AbstractVTKViewer::AbstractVTKViewer(std::string name) : Viewer(name)
+{
+    viewerDisabledCallback = vtkSmartPointer<vtkCallbackCommand>::New();
+    viewerDisabledCallback->SetCallback(viewerDisabled);
+    viewerDisabledCallback->SetClientData(this);
+    viewerEnabledCallback = vtkSmartPointer<vtkCallbackCommand>::New();
+    viewerEnabledCallback->SetCallback(viewerEnabled);
+    viewerEnabledCallback->SetClientData(this);
+}
+
+Renderer::Mode
+AbstractVTKViewer::getRenderingMode() const
+{
+    return this->getActiveRenderer()->getMode();
+}
+
+void
+AbstractVTKViewer::stopThread()
+{
+    // close the rendering window
+    m_vtkRenderWindow->Finalize();
+
+    // Terminate the interactor
+    m_vtkRenderWindow->GetInteractor()->TerminateApp();
+}
+
+void
+AbstractVTKViewer::pause(bool sync)
+{
+    // It doesn't actually stop until disable event
+    if (m_status == ThreadStatus::Inactive)
+    {
+        return;
+    }
+
+    this->postEvent(Event(EventType::Pause));
+
+    pauseThread();
+
+    if (m_status == ThreadStatus::Running)
+    {
+        // Request that it disables
+
+        // If sync, wait until the module actually pauses before returning from function
+        if (sync)
+        {
+            m_vtkRenderWindow->GetInteractor()->AddObserver(vtkCallbackCommand::DisableEvent, viewerDisabledCallback);
+            m_vtkRenderWindow->GetInteractor()->Disable();
+            while (m_status != ThreadStatus::Paused) { }
+            m_vtkRenderWindow->GetInteractor()->RemoveObserver(viewerDisabledCallback);
+        }
+        else
+        {
+            m_vtkRenderWindow->GetInteractor()->Disable();
+        }
+    }
+}
+
+void
+AbstractVTKViewer::resume(bool sync)
+{
+    if (m_status == ThreadStatus::Inactive)
+    {
+        return;
+    }
+
+    this->postEvent(Event(EventType::Resume));
+
+    resumeThread();
+    if (m_status == ThreadStatus::Paused)
+    {
+        m_requestedStatus = ThreadStatus::Running;
+        // If sync, wait until the module actually pauses before returning from function
+        if (sync)
+        {
+            m_vtkRenderWindow->GetInteractor()->AddObserver(vtkCallbackCommand::EnableEvent, viewerEnabledCallback);
+            m_vtkRenderWindow->GetInteractor()->Disable();
+            while (m_status != ThreadStatus::Running) { }
+            m_vtkRenderWindow->GetInteractor()->RemoveObserver(viewerEnabledCallback);
+        }
+        else
+        {
+            m_vtkRenderWindow->GetInteractor()->Disable();
+        }
+    }
+}
+
+void
+AbstractVTKViewer::setSize(const int width, const int height)
+{
+    if (m_vtkRenderWindow != NULL)
+    {
+        m_vtkRenderWindow->SetSize(width, height);
+    }
+}
+
+void
+AbstractVTKViewer::setWindowTitle(const std::string& title)
+{
+    m_config->m_windowName = title;
+    if (m_vtkRenderWindow)
+    {
+        m_vtkRenderWindow->SetWindowName(title.c_str());
+    }
+}
+
+void
+AbstractVTKViewer::setBackgroundColors(const Vec3d color1, const Vec3d color2 /*= Vec3d::Zero()*/, const bool gradientBackground /*= false*/)
+{
+    if (getActiveScene() == nullptr)
+    {
+        LOG(WARNING) << "Must set active scene before setting background color";
+        return;
+    }
+    this->getActiveRenderer()->updateBackground(color1, color2, gradientBackground);
+}
+
+void
+AbstractVTKViewer::viewerDisabled(vtkObject* vtkNotUsed(sender),
+                                  unsigned long vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData))
+{
+    imstk::AbstractVTKViewer* viewer = static_cast<imstk::AbstractVTKViewer*>(clientData);
+    viewer->m_status = ThreadStatus::Paused;
+}
+
+void
+AbstractVTKViewer::viewerEnabled(vtkObject* vtkNotUsed(sender),
+                                 unsigned long vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData))
+{
+    imstk::AbstractVTKViewer* viewer = static_cast<imstk::AbstractVTKViewer*>(clientData);
+    viewer->m_status = ThreadStatus::Running;
+}
+}
diff --git a/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.h b/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.h
new file mode 100644
index 0000000000000000000000000000000000000000..869a04ff4915759f9df045b0ca46616d1cb6d1c8
--- /dev/null
+++ b/Source/SimulationManager/VTKRenderer/imstkAbstractVTKViewer.h
@@ -0,0 +1,116 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkViewer.h"
+
+#include <vtkSmartPointer.h>
+
+class vtkInteractorStyle;
+class vtkRenderWindow;
+class vtkCallbackCommand;
+class vtkObject;
+
+namespace imstk
+{
+class VTKScreenCaptureUtility;
+class VTKTextStatusManager;
+
+///
+/// \class AbstractVTKViewer
+///
+/// \brief Subclasses viewer for the VTK rendering back-end
+/// \todo: Implement pausing/resuming
+///
+class AbstractVTKViewer : public Viewer
+{
+protected:
+    AbstractVTKViewer(std::string name);
+public:
+    virtual ~AbstractVTKViewer() override = default;
+
+public:
+    ///
+    /// \brief Terminate rendering
+    ///
+    virtual void stopThread() override;
+
+    ///
+    /// \brief Pause is reimplemented for VTK viewers
+    ///
+    void pause(bool sync = false) override;
+
+    ///
+    /// \brief Resume is reimplemented for VTK viewers
+    ///
+    void resume(bool sync = false) override;
+
+public:
+    ///
+    /// \brief Get the current renderer mode
+    ///
+    virtual Renderer::Mode getRenderingMode() const override;
+
+    ///
+    /// \brief Get pointer to the vtkRenderWindow rendering
+    ///
+    vtkSmartPointer<vtkRenderWindow> getVtkRenderWindow() const { return m_vtkRenderWindow; }
+
+    ///
+    /// \brief Set the render window size
+    ///
+    void setSize(const int width, const int height) override;
+
+    ///
+    /// \brief Set the render window title
+    ///
+    void setWindowTitle(const std::string& title) override;
+
+    ///
+    /// \brief Set the coloring of the screen background
+    /// If 'gradientBackground' is false or not supplied color1 will fill the entire background
+    ///
+    virtual void setBackgroundColors(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(),
+                                     const bool gradientBackground = false) override;
+
+    ///
+    /// \brief Returns the vtk interactor style
+    ///
+    std::shared_ptr<vtkInteractorStyle> getVtkInteractorStyle() const { return m_vtkInteractorStyle; }
+
+protected:
+    ///
+    /// \brief Callback for when the viewer is disabled
+    ///
+    static void viewerDisabled(vtkObject* sender, unsigned long eventId, void* clientData, void* callData);
+    ///
+    /// \brief Callback for when the viewer is enabled
+    ///
+    static void viewerEnabled(vtkObject* sender, unsigned long eventId, void* clientData, void* callData);
+
+protected:
+    vtkSmartPointer<vtkRenderWindow>    m_vtkRenderWindow;
+    std::shared_ptr<vtkInteractorStyle> m_vtkInteractorStyle;
+    vtkSmartPointer<vtkCallbackCommand> viewerDisabledCallback;
+    vtkSmartPointer<vtkCallbackCommand> viewerEnabledCallback;
+};
+} // imstk
diff --git a/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.cpp b/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.cpp
deleted file mode 100644
index 2ba7f86c8b2cc2a950e5bf49e5b43eb856b14211..0000000000000000000000000000000000000000
--- a/Source/SimulationManager/VTKRenderer/imstkOpenVRCommand.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*=========================================================================
-
-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.
-
-=========================================================================*/
-
-// vtk
-#include <vtkObjectFactory.h>
-
-// imstk
-#include "imstkOpenVRCommand.h"
-#include "imstkSimulationManager.h"
-#include "VTKRenderer/imstkVTKRenderer.h"
-#include "imstkCamera.h"
-
-namespace imstk
-{
-void
-OpenVRCommand::Execute(
-    vtkObject*    caller,
-    unsigned long eventId,
-    void*         callData)
-{
-    /// \todo Clear warnings  caller, callData are not used!
-    // prevent warnings
-    caller;
-    callData;
-
-    if (!m_simManager)
-    {
-        return;
-    }
-
-    // trigger button
-    if (eventId == vtkCommand::CharEvent)
-    {
-        SimulationStatus status = m_simManager->getStatus();
-
-        if (status == SimulationStatus::Running)
-        {
-            m_simManager->pause();
-        }
-
-        // pause simulation
-        if (status == SimulationStatus::Inactive)
-        {
-            m_simManager->start();
-        }
-
-        // continue simulation
-        if (status == SimulationStatus::Paused)
-        {
-            m_simManager->run();
-        }
-
-        this->AbortFlagOn();
-    }
-
-    if (eventId == vtkCommand::LeftButtonPressEvent)
-    {
-        SimulationStatus status = m_simManager->getStatus();
-
-        // pause simulation
-        if (status == SimulationStatus::Running)
-        {
-            m_simManager->pause();
-        }
-
-        // continue simulation
-        if (status == SimulationStatus::Paused)
-        {
-            m_simManager->run();
-        }
-
-        this->AbortFlagOn();
-    }
-
-    // home button
-    if (eventId == vtkCommand::FourthButtonReleaseEvent)
-    {
-        SimulationStatus status = m_simManager->getStatus();
-
-        if (status == SimulationStatus::Inactive)
-        {
-            m_simManager->start();
-        }
-        else
-        {
-            m_simManager->end();
-        }
-
-        this->AbortFlagOn();
-    }
-
-    // Pad
-    if (eventId == vtkCommand::RightButtonPressEvent)
-    {
-        SimulationStatus status = m_simManager->getStatus();
-        // desactivate pad if in simulation mode
-        if (status != SimulationStatus::Inactive)
-        {
-            this->AbortFlagOn();
-        }
-    }
-
-    // grip button
-    if (eventId == vtkCommand::MiddleButtonPressEvent)
-    {
-        /// \todo Take a screenshot
-
-        this->AbortFlagOn();
-    }
-
-    // Update render delagates after each rendering
-    // same as subclassing vtkOpenVRRenderWindowInteractor and
-    // override DoOneEvent() by calling itself and then updateRenderDelegates()
-    if (eventId == vtkCommand::StartEvent)
-    {
-        //SimulationStatus status = m_simManager->getStatus();
-
-#ifndef iMSTK_USE_Vulkan
-        std::dynamic_pointer_cast<VTKRenderer>(m_simManager->getViewer()->getActiveRenderer())->updateRenderDelegates();
-#endif
-    }
-    else
-    {
-        //int a = eventId;
-    }
-}
-} // imstk
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp
index 78a57f8beb24b49ad386afc5ebea67b14c728be7..72f7ec3878e7b52dae34e395e47ba08d8a0738d3 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp
@@ -19,29 +19,22 @@
 
 =========================================================================*/
 
-// imstk
 #include "imstkVTKInteractorStyle.h"
-#include "imstkSimulationManager.h"
-#include "imstkVTKTextStatusManager.h"
-#include "imstkVTKRenderer.h"
-#include "imstkCamera.h"
-#include "imstkScene.h"
+#include "imstkKeyboardDeviceClient.h"
+#include "imstkMouseDeviceClient.h"
 
-// vtk
-#include "vtkObjectFactory.h"
-#include "vtkRenderWindow.h"
-#include "vtkRenderWindowInteractor.h"
-#include "vtkRenderer.h"
-#include "vtkCamera.h"
-#include "vtkTextActor.h"
+#include <vtkObjectFactory.h>
+#include <vtkRenderWindowInteractor.h>
+#include <vtkRenderWindow.h>
 
 namespace imstk
 {
-VTKInteractorStyle::VTKInteractorStyle()
+vtkStandardNewMacro(VTKInteractorStyle);
+
+VTKInteractorStyle::VTKInteractorStyle() :
+    m_keyboardDeviceClient(KeyboardDeviceClient::New()),
+    m_mouseDeviceClient(MouseDeviceClient::New())
 {
-    m_textStatusManager = std::make_shared<VTKTextStatusManager>(this);
-    m_lastFpsUpdate     = std::chrono::high_resolution_clock::now();
-    m_lastFps = 60.0;
 }
 
 VTKInteractorStyle::~VTKInteractorStyle()
@@ -50,337 +43,82 @@ VTKInteractorStyle::~VTKInteractorStyle()
 }
 
 void
-VTKInteractorStyle::SetCurrentRenderer(vtkRenderer* ren)
+VTKInteractorStyle::OnTimer()
 {
-    // Remove actor if previous renderer
-    if (this->CurrentRenderer)
-    {
-        for (int i = 0; i < VTKTextStatusManager::NumStatusTypes; ++i)
-        {
-            this->CurrentRenderer->RemoveActor2D(m_textStatusManager->getTextActor(i));
-        }
-    }
-
-    // Set new current renderer
-    vtkBaseInteractorStyle::SetCurrentRenderer(ren);
-
-    // Add actor to current renderer
-    for (int i = 0; i < VTKTextStatusManager::NumStatusTypes; ++i)
-    {
-        this->CurrentRenderer->AddActor2D(m_textStatusManager->getTextActor(i));
-    }
+    m_updateFunc();
 }
 
 void
-VTKInteractorStyle::OnTimer()
+VTKInteractorStyle::OnKeyPress()
 {
-    auto renderer = std::static_pointer_cast<VTKRenderer>(m_simManager->getViewer()->getActiveRenderer());
-
-    // Update Camera
-    renderer->updateSceneCamera(m_simManager->getActiveScene()->getCamera());
-
-    // Update render delegates
-    renderer->updateRenderDelegates();
-
-    // Reset camera clipping range
-    this->CurrentRenderer->ResetCameraClippingRange();
-
-    if (m_displayFps)
-    {
-        // Update framerate value display
-        auto   now       = std::chrono::high_resolution_clock::now();
-        double visualFPS = 1e6 / static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(now - m_pre).count());
-        visualFPS = 0.1 * visualFPS + 0.9 * m_lastFps;
-        m_lastFps = visualFPS;
-
-        int t = static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastFpsUpdate).count());
-        if (t > 250) //wait 250ms before updating displayed value
-        {
-            double physicalFPS;
-            if (m_simManager->getStatus() != SimulationStatus::Paused)
-            {
-                physicalFPS = m_simManager->getActiveScene()->getFPS();
-            }
-            else
-            {
-                physicalFPS = -1.0; // negative value means paused
-            }
-
-            m_textStatusManager->setFPS(visualFPS, physicalFPS);
-            m_lastFpsUpdate = now;
-        }
-        m_pre = now;
-    }
-
-    // Render
-    this->Interactor->Render();
-    m_post = std::chrono::high_resolution_clock::now();
-
-    // Plan next render
-    this->Interactor->CreateOneShotTimer(0);
-
-    // Call custom behavior
-    if (m_onTimerFunction)
-    {
-        // Call the custom behavior to run on every frame
-        m_onTimerFunction(this);
-    }
+    // Submit the change to the keyboard device client
+    m_keyboardDeviceClient->emitKeyDown(this->Interactor->GetKeyCode());
 }
 
 void
-VTKInteractorStyle::OnChar()
+VTKInteractorStyle::OnKeyRelease()
 {
-    char key = this->Interactor->GetKeyCode();
-
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onCharFunctionMap.count(key)
-        && m_onCharFunctionMap.at(key)
-        && m_onCharFunctionMap.at(key)(this))
-    {
-        return;
-    }
-
-    SimulationStatus status = m_simManager->getStatus();
-
-    if (key == ' ')
-    {
-        // pause simulation
-        if (status == SimulationStatus::Running)
-        {
-            m_simManager->pause();
-        }
-        // play simulation
-        else if (status == SimulationStatus::Paused)
-        {
-            m_simManager->run();
-        }
-        // Launch simulation if inactive
-        if (status == SimulationStatus::Inactive)
-        {
-            m_textStatusManager->setStatusVisibility(VTKTextStatusManager::FPS, m_displayFps);
-            m_simManager->start(SimulationStatus::Running);
-        }
-    }
-    else if (status != SimulationStatus::Inactive
-             && (key == 'q' || key == 'Q' || key == 'e' || key == 'E')) // end Simulation
-    {
-        m_textStatusManager->setStatusVisibility(VTKTextStatusManager::FPS, false);
-        //m_simManager->endSimulation();
-    }
-    else if (key == 'd' || key == 'D')  // switch rendering mode
-    {
-        if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Simulation)
-        {
-            m_simManager->getViewer()->setRenderingMode(Renderer::Mode::Simulation);
-        }
-        else
-        {
-            m_simManager->getViewer()->setRenderingMode(Renderer::Mode::Debug);
-        }
-    }
-    else if (key == '\u001B')  // quit viewer
-    {
-        m_simManager->getViewer()->endRenderingLoop();
-    }
-    else if (key == 'p' || key == 'P')  // switch framerate display
-    {
-        m_displayFps = !m_displayFps;
-        m_textStatusManager->setStatusVisibility(VTKTextStatusManager::FPS, m_displayFps);
-        this->Interactor->Render();
-    }
-    else if (key == 'r' || key == 'R')
-    {
-        m_simManager->reset();
-    }
+    // Submit the change to the keyboard device client
+    m_keyboardDeviceClient->emitKeyUp(this->Interactor->GetKeyCode());
 }
 
 void
 VTKInteractorStyle::OnMouseMove()
 {
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onMouseMoveFunction
-        && m_onMouseMoveFunction(this))
-    {
-        return;
-    }
-
-    // Default behavior : ignore mouse if simulation active
-    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug)
-    {
-        return;
-    }
-
-    // Else : use base class interaction
-    vtkBaseInteractorStyle::OnMouseMove();
+    Vec2i mousePos;
+    this->Interactor->GetEventPosition(mousePos[0], mousePos[1]);
+    Vec2i dim;
+    Interactor->GetSize(dim[0], dim[1]);
+    m_mouseDeviceClient->updateMousePos(mousePos.cast<double>().cwiseQuotient(dim.cast<double>()));
 }
 
 void
 VTKInteractorStyle::OnLeftButtonDown()
 {
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onLeftButtonDownFunction
-        && m_onLeftButtonDownFunction(this))
-    {
-        return;
-    }
-
-    // Default behavior : ignore mouse if simulation active
-    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug)
-    {
-        return;
-    }
-
-    // Else : use base class interaction
-    vtkBaseInteractorStyle::OnLeftButtonDown();
+    m_mouseDeviceClient->emitButtonPress(LEFT_BUTTON);
 }
 
 void
 VTKInteractorStyle::OnLeftButtonUp()
 {
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onLeftButtonUpFunction
-        && m_onLeftButtonUpFunction(this))
-    {
-        return;
-    }
-
-    // Default behavior : ignore mouse if simulation active
-    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug)
-    {
-        return;
-    }
-
-    // Else : use base class interaction
-    vtkBaseInteractorStyle::OnLeftButtonUp();
+    m_mouseDeviceClient->emitButtonRelease(LEFT_BUTTON);
 }
 
 void
 VTKInteractorStyle::OnMiddleButtonDown()
 {
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onMiddleButtonDownFunction
-        && m_onMiddleButtonDownFunction(this))
-    {
-        return;
-    }
-
-    // Default behavior : ignore mouse if simulation active
-    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug)
-    {
-        return;
-    }
-
-    // Else : use base class interaction
-    vtkBaseInteractorStyle::OnMiddleButtonDown();
+    m_mouseDeviceClient->emitButtonPress(MIDDLE_BUTTON);
 }
 
 void
 VTKInteractorStyle::OnMiddleButtonUp()
 {
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onMiddleButtonUpFunction
-        && m_onMiddleButtonUpFunction(this))
-    {
-        return;
-    }
-
-    // Default behavior : ignore mouse if simulation active
-    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug)
-    {
-        return;
-    }
-
-    // Else : use base class interaction
-    vtkBaseInteractorStyle::OnMiddleButtonUp();
+    m_mouseDeviceClient->emitButtonRelease(MIDDLE_BUTTON);
 }
 
 void
 VTKInteractorStyle::OnRightButtonDown()
 {
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onRightButtonDownFunction
-        && m_onRightButtonDownFunction(this))
-    {
-        return;
-    }
-
-    // Default behavior : ignore mouse if simulation active
-    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug)
-    {
-        return;
-    }
-
-    // Else : use base class interaction
-    vtkBaseInteractorStyle::OnRightButtonDown();
+    m_mouseDeviceClient->emitButtonPress(RIGHT_BUTTON);
 }
 
 void
 VTKInteractorStyle::OnRightButtonUp()
 {
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onRightButtonUpFunction
-        && m_onRightButtonUpFunction(this))
-    {
-        return;
-    }
-
-    // Default behavior : ignore mouse if simulation active
-    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug)
-    {
-        return;
-    }
-
-    // Else : use base class interaction
-    vtkBaseInteractorStyle::OnRightButtonUp();
+    m_mouseDeviceClient->emitButtonRelease(RIGHT_BUTTON);
 }
 
 void
 VTKInteractorStyle::OnMouseWheelForward()
 {
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onMouseWheelForwardFunction
-        && m_onMouseWheelForwardFunction(this))
-    {
-        return;
-    }
-
-    // Default behavior : ignore mouse if simulation active
-    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug)
-    {
-        return;
-    }
-
-    // Else : use base class interaction
-    vtkBaseInteractorStyle::OnMouseWheelForward();
+    // \todo: VTK provides no scroll amount?
+    m_mouseDeviceClient->emitScroll(-0.2);
 }
 
 void
 VTKInteractorStyle::OnMouseWheelBackward()
 {
-    // Call custom function if exists, and return
-    // if it returned `override=true`
-    if (m_onMouseWheelBackwardFunction
-        && m_onMouseWheelBackwardFunction(this))
-    {
-        return;
-    }
-
-    // Default behavior : ignore mouse if simulation active
-    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::Debug)
-    {
-        return;
-    }
-
-    // Else : use base class interaction
-    vtkBaseInteractorStyle::OnMouseWheelBackward();
+    // \todo: VTK provides no scroll amount?
+    m_mouseDeviceClient->emitScroll(0.2);
+}
 }
-} // imstk
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h
index 69a9c3d3bebc06a5d21deca5bc38eb70f6e1756e..45a4b45659100254fb27946f1d6059980dbdcd44 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h
@@ -21,36 +21,28 @@
 
 #pragma once
 
-#include <chrono>
-#include <memory>
-
 #include "imstkInteractorStyle.h"
 
-#include "vtkInteractorStyleTrackballCamera.h"
+#include <vtkInteractorStyleTrackballCamera.h>
 
 namespace imstk
 {
-class SimulationManager;
-class VTKTextStatusManager;
-/// Base class of the vtk interactor style used
-using vtkBaseInteractorStyle = vtkInteractorStyleTrackballCamera;
+class KeyboardDeviceClient;
+class MouseDeviceClient;
 
 ///
 /// \class VTKInteractorStyle
 ///
-/// \brief TODO
+/// \brief Interactor styles forward their controls to imstk objects
 ///
-class VTKInteractorStyle : public vtkBaseInteractorStyle, public InteractorStyle
+class VTKInteractorStyle : public vtkInteractorStyleTrackballCamera, public InteractorStyle
 {
 public:
-    vtkTypeMacro(VTKInteractorStyle, vtkBaseInteractorStyle) VTKInteractorStyle();
+    static VTKInteractorStyle* New();
+    vtkTypeMacro(VTKInteractorStyle, vtkInteractorStyleTrackballCamera) VTKInteractorStyle();
     virtual ~VTKInteractorStyle() override;
 
-    ///
-    /// \brief Set current renderer
-    ///
-    virtual void SetCurrentRenderer(vtkRenderer* ren) override;
-
+public:
     ///
     /// \brief Slot for timer tick
     ///
@@ -59,7 +51,19 @@ public:
     ///
     /// \brief Slot for key pressed
     ///
-    virtual void OnChar() override;
+    virtual void OnKeyPress() override;
+
+    ///
+    /// \brief Slot for key released
+    ///
+    virtual void OnKeyRelease() override;
+
+    ///
+    /// \brief Filter out these events
+    ///
+    virtual void OnKeyDown() override { }
+    virtual void OnKeyUp() override { }
+    virtual void OnChar() override { }
 
     ///
     /// \brief Slot for moved mouse cursor
@@ -114,27 +118,11 @@ public:
     virtual void OnFourthButtonUp() override {}
     virtual void OnFifthButtonUp() override {}
 
-    ///
-    /// \brief Return the pointer to simulation manager
-    ///
-    SimulationManager* getSimulationManager() { return m_simManager; }
-
-    ///
-    /// \brief Return the window status handler
-    ///
-    const std::shared_ptr<VTKTextStatusManager>& getTextStatusManager() { return m_textStatusManager; }
+    std::shared_ptr<KeyboardDeviceClient> getKeyboardDeviceClient() const { return m_keyboardDeviceClient; }
+    std::shared_ptr<MouseDeviceClient> getMouseDeviceClient() const { return m_mouseDeviceClient; }
 
 private:
-
-    friend class VTKViewer;
-
-    SimulationManager* m_simManager;                                ///> SimulationManager owning the current simulation being interacted with
-    std::chrono::high_resolution_clock::time_point m_pre;           ///> time point pre-rendering
-    std::chrono::high_resolution_clock::time_point m_post;          ///> time point post-rendering
-    std::chrono::high_resolution_clock::time_point m_lastFpsUpdate; ///> time point for last framerate display update
-
-    std::shared_ptr<VTKTextStatusManager> m_textStatusManager;      ///> Handle text statuses, including fps status and custom text status
-    bool   m_displayFps = false;                                    ///> hide or display framerate
-    double m_lastFps;                                               ///> last framerate value used for moving average estimate
+    std::shared_ptr<KeyboardDeviceClient> m_keyboardDeviceClient;
+    std::shared_ptr<MouseDeviceClient>    m_mouseDeviceClient;
 };
 } // imstk
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..47c9723cfd052a597b1efda9aa28686393791032
--- /dev/null
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.cpp
@@ -0,0 +1,133 @@
+/*=========================================================================
+
+   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 "imstkVTKInteractorStyleVR.h"
+#include "imstkOpenVRDeviceClient.h"
+
+#include <vtkObjectFactory.h>
+#include <vtkOpenVRRenderWindowInteractor.h>
+
+vtkStandardNewMacro(vtkInteractorStyleVR);
+
+vtkInteractorStyleVR::vtkInteractorStyleVR()
+{
+    // Setup the VR device clients
+    m_leftControllerDeviceClient  = imstk::OpenVRDeviceClient::New(OPENVR_LEFT_CONTROLLER);
+    m_rightControllerDeviceClient = imstk::OpenVRDeviceClient::New(OPENVR_RIGHT_CONTROLLER);
+    m_hmdDeviceClient = imstk::OpenVRDeviceClient::New(OPENVR_HMD);
+}
+
+void
+vtkInteractorStyleVR::OnMove3D(vtkEventData* eventData)
+{
+    if (eventData->GetType() != vtkCommand::Move3DEvent)
+    {
+        return;
+    }
+    vtkEventDataDevice3D* eventDataDevice = static_cast<vtkEventDataDevice3D*>(eventData);
+    if (vtkEventDataDevice::LeftController == eventDataDevice->GetDevice())
+    {
+        imstk::Vec3d pos;
+        eventDataDevice->GetWorldPosition(pos.data());
+        double orientation[4];
+        eventDataDevice->GetWorldOrientation(orientation);
+        m_leftControllerDeviceClient->setPose(pos, imstk::Quatd(imstk::Rotd(vtkMath::RadiansFromDegrees(orientation[0]),
+            imstk::Vec3d(orientation[1], orientation[2], orientation[3]))));
+    }
+    else if (vtkEventDataDevice::RightController == eventDataDevice->GetDevice())
+    {
+        imstk::Vec3d pos;
+        eventDataDevice->GetWorldPosition(pos.data());
+        double orientation[4];
+        eventDataDevice->GetWorldOrientation(orientation);
+        m_rightControllerDeviceClient->setPose(pos, imstk::Quatd(imstk::Rotd(vtkMath::RadiansFromDegrees(orientation[0]),
+            imstk::Vec3d(orientation[1], orientation[2], orientation[3]))));
+    }
+    else if (vtkEventDataDevice::HeadMountedDisplay == eventDataDevice->GetDevice())
+    {
+        imstk::Vec3d pos;
+        eventDataDevice->GetWorldPosition(pos.data());
+        double orientation[4];
+        eventDataDevice->GetWorldOrientation(orientation);
+        m_hmdDeviceClient->setPose(pos, imstk::Quatd(imstk::Rotd(vtkMath::RadiansFromDegrees(orientation[0]),
+            imstk::Vec3d(orientation[1], orientation[2], orientation[3]))));
+    }
+}
+
+void
+vtkInteractorStyleVR::OnButton3D(vtkEventData* eventData)
+{
+    if (eventData->GetType() != vtkCommand::Button3DEvent)
+    {
+        return;
+    }
+    vtkEventDataButton3D*         eventDataButton = static_cast<vtkEventDataButton3D*>(eventData);
+    const vtkEventDataDevice      device = eventDataButton->GetDevice();
+    const vtkEventDataAction      action = eventDataButton->GetAction();
+    const vtkEventDataDeviceInput input  = eventDataButton->GetInput();
+
+    switch (action)
+    {
+    case vtkEventDataAction::Press:
+        if (device == vtkEventDataDevice::LeftController)
+        {
+            m_leftControllerDeviceClient->emitButtonPress(static_cast<int>(input));
+        }
+        else if (device == vtkEventDataDevice::RightController)
+        {
+            m_rightControllerDeviceClient->emitButtonPress(static_cast<int>(input));
+        }
+        break;
+    case vtkEventDataAction::Release:
+        if (device == vtkEventDataDevice::LeftController)
+        {
+            m_leftControllerDeviceClient->emitButtonRelease(static_cast<int>(input));
+        }
+        else if (device == vtkEventDataDevice::RightController)
+        {
+            m_rightControllerDeviceClient->emitButtonRelease(static_cast<int>(input));
+        }
+        break;
+    case vtkEventDataAction::Touch:
+        if (device == vtkEventDataDevice::LeftController)
+        {
+            m_leftControllerDeviceClient->emitButtonTouched(static_cast<int>(input));
+        }
+        else if (device == vtkEventDataDevice::RightController)
+        {
+            m_rightControllerDeviceClient->emitButtonTouched(static_cast<int>(input));
+        }
+        break;
+    case vtkEventDataAction::Untouch:
+        if (device == vtkEventDataDevice::LeftController)
+        {
+            m_leftControllerDeviceClient->emitButtonUntouched(static_cast<int>(input));
+        }
+        else if (device == vtkEventDataDevice::RightController)
+        {
+            m_rightControllerDeviceClient->emitButtonUntouched(static_cast<int>(input));
+        }
+        break;
+    default:
+        break;
+    }
+    ;
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.h b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e6451469a2ebb562aab25c3eb8578cfd6e00a81
--- /dev/null
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyleVR.h
@@ -0,0 +1,61 @@
+/*=========================================================================
+
+   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 "imstkInteractorStyle.h"
+
+#include <vtkInteractorStyle3D.h>
+
+namespace imstk
+{
+class OpenVRDeviceClient;
+}
+
+///
+/// \brief VTK Interactor style for VR
+///
+class vtkInteractorStyleVR : public vtkInteractorStyle3D, public imstk::InteractorStyle
+{
+public:
+    static vtkInteractorStyleVR* New();
+    vtkTypeMacro(vtkInteractorStyleVR, vtkInteractorStyle3D);
+
+    void OnMove3D(vtkEventData* edata) override;
+    void OnButton3D(vtkEventData* edata) override;
+    void OnTimer() override
+    {
+        if (m_updateFunc != nullptr)
+        {
+            m_updateFunc();
+        }
+    }
+
+    std::shared_ptr<imstk::OpenVRDeviceClient> getLeftControllerDeviceClient() const { return m_leftControllerDeviceClient; }
+    std::shared_ptr<imstk::OpenVRDeviceClient> getRightControllerDeviceClient() const { return m_rightControllerDeviceClient; }
+    std::shared_ptr<imstk::OpenVRDeviceClient> getHmdDeviceClient() const { return m_hmdDeviceClient; }
+
+public:
+    vtkInteractorStyleVR();
+
+public:
+    std::shared_ptr<imstk::OpenVRDeviceClient> m_leftControllerDeviceClient;
+    std::shared_ptr<imstk::OpenVRDeviceClient> m_rightControllerDeviceClient;
+    std::shared_ptr<imstk::OpenVRDeviceClient> m_hmdDeviceClient;
+};
\ No newline at end of file
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb3d964c2e90ea043db5abaec0cb2db840f70eb2
--- /dev/null
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.cpp
@@ -0,0 +1,208 @@
+/*=========================================================================
+
+   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 "imstkVTKOpenVRViewer.h"
+#include "imstkDeviceControl.h"
+#include "imstkLogger.h"
+#include "imstkOpenVRDeviceClient.h"
+#include "imstkScene.h"
+#include "imstkVTKInteractorStyle.h"
+#include "imstkVTKInteractorStyleVR.h"
+#include "imstkVTKRenderer.h"
+
+#include <vtkOpenVRRenderer.h>
+#include <vtkOpenVRRenderWindow.h>
+#include <vtkOpenVRRenderWindowInteractor.h>
+#include <vtkOpenVRModel.h>
+
+namespace imstk
+{
+VTKOpenVRViewer::VTKOpenVRViewer(std::string name) : AbstractVTKViewer(name)
+{
+    // Create the interactor style
+    auto vrInteractorStyle = std::make_shared<vtkInteractorStyleVR>();
+    m_interactorStyle    = std::dynamic_pointer_cast<InteractorStyle>(vrInteractorStyle);
+    m_vtkInteractorStyle = std::dynamic_pointer_cast<vtkInteractorStyle>(m_interactorStyle);
+    m_interactorStyle->setUpdateFunc([&]() { updateThread(); });
+
+    // Create the interactor
+    vtkNew<vtkOpenVRRenderWindowInteractor> iren;
+    iren->SetInteractorStyle(m_vtkInteractorStyle.get());
+
+    // Create the RenderWindow
+    m_vtkRenderWindow = vtkSmartPointer<vtkOpenVRRenderWindow>::New();
+    m_vtkRenderWindow->SetInteractor(iren);
+    iren->SetRenderWindow(m_vtkRenderWindow);
+    m_vtkRenderWindow->HideCursor();
+
+    m_vrDeviceClients.push_back(vrInteractorStyle->getLeftControllerDeviceClient());
+    m_vrDeviceClients.push_back(vrInteractorStyle->getRightControllerDeviceClient());
+    m_vrDeviceClients.push_back(vrInteractorStyle->getHmdDeviceClient());
+}
+
+void
+VTKOpenVRViewer::setActiveScene(const std::shared_ptr<Scene>& scene)
+{
+    // If already current scene
+    if (scene == m_activeScene)
+    {
+        LOG(WARNING) << scene->getName() << " already is the viewer current scene.";
+        return;
+    }
+
+    // If the current scene has a renderer, remove it
+    if (m_activeScene)
+    {
+        auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer();
+        if (m_vtkRenderWindow->HasRenderer(vtkRenderer))
+        {
+            m_vtkRenderWindow->RemoveRenderer(vtkRenderer);
+        }
+    }
+
+    // Update current scene
+    m_activeScene = scene;
+
+    // Create renderer if it doesn't exist
+    if (!m_rendererMap.count(m_activeScene))
+    {
+        m_rendererMap[m_activeScene] = std::make_shared<VTKRenderer>(m_activeScene, true);
+    }
+
+    // Cast to VTK renderer
+    auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer();
+
+    // Set renderer to renderWindow
+    m_vtkRenderWindow->AddRenderer(vtkRenderer);
+
+    m_vtkInteractorStyle->SetCurrentRenderer(vtkRenderer);
+}
+
+void
+VTKOpenVRViewer::setRenderingMode(const Renderer::Mode mode)
+{
+    if (!m_activeScene)
+    {
+        LOG(WARNING) << "Missing scene, can not set rendering mode.\n"
+                     << "Use Viewer::setCurrentScene to setup scene.";
+        return;
+    }
+
+    // Setup renderer
+    this->getActiveRenderer()->setMode(mode, true);
+    if (m_status != ThreadStatus::Running)
+    {
+        return;
+    }
+
+    // Render to update displayed actors
+    m_vtkRenderWindow->Render();
+}
+
+void
+VTKOpenVRViewer::startThread()
+{
+    // Print all controls on viewer
+    for (auto control : m_controls)
+    {
+        control->printControls();
+    }
+
+    // VR interactor doesn't support timers, here we throw timer event every update
+    // another option would be to conform VTKs VR interactor
+    vtkSmartPointer<vtkOpenVRRenderWindowInteractor> iren = vtkOpenVRRenderWindowInteractor::SafeDownCast(m_vtkRenderWindow->GetInteractor());
+    //iren->Start(); // Cannot use
+    if (iren->HasObserver(vtkCommand::StartEvent))
+    {
+        iren->InvokeEvent(vtkCommand::StartEvent, nullptr);
+        return;
+    }
+    iren->Initialize();
+
+    // Hide the device overlays
+    // \todo: put in debug mode
+    vtkSmartPointer<vtkOpenVRRenderWindow> renWin = vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderWindow);
+    renWin->Initialize();
+    renWin->Render(); // Must do one render to initialize vtkOpenVRModel's to then hide the controllers
+
+    //renWin->GetTrackedDeviceModel(vr::trackeddevice)
+    // Hide all controllers
+    for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++)
+    {
+        vtkOpenVRModel* trackedDeviceModel = renWin->GetTrackedDeviceModel(i);
+        if (trackedDeviceModel != nullptr)
+        {
+            trackedDeviceModel->SetVisibility(false);
+        }
+    }
+
+    while (!iren->GetDone())
+    {
+        auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer());
+        iren->DoOneEvent(vtkOpenVRRenderWindow::SafeDownCast(m_vtkRenderWindow), vtkOpenVRRenderer::SafeDownCast(vtkRen->getVtkRenderer()));
+        iren->InvokeEvent(vtkCommand::TimerEvent);
+    }
+}
+
+std::shared_ptr<OpenVRDeviceClient>
+VTKOpenVRViewer::getVRDeviceClient(int deviceType)
+{
+    auto iter = std::find_if(m_vrDeviceClients.begin(), m_vrDeviceClients.end(),
+        [&](const std::shared_ptr<OpenVRDeviceClient>& deviceClient)
+        {
+            return static_cast<int>(deviceClient->getDeviceType()) == deviceType;
+        });
+    return (iter == m_vrDeviceClients.end()) ? nullptr : *iter;
+}
+
+void
+VTKOpenVRViewer::updateThread()
+{
+    this->postEvent(Event(EventType::PreUpdate));
+
+    // Update all controls
+    for (auto control : m_controls)
+    {
+        control->update();
+    }
+
+    std::shared_ptr<imstk::VTKRenderer> renderer = std::dynamic_pointer_cast<imstk::VTKRenderer>(getActiveRenderer());
+    if (renderer == nullptr)
+    {
+        return;
+    }
+
+    // Update Camera
+    // \todo: No programmatic control over VR camera currently
+    //renderer->updateSceneCamera(getActiveScene()->getCamera());
+
+    // Update render delegates
+    renderer->updateRenderDelegates();
+
+    // Render
+    m_vtkRenderWindow->GetInteractor()->Render();
+
+    this->postEvent(Event(EventType::PostUpdate));
+
+    // Plan next render
+    m_vtkRenderWindow->GetInteractor()->CreateOneShotTimer(0);
+}
+}
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.h b/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.h
new file mode 100644
index 0000000000000000000000000000000000000000..2d57e5940cf11f8d9e2223b54415affe981111e7
--- /dev/null
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKOpenVRViewer.h
@@ -0,0 +1,87 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkAbstractVTKViewer.h"
+
+#include <vtkSmartPointer.h>
+#include <list>
+
+class vtkInteractorStyle;
+class vtkInteractorStyleVR;
+class vtkRenderWindow;
+
+namespace imstk
+{
+class OpenVRDeviceClient;
+
+///
+/// \class VTKViewer
+///
+/// \brief Subclasses viewer for the VTK rendering back-end
+/// Creates vtk renderer for each scene. Forwards mouse and keyboard events
+/// to the vtk renderwindow
+///
+class VTKOpenVRViewer : public AbstractVTKViewer
+{
+public:
+    VTKOpenVRViewer(std::string name = "VTKOpenVRViewer");
+    ~VTKOpenVRViewer() override      = default;
+
+public:
+    ///
+    /// \brief Start rendering
+    ///
+    void startThread() override;
+
+public:
+    ///
+    /// \brief Destructor
+    ///
+    void setRenderingMode(const Renderer::Mode mode) override;
+
+    ///
+    /// \brief Set scene to be rendered
+    ///
+    void setActiveScene(const std::shared_ptr<Scene>& scene) override;
+
+    ///
+    /// \brief Get one of the device clients for VR
+    ///
+    std::shared_ptr<OpenVRDeviceClient> getVRDeviceClient(int deviceType);
+
+    ///
+    /// \brief Acquire the full list of VR devices tied to this viewer
+    ///
+    const std::list<std::shared_ptr<OpenVRDeviceClient>>& getVRDeviceClients() const { return m_vrDeviceClients; }
+
+protected:
+    void updateThread() override;
+
+protected:
+    vtkSmartPointer<vtkRenderWindow>    m_vtkRenderWindow;
+    std::shared_ptr<vtkInteractorStyle> m_vtkInteractorStyle;
+
+    ///> The VR controllers are tied to the view
+    std::list<std::shared_ptr<OpenVRDeviceClient>> m_vrDeviceClients;
+};
+} // imstk
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp
index cac4039bb4620b8df9a85bb61f02f9486e9f5e2f..92bd728426130172f849d00ab1aa6dc6d92c3d19 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp
@@ -22,9 +22,15 @@
 #include "imstkVTKScreenCaptureUtility.h"
 #include "imstkLogger.h"
 
+#include <vtkPNGWriter.h>
+#include <vtkRenderWindow.h>
+#include <vtkWindowToImageFilter.h>
+
 namespace imstk
 {
-VTKScreenCaptureUtility::VTKScreenCaptureUtility(vtkRenderWindow* const rw, const std::string prefix /*= "Screenshot-"*/)
+VTKScreenCaptureUtility::VTKScreenCaptureUtility(vtkRenderWindow* const rw, const std::string prefix /*= "Screenshot-"*/) :
+    m_windowToImageFilter(vtkSmartPointer<vtkWindowToImageFilter>::New()),
+    m_pngWriter(vtkSmartPointer<vtkPNGWriter>::New())
 {
     m_screenShotNumber = 0;
     m_screenShotPrefix = prefix;
@@ -66,26 +72,4 @@ VTKScreenCaptureUtility::saveScreenShot()
 
     m_screenShotNumber++;
 }
-
-unsigned int
-VTKScreenCaptureUtility::getScreenShotNumber() const
-{
-    return m_screenShotNumber;
-}
-
-void
-VTKScreenCaptureUtility::setScreenShotPrefix(const std::string newPrefix)
-{
-    if (m_screenShotPrefix.compare(newPrefix) != 0)
-    {
-        m_screenShotPrefix = newPrefix;
-        m_screenShotNumber = 0;
-    }
-}
-
-void
-VTKScreenCaptureUtility::resetScreenShotNumber()
-{
-    m_screenShotNumber = 0;
-}
 } // imstk
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h
index c10b5b23d311e176fe0e29aa74cd9a2e5de6d579..d1be6ad193ef5cb4d563ddb72cf3699da7769a7b 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h
@@ -23,12 +23,11 @@
 
 #include "imstkScreenCaptureUtility.h"
 
-#include <vtkRenderWindow.h>
-#include <vtkWindowToImageFilter.h>
-#include <vtkPNGWriter.h>
-#include <vtkNew.h>
+#include <vtkSmartPointer.h>
 
-#include <string>
+class vtkPNGWriter;
+class vtkRenderWindow;
+class vtkWindowToImageFilter;
 
 namespace imstk
 {
@@ -48,31 +47,16 @@ public:
     ///
     /// \brief Destructor
     ///
-    ~VTKScreenCaptureUtility() = default;
+    virtual ~VTKScreenCaptureUtility() override = default;
 
     ///
     /// \brief Saves the screenshot as a png file
     ///
-    virtual void saveScreenShot();
-
-    ///
-    /// \brief Get screen shot number
-    ///
-    unsigned int getScreenShotNumber() const;
-
-    ///
-    /// \brief Set screen shot prefix
-    ///
-    void setScreenShotPrefix(const std::string newPrefix);
-
-    ///
-    /// \brief Reset screen shot number to zero
-    ///
-    void resetScreenShotNumber();
+    virtual void saveScreenShot() override;
 
 protected:
-    vtkNew<vtkWindowToImageFilter> m_windowToImageFilter;
-    vtkNew<vtkPNGWriter> m_pngWriter;           //> using vtk's png writer to save the screenshots
-    vtkRenderWindow*     m_renderWindow;        //> render window whose screen shot will be taken
+    vtkSmartPointer<vtkWindowToImageFilter> m_windowToImageFilter;
+    vtkSmartPointer<vtkPNGWriter> m_pngWriter; //> using vtk's png writer to save the screenshots
+    vtkRenderWindow* m_renderWindow;           //> render window whose screen shot will be taken
 };
 } // imstk
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.cpp
index 102cda91fc654ef868e3504f74ad45319ce0d594..2fb4bd2c5d7ea6f6d2a2873fcfa84c6970c7292b 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.cpp
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.cpp
@@ -19,27 +19,20 @@
 
 =========================================================================*/
 
-#include "imstkSimulationManager.h"
 #include "imstkVTKTextStatusManager.h"
 #include "imstkVTKInteractorStyle.h"
+#include "imstkVTKViewer.h"
 #include "imstkLogger.h"
-#include "imstkCamera.h"
 
-#include "vtkTextActor.h"
-#include "vtkRenderWindow.h"
-#include "vtkTextProperty.h"
-
-#include <algorithm>
-#include <sstream>
-#include <iostream>
+#include <vtkRenderWindow.h>
+#include <vtkTextActor.h>
+#include <vtkTextProperty.h>
 
 namespace imstk
 {
-VTKTextStatusManager::VTKTextStatusManager(VTKInteractorStyle* const vtkInteractorStyle) :
-    m_vtkInteractorStyle(vtkInteractorStyle)
+VTKTextStatusManager::VTKTextStatusManager()
 {
-    LOG_IF(FATAL, (!vtkInteractorStyle)) << "Invalid vtkInteractorStyle";
-    for (int i = 0; i < StatusType::NumStatusTypes; ++i)
+    for (int i = 0; i < static_cast<int>(StatusType::NumStatusTypes); ++i)
     {
         m_StatusActors[i] = vtkTextActor::New();
         m_StatusActors[i]->SetVisibility(false);
@@ -50,7 +43,7 @@ VTKTextStatusManager::VTKTextStatusManager(VTKInteractorStyle* const vtkInteract
 
 VTKTextStatusManager::~VTKTextStatusManager()
 {
-    for (int i = 0; i < StatusType::NumStatusTypes; ++i)
+    for (int i = 0; i < static_cast<int>(StatusType::NumStatusTypes); ++i)
     {
         m_StatusActors[i]->Delete();
     }
@@ -59,7 +52,7 @@ VTKTextStatusManager::~VTKTextStatusManager()
 vtkTextActor*
 VTKTextStatusManager::getTextActor(const int i)
 {
-    if (i < 0 || i >= StatusType::NumStatusTypes)
+    if (i < 0 || i >= static_cast<int>(StatusType::NumStatusTypes))
     {
         LOG(WARNING) << "Invalid text actor index";
         return m_StatusActors[0];
@@ -70,26 +63,32 @@ VTKTextStatusManager::getTextActor(const int i)
 void
 VTKTextStatusManager::setStatusVisibility(const StatusType type, const bool bVisible)
 {
-    m_StatusActors[type]->SetVisibility(bVisible);
+    m_StatusActors[static_cast<int>(type)]->SetVisibility(bVisible);
+}
+
+bool
+VTKTextStatusManager::getStatusVisibility(const StatusType type)
+{
+    return m_StatusActors[static_cast<int>(type)]->GetVisibility();
 }
 
 void
 VTKTextStatusManager::setStatusFontSize(const StatusType type, const int fontSize)
 {
-    m_StatusFontSizes[type] = fontSize; // Store font size to compute and adjust text location later
-    m_StatusActors[type]->GetTextProperty()->SetFontSize(fontSize);
+    m_StatusFontSizes[static_cast<int>(type)] = fontSize; // Store font size to compute and adjust text location later
+    m_StatusActors[static_cast<int>(type)]->GetTextProperty()->SetFontSize(fontSize);
 }
 
 void
 VTKTextStatusManager::setStatusFontColor(const StatusType type, const Color color)
 {
-    m_StatusActors[type]->GetTextProperty()->SetColor(color.r, color.g, color.b);
+    m_StatusActors[static_cast<int>(type)]->GetTextProperty()->SetColor(color.r, color.g, color.b);
 }
 
 void
 VTKTextStatusManager::setStatusDisplayCorner(const StatusType type, const DisplayCorner corner)
 {
-    m_StatusDisplayCorners[type] = corner;
+    m_StatusDisplayCorners[static_cast<int>(type)] = corner;
 }
 
 void
@@ -115,39 +114,35 @@ VTKTextStatusManager::setFPS(const double visualFPS, const double physicsFPS)
     }
 
     std::string fpsString = fpsVisualStr + std::string(" | ") + fpsPhysicalStr;
-    auto        fpsStatusCoordinate = computeStatusLocation(m_StatusDisplayCorners[StatusType::FPS],
-                                                     m_StatusFontSizes[StatusType::FPS],
+    auto        fpsStatusCoordinate = computeStatusLocation(m_StatusDisplayCorners[static_cast<int>(StatusType::FPS)],
+                                                     m_StatusFontSizes[static_cast<int>(StatusType::FPS)],
                                                      fpsString);
-    m_StatusActors[StatusType::FPS]->SetDisplayPosition(fpsStatusCoordinate[0], fpsStatusCoordinate[1]);
-    m_StatusActors[StatusType::FPS]->SetInput((fpsString).c_str());
+    m_StatusActors[static_cast<int>(StatusType::FPS)]->SetDisplayPosition(fpsStatusCoordinate[0], fpsStatusCoordinate[1]);
+    m_StatusActors[static_cast<int>(StatusType::FPS)]->SetInput((fpsString).c_str());
 }
 
 void
 VTKTextStatusManager::setCustomStatus(const std::string& status)
 {
-    auto customStatusCoordinate = computeStatusLocation(m_StatusDisplayCorners[StatusType::Custom],
-                                                        m_StatusFontSizes[StatusType::Custom],
+    auto customStatusCoordinate = computeStatusLocation(m_StatusDisplayCorners[static_cast<int>(StatusType::Custom)],
+                                                        m_StatusFontSizes[static_cast<int>(StatusType::Custom)],
                                                         status);
-    m_StatusActors[StatusType::Custom]->SetInput(status.c_str());
-    m_StatusActors[StatusType::Custom]->SetDisplayPosition(customStatusCoordinate[0], customStatusCoordinate[1]);
-    m_StatusActors[StatusType::Custom]->SetVisibility(true);
+    m_StatusActors[static_cast<int>(StatusType::Custom)]->SetInput(status.c_str());
+    m_StatusActors[static_cast<int>(StatusType::Custom)]->SetDisplayPosition(customStatusCoordinate[0], customStatusCoordinate[1]);
+    m_StatusActors[static_cast<int>(StatusType::Custom)]->SetVisibility(true);
 }
 
 void
 VTKTextStatusManager::clearCustomStatus()
 {
-    m_StatusActors[StatusType::Custom]->SetInput("");
-    m_StatusActors[StatusType::Custom]->SetVisibility(false);
+    m_StatusActors[static_cast<int>(StatusType::Custom)]->SetInput("");
+    m_StatusActors[static_cast<int>(StatusType::Custom)]->SetVisibility(false);
 }
 
 std::array<int, 2>
 VTKTextStatusManager::computeStatusLocation(const DisplayCorner corner, const int fontSize, const std::string& text)
 {
-    auto simManager = m_vtkInteractorStyle->getSimulationManager();
-    LOG_IF(FATAL, (!simManager)) << "Invalid simulation manager";
-
-    auto       viewer       = std::dynamic_pointer_cast<VTKViewer>(simManager->getViewer());
-    const int* windowSize   = viewer->getVtkRenderWindow()->GetSize();
+    const int* windowSize   = m_viewer->getVtkRenderWindow()->GetSize();
     const auto wWidth       = windowSize[0];
     const auto wHeight      = windowSize[1];
     const int  numLines     = static_cast<int>(std::count(text.begin(), text.end(), '\n')) + 1;
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.h b/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.h
index 1ffcf8aa58a7284d0016eed0b65dcf7e3da80cd9..bcc492e99db29683deb7c48a6bd14243f452823c 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.h
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKTextStatusManager.h
@@ -21,9 +21,10 @@
 
 #pragma once
 
-#include <array>
-
 #include "imstkColor.h"
+#include "imstkMath.h"
+
+#include <array>
 
 class vtkTextActor;
 
@@ -36,7 +37,8 @@ class vtkTextActor;
 
 namespace imstk
 {
-class VTKInteractorStyle;
+class VTKViewer;
+
 ///
 /// \brief The VTKTextStatusManager class
 ///
@@ -46,7 +48,7 @@ public:
     ///
     /// \brief The StatusType enum
     ///
-    enum StatusType
+    enum class StatusType
     {
         FPS = 0,
         Custom,
@@ -56,7 +58,7 @@ public:
     ///
     /// \brief The TextLocation enum
     ///
-    enum DisplayCorner
+    enum class DisplayCorner
     {
         LowerLeft,
         UpperLeft,
@@ -64,9 +66,11 @@ public:
         LowerRight
     };
 
-    explicit VTKTextStatusManager(VTKInteractorStyle* const vtkInteractorStyle);
+public:
+    explicit VTKTextStatusManager();
     virtual ~VTKTextStatusManager();
 
+public:
     ///
     /// \brief Return the text actor at index i
     ///
@@ -77,6 +81,11 @@ public:
     ///
     void setStatusVisibility(const StatusType type, const bool bVisible);
 
+    ///
+    /// \brief Get the visibility of the text status
+    ///
+    bool getStatusVisibility(const StatusType type);
+
     ///
     /// \brief Set the font size for the status
     ///
@@ -99,6 +108,11 @@ public:
     ///
     void setFPS(const double visualFPS, const double physicsFPS);
 
+    ///
+    /// \brief Set the window size
+    ///
+    void setWindowSize(VTKViewer* viewer) { m_viewer = viewer; }
+
     ///
     /// \brief Set custom status text
     /// The string parameter should be passed by value, not const reference
@@ -116,10 +130,10 @@ private:
     ///
     std::array<int, 2> computeStatusLocation(const DisplayCorner corner, const int fontSize, const std::string& text);
 
-    vtkTextActor* m_StatusActors[StatusType::NumStatusTypes];         ///> Statuses to display
-    DisplayCorner m_StatusDisplayCorners[StatusType::NumStatusTypes]; ///> Location (corner) of the statuses
-    int m_StatusFontSizes[StatusType::NumStatusTypes];                ///> Size of the statuses
+    vtkTextActor* m_StatusActors[static_cast<int>(StatusType::NumStatusTypes)];         ///> Statuses to display
+    DisplayCorner m_StatusDisplayCorners[static_cast<int>(StatusType::NumStatusTypes)]; ///> Location (corner) of the statuses
+    int m_StatusFontSizes[static_cast<int>(StatusType::NumStatusTypes)];                ///> Size of the statuses
 
-    VTKInteractorStyle* m_vtkInteractorStyle;                         ///> vtkInteractorStyle
+    VTKViewer* m_viewer;                                                                // Used for dimensions
 };
-} // end namespace imstk
+}
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp
index d9b12fe15baabf6ad63d4895a3d8e428391d62d9..6bd28b1965be873cb02068ba5dabc231c6eaf0da 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp
@@ -9,7 +9,7 @@
    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
+	  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,
@@ -20,69 +20,46 @@
 =========================================================================*/
 
 #include "imstkVTKViewer.h"
-#include "imstkVTKRenderDelegate.h"
-#include "imstkVTKInteractorStyle.h"
-#include "imstkVTKRenderer.h"
-#include "imstkCamera.h"
+#include "imstkDeviceControl.h"
 #include "imstkLogger.h"
 #include "imstkScene.h"
+#include "imstkVTKInteractorStyle.h"
+#include "imstkVTKRenderer.h"
+#include "imstkVTKScreenCaptureUtility.h"
+#include "imstkVTKTextStatusManager.h"
 
 #include <vtkRenderer.h>
 #include <vtkRenderWindow.h>
 #include <vtkRenderWindowInteractor.h>
-#include <vtkCallbackCommand.h>
-
-#include "imstkParallelUtils.h"
+#include <vtkTextActor.h>
 
 namespace imstk
 {
-VTKViewer::VTKViewer(SimulationManager* manager /*= nullptr*/, bool enableVR /*= false*/) :
-    m_enableVR(enableVR)
+VTKViewer::VTKViewer(std::string name) : AbstractVTKViewer(name),
+    m_lastFpsUpdate(std::chrono::high_resolution_clock::now()),
+    m_textStatusManager(std::make_shared<VTKTextStatusManager>()),
+    m_lastFps(60.0)
 {
-    // init render window / interactor / command based
-    // depending on if we enable VR or not
-    if (!m_enableVR)
-    {
-        // Interactor style / commands
-        m_interactorStyle = std::make_shared<VTKInteractorStyle>();
-
-        m_vtkInteractorStyle = std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle);
-        m_vtkInteractorStyle->m_simManager = manager;
-
-        // Interactor
-        auto vtkInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
-        vtkInteractor->SetInteractorStyle(m_vtkInteractorStyle.get());
-
-        // Render window
-        m_vtkRenderWindow = vtkSmartPointer<vtkRenderWindow>::New();
-        m_vtkRenderWindow->SetInteractor(vtkInteractor);
-        m_vtkRenderWindow->SetSize(m_config->m_renderWinWidth, m_config->m_renderWinHeight);
-
-        // Screen capture
-        m_screenCapturer = std::make_shared<VTKScreenCaptureUtility>(m_vtkRenderWindow);
-    }
-#ifdef iMSTK_ENABLE_VR
-    else
-    {
-        // Interactor style / commands
-        m_openVRCommand = vtkSmartPointer<OpenVRCommand>::New();
-        m_openVRCommand->SetSimulationManager(manager);
-
-        // Interactor
-        auto vtkOpenVRinteractor = vtkSmartPointer<vtkOpenVRRenderWindowInteractor>::New();
-
-        // Add observer openVR command
-        m_vtkRenderWindow = vtkSmartPointer<vtkOpenVRRenderWindow>::New();
-        m_vtkRenderWindow->SetInteractor(vtkOpenVRinteractor);
-        vtkOpenVRinteractor->SetRenderWindow(m_vtkRenderWindow);
-        m_vtkRenderWindow->AddObserver(vtkCommand::StartEvent, m_openVRCommand, 1.0);
-    }
-#endif
-
-    // Setup callback for timer on the interactor
-    timerCallbackCommand = vtkSmartPointer<vtkCallbackCommand>::New();
-    timerCallbackCommand->SetCallback(timerCallback);
-    timerCallbackCommand->SetClientData(this);
+    // Create the interactor style
+    m_interactorStyle    = std::make_shared<VTKInteractorStyle>();
+    m_vtkInteractorStyle = std::dynamic_pointer_cast<vtkInteractorStyle>(m_interactorStyle);
+    // Bring control back out to the viewer
+    m_interactorStyle->setUpdateFunc([&]() { this->updateThread(); });
+
+    // Create the interactor
+    vtkNew<vtkRenderWindowInteractor> iren;
+    iren->SetInteractorStyle(m_vtkInteractorStyle.get());
+
+    // Create the RenderWindow
+    m_vtkRenderWindow = vtkSmartPointer<vtkRenderWindow>::New();
+    m_vtkRenderWindow->SetInteractor(iren);
+    m_vtkRenderWindow->SetSize(m_config->m_renderWinWidth, m_config->m_renderWinHeight);
+
+    // Screen capture
+    m_screenCapturer = std::make_shared<VTKScreenCaptureUtility>(m_vtkRenderWindow);
+
+    // Setup text status
+    m_textStatusManager->setWindowSize(this);
 }
 
 void
@@ -96,7 +73,7 @@ VTKViewer::setActiveScene(const std::shared_ptr<Scene>& scene)
     }
 
     // If the current scene has a renderer, remove it
-    if (m_activeScene)
+    if (m_activeScene != nullptr)
     {
         auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer();
         if (m_vtkRenderWindow->HasRenderer(vtkRenderer))
@@ -111,7 +88,7 @@ VTKViewer::setActiveScene(const std::shared_ptr<Scene>& scene)
     // Create renderer if it doesn't exist
     if (!m_rendererMap.count(m_activeScene))
     {
-        m_rendererMap[m_activeScene] = std::make_shared<VTKRenderer>(m_activeScene, m_enableVR);
+        m_rendererMap[m_activeScene] = std::make_shared<VTKRenderer>(m_activeScene, false);
     }
 
     // Cast to VTK renderer
@@ -120,13 +97,30 @@ VTKViewer::setActiveScene(const std::shared_ptr<Scene>& scene)
     // Set renderer to renderWindow
     m_vtkRenderWindow->AddRenderer(vtkRenderer);
 
-    if (!m_enableVR)
+    // Move text actors from old to new renderer
+    if (m_vtkInteractorStyle->GetCurrentRenderer() != NULL)
     {
-        // Set renderer to interactorStyle
-        std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle)->SetCurrentRenderer(vtkRenderer);
+        // Remove from old renderer
+        for (int i = 0; i < static_cast<int>(VTKTextStatusManager::StatusType::NumStatusTypes); i++)
+        {
+            m_vtkInteractorStyle->GetCurrentRenderer()->RemoveActor2D(m_textStatusManager->getTextActor(i));
+        }
+    }
+    m_vtkInteractorStyle->SetCurrentRenderer(vtkRenderer);
+    // Add to new renderer
+    for (int i = 0; i < static_cast<int>(VTKTextStatusManager::StatusType::NumStatusTypes); i++)
+    {
+        vtkRenderer->AddActor2D(m_textStatusManager->getTextActor(i));
+    }
+
+    // Set name to renderWindow
+    m_vtkRenderWindow->SetWindowName(m_activeScene->getName().data());
 
-        // Set name to renderWindow
-        m_vtkRenderWindow->SetWindowName(m_activeScene->getName().data());
+    // Update the camera
+    std::shared_ptr<VTKRenderer> ren = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer());
+    if (ren != nullptr)
+    {
+        ren->updateCamera();
     }
 }
 
@@ -140,23 +134,14 @@ VTKViewer::setRenderingMode(const Renderer::Mode mode)
         return;
     }
 
-    // Setup renderer
-    this->getActiveRenderer()->setMode(mode, m_enableVR);
-    if (!m_running)
+    // Switch the renderer to the mode
+    this->getActiveRenderer()->setMode(mode, false);
+    if (m_status != ThreadStatus::Running)
     {
         return;
     }
 
-    // Render to update displayed actors
-    m_vtkRenderWindow->Render();
-
-    if (m_enableVR)
-    {
-        return;
-    }
-
-    // Setup render window
-    //std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle)->HighlightProp(nullptr);
+    updateThread();
 
     if (m_config->m_hideCurzor)
     {
@@ -174,56 +159,21 @@ VTKViewer::setRenderingMode(const Renderer::Mode mode)
     }
 }
 
-Renderer::Mode
-VTKViewer::getRenderingMode()
-{
-    return this->getActiveRenderer()->getMode();
-}
-
 void
-VTKViewer::startRenderingLoop()
+VTKViewer::startThread()
 {
-    m_running = true;
-    if (!m_enableVR)
+    // Print all controls on viewer
+    for (auto control : m_controls)
     {
-        m_vtkRenderWindow->GetInteractor()->Initialize();
-        m_vtkRenderWindow->GetInteractor()->CreateOneShotTimer(0);
-
-        // If the Scene wants benchmarking hookup timer to update the table
-        auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer());
-        vtkRen->setTimeTableVisibility(m_activeScene->getConfig()->taskTimingEnabled);
-        if (m_activeScene->getConfig()->taskTimingEnabled)
-        {
-            m_vtkRenderWindow->GetInteractor()->AddObserver(vtkCommand::TimerEvent, timerCallbackCommand);
-            m_vtkRenderWindow->GetInteractor()->CreateRepeatingTimer(500);
-        }
-
-        m_vtkRenderWindow->SetWindowName(m_config->m_windowName.c_str());
-        m_vtkRenderWindow->GetInteractor()->Start();
-        m_vtkRenderWindow->GetInteractor()->DestroyTimer();
-    }
-    else
-    {
-        m_vtkRenderWindow->GetInteractor()->Start();
+        control->printControls();
     }
 
-    m_running = false;
-}
-
-void
-VTKViewer::endRenderingLoop()
-{
-    // close the rendering window
-    m_vtkRenderWindow->Finalize();
+    m_vtkRenderWindow->GetInteractor()->Initialize();
+    m_vtkRenderWindow->GetInteractor()->CreateOneShotTimer(0);
 
-    // Terminate the interactor
-    m_vtkRenderWindow->GetInteractor()->TerminateApp();
-}
-
-vtkSmartPointer<vtkRenderWindow>
-VTKViewer::getVtkRenderWindow() const
-{
-    return m_vtkRenderWindow;
+    m_vtkRenderWindow->SetWindowName(m_config->m_windowName.c_str());
+    m_vtkRenderWindow->GetInteractor()->Start();
+    m_vtkRenderWindow->GetInteractor()->DestroyTimer();
 }
 
 std::shared_ptr<VTKScreenCaptureUtility>
@@ -232,39 +182,71 @@ VTKViewer::getScreenCaptureUtility() const
     return std::static_pointer_cast<VTKScreenCaptureUtility>(m_screenCapturer);
 }
 
-void
-VTKViewer::setBackgroundColors(const Vec3d color1, const Vec3d color2 /*= Vec3d::Zero()*/, const bool gradientBackground /*= false*/)
+std::shared_ptr<KeyboardDeviceClient>
+VTKViewer::getKeyboardDevice() const
+{
+    return std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle)->getKeyboardDeviceClient();
+}
+
+std::shared_ptr<MouseDeviceClient>
+VTKViewer::getMouseDevice() const
 {
-    this->getActiveRenderer()->updateBackground(color1, color2, gradientBackground);
+    return std::dynamic_pointer_cast<VTKInteractorStyle>(m_interactorStyle)->getMouseDeviceClient();
 }
 
 void
-VTKViewer::setWindowTitle(const std::string& title)
+VTKViewer::updateThread()
 {
-    m_config->m_windowName = title;
-    if (m_vtkRenderWindow)
+    this->postEvent(Event(EventType::PreUpdate));
+
+    // Update all controls
+    for (auto control : m_controls)
     {
-        m_vtkRenderWindow->SetWindowName(title.c_str());
+        control->update();
     }
-}
 
-const std::shared_ptr<VTKTextStatusManager>&
-VTKViewer::getTextStatusManager()
-{
-    return m_vtkInteractorStyle->getTextStatusManager();
-}
+    std::shared_ptr<VTKRenderer> ren = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer());
 
-void
-VTKViewer::timerCallback(vtkObject* vtkNotUsed(caller), long unsigned int vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData))
-{
-    VTKViewer* self = static_cast<VTKViewer*>(clientData);
+    // Update Camera
+    ren->updateCamera();
+
+    // Update render delegates
+    ren->updateRenderDelegates();
+
+    // Reset camera clipping range
+    ren->getVtkRenderer()->ResetCameraClippingRange();
 
-    if (self->getActiveScene()->getConfig()->taskTimingEnabled)
+    // If fps status is on, measure it
+    if (getTextStatusManager()->getStatusVisibility(VTKTextStatusManager::StatusType::FPS))
     {
-        auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(self->getActiveRenderer());
-        self->getActiveScene()->lockComputeTimes();
-        vtkRen->setTimeTable(self->getActiveScene()->getTaskComputeTimes());
-        self->getActiveScene()->unlockComputeTimes();
+        // Update framerate value display
+        auto   now       = std::chrono::high_resolution_clock::now();
+        double visualFPS = 1e6 / static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(now - m_pre).count());
+        visualFPS = 0.1 * visualFPS + 0.9 * m_lastFps;
+        m_lastFps = visualFPS;
+
+        const int t = static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastFpsUpdate).count());
+        if (t > 150) // wait 150ms before updating displayed value
+        {
+            const double physicalFPS = getActiveScene()->getFPS();
+            m_textStatusManager->setFPS(visualFPS, physicalFPS);
+            m_lastFpsUpdate = now;
+
+            // Update the timing table
+            getActiveScene()->lockComputeTimes();
+            ren->setTimeTable(getActiveScene()->getTaskComputeTimes());
+            getActiveScene()->unlockComputeTimes();
+        }
+        m_pre = now;
     }
+
+    // Render
+    getVtkRenderWindow()->GetInteractor()->Render();
+    m_post = std::chrono::high_resolution_clock::now();
+
+    this->postEvent(Event(EventType::PostUpdate));
+
+    // Plan next render
+    getVtkRenderWindow()->GetInteractor()->CreateOneShotTimer(0);
+}
 }
-} // imstk
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h
index 24832d5948a19d9b7fef132cbf419bcfbcd62545..433c34bded24aa809b035ac3400d5ecc7adad5c1 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h
@@ -21,72 +21,44 @@
 
 #pragma once
 
-#include "imstkVTKScreenCaptureUtility.h"
-#include "imstkViewer.h"
-#include "imstkVTKRenderDelegate.h"
-#include "imstkVTKScreenCaptureUtility.h"
-
-#ifdef iMSTK_ENABLE_VR
-#include "imstkOpenVRCommand.h"
-#include "vtkOpenVRRenderWindow.h"
-#include "vtkOpenVRRenderWindowInteractor.h"
-#endif
-
-class vtkCallbackCommand;
-class vtkRenderWindow;
+#include "imstkAbstractVTKViewer.h"
 
 namespace imstk
 {
-class SimulationManager;
-class VTKTextStatusManager;
-class VTKInteractorStyle;
+class KeyboardDeviceClient;
+class MouseDeviceClient;
 class Scene;
+class VTKScreenCaptureUtility;
+class VTKTextStatusManager;
 
 ///
 /// \class VTKViewer
 ///
 /// \brief Subclasses viewer for the VTK rendering back-end
-/// Creates vtk renderer for each scene. Forwards mouse and keyboard events
-/// to the vtk renderwindow
+/// Creates vtk renderer for each scene.
 ///
-class VTKViewer : public Viewer
+class VTKViewer : public AbstractVTKViewer
 {
 public:
-    ///
-    /// \brief Constructor
-    /// \todo: SimulationManager and Viewer's should not have a circular dependence
-    ///
-    VTKViewer(SimulationManager* manager = nullptr, bool enableVR = false);
-
-    ///
-    /// \brief Destructor
-    ///
-    virtual void setRenderingMode(const Renderer::Mode mode) override;
-
-    ///
-    /// \brief Set scene to be rendered
-    ///
-    virtual void setActiveScene(const std::shared_ptr<Scene>& scene) override;
-
-    ///
-    /// \brief Get the current renderer mode
-    ///
-    virtual Renderer::Mode getRenderingMode() override;
+    VTKViewer(std::string name = "VTKViewer");
+    ~VTKViewer() override      = default;
 
+public:
     ///
     /// \brief Start rendering
     ///
-    virtual void startRenderingLoop() override;
+    void startThread() override;
 
+public:
     ///
-    /// \brief Terminate rendering
+    /// \brief Set the rendering mode. In debug, debug actors will be shown.
     ///
-    virtual void endRenderingLoop() override;
+    void setRenderingMode(const Renderer::Mode mode) override;
 
     ///
-    /// \brief Get pointer to the vtkRenderWindow rendering
+    /// \brief Set scene to be rendered
     ///
-    vtkSmartPointer<vtkRenderWindow> getVtkRenderWindow() const;
+    void setActiveScene(const std::shared_ptr<Scene>& scene) override;
 
     ///
     /// \brief Access screen shot utility
@@ -94,34 +66,34 @@ public:
     std::shared_ptr<VTKScreenCaptureUtility> getScreenCaptureUtility() const;
 
     ///
-    /// \brief Set the coloring of the screen background
-    /// If 'gradientBackground' is false or not supplied color1 will fill the entire background
+    /// \brief Return the window status handler
     ///
-    virtual void setBackgroundColors(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(),
-                                     const bool gradientBackground = false) override;
+    std::shared_ptr<VTKTextStatusManager> getTextStatusManager() const { return m_textStatusManager; }
 
     ///
-    /// \brief set the window title
+    /// \brief Returns the device that emits key events
     ///
-    virtual void setWindowTitle(const std::string& title);
+    std::shared_ptr<KeyboardDeviceClient> getKeyboardDevice() const;
 
     ///
-    /// \brief Return the window status handler
+    /// \brief Returns the device that emits mouse events
     ///
-    const std::shared_ptr<VTKTextStatusManager>& getTextStatusManager();
+    std::shared_ptr<MouseDeviceClient> getMouseDevice() const;
 
 protected:
-    /// \brief VTKTimer callback, every 500ms
-    static void timerCallback(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData);
-
-    vtkSmartPointer<vtkRenderWindow>    m_vtkRenderWindow;
-    std::shared_ptr<VTKInteractorStyle> m_vtkInteractorStyle;
-    bool m_enableVR;
+    ///
+    /// \brief Connected to VTKs on timer event, called continously
+    /// and synchronously on the VTK/rendering thread
+    ///
+    void updateThread() override;
 
-    vtkSmartPointer<vtkCallbackCommand> timerCallbackCommand;
+protected:
+    std::chrono::high_resolution_clock::time_point m_pre;           ///> time point pre-rendering
+    std::chrono::high_resolution_clock::time_point m_post;          ///> time point post-rendering
+    std::chrono::high_resolution_clock::time_point m_lastFpsUpdate; ///> time point for last framerate display update
 
-#ifdef iMSTK_ENABLE_VR
-    vtkSmartPointer<OpenVRCommand> m_openVRCommand;
-#endif
+    std::shared_ptr<VTKTextStatusManager> m_textStatusManager;      ///> Handle text statuses, including fps status and custom text status
+    bool   m_displayFps = false;                                    ///> hide or display framerate
+    double m_lastFps;                                               ///> last framerate value used for moving average estimate
 };
 } // imstk
diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp
index 0847ef572f83ac8367d5a902e8b0191b89dbfb55..221a458efc301247cf64f314b31c06c8c276e22a 100644
--- a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp
+++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp
@@ -21,12 +21,14 @@
 
 #include "imstkVulkanViewer.h"
 #include "imgui_impl_glfw.h"
+#include "imstkOpenVRDeviceClient.h"
 
 namespace imstk
 {
 VulkanViewer::VulkanViewer(SimulationManager* manager, bool enableVR)
 {
     m_simManager = manager;
+    m_config->m_enableVR = enableVR;
 
 #ifdef iMSTK_ENABLE_VR
     if (vr::VR_IsHmdPresent() && enableVR)
@@ -121,6 +123,13 @@ VulkanViewer::startRenderingLoop()
     {
         m_renderer->m_VRMode = true;
 
+        std::shared_ptr<OpenVRDeviceClient> leftControllerDevice = std::make_shared<OpenVRDeviceClient>(OpenVRDeviceClient::DeviceType::LEFT_CONTROLLER);
+        m_vrDeviceClients.push_back(leftControllerDevice);
+        std::shared_ptr<OpenVRDeviceClient> rightControllerDevice = std::make_shared<OpenVRDeviceClient>(OpenVRDeviceClient::DeviceType::RIGHT_CONTROLLER);
+        m_vrDeviceClients.push_back(rightControllerDevice);
+        std::shared_ptr<OpenVRDeviceClient> hmdControllerDevice = std::make_shared<OpenVRDeviceClient>(OpenVRDeviceClient::DeviceType::RIGHT_CONTROLLER);
+        m_vrDeviceClients.push_back(hmdControllerDevice);
+
         vr::EVRInitError error;
         m_renderer->m_VRSystem = vr::VR_Init(&error, vr::EVRApplicationType::VRApplication_Scene);
 
diff --git a/Source/SceneEntities/Objects/imstkDeformableObject.cpp b/Source/SimulationManager/imstkConsoleThread.cpp
similarity index 65%
rename from Source/SceneEntities/Objects/imstkDeformableObject.cpp
rename to Source/SimulationManager/imstkConsoleThread.cpp
index d49510a0a844bf161759b65d0e48874f1c08a1db..8cb369ea73e2b33169dd119ad4fddb43e9d39135 100644
--- a/Source/SceneEntities/Objects/imstkDeformableObject.cpp
+++ b/Source/SimulationManager/imstkConsoleThread.cpp
@@ -19,25 +19,21 @@
 
 =========================================================================*/
 
-#include "imstkFeDeformableObject.h"
-#include "imstkFEMDeformableBodyModel.h"
-#include "imstkLogger.h"
+#include "imstkConsoleThread.h"
+#include "imstkKeyboardDeviceClient.h"
 
 namespace imstk
 {
-bool
-FeDeformableObject::initialize()
+ConsoleThread::ConsoleThread(std::string name) :
+    LoopThreadObject(name),
+    m_keyboardDeviceClient(KeyboardDeviceClient::New())
 {
-    m_femModel = std::dynamic_pointer_cast<FEMDeformableBodyModel>(m_dynamicalModel);
-    if (m_femModel == nullptr)
-    {
-        LOG(FATAL) << "Dynamics pointer cast failure in DeformableObject::initialize()";
-        return false;
-    }
-
-    DynamicObject::initialize();
-    m_femModel->initialize();
+}
 
-    return true;
+void
+ConsoleThread::updateThread()
+{
+    const char c = static_cast<char>(getchar());
+    m_keyboardDeviceClient->emitKeyDown(c);
 }
-} // imstk
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/imstkConsoleThread.h b/Source/SimulationManager/imstkConsoleThread.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e11a0d2042fb657533421ca7fe8ab3847c4b713
--- /dev/null
+++ b/Source/SimulationManager/imstkConsoleThread.h
@@ -0,0 +1,55 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkLoopThreadObject.h"
+
+namespace imstk
+{
+class KeyboardDeviceClient;
+
+///
+/// \class ConsoleThread
+///
+/// \brief The console thread can run separately or in
+/// sync to provide keyboard events from the console
+/// they should be handled on another thread
+///
+class ConsoleThread : public LoopThreadObject
+{
+public:
+    ConsoleThread(std::string name = "ConsoleThread");
+    ~ConsoleThread() override      = default;
+
+public:
+    std::shared_ptr<KeyboardDeviceClient> getKeyboardDevice() const { return m_keyboardDeviceClient; }
+
+protected:
+    ///
+    /// \brief Awaits input
+    ///
+    void updateThread() override;
+
+protected:
+    std::shared_ptr<KeyboardDeviceClient> m_keyboardDeviceClient;
+};
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/imstkInteractorStyle.h b/Source/SimulationManager/imstkInteractorStyle.h
index ed6f85225da433167437fe07484e84623967c6c9..6e42bab4e2e0e361dc2c8cceb247ec68b8e77e0b 100644
--- a/Source/SimulationManager/imstkInteractorStyle.h
+++ b/Source/SimulationManager/imstkInteractorStyle.h
@@ -21,17 +21,12 @@
 
 #pragma once
 
-#include <unordered_map>
-#include <functional>
+#include "imstkEventObject.h"
 
 namespace imstk
 {
 class InteractorStyle;
 
-/// Signature of custom function called in each even callback.
-/// Return true to override base class behavior, or false to maintain it.
-using EventHandlerFunction = std::function<bool (InteractorStyle* iStyle)>;
-
 ///
 /// \class InteractorStyle
 /// \brief TODO
@@ -39,26 +34,18 @@ using EventHandlerFunction = std::function<bool (InteractorStyle* iStyle)>;
 class InteractorStyle
 {
 public:
-    InteractorStyle() {};
+    InteractorStyle() = default;
+    virtual ~InteractorStyle() = default;
 
-    virtual ~InteractorStyle() {};
+    ///
+    /// \brief Called continously
+    ///
+    void setUpdateFunc(std::function<void()> func)
+    {
+        m_updateFunc = func;
+    }
 
 protected:
-    friend class Viewer;
-    friend class VulkanViewer;
-
-    /// Custom event handlers
-    /// Return true to override default event slot
-    std::unordered_map<char, EventHandlerFunction> m_onCharFunctionMap;
-    EventHandlerFunction m_onMouseMoveFunction;
-    EventHandlerFunction m_onLeftButtonDownFunction;
-    EventHandlerFunction m_onLeftButtonUpFunction;
-    EventHandlerFunction m_onMiddleButtonDownFunction;
-    EventHandlerFunction m_onMiddleButtonUpFunction;
-    EventHandlerFunction m_onRightButtonDownFunction;
-    EventHandlerFunction m_onRightButtonUpFunction;
-    EventHandlerFunction m_onMouseWheelForwardFunction;
-    EventHandlerFunction m_onMouseWheelBackwardFunction;
-    EventHandlerFunction m_onTimerFunction;
+    std::function<void()> m_updateFunc;
 };
 }
diff --git a/Source/SimulationManager/imstkKeyboardSceneControl.cpp b/Source/SimulationManager/imstkKeyboardSceneControl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ffe47deba77ceb30d4ab6a9d3cb845d70bd68d9e
--- /dev/null
+++ b/Source/SimulationManager/imstkKeyboardSceneControl.cpp
@@ -0,0 +1,154 @@
+/*=========================================================================
+
+   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 "imstkKeyboardSceneControl.h"
+#include "imstkLogger.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkVTKRenderer.h"
+#include "imstkVTKTextStatusManager.h"
+#include "imstkVTKViewer.h"
+
+namespace imstk
+{
+KeyboardSceneControl::KeyboardSceneControl() :
+    m_showFps(false), m_sceneManager(nullptr), m_viewer(nullptr)
+{
+}
+
+KeyboardSceneControl::KeyboardSceneControl(std::shared_ptr<KeyboardDeviceClient> keyDevice) :
+    KeyboardControl(keyDevice),
+    m_showFps(false), m_sceneManager(nullptr), m_viewer(nullptr)
+{
+}
+
+void
+KeyboardSceneControl::printControls()
+{
+    LOG(INFO) << "Keyboard Scene Controls:";
+    LOG(INFO) << "----------------------------------------------------------------------";
+    LOG(INFO) << " | Space - pause/resume the scene";
+    LOG(INFO) << " | q/Q   - stop both the scene and viewer";
+    LOG(INFO) << " | d/D   - toggle debug/simulation mode";
+    LOG(INFO) << " | p/P   - toggle visual/physics updates/second and task times display";
+    LOG(INFO) << " | r/R   - reset the simulation";
+    LOG(INFO) << "----------------------------------------------------------------------";
+}
+
+void
+KeyboardSceneControl::OnKeyPress(const char key)
+{
+    if (key == ' ')
+    {
+        if (m_sceneManager != nullptr)
+        {
+            ThreadStatus status = m_sceneManager->getStatus();
+            // Pause the active scene
+            if (status == ThreadStatus::Running)
+            {
+                m_sceneManager->pause(true);
+            }
+            // Resume the active scene
+            else if (status == ThreadStatus::Paused)
+            {
+                m_sceneManager->resume();
+            }
+            // Launch the active scene if it has yet to start
+            if (status == ThreadStatus::Inactive)
+            {
+                //m_textStatusManager->setStatusVisibility(VTKTextStatusManager::FPS, m_displayFps);
+                m_sceneManager->resume();
+            }
+        }
+    }
+    else if (key == 'q' || key == 'Q' || key == 'e' || key == 'E') // end Simulation
+    {
+        if (m_sceneManager != nullptr && m_viewer != nullptr)
+        {
+            if (m_viewer->getStatus() != ThreadStatus::Inactive)
+            {
+                m_viewer->stop(false);
+            }
+        }
+        else if (m_sceneManager != nullptr && m_viewer == nullptr)
+        {
+            if (m_sceneManager->getStatus() != ThreadStatus::Inactive)
+            {
+                m_sceneManager->stop(false);
+            }
+        }
+        else if (m_sceneManager == nullptr && m_viewer != nullptr)
+        {
+            if (m_viewer->getStatus() != ThreadStatus::Inactive)
+            {
+                m_viewer->stop(false);
+            }
+        }
+    }
+    else if (key == 'd' || key == 'D') // switch rendering mode of the modules
+    {
+        if (m_sceneManager != nullptr && m_viewer != nullptr)
+        {
+            if (m_viewer->getRenderingMode() != Renderer::Mode::Simulation)
+            {
+                m_sceneManager->setMode(SceneManager::Mode::Simulation);
+                m_viewer->setRenderingMode(Renderer::Mode::Simulation);
+            }
+            else
+            {
+                m_sceneManager->setMode(SceneManager::Mode::Debug);
+                m_viewer->setRenderingMode(Renderer::Mode::Debug);
+            }
+        }
+    }
+    else if (key == 'p' || key == 'P')  // switch framerate display
+    {
+        if (m_sceneManager != nullptr && m_viewer != nullptr)
+        {
+            // If we're dealing with a VTK viewer, flip the text visibility for FPS
+            std::shared_ptr<VTKViewer> vtkViewer = std::dynamic_pointer_cast<VTKViewer>(m_viewer);
+            if (vtkViewer != nullptr)
+            {
+                m_showFps = !m_showFps;
+                std::shared_ptr<VTKTextStatusManager> textManager = vtkViewer->getTextStatusManager();
+                textManager->setStatusVisibility(VTKTextStatusManager::StatusType::FPS, m_showFps);
+
+                std::shared_ptr<Scene> activeScene = m_sceneManager->getActiveScene();
+                activeScene->setEnableTaskTiming(m_showFps);
+                const auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(m_viewer->getActiveRenderer());
+                vtkRen->setTimeTableVisibility(m_showFps);
+            }
+        }
+    }
+    else if (key == 'r' || key == 'R')
+    {
+        if (m_sceneManager != nullptr)
+        {
+            m_sceneManager->getActiveScene()->reset();
+        }
+    }
+}
+
+void
+KeyboardSceneControl::OnKeyRelease(const char imstkNotUsed(key))
+{
+}
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/imstkKeyboardSceneControl.h b/Source/SimulationManager/imstkKeyboardSceneControl.h
new file mode 100644
index 0000000000000000000000000000000000000000..e3da51f910b6d53b8be7544ce08a2ef8fd82acbf
--- /dev/null
+++ b/Source/SimulationManager/imstkKeyboardSceneControl.h
@@ -0,0 +1,66 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkKeyboardControl.h"
+
+namespace imstk
+{
+class SceneManager;
+class Viewer;
+
+///
+/// \class KeyboardSceneControl
+///
+/// \brief This implements keyboard controls to control a scene manager and viewer
+/// it may operate with both sceneManager and viewer, or only one or the other.
+/// warning: This control may pause a thread. Thus it is a bad idea to process it
+/// on the thread you're pausing, as you then could not resume.
+/// \todo: Thread affinity
+///
+class KeyboardSceneControl : public KeyboardControl
+{
+public:
+    KeyboardSceneControl();
+    KeyboardSceneControl(std::shared_ptr<KeyboardDeviceClient> keyDevice);
+    virtual ~KeyboardSceneControl() override = default;
+
+public:
+    void setSceneManager(std::shared_ptr<SceneManager> sceneManager) { m_sceneManager = sceneManager; }
+    std::shared_ptr<SceneManager> getSceneManager() const { return m_sceneManager; }
+
+    void setViewer(std::shared_ptr<Viewer> viewer) { m_viewer = viewer; }
+    std::shared_ptr<Viewer> getViewer() const { return m_viewer; }
+
+public:
+    void printControls() override;
+
+    void OnKeyPress(const char key) override;
+
+    void OnKeyRelease(const char key) override;
+
+protected:
+    std::shared_ptr<SceneManager> m_sceneManager;
+    std::shared_ptr<Viewer>       m_viewer;
+    bool m_showFps;
+};
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/imstkMouseSceneControl.cpp b/Source/SimulationManager/imstkMouseSceneControl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dbe13dff604b37af2f26a1f7fa915259af1c7343
--- /dev/null
+++ b/Source/SimulationManager/imstkMouseSceneControl.cpp
@@ -0,0 +1,179 @@
+/*=========================================================================
+
+   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 "imstkMouseSceneControl.h"
+#include "imstkCamera.h"
+#include "imstkLogger.h"
+#include "imstkMouseDeviceClient.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+
+namespace imstk
+{
+MouseSceneControl::MouseSceneControl(std::shared_ptr<MouseDeviceClient> device) : MouseControl(device)
+{
+}
+
+void
+MouseSceneControl::printControls()
+{
+    LOG(INFO) << "Mouse Scene Controls: Only usable in debug mode";
+    LOG(INFO) << "----------------------------------------------------------------------";
+    LOG(INFO) << " | Left click drag   - rotate view";
+    LOG(INFO) << " | Middle click drag - pan view";
+    LOG(INFO) << " | Scroll            - zoom in/out";
+    LOG(INFO) << "----------------------------------------------------------------------";
+}
+
+void
+MouseSceneControl::OnButtonPress(const int key)
+{
+    // If no mode currently selected
+    if (m_mode == Mode::None)
+    {
+        // Set the mode
+        if (key == LEFT_BUTTON)
+        {
+            m_mode = Mode::Rotate;
+        }
+        else if (key == MIDDLE_BUTTON)
+        {
+            m_mode = Mode::Pan;
+        }
+    }
+}
+
+void
+MouseSceneControl::OnButtonRelease(const int key)
+{
+    if (key == LEFT_BUTTON && m_mode == Mode::Rotate)
+    {
+        m_mode = Mode::None;
+    }
+    else if (key == MIDDLE_BUTTON && m_mode == Mode::Pan)
+    {
+        m_mode = Mode::None;
+    }
+}
+
+void
+MouseSceneControl::OnScroll(const double dx)
+{
+    // This control is disabled in simulation mode
+    if (m_sceneManager->getMode() == SceneManager::Mode::Simulation)
+    {
+        return;
+    }
+
+    std::shared_ptr<Camera> cam     = m_sceneManager->getActiveScene()->getActiveCamera();
+    const Vec3d&            focalPt = cam->getFocalPoint();
+    const Vec3d&            camPos  = cam->getPosition();
+    const Vec3d             diff    = camPos - focalPt;
+
+    // Linear zoom function
+    Vec3d newDiff;
+    if (dx > 0.0)
+    {
+        newDiff = diff * 1.1 * m_zoomSpeed * m_zoomFactor;
+    }
+    else
+    {
+        newDiff = diff * 0.9 * m_zoomSpeed * m_zoomFactor;
+    }
+    const Vec3d newPos = focalPt + newDiff;
+    cam->setPosition(newPos);
+    cam->update();
+}
+
+void
+MouseSceneControl::OnMouseMove(const Vec2d& pos)
+{
+    // Controls disabled in simulation mode
+    if (m_sceneManager->getMode() == SceneManager::Mode::Simulation)
+    {
+        return;
+    }
+
+    std::shared_ptr<Camera> cam = m_sceneManager->getActiveScene()->getActiveCamera();
+
+    // Push back the position
+    m_prevPos = m_pos;
+    m_pos     = pos;
+
+    if (m_mode == Mode::Rotate)
+    {
+        // Map mouse deltas to theta, phi rotations on a sphere
+        const Vec2d  dx     = (m_pos - m_prevPos) * (m_rotateSpeed * m_rotateFactor);
+        const double dTheta = dx[1];  // Elevation
+        const double dPhi   = -dx[0]; // Azimuth
+
+        const Vec3d& focalPt     = cam->getFocalPoint();
+        const Vec3d& camPos      = cam->getPosition();
+        Vec3d        localCamPos = camPos - focalPt;
+
+        // Get the rotation axes
+        const Mat4d& view  = cam->getView();
+        const Vec3d  up    = Vec3d(view(1, 0), view(1, 1), view(1, 2));
+        const Vec3d  right = Vec3d(view(0, 0), view(0, 1), view(0, 2));
+        // Rotate around each
+        localCamPos = Rotd(dPhi, up).toRotationMatrix() * localCamPos;
+        localCamPos = Rotd(dTheta, right).toRotationMatrix() * localCamPos;
+
+        // Set the new cam pos and up, then compute lookat
+        const Vec3d newPos = localCamPos + focalPt;
+        cam->setPosition(newPos);
+        cam->setViewUp(Vec3d(view(1, 0), view(1, 1), view(1, 2)));
+        cam->update();
+    }
+    else if (m_mode == Mode::Pan)
+    {
+        // Move camera along up and right
+        const Vec2d dx = m_pos - m_prevPos;
+
+        const Vec3d& focalPt = cam->getFocalPoint();
+        const Vec3d& camPos  = cam->getPosition();
+
+        Mat4d&      view  = cam->getView();
+        const Vec3d up    = Vec3d(view(1, 0), view(1, 1), view(1, 2));
+        const Vec3d right = Vec3d(view(0, 0), view(0, 1), view(0, 2));
+
+        // scale pan by zoom as well
+        const double dist = (focalPt - camPos).norm();
+        const Vec3d  dPos = (up * dx[1] + right * dx[0]) * -(m_panSpeed * m_panFactor * dist);
+        cam->setFocalPoint(focalPt + dPos);
+        cam->setPosition(camPos + dPos);
+        cam->update();
+    }
+}
+
+void
+MouseSceneControl::update()
+{
+    // Directly set it
+    //m_camera->getView() = m_targetViewTransform;
+
+    // Slerp the camera rotation
+    /*const Quatd currOrientation = Quatd(m_camera->getView().block<3, 3>(0, 0)).normalized();
+    const Quatd targetOrientation = Quatd(m_targetViewTransform.block<3, 3>(0, 0)).normalized();
+    const Quatd newOrientation = currOrientation.slerp(0.1, targetOrientation).normalized();
+    m_camera->getView().block<3, 3>(0, 0) = newOrientation.toRotationMatrix();*/
+}
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/imstkMouseSceneControl.h b/Source/SimulationManager/imstkMouseSceneControl.h
new file mode 100644
index 0000000000000000000000000000000000000000..b3cb9f35fb9eea983928833e7be67d7fdcd7053a
--- /dev/null
+++ b/Source/SimulationManager/imstkMouseSceneControl.h
@@ -0,0 +1,105 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkMouseControl.h"
+
+namespace imstk
+{
+class MouseDeviceClient;
+class SceneManager;
+
+///
+/// \class MouseSceneControl
+///
+/// \brief Controls the camera using trackball controls
+/// Left click rotate, middle click pan
+///
+class MouseSceneControl : public MouseControl
+{
+public:
+    enum class Mode
+    {
+        None,
+        Pan,
+        Rotate
+    };
+
+public:
+    MouseSceneControl() = default;
+    MouseSceneControl(std::shared_ptr<MouseDeviceClient> device);
+    ~MouseSceneControl() override = default;
+
+public:
+    ///
+    /// \brief Set the scroll controlled zoom speed
+    ///
+    void setZoomSpeed(const double zoomSpeed) { m_zoomSpeed = zoomSpeed; }
+
+    ///
+    /// \brief Set the mouse controlled rotate speed
+    ///
+    void setRotateSpeed(const double rotateSpeed) { m_rotateSpeed = rotateSpeed; }
+
+    ///
+    /// \brief Set the pan speed
+    ///
+    void setPanSpeed(const double panSpeed) { m_panSpeed = panSpeed; }
+
+    ///
+    /// \brief Set the scene manager to be controlled
+    /// The active scene's camera will be controllable depending on SceneManager's mode
+    ///
+    void setSceneManager(std::shared_ptr<SceneManager> manager) { m_sceneManager = manager; }
+
+public:
+    void printControls() override;
+
+    ///
+    /// \brief On the mouse scene control button press
+    ///
+    void OnButtonPress(const int key) override;
+    void OnButtonRelease(const int key) override;
+    void OnScroll(const double dx) override;
+    void OnMouseMove(const Vec2d& pos) override;
+
+    // How to handle mouse movements?
+    // Mouse movements best done in update func or event? event would still require update for interpolation
+    void update() override;
+
+protected:
+    std::shared_ptr<SceneManager> m_sceneManager;
+    Mode  m_mode = Mode::None;
+    Vec2d m_prevPos;
+    Vec2d m_pos;
+
+    // User changeable values
+    double m_zoomSpeed   = 1.0;
+    double m_rotateSpeed = 1.0;
+    double m_panSpeed    = 1.0;
+
+    // Hardcoded values
+    double m_zoomFactor   = 1.0;
+    double m_rotateFactor = 5.0;
+    double m_panFactor    = 1.0;
+};
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/imstkSceneManager.cpp b/Source/SimulationManager/imstkSceneManager.cpp
index d77823acb907d050d66349eebbec1c560cbd7531..9be929f5271fe4379e49ff8bea9608156781eba6 100644
--- a/Source/SimulationManager/imstkSceneManager.cpp
+++ b/Source/SimulationManager/imstkSceneManager.cpp
@@ -19,47 +19,144 @@
 
 =========================================================================*/
 
-// imstk
-#include "imstkScene.h"
 #include "imstkSceneManager.h"
-//#include "imstkCameraController.h"
-#include "imstkCamera.h"
+#include "imstkScene.h"
+#include "imstkLogger.h"
+#include "imstkDeviceControl.h"
 
 namespace imstk
 {
-SceneManager::SceneManager(std::shared_ptr<Scene> scene) :
-    Module(scene->getName()),
-    m_scene(scene)
+SceneManager::SceneManager(std::string name) :
+    LoopThreadObject(name), m_mode(Mode::Simulation),
+    m_prevCamName("default"), m_activeScene(nullptr)
+{
+}
+
+void
+SceneManager::setMode(Mode mode)
+{
+    if (m_mode == Mode::Simulation && mode == Mode::Debug)
+    {
+        // Store the previous camera name and switch to debug cam
+        m_prevCamName =
+            m_activeScene->getCameraName(m_activeScene->getActiveCamera());
+        m_activeScene->setActiveCamera("debug");
+    }
+    else if (m_mode == Mode::Debug && mode == Mode::Simulation)
+    {
+        // Switch back
+        m_activeScene->setActiveCamera(m_prevCamName);
+    }
+    m_mode = mode;
+}
+
+bool
+SceneManager::containsScene(std::string name) const
+{
+    return (m_sceneMap.find(name) != m_sceneMap.end());
+}
+
+void
+SceneManager::setActiveScene(std::string name)
+{
+    // Check if the requested scene exists
+    if (!containsScene(name))
+    {
+        LOG(WARNING) << "Scene '" << name << "' not registered! Please register before setting active";
+        return;
+    }
+    // Check if the scene is already active
+    if (m_activeScene != nullptr && name == m_activeScene->getName())
+    {
+        LOG(INFO) << "Scene '" << name << "' is already active!";
+        return;
+    }
+
+    auto newScene = this->getScene(name);
+
+    // If the scene wants to trackFPS enable framecounting in this module
+    // \todo: Figure out why this can't change on the fly
+    if (newScene->getConfig()->trackFPS)
+    {
+        enableFrameCount();
+    }
+
+    // Pause before swapping for thread safety
+    ThreadStatus prevStatus = getStatus();
+    if (prevStatus == ThreadStatus::Inactive
+        || prevStatus == ThreadStatus::Paused)
+    {
+        m_activeScene = newScene;
+    }
+    else if (prevStatus == ThreadStatus::Running)
+    {
+        // \todo: Dangerous to call this function from the thread you're about to pause
+        pause(true);
+        m_activeScene = newScene;
+        resume(true);
+    }
+}
+
+void
+SceneManager::setActiveScene(std::shared_ptr<Scene> scene)
 {
+    std::string name = scene->getName();
+
+    // Check if the requested scene exists
+    if (!containsScene(name))
+    {
+        addScene(scene);
+    }
+    setActiveScene(name);
 }
 
 void
-SceneManager::initModule()
+SceneManager::initThread()
 {
-    m_scene->launchModules();
+    if (m_activeScene != nullptr)
+    {
+        m_activeScene->initialize();
+    }
 }
 
 void
-SceneManager::cleanUpModule()
+SceneManager::updateThread()
 {
-    // End Camera Controller
-    /// \todo move this out of scene manager
-    /*if (auto camController = m_scene->getCamera()->getController())
+    // Advance the scene
+    if (m_activeScene != nullptr)
     {
-        camController->end();
-        m_threadMap.at(camController->getName()).join();
-    }*/
+        // Process one event
+        doEvent();
+
+        m_activeScene->advance();
+    }
 }
 
 void
-SceneManager::runModule()
+SceneManager::addScene(std::shared_ptr<Scene> scene)
 {
-    m_scene->advance();
-};
+    if (scene == nullptr)
+    {
+        LOG(WARNING) << "Tried to add null scene!";
+        return;
+    }
+    m_sceneMap[scene->getName()] = scene;
+}
 
 void
-SceneManager::startModuleInNewThread(std::shared_ptr<Module> module)
+SceneManager::removeScene(std::string name)
 {
-    m_threadMap[module->getName()] = std::thread([module] { module->start(); });
+    if (containsScene(name))
+    {
+        std::shared_ptr<Scene> scene = m_sceneMap[name];
+        if (m_activeScene == scene)
+        {
+            // \todo: Dangerous to call this function from the thread you're about to pause
+            pause(true);
+            m_activeScene = nullptr;
+            resume(true);
+        }
+        m_sceneMap.erase(name);
+    }
 }
-} // imstk
+}
\ No newline at end of file
diff --git a/Source/SimulationManager/imstkSceneManager.h b/Source/SimulationManager/imstkSceneManager.h
index e56b932a6528c8694e51ab35665d8b3b313b48d6..73c48ddc54a826d6ff91cac45511ed3d19084cb1 100644
--- a/Source/SimulationManager/imstkSceneManager.h
+++ b/Source/SimulationManager/imstkSceneManager.h
@@ -21,59 +21,106 @@
 
 #pragma once
 
+#include "imstkLoopThreadObject.h"
+
 #include <unordered_map>
 #include <thread>
 
-#include "imstkModule.h"
-
 namespace imstk
 {
+class DeviceControl;
 class Scene;
+
 ///
 /// \class SceneManager
 ///
-/// \brief Scene manager module launches the scene in a separate thread
+/// \brief Scene manager module manages multiple scenes and runs the active one
 ///
-class SceneManager : public Module
+class SceneManager : public LoopThreadObject
 {
+public:
+    enum class Mode
+    {
+        Simulation,
+        Debug
+    };
+
+public:
+    SceneManager(std::string name    = "SceneManager");
+    virtual ~SceneManager() override = default;
+
 public:
     ///
-    /// \brief Constructor
+    /// \brief Get the scene that the scene manager is managing
     ///
-    explicit SceneManager(std::shared_ptr<Scene> scene);
+    std::shared_ptr<Scene> getActiveScene() const { return m_activeScene; };
 
     ///
-    /// \brief Destructor
+    /// \brief Search for scene by name, returns nullptr if not found
     ///
-    virtual ~SceneManager() override = default;
+    std::shared_ptr<Scene> getScene(std::string name) const
+    {
+        if (containsScene(name))
+        {
+            return m_sceneMap.at(name);
+        }
+        else
+        {
+            return nullptr;
+        }
+    }
 
     ///
-    /// \brief Get the scene that the scene manager is managing
+    /// \brief Get the current mode
     ///
-    std::shared_ptr<Scene> getScene() { return m_scene; };
+    Mode getMode() const { return m_mode; }
 
-protected:
     ///
-    /// \brief Initialize the module
+    /// \brief Switches the mode of the scene manager
+    /// This alters the active scene
+    ///
+    void setMode(Mode mode);
+
+    ///
+    /// \brief Returns if the SceneManager contains the scene or not
     ///
-    void initModule() override;
+    bool containsScene(std::string name) const;
 
     ///
-    /// \brief Run the module
+    /// \brief Sets the currently updating scene
     ///
-    void runModule() override;
+    void setActiveScene(std::string newSceneName);
 
     ///
-    /// \brief Clean up the module
+    /// \brief Sets the currently updating scene, adds if does not exist yet
     ///
-    void cleanUpModule() override;
+    void setActiveScene(std::shared_ptr<Scene> scene);
 
     ///
-    /// \brief TODO
+    /// \brief Adds scene to the manager
     ///
-    void startModuleInNewThread(std::shared_ptr<Module> module);
+    void addScene(std::shared_ptr<Scene> scene);
 
-    std::shared_ptr<Scene> m_scene;                           ///> Scene that is being managed
-    std::unordered_map<std::string, std::thread> m_threadMap; ///>
+    ///
+    /// \brief Remove a scene from the manager
+    ///
+    void removeScene(std::string name);
+
+protected:
+    ///
+    /// \brief Initialize the thread
+    ///
+    void initThread() override;
+
+    ///
+    /// \brief Run the thread
+    ///
+    void updateThread() override;
+
+protected:
+    std::shared_ptr<Scene> m_activeScene;                               ///> Scene that is being managed
+    std::unordered_map<std::string, std::shared_ptr<Scene>> m_sceneMap; // used in backend mode where m_sceneManagerMap is not used
+    Mode m_mode;
+    std::string m_prevCamName;
 };
 } // imstk
diff --git a/Source/SimulationManager/imstkScreenCaptureUtility.cpp b/Source/SimulationManager/imstkScreenCaptureUtility.cpp
index a379219ecc0cd0db4c45d661e22d1529f5f3c440..be19bdb9e020f5a550575b9b83f97e9bfa458c6a 100644
--- a/Source/SimulationManager/imstkScreenCaptureUtility.cpp
+++ b/Source/SimulationManager/imstkScreenCaptureUtility.cpp
@@ -21,8 +21,6 @@
 
 #include "imstkScreenCaptureUtility.h"
 
-#include "imstkLogger.h"
-
 namespace imstk
 {
 unsigned int
diff --git a/Source/SimulationManager/imstkScreenCaptureUtility.h b/Source/SimulationManager/imstkScreenCaptureUtility.h
index 51fd6e273cc82a9689ab7da0a5544fc17d79e85f..415265b2145dfba525da12b428f67ab88d8f87b6 100644
--- a/Source/SimulationManager/imstkScreenCaptureUtility.h
+++ b/Source/SimulationManager/imstkScreenCaptureUtility.h
@@ -36,7 +36,7 @@ public:
     ///
     /// \brief Saves the screenshot as a png file
     ///
-    virtual void saveScreenShot() {};
+    virtual void saveScreenShot() = 0;
 
     ///
     /// \brief Returns the number of the screenshot
@@ -55,12 +55,12 @@ protected:
     ///
     /// \brief Constructor
     ///
-    ScreenCaptureUtility() {};
+    ScreenCaptureUtility() = default;
 
     ///
     /// \brief Destructor
     ///
-    ~ScreenCaptureUtility() = default;
+    virtual ~ScreenCaptureUtility() = default;
 
     unsigned int m_screenShotNumber = 0; //> screen shot number is added to the file prefix, and incremented everytime a screen shot is taken
     std::string  m_screenShotPrefix;     //> the prefix for the screenshots to be saved
diff --git a/Source/SimulationManager/imstkSimulationManager.h b/Source/SimulationManager/imstkSimulationManager.h
deleted file mode 100644
index ea47b59c4b7eb744111dc0ff87b6f97e596433c9..0000000000000000000000000000000000000000
--- a/Source/SimulationManager/imstkSimulationManager.h
+++ /dev/null
@@ -1,352 +0,0 @@
-/*=========================================================================
-
-   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.
-
-=========================================================================*/
-
-#pragma once
-
-#include <mutex>
-
-#include "imstkModule.h"
-
-#ifdef iMSTK_USE_Vulkan
-#include "imstkVulkanViewer.h"
-#else
-#include "imstkVTKViewer.h"
-#endif
-
-namespace imstk
-{
-class SceneManager;
-class Scene;
-struct SceneConfig;
-class Viewer;
-
-using SimulationStatus = ModuleStatus;
-
-template<class T>
-using SceneNameMap = std::unordered_map<std::string, std::shared_ptr<T>>;
-
-///
-/// \brief Simulation manager mode
-/// \note The mode is set at the time of initialization
-///
-enum class SimulationMode
-{
-    /// Simulation manager launches the simulation with a
-    /// render window
-    Rendering = 0,
-
-    /// Simulation manager launches the simulation without a
-    /// render window but keeps looping the simulation
-    RunInBackgroundSync,
-
-    /// Simulation manager launches the simulation without a
-    /// render window no waiting
-    RunInBackgroundAsync,
-
-    /// Simulation manager launches the simulation without a
-    /// render window and returns the control
-    Backend
-};
-
-///
-/// \brief Simulation manager configuration
-///
-struct SimManagerConfig
-{
-    // logger
-    bool enableFileLogging    = true;
-    bool enableStdoutLogging  = true;
-    std::string logPath       = "./";
-    std::string logFilePrefix = "simulation";
-
-    // Name
-    std::string simulationName = "imstk";
-
-    // states
-    SimulationMode simulationMode   = SimulationMode::Rendering;
-    SimulationStatus startingStatus = SimulationStatus::Running;
-    bool VR_Enabled = false;
-    bool startInPausedState = false;
-
-    // 0 indicates that an optimal size will be used
-    unsigned int threadPoolSize = 0;
-};
-
-///
-/// \class SimulationManager
-///
-/// \brief This class is the manager of the simulation at the top level.
-/// The simulation can contain multiple scenes. It can be launched in three
-///  modes: rendering (default), runInBackground and backend
-///
-class SimulationManager
-{
-using keyPressCallback = std::function<void (void)>;
-
-public:
-    ///
-    /// \brief Constructor
-    ///
-    SimulationManager(const std::shared_ptr<SimManagerConfig> config = std::make_shared<SimManagerConfig>());
-
-    ///
-    /// \brief Default destructor
-    ///
-    ~SimulationManager() { this->end(); };
-
-    ///
-    /// \brief Returns the simulation status
-    ///
-    const SimulationStatus& getStatus() const { return m_status; };
-
-    ///
-    /// \brief Returns log worker
-    ///
-    //std::shared_ptr<g3::LogWorker> getLogWorker() { return m_logUtil->getLogWorker(); }
-
-    ///
-    /// \brief Set number of worker threads in thread pool for parallel computation
-    /// \param nThreads Size of the thread pool to set,
-    /// if nThreads <= 0 then the optimal value (which typically equals to number of logical cores) will be used
-    ///
-    void setThreadPoolSize(const int nThreads);
-
-    ///
-    /// \brief Set number of worker threads in thread pool for parallel computation to be the optimal value,
-    /// which typically equals to the number of logical cores of the machine
-    ///
-    void setOptimalThreadPoolSize();
-
-    ///
-    /// \brief Set the viewer
-    ///
-    void setViewer(std::shared_ptr<Viewer> viewer) { m_viewer = viewer; }
-
-    ///
-    /// \brief Returns true if the scene is registered, else false
-    ///
-    bool isSceneRegistered(const std::string& sceneName) const;
-
-    ///
-    /// \brief Returns the scene manager given the scene
-    ///
-    std::shared_ptr<SceneManager> getSceneManager(const std::string& sceneName) const;
-    std::shared_ptr<SceneManager> getSceneManager(std::shared_ptr<Scene> scene) const;
-
-    ///
-    /// \brief Returns the scene manager config
-    ///
-    std::shared_ptr<SimManagerConfig> getConfig() const { return m_config; }
-
-    ///
-    /// \brief Returns the scene with a given name
-    ///
-    std::shared_ptr<Scene> getScene(const std::string& sceneName) const;
-
-    ///
-    /// \brief Returns the scene that is currently active
-    ///
-    std::shared_ptr<Scene> getActiveScene() const;
-
-    ///
-    /// \brief Create a new scene with a given name
-    ///
-    std::shared_ptr<Scene> createNewScene(const std::string&           newSceneName,
-                                          std::shared_ptr<SceneConfig> config);
-    std::shared_ptr<Scene> createNewScene(const std::string& newSceneName);
-
-    ///
-    /// \brief Create a new scene
-    /// \note Scene name is automatically assigned
-    ///
-    std::shared_ptr<Scene> createNewScene();
-
-    ///
-    /// \brief Add a new scene with given name to the scene list
-    ///
-    void addScene(std::shared_ptr<Scene> newScene);
-
-    ///
-    /// \brief Remove the scene with given name from the scene list
-    ///
-    void removeScene(const std::string& sceneName);
-
-    // Modules
-
-    ///
-    /// \brief Returns true if the modules is registered, else false
-    ///
-    bool isModuleRegistered(const std::string& moduleName) const;
-
-    ///
-    /// \brief Returns the module given the name
-    ///
-    std::shared_ptr<Module> getModule(const std::string& moduleName) const;
-
-    ///
-    /// \brief Add a new module with a given name
-    ///
-    void addModule(std::shared_ptr<Module> newModule);
-
-    ///
-    /// \brief Remove the module with a given name
-    ///
-    void removeModule(const std::string& moduleName);
-
-    // Viewer
-    std::shared_ptr<Viewer> getViewer() const;
-
-    ///
-    /// \brief Set the current scene to the one with the supplied name
-    ///
-    void setActiveScene(const std::string& newSceneName,
-                        const bool         unloadCurrentScene = false);
-    void setActiveScene(std::shared_ptr<Scene> scene,
-                        const bool             unloadCurrentScene = false);
-
-    ///
-    /// \brief Start the simulation by initializing the active scene
-    /// In Mode::backend mode, the simulation manager is initialized and
-    /// the modules except the scene manager are launched in new threads
-    /// and returned. In rendering and runInBackground modes the simulation manager
-    /// module gets launched and an never returns
-    ///
-    void start(const SimulationStatus simStatus  = SimulationStatus::Running,
-               const Renderer::Mode   renderMode = Renderer::Mode::Simulation);
-
-    ///
-    /// \brief Initialize the modules and the active scene
-    ///
-    void initialize();
-
-    ///
-    /// \brief Run the simulation from a paused state
-    /// In Mode::backend mode, the simulation manager is initialized if not and returned
-    ///
-    void run();
-
-    ///
-    /// \brief Pause the simulation
-    ///
-    void pause();
-
-    ///
-    /// \brief Reset the simulation to initial state
-    ///
-    void reset();
-
-    ///
-    /// \brief End the simulation
-    ///
-    void end();
-
-    ///
-    /// \brief Advance to next frame
-    ///
-    void advanceFrame();
-
-    ///
-    /// \brief Return the mode of the simulation manager
-    ///
-    SimulationMode getMode() const { return m_config->simulationMode; }
-
-    ///
-    /// \brief Add key press callback to be used in background mode only
-    /// \todo add remove function as well
-    ///
-    void addKeyPressCallback(keyPressCallback func, const int c);
-
-private:
-    ///
-    /// \brief Create a viewer
-    ///
-    void createViewer(const bool enableVR);
-
-    ///
-    /// \brief Start the viewer
-    ///
-    void startViewer(const Renderer::Mode renderMode = Renderer::Mode::Debug);
-
-    ///
-    /// \brief Print user keyboard controls
-    ///
-    void printUserControlsInfo(const bool isRendering = true) const;
-
-    ///
-    /// \brief Start a module (refer \link  imstkModule \endlink) in new thread
-    ///
-    void startModuleInNewThread(std::shared_ptr<Module> module);
-
-    ///
-    /// \brief Start modules
-    ///
-    void startNonSceneModules();
-
-    ///
-    /// \brief Launch scene manager modules
-    ///
-    void launchSceneModule(std::string sceneName);
-
-    ///
-    /// \brief Pause modules
-    ///
-    void pauseModules();
-
-    ///
-    /// \brief End modules
-    ///
-    void endModules();
-
-    ///
-    /// \brief Keeps things in an infinite loop if rendering is disabled
-    /// The same keys can be used to trigger PAUSE, RUNNING, RESET of the simulation
-    ///
-    void infiniteLoopNoRenderingMode();
-
-    std::string m_activeSceneName = "";
-
-    // Maps
-    SceneNameMap<SceneManager> m_sceneManagerMap;
-    SceneNameMap<Scene>  m_sceneMap;       // used in backend mode where m_sceneManagerMap is not used
-    SceneNameMap<Module> m_modulesMap;
-
-    std::unordered_map<std::string, std::thread> m_threadMap;
-
-    std::shared_ptr<Viewer> m_viewer = nullptr;
-
-    // logging
-    //std::shared_ptr<Logger> m_logUtil = std::make_shared<Logger>();
-    std::unique_ptr<FileSinkHandle>   m_fileSinkHandle;
-    std::unique_ptr<StdoutSinkHandle> m_stdSinkHandle;
-
-    struct callbackKeyPair { int key; keyPressCallback func; };
-    std::vector<callbackKeyPair> m_kepPressCallbacks;
-
-    // states
-    SimulationStatus m_status = SimulationStatus::Inactive;
-    bool m_simulationStarted  = false;
-    bool m_initialized = false;
-
-    std::shared_ptr<SimManagerConfig> m_config;
-
-    std::mutex m_mutex;
-};
-} // imstk
diff --git a/Source/SimulationManager/imstkViewer.cpp b/Source/SimulationManager/imstkViewer.cpp
index 483884c6c8b23316722f74510ca6839b7d16b20d..d834d1c425308855d19fa83f040c34cbc216a1c5 100644
--- a/Source/SimulationManager/imstkViewer.cpp
+++ b/Source/SimulationManager/imstkViewer.cpp
@@ -20,10 +20,10 @@
 =========================================================================*/
 
 #include "imstkViewer.h"
-#include "imstkScene.h"
 #include "imstkCamera.h"
+#include "imstkDeviceControl.h"
+#include "imstkInteractorStyle.h"
 #include "imstkLogger.h"
-#include "imstkScreenCaptureUtility.h"
 
 #ifdef iMSTK_USE_Vulkan
 #include "imstkGUICanvas.h"
@@ -31,19 +31,19 @@
 
 namespace imstk
 {
-Viewer::Viewer() : m_config(std::make_shared<viewerConfig>())
+Viewer::Viewer(std::string name) :
+    ThreadObject(name),
+    m_activeScene(nullptr),
+    m_config(std::make_shared<ViewerConfig>()),
+    m_debugCamera(std::make_shared<Camera>()),
+    m_interactorStyle(nullptr),
+    m_screenCapturer(nullptr)
 {
 #ifdef iMSTK_USE_Vulkan
     m_canvas(std::make_shared<GUIOverlay::Canvas>())
 #endif
 }
 
-const std::shared_ptr<Scene>&
-Viewer::getActiveScene() const
-{
-    return m_activeScene;
-}
-
 const std::shared_ptr<Renderer>&
 Viewer::getActiveRenderer() const
 {
@@ -52,90 +52,14 @@ Viewer::getActiveRenderer() const
     return m_rendererMap.at(m_activeScene);
 }
 
-const bool&
-Viewer::isRendering() const
-{
-    return m_running;
-}
-
-const std::shared_ptr<ScreenCaptureUtility>&
-Viewer::getScreenCaptureUtility() const
-{
-    return m_screenCapturer;
-}
-
-#ifdef iMSTK_USE_Vulkan
-const std::shared_ptr<GUIOverlay::Canvas>&
-Viewer::getCanvas()
-{
-    return m_canvas;
-}
-
-#endif
-
-void
-Viewer::setOnCharFunction(char c, EventHandlerFunction func)
-{
-    m_interactorStyle->m_onCharFunctionMap[c] = func;
-}
-
-void
-Viewer::setOnMouseMoveFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onMouseMoveFunction = func;
-}
-
-void
-Viewer::setOnLeftButtonDownFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onLeftButtonDownFunction = func;
-}
-
-void
-Viewer::setOnLeftButtonUpFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onLeftButtonUpFunction = func;
-}
-
-void
-Viewer::setOnMiddleButtonDownFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onMiddleButtonDownFunction = func;
-}
-
-void
-Viewer::setOnMiddleButtonUpFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onMiddleButtonUpFunction = func;
-}
-
-void
-Viewer::setOnRightButtonDownFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onRightButtonDownFunction = func;
-}
-
-void
-Viewer::setOnRightButtonUpFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onRightButtonUpFunction = func;
-}
-
-void
-Viewer::setOnMouseWheelForwardFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onMouseWheelForwardFunction = func;
-}
-
 void
-Viewer::setOnMouseWheelBackwardFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onMouseWheelBackwardFunction = func;
-}
-
-void
-Viewer::setOnTimerFunction(EventHandlerFunction func)
-{
-    m_interactorStyle->m_onTimerFunction = func;
+Viewer::updateThread()
+{
+    this->postEvent(Event(EventType::PreUpdate));
+    for (auto control : m_controls)
+    {
+        control->update();
+    }
+    this->postEvent(Event(EventType::PostUpdate));
 }
 }
diff --git a/Source/SimulationManager/imstkViewer.h b/Source/SimulationManager/imstkViewer.h
index be452649c3b39d883c82132f2762bdd0b768e229..01dba74dc38b93820c05cf927a4a6201b61b69ec 100644
--- a/Source/SimulationManager/imstkViewer.h
+++ b/Source/SimulationManager/imstkViewer.h
@@ -22,11 +22,15 @@
 #pragma once
 
 #include "imstkRenderer.h"
-#include "imstkInteractorStyle.h"
+#include "imstkThreadObject.h"
+
+#include <unordered_map>
 
 namespace imstk
 {
-class SimulationManager;
+class Camera;
+class DeviceControl;
+class InteractorStyle;
 class Scene;
 class ScreenCaptureUtility;
 
@@ -37,7 +41,7 @@ class Canvas;
 }
 #endif
 
-struct viewerConfig
+struct ViewerConfig
 {
     std::string m_windowName = "imstk";
 
@@ -57,34 +61,24 @@ struct viewerConfig
 /// Contains user API to configure the rendering with various backends
 /// Manages the keyboard and mouse events
 ///
-class Viewer
+class Viewer : public ThreadObject
 {
+protected:
+    Viewer(std::string name);
 public:
-
-    Viewer();
-    Viewer(SimulationManager*) {}
     virtual ~Viewer() = default;
 
+public:
     ///
     /// \brief Get scene currently being rendered
     ///
-    const std::shared_ptr<Scene>& getActiveScene() const;
+    std::shared_ptr<Scene> getActiveScene() const { return m_activeScene; }
 
     ///
     /// \brief Set scene to be rendered
     ///
     virtual void setActiveScene(const std::shared_ptr<Scene>& scene) = 0;
 
-    ///
-    /// \brief Start rendering
-    ///
-    virtual void startRenderingLoop() = 0;
-
-    ///
-    /// \brief Terminate rendering
-    ///
-    virtual void endRenderingLoop() = 0;
-
     ///
     /// \brief Setup the current renderer to render what's needed
     /// based on the mode chosen
@@ -92,14 +86,14 @@ public:
     virtual void setRenderingMode(const Renderer::Mode mode) = 0;
 
     ///
-    /// \brief Get the current renderer's mode
+    /// \brief Set the render window size
     ///
-    virtual Renderer::Mode getRenderingMode() { return Renderer::Mode::Empty; }
+    virtual void setSize(int, int) { }
 
     ///
-    /// \brief Returns true if the Viewer is rendering
+    /// \brief Get the current renderer's mode
     ///
-    const bool& isRendering() const;
+    virtual Renderer::Mode getRenderingMode() const { return Renderer::Mode::Empty; }
 
     ///
     /// \brief Retrieve the renderer associated with the current scene
@@ -114,7 +108,7 @@ public:
     ///
     /// \brief access screen shot utility
     ///
-    const std::shared_ptr<ScreenCaptureUtility>& getScreenCaptureUtility() const;
+    std::shared_ptr<ScreenCaptureUtility> getScreenCaptureUtility() const { return m_screenCapturer; }
 
     ///
     /// \brief Set the coloring of the screen background
@@ -126,41 +120,43 @@ public:
     ///
     /// \brief Get canvas
     ///
-    const std::shared_ptr<GUIOverlay::Canvas>& getCanvas();
+    std::shared_ptr<GUIOverlay::Canvas> getCanvas() const { return m_canvas; }
 #endif
 
     ///
-    /// \brief Set custom event handlers on interactor style
+    /// \brief Add a control whose events should be handled
     ///
-    void setOnCharFunction(char c, EventHandlerFunction func);
-    void setOnMouseMoveFunction(EventHandlerFunction func);
-    void setOnLeftButtonDownFunction(EventHandlerFunction func);
-    void setOnLeftButtonUpFunction(EventHandlerFunction func);
-    void setOnMiddleButtonDownFunction(EventHandlerFunction func);
-    void setOnMiddleButtonUpFunction(EventHandlerFunction func);
-    void setOnRightButtonDownFunction(EventHandlerFunction func);
-    void setOnRightButtonUpFunction(EventHandlerFunction func);
-    void setOnMouseWheelForwardFunction(EventHandlerFunction func);
-    void setOnMouseWheelBackwardFunction(EventHandlerFunction func);
+    void addControl(std::shared_ptr<DeviceControl> control) { m_controls.push_back(control); }
 
     ///
-    /// \brief Set custom behavior to be run on every frame.
-    /// The return of the function will not have any  effect.
+    /// \brief Remove an existing control if it exists
     ///
-    void setOnTimerFunction(EventHandlerFunction func);
+    void removeControl(std::shared_ptr<DeviceControl> control)
+    {
+        std::vector<std::shared_ptr<DeviceControl>>::iterator i =
+            std::find(m_controls.begin(), m_controls.end(), control);
+        if (i != m_controls.end())
+        {
+            m_controls.erase(i);
+        }
+    }
+
+protected:
+    virtual void updateThread();
 
 protected:
+    std::vector<std::shared_ptr<DeviceControl>> m_controls; ///> Set of controls updated on the viewer thread
     std::unordered_map<std::shared_ptr<Scene>, std::shared_ptr<Renderer>> m_rendererMap;
 
-    std::shared_ptr<Scene> m_activeScene;
+    std::shared_ptr<Scene>  m_activeScene;
+    std::shared_ptr<Camera> m_debugCamera;
     std::shared_ptr<InteractorStyle>      m_interactorStyle;
     std::shared_ptr<ScreenCaptureUtility> m_screenCapturer; ///> Screen shot utility
 
-    bool m_running = false;
 #ifdef iMSTK_USE_Vulkan
     std::shared_ptr<GUIOverlay::Canvas> m_canvas = nullptr;
 #endif
 
-    std::shared_ptr<viewerConfig> m_config = nullptr;
+    std::shared_ptr<ViewerConfig> m_config;
 };
 }
diff --git a/Source/Solvers/imstkConjugateGradient.h b/Source/Solvers/imstkConjugateGradient.h
index 16c3c7ec52ca29593ad778b2384782a4dc4fd2c8..62258a74cfed12dbc1c0eff083564dd0079869cd 100644
--- a/Source/Solvers/imstkConjugateGradient.h
+++ b/Source/Solvers/imstkConjugateGradient.h
@@ -23,7 +23,6 @@
 
 #include "imstkIterativeLinearSolver.h"
 
-// Eigen includes
 #include <Eigen/IterativeLinearSolvers>
 
 namespace imstk
@@ -40,7 +39,7 @@ public:
     ///
     ConjugateGradient();
     ConjugateGradient(const SparseMatrixd& A, const Vectord& rhs);
-    ~ConjugateGradient() = default;
+    virtual ~ConjugateGradient() override = default;
 
     ///
     /// \brief Remove specific constructor signatures
diff --git a/Source/Solvers/imstkDirectLinearSolver.cpp b/Source/Solvers/imstkDirectLinearSolver.cpp
index 1b82a4eb8a063a23f78be90caf956db0cad20986..9e0f1f7eb0d28b6e9883e4d468e388231cb495f9 100644
--- a/Source/Solvers/imstkDirectLinearSolver.cpp
+++ b/Source/Solvers/imstkDirectLinearSolver.cpp
@@ -20,9 +20,7 @@
 =========================================================================*/
 
 #include "imstkDirectLinearSolver.h"
-#include "imstkLinearSystem.h"
 #include "imstkLogger.h"
-#include <iostream>
 
 namespace imstk
 {
diff --git a/Source/Solvers/imstkDirectLinearSolver.h b/Source/Solvers/imstkDirectLinearSolver.h
index 09e3ac4ab891d1c6a9b2ed97bbf30cdc9332cf6d..bd59e940583b6f440d1faba07b18b5cc8100c352 100644
--- a/Source/Solvers/imstkDirectLinearSolver.h
+++ b/Source/Solvers/imstkDirectLinearSolver.h
@@ -21,16 +21,15 @@
 
 #pragma once
 
+#include "imstkLinearSolver.h"
+#include "imstkMath.h"
+
 #pragma warning( push )
 #pragma warning( disable : 4127 )
 #include <Eigen/Sparse>
 #include <Eigen/SparseLU>
 #pragma warning( pop )
 
-// iMSTK includes
-#include "imstkLinearSolver.h"
-#include "imstkMath.h"
-
 namespace imstk
 {
 template<typename MatrixType> class DirectLinearSolver;
@@ -99,8 +98,8 @@ public:
     ///
     /// \brief Default constructor/destructor
     ///
-    DirectLinearSolver()  = default;
-    ~DirectLinearSolver() = default;
+    DirectLinearSolver() = default;
+    virtual ~DirectLinearSolver() override = default;
 
     ///
     /// \brief Constructor
diff --git a/Source/Solvers/imstkGaussSeidel.cpp b/Source/Solvers/imstkGaussSeidel.cpp
index 514fb4ca45fc5c32491d53d711e984344b1a25bd..1d36c39baf6c231eb25358a401cbe8370af47f92 100644
--- a/Source/Solvers/imstkGaussSeidel.cpp
+++ b/Source/Solvers/imstkGaussSeidel.cpp
@@ -21,10 +21,6 @@
 
 #include "imstkGaussSeidel.h"
 #include "imstkLogger.h"
-#include "imstkLinearProjectionConstraint.h"
-
-// Eigen includes
-#include <Eigen/IterativeLinearSolvers>
 
 namespace imstk
 {
diff --git a/Source/Solvers/imstkGaussSeidel.h b/Source/Solvers/imstkGaussSeidel.h
index 4caf0cbf0a4fea7a1ab460667a4ceed43c27afe8..e3cc6eb71e52ba5ad96ed35bea3967ca8920a5de 100644
--- a/Source/Solvers/imstkGaussSeidel.h
+++ b/Source/Solvers/imstkGaussSeidel.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// iMSTK includes
 #include "imstkIterativeLinearSolver.h"
 
 namespace imstk
@@ -39,7 +38,7 @@ public:
     ///
     GaussSeidel() { m_type = Type::GaussSeidel; };
     GaussSeidel(const SparseMatrixd& A, const Vectord& rhs);
-    ~GaussSeidel() = default;
+    virtual ~GaussSeidel() override = default;
 
     ///
     /// \brief Remove specific constructor signatures
diff --git a/Source/Solvers/imstkIterativeLinearSolver.cpp b/Source/Solvers/imstkIterativeLinearSolver.cpp
index c287f23a5b09fd4c3fe12e3c4e7e703a25d4fe35..d20bcf8a0122470f309410f78c1d5ef6efb10e75 100644
--- a/Source/Solvers/imstkIterativeLinearSolver.cpp
+++ b/Source/Solvers/imstkIterativeLinearSolver.cpp
@@ -21,6 +21,7 @@
 
 #include "imstkIterativeLinearSolver.h"
 #include "imstkLogger.h"
+#include "imstkTypes.h"
 
 namespace imstk
 {
@@ -66,10 +67,9 @@ IterativeLinearSolver::print() const
 }
 
 void
-IterativeLinearSolver::solve(Vectord& x)
+IterativeLinearSolver::solve(Vectord& imstkNotUsed(x))
 {
     LOG(WARNING) << "IterativeLinearSolver::solve is not implemented!";
-    x;
     /*
     if (!m_linearSystem)
     {
diff --git a/Source/Solvers/imstkIterativeLinearSolver.h b/Source/Solvers/imstkIterativeLinearSolver.h
index 89d22be6fd37e932ab8eff9202418096fa752ddf..9cbfd748d8925a01de70ebe4f69872a0039f8e27 100644
--- a/Source/Solvers/imstkIterativeLinearSolver.h
+++ b/Source/Solvers/imstkIterativeLinearSolver.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// iMSTK includes
 #include "imstkLinearSolver.h"
 
 namespace imstk
@@ -35,8 +34,8 @@ public:
     ///
     /// \brief Default constructor/destructor
     ///
-    IterativeLinearSolver() {};
-    virtual ~IterativeLinearSolver() {};
+    IterativeLinearSolver() = default;
+    virtual ~IterativeLinearSolver() override = default;
 
     ///
     /// \brief Do one iteration of the method.
diff --git a/Source/Solvers/imstkJacobi.cpp b/Source/Solvers/imstkJacobi.cpp
index 5d7d4714dda6f2d5ba4f794204f2440f3eaea5e0..aaaabfcd494fb82ce8587784bff3a445127f9d54 100644
--- a/Source/Solvers/imstkJacobi.cpp
+++ b/Source/Solvers/imstkJacobi.cpp
@@ -20,11 +20,8 @@
 =========================================================================*/
 
 #include "imstkJacobi.h"
-#include "imstkLogger.h"
 #include "imstkLinearProjectionConstraint.h"
-
-// Eigen includes
-#include <Eigen/IterativeLinearSolvers>
+#include "imstkLogger.h"
 
 namespace imstk
 {
diff --git a/Source/Solvers/imstkJacobi.h b/Source/Solvers/imstkJacobi.h
index 7d1ee27070c6d0c3479dc459ae66fc24373ae822..7c72c2b50dbb9823cc3a3f1b30638a969dfcdd97 100644
--- a/Source/Solvers/imstkJacobi.h
+++ b/Source/Solvers/imstkJacobi.h
@@ -38,7 +38,7 @@ public:
     ///
     Jacobi() { m_type = Type::Jacobi; };
     Jacobi(const SparseMatrixd& A, const Vectord& rhs);
-    ~Jacobi() = default;
+    virtual ~Jacobi() override = default;
 
     ///
     /// \brief Remove specific constructor signatures
diff --git a/Source/Solvers/imstkLinearSolver.h b/Source/Solvers/imstkLinearSolver.h
index 7b279c1db9f4828b5996159d90acf2d98b0d1c16..1d55d8ed32f46b7cceeae9f3dfbbd84dee66ed88 100644
--- a/Source/Solvers/imstkLinearSolver.h
+++ b/Source/Solvers/imstkLinearSolver.h
@@ -21,7 +21,6 @@
 
 #pragma once
 
-// imstk includes
 #include "imstkLinearSystem.h"
 #include "imstkMath.h"
 
@@ -53,7 +52,7 @@ public:
     /// \brief Default constructor/destructor
     ///
     LinearSolver() : m_linearSystem(nullptr) {};
-    virtual ~LinearSolver() {};
+    virtual ~LinearSolver() = default;
 
     ///
     /// \brief Main solve routine
diff --git a/Source/Solvers/imstkLinearSystem.cpp b/Source/Solvers/imstkLinearSystem.cpp
index be680e5b0a9b36d09b528a91762dfb124a4646d7..8d6f71639cd8b0c7caee8359934122e26ff5984e 100644
--- a/Source/Solvers/imstkLinearSystem.cpp
+++ b/Source/Solvers/imstkLinearSystem.cpp
@@ -21,8 +21,6 @@
 
 #include "imstkLinearSystem.h"
 
-#include <g3log/g3log.hpp>
-
 namespace imstk
 {
 //template<typename SystemMatrixType>
diff --git a/Source/Solvers/imstkLinearSystem.h b/Source/Solvers/imstkLinearSystem.h
index 5c0814258a80dd0e654bbfcdaf44e4e519d12b3b..e5eb88741d2d2ed44cb89d8f6c50d8decd580dc1 100644
--- a/Source/Solvers/imstkLinearSystem.h
+++ b/Source/Solvers/imstkLinearSystem.h
@@ -62,7 +62,7 @@ public:
     ///
     /// \brief Destructor
     ///
-    virtual ~LinearSystem() {};
+    virtual ~LinearSystem() override {};
 
     ///
     ///  \brief Returns a reference to local right hand side vector.
diff --git a/Source/Solvers/imstkNewtonSolver.cpp b/Source/Solvers/imstkNewtonSolver.cpp
index 28bf71a30b630c900b32351805baa8206d6022eb..8f11b8b70be79af9bcbf24a7215d65d9a44671b0 100644
--- a/Source/Solvers/imstkNewtonSolver.cpp
+++ b/Source/Solvers/imstkNewtonSolver.cpp
@@ -19,15 +19,13 @@
 
 =========================================================================*/
 
-#include <iostream>
-#include <memory>
-
 #include "imstkNewtonSolver.h"
-#include "imstkIterativeLinearSolver.h"
 #include "imstkConjugateGradient.h"
 #include "imstkDirectLinearSolver.h"
 #include "imstkLogger.h"
 
+#include <iostream>
+
 namespace imstk
 {
 template<>
diff --git a/Source/Solvers/imstkNewtonSolver.h b/Source/Solvers/imstkNewtonSolver.h
index 2dded1606af66aec5fecab42a955738777bba738..3d0cea8ee71600b0ff7852595ff881106c75ab3c 100644
--- a/Source/Solvers/imstkNewtonSolver.h
+++ b/Source/Solvers/imstkNewtonSolver.h
@@ -41,11 +41,11 @@ public:
 
 public:
     ///
-    /// \brief Constructors/Destructors
+    /// \brief Constructors\Destructors
     ///
     NewtonSolver();
-    ~NewtonSolver() = default;
     NewtonSolver(const NewtonSolver& other) = delete;
+    virtual ~NewtonSolver() override = default;
 
     NewtonSolver& operator=(const NewtonSolver& other) = delete;
 
@@ -95,7 +95,7 @@ public:
     ///
     /// \brief Get JacobianMatrix. Returns jacobian matrix
     ///
-    SystemMatrix& getJacobianMatrix();
+    //SystemMatrix& getJacobianMatrix();
 
     ///
     /// \brief Set AbsoluteTolerance
diff --git a/Source/Solvers/imstkNonLinearSolver.cpp b/Source/Solvers/imstkNonLinearSolver.cpp
index 6eac4676c94c171ba1a6e480f8ee1160401c8ffa..b7b18691b9c1099961e728243c506de1452b8c62 100644
--- a/Source/Solvers/imstkNonLinearSolver.cpp
+++ b/Source/Solvers/imstkNonLinearSolver.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkNonLinearSolver.h"
-#include "imstkMath.h"
 
 namespace imstk
 {
diff --git a/Source/Solvers/imstkNonLinearSolver.h b/Source/Solvers/imstkNonLinearSolver.h
index f576ea458b2376f5c8574c01976adee1bf2af6ef..af3c1cec7f2064b551ba48d0771948bdb45ed12b 100644
--- a/Source/Solvers/imstkNonLinearSolver.h
+++ b/Source/Solvers/imstkNonLinearSolver.h
@@ -21,15 +21,13 @@
 
 #pragma once
 
-// STL includes
-#include <array>
-#include <functional>
-
-// imstk includes
 #include "imstkNonLinearSystem.h"
 #include "imstkMath.h"
 #include "imstkSolverBase.h"
 
+#include <array>
+#include <functional>
+
 namespace imstk
 {
 ///
@@ -48,7 +46,7 @@ public:
     /// \brief Default Constructor/Destructor
     ///
     NonLinearSolver();
-    virtual ~NonLinearSolver() = default;
+    virtual ~NonLinearSolver() override = default;
 
     ///
     /// \brief Main solve routine.
diff --git a/Source/Solvers/imstkNonLinearSystem.cpp b/Source/Solvers/imstkNonLinearSystem.cpp
index 0ce7bc971b8f0d85199110ca511ba94aad6d975f..fde018908fe7fca4e51ece7800f31a31412d560a 100644
--- a/Source/Solvers/imstkNonLinearSystem.cpp
+++ b/Source/Solvers/imstkNonLinearSystem.cpp
@@ -22,8 +22,6 @@
 #include "imstkNonLinearSystem.h"
 #include "imstkMath.h"
 
-// #include <g3log/g3log.hpp>
-
 namespace imstk
 {
 template<typename Matrix>
diff --git a/Source/Solvers/imstkNonLinearSystem.h b/Source/Solvers/imstkNonLinearSystem.h
index 2a49cc24362b31b3c083113b11f83c76d012bac7..c6359200e4c68bf242aa50682fb8c01f01c877ca 100644
--- a/Source/Solvers/imstkNonLinearSystem.h
+++ b/Source/Solvers/imstkNonLinearSystem.h
@@ -22,7 +22,6 @@
 #pragma once
 
 #include "imstkMath.h"
-//#include "imstkLinearProjectionConstraint.h"
 
 namespace imstk
 {
diff --git a/Source/Solvers/imstkPbdSolver.cpp b/Source/Solvers/imstkPbdSolver.cpp
index a03ff5351351d8448fa6371394dc1600eaaffe29..87edaeb46e5fc0012a5ba2ce7f471f333349d79d 100644
--- a/Source/Solvers/imstkPbdSolver.cpp
+++ b/Source/Solvers/imstkPbdSolver.cpp
@@ -20,7 +20,9 @@
 =========================================================================*/
 
 #include "imstkPbdSolver.h"
+#include "imstkLogger.h"
 #include "imstkParallelUtils.h"
+#include "imstkPbdCollisionConstraint.h"
 
 namespace imstk
 {
@@ -32,6 +34,19 @@ PbdSolver::PbdSolver() :
 {
 }
 
+void
+PbdSolver::setSolverType(const PbdConstraint::SolverType& type)
+{
+    if (type == PbdConstraint::SolverType::GCD)
+    {
+        LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead";
+        m_solverType = PbdConstraint::SolverType::xPBD;
+        return;
+    }
+
+    m_solverType = type;
+}
+
 void
 PbdSolver::solve()
 {
diff --git a/Source/Solvers/imstkPbdSolver.h b/Source/Solvers/imstkPbdSolver.h
index 73feaf9fef5a47026dde13638737f3b9ec5f4fcf..3e873bbf7be6519a3d096457e9378e5141abf5c7 100644
--- a/Source/Solvers/imstkPbdSolver.h
+++ b/Source/Solvers/imstkPbdSolver.h
@@ -21,13 +21,13 @@
 
 #pragma once
 
-#include "imstkPbdCollisionConstraint.h"
 #include "imstkPbdConstraint.h"
 #include "imstkSolverBase.h"
-#include "imstkLogger.h"
 
 namespace imstk
 {
+class PbdCollisionConstraint;
+
 ///
 /// \struct CollisionConstraintData
 /// \brief Stores positions and masses of two colliding objects
@@ -105,17 +105,7 @@ public:
     ///
     /// \brief Set the PBD solver type
     ///
-    void setSolverType(const PbdConstraint::SolverType& type)
-    {
-        if (type == PbdConstraint::SolverType::GCD)
-        {
-            LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead";
-            m_solverType = PbdConstraint::SolverType::xPBD;
-            return;
-        }
-
-        m_solverType = type;
-    }
+    void setSolverType(const PbdConstraint::SolverType& type);
 
     ///
     /// \brief Solve the non linear system of equations G(x)=0 using Newton's method.
@@ -155,7 +145,7 @@ public:
     ///
     /// \brief Add the global collision contraints to this solver
     ///
-    void addCollisionConstraints(PBDCollisionConstraintVector* constraints,
+    void addCollisionConstraints(std::vector<PbdCollisionConstraint*>* constraints,
                                  std::shared_ptr<StdVectorOfVec3d> posA, std::shared_ptr<StdVectorOfReal> invMassA,
                                  std::shared_ptr<StdVectorOfVec3d> posB, std::shared_ptr<StdVectorOfReal> invMassB);
 
@@ -165,9 +155,9 @@ public:
     void solve() override;
 
 private:
-    size_t m_collisionIterations = 5;                                                               ///> Number of NL Gauss-Seidel iterations for collision constraints
+    size_t m_collisionIterations = 5;                                                                   ///> Number of NL Gauss-Seidel iterations for collision constraints
 
-    std::shared_ptr<std::list<PBDCollisionConstraintVector*>> m_collisionConstraints     = nullptr; ///< Collision contraints charged to this solver
-    std::shared_ptr<std::list<CollisionConstraintData>>       m_collisionConstraintsData = nullptr;
+    std::shared_ptr<std::list<std::vector<PbdCollisionConstraint*>*>> m_collisionConstraints = nullptr; ///< Collision contraints charged to this solver
+    std::shared_ptr<std::list<CollisionConstraintData>> m_collisionConstraintsData = nullptr;
 };
 } // imstk
diff --git a/Source/Solvers/imstkProjectedGaussSeidelSolver.h b/Source/Solvers/imstkProjectedGaussSeidelSolver.h
new file mode 100644
index 0000000000000000000000000000000000000000..c833eaa83b35fc72a515b3f0b791a45ac1af354a
--- /dev/null
+++ b/Source/Solvers/imstkProjectedGaussSeidelSolver.h
@@ -0,0 +1,88 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkMath.h"
+
+namespace imstk
+{
+template<typename Scalar>
+class ProjectedGaussSeidelSolver
+{
+public:
+    // Sets the vector to be used for the solve
+    //void setGuess(Matrix<Scalar, -1, 1>& g) { x = g; }
+    void setA(Eigen::SparseMatrix<Scalar>* A) { this->m_A = A; }
+    void setMaxIterations(const unsigned int maxIterations) { this->m_maxIterations = maxIterations; }
+    void setRelaxation(const Scalar relaxation) { this->m_relaxation = relaxation; }
+
+    Eigen::Matrix<Scalar, -1, 1>& solve(const Eigen::Matrix<Scalar, -1, 1>& b, const Eigen::Matrix<Scalar, -1, 2>& cu)
+    {
+        const Eigen::SparseMatrix<Scalar>& A = *m_A;
+
+        // Allocate new results
+        m_x = Eigen::Matrix<Scalar, -1, 1>(b.rows());
+        m_x.setZero();
+
+        // Naive implementation of PGS
+        // Consider graph coloring and TBB parallizing
+        Eigen::Matrix<Scalar, -1, 1> xOld;
+        for (unsigned int i = 0; i < m_maxIterations; i++)
+        {
+            xOld = m_x;
+            for (Eigen::Index r = 0; r < A.rows(); r++)
+            {
+                Scalar delta = 0.0;
+
+                // Sum up rows (skip r)
+                for (Eigen::Index c = 0; c < r; c++)
+                {
+                    delta += A.coeff(r, c) * m_x[c];
+                }
+                for (Eigen::Index c = r + 1; c < A.cols(); c++)
+                {
+                    delta += A.coeff(r, c) * m_x[c];
+                }
+
+                delta = (b[r] - delta) / A.coeff(r, r);
+                // Apply relaxation factor
+                m_x(r) += m_relaxation * (delta - m_x(r));
+                // Do projection *every iteration*
+                m_x(r) = std::min(cu(r, 1), std::max(cu(r, 0), m_x(r)));
+            }
+
+            // Check convergence
+            if ((m_x - xOld).norm() < 1.0e-4)
+            {
+                return m_x;
+            }
+        }
+
+        return m_x;
+    }
+
+private:
+    unsigned int m_maxIterations = 3;
+    Scalar       m_relaxation    = static_cast<Scalar>(0.1);
+    Eigen::Matrix<Scalar, -1, 1> m_x; ///> Results
+    Eigen::SparseMatrix<Scalar>* m_A = nullptr;
+};
+}
\ No newline at end of file
diff --git a/Source/Solvers/imstkSOR.h b/Source/Solvers/imstkSOR.h
index d71a93fd9af8aeea16b06a432ab856f6723d3c0e..88b89b72913523fa3500607ca4e9a7324a2b3d36 100644
--- a/Source/Solvers/imstkSOR.h
+++ b/Source/Solvers/imstkSOR.h
@@ -21,11 +21,9 @@
 
 #pragma once
 
-// iMSTK includes
 #include "imstkNonLinearSystem.h"
 #include "imstkIterativeLinearSolver.h"
 
-// Eigen includes
 #include <Eigen/IterativeLinearSolvers>
 
 namespace imstk
@@ -43,7 +41,7 @@ public:
     ///
     SOR(const double relaxationFactor = 0.5) : m_relaxationFactor(relaxationFactor) { m_type = Type::SuccessiveOverRelaxation; };
     SOR(const SparseMatrixd& A, const Vectord& rhs);
-    ~SOR() = default;
+    virtual ~SOR() override = default;
 
     ///
     /// \brief Remove specific constructor signatures
diff --git a/Source/apiUtilities/imstkAPIUtilities.cpp b/Source/apiUtilities/imstkAPIUtilities.cpp
index 3dcf882c6757e8e78c1157ca62b889715539bc17..6351de87c00b2254d136be152eca23b59fbef77e 100644
--- a/Source/apiUtilities/imstkAPIUtilities.cpp
+++ b/Source/apiUtilities/imstkAPIUtilities.cpp
@@ -19,38 +19,25 @@
 
 =========================================================================*/
 #include "imstkAPIUtilities.h"
+#include "imstkGraph.h"
+#include "imstkLinearProjectionConstraint.h"
+#include "imstkLogger.h"
 
 // Objects
-#include "imstkFEMDeformableBodyModel.h"
-#include "imstkSceneObject.h"
-#include "imstkSceneManager.h"
 #include "imstkCollidingObject.h"
+#include "imstkFEMDeformableBodyModel.h"
 #include "imstkScene.h"
-
-#include "imstkColor.h"
-
-// Solvers
-#include "imstkNonLinearSystem.h"
+#include "imstkSceneManager.h"
 
 // Geometry
-#include "imstkPlane.h"
-#include "imstkSphere.h"
 #include "imstkCapsule.h"
 #include "imstkCube.h"
-#include "imstkPointSet.h"
+#include "imstkImageData.h"
+#include "imstkMeshIO.h"
+#include "imstkPlane.h"
+#include "imstkSphere.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkTetrahedralMesh.h"
-#include "imstkMeshIO.h"
-#include "imstkImageData.h"
-
-#include "imstkGraph.h"
-#include "imstkCollisionGraph.h"
-#include "imstkCamera.h"
-#include "imstkLinearProjectionConstraint.h"
-
-// logger
-#include "imstkLogger.h"
-#include "imstkTimer.h"
 
 namespace imstk
 {
@@ -211,11 +198,13 @@ printUPS(std::shared_ptr<SceneManager> sceneManager)
     }
 
     sceneManager->enableFrameCount();
-    sceneManager->setPostUpdateCallback([&sceneManager](Module* module)
+    // When sceneManager emits PreUpdate, cout the ups
+    connect<Event>(sceneManager, EventType::PreUpdate,
+        [&sceneManager](Event*)
             {
-                std::cout << "\r" << module->getName() << " running at "
+                std::cout << "\r" << sceneManager->getName() << " running at "
                           << sceneManager->getUPS() << " ups   " << std::flush;
-                });
+        });
 }
 
 std::shared_ptr<Graph>
diff --git a/Source/apiUtilities/imstkAPIUtilities.h b/Source/apiUtilities/imstkAPIUtilities.h
index e1ee8ddae31321d422fdc44d08c759925fc603fb..4b15f5cfd9f7f49f3075f21936f90f1f6dbf3597 100644
--- a/Source/apiUtilities/imstkAPIUtilities.h
+++ b/Source/apiUtilities/imstkAPIUtilities.h
@@ -22,32 +22,32 @@
 #pragma once
 
 #include "imstkGeometry.h"
-#include "imstkSceneObject.h"
 #include "imstkMath.h"
 
 namespace imstk
 {
-class TetrahedralMesh;
-class SurfaceMesh;
-class PointSet;
-class SceneManager;
-class Scene;
+class CollidingObject;
 class FEMDeformableBodyModel;
+class Graph;
 template<typename Matrix>
 class NonLinearSystem;
-class CollidingObject;
-class Graph;
+class PointSet;
+class Scene;
+class SceneManager;
+class SceneObject;
+class SurfaceMesh;
+class TetrahedralMesh;
 
 namespace apiutils
 {
 ///
 /// \brief Create a analytical visual scene object that and add it to the scene
 ///
-std::shared_ptr<VisualObject> createVisualAnalyticalSceneObject(Geometry::Type type,
-                                                                std::shared_ptr<Scene> scene,
-                                                                const std::string& objName,
-                                                                const double scale = 1.,
-                                                                const Vec3d t      = Vec3d(0., 0., 0.));
+std::shared_ptr<SceneObject> createVisualAnalyticalSceneObject(Geometry::Type type,
+                                                               std::shared_ptr<Scene> scene,
+                                                               const std::string& objName,
+                                                               const double scale = 1.,
+                                                               const Vec3d t      = Vec3d(0., 0., 0.));
 
 ///
 /// \brief Create a analytical colliding scene object that and add it to the scene
diff --git a/Source/apiUtilities/imstkPlotterUtils.cpp b/Source/apiUtilities/imstkPlotterUtils.cpp
index 28af152b647d667477184d81c08e1bd1c6fe5341..305ac6780b3d7a6cd6723c2149a6d6418f1a0398 100644
--- a/Source/apiUtilities/imstkPlotterUtils.cpp
+++ b/Source/apiUtilities/imstkPlotterUtils.cpp
@@ -18,4 +18,144 @@
    limitations under the License.
 
 =========================================================================*/
-#include "imstkPlotterUtils.h"
\ No newline at end of file
+
+#include "imstkPlotterUtils.h"
+#include "imstkLogger.h"
+
+namespace imstk
+{
+namespace plotterutils
+{
+void
+writePlotterVectorMatlab(Vectord& x, const char* fileName)
+{
+    std::ofstream scriptFile(fileName);
+
+    CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!";
+
+    // print x
+    scriptFile << "X=[\n";
+    for (auto i = 0; i < x.size(); ++i)
+    {
+        scriptFile << x[i] << "\n";
+    }
+    scriptFile << "];\n";
+
+    // plot x
+    scriptFile << "plot(X, 'r-', 'LineWidth', 2, 'MarkerSize', 10);\n";
+    scriptFile.close();
+}
+
+///
+/// \brief Write a Matlab script to plot X vs Y where X, Y are input vectors of same size
+///
+void
+writePlotterVecVsVecMatlab(Vectord& x, Vectord& y, const char* fileName)
+{
+    // check if the vectors are of the same size
+    if (x.size() != y.size())
+    {
+        LOG(WARNING) << "The vectors supplied for plotting are not of same size!";
+        return;
+    }
+
+    std::ofstream scriptFile(fileName);
+
+    CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!";
+
+    // print x
+    scriptFile << "X=[\n";
+    for (auto i = 0; i < x.size(); ++i)
+    {
+        scriptFile << x[i] << "\n";
+    }
+    scriptFile << "];\n";
+
+    // print y
+    scriptFile << "Y=[\n";
+    for (auto i = 0; i < y.size(); ++i)
+    {
+        scriptFile << y[i] << "\n";
+    }
+    scriptFile << "];\n";
+
+    // plot x vs y
+    scriptFile << "plot(X, Y, 'r-', 'LineWidth', 2, 'MarkerSize', 10);\n";
+    scriptFile.close();
+}
+
+///
+/// \brief Write a MatPlotlib script to plot a given vector
+///
+void
+writePlotterVectorMatPlotlib(Vectord& x, const char* fileName)
+{
+    std::ofstream scriptFile(fileName);
+
+    CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!";
+
+    // import
+    scriptFile << "import numpy as np\n";
+    scriptFile << "import matplotlib.pyplot as plt\n";
+
+    // print x
+    scriptFile << "X=[\n";
+    for (auto i = 0; i < x.size(); ++i)
+    {
+        scriptFile << x[i] << ",\n";
+    }
+    scriptFile << "];\n";
+
+    // plot
+    scriptFile << "plt.plot(X, 'ro')\n";
+
+    // show the plot
+    scriptFile << "plt.show()\n";
+}
+
+///
+/// \brief Write a MatPlotlib script to plot \p x vs \p y where \p x, \p y are of same
+/// size
+///
+void
+writePlotterVecVsVecMatPlotlib(Vectord& x, Vectord& y, const char* fileName)
+{
+    // check if the vectors are of the same size
+    if (x.size() != y.size())
+    {
+        LOG(WARNING) << "The vectors supplied for plotting are not of same size!";
+        return;
+    }
+
+    std::ofstream scriptFile(fileName);
+
+    CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!";
+
+    // import
+    scriptFile << "import numpy as np\n";
+    scriptFile << "import matplotlib.pyplot as plt\n";
+
+    // print x
+    scriptFile << "X=[\n";
+    for (auto i = 0; i < x.size(); ++i)
+    {
+        scriptFile << x[i] << ",\n";
+    }
+    scriptFile << "];\n";
+
+    // print y
+    scriptFile << "Y=[\n";
+    for (auto i = 0; i < y.size(); ++i)
+    {
+        scriptFile << y[i] << ",\n";
+    }
+    scriptFile << "];\n";
+
+    // plot
+    scriptFile << "plt.plot(X, Y, 'ro')\n";
+
+    // show the plot
+    scriptFile << "plt.show()\n";
+}
+}
+}
\ No newline at end of file
diff --git a/Source/apiUtilities/imstkPlotterUtils.h b/Source/apiUtilities/imstkPlotterUtils.h
index d592c7665ac3bd65a9395863f709a0e522ce76f6..828a4f28ac27144f7e46a42154a3dc9a45fb2097 100644
--- a/Source/apiUtilities/imstkPlotterUtils.h
+++ b/Source/apiUtilities/imstkPlotterUtils.h
@@ -21,13 +21,7 @@
 
 #pragma once
 
-// STL includes
-#include <iostream>
-#include <fstream>
-
-// imstk
 #include "imstkMath.h"
-#include "imstkLogger.h"
 
 #pragma warning( push )
 #pragma warning( disable : 4505 ) // Warning C4505 will vanish upon calls to the following functions
@@ -38,137 +32,23 @@ namespace plotterutils
 ///
 /// \brief Write a Matlab script to plot a given vector
 ///
-static void
-writePlotterVectorMatlab(Vectord& x, const char* fileName)
-{
-    std::ofstream scriptFile(fileName);
-
-    CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!";
-
-    // print x
-    scriptFile << "X=[\n";
-    for (auto i = 0; i < x.size(); ++i)
-    {
-        scriptFile << x[i] << "\n";
-    }
-    scriptFile << "];\n";
-
-    // plot x
-    scriptFile << "plot(X, 'r-', 'LineWidth', 2, 'MarkerSize', 10);\n";
-    scriptFile.close();
-}
+void writePlotterVectorMatlab(Vectord& x, const char* fileName);
 
 ///
 /// \brief Write a Matlab script to plot X vs Y where X, Y are input vectors of same size
 ///
-static void
-writePlotterVecVsVecMatlab(Vectord& x, Vectord& y, const char* fileName)
-{
-    // check if the vectors are of the same size
-    if (x.size() != y.size())
-    {
-        LOG(WARNING) << "The vectors supplied for plotting are not of same size!";
-        return;
-    }
-
-    std::ofstream scriptFile(fileName);
-
-    CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!";
-
-    // print x
-    scriptFile << "X=[\n";
-    for (auto i = 0; i < x.size(); ++i)
-    {
-        scriptFile << x[i] << "\n";
-    }
-    scriptFile << "];\n";
-
-    // print y
-    scriptFile << "Y=[\n";
-    for (auto i = 0; i < y.size(); ++i)
-    {
-        scriptFile << y[i] << "\n";
-    }
-    scriptFile << "];\n";
-
-    // plot x vs y
-    scriptFile << "plot(X, Y, 'r-', 'LineWidth', 2, 'MarkerSize', 10);\n";
-    scriptFile.close();
-}
+void writePlotterVecVsVecMatlab(Vectord& x, Vectord& y, const char* fileName);
 
 ///
 /// \brief Write a MatPlotlib script to plot a given vector
 ///
-static void
-writePlotterVectorMatPlotlib(Vectord& x, const char* fileName)
-{
-    std::ofstream scriptFile(fileName);
-
-    CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!";
-
-    // import
-    scriptFile << "import numpy as np\n";
-    scriptFile << "import matplotlib.pyplot as plt\n";
-
-    // print x
-    scriptFile << "X=[\n";
-    for (auto i = 0; i < x.size(); ++i)
-    {
-        scriptFile << x[i] << ",\n";
-    }
-    scriptFile << "];\n";
-
-    // plot
-    scriptFile << "plt.plot(X, 'ro')\n";
-
-    // show the plot
-    scriptFile << "plt.show()\n";
-}
+void writePlotterVectorMatPlotlib(Vectord& x, const char* fileName);
 
 ///
 /// \brief Write a MatPlotlib script to plot \p x vs \p y where \p x, \p y are of same
 /// size
 ///
-static void
-writePlotterVecVsVecMatPlotlib(Vectord& x, Vectord& y, const char* fileName)
-{
-    // check if the vectors are of the same size
-    if (x.size() != y.size())
-    {
-        LOG(WARNING) << "The vectors supplied for plotting are not of same size!";
-        return;
-    }
-
-    std::ofstream scriptFile(fileName);
-
-    CHECK(scriptFile.is_open()) << "Unable to create or open the specified file for plot script!";
-
-    // import
-    scriptFile << "import numpy as np\n";
-    scriptFile << "import matplotlib.pyplot as plt\n";
-
-    // print x
-    scriptFile << "X=[\n";
-    for (auto i = 0; i < x.size(); ++i)
-    {
-        scriptFile << x[i] << ",\n";
-    }
-    scriptFile << "];\n";
-
-    // print y
-    scriptFile << "Y=[\n";
-    for (auto i = 0; i < y.size(); ++i)
-    {
-        scriptFile << y[i] << ",\n";
-    }
-    scriptFile << "];\n";
-
-    // plot
-    scriptFile << "plt.plot(X, Y, 'ro')\n";
-
-    // show the plot
-    scriptFile << "plt.show()\n";
-}
+void writePlotterVecVsVecMatPlotlib(Vectord& x, Vectord& y, const char* fileName);
 } // plotters
 } // imstk