diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..29c5e400
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,5 @@
+root = true
+
+[*.{c,cpp,h,hpp}]
+indent_style = space
+indent_size = 2
\ No newline at end of file
diff --git a/Assets/Cube.003.shmesh.shmeta b/Assets/Cube.003.shmesh.shmeta
index d41be546..207f3999 100644
--- a/Assets/Cube.003.shmesh.shmeta
+++ b/Assets/Cube.003.shmesh.shmeta
@@ -1,3 +1,3 @@
 Name: Cube.003
 ID: 110152941
-Type: 
+Type: 6
diff --git a/Assets/Cube.012.shmesh.shmeta b/Assets/Cube.012.shmesh.shmeta
index d5cd1090..3af04f93 100644
--- a/Assets/Cube.012.shmesh.shmeta
+++ b/Assets/Cube.012.shmesh.shmeta
@@ -1,3 +1,3 @@
 Name: Cube.012
 ID: 107348815
-Type: 
+Type: 6
diff --git a/Assets/Editor/Layouts/Default.ini b/Assets/Editor/Layouts/Default.ini
index 4ddc46c2..d7a7bf69 100644
--- a/Assets/Editor/Layouts/Default.ini
+++ b/Assets/Editor/Layouts/Default.ini
@@ -4,13 +4,13 @@ Size=1920,20
 Collapsed=0
 
 [Window][SHEditorMenuBar]
-Pos=0,24
-Size=1920,1036
+Pos=0,48
+Size=1920,1012
 Collapsed=0
 
 [Window][Hierarchy Panel]
-Pos=0,120
-Size=225,940
+Pos=0,197
+Size=308,863
 Collapsed=0
 DockId=0x00000004,0
 
@@ -20,29 +20,96 @@ Size=400,400
 Collapsed=0
 
 [Window][Inspector]
-Pos=1686,24
-Size=234,1036
+Pos=1528,48
+Size=392,1012
 Collapsed=0
 DockId=0x00000006,0
 
 [Window][Profiler]
-Pos=0,24
-Size=225,94
+Pos=0,48
+Size=308,147
 Collapsed=0
 DockId=0x00000003,0
 
 [Window][Viewport]
-Pos=227,24
-Size=1457,1036
+Pos=227,48
+Size=1457,1012
 Collapsed=0
-DockId=0x00000002,0
+DockId=0x0000000B,0
+
+[Window][�������������������������������������������������������������������������������������������������������������������������������������������������������������������o�]
+Pos=60,60
+Size=32,64
+Collapsed=0
+
+[Window][��������������������������������������������������������������������������������������������������������������������������������������������������������������������]
+Pos=60,60
+Size=999,581
+Collapsed=0
+
+[Window][���o�]
+Pos=60,60
+Size=32,64
+Collapsed=0
+
+[Window][����]
+Pos=60,60
+Size=553,422
+Collapsed=0
+
+[Window][]
+Pos=60,60
+Size=770,394
+Collapsed=0
+
+[Window][ Viewport]
+Pos=227,48
+Size=1457,1012
+Collapsed=0
+DockId=0x0000000B,0
+
+[Window][ Viewport]
+Pos=227,48
+Size=1457,1012
+Collapsed=0
+DockId=0x0000000B,0
+
+[Window][ Viewport]
+Pos=310,48
+Size=1216,715
+Collapsed=0
+DockId=0x0000000B,0
+
+[Window][V]
+Pos=310,722
+Size=1501,338
+Collapsed=0
+DockId=0x00000008,0
+
+[Window][p����]
+Pos=310,750
+Size=1501,310
+Collapsed=0
+DockId=0x0000000A,0
+
+[Window][ Asset Browser]
+Pos=310,765
+Size=1216,295
+Collapsed=0
+DockId=0x0000000C,0
 
 [Docking][Data]
-DockSpace       ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,55 Size=1920,1036 Split=X
-  DockNode      ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1684,1036 Split=X
-    DockNode    ID=0x00000001 Parent=0x00000005 SizeRef=225,1036 Split=Y Selected=0x1E6EB881
-      DockNode  ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
-      DockNode  ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
-    DockNode    ID=0x00000002 Parent=0x00000005 SizeRef=1293,1036 CentralNode=1 Selected=0x13926F0B
-  DockNode      ID=0x00000006 Parent=0xC5C9B8AB SizeRef=234,1036 Selected=0xE7039252
+DockSpace           ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
+  DockNode          ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1526,1036 Split=X
+    DockNode        ID=0x00000001 Parent=0x00000005 SizeRef=308,1036 Split=Y Selected=0x1E6EB881
+      DockNode      ID=0x00000003 Parent=0x00000001 SizeRef=225,147 Selected=0x1E6EB881
+      DockNode      ID=0x00000004 Parent=0x00000001 SizeRef=225,863 Selected=0xE096E5AE
+    DockNode        ID=0x00000002 Parent=0x00000005 SizeRef=1216,1036 Split=Y Selected=0xB41284E7
+      DockNode      ID=0x00000007 Parent=0x00000002 SizeRef=1501,672 Split=Y Selected=0xB41284E7
+        DockNode    ID=0x00000009 Parent=0x00000007 SizeRef=1501,700 Split=Y Selected=0xB41284E7
+          DockNode  ID=0x0000000B Parent=0x00000009 SizeRef=1501,715 CentralNode=1 Selected=0xB41284E7
+          DockNode  ID=0x0000000C Parent=0x00000009 SizeRef=1501,295 Selected=0xB128252A
+        DockNode    ID=0x0000000A Parent=0x00000007 SizeRef=1501,310 Selected=0xD446F7B6
+      DockNode      ID=0x00000008 Parent=0x00000002 SizeRef=1501,338 Selected=0xD9F31532
+  DockNode          ID=0x00000006 Parent=0xC5C9B8AB SizeRef=392,1036 Selected=0xE7039252
 
diff --git a/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta b/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta
index f8c267d9..3905aa4f 100644
--- a/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta
+++ b/Assets/RaccoonPreTexturedVer1_Base9.shtex.shmeta
@@ -1,3 +1,3 @@
 Name: RaccoonPreTexturedVer1_Base9
 ID: 91918845
-Type: 
+Type: 4
diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp
index a9f632da..54dc0ccf 100644
--- a/SHADE_Application/src/Application/SBApplication.cpp
+++ b/SHADE_Application/src/Application/SBApplication.cpp
@@ -56,8 +56,8 @@ namespace Sandbox
     _In_      INT       nCmdShow
   )
   {
-	  // Set working directory
-	  SHFileUtilities::SetWorkDirToExecDir();
+    // Set working directory
+    SHFileUtilities::SetWorkDirToExecDir();
 
     window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
 
@@ -83,16 +83,19 @@ namespace Sandbox
     SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::LateUpdateRoutine>();
     SHSystemManager::RegisterRoutine<SHScriptEngine, SHScriptEngine::FrameCleanUpRoutine>();
 
+    SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostLogicUpdate>();
+
     SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
     SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
     SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
 
-    SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformUpdateRoutine>();
+    SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
 
     SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BatcherDispatcherRoutine>();
     SHSystemManager::RegisterRoutine<SHGraphicsSystem, SHGraphicsSystem::BeginRoutine>();
 
     SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::EditorCameraUpdate>();
+    SHSystemManager::RegisterRoutine<SHCameraSystem, SHCameraSystem::CameraSystemUpdate>();
     
 #ifdef SHEDITOR
     SHSystemManager::RegisterRoutine<SHEditor, SHEditor::EditorRoutine>();
@@ -149,16 +152,16 @@ namespace Sandbox
         SHSceneManager::SceneUpdate(0.016f);
 #endif
       SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f);
-      //editor->PollPicking();
+      editor->PollPicking();
     }
     // Finish all graphics jobs first
-	  graphicsSystem->AwaitGraphicsExecution();
+    graphicsSystem->AwaitGraphicsExecution();
   }
 
 
   void SBApplication::Exit(void)
   {
-	#ifdef SHEDITOR
+  #ifdef SHEDITOR
     SDL_DestroyWindow(sdlWindow);
     SDL_Quit();
   #endif
diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp
index 41326174..a06e68c2 100644
--- a/SHADE_Application/src/Scenes/SBTestScene.cpp
+++ b/SHADE_Application/src/Scenes/SBTestScene.cpp
@@ -12,8 +12,10 @@
 #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
 #include "Physics/Components/SHRigidBodyComponent.h"
 #include "Physics/Components/SHColliderComponent.h"
+#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
 
 #include "Assets/SHAssetManager.h"
+#include "Camera/SHCameraComponent.h"
 #include "Resource/SHResourceManager.h"
 
 using namespace SHADE;
@@ -51,7 +53,7 @@ namespace Sandbox
           if (asset.name == "Cube.012")
           handles.emplace_back(SHResourceManager::LoadOrGet<SHMesh>(asset.id));
           break;
-        case AssetType::TEXTURE:
+        case AssetType::IMAGE:
           texHandles.emplace_back(SHResourceManager::LoadOrGet<SHTexture>(asset.id));
           break;
       }
@@ -66,9 +68,9 @@ namespace Sandbox
     customMat->SetProperty("data.alpha", 0.1f);
 
     // Create Stress Test Objects
-    static const SHVec3 TEST_OBJ_SCALE = SHVec3::One * 0.5f;
-    constexpr int NUM_ROWS = 0;
-    constexpr int NUM_COLS = 0;
+    static const SHVec3 TEST_OBJ_SCALE = SHVec3::One;
+    constexpr int NUM_ROWS = 3;
+    constexpr int NUM_COLS = 1;
     static const SHVec3 TEST_OBJ_SPACING = { 0.1f, 0.1f, 0.1f };
     static const SHVec3 TEST_OBJ_START_POS = { -(NUM_COLS / 2 * TEST_OBJ_SPACING.x) + 1.0f, -2.0f, -1.0f };
 
@@ -90,13 +92,13 @@ namespace Sandbox
         //Set initial positions
         transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, y * TEST_OBJ_SPACING.y, SHMath::GenerateRandomNumber(-3.5f, -5.0f) });
         //transform.SetWorldPosition({-1.0f, -1.0f, -1.0f});
-        transform.SetWorldRotation(SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber(), SHMath::GenerateRandomNumber());
+        transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f));
         transform.SetWorldScale(TEST_OBJ_SCALE);
 
-        if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
+        //if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN)
           collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero);
-        else
-          collider.AddBoundingSphere(0.5f, SHVec3::Zero);
+        //else
+        //  collider.AddBoundingSphere(0.5f, SHVec3::Zero);
 
         stressTestObjects.emplace_back(entity);
       }
@@ -155,6 +157,11 @@ namespace Sandbox
     transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f });
     transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f });
     scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase");
+
+    SHComponentManager::AddComponent<SHCameraComponent>(0);
+    SHComponentManager::AddComponent<SHLightComponent>(0);
+    SHComponentManager::RemoveComponent <SHRigidBodyComponent>(0);
+    SHComponentManager::RemoveComponent <SHColliderComponent>(0);
   }
 
   void SBTestScene::Update(float dt)
diff --git a/SHADE_Engine/SHAnimationAsset.h b/SHADE_Engine/SHAnimationAsset.h
new file mode 100644
index 00000000..d8d0ffb1
--- /dev/null
+++ b/SHADE_Engine/SHAnimationAsset.h
@@ -0,0 +1,30 @@
+/*************************************************************************//**
+ * \file    SHAnimationAsset.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+#include <vector>
+#include <assimp/anim.h>
+#include "SH_API.power h"
+
+namespace SHADE
+{
+	struct SH_API SHAnimationAsset
+	{
+		std::string name;
+
+		std::vector<aiNodeAnim*> nodeChannels;
+		std::vector<aiMeshAnim*> meshChannels;
+		std::vector<aiMeshMorphAnim*> morphMeshChannels;
+
+		double duration;
+		double ticksPerSecond;
+	};
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h
new file mode 100644
index 00000000..b411a11e
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h	
@@ -0,0 +1,30 @@
+/*************************************************************************//**
+ * \file    SHAnimationAsset.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+#include <vector>
+#include <assimp/anim.h>
+#include "SHAssetData.h"
+
+namespace SHADE
+{
+	struct SH_API SHAnimationAsset : SHAssetData
+	{
+		std::string name;
+
+		std::vector<aiNodeAnim*> nodeChannels;
+		std::vector<aiMeshAnim*> meshChannels;
+		std::vector<aiMeshMorphAnim*> morphMeshChannels;
+
+		double duration;
+		double ticksPerSecond;
+	};
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAssetData.h b/SHADE_Engine/src/Assets/Asset Types/SHAssetData.h
new file mode 100644
index 00000000..8db9824c
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Asset Types/SHAssetData.h	
@@ -0,0 +1,19 @@
+/*************************************************************************//**
+ * \file    SHAssetDataBase.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+namespace SHADE
+{
+	struct SHAssetData
+	{
+		virtual ~SHAssetData(){}
+	};
+}
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAssetIncludes.h b/SHADE_Engine/src/Assets/Asset Types/SHAssetIncludes.h
new file mode 100644
index 00000000..1c1ed44a
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Asset Types/SHAssetIncludes.h	
@@ -0,0 +1,4 @@
+#pragma once
+
+#include "SHMeshAsset.h"
+#include "SHTextureAsset.h"
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHInternalAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHInternalAsset.h
new file mode 100644
index 00000000..8bef34e9
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Asset Types/SHInternalAsset.h	
@@ -0,0 +1,21 @@
+/*************************************************************************//**
+ * \file    SHInternalAsset.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+#include "SHAsset.h"
+
+namespace SHADE
+{
+	struct SHInternalAsset : SHAsset
+	{
+		
+	};
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h
index 68c0d150..20b442ba 100644
--- a/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h	
+++ b/SHADE_Engine/src/Assets/Asset Types/SHMeshAsset.h	
@@ -14,7 +14,7 @@
 
 #include <vector>
 #include "Math/SHMath.h"
-#include "SH_API.h"
+#include "SHAssetData.h"
 
 namespace SHADE
 {
@@ -22,10 +22,10 @@ namespace SHADE
 	{
 		uint32_t vertexCount;
 		uint32_t indexCount;
-		std::string meshName;
+		std::string name;
 	};
 
-	struct SH_API SHMeshAsset
+	struct SH_API SHMeshAsset : SHAssetData
 	{
 		bool compiled;
 		bool changed;
diff --git a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h
index d24b6c02..d26a2c30 100644
--- a/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h	
+++ b/SHADE_Engine/src/Assets/Asset Types/SHTextureAsset.h	
@@ -2,10 +2,11 @@
 
 #include "tinyddsloader.h"
 #include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h"
+#include "SHAssetData.h"
 
 namespace SHADE
 {
-	struct SHTextureAsset
+	struct SHTextureAsset : SHAssetData
 	{
 		bool compiled;
 
diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h b/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h
new file mode 100644
index 00000000..41595519
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Libraries/SHAssetLoader.h
@@ -0,0 +1,21 @@
+/*************************************************************************//**
+ * \file    SHAssetLoader.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#pragma once
+
+#include "Assets/Asset Types/SHAssetData.h"
+
+namespace SHADE
+{
+	struct SHAssetLoader
+	{
+		virtual SHAssetData* Load(AssetPath path) = 0;
+	};
+}
diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp
new file mode 100644
index 00000000..f4be0b68
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp
@@ -0,0 +1,141 @@
+/*************************************************************************//**
+ * \file    SHAssimpLibrary.cpp
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+#include "SHpch.h"
+#include "SHAssimpLibrary.h"
+#include <assimp/postprocess.h>
+
+namespace SHADE
+{
+	Assimp::Importer SHAssimpLibrary::aiImporter;
+
+	void SHAssimpLibrary::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept
+	{
+    for (size_t i {0}; i < node.mNumMeshes; ++i)
+    {
+      aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
+      meshes.push_back(ProcessMesh(*mesh));
+    }
+
+    for (size_t i{ 0 }; i < node.mNumChildren; ++i)
+    {
+      ProcessNode(*node.mChildren[i], scene, meshes);
+    }
+	}
+
+	void SHAssimpLibrary::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept
+	{
+		if (scene.HasAnimations())
+    {
+			std::vector<SHAnimationAsset> anims(scene.mNumAnimations);
+	    for (auto i{0}; i < scene.mNumAnimations; ++i)
+	    {
+		    auto const& anim {*scene.mAnimations[i]};
+
+        anims[i].name = anim.mName.C_Str();
+
+        anims[i].duration = anim.mDuration;
+        anims[i].ticksPerSecond = anim.mTicksPerSecond;
+
+        std::copy_n(anim.mChannels, anim.mNumChannels, anims[i].nodeChannels.data());
+        std::copy_n(anim.mMeshChannels, anim.mNumMeshChannels, anims[i].meshChannels.data());
+        std::copy_n(anim.mMorphMeshChannels, anim.mNumMorphMeshChannels, anims[i].morphMeshChannels.data());
+	    }
+    }
+	}
+
+	SHMeshAsset* SHAssimpLibrary::ProcessMesh(aiMesh const& mesh) noexcept
+	{
+    SHMeshAsset* result = new SHMeshAsset();
+    result->compiled = false;
+    result->changed = false;
+
+    for (size_t i{0}; i < mesh.mNumVertices; ++i)
+    {
+      // Vertex position
+      SHVec3 vertex;
+      vertex.x = mesh.mVertices[i].x;
+      vertex.y = mesh.mVertices[i].y;
+      vertex.z = mesh.mVertices[i].z;
+      result->vertexPosition.push_back(vertex);
+
+      // Tex coords
+      SHVec2 texCoord{0.f, 0.f};
+      if (mesh.mTextureCoords[0])
+      {
+        texCoord.x = mesh.mTextureCoords[0][i].x;
+        texCoord.y = mesh.mTextureCoords[0][i].y;
+      }
+      result->texCoords.push_back(texCoord);
+
+      // Normals
+      SHVec3 normal{0.f, 0.f, 0.f};
+      if (mesh.mNormals)
+      {
+        normal.x = mesh.mNormals[i].x;
+        normal.y = mesh.mNormals[i].y;
+        normal.z = mesh.mNormals[i].z;
+      }
+      result->vertexNormal.push_back(normal);
+
+      // Tangent
+      SHVec3 tangent{0.f, 0.f, 0.f};
+      if (mesh.mTangents)
+      {
+        tangent.x = mesh.mTangents[i].x;
+        tangent.y = mesh.mTangents[i].y;
+        tangent.z = mesh.mTangents[i].z;
+      }
+      result->vertexTangent.push_back(tangent);
+    }
+
+    for (size_t i {0}; i < mesh.mNumFaces; ++i)
+    {
+      aiFace face = mesh.mFaces[i];
+      for (size_t j{0}; j < face.mNumIndices; ++j)
+      {
+        result->indices.push_back(face.mIndices[j]);
+      }
+    }
+
+    result->header.vertexCount = static_cast<uint32_t>(result->vertexPosition.size());
+    result->header.indexCount = static_cast<uint32_t>(result->indices.size());
+    result->header.name = mesh.mName.C_Str();
+
+    return result;
+	}
+
+	void SHAssimpLibrary::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept
+	{
+    const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
+      aiProcess_Triangulate                 // Make sure we get triangles rather than nvert polygons
+      | aiProcess_GenUVCoords               // Convert any type of mapping to uv mapping
+      | aiProcess_TransformUVCoords         // preprocess UV transformations (scaling, translation ...)
+      | aiProcess_FindInstances             // search for instanced meshes and remove them by references to one master
+      | aiProcess_CalcTangentSpace          // calculate tangents and bitangents if possible
+      | aiProcess_JoinIdenticalVertices     // join identical vertices/ optimize indexing
+      | aiProcess_RemoveRedundantMaterials  // remove redundant materials
+      | aiProcess_FindInvalidData           // detect invalid model data, such as invalid normal vectors
+      | aiProcess_FlipUVs                   // flip the V to match the Vulkans way of doing UVs
+    );
+
+    if (!scene || !scene->HasMeshes())
+    {
+      SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string());
+      return;
+    }
+
+    ExtractAnimations(*scene, anims);
+
+    ProcessNode(*scene->mRootNode, *scene, meshes);
+
+    aiImporter.FreeScene();
+	}
+}
diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h
new file mode 100644
index 00000000..83755b4c
--- /dev/null
+++ b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h
@@ -0,0 +1,36 @@
+/*************************************************************************//**
+ * \file    SHAssimpLibrary.h
+ * \author  Loh Xiao Qi
+ * \date    October 2022
+ * \brief    
+ *
+ * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
+ * disclosure of this file or its contents without the prior written consent
+ * of DigiPen Institute of Technology is prohibited.
+ *****************************************************************************/
+
+#pragma once
+#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
+#include <vector>
+#include "../SHAssetMacros.h"
+#include "../Asset Types/SHMeshAsset.h"
+#include "../Asset Types/SHAnimationAsset.h"
+
+namespace SHADE
+{
+	class SHAssimpLibrary
+	{
+	private:
+		using MeshVectorRef = std::vector<SHMeshAsset*>&;
+		using AnimVectorRef = std::vector<SHAnimationAsset*>&;
+
+		static Assimp::Importer aiImporter;
+		static void ProcessNode(aiNode const& node, aiScene const& scene,MeshVectorRef meshes) noexcept;
+		static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept;
+		static SHMeshAsset* ProcessMesh(aiMesh const& mesh) noexcept;
+
+	public:
+		static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept;
+	};
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp
index 8026f0e1..2346714e 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp
+++ b/SHADE_Engine/src/Assets/Libraries/SHMeshCompiler.cpp
@@ -20,7 +20,7 @@ std::string SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, A
 {
 	std::string newPath{ path.string() };
 	newPath = newPath.substr(0, newPath.find_last_of('/') + 1);
-	newPath += asset.header.meshName + MESH_EXTENSION;
+	newPath += asset.header.name + MESH_EXTENSION.data();
 
 	std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
 	if (!file.is_open())
diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp
index 4bfa2d9b..90dd58d4 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp
+++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp
@@ -12,129 +12,11 @@
  *****************************************************************************/
 #include "SHpch.h"
 #include "SHMeshLoader.h"
-#include <assimp/postprocess.h>
 #include <fstream>
 
 namespace SHADE
 {
-	Assimp::Importer SHMeshLoader::aiImporter;
-
-	void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept
-	{
-    for (size_t i {0}; i < node.mNumMeshes; ++i)
-    {
-      aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
-      meshes.push_back(ProcessMesh(*mesh, scene));
-    }
-
-    for (size_t i{ 0 }; i < node.mNumChildren; ++i)
-    {
-      ProcessNode(*node.mChildren[i], scene, meshes);
-    }
-	}
-
-	SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept
-	{
-    (void)scene;
-
-    SHMeshAsset result
-    {
-      .compiled { false},
-      .changed { false }
-    };
-
-    for (size_t i{0}; i < mesh.mNumVertices; ++i)
-    {
-      // Vertex position
-      SHVec3 vertex;
-      vertex.x = mesh.mVertices[i].x;
-      vertex.y = mesh.mVertices[i].y;
-      vertex.z = mesh.mVertices[i].z;
-      result.vertexPosition.push_back(vertex);
-
-      // Tex coords
-      SHVec2 texCoord{0.f, 0.f};
-      if (mesh.mTextureCoords[0])
-      {
-        texCoord.x = mesh.mTextureCoords[0][i].x;
-        texCoord.y = mesh.mTextureCoords[0][i].y;
-      }
-      result.texCoords.push_back(texCoord);
-
-      // Normals
-      SHVec3 normal{0.f, 0.f, 0.f};
-      if (mesh.mNormals)
-      {
-        normal.x = mesh.mNormals[i].x;
-        normal.y = mesh.mNormals[i].y;
-        normal.z = mesh.mNormals[i].z;
-      }
-      result.vertexNormal.push_back(normal);
-
-      // Tangent
-      SHVec3 tangent{0.f, 0.f, 0.f};
-      if (mesh.mTangents)
-      {
-        tangent.x = mesh.mTangents[i].x;
-        tangent.y = mesh.mTangents[i].y;
-        tangent.z = mesh.mTangents[i].z;
-      }
-      result.vertexTangent.push_back(tangent);
-    }
-
-    for (size_t i {0}; i < mesh.mNumFaces; ++i)
-    {
-      aiFace face = mesh.mFaces[i];
-      for (size_t j{0}; j < face.mNumIndices; ++j)
-      {
-        result.indices.push_back(face.mIndices[j]);
-      }
-    }
-
-    result.header.vertexCount = static_cast<uint32_t>(result.vertexPosition.size());
-    result.header.indexCount = static_cast<uint32_t>(result.indices.size());
-    result.header.meshName = mesh.mName.C_Str();
-
-    return result;
-	}
-
-	void SHMeshLoader::LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
-	{
-    const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
-      aiProcess_Triangulate                 // Make sure we get triangles rather than nvert polygons
-      | aiProcess_GenUVCoords               // Convert any type of mapping to uv mapping
-      | aiProcess_TransformUVCoords         // preprocess UV transformations (scaling, translation ...)
-      | aiProcess_FindInstances             // search for instanced meshes and remove them by references to one master
-      | aiProcess_CalcTangentSpace          // calculate tangents and bitangents if possible
-      | aiProcess_JoinIdenticalVertices     // join identical vertices/ optimize indexing
-      | aiProcess_RemoveRedundantMaterials  // remove redundant materials
-      | aiProcess_FindInvalidData           // detect invalid model data, such as invalid normal vectors
-      | aiProcess_FlipUVs                   // flip the V to match the Vulkans way of doing UVs
-    );
-
-    if (!scene || !scene->HasMeshes())
-    {
-      SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string());
-      return;
-    }
-
-    //TODO MATERIALS FROM MESHES
-    //if (scene->HasMaterials())
-    //{
-    //  for (int i{0}; i < scene->mNumMaterials; ++i)
-    //  {
-    //    if (scene->mMaterials[i]->mNumProperties > 0)
-    //    {
-     //     for (int j{0}; j < scene->mMaterials[i]->mProperties[j].)
-    //    }
-        //std::cout << scene->mMaterials[i]->;
-    //  }
-    //}
-
-    ProcessNode(*scene->mRootNode, *scene, meshes);
-	}
-
-	void SHMeshLoader::LoadSHMesh(SHMeshAsset& mesh, AssetPath path) noexcept
+	void SHMeshLoader::LoadSHMesh(AssetPath path, SHMeshAsset& mesh) noexcept
 	{
     std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
     if (!file.is_open())
@@ -168,45 +50,13 @@ namespace SHADE
     file.read(reinterpret_cast<char *>(vertNorm.data()), vertexVec3Byte);
     file.read(reinterpret_cast<char *>(texCoord.data()), vertexVec2Byte);
     file.read(reinterpret_cast<char *>(indices.data()), sizeof(uint32_t) * indexCount);
-    
-    //for (auto i{ 0 }; i < vertCount; ++i)
-    //{
-    //  file >> vertPos[i].x;
-    //  file >> vertPos[i].y;
-    //  file >> vertPos[i].z;
-    //}
-    //
-    //for (auto i{ 0 }; i < vertCount; ++i)
-    //{
-    //  file >> vertTan[i].x;
-    //  file >> vertTan[i].y;
-    //  file >> vertTan[i].z;
-    //}
-
-    //for (auto i{ 0 }; i < vertCount; ++i)
-    //{
-    //  file >> vertNorm[i].x;
-    //  file >> vertNorm[i].y;
-    //  file >> vertNorm[i].z;
-    //}
-
-    //for (auto i{ 0 }; i < vertCount; ++i)
-    //{
-    //  file >> texCoord[i].x;
-    //  file >> texCoord[i].y;
-    //}
-
-    //for (auto i{ 0 }; i < indexCount; ++i)
-    //{
-    //  file >> indices[i];
-    //}
 
     mesh.compiled = true;
     mesh.changed  = false;
 
     mesh.header.indexCount  = indexCount;
     mesh.header.vertexCount = vertCount;
-    mesh.header.meshName    = name;
+    mesh.header.name = name;
 
     mesh.vertexPosition = std::move(vertPos);
     mesh.vertexTangent  = std::move(vertTan);
@@ -217,15 +67,12 @@ namespace SHADE
     file.close();
 	}
 
-	void SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept
-  {
-    if (path.extension().string() == GLTF_EXTENSION)
-    {
-      LoadExternal(meshes, path);
-      return;
-    }
+	SHAssetData* SHMeshLoader::Load(AssetPath path)
+	{
+    auto result = new SHMeshAsset();
 
-    meshes.emplace_back();
-    LoadSHMesh(meshes.back(), path);
+    LoadSHMesh(path, *result);
+
+    return result;
 	}
 }
diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h
index a27d63ea..34c4e5d2 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h
+++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h
@@ -10,27 +10,15 @@
  * of DigiPen Institute of Technology is prohibited.
  *****************************************************************************/
 #pragma once
-#include <assimp/Importer.hpp>
-#include <assimp/scene.h>
 #include "../SHAssetMacros.h"
 #include "../Asset Types/SHMeshAsset.h"
-#include <vector>
+#include "SHAssetLoader.h"
 
 namespace SHADE
 {
-	class SHMeshLoader
+	struct SHMeshLoader : public SHAssetLoader
 	{
-	private:
-		static Assimp::Importer aiImporter;
-
-		static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes) noexcept;
-
-		static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept;
-
-		static void LoadExternal(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
-
-	public:
-		static void LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path) noexcept;
-		static void LoadSHMesh(SHMeshAsset& meshes, AssetPath path) noexcept;
+		void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept;
+		SHAssetData* Load(AssetPath path) override;
 	};
 }
\ No newline at end of file
diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp
index 5147562a..8b986524 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp
+++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.cpp
@@ -133,6 +133,15 @@ namespace SHADE
 		file.close();
 	}
 
+	SHAssetData* SHTextureLoader::Load(AssetPath path)
+	{
+		auto result = new SHTextureAsset();
+
+		LoadImageAsset(path, *result);
+
+		return result;
+	}
+
 	void SHTextureLoader::LoadImageAsset(AssetPath path, SHTextureAsset& asset)
 	{
 		if (path.extension().string() == DDS_EXTENSION)
diff --git a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h
index eb61ea91..8bdf91b1 100644
--- a/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h
+++ b/SHADE_Engine/src/Assets/Libraries/SHTextureLoader.h
@@ -15,19 +15,20 @@
 #include "../SHAssetMacros.h"
 #include "../Asset Types/SHTextureAsset.h"
 #include "tinyddsloader.h"
+#include "SHAssetLoader.h"
 
 namespace SHADE
 {
-	class SHTextureLoader
+	class SHTextureLoader : public SHAssetLoader
 	{
 	private:
-		static std::string TinyDDSResultToString(tinyddsloader::Result value);
-		static vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
-
-
-		static void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
+		std::string TinyDDSResultToString(tinyddsloader::Result value);
+		vk::Format ddsLoaderToVkFormat(tinyddsloader::DDSFile::DXGIFormat format, bool isLinear);
+		
+		void LoadTinyDDS(AssetPath path, SHTextureAsset& asset) noexcept;
 	public:
-		static void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
-		static void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
+		void LoadImageAsset(AssetPath paths, SHTextureAsset& image);
+		void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
+		SHAssetData* Load(AssetPath path) override;
 	};
 }
diff --git a/SHADE_Engine/src/Assets/SHAsset.h b/SHADE_Engine/src/Assets/SHAsset.h
index 8d7b55d1..86e8a722 100644
--- a/SHADE_Engine/src/Assets/SHAsset.h
+++ b/SHADE_Engine/src/Assets/SHAsset.h
@@ -12,11 +12,12 @@
 #pragma once
 
 #include "Filesystem/SHFileSystem.h"
-#include "SHAssetMacros.h"
+#include "Assets/SHAssetMacros.h"
+#include "SH_API.h"
 
 namespace SHADE
 {
-	struct SHAsset
+	struct SH_API SHAsset
 	{
 		AssetName name;
 		AssetID id;
diff --git a/SHADE_Engine/src/Assets/SHAssetMacros.h b/SHADE_Engine/src/Assets/SHAssetMacros.h
index 61c5879d..0fdfa04e 100644
--- a/SHADE_Engine/src/Assets/SHAssetMacros.h
+++ b/SHADE_Engine/src/Assets/SHAssetMacros.h
@@ -32,12 +32,12 @@ typedef std::filesystem::path AssetPath;
 typedef unsigned char*				AssetData;
 typedef std::string						AssetMetaVersion;
 typedef std::string						AssetExtension;
-typedef unsigned char					AssetTypeMeta;
+typedef size_t					AssetTypeMeta;
 
 typedef FMOD::Sound*					SHSound;
 
 // Asset Meta Version
-#define ASSET_META_VER "1.0"
+constexpr std::string_view ASSET_META_VER { "1.0" };
 
 // Asset type enum
 enum class AssetType : AssetTypeMeta
@@ -53,34 +53,35 @@ enum class AssetType : AssetTypeMeta
 	SCENE,
 	PREFAB,
 	AUDIO_WAV,
-	DDS
+	DDS,
+	MAX_COUNT
 };
 
 //Directory
 #ifdef _PUBLISH
-#define ASSET_ROOT "Assets"
+constexpr std::string_view ASSET_ROOT {"Assets"};
 #else
-#define ASSET_ROOT "../../Assets"
+constexpr std::string_view ASSET_ROOT {"../../Assets"};
 #endif
 
 
 // ASSET EXTENSIONS
-#define META_EXTENSION ".shmeta"
-#define IMAGE_EXTENSION ".png"
-#define AUDIO_EXTENSION ".ogg"
-#define AUDIO_WAV_EXTENSION ".wav"
-#define SHADER_EXTENSION ".glsl"
-#define SCRIPT_EXTENSION ".cs"
-#define SCENE_EXTENSION ".SHADE"
-#define PREFAB_EXTENSION ".SHPrefab"
-#define MATERIAL_EXTENSION ".SHMat"
-#define TEXTURE_EXTENSION ".shtex"
-#define DDS_EXTENSION ".dds"
-#define FBX_EXTENSION ".fbx"
-#define GLTF_EXTENSION ".gltf"
-#define MESH_EXTENSION ".shmesh"
+constexpr std::string_view META_EXTENSION {".shmeta"};
+constexpr std::string_view IMAGE_EXTENSION {".png"};
+constexpr std::string_view AUDIO_EXTENSION {".ogg"};
+constexpr std::string_view AUDIO_WAV_EXTENSION {".wav"};
+constexpr std::string_view SHADER_EXTENSION {".glsl"};
+constexpr std::string_view SCRIPT_EXTENSION {".cs"};
+constexpr std::string_view SCENE_EXTENSION {".SHADE"};
+constexpr std::string_view PREFAB_EXTENSION {".SHPrefab"};
+constexpr std::string_view MATERIAL_EXTENSION {".SHMat"};
+constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
+constexpr std::string_view DDS_EXTENSION {".dds"};
+constexpr std::string_view FBX_EXTENSION {".fbx"};
+constexpr std::string_view GLTF_EXTENSION {".gltf"};
+constexpr std::string_view MESH_EXTENSION {".shmesh"};
 
-std::string const EXTENSIONS[] = {
+constexpr std::string_view EXTENSIONS[] = {
 	AUDIO_EXTENSION,
 	SHADER_EXTENSION,
 	MATERIAL_EXTENSION,
@@ -96,10 +97,12 @@ std::string const EXTENSIONS[] = {
 	GLTF_EXTENSION
 };
 
+constexpr size_t TYPE_COUNT {static_cast<size_t>(AssetType::MAX_COUNT) };
+
 // Error flags
-#define FILE_NOT_FOUND_ERR "FILE NOT FOUND"
-#define META_NOT_FOUND_ERR "META NOT FOUND"
-#define ASSET_NOT_FOUND_ERR "ASSET NOT FOUND"
-#define EXT_DOES_NOT_EXIST "TYPE DOES NOT HAVE EXTENSION DEFINED"
+constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"};
+constexpr std::string_view META_NOT_FOUND_ERR {"META NOT FOUND"};
+constexpr std::string_view ASSET_NOT_FOUND_ERR {"ASSET NOT FOUND"};
+constexpr std::string_view EXT_DOES_NOT_EXIST {"TYPE DOES NOT HAVE EXTENSION DEFINED"};
 
 #endif // !SH_ASSET_MACROS_H
diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp
index 956d52e8..3032ba51 100644
--- a/SHADE_Engine/src/Assets/SHAssetManager.cpp
+++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp
@@ -14,6 +14,7 @@
 #include "SHAssetMetaHandler.h"
 #include "Filesystem/SHFileSystem.h"
 
+#include "Libraries/SHAssimpLibrary.h"
 #include "Libraries/SHMeshLoader.h"
 #include "Libraries/SHTextureLoader.h"
 
@@ -25,11 +26,10 @@ namespace SHADE
 	FMOD::System* SHAssetManager::audioSystem;
 	std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList;
 
-	std::vector<SHAsset> SHAssetManager::assetCollection;
-	std::unordered_map<AssetID, SHAsset> SHAssetManager::assetRegistry;
+	std::vector<SHAssetLoader*> SHAssetManager::loaders(TYPE_COUNT);
 
-	std::unordered_map<AssetID, SHMeshAsset> SHAssetManager::meshCollection;
-	std::unordered_map<AssetID, SHTextureAsset> SHAssetManager::textureCollection;
+	std::vector<SHAsset> SHAssetManager::assetCollection;
+	std::unordered_map<AssetID, SHAssetData * const> SHAssetManager::assetData;
 
 	/****************************************************************************
 	 * \brief   Static function to generate asset ID.
@@ -56,18 +56,15 @@ namespace SHADE
 	****************************************************************************/
 	void SHAssetManager::Unload() noexcept
 	{
-		for (auto const& asset : assetCollection)
-		{
-			SHAssetMetaHandler::WriteMetaData(asset);
-		}
+
 	}
 
-    void SHAssetManager::Unload(AssetID assetId) noexcept
-    {
-		// TODO
-    }
+	void SHAssetManager::Unload(AssetID assetId) noexcept
+	{
+	// TODO
+	}
 
-    AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
+		AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
 	{
 		if (!IsRecognised(path.extension().string().c_str()))
 		{
@@ -85,7 +82,37 @@ namespace SHADE
 		//	return std::filesystem::path();
 		//}
 
-		return std::filesystem::path(ASSET_ROOT + folder + path.filename().string());
+		return std::filesystem::path(std::string(ASSET_ROOT) + folder + path.filename().string());
+	}
+
+	AssetPath SHAssetManager::GenerateNewPath(AssetName name, AssetType type)
+	{
+		std::string folder;
+
+		switch(type)
+		{
+		case AssetType::SCENE:
+			folder = "scenes/";
+			break;
+
+		case AssetType::PREFAB:
+			folder = "prefabs/";
+			break;
+
+		case AssetType::MATERIAL:
+			folder = "materials/";
+			break;
+
+		default:
+			folder = "/";
+		}
+
+		return std::filesystem::path{
+			std::string(ASSET_ROOT) + 
+			folder + 
+			name + 
+			std::string(EXTENSIONS[static_cast<size_t>(type)])
+		};
 	}
 
 	/****************************************************************************
@@ -121,7 +148,7 @@ namespace SHADE
 		//	folder = "";
 		//	break;
 		//}
-		AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
+		AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
 
 		SHAssetMetaHandler::WriteMetaData(meta);
 
@@ -130,6 +157,19 @@ namespace SHADE
 		return id;
 	}
 
+	AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept
+	{
+			AssetID id = GenerateAssetID(type);
+
+			assetCollection.emplace_back(
+				name,
+				id,
+				type,
+				GenerateNewPath(name, type),
+				0
+			); 
+			return id;
+		}
 	/****************************************************************************
 	 * \brief Import new asset from outside editor window.
 	 *
@@ -138,7 +178,10 @@ namespace SHADE
 	****************************************************************************/
 	AssetID SHAssetManager::ImportNewAsset(char const* p) noexcept
 	{
-		 std::filesystem::path const path{ p };
+		std::filesystem::path const path{ p };
+
+		auto const type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
+		auto const id = GenerateAssetID(type);
 
 		std::filesystem::path const newPath{ GenerateLocalPath(path) };
 		if (newPath.empty())
@@ -149,11 +192,7 @@ namespace SHADE
 
 		std::filesystem::copy(path, newPath);
 
-		AssetID id{ RetrieveAsset(newPath.string().c_str()) };
-		if (id != 0)
-		{
-			LoadData(id);
-		}
+		assetCollection.push_back(CreateAssetFromPath(newPath));
 
 		return id;
 	}
@@ -164,158 +203,14 @@ namespace SHADE
 	****************************************************************************/
 	void SHAssetManager::RefreshAllAssets() noexcept
 	{
-		std::vector<AssetPath> metaFiles;
-		std::vector<AssetPath> AssetFiles;
 
-		//SHFileSystem::LoadAllFiles(metaFiles, AssetFiles);
-		//std::vector<AssetPath> AssetFilesVerified;
-		std::vector<AssetPath> AssetFilesNew;
-
-		for (auto const& asset : AssetFiles)
-		{
-			bool found = false;
-		  for (auto it {metaFiles.begin()}; it != metaFiles.end(); ++it)
-		  {
-				std::string fileExtCheck{ asset.filename().string() };
-				fileExtCheck += META_EXTENSION;
-				if (it->filename().string() == fileExtCheck)
-				{
-					metaFiles.erase(it);
-					found = true;
-					break;
-				}
-		  }
-
-			if (!found && IsRecognised(asset.extension().string().c_str()))
-			{
-				AssetFilesNew.push_back(asset);
-			}
-		}
-
-		std::vector<SHAsset> newLoad;
-		newLoad.reserve(AssetFilesNew.size());
-
-		//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
-		for (auto const& file : AssetFilesNew)
-		{
-			newLoad.push_back(RegisterAssetNew(file));
-		}
-
-    //UpdateAllSpriteSets();
-
-	}
-
-	void SHAssetManager::LoadDataTemp(std::string p) noexcept
-	{
-		AssetPath path{ p };
-
-		if (path.extension().string() == FBX_EXTENSION
-			|| path.extension().string() == GLTF_EXTENSION
-			|| path.extension().string() == MESH_EXTENSION)
-		{
-			LoadGLTF(
-				{
-					.name {path.filename().string()},
-					.id {0},
-					.type {AssetType::MESH},
-					.path {path},
-					.location {0}
-				}
-			);
-		}
-		else if (path.extension().string() == DDS_EXTENSION
-			|| path.extension().string() == TEXTURE_EXTENSION)
-		{
-			LoadDDS(
-				{
-					.name {path.filename().string()},
-					.id {0},
-					.type {AssetType::DDS},
-					.path {path},
-					.location {0}
-				}
-			);
-		}
-	}
-
-	std::vector<SHMeshAsset> SHAssetManager::GetAllMeshes() noexcept
-	{
-		std::vector<SHMeshAsset> result;
-		for (auto const& mesh : meshCollection)
-		{
-			result.push_back(mesh.second);
-		}
-
-		return result;
-	}
-
-	std::vector<SHTextureAsset> SHAssetManager::GetAllTextures() noexcept
-	{
-		std::vector<SHTextureAsset> result;
-		for (auto const& dds : textureCollection)
-		{
-			result.push_back(dds.second);
-		}
-
-		return result;
-	}
-
-	SHMeshAsset const* SHAssetManager::GetMesh(AssetID id) noexcept
-	{
-		if (meshCollection.find(id) == meshCollection.end())
-		{
-			return nullptr;
-		}
-
-		return &meshCollection[id];
-	}
-
-	SHTextureAsset const* SHAssetManager::GetTexture(AssetID id) noexcept
-	{
-		if (textureCollection.find(id) == textureCollection.end())
-		{
-			return nullptr;
-		}
-
-		return &textureCollection[id];
-	}
-
-	/****************************************************************************
-	 * \param   Path for meta data file
-	 * \param   Path for asset file
-
-	 * \brief   Links meta data to asset in registries. Meta data should
-	 *					already exist
-	****************************************************************************/
-	void SHAssetManager::RegisterAsset(AssetPath const& metaPath, AssetPath const& path) noexcept
-	{
-		SHAsset const meta = SHAssetMetaHandler::RetrieveMetaData(metaPath);
-
-		assetCollection.push_back(meta);
-	}
-
-	/****************************************************************************
-	 * \param   Path for asset file
-
-	 * \brief   Creates new meta data for new asset.
-	****************************************************************************/
-	SHAsset SHAssetManager::RegisterAssetNew(AssetPath const& asset) noexcept
-	{
-		SHAsset meta;
-		meta.type = SHAssetMetaHandler::GetTypeFromExtension(asset.extension().string());
-		meta.id = GenerateAssetID(meta.type);
-
-		assetCollection.push_back(meta);
-
-		SHAssetMetaHandler::WriteMetaData(meta);
-		return assetCollection.back();
 	}
 
 	bool SHAssetManager::IsRecognised(char const* ext) noexcept
 	{
 		for (auto const& e : EXTENSIONS)
 		{
-			if (strcmp(ext, e.c_str()) == 0)
+			if (strcmp(ext, e.data()) == 0)
 			{
 				return true;
 			}
@@ -324,54 +219,31 @@ namespace SHADE
 		return false;
 	}
 
-	void SHAssetManager::LoadGLTF(SHAsset asset) noexcept
+	SHAsset SHAssetManager::CreateAssetFromPath(AssetPath path) noexcept
 	{
-		std::vector<SHMeshAsset> meshes;
+		SHAsset result;
 
-		SHMeshLoader::LoadMesh(meshes, asset.path);
+		result.name = path.stem().string();
+		result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
+		result.id = GenerateAssetID(result.type);
+		result.path = path;
 
-		for (auto const& mesh : meshes)
-		{
-			auto id{ GenerateAssetID(AssetType::MESH) };
-			meshCollection.emplace(id, mesh);
-
-			AssetPath path;
-			if (!mesh.compiled)
-			{
-				path = SHMeshCompiler::CompileMeshBinary(mesh, asset.path);
-			}
-			
-			assetCollection.emplace_back(
-				mesh.header.meshName,
-				id,
-				AssetType::MESH,
-				path,
-				0
-			);
-		}
+		return result;
 	}
 
-	void SHAssetManager::LoadDDS(SHAsset asset) noexcept
+	void SHAssetManager::InitLoaders() noexcept
 	{
-		SHTextureAsset image;
-
-		SHTextureLoader::LoadImageAsset(asset.path, image);
-
-		if (!image.compiled)
-		{
-			auto id{ GenerateAssetID(AssetType::TEXTURE) };
-			textureCollection.emplace(id, image);
-
-			auto path{ SHTextureCompiler::CompileTextureBinary(image, asset.path) };
-
-			assetCollection.emplace_back(
-				image.name,
-				id,
-				AssetType::TEXTURE,
-				path,
-				0
-			);
-		}
+		loaders[static_cast<size_t>(AssetType::AUDIO)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::SHADER)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::MATERIAL)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::IMAGE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
+		loaders[static_cast<size_t>(AssetType::TEXTURE)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader());
+		loaders[static_cast<size_t>(AssetType::SCRIPT)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::SCENE)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::PREFAB)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::AUDIO_WAV)] = nullptr;
+		loaders[static_cast<size_t>(AssetType::DDS)] = nullptr;
 	}
 
 	/****************************************************************************
@@ -379,8 +251,9 @@ namespace SHADE
 	****************************************************************************/
 	void SHAssetManager::Load() noexcept
 	{
-		RetrieveAssets();
-		LoadAllData();
+		InitLoaders();
+		BuildAssetCollection();
+		//LoadAllData();
 	}
 
 	/****************************************************************************
@@ -388,143 +261,40 @@ namespace SHADE
 	****************************************************************************/
 	void SHAssetManager::LoadAllData() noexcept
 	{
-		//TODO Remove when on demand loading is done
 		for (auto const& asset : assetCollection)
 		{
-			switch (asset.type)
-			{
-			case AssetType::MESH:
-				meshCollection.emplace(asset.id, SHMeshAsset());
-				SHMeshLoader::LoadSHMesh(meshCollection[asset.id], asset.path);
-				break;
-
-			case AssetType::TEXTURE:
-				textureCollection.emplace(asset.id, SHTextureAsset());
-				SHTextureLoader::LoadSHTexture(asset.path, textureCollection[asset.id]);
-				break;
-
-			default:
-				void;
-			}
+			SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
+			assetData.emplace(asset.id, data);
 		}
 	}
 
-	void SHAssetManager::LoadData(AssetID id) noexcept
+	SHAssetData* SHAssetManager::LoadData(SHAsset const& asset) noexcept
 	{
-		(void)id;
-	}
+		SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
 
-	/****************************************************************************
-	 * \brief   Retrieve all asset files and meta files from filesystem
-	****************************************************************************/
-	void SHAssetManager::RetrieveAssets() noexcept
-	{
-		std::vector<AssetPath> metaFiles;
-		std::vector<AssetPath> AssetFiles;
-
-		for (auto const dir : std::filesystem::recursive_directory_iterator(ASSET_ROOT))
+		if (data == nullptr)
 		{
-			if (dir.path().extension().string() == META_EXTENSION)
-			{
-				auto meta{ SHAssetMetaHandler::RetrieveMetaData(dir.path()) };
-
-				assetCollection.push_back(meta);
-				assetRegistry.emplace(meta.id, meta);
-			}
-		}
-
-		//TODO: Write new function for file manager to loop through all files
-		//SHFileSystem::StartupFillDirectories(ASSET_ROOT);
-		//FolderPointer rootFolder = SHFileSystem::GetRoot();
-
-		//for (auto const& meta : metaFiles)
-		//{
-		//	for (std::vector<AssetPath>::const_iterator it{ AssetFiles.cbegin() };
-		//		it != AssetFiles.cend();
-		//		++it)
-		//	{
-		//		// Asset exists for meta file
-		//		std::string fileExtCheck{ it->filename().string() };
-		//		fileExtCheck += META_EXTENSION;
-		//		if (meta.filename().string() == fileExtCheck)
-		//		{
-		//			RegisterAsset(meta, *it);
-		//			AssetFiles.erase(it);
-		//			break;
-		//		}
-		//	}
-		//}
-
-		//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
-		//for (auto const& file : AssetFiles)
-		//{
-		//	if (IsRecognised(file.extension().string().c_str()))
-		//	{
-		//		SHAssetMetaHandler::WriteMetaData(RegisterAssetNew(file));
-		//	}
-		//	else
-		//	{
-		//		std::cout << "Unsupported File Format: " << file.filename() << "\n";
-		//	}
-		//}
-	}
-
-	AssetID SHAssetManager::RetrieveAsset(char const* path) noexcept
-	{
-		std::filesystem::path p{ path };
-		if (IsRecognised(p.extension().string().c_str()))
-		{
-			SHAsset const& meta{ RegisterAssetNew(p) };
-			SHAssetMetaHandler::WriteMetaData(meta);
-			return meta.id;
+			SHLOG_ERROR("Unable to load asset into memory: {}\n", asset.path.string());
 		}
 		else
 		{
-			std::cout << "Unsupported File Format: " << p.filename() << "\n";
+			assetData.emplace(asset.id, data);
 		}
 
-		// Assert that file imported is not recognised
-		return 0;
+		return data;
 	}
 
-	/****************************************************************************
-	 * \param   Full path of file
-
-	 * \brief   Extracts file name from path. Formats file name into readable
-	 *					with spaces and capitalises first letter of every word
-	****************************************************************************/
-	AssetName SHAssetManager::GetNameFromPath(AssetPath filepath) noexcept
+	void SHAssetManager::BuildAssetCollection() noexcept
 	{
-		std::string name{ filepath.filename().string() };
-		name = name.substr(0, name.find_last_of('.'));
-
-		//if (name[0] <= 122 && name[0] >= 97)
-		//{
-		//	name[0] -= 32;
-		//}
-
-		//for (size_t i{ 1 }; i < name.length(); ++i)
-		//{
-		//	// Replace all underscores with spaces
-		//	if (name[i] == '_')
-		//	{
-		//		name[i] = ' ';
-		//		continue;
-		//	}
-
-		//	if (name[i + 1] <= 'Z' && name[i + 1] >= 'A'
-		//		&& name[i] <= 'z' && name[i] >= 'a')
-		//	{
-		//		name.insert(i + 1, 1, ' ');
-		//		continue;
-		//	}
-
-		//	if (name[i - 1] == ' ' && name[i] <= 'z' && name[i] >= 'a')
-		//	{
-		//		name[i] -= 32;
-		//	}
-		//}
-
-		return name;
+		for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT})
+		{
+			if (dir.is_regular_file())
+			{
+				if (dir.path().extension().string() == META_EXTENSION.data())
+				{
+					assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path()));
+				}
+			}
+		}
 	}
 }
diff --git a/SHADE_Engine/src/Assets/SHAssetManager.h b/SHADE_Engine/src/Assets/SHAssetManager.h
index 2469165a..9ee7ab92 100644
--- a/SHADE_Engine/src/Assets/SHAssetManager.h
+++ b/SHADE_Engine/src/Assets/SHAssetManager.h
@@ -11,9 +11,10 @@
 #pragma once
 #include "tinyddsloader.h"
 #include "SHAsset.h"
+#include "Asset Types/SHAssetData.h"
+#include "Libraries/SHAssetLoader.h"
+#include <memory>
 
-#include "Asset Types/SHMeshAsset.h"	
-#include "Asset Types/SHTextureAsset.h"	
 #include "SH_API.h"
 
 namespace SHADE
@@ -28,6 +29,8 @@ namespace SHADE
 
 		static AssetPath GenerateLocalPath(AssetPath path) noexcept;
 
+		static AssetPath GenerateNewPath(AssetName name, AssetType type);
+
 		/****************************************************************************
 		 * \brief   Deallocate all memory used by resource data
 		****************************************************************************/
@@ -55,6 +58,7 @@ namespace SHADE
 		 * \return resource id generated for new asset
 		****************************************************************************/
 		static AssetID CreateNewAsset(AssetType, AssetName) noexcept;
+		static AssetID CreateAsset(AssetName name, AssetType type) noexcept;
 
 		/****************************************************************************
 		 * \brief Import new resource from outside editor window.
@@ -71,66 +75,33 @@ namespace SHADE
 		static void RefreshAllAssets() noexcept;
 		// -------------------------------------------------------------------------/
 
-		//TODO: TEMPORARY FOR TESTING GLTF & DDS
-		static void LoadDataTemp(std::string path) noexcept;
-		static std::vector<SHMeshAsset> GetAllMeshes() noexcept;
-		static std::vector<SHTextureAsset> GetAllTextures() noexcept;
-
-		static SHMeshAsset const* GetMesh(AssetID id) noexcept;
-		static SHTextureAsset const* GetTexture(AssetID id) noexcept;
+		template<typename T>
+		static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetData(AssetID id) noexcept;
 	private:
 		/****************************************************************************
 		 * \brief   Load resource data into memory
 		****************************************************************************/
 		static void LoadAllData() noexcept;
 
-		static void LoadData(AssetID id) noexcept;
+		static SHAssetData* LoadData(SHAsset const& asset) noexcept;
 
-		/****************************************************************************
-		 * \brief   Retrieve all resource files and meta files from filesystem
-		****************************************************************************/
-		static void RetrieveAssets() noexcept;
-
-		static AssetID RetrieveAsset(char const* path) noexcept;
-
-		/****************************************************************************
-		 * \param   Full path of file
-		
-		 * \brief   Extracts file name from path. Formats file name into readable
-		 *					with spaces and capitalises first letter of every word
-		****************************************************************************/
-		static AssetName GetNameFromPath(AssetPath) noexcept;
-
-		/****************************************************************************
-		 * \param   Path for meta data file
-		 * \param   Path for resource file
-		
-		 * \brief   Links meta data to resource in registries. Meta data should 
-		 *					already exist
-		****************************************************************************/
-		static void RegisterAsset(AssetPath const&, AssetPath const&) noexcept;
-
-		/****************************************************************************
-		 * \param   Path for resource file
-		
-		 * \brief   Creates new meta data for new resource.
-		****************************************************************************/
-		static SHAsset RegisterAssetNew(AssetPath const&) noexcept;
+		inline static void BuildAssetCollection() noexcept;
 
 		static bool IsRecognised(char const*) noexcept;
+		
+		static SHAsset CreateAssetFromPath(AssetPath	path) noexcept;
 
-		// Specialised load calls
-		static void LoadGLTF(SHAsset asset) noexcept;
-		static void LoadDDS(SHAsset asset) noexcept;
+		static void InitLoaders() noexcept;
 
 		static FMOD::System* audioSystem;
 		static std::unordered_map<AssetID,SHSound>* audioSoundList;
 
+		static std::vector<SHAssetLoader*> loaders;
+
 		// For all resources
 		static std::vector<SHAsset> assetCollection;
-		static std::unordered_map<AssetID, SHAsset> assetRegistry;
-
-		static std::unordered_map<AssetID, SHMeshAsset> meshCollection;
-		static std::unordered_map<AssetID, SHTextureAsset> textureCollection;
+		static std::unordered_map<AssetID, SHAssetData * const> assetData;
 	};
 }
+
+#include "SHAssetManager.hpp"
diff --git a/SHADE_Engine/src/Assets/SHAssetManager.hpp b/SHADE_Engine/src/Assets/SHAssetManager.hpp
new file mode 100644
index 00000000..6c420778
--- /dev/null
+++ b/SHADE_Engine/src/Assets/SHAssetManager.hpp
@@ -0,0 +1,26 @@
+
+#include "SHAssetManager.h"
+
+namespace SHADE
+{
+	template<typename T>
+	std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> SHAssetManager::GetData(AssetID id) noexcept
+	{
+		if (!assetData.contains(id))
+		{
+			for (auto const& asset : assetCollection)
+			{
+				if (asset.id == id)
+				{
+					assetData.emplace(id, LoadData(asset));
+					return dynamic_cast<T const* const>(assetData[id]);
+				}
+			}
+
+			SHLOG_ERROR("Asset ID provided does not exist: {}", id);
+			return nullptr;
+		}
+
+		return dynamic_cast<T const* const>(assetData[id]);
+	}
+}
diff --git a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp
index 442c3d96..1bfec00d 100644
--- a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp
+++ b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp
@@ -37,7 +37,7 @@ namespace SHADE
 	{
 		for (int i{0}; i < EXTENSIONS->size(); ++i)
 		{
-			if (ext == EXTENSIONS[i])
+			if (strcmp(ext.c_str(), EXTENSIONS[i].data()) == 0)
 			{
 				return static_cast<AssetType>(i);
 			}
@@ -53,7 +53,7 @@ namespace SHADE
 	****************************************************************************/
 	AssetExtension SHAssetMetaHandler::GetExtensionFromType(AssetType type) noexcept
 	{
-		return EXTENSIONS[static_cast<size_t>(type)];
+		return AssetExtension(EXTENSIONS[static_cast<size_t>(type)]);
 	}
 
 	/****************************************************************************
@@ -124,16 +124,6 @@ namespace SHADE
 		metaFile << "ID: " << meta.id << "\n";
 		metaFile << "Type: " << static_cast<AssetTypeMeta>(meta.type) << std::endl;
 
-		////TODO Add in information that is specific to types like mesh
-		//switch(meta.type)
-		//{
-		//case AssetType::MESH:
-		//	break;
-
-		//default:
-		//	break;
-		//}
-
 		metaFile.close();
 	}
 
diff --git a/SHADE_Engine/src/Camera/SHCameraSystem.cpp b/SHADE_Engine/src/Camera/SHCameraSystem.cpp
index 66018495..0d86c17a 100644
--- a/SHADE_Engine/src/Camera/SHCameraSystem.cpp
+++ b/SHADE_Engine/src/Camera/SHCameraSystem.cpp
@@ -140,10 +140,11 @@ namespace SHADE
     {
       auto transform = SHComponentManager::GetComponent<SHTransformComponent>(camera.GetEID());
       SHVec3 rotation = transform->GetWorldRotation();
-      camera.pitch = rotation.x;
-      camera.yaw = rotation.y;
-      camera.roll = rotation.z;
+      camera.pitch = SHMath::RadiansToDegrees(rotation.x);
+      camera.yaw =   SHMath::RadiansToDegrees(rotation.y);
+      camera.roll =  SHMath::RadiansToDegrees(rotation.z);
       camera.position = transform->GetWorldPosition();    
+      camera.dirtyView = true;
     }
     
 
diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp
new file mode 100644
index 00000000..caad9b10
--- /dev/null
+++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp
@@ -0,0 +1,84 @@
+#include "SHpch.h"
+#include "SHAssetBrowser.h"
+
+#include "Editor/IconsMaterialDesign.h"
+#include "Editor/SHImGuiHelpers.hpp"
+#include <imgui.h>
+
+#include "Assets/SHAssetManager.h"
+#include "Editor/DragDrop/SHDragDrop.hpp"
+
+namespace SHADE
+{
+  SHAssetBrowser::SHAssetBrowser()
+    :SHEditorWindow("\xee\x8b\x87 Asset Browser", ImGuiWindowFlags_MenuBar)
+  {
+  }
+
+  void SHAssetBrowser::Init()
+  {
+    SHEditorWindow::Init();
+  }
+
+  void SHAssetBrowser::Update()
+  {
+    SHEditorWindow::Update();
+    if(Begin())
+    {
+      DrawMenuBar();
+      auto const& assets = SHAssetManager::GetAllAssets();
+      if(ImGui::BeginTable("AssetBrowserTable", 3))
+      {
+        ImGui::TableNextColumn();
+        ImGui::TableHeader("Asset ID");
+        ImGui::TableNextColumn();
+        ImGui::TableHeader("Name");
+        ImGui::TableNextColumn();
+        ImGui::TableHeader("Type");
+        for(SHAsset const& asset : assets)
+        {
+          DrawAsset(asset);
+        }
+        ImGui::EndTable();
+      }
+    }
+    ImGui::End();
+  }
+
+  void SHAssetBrowser::DrawMenuBar()
+  {
+    if(ImGui::BeginMenuBar())
+    {
+
+      ImGui::EndMenuBar();
+    }
+  }
+
+  void SHAssetBrowser::DrawAsset(SHAsset const& asset)
+  {
+    ImGui::PushID(asset.id);
+    ImGui::BeginGroup();
+
+    ImGui::TableNextColumn();
+    ImGui::Selectable(std::format("{}", asset.id).data(), false, ImGuiSelectableFlags_SpanAllColumns);
+    if(SHDragDrop::BeginSource())
+    {
+      auto id = asset.id;
+      ImGui::Text("Moving Asset: %zu", id);
+      SHDragDrop::SetPayload<AssetID>(DRAG_RESOURCE, &id);
+      SHDragDrop::EndSource();
+    }
+
+    ImGui::TableNextColumn();
+    ImGui::Text("%s", asset.name.c_str());
+
+    ImGui::TableNextColumn();
+    ImGui::Text("%s", "Type");
+
+    ImGui::EndGroup();
+    ImGui::PopID();
+
+    
+
+  }
+}
diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h
new file mode 100644
index 00000000..0e3053bc
--- /dev/null
+++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "Assets/SHAsset.h"
+#include "Editor/EditorWindow/SHEditorWindow.h"
+
+namespace SHADE
+{
+  class SHAssetBrowser final : public SHEditorWindow
+  {
+  public:
+    SHAssetBrowser();
+
+    void Init();
+    void Update();
+
+    void Refresh();
+  private:
+    void DrawMenuBar();
+    void DrawAsset(SHAsset const& asset);
+
+    float idColumnWidth, nameColumnWidth, typeColumnWidth;
+    
+  };
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp
index 27e46d98..f2f8d927 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp
+++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp
@@ -93,8 +93,7 @@ namespace SHADE
   {
     if (ImGui::BeginMenuBar())
     {
-      
-      ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x - 35.0f);
+      ImGui::SetCursorPosX(ImGui::GetContentRegionAvail().x * 0.75f);
       if(ImGui::SmallButton(ICON_MD_DESELECT))
       {
         auto editor = SHSystemManager::GetSystem<SHEditor>();
diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp
index 08f5695b..7fa39d74 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp
+++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp
@@ -39,6 +39,10 @@ namespace SHADE
       {
         SHComponentManager::RemoveComponent<T>(component->GetEID());
       }
+      if (ImGui::Selectable(std::format("{} Reset {}", ICON_MD_RESTART_ALT, componentName.data()).data()))
+      {
+        *component = T();
+      }
       ImGui::EndPopup();
     }
   }
@@ -48,7 +52,7 @@ namespace SHADE
     if (!component)
       return;
     const auto componentType = rttr::type::get(*component);
-    SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; });
+    SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
     ImGui::SameLine();
     if (ImGui::CollapsingHeader(componentType.get_name().data()))
     {
@@ -89,7 +93,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin && metaMax)
             {
-              SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMin.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
+              SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value<int>(), metaMax.template get_value<int>(), [component, property] {return property.get_value(component).to_int(); }, [component, property](int const& result) {property.set_value(component, result); });
             }
             else
             {
@@ -115,7 +119,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMin.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu");
+              SHEditorWidgets::SliderScalar<uint16_t>(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value<uint16_t>(), metaMax.template get_value<uint16_t>(), [component, property] {return property.get_value(component).to_uint16(); }, [component, property](uint16_t const& result) {property.set_value(component, result); }, "%zu");
             }
             else
             {
@@ -128,7 +132,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMin.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu");
+              SHEditorWidgets::SliderScalar<uint32_t>(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value<uint32_t>(), metaMax.template get_value<uint32_t>(), [component, property] { return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result) {property.set_value(component, result); }, "%zu");
             }
             else
             {
@@ -141,7 +145,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMin.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu");
+              SHEditorWidgets::SliderScalar<uint64_t>(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value<uint64_t>(), metaMax.template get_value<uint64_t>(), [component, property] {return property.get_value(component).to_uint64(); }, [component, property](uint64_t const& result) {property.set_value(component, result); }, "%zu");
             }
             else
             {
@@ -152,13 +156,18 @@ namespace SHADE
           {
             auto metaMin = property.get_metadata(META::min);
             auto metaMax = property.get_metadata(META::max);
+            float min{}, max{};
+            if(metaMin.is_valid())
+              min = std::max(metaMin.template get_value<float>(), -FLT_MAX * 0.5f);
+            if(metaMax.is_valid())
+              max = std::min(metaMax.template get_value<float>(), FLT_MAX * 0.5f);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderFloat(property.get_name().data(), metaMin.template get_value<float>(), metaMin.template get_value<float>(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
+              SHEditorWidgets::SliderFloat(property.get_name().data(), min, max, [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
             }
             else
             {
-              SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); });
+              SHEditorWidgets::DragFloat(property.get_name().data(), [component, property] {return property.get_value(component).to_float(); }, [component, property](float const& result) {property.set_value(component, result); }, "Test");
             }
           }
           else if (type == rttr::type::get<double>())
@@ -167,7 +176,7 @@ namespace SHADE
             auto metaMax = property.get_metadata(META::max);
             if (metaMin.is_valid() && metaMax.is_valid())
             {
-              SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMin.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); });
+              SHEditorWidgets::SliderScalar<double>(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value<double>(), metaMax.template get_value<double>(), [component, property] {return property.get_value(component).to_double(); }, [component, property](double const& result) {property.set_value(component, result); });
             }
             else
             {
diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp
index b59ce9cc..d9b235e5 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp
+++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp
@@ -35,6 +35,23 @@ namespace SHADE
     return selected;
   }
 
+  template <typename ComponentType, typename EnforcedComponent, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true, std::enable_if_t<std::is_base_of_v<SHComponent, EnforcedComponent>, bool> = true>
+  bool DrawAddComponentWithEnforcedComponentButton(EntityID const& eid)
+  {
+    bool selected = false;
+    if (!SHComponentManager::HasComponent<ComponentType>(eid))
+    {
+      if(selected = ImGui::Selectable(std::format("Add {}", rttr::type::get<ComponentType>().get_name().data()).data()); selected)
+      {
+        if(SHComponentManager::GetComponent_s<EnforcedComponent>(eid) == nullptr)
+          SHComponentManager::AddComponent<EnforcedComponent>(eid);
+
+        SHComponentManager::AddComponent<ComponentType>(eid);
+      }
+    }
+    return selected;
+  }
+
   SHEditorInspector::SHEditorInspector()
     :SHEditorWindow("Inspector", ImGuiWindowFlags_MenuBar)
   {
@@ -84,21 +101,19 @@ namespace SHADE
         }
         ImGui::Separator();
         // Render Scripts
-		    SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
-		    scriptEngine->RenderScriptsInInspector(eid);
+        SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
+        scriptEngine->RenderScriptsInInspector(eid);
         ImGui::Separator();
         if(ImGui::BeginMenu(std::format("{} Add Component", ICON_MD_LIBRARY_ADD).data()))
         {
           DrawAddComponentButton<SHTransformComponent>(eid);
-          DrawAddComponentButton<SHRenderable>(eid);
-          DrawAddComponentButton<SHColliderComponent>(eid);
-          if(DrawAddComponentButton<SHRigidBodyComponent>(eid))
-          {
-            if(SHComponentManager::GetComponent_s<SHTransformComponent>(eid) == nullptr)
-            {
-              SHComponentManager::AddComponent<SHTransformComponent>(eid);
-            }
-          }
+
+          // Components that require Transforms
+
+          DrawAddComponentWithEnforcedComponentButton<SHRenderable, SHTransformComponent>(eid);
+          DrawAddComponentWithEnforcedComponentButton<SHRigidBodyComponent, SHTransformComponent>(eid);
+          DrawAddComponentWithEnforcedComponentButton<SHColliderComponent, SHTransformComponent>(eid);
+
           ImGui::EndMenu();
         }
 
diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h
index f0267b06..5208c6d9 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h
+++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h
@@ -3,4 +3,5 @@
 #include "HierarchyPanel/SHHierarchyPanel.h"  //Hierarchy Panel
 #include "Inspector/SHEditorInspector.h"      //Inspector
 #include "Profiling/SHEditorProfiler.h"       //Profiler
-#include "ViewportWindow/SHEditorViewport.h"  //Editor Viewport
\ No newline at end of file
+#include "ViewportWindow/SHEditorViewport.h"  //Editor Viewport
+#include "AssetBrowser/SHAssetBrowser.h"      //Asset Browser
\ No newline at end of file
diff --git a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp
index b06c37c7..f5170999 100644
--- a/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp
+++ b/SHADE_Engine/src/Editor/EditorWindow/ViewportWindow/SHEditorViewport.cpp
@@ -24,12 +24,13 @@ namespace SHADE
   void SHEditorViewport::Init()
   {
     SHEditorWindow::Init();
-
+    transformGizmo.Init();
   }
 
   void SHEditorViewport::Update()
   {
     SHEditorWindow::Update();
+    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f,0.0f));
     if(Begin())
     {
       ImGuizmo::SetDrawlist();
@@ -55,7 +56,7 @@ namespace SHADE
     ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
     transformGizmo.Draw();
     ImGui::End();
-
+    ImGui::PopStyleVar();
   }
 
   void SHEditorViewport::Exit()
diff --git a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp
index a53b8c10..3c984051 100644
--- a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp
+++ b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.cpp
@@ -13,6 +13,12 @@
 #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
 namespace SHADE
 {
+  void SHTransformGizmo::Init()
+  {
+    auto& style = ImGuizmo::GetStyle();
+    style.RotationLineThickness = 2.5f;
+  }
+
   void SHTransformGizmo::Draw()
   {
     bool justChangedTfm = false;
@@ -26,9 +32,12 @@ namespace SHADE
 
     SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix());
     SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix());
+
+    //Invert projection y-axis
     proj(1, 1) *= -1;
+
     static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity;
-    //ImGuizmo::DrawGrid(&view._11, &proj._11, &gridMat._11, 100.f);
+
     if (selectedEntityTransformComponent == nullptr)
     {
       SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
@@ -55,31 +64,37 @@ namespace SHADE
       return;
 
     SHMatrix mat = selectedEntityTransformComponent->GetTRS();
-    isManipulating = ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11);
-    if (!justChangedTfm)
+    useSnap = ImGui::IsKeyDown(ImGuiKey_LeftCtrl);
+    if(useSnap)
     {
-      if (ImGui::IsItemClicked())
-        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx)
-          {
-            if (!tfm)
-              return;
-            SHVec3 translate{}, rotate{}, scale{};
-            mtx.Decompose(translate, rotate, scale);
-            tfm->SetWorldPosition(translate);
-            tfm->SetWorldRotation(rotate);
-            tfm->SetWorldScale(scale);
-          })));
-      else if (ImGui::IsItemHovered(ImGuiMouseButton_Left) && ImGui::IsMouseDown(ImGuiMouseButton_Left) && isManipulating)
-        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx)
-          {
-            if (!tfm)
-              return;
-            SHVec3 translate{}, rotate{}, scale{};
-            mtx.Decompose(translate, rotate, scale);
-            tfm->SetWorldPosition(translate);
-            tfm->SetWorldRotation(rotate);
-            tfm->SetWorldScale(scale);
-          })), true);
+      switch (operation)
+      {
+      case Operation::TRANSLATE: snap = &translationSnap.x; break;
+      case Operation::ROTATE: snap = &rotationSnap; break;
+      case Operation::SCALE: snap = &scaleSnap; break;
+      default: snap = &translationSnap.x;
+      }
     }
+    ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11, nullptr, useSnap ? snap : nullptr);
+    static bool startRecording = false;
+    if (!justChangedTfm && ImGuizmo::IsUsing())
+    {
+      
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = (selectedEntityTransformComponent)](SHMatrix const& mtx)
+          {
+            if (!tfm)
+              return;
+            SHVec3 translate{}, rotate{}, scale{};
+            mtx.Decompose(translate, rotate, scale);
+            tfm->SetWorldPosition(translate);
+            tfm->SetWorldRotation(rotate);
+            tfm->SetWorldScale(scale);
+          })), startRecording);
+      if(!startRecording)
+        startRecording = true;
+    }
+    isManipulating = ImGuizmo::IsUsing() || startRecording;
+    if(startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      startRecording = false;
   }
 }
diff --git a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h
index 2565575f..fd847335 100644
--- a/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h
+++ b/SHADE_Engine/src/Editor/Gizmos/SHTransformGizmo.h
@@ -37,11 +37,17 @@ namespace SHADE
       UNIVERSAL = TRANSLATE | ROTATE | SCALEU
     };
 
+    void Init();
     void Draw();
     bool isManipulating = false;
+    bool useSnap = false;
     Mode mode = Mode::WORLD;
     Operation operation = Operation::TRANSLATE;
   private:
+    float scaleSnap = 0.25f;
+    float rotationSnap = 1.0f;
+    SHVec3 translationSnap = SHVec3(0.25f, 0.25f, 0.25f);
+    float* snap = nullptr;
     SHTransformComponent* selectedEntityTransformComponent{nullptr};
     SHCameraComponent* editorCamera{nullptr};
   };
diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp
index aff1eaad..06fadfee 100644
--- a/SHADE_Engine/src/Editor/SHEditor.cpp
+++ b/SHADE_Engine/src/Editor/SHEditor.cpp
@@ -92,6 +92,7 @@ namespace SHADE
     SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
     SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
     SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
+    SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>();
     SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
 
     io = &ImGui::GetIO();
@@ -134,7 +135,7 @@ namespace SHADE
       }
     }
     
-    PollPicking();
+    //PollPicking();
 
     if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
     {
diff --git a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp
index 5788dc15..b54a6799 100644
--- a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp
+++ b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp
@@ -40,7 +40,6 @@ namespace SHADE
     {
       ImGui::BeginGroup();
 
-      auto cursorPos = ImGui::GetCursorScreenPos();
       auto itemSpacing = ImGui::GetStyle().ItemSpacing;
       ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
       ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
@@ -158,7 +157,7 @@ namespace SHADE
     }
 
     template <typename T, std::size_t N>
-    static bool DragN(const std::string& fieldLabel, std::vector<std::string>const& componentLabels,
+    static bool DragN(const std::string& label, std::vector<std::string>const& componentLabels,
       std::vector<T*> values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(),
       ImGuiSliderFlags flags = 0, bool* isHovered = nullptr)
     {
@@ -169,13 +168,13 @@ namespace SHADE
       const ImGuiContext& g = *GImGui;
       bool valueChanged = false;
       ImGui::BeginGroup();
-      ImGui::PushID(fieldLabel.c_str());
+      ImGui::PushID(label.c_str());
       PushMultiItemsWidthsAndLabels(componentLabels, 0.0f);
       ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize);
       ImGui::SetColumnWidth(-1, 80.0f);
-      ImGui::Text(fieldLabel.c_str());
+      ImGui::Text(label.c_str());
       if (isHovered)
-          *isHovered = ImGui::IsItemHovered();
+        *isHovered = ImGui::IsItemHovered();
       ImGui::NextColumn();
       for (std::size_t i = 0; i < N; ++i)
       {
@@ -203,75 +202,91 @@ namespace SHADE
       return valueChanged;
     }
 
-    static bool DragVec2(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
-      std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
+    static bool DragVec2(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec2(void)> get,
+      std::function<void(SHVec2)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
       ImGuiSliderFlags flags = 0)
     {
       SHVec2 values = get();
-      bool changed = false;
-      if (DragN<float, 2>(fieldLabel, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags))
-      {
-        changed = true;
-      }
-
+      bool const changed = DragN<float, 2>(label, componentLabels, { &values.x, &values.y }, speed, displayFormat, valueMin, valueMax, flags);
+      static bool startRecording = false;
       if (changed)
       {
-        if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), false);
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec2>>(get(), values, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
+      }
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+        startRecording = false;
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
       }
-
       return changed;
     }
 
-    static bool DragVec3(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
-      std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
+    static bool DragVec3(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec3(void)> get,
+      std::function<void(SHVec3)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
       ImGuiSliderFlags flags = 0)
     {
       SHVec3 values = get();
-      bool changed = false;
-      if (DragN<float, 3>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags))
-      {
-        changed = true;
-      }
+      bool const changed = DragN<float, 3>(label, componentLabels, { &values.x, &values.y, &values.z }, speed, displayFormat, valueMin, valueMax, flags);
 
+
+      static bool startRecording = false;
       if (changed)
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(get(), values, set)), false);
+        SHVec3 old = get();
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec3>>(old, values, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
+      }
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
       }
-
       return changed;
     }
 
-    static bool DragVec4(const std::string& fieldLabel, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
-      std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f,
+    static bool DragVec4(const std::string& label, std::vector<std::string>const& componentLabels, std::function<SHVec4(void)> get,
+      std::function<void(SHVec4)> set, float speed = 0.1f, const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, float valueMin = 0.0f, float valueMax = 0.0f,
       ImGuiSliderFlags flags = 0)
     {
       SHVec4 values = get();
-      bool changed = false;
-      if (DragN<float, 4>(fieldLabel, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags))
-      {
-        changed = true;
-      }
-
+      bool const changed = DragN<float, 4>(label, componentLabels, { &values.x, &values.y, &values.z, &values.w }, speed, displayFormat, valueMin, valueMax, flags);
+      static bool startRecording = false;
       if (changed)
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), false);
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHVec4>>(get(), values, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
+      }
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
       }
-
       return changed;
     }
 
@@ -279,173 +294,325 @@ namespace SHADE
     //||                     Widget Extensions                      ||
     //#==============================================================#
 
-    static bool CheckBox(std::string const& label, std::function<bool(void)> get, std::function<void(bool const&)> set)
+    static void TextLabel(std::string_view const& text, bool sameLine = true)
+    {
+      const ImVec2 textSize = ImGui::CalcTextSize(text.data(), NULL, true);
+      if(textSize.x > 0.0f)
+      {
+        ImGui::Text(text.data());
+        ImGui::SameLine();
+      }
+    }
+
+    static bool CheckBox(std::string_view const& label, std::function<bool(void)> get, std::function<void(bool const&)> set, std::string_view const& tooltip = {})
     {
       bool value = get();
-      if (ImGui::Checkbox(label.c_str(), &value))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      if (ImGui::Checkbox("##", &value))
       {
         SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<bool>>(get(), value, set)), false);
         return true;
       }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
       return false;
     }
 
     template<typename T>
-    static bool RadioButton(std::vector<std::string> const& listLabels, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set)
+    static bool RadioButton(std::vector<std::string> const& label, std::vector<T> const& listTypes, std::function<T(void)> get, std::function<void(T const&)> set ,std::string_view const& tooltip = {})
     {
       T type = get();
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
       for (size_t i = 0; i < listTypes.size(); i++)
       {
-        if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i]))
+        if (ImGui::RadioButton(label[i].c_str(), type == listTypes[i]))
         {
           SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), listTypes[i], set)), false);
         }
         ImGui::SameLine();
       }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
       return true;
     }
 
     static bool InputText(const std::string& label, const std::function<std::string(void)> get,
-      const std::function<void(std::string)> set, ImGuiInputTextFlags flag = 0,
-      ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
+      const std::function<void(std::string)> set, std::string_view const& tooltip = {},
+      ImGuiInputTextFlags flag = 0, ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0)
     {
       std::string text = get();
-      if (ImGui::InputText(label.c_str(), &text, flag, callback, userData))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      if (ImGui::InputText("##", &text, flag, callback, userData))
       {
         if (ImGui::IsItemDeactivatedAfterEdit())
           SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<std::string>>(get(), text, set)), false);
 
         return true;
       }
-      return false;
-    }
-
-    template <typename T>
-    static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)>   set,
-      float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
-    {
-      T value = get();
-      std::cout << value << " \n";
-      //bool hasChange = ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
-
-      if (ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags))
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
-
-        return true;
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
       }
       return false;
     }
 
-    static bool DragFloat(const std::string& fieldLabel, std::function<float(void)> get, std::function<void(float const&)> set,
+    template <typename T>
+    static bool DragScalar(const std::string& label, ImGuiDataType data_type, std::function<T(void)> get, std::function<void(T const&)> set,
+      float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", std::string_view const& tooltip = {}, ImGuiSliderFlags flags = 0)
+    {
+      T value = get();
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      const bool hasChange = ImGui::DragScalar("##", data_type, &value, speed, &p_min, &p_max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
+      {
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
+      }
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
+    }
+
+    static bool DragFloat(const std::string_view& label, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
       float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
     {
       float value = get();
-      //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
-      if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      const bool hasChange = ImGui::DragFloat("##", &value, speed, p_min, p_max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
-
-        return true;
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if(!tooltip.empty())
+      {
+        if(ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
 
-    static bool DragInt(const std::string& fieldLabel, std::function<int(void)> get, std::function<void(int const&)> set,
+    static bool DragInt(const std::string& label, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
       float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
     {
       int value = get();
-      //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags);
-      if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      const bool hasChange = ImGui::DragInt("##", &value, speed, p_min, p_max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
-        else if (ImGui::IsItemDeactivatedAfterEdit())
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
-
-        return true;
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
     template <typename T>
-    static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set,
+    static bool SliderScalar(const std::string& label, ImGuiDataType data_type, T min, T max, std::function<T(void)> get, std::function<void(T const&)> set, std::string_view const& tooltip = {},
       const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
     {
       T value = get();
-      if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      bool const hasChange = ImGui::SliderScalar("##", data_type, &value, &min, &max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), true);
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<T>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
 
-        return true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
 
-    static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function<float(void)> get, std::function<void(float   const&)> set,
+    static bool SliderFloat(const std::string& label, float const& min, float const& max, std::function<float(void)> get, std::function<void(float const&)> set, std::string_view const& tooltip = {},
       const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0)
     {
       float value = get();
-      if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      bool const hasChange = ImGui::SliderFloat("##", &value, min, max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), true);
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<float>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
 
-
-        return true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
 
-    static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function<int(void)> get, std::function<void(int const&)>  set,
+    static bool SliderInt(const std::string& label, int min, int max, std::function<int(void)> get, std::function<void(int const&)> set, std::string_view const& tooltip = {},
       const char* displayFormat = "%d", ImGuiSliderFlags flags = 0)
     {
       int value = get();
-      if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags))
+      ImGui::BeginGroup();
+      ImGui::PushID(label.data());
+      TextLabel(label);
+      bool const hasChange = ImGui::SliderInt("##", &value, min, max, displayFormat, flags);
+      static bool startRecording = false;
+      if (hasChange)
       {
-        if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), false);
-        else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left))
-          SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), true);
 
-        return true;
+        SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), value, set)), startRecording);
+        if (!startRecording)
+          startRecording = true;
       }
-
-      return false;
+      if (startRecording && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
+      {
+        startRecording = false;
+      }
+      ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
+      return hasChange;
     }
 
-    static bool ComboBox(const std::string& fieldLabel, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int   const&)> set)
+    static bool ComboBox(const std::string& label, std::vector<const char*> list, std::function<int(void)> get, std::function<void(int   const&)> set, std::string_view const& tooltip = {})
     {
       bool edited = false;
       int selected = get();
-      ImGui::PushID(fieldLabel.c_str());
-      ImGui::Text(fieldLabel.c_str()); ImGui::SameLine();
+      ImGui::BeginGroup();
+      ImGui::PushID(label.c_str());
+      TextLabel(label);
+      ImGui::SameLine();
 
       if (edited = ImGui::Combo("##Combo", &selected, list.data(), static_cast<int>(list.size())))
       {
         SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<int>>(get(), selected, set)), false);
       }
       ImGui::PopID();
+      ImGui::EndGroup();
+      if (!tooltip.empty())
+      {
+        if (ImGui::IsItemHovered())
+        {
+          ImGui::BeginTooltip();
+          ImGui::Text(tooltip.data());
+          ImGui::EndTooltip();
+        }
+      }
       return edited;
     }
   };
diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h
index 317b67c1..804fbfec 100644
--- a/SHADE_Engine/src/Events/SHEventDefines.h
+++ b/SHADE_Engine/src/Events/SHEventDefines.h
@@ -5,8 +5,12 @@ typedef uint32_t SHEventIdentifier;
 typedef uint32_t SHEventHandle;
 
 //Add your event identifiers here:
-constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0};
-constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT{ 1 };
-constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT{ 2 };
-constexpr SHEventIdentifier	SH_COMPONENT_ADDED_EVENT{ 3 };
-constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT{ 4 };
+constexpr SHEventIdentifier SH_EXAMPLE_EVENT                  { 0 };
+constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT         { 1 };
+constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT          { 2 };
+constexpr SHEventIdentifier	SH_COMPONENT_ADDED_EVENT          { 3 };
+constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT        { 4 };
+constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 };
+constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT   { 6 };
+constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 7 };
+
diff --git a/SHADE_Engine/src/Events/SHEventManager.hpp b/SHADE_Engine/src/Events/SHEventManager.hpp
index f511518a..490c6b10 100644
--- a/SHADE_Engine/src/Events/SHEventManager.hpp
+++ b/SHADE_Engine/src/Events/SHEventManager.hpp
@@ -12,6 +12,7 @@
 #include "SHpch.h"
 #include "SHEvent.h"
 #include "SHEventReceiver.h"
+#include "SH_API.h"
 
 /******************************************************************************
 	INSTRUCTIONS FOR USE:
@@ -67,7 +68,7 @@ namespace SHADE
 	using EventManagerListener = std::function<void(SHEvent)>;
 
 
-	class SHEventManager
+	class SH_API SHEventManager
 	{
 	private:
 
diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp
index 4501ba7b..a744c795 100644
--- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp
+++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp
@@ -10,6 +10,7 @@
 #include "Graphics/Buffers/SHVkBuffer.h"
 #include "Graphics/Images/SHVkImage.h"
 #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
+#include "Graphics/SHVkUtil.h"
 
 
 namespace SHADE
@@ -299,7 +300,7 @@ namespace SHADE
       SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound. ");
       return;
     }
-    boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout();
+    bindPointData[static_cast<uint32_t>(pipelineHdl->GetPipelineType())].boundPipelineLayoutHdl = pipelineHdl->GetPipelineLayout();
     vkCommandBuffer.bindPipeline(pipelineHdl->GetPipelineBindPoint(), pipelineHdl->GetVkPipeline());
   }
 
@@ -358,9 +359,10 @@ namespace SHADE
     }
   }
 
-  void SHVkCommandBuffer::BindDescriptorSet(Handle<SHVkDescriptorSetGroup> descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets)
+  void SHVkCommandBuffer::BindDescriptorSet(Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets)
   {
-    vkCommandBuffer.bindDescriptorSets(bindPoint, boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets);
+    uint32_t bindPointIndex = static_cast<uint32_t>(bindPoint);
+    vkCommandBuffer.bindDescriptorSets(SHVkUtil::GetPipelineBindPointFromType(bindPoint), bindPointData[bindPointIndex].boundPipelineLayoutHdl->GetVkPipelineLayout(), firstSet, descSetGroup->GetVkHandle(), dynamicOffsets);
   }
 
   /***************************************************************************/
@@ -452,6 +454,11 @@ namespace SHADE
       vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand));
   }
 
+  void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept
+  {
+    vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ);
+  }
+
   void SHVkCommandBuffer::CopyBufferToImage(const vk::Buffer& src, const vk::Image& dst, const std::vector<vk::BufferImageCopy>& copyInfo)
   {
     vkCommandBuffer.copyBufferToImage
@@ -500,9 +507,9 @@ namespace SHADE
   //  //vkCommandBuffer.pipelineBarrier()
   //}
 
-  void SHVkCommandBuffer::ForceSetPipelineLayout(Handle<SHVkPipelineLayout> pipelineLayout) noexcept
+  void SHVkCommandBuffer::ForceSetPipelineLayout(Handle<SHVkPipelineLayout> pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept
   {
-    boundPipelineLayoutHdl = pipelineLayout;
+    bindPointData[static_cast<uint32_t>(pipelineType)].boundPipelineLayoutHdl = pipelineLayout;
   }
 
   /***************************************************************************/
@@ -513,12 +520,13 @@ namespace SHADE
 
   */
   /***************************************************************************/
-  void SHVkCommandBuffer::SubmitPushConstants(void) const noexcept
+  void SHVkCommandBuffer::SubmitPushConstants(SH_PIPELINE_TYPE bindPoint) const noexcept
   {
-    vkCommandBuffer.pushConstants(boundPipelineLayoutHdl->GetVkPipelineLayout(),
-      boundPipelineLayoutHdl->GetPushConstantInterface().GetShaderStageFlags(),
+    auto layoutHdl = bindPointData[static_cast<uint32_t>(bindPoint)].boundPipelineLayoutHdl;
+    vkCommandBuffer.pushConstants(layoutHdl->GetVkPipelineLayout(),
+      layoutHdl->GetPushConstantInterface().GetShaderStageFlags(),
       0,
-      boundPipelineLayoutHdl->GetPushConstantInterface().GetSize(), pushConstantData);
+      layoutHdl->GetPushConstantInterface().GetSize(), pushConstantData);
   }
 
   /***************************************************************************/
@@ -695,7 +703,7 @@ namespace SHADE
     , usageFlags{ rhs.usageFlags }
     , commandBufferCount{ rhs.commandBufferCount }
     , parentPool{ rhs.parentPool }
-    , boundPipelineLayoutHdl{ rhs.boundPipelineLayoutHdl }
+    , bindPointData{ std::move (rhs.bindPointData)}
   {
     memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
 
@@ -728,7 +736,7 @@ namespace SHADE
     usageFlags = rhs.usageFlags;
     commandBufferCount = rhs.commandBufferCount;
     parentPool = rhs.parentPool;
-    boundPipelineLayoutHdl = rhs.boundPipelineLayoutHdl;
+    bindPointData = std::move(rhs.bindPointData);
     memcpy(pushConstantData, rhs.pushConstantData, PUSH_CONSTANT_SIZE);
 
     rhs.vkCommandBuffer = VK_NULL_HANDLE;
diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h
index deb1131c..4c978c34 100644
--- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h
+++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h
@@ -6,6 +6,7 @@
 #include "SHCommandPoolResetMode.h"
 #include "Resource/SHResourceLibrary.h"
 #include "Graphics/Pipeline/SHVkPipelineLayout.h"
+#include "Graphics/Pipeline/SHPipelineType.h"
 
 namespace SHADE
 {
@@ -39,7 +40,14 @@ namespace SHADE
     friend class SHResourceLibrary<SHVkCommandBuffer>;
 
     static constexpr uint16_t PUSH_CONSTANT_SIZE = 512;
+    
   private:
+    struct PipelineBindPointData
+    {
+      //! The currently bound pipeline
+      Handle<SHVkPipelineLayout> boundPipelineLayoutHdl;
+    };
+
     /*-----------------------------------------------------------------------*/
     /* PRIVATE MEMBER VARIABLES                                              */
     /*-----------------------------------------------------------------------*/
@@ -66,8 +74,8 @@ namespace SHADE
     //! The command pool that this command buffer belongs to
     Handle<SHVkCommandPool> parentPool;
 
-    //! The currently bound pipeline
-    Handle<SHVkPipelineLayout> boundPipelineLayoutHdl;
+    //! Every command buffer will have a set of pipeline bind point specific data
+    std::array<PipelineBindPointData, static_cast<uint32_t>(SH_PIPELINE_TYPE::NUM_TYPES)> bindPointData;
 
     //! The push constant data for the command buffer 
     uint8_t pushConstantData[PUSH_CONSTANT_SIZE];
@@ -112,13 +120,16 @@ namespace SHADE
     void BindPipeline       (Handle<SHVkPipeline> const& pipelineHdl) noexcept;
     void BindVertexBuffer   (uint32_t bindingPoint, Handle<SHVkBuffer> const& buffer, vk::DeviceSize offset) noexcept;
     void BindIndexBuffer    (Handle<SHVkBuffer> const& buffer, uint32_t startingIndex) const noexcept;
-    void BindDescriptorSet  (Handle<SHVkDescriptorSetGroup> descSetGroup, vk::PipelineBindPoint bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets);
+    void BindDescriptorSet  (Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> dynamicOffsets);
     
     // Draw Commands
     void DrawArrays         (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
     void DrawIndexed        (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
     void DrawMultiIndirect  (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
 
+    // Compute Commands
+    void ComputeDispatch    (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept;
+
     // Buffer Copy
     void CopyBufferToImage  (const vk::Buffer& src, const vk::Image&  dst, const std::vector<vk::BufferImageCopy>& copyInfo);
     void CopyImageToBuffer  (const vk::Image&  src, const vk::Buffer& dst, const std::vector<vk::BufferImageCopy>& copyInfo);
@@ -138,13 +149,13 @@ namespace SHADE
 
     // Push Constant variable setting
     template <typename T>
-    void SetPushConstantVariable(std::string variableName, T const& data) noexcept
+    void SetPushConstantVariable(std::string variableName, T const& data, SH_PIPELINE_TYPE bindPoint) noexcept
     {
-      memcpy (static_cast<uint8_t*>(pushConstantData) + boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T));
+      memcpy (static_cast<uint8_t*>(pushConstantData) + bindPointData[static_cast<uint32_t>(bindPoint)].boundPipelineLayoutHdl->GetPushConstantInterface().GetOffset(variableName), &data, sizeof (T));
     };
-    void ForceSetPipelineLayout (Handle<SHVkPipelineLayout> pipelineLayout) noexcept;
+    void ForceSetPipelineLayout (Handle<SHVkPipelineLayout> pipelineLayout, SH_PIPELINE_TYPE pipelineType) noexcept;
 
-    void SubmitPushConstants (void) const noexcept;
+    void SubmitPushConstants (SH_PIPELINE_TYPE bindPoint) const noexcept;
 
     /*-----------------------------------------------------------------------*/
     /* GETTERS AND SETTERS                                                   */
diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp
index 6b770c3d..e5618c9c 100644
--- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp
+++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.cpp
@@ -25,7 +25,8 @@ namespace SHADE
   }
 
   SHVkDescriptorPool::SHVkDescriptorPool(SHVkDescriptorPool&& rhs) noexcept
-    : device{ rhs.device }
+    : ISelfHandle (rhs)
+    , device{ rhs.device }
     , pool{ rhs.pool }
   {
     rhs.pool = VK_NULL_HANDLE;
diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp
index ea859718..de68c583 100644
--- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp
+++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.cpp
@@ -91,7 +91,7 @@ namespace SHADE
 
         // new write for the binding
         updater.writeInfos.emplace_back();
-        updater.writeHashMap.try_emplace(writeHash, updater.writeInfos.size() - 1);
+        updater.writeHashMap.try_emplace(writeHash, static_cast<uint32_t>(updater.writeInfos.size()) - 1u);
         auto& writeInfo = updater.writeInfos.back();
 
         // Descriptor count for the write descriptor set. Usually this is set to 1, but if binding is variable sized, set to info passed in
@@ -102,10 +102,10 @@ namespace SHADE
           //case vk::DescriptorType::eSampler:
           //case vk::DescriptorType::eSampledImage:
         case vk::DescriptorType::eCombinedImageSampler:
+        case vk::DescriptorType::eStorageImage:
+        case vk::DescriptorType::eInputAttachment:
           writeInfo.descImageInfos.resize(descriptorCount);
-        break;
-        //case vk::DescriptorType::eStorageImage:
-        //  break;
+          break;
         case vk::DescriptorType::eUniformTexelBuffer:
         case vk::DescriptorType::eStorageTexelBuffer:
         case vk::DescriptorType::eUniformBuffer:
@@ -165,6 +165,7 @@ namespace SHADE
     if (imageViewsAndSamplers.size() > writeInfo.descImageInfos.size())
     {
       SHLOG_ERROR("Attempting write too many descriptors into descriptor set. Failed to write to vk::WriteDescriptorSet. ");
+      return;
     }
 
     for (uint32_t i = 0; i < imageViewsAndSamplers.size(); ++i)
diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h
index b2536de8..3f42afcc 100644
--- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h
+++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorSetGroup.h
@@ -31,6 +31,8 @@ namespace SHADE
   class SHVkDescriptorSetGroup
   {
   public:
+    using viewSamplerLayout = std::tuple<Handle<SHVkImageView>, Handle<SHVkSampler>, vk::ImageLayout>;
+
     /*-----------------------------------------------------------------------------*/
     /* Constructor/Destructors                                                     */
     /*-----------------------------------------------------------------------------*/
diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp
index 7c7acfc5..a6b415a9 100644
--- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp
+++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.cpp
@@ -233,6 +233,8 @@ namespace SHADE
     , vmaAllocator{rhs.vmaAllocator}
     , nonDedicatedBestIndex {0}
     , parentPhysicalDeviceHdl {rhs.parentPhysicalDeviceHdl}
+    , uboBufferMemoryAlignment{ 0 }
+    , ssboBufferMemoryAlignment{ 0 }
   {
     rhs.vkLogicalDevice = VK_NULL_HANDLE;
   }
@@ -261,6 +263,8 @@ namespace SHADE
     vmaAllocator = rhs.vmaAllocator;
     nonDedicatedBestIndex = 0;
     parentPhysicalDeviceHdl = rhs.parentPhysicalDeviceHdl;
+    uboBufferMemoryAlignment = rhs.uboBufferMemoryAlignment;
+    ssboBufferMemoryAlignment = rhs.ssboBufferMemoryAlignment;
 
     rhs.vkLogicalDevice = VK_NULL_HANDLE;
 
@@ -529,6 +533,11 @@ namespace SHADE
 
   }
 
+  Handle<SHVkPipeline> SHVkLogicalDevice::CreateComputePipeline(Handle<SHVkPipelineLayout> const& pipelineLayoutHdl) noexcept
+  {
+    return SHVkInstance::GetResourceManager().Create <SHVkPipeline>(GetHandle(), pipelineLayoutHdl);
+  }
+
   Handle<SHVkSampler> SHVkLogicalDevice::CreateSampler(const SHVkSamplerParams& params) noexcept
   {
     return SHVkInstance::GetResourceManager().Create <SHVkSampler>(GetHandle(), params);
diff --git a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h
index 3d59d5c6..2aa59941 100644
--- a/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h
+++ b/SHADE_Engine/src/Graphics/Devices/SHVkLogicalDevice.h
@@ -175,12 +175,17 @@ namespace SHADE
                                                                std::string const&               shaderName
                                                               ) noexcept;
                                     
-    Handle<SHVkPipeline>            CreateGraphicsPipeline            (
+    Handle<SHVkPipeline>            CreateGraphicsPipeline    (
                                                                Handle<SHVkPipelineLayout> const& pipelineLayoutHdl, 
                                                                SHVkPipelineState const* const    state, 
                                                                Handle<SHVkRenderpass> const&     renderpassHdl,
                                                                Handle<SHSubpass>                 subpass
                                                               ) noexcept;
+
+    Handle<SHVkPipeline>            CreateComputePipeline     ( 
+                                                               Handle<SHVkPipelineLayout> const& pipelineLayoutHdl
+                                                              ) noexcept;
+
     Handle<SHVkSampler>             CreateSampler             (const SHVkSamplerParams& params) noexcept;
                                     
     Handle<SHVkRenderpass>          CreateRenderpass          (std::span<vk::AttachmentDescription> const vkDescriptions, std::vector<SHVkSubpassParams> const& subpasses) noexcept;
diff --git a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp
index 4300f2bd..7443b6e2 100644
--- a/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp
+++ b/SHADE_Engine/src/Graphics/Images/SHVkSampler.cpp
@@ -49,7 +49,7 @@ namespace SHADE
   SHVkSampler::~SHVkSampler() noexcept
   {
     if (vkSampler)
-      device->GetVkLogicalDevice().destroySampler();
+      device->GetVkLogicalDevice().destroySampler(vkSampler);
   }
 
   /*-----------------------------------------------------------------------------------*/
diff --git a/SHADE_Engine/src/Graphics/Instance/SHVkInstance.cpp b/SHADE_Engine/src/Graphics/Instance/SHVkInstance.cpp
index 191bc563..edfe4b46 100644
--- a/SHADE_Engine/src/Graphics/Instance/SHVkInstance.cpp
+++ b/SHADE_Engine/src/Graphics/Instance/SHVkInstance.cpp
@@ -155,7 +155,7 @@ namespace SHADE
       SHVkDebugMessenger::GenMessengerType(SH_DEBUG_MSG_TYPE::T_GENERAL, SH_DEBUG_MSG_TYPE::T_VALIDATION, SH_DEBUG_MSG_TYPE::T_PERFORMANCE));
 
       instanceDbgInfo.pfnUserCallback = SHVulkanDebugUtil::GenericDebugCallback;
-      instanceInfo.pNext = static_cast<vk::DebugUtilsMessengerCreateInfoEXT*>(&instanceDbgInfo);
+      //instanceInfo.pNext = static_cast<vk::DebugUtilsMessengerCreateInfoEXT*>(&instanceDbgInfo);
     }
 
     // Finally create the instance
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp
index 2705b4d1..09fde60f 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp
@@ -30,185 +30,200 @@ of DigiPen Institute of Technology is prohibited.
 
 namespace SHADE
 {
-    /*---------------------------------------------------------------------------------*/
-    /* SHBatch - Usage Functions                                                       */
-    /*---------------------------------------------------------------------------------*/
-    SHBatch::SHBatch(Handle<SHVkPipeline> pipeline)
+  /*---------------------------------------------------------------------------------*/
+  /* SHBatch - Usage Functions                                                       */
+  /*---------------------------------------------------------------------------------*/
+  SHBatch::SHBatch(Handle<SHVkPipeline> pipeline)
     : pipeline{ pipeline }
-    {
-        if (!pipeline)
-            throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
+  {
+    if (!pipeline)
+      throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
 
-        // Mark all as dirty
-        setAllDirtyFlags();
+    // Mark all as dirty
+    setAllDirtyFlags();
+  }
+
+  void SHBatch::Add(const SHRenderable* renderable)
+  {
+    // Check if we have a SubBatch with the same mesh yet
+    auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
+      {
+        return batch.Mesh == renderable->Mesh;
+      });
+
+    // Create one if not found
+    if (subBatch == subBatches.end())
+    {
+      subBatches.emplace_back(renderable->Mesh);
+      subBatch = subBatches.end() - 1;
     }
 
-    void SHBatch::Add(const SHRenderable* renderable)
-    {
-        // Check if we have a SubBatch with the same mesh yet
-        auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
-        {
-            return batch.Mesh == renderable->Mesh;
-        });
+    // Add renderable in
+    subBatch->Renderables.insert(renderable->GetEID());
 
-        // Create one if not found
-        if (subBatch == subBatches.end())
+    // Also add material instance in
+    referencedMatInstances.insert(renderable->GetMaterial());
+
+    // Mark all as dirty
+    setAllDirtyFlags();
+  }
+
+  void SHBatch::Remove(const SHRenderable* renderable)
+  {
+    // Check if we have a SubBatch with the same mesh yet
+    auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
+      {
+        return batch.Mesh == renderable->Mesh;
+      });
+
+    // Attempt to remove if it exists
+    if (subBatch == subBatches.end())
+      return;
+
+    subBatch->Renderables.erase(renderable->GetEID());
+
+    // Check if other renderables in subBatches contain the same material instance
+    bool matUnused = true;
+    for (const auto& sb : subBatches)
+      for (const auto& rendId : sb.Renderables)
+      {
+        auto rend = SHComponentManager::GetComponent<SHRenderable>(rendId);
+        if (rend)
         {
-            subBatches.emplace_back(renderable->Mesh);
-            subBatch = subBatches.end() - 1;
+          if (rend->GetMaterial() == renderable->GetMaterial())
+          {
+            matUnused = false;
+            break;
+          }
         }
+        else
+        {
+          SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
+        }
+      }
 
-        // Add renderable in
-        subBatch->Renderables.insert(renderable);
+    // Material is no longer in this library, so we remove it
+    if (matUnused)
+      referencedMatInstances.erase(renderable->WasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial());
 
-        // Also add material instance in
-        referencedMatInstances.insert(renderable->GetMaterial());
+    // Mark all as dirty
+    setAllDirtyFlags();
+  }
 
-        // Mark all as dirty
-        setAllDirtyFlags();
+  void SHBatch::Clear()
+  {
+    subBatches.clear();
+
+    // Clear CPU buffers
+    drawData.clear();
+    transformData.clear();
+    instancedIntegerData.clear();
+    matPropsData.reset();
+    matPropsDataSize = 0;
+
+
+    // Clear GPU buffers
+    for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
+    {
+      drawDataBuffer[i].Free();
+      transformDataBuffer[i].Free();
+      instancedIntegerBuffer[i].Free();
+      matPropsBuffer[i].Free();
+    }
+  }
+
+  void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
+  {
+    if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
+    {
+      SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
+      return;
     }
 
-    void SHBatch::Remove(const SHRenderable* renderable)
+    // Check if there are even material properties to update
+    if (!matPropsData)
+      return;
+
+    // Check if any materials have changed
+    bool hasChanged = false;
+    for (const auto& material : referencedMatInstances)
     {
-        // Check if we have a SubBatch with the same mesh yet
-        auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
-        {
-            return batch.Mesh == renderable->Mesh;
-        });
-
-        // Attempt to remove if it exists
-        if (subBatch == subBatches.end())
-            return;
-
-        subBatch->Renderables.erase(renderable);
-
-        // Check if other renderables in subBatches contain the same material instance
-        bool matUnused = true;
-        for (const auto& sb : subBatches)
-        for (const auto& rend : sb.Renderables)
-        {
-            if (rend->GetMaterial() == renderable->GetMaterial())
-            {
-                matUnused = false;
-                break;
-            }
-        }
-
-        // Material is no longer in this library, so we remove it
-        if (matUnused)
-            referencedMatInstances.erase(renderable->GetMaterial());
-
-        // Mark all as dirty
-        for (bool& dirt : isDirty)
-            dirt = true;
+      if (material->HasChanged())
+      {
+        hasChanged = true;
+        break;
+      }
     }
 
-    void SHBatch::Clear()
+    // We need to update all the material buffers if the materials have changed
+    if (hasChanged)
     {
-        subBatches.clear();
-
-        // Clear CPU buffers
-        drawData.clear();
-        transformData.clear();
-        eidData.clear();
-        matPropsData.reset();
-        matPropsDataSize = 0;
-
-
-        // Clear GPU buffers
-        for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
-        {
-            drawDataBuffer[i].Free();
-            transformDataBuffer[i].Free();
-            eidBuffer[i].Free();
-            matPropsBuffer[i].Free();
-        }
+      for (auto& dirt : matBufferDirty)
+        dirt = true;
     }
 
-	void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
-	{
-		if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
-		{
-			SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
-			return;
-		}
+    // Check if this frame's buffer is dirty
+    if (!matBufferDirty[frameIndex])
+      return;
 
-        // Check if there are even material properties to update
-        if (!matPropsData)
-            return;
-
-        // Check if any materials have changed
-        bool hasChanged = false;
-        for (const auto& material : referencedMatInstances)
+    // Build CPU Buffer
+    char* propsCurrPtr = matPropsData.get();
+    for (auto& subBatch : subBatches)
+      for (auto rendId : subBatch.Renderables)
+      {
+        const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
+        if (renderable)
         {
-            if (material->HasChanged())
-            {
-                hasChanged = true;
-                break;
-            }
+          renderable->GetMaterial()->ExportProperties(propsCurrPtr);
         }
-
-        // We need to update all the material buffers if the materials have changed
-        if (hasChanged)
+        else
         {
-            for (auto& dirt : matBufferDirty)
-			    dirt = true;
+          SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
         }
+        propsCurrPtr += singleMatPropAlignedSize;
+      }
 
-        // Check if this frame's buffer is dirty
-        if (!matBufferDirty[frameIndex])
-            return;
+    // Transfer to GPU
+    rebuildMaterialBuffers(frameIndex, descPool);
 
-		// Build CPU Buffer
-		char* propsCurrPtr = matPropsData.get();
-		for (auto& subBatch : subBatches)
-		for (const SHRenderable* renderable : subBatch.Renderables)
-		{
-			renderable->GetMaterial()->ExportProperties(propsCurrPtr);
-			propsCurrPtr += singleMatPropAlignedSize;
-		}
-        
-        // Transfer to GPU
-        rebuildMaterialBuffers(frameIndex, descPool);
+    // This frame is updated
+    matBufferDirty[frameIndex] = false;
+  }
 
-        // This frame is updated
-        matBufferDirty[frameIndex] = false;
-	}
-
-	void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
+  void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
+  {
+    if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
     {
-        if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
-        {
-            SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
-            return;
-        }
-
-        // Reset Transform Data
-        transformData.clear();
-
-        // Populate on the CPU
-        for (auto& subBatch : subBatches)
-        for (const SHRenderable* renderable : subBatch.Renderables)
-        {
-            // Transform
-            auto transform = SHComponentManager::GetComponent<SHTransformComponent>(renderable->GetEID());
-            if (!transform)
-            {
-                SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
-                transformData.emplace_back();
-            }
-            else
-            {
-                transformData.emplace_back(transform->GetTRS());
-            }
-        }
-
-        // Transfer to GPU
-        if (transformDataBuffer[frameIndex])
-          transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
+      SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
+      return;
     }
 
-  void SHBatch::UpdateEIDBuffer(uint32_t frameIndex)
+    // Reset Transform Data
+    transformData.clear();
+
+    // Populate on the CPU
+    for (auto& subBatch : subBatches)
+      for (auto rendId : subBatch.Renderables)
+      {
+        // Transform
+        auto transform = SHComponentManager::GetComponent<SHTransformComponent>(rendId);
+        if (transform)
+        {
+          transformData.emplace_back(transform->GetTRS());
+        }
+        else
+        {
+          SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
+          transformData.emplace_back();
+        }
+      }
+
+    // Transfer to GPU
+    if (transformDataBuffer[frameIndex])
+      transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)), 0, 0);
+  }
+
+  void SHBatch::UpdateInstancedIntegerBuffer(uint32_t frameIndex)
   {
     if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
     {
@@ -217,224 +232,244 @@ namespace SHADE
     }
 
     // Reset Transform Data
-    eidData.clear();
+    instancedIntegerData.clear();
 
     // Populate on the CPU
     for (auto& subBatch : subBatches)
-      for (const SHRenderable* renderable : subBatch.Renderables)
+      for (auto rendId : subBatch.Renderables)
       {
-        eidData.emplace_back(renderable->GetEID());
+        auto* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
+        instancedIntegerData.emplace_back(SHInstancedIntegerData
+          {
+            rendId,
+            renderable->GetLightLayer()
+          }
+        );
       }
 
     // Transfer to GPU
-    if (eidBuffer[frameIndex])
-      eidBuffer[frameIndex]->WriteToMemory(eidData.data(), static_cast<EntityID>(eidData.size() * sizeof(EntityID)), 0, 0);
+    if (instancedIntegerBuffer[frameIndex])
+      instancedIntegerBuffer[frameIndex]->WriteToMemory(instancedIntegerData.data(), static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData)), 0, 0);
 
   }
 
   void SHBatch::Build(Handle<SHVkLogicalDevice> _device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)
+  {
+    if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
     {
-        if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
-        {
-            SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
-            return;
-        }
-
-        // Save logical device
-        device = _device;
-
-        // No need to build as there are no changes
-        if (!isDirty[frameIndex])
-            return;
-
-        // Count number of elements
-        size_t numTotalElements = 0;
-        for (const auto& subBatch : subBatches)
-        {
-            numTotalElements += subBatch.Renderables.size();
-        }
-
-        // Generate CPU buffers if there are changes
-        if (isCPUBuffersDirty)
-        {
-            // - Draw data
-            drawData.reserve(subBatches.size());
-            drawData.clear();
-            // - Transform data
-            transformData.reserve(numTotalElements);
-            transformData.clear();
-            // - EID data
-            eidData.reserve(numTotalElements);
-            eidData.clear();
-
-
-            // - Material Properties Data
-		    const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
-		    (
-			    SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
-			    SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
-			    vk::ShaderStageFlagBits::eFragment
-		    );
-            const bool EMPTY_MAT_PROPS = !SHADER_INFO;
-            Byte matPropTotalBytes = 0;
-            if (!EMPTY_MAT_PROPS)
-            {
-                singleMatPropSize = SHADER_INFO->GetBytesRequired();
-                singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
-                matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
-                if (matPropsDataSize < matPropTotalBytes)
-                {
-                    matPropsData.reset(new char[matPropTotalBytes]);
-                    matPropsDataSize = matPropTotalBytes;
-                }
-            }
-
-            // Build Sub Batches
-            uint32_t nextInstanceIndex = 0;
-            char* propsCurrPtr = matPropsData.get();
-            for (auto& subBatch : subBatches)
-            {
-                // Create command
-                drawData.emplace_back(vk::DrawIndexedIndirectCommand
-                {
-                    .indexCount = subBatch.Mesh->IndexCount,
-                    .instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
-                    .firstIndex = subBatch.Mesh->FirstIndex,
-                    .vertexOffset = subBatch.Mesh->FirstVertex,
-                    .firstInstance = nextInstanceIndex++
-                });
-
-                // Fill in buffers (CPU)
-                for (const SHRenderable* renderable : subBatch.Renderables)
-                {
-                    // Transform
-                    EntityID eid = renderable->GetEID();
-                    auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
-                    if (!transform)
-                    {
-                        SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
-                        transformData.emplace_back();
-                    }
-                    else
-                    {
-                        transformData.emplace_back(transform->GetTRS());
-                    }
-
-                    eidData.emplace_back(eid);
-                   
-                    // Material Properties
-                    if (!EMPTY_MAT_PROPS)
-                    {
-                        renderable->GetMaterial()->ExportProperties(propsCurrPtr);
-                        propsCurrPtr += singleMatPropAlignedSize;
-                    }
-                }
-            }
-
-            // Successfully update CPU buffers
-            isCPUBuffersDirty = false;
-        }
-
-        // Send all buffered data to the GPU buffers
-        using BuffUsage = vk::BufferUsageFlagBits;
-        // - Draw Data
-        const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
-        SHVkUtil::EnsureBufferAndCopyHostVisibleData
-        (
-            device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
-            BuffUsage::eIndirectBuffer
-        );
-        // - Transform Buffer
-        const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
-        SHVkUtil::EnsureBufferAndCopyHostVisibleData
-        (
-            device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
-            BuffUsage::eVertexBuffer
-        );
-        const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(eidData.size() * sizeof(EntityID));
-        SHVkUtil::EnsureBufferAndCopyHostVisibleData
-        (
-          device, eidBuffer[frameIndex], eidData.data(), EID_DATA_BYTES,
-          BuffUsage::eVertexBuffer
-        );
-        // - Material Properties Buffer
-        rebuildMaterialBuffers(frameIndex, descPool);
-
-        // Mark this frame as no longer dirty
-        isDirty[frameIndex] = false;
+      SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
+      return;
     }
 
-    /*---------------------------------------------------------------------------------*/
-    /* SHBatch - Usage Functions                                                       */
-    /*---------------------------------------------------------------------------------*/
-    void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
-    {
-        if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
-        {
-            SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
-            return;
-        }
+    // Save logical device
+    device = _device;
 
-        // Bind all required objects before drawing
-        static std::array<uint32_t, 1> dynamicOffset { 0 };
-        cmdBuffer->BindPipeline(pipeline);
-        cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
-        cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::EID,       eidBuffer[frameIndex], 0);
-        if (matPropsDescSet[frameIndex])
+    // No need to build as there are no changes
+    if (!isDirty[frameIndex])
+      return;
+
+    // Count number of elements
+    size_t numTotalElements = 0;
+    for (const auto& subBatch : subBatches)
+    {
+      numTotalElements += subBatch.Renderables.size();
+    }
+
+    // Generate CPU buffers if there are changes
+    if (isCPUBuffersDirty)
+    {
+      // - Draw data
+      drawData.reserve(subBatches.size());
+      drawData.clear();
+      // - Transform data
+      transformData.reserve(numTotalElements);
+      transformData.clear();
+      // - EID data
+      instancedIntegerData.reserve(numTotalElements);
+      instancedIntegerData.clear();
+
+
+      // - Material Properties Data
+      const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
+      (
+        SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
+        SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
+        vk::ShaderStageFlagBits::eFragment
+      );
+      const bool EMPTY_MAT_PROPS = !SHADER_INFO;
+      Byte matPropTotalBytes = 0;
+      if (!EMPTY_MAT_PROPS)
+      {
+        singleMatPropSize = SHADER_INFO->GetBytesRequired();
+        singleMatPropAlignedSize = device->PadSSBOSize(static_cast<uint32_t>(singleMatPropSize));
+        matPropTotalBytes = numTotalElements * singleMatPropAlignedSize;
+        if (matPropsDataSize < matPropTotalBytes)
         {
-          cmdBuffer->BindDescriptorSet
-          (
-            matPropsDescSet[frameIndex],
-            vk::PipelineBindPoint::eGraphics,
-            SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
-            dynamicOffset
+          matPropsData.reset(new char[matPropTotalBytes]);
+          matPropsDataSize = matPropTotalBytes;
+        }
+      }
+
+      // Build Sub Batches
+      uint32_t nextInstanceIndex = 0;
+      char* propsCurrPtr = matPropsData.get();
+      for (auto& subBatch : subBatches)
+      {
+        // Create command
+        const uint32_t CURR_INSTANCES = static_cast<uint32_t>(subBatch.Renderables.size());
+        drawData.emplace_back(vk::DrawIndexedIndirectCommand
+          {
+              .indexCount = subBatch.Mesh->IndexCount,
+              .instanceCount = CURR_INSTANCES,
+              .firstIndex = subBatch.Mesh->FirstIndex,
+              .vertexOffset = subBatch.Mesh->FirstVertex,
+              .firstInstance = nextInstanceIndex
+          });
+        nextInstanceIndex += CURR_INSTANCES;
+
+        // Fill in buffers (CPU)
+        for (auto rendId : subBatch.Renderables)
+        {
+          // Transform
+          auto transform = SHComponentManager::GetComponent_s<SHTransformComponent>(rendId);
+          if (!transform)
+          {
+            SHLOG_WARNING("[SHBatch] Entity contianing a SHRenderable with no SHTransformComponent found!");
+            transformData.emplace_back();
+          }
+          else
+          {
+            transformData.emplace_back(transform->GetTRS());
+          }
+
+          const SHRenderable* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
+          instancedIntegerData.emplace_back(SHInstancedIntegerData
+            {
+              rendId,
+              renderable->GetLightLayer()
+            }
           );
-        }
-        cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
-    }
 
-    /*---------------------------------------------------------------------------------*/
-    /* SHBatch - Helper Functions                                                      */
-    /*---------------------------------------------------------------------------------*/
-    void SHBatch::setAllDirtyFlags()
-    {
-        for (bool& dirt : isDirty)
-            dirt = true;
-        isCPUBuffersDirty = true;
-    }
-
-    void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
-    {
-        if (matPropsData)
-        {
-            SHVkUtil::EnsureBufferAndCopyHostVisibleData
-            (
-                device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
-                vk::BufferUsageFlagBits::eStorageBuffer
-            );
-
-            if (!matPropsDescSet[frameIndex])
+          // Material Properties
+          if (!EMPTY_MAT_PROPS)
+          {
+            if (renderable)
             {
-                matPropsDescSet[frameIndex] = descPool->Allocate
-                (
-                    { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
-                    { 0 }
-                );
+              renderable->GetMaterial()->ExportProperties(propsCurrPtr);
             }
-            std::array<Handle<SHVkBuffer>, 1>  bufferList = { matPropsBuffer[frameIndex] };
-            matPropsDescSet[frameIndex]->ModifyWriteDescBuffer
-            (
-                SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
-                SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
-                bufferList,
-                0, static_cast<uint32_t>(matPropsDataSize)
-            );
-            matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
-            (
-                SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
-                SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
-            );
+            else
+            {
+              SHLOG_WARNING("[SHBatch] Entity with a missing SHRenderable found!");
+            }
+            propsCurrPtr += singleMatPropAlignedSize;
+          }
         }
+      }
+
+      // Successfully update CPU buffers
+      isCPUBuffersDirty = false;
     }
 
+    // Send all buffered data to the GPU buffers
+    using BuffUsage = vk::BufferUsageFlagBits;
+    // - Draw Data
+    const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
+    SHVkUtil::EnsureBufferAndCopyHostVisibleData
+    (
+      device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
+      BuffUsage::eIndirectBuffer
+    );
+    // - Transform Buffer
+    const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
+    SHVkUtil::EnsureBufferAndCopyHostVisibleData
+    (
+      device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
+      BuffUsage::eVertexBuffer
+    );
+    const uint32_t EID_DATA_BYTES = static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData));
+    SHVkUtil::EnsureBufferAndCopyHostVisibleData
+    (
+      device, instancedIntegerBuffer[frameIndex], instancedIntegerData.data(), EID_DATA_BYTES,
+      BuffUsage::eVertexBuffer
+    );
+    // - Material Properties Buffer
+    rebuildMaterialBuffers(frameIndex, descPool);
+
+    // Mark this frame as no longer dirty
+    isDirty[frameIndex] = false;
+  }
+
+  /*---------------------------------------------------------------------------------*/
+  /* SHBatch - Usage Functions                                                       */
+  /*---------------------------------------------------------------------------------*/
+  void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
+  {
+    if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
+    {
+      SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
+      return;
+    }
+
+    // Bind all required objects before drawing
+    static std::array<uint32_t, 1> dynamicOffset{ 0 };
+    cmdBuffer->BindPipeline(pipeline);
+    cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
+    cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
+    if (matPropsDescSet[frameIndex])
+    {
+      cmdBuffer->BindDescriptorSet
+      (
+        matPropsDescSet[frameIndex],
+        SH_PIPELINE_TYPE::GRAPHICS,
+        SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
+        dynamicOffset
+      );
+    }
+    cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
+  }
+
+  /*---------------------------------------------------------------------------------*/
+  /* SHBatch - Helper Functions                                                      */
+  /*---------------------------------------------------------------------------------*/
+  void SHBatch::setAllDirtyFlags()
+  {
+    for (bool& dirt : isDirty)
+      dirt = true;
+    isCPUBuffersDirty = true;
+  }
+
+  void SHBatch::rebuildMaterialBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
+  {
+    if (matPropsData)
+    {
+      SHVkUtil::EnsureBufferAndCopyHostVisibleData
+      (
+        device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
+        vk::BufferUsageFlagBits::eStorageBuffer
+      );
+
+      if (!matPropsDescSet[frameIndex])
+      {
+        matPropsDescSet[frameIndex] = descPool->Allocate
+        (
+          { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE] },
+          { 0 }
+        );
+      }
+      std::array<Handle<SHVkBuffer>, 1>  bufferList = { matPropsBuffer[frameIndex] };
+      matPropsDescSet[frameIndex]->ModifyWriteDescBuffer
+      (
+        SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
+        SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
+        bufferList,
+        0, static_cast<uint32_t>(matPropsDataSize)
+      );
+      matPropsDescSet[frameIndex]->UpdateDescriptorSetBuffer
+      (
+        SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
+        SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA
+      );
+    }
+  }
+
 }
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h
index 193fff0d..de137b28 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h
@@ -23,6 +23,7 @@ of DigiPen Institute of Technology is prohibited.
 #include "Math/SHMatrix.h"
 #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
 #include "ECS_Base/SHECSMacros.h"
+#include "Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h"
 
 namespace SHADE
 {
@@ -55,7 +56,7 @@ namespace SHADE
         /* Data Members                                                                */
         /*-----------------------------------------------------------------------------*/
         Handle<SHMesh> Mesh;
-        std::unordered_set<const SHRenderable*> Renderables;
+        std::unordered_set<EntityID> Renderables;
     };
     /***********************************************************************************/
     /*!
@@ -79,7 +80,7 @@ namespace SHADE
         void Clear();
         void UpdateMaterialBuffer(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
         void UpdateTransformBuffer(uint32_t frameIndex);
-        void UpdateEIDBuffer(uint32_t frameIndex);
+        void UpdateInstancedIntegerBuffer(uint32_t frameIndex);
         void Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex)  ;
         void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex);
 
@@ -111,7 +112,7 @@ namespace SHADE
         // CPU Buffers                                 
         std::vector<vk::DrawIndexedIndirectCommand>    drawData;
         std::vector<SHMatrix>                          transformData;
-        std::vector<EntityID>                          eidData;
+        std::vector<SHInstancedIntegerData>            instancedIntegerData;
         std::unique_ptr<char>                          matPropsData;
         Byte                                           matPropsDataSize          = 0;
         Byte                                           singleMatPropAlignedSize  = 0;
@@ -120,7 +121,7 @@ namespace SHADE
         // GPU Buffers                                 
         TripleBuffer                                   drawDataBuffer;
         TripleBuffer                                   transformDataBuffer;
-        TripleBuffer                                   eidBuffer;
+        TripleBuffer                                   instancedIntegerBuffer;
         TripleBuffer                                   matPropsBuffer;
         TripleDescSet                                  matPropsDescSet;
 
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp
index add51196..434e7163 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp
@@ -20,91 +20,91 @@ of DigiPen Institute of Technology is prohibited.
 
 namespace SHADE
 {
-    /*---------------------------------------------------------------------------------*/
-    /* Constructor/Destructors                                                         */
-    /*---------------------------------------------------------------------------------*/
+  /*---------------------------------------------------------------------------------*/
+  /* Constructor/Destructors                                                         */
+  /*---------------------------------------------------------------------------------*/
 
-    SHSuperBatch::SHSuperBatch(Handle<SHSubpass> sp)
-    : subpass { sp }
-    {}
+  SHSuperBatch::SHSuperBatch(Handle<SHSubpass> sp)
+    : subpass{ sp }
+  {}
 
-    /*---------------------------------------------------------------------------------*/
-    /* Usage Functions                                                                 */
-    /*---------------------------------------------------------------------------------*/
-    void SHSuperBatch::Add(const SHRenderable* renderable) noexcept
+  /*---------------------------------------------------------------------------------*/
+  /* Usage Functions                                                                 */
+  /*---------------------------------------------------------------------------------*/
+  void SHSuperBatch::Add(const SHRenderable* renderable) noexcept
+  {
+    const Handle<SHVkPipeline> PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline();
+
+    // Check if we have a batch with the same pipeline first
+    auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch)
+      {
+        return batch.GetPipeline() == PIPELINE;
+      });
+
+
+    // Create one if not found
+    if (batch == batches.end())
     {
-        const Handle<SHVkPipeline> PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline();
-
-        // Check if we have a batch with the same pipeline first
-        auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch)
-        {
-            return batch.GetPipeline() == PIPELINE;
-        });
-
-
-        // Create one if not found
-        if (batch == batches.end())
-        {
-            batches.emplace_back(PIPELINE);
-            batch = batches.end() - 1;
-        }
-
-        // Add renderable in
-        batch->Add(renderable);
+      batches.emplace_back(PIPELINE);
+      batch = batches.end() - 1;
     }
 
-    void SHSuperBatch::Remove(const SHRenderable* renderable) noexcept
+    // Add renderable in
+    batch->Add(renderable);
+  }
+
+  void SHSuperBatch::Remove(const SHRenderable* renderable) noexcept
+  {
+    const Handle<SHVkPipeline> PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline();
+
+    // Check if we have a Batch with the same pipeline yet
+    auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch)
+      {
+        return batch.GetPipeline() == PIPELINE;
+      });
+
+    // Attempt to remove if it exists
+    if (batch == batches.end())
+      return;
+
+    batch->Remove(renderable);
+  }
+
+  void SHSuperBatch::Clear() noexcept
+  {
+    for (auto& batch : batches)
     {
-        const Handle<SHVkPipeline> PIPELINE = renderable->GetMaterial()->GetBaseMaterial()->GetPipeline();
-
-        // Check if we have a Batch with the same pipeline yet
-        auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch)
-        {
-            return batch.GetPipeline() == PIPELINE;
-        });
-
-        // Attempt to remove if it exists
-        if (batch == batches.end())
-            return;
-
-        batch->Remove(renderable);
+      batch.Clear();
     }
+    batches.clear();
+  }
 
-    void SHSuperBatch::Clear() noexcept
+  void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
+  {
+    for (auto& batch : batches)
     {
-        for (auto& batch : batches)
-        {
-            batch.Clear();
-        }
-        batches.clear();
+      batch.UpdateMaterialBuffer(frameIndex, descPool);
+      batch.UpdateTransformBuffer(frameIndex);
+      batch.UpdateInstancedIntegerBuffer(frameIndex);
     }
+  }
 
-	void SHSuperBatch::UpdateBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
+  void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
+  {
+    // Build all batches
+    for (auto& batch : batches)
     {
-        for (auto& batch : batches)
-        {
-			      batch.UpdateMaterialBuffer(frameIndex, descPool);
-            batch.UpdateTransformBuffer(frameIndex);
-            batch.UpdateEIDBuffer(frameIndex);
-        }
+      batch.Build(device, descPool, frameIndex);
     }
+  }
 
-    void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
+  void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
+  {
+    // Build all batches
+    for (auto& batch : batches)
     {
-        // Build all batches
-        for (auto& batch : batches)
-        {
-            batch.Build(device, descPool, frameIndex);
-        }
-    }
-
-    void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
-    {
-        // Build all batches
-        for (auto& batch : batches)
-        {
-            batch.Draw(cmdBuffer, frameIndex);
-        }
+      batch.Draw(cmdBuffer, frameIndex);
     }
+  }
 
 }
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp
index d8b1bad1..0f1658f3 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.cpp
@@ -4,6 +4,8 @@
 #include "Graphics/Pipeline/SHPipelineState.h"
 #include "Graphics/Pipeline/SHVkPipelineLayout.h"
 #include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
+#include "Graphics/MiddleEnd/Lights/SHLightData.h"
+#include "Tools/SHUtilities.h"
 
 namespace SHADE
 {
@@ -45,16 +47,35 @@ namespace SHADE
     // For global data (generic data and textures)
     Handle<SHVkDescriptorSetLayout> staticGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS,{ genericDataBinding, texturesBinding });
 
-    SHVkDescriptorSetLayout::Binding lightBinding
+    std::vector<SHVkDescriptorSetLayout::Binding> lightBindings{};
+    for (uint32_t i = 0; i < SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); ++i)
     {
-      .Type = vk::DescriptorType::eStorageBufferDynamic,
-      .Stage = vk::ShaderStageFlagBits::eFragment,
-      .BindPoint = SHGraphicsConstants::DescriptorSetBindings::LIGHTS_DATA,
-      .DescriptorCount = 1,
-    };
+      lightBindings.push_back (SHVkDescriptorSetLayout::Binding
+      {
+        .Type = vk::DescriptorType::eStorageBufferDynamic,
+        .Stage = vk::ShaderStageFlagBits::eFragment,
+        .BindPoint = i,
+        .DescriptorCount = 1,
+      });
+    }
+    //SHVkDescriptorSetLayout::Binding pointLightBinding
+    //{
+    //  .Type = vk::DescriptorType::eStorageBufferDynamic,
+    //  .Stage = vk::ShaderStageFlagBits::eFragment,
+    //  .BindPoint = SHGraphicsConstants::DescriptorSetBindings::POINT_LIGHT_DATA,
+    //  .DescriptorCount = 1,
+    //};
+
+    //SHVkDescriptorSetLayout::Binding spotLightBinding
+    //{
+    //  .Type = vk::DescriptorType::eStorageBufferDynamic,
+    //  .Stage = vk::ShaderStageFlagBits::eFragment,
+    //  .BindPoint = SHGraphicsConstants::DescriptorSetBindings::SPOT_LIGHT_DATA,
+    //  .DescriptorCount = 1,
+    //};
 
     // For Dynamic global data (lights)
-    Handle<SHVkDescriptorSetLayout> dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, { lightBinding });
+    Handle<SHVkDescriptorSetLayout> dynamicGlobalLayout = logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, lightBindings);
 
     SHVkDescriptorSetLayout::Binding cameraDataBinding
     {
@@ -94,7 +115,7 @@ namespace SHADE
     defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Normals at binding 2
     defaultVertexInputState.AddBinding(false, false, { SHVertexAttribute(SHAttribFormat::FLOAT_3D) }); // Tangents at binding 3
     defaultVertexInputState.AddBinding(true, true,   { SHVertexAttribute(SHAttribFormat::MAT_4D)   }); // Transform at binding 4 - 7 (4 slots)
-    defaultVertexInputState.AddBinding(true, true,   { SHVertexAttribute(SHAttribFormat::UINT32_1D) }); // EID at binding 8
+    defaultVertexInputState.AddBinding(true, true,   { SHVertexAttribute(SHAttribFormat::UINT32_2D) }); // Instanced integer data at index 8
   }
 
   void SHGraphicsGlobalData::Init(Handle<SHVkLogicalDevice> logicalDevice) noexcept
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h
index 67cbc001..4c3ba7f9 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h
@@ -63,6 +63,14 @@ namespace SHADE
       */
       /***************************************************************************/
       static constexpr uint32_t PER_INSTANCE = 3;
+      /***************************************************************************/
+      /*!
+        \brief
+          DescriptorSet Index for render graph resources.
+      */
+      /***************************************************************************/
+      static constexpr uint32_t RENDERGRAPH_RESOURCE = 4;
+
 
     };
 
@@ -86,14 +94,32 @@ namespace SHADE
       /***************************************************************************/
       static constexpr uint32_t IMAGE_AND_SAMPLERS_DATA = 1;
 
-      /***************************************************************************/
-      /*!
-        \brief
-          DescriptorSet binding for lights.
+      ///***************************************************************************/
+      ///*!
+      //  \brief
+      //    DescriptorSet binding for directional lights.
 
-      */
-      /***************************************************************************/
-      static constexpr uint32_t LIGHTS_DATA = 0;
+      //*/
+      ///***************************************************************************/
+      //static constexpr uint32_t DIRECTIONAL_LIGHT_DATA = 0;
+
+      ///***************************************************************************/
+      ///*!
+      //  \brief
+      //    DescriptorSet binding for directional lights.
+
+      //*/
+      ///***************************************************************************/
+      //static constexpr uint32_t POINT_LIGHT_DATA = 1;
+
+      ///***************************************************************************/
+      ///*!
+      //  \brief
+      //    DescriptorSet binding for directional lights.
+
+      //*/
+      ///***************************************************************************/
+      //static constexpr uint32_t SPOT_LIGHT_DATA = 2;
 
       /***************************************************************************/
       /*!
@@ -156,7 +182,7 @@ namespace SHADE
           Vertex buffer bindings for the eid buffer.
       */
       /***************************************************************************/
-      static constexpr uint32_t EID = 5;
+      static constexpr uint32_t INTEGER_DATA = 5;
 
     };
 
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp
index 44404bc7..9b984a4b 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp
@@ -36,6 +36,7 @@ of DigiPen Institute of Technology is prohibited.
 #include "Graphics/Images/SHVkSampler.h"
 #include "Assets/Asset Types/SHTextureAsset.h"
 #include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
+#include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h"
 
 namespace SHADE
 {
@@ -115,6 +116,26 @@ namespace SHADE
     graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
     transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
     graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
+
+
+    // TODO: This is VERY temporarily here until a more solid resource management system is implemented
+    shaderSourceLibrary.Init("../../TempShaderFolder/");
+
+    shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
+    shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
+
+    shaderSourceLibrary.LoadShader(2, "KirschCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
+    shaderSourceLibrary.LoadShader(3, "PureCopyCs.glsl", SH_SHADER_TYPE::COMPUTE, true);
+
+    shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
+    auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
+    auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
+    auto greyscale = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
+    auto pureCopy = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
+    cubeVS->Reflect();
+    cubeFS->Reflect();
+    greyscale->Reflect();
+    pureCopy->Reflect();
   }
 
   void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@@ -130,6 +151,7 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     auto windowDims = window->GetWindowSize();
 
+    auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
 
     // Set Up Cameras
     screenCamera = resourceManager.Create<SHCamera>();
@@ -154,21 +176,32 @@ namespace SHADE
 
     // Initialize world render graph
     worldRenderGraph->Init(device, swapchain);
-    worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT }, windowDims.first, windowDims.second);
-    worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
-    worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
+    worldRenderGraph->AddResource("Scene Pre-Process",   { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
+    worldRenderGraph->AddResource("Scene",               { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
+    worldRenderGraph->AddResource("Depth Buffer",        { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
+    worldRenderGraph->AddResource("Entity ID",           { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
+    worldRenderGraph->AddResource("Light Layer Indices", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
 
-    auto node = worldRenderGraph->AddNode("G-Buffer", { "Entity ID", "Depth Buffer", "Scene"}, {}); // no predecessors
+    auto gBufferNode = worldRenderGraph->AddNode("G-Buffer", { "Light Layer Indices", "Entity ID", "Depth Buffer", "Scene", "Scene Pre-Process"}, {}); // no predecessors
+    auto gBufferSubpass = gBufferNode->AddSubpass("G-Buffer Write");
+    gBufferSubpass->AddColorOutput("Scene Pre-Process");
+    gBufferSubpass->AddColorOutput("Entity ID");
+    gBufferSubpass->AddColorOutput("Light Layer Indices");
+    gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
 
-     //First subpass to write to G-Buffer
-    auto gBufferWriteSubpass = node->AddSubpass("G-Buffer Write");
-    gBufferWriteSubpass->AddColorOutput("Scene");
-    gBufferWriteSubpass->AddColorOutput("Entity ID");
-    gBufferWriteSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
+    //// kirsch
+    //auto kirschShader = shaderModuleLibrary.GetShaderModule("KirschCs.glsl");
+    //gBufferNode->AddNodeCompute(kirschShader, { "Scene Pre-Process", "Scene" });
+
+    // copy
+    auto pureCopyShader = shaderModuleLibrary.GetShaderModule("PureCopyCs.glsl");
+    gBufferNode->AddNodeCompute(pureCopyShader, { "Scene Pre-Process", "Scene" });
+
+
+    auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, {"G-Buffer"}); // no predecessors
+    auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass");
+    dummySubpass->AddInput("Scene");
 
-    // We do this to just transition our scene layout to shader read
-    auto sceneLayoutTransitionSubpass = node->AddSubpass("Scene Layout Transition");
-    sceneLayoutTransitionSubpass->AddInput("Scene");
 
     // Generate world render graph
     worldRenderGraph->Generate();
@@ -177,20 +210,13 @@ namespace SHADE
     worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph);
     worldRenderer->SetCamera(worldCamera);
 
+    worldRenderer->SetCameraDirector(cameraSystem->CreateDirector());
 
-    // TODO: This is VERY temporarily here until a more solid resource management system is implemented
-    shaderSourceLibrary.Init("../../TempShaderFolder/");
-
-    shaderSourceLibrary.LoadShader(0, "TestCubeVs.glsl", SH_SHADER_TYPE::VERTEX, true);
-    shaderSourceLibrary.LoadShader(1, "TestCubeFs.glsl", SH_SHADER_TYPE::FRAGMENT, true);
-
-    shaderModuleLibrary.ImportFromSourceLibrary(device, shaderSourceLibrary);
     auto cubeVS = shaderModuleLibrary.GetShaderModule("TestCubeVs.glsl");
     auto cubeFS = shaderModuleLibrary.GetShaderModule("TestCubeFs.glsl");
-    cubeVS->Reflect();
-    cubeFS->Reflect();
 
-    defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferWriteSubpass);
+    defaultMaterial = AddMaterial(cubeVS, cubeFS, gBufferSubpass);
+
   }
 
   void SHGraphicsSystem::InitMiddleEnd(void) noexcept
@@ -220,11 +246,15 @@ namespace SHADE
     for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
       cmdPools.push_back(renderContext.GetFrameData(i).cmdPoolHdls[0]);
 
+    // Mouse picking system for the editor (Will still run with editor disabled)
     mousePickSystem->Init(device, cmdPools, worldRenderGraph->GetRenderGraphResource("Entity ID"));
 
     // Register the post offscreen render to the system
     postOffscreenRender = resourceManager.Create<SHPostOffscreenRenderSystem>();
     postOffscreenRender->Init(device, worldRenderGraph->GetRenderGraphResource("Scene"), descPool);
+
+    lightingSubSystem = resourceManager.Create<SHLightingSubSystem>();
+    lightingSubSystem->Init(device, descPool);
   }
 
 #ifdef SHEDITOR
@@ -323,21 +353,7 @@ namespace SHADE
     
     auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
     
-#ifdef SHEDITOR
 
-    auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
-    if (editorSystem->editorState != SHEditor::State::PLAY)
-    {
-      worldRenderer->SetViewProjectionMatrix(SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix()));
-    }
-    else
-    {
-      // main camera
-    }
-
-#else
-    // main camera
-#endif
 
     // For every viewport 
     for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex)
@@ -356,11 +372,13 @@ namespace SHADE
         // Begin recording the command buffer
         currentCmdBuffer->BeginRecording();
 
+        // set viewport and scissor
         uint32_t w = static_cast<uint32_t>(viewports[vpIndex]->GetWidth());
         uint32_t h = static_cast<uint32_t>(viewports[vpIndex]->GetHeight());
         currentCmdBuffer->SetViewportScissor (static_cast<float>(w), static_cast<float>(h), w, h);
 
-        currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout());
+        // Force set the pipeline layout 
+        currentCmdBuffer->ForceSetPipelineLayout(SHGraphicsGlobalData::GetDummyPipelineLayout(), SH_PIPELINE_TYPE::GRAPHICS);
 
         // Bind all the buffers required for meshes
         for (auto& [buffer, bindingPoint] : MESH_DATA)
@@ -371,6 +389,8 @@ namespace SHADE
             currentCmdBuffer->BindIndexBuffer(buffer, 0);
         }
 
+        // Bind the descriptor set for lights
+        lightingSubSystem->Run(currentCmdBuffer, frameIndex);
 
         // Bind textures
         auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup();
@@ -380,16 +400,31 @@ namespace SHADE
           currentCmdBuffer->BindDescriptorSet
           (
             textureDescSet,
-            vk::PipelineBindPoint::eGraphics,
+            SH_PIPELINE_TYPE::GRAPHICS,
             0,
             texDynamicOffset
           );
         }
 
         // bind camera data
-        renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
+        //renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
 
-        // Draw first
+#ifdef SHEDITOR
+        if (renderers[renIndex] == worldRenderer)
+        {
+          auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
+          if (editorSystem->editorState != SHEditor::State::PLAY)
+            worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix()));
+          else
+            renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
+        }
+        else
+          renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
+#else
+        renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
+#endif
+
+        // Draw the scene
         renderers[renIndex]->Draw(frameIndex, descPool);
 
         // End the command buffer recording
@@ -665,10 +700,10 @@ namespace SHADE
         continue;
     
       // Remove from old material's SuperBatch
-      Handle<SHMaterial> prevMaterial = renderable.GetPrevMaterial();
+      Handle<SHMaterialInstance> prevMaterial = renderable.GetPrevMaterial();
       if (prevMaterial)
       {
-        Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
+        Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
         oldSuperBatch->Remove(&renderable);
       }
     
@@ -726,8 +761,8 @@ namespace SHADE
 
     auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
 #ifdef SHEDITOR
-    cameraSystem->GetEditorCamera()->SetWidth(resizeWidth);
-    cameraSystem->GetEditorCamera()->SetHeight(resizeHeight);
+    cameraSystem->GetEditorCamera()->SetWidth(static_cast<float>(resizeWidth));
+    cameraSystem->GetEditorCamera()->SetHeight(static_cast<float>(resizeHeight));
 #else
 
 #endif
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h
index 870325ac..ae93bd78 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h
@@ -32,6 +32,7 @@ of DigiPen Institute of Technology is prohibited.
 #include "../Textures/SHTextureLibrary.h"
 #include "../Textures/SHVkSamplerCache.h"
 #include "Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h"
+#include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h"
 
 namespace SHADE
 {
@@ -351,6 +352,7 @@ namespace SHADE
     // Sub systems
     Handle<SHMousePickSystem>                                 mousePickSystem;
     Handle<SHPostOffscreenRenderSystem>                       postOffscreenRender;
+    Handle<SHLightingSubSystem>                               lightingSubSystem;
 
     uint32_t                                                  resizeWidth;
     uint32_t                                                  resizeHeight;
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h
new file mode 100644
index 00000000..8ba5adf8
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "ECS_Base/SHECSMacros.h"
+
+namespace SHADE
+{
+  struct SHInstancedIntegerData
+  {
+    EntityID eid;
+    uint32_t lightLayer;
+  };
+}
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.cpp
index 57a08d47..46126ae1 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMousePickSystem.cpp
@@ -7,6 +7,7 @@
 #include "Graphics/Buffers/SHVkBuffer.h"
 #include "Graphics/SHVkUtil.h"
 #include "Graphics/MiddleEnd/Interface/SHViewport.h"
+//#include "Graphics/MiddleEnd/Interface/SHInstancedIntegerData.h"
 
 namespace SHADE
 {
@@ -53,7 +54,7 @@ namespace SHADE
       // wait for the copy to be done
       afterCopyFence->Wait(true, std::numeric_limits<uint64_t>::max());
 
-      pickedEID = imageDataDstBuffer->GetDataFromMappedPointer<uint32_t>(static_cast<uint32_t>(viewportMousePos.y) * entityIDAttachment->GetWidth() + static_cast<uint32_t>(viewportMousePos.x));
+      pickedEID = imageDataDstBuffer->GetDataFromMappedPointer<EntityID>(static_cast<uint32_t>(viewportMousePos.y) * entityIDAttachment->GetWidth() + static_cast<uint32_t>(viewportMousePos.x));
 
     }
   }
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp
index 0b1c1b66..7c4d0bb9 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.cpp
@@ -27,19 +27,22 @@ namespace SHADE
     sharedMaterial = {};
     material = {};
     oldMaterial = {};
+
+    lightLayer = 0;
   }
 
   void SHRenderable::OnDestroy()
   {
+    // Remove from SuperBatch
+    Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
+	superBatch->Remove(this);
+
+    // Free resources
     if (material)
     {
       material.Free();
       material = {};
     }
-
-    // Remove from SuperBatch
-    Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
-	superBatch->Remove(this);
   }
   
   /*-----------------------------------------------------------------------------------*/
@@ -51,20 +54,23 @@ namespace SHADE
     if (!material && sharedMaterial == materialInstance)
       return;
 
+    // Flag that material was changed
+    materialChanged = true;
+
     // Free copies of materials if any
     if (material)
     {
+      oldMaterial = material;
       material.Free();
       material = {};
     }
-
-    // Flag that material was changed
-	materialChanged = true;
-    if (sharedMaterial)
-	  oldMaterial = sharedMaterial->GetBaseMaterial();
+    else if (sharedMaterial)
+    {
+      oldMaterial = sharedMaterial;
+    }
 
     // Update the material
-    sharedMaterial = materialInstance;	
+    sharedMaterial = materialInstance;
   }
 
   Handle<SHMaterialInstance> SHRenderable::GetMaterial() const
@@ -87,6 +93,11 @@ namespace SHADE
     return material;
   }
 
+  uint8_t SHRenderable::GetLightLayer(void) const noexcept
+  {
+    return lightLayer;
+  }
+
   void SHRenderable::ResetChangedFlag()
   {
       materialChanged = false;
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h
index bc885ca2..75e42d60 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderable.h
@@ -55,7 +55,8 @@ namespace SHADE
       /* Getter Functions                                                              */
       /*-------------------------------------------------------------------------------*/
       bool WasMaterialChanged() const noexcept { return materialChanged; }
-      Handle<SHMaterial> GetPrevMaterial() const noexcept { return oldMaterial; }
+      Handle<SHMaterialInstance> GetPrevMaterial() const noexcept { return oldMaterial; }
+      uint8_t GetLightLayer (void) const noexcept;
 
       /*-------------------------------------------------------------------------------*/
       /* Batcher Dispatcher Functions                                                  */
@@ -74,7 +75,8 @@ namespace SHADE
       Handle<SHMaterialInstance> sharedMaterial;
       Handle<SHMaterialInstance> material;
       bool materialChanged = true;
-      Handle<SHMaterial> oldMaterial; 
+      Handle<SHMaterialInstance> oldMaterial; 
+      uint8_t lightLayer;
 	};
 }
 
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp
index 2532f308..962130be 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.cpp
@@ -21,6 +21,7 @@ of DigiPen Institute of Technology is prohibited.
 #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
 #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
 #include "Graphics/Buffers/SHVkBuffer.h"
+#include "Camera/SHCameraDirector.h"
 
 namespace SHADE
 {
@@ -65,6 +66,11 @@ namespace SHADE
     camera = _camera;
   }
 
+  void SHRenderer::SetCameraDirector(Handle<SHCameraDirector> director) noexcept
+  {
+    cameraDirector = director;
+  }
+
   /*-----------------------------------------------------------------------------------*/
   /* Drawing Functions                                                                 */
   /*-----------------------------------------------------------------------------------*/
@@ -75,17 +81,24 @@ namespace SHADE
 
   void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
   {
-    if (camera)
+    if (camera && cameraDirector)
     {
-      //cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix();
-      cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex);
-
-        std::array<uint32_t, 1> dynamicOffsets{ frameIndex * cameraDataAlignedSize };
-
-      cmdBuffer->BindDescriptorSet(cameraDescriptorSet, vk::PipelineBindPoint::eGraphics, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
+      UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix()));
     }
   }
 
+  void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept
+  {
+    SetViewProjectionMatrix(exteriorMatrix);
+
+    //cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix();
+    cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex);
+
+    std::array<uint32_t, 1> dynamicOffsets{ frameIndex * cameraDataAlignedSize };
+
+    cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
+  }
+
   void SHRenderer::UpdateCameraDataToBuffer(void) noexcept
   {
   }
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h
index dbd1e415..87cf8ee9 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHRenderer.h
@@ -40,6 +40,7 @@ namespace SHADE
     class SHGraphicsGlobalData;
     class SHVkDescriptorPool;
     class SHVkBuffer;
+    class SHCameraDirector;
 
     struct SHShaderCameraData
     {
@@ -71,12 +72,14 @@ namespace SHADE
         /* Camera Registration                                                         */
         /*-----------------------------------------------------------------------------*/
         void SetCamera(Handle<SHCamera> _camera);
+        void SetCameraDirector (Handle<SHCameraDirector> director) noexcept;
 
         /*-----------------------------------------------------------------------------*/
         /* Drawing Functions                                                           */
         /*-----------------------------------------------------------------------------*/
         void Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
-        void UpdateDataAndBind (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
+        void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
+        void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept;
         void UpdateCameraDataToBuffer (void) noexcept;
         void SetViewProjectionMatrix (SHMatrix const& vpMatrix) noexcept;
 
@@ -99,6 +102,8 @@ namespace SHADE
         Handle<SHVkDescriptorSetGroup>  cameraDescriptorSet;
         Handle<SHVkBuffer>              cameraBuffer;
 
+        Handle<SHCameraDirector>        cameraDirector;
+
         // we really only need 1 copy even though we need %swapchainImages copies for
         // GPU.
         SHShaderCameraData              cpuCameraData; 
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp
new file mode 100644
index 00000000..fd122334
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.cpp
@@ -0,0 +1,123 @@
+#include "SHpch.h"
+#include "SHLightComponent.h"
+
+namespace SHADE
+{
+
+
+  void SHLightComponent::OnCreate(void)
+  {
+    lightData.Reset();
+    SetType(SH_LIGHT_TYPE::DIRECTIONAL);
+    indexInBuffer = std::numeric_limits<uint32_t>::max();
+    active = true;
+    Unbind();
+  }
+
+
+  void SHLightComponent::OnDestroy(void)
+  {
+
+  }
+
+  void SHLightComponent::SetPosition(SHVec3 position) noexcept
+  {
+    lightData.position = position;
+    MakeDirty();
+  }
+
+
+  void SHLightComponent::SetType(SH_LIGHT_TYPE type) noexcept
+  {
+    lightData.type = type;
+    MakeDirty();
+  }
+
+
+  void SHLightComponent::SetDirection(SHVec3 direction) noexcept
+  {
+    lightData.direction = direction;
+    MakeDirty();
+  }
+
+
+  void SHLightComponent::SetDiffuseColor(SHVec4 diffuseColor) noexcept
+  {
+    lightData.diffuseColor = diffuseColor;
+    MakeDirty();
+  }
+
+  void SHLightComponent::ModifyLayer(uint8_t layerIndex, bool value) noexcept
+  {
+    if (value)
+      lightData.cullingMask |= (1u << layerIndex);
+    else
+      lightData.cullingMask &= ~(1u << layerIndex);
+
+    MakeDirty();
+  }
+
+
+  void SHLightComponent::SetAllLayers(void) noexcept
+  {
+    lightData.cullingMask = std::numeric_limits<uint32_t>::max();
+    MakeDirty();
+  }
+
+
+  void SHLightComponent::ClearAllLayers(void) noexcept
+  {
+    lightData.cullingMask = 0;
+    MakeDirty();
+  }
+
+  void SHLightComponent::MakeDirty(void) noexcept
+  {
+    dirty = true;
+  }
+
+  void SHLightComponent::ClearDirtyFlag(void) noexcept
+  {
+    dirty = false;
+  }
+
+  void SHLightComponent::Unbind(void) noexcept
+  {
+    bound = false;
+    MakeDirty();
+  }
+
+  void SHLightComponent::SetBound(uint32_t inIndexInBuffer) noexcept
+{
+    bound = true;
+    indexInBuffer = inIndexInBuffer;
+  }
+
+  void SHLightComponent::SetActive(bool flag) noexcept
+  {
+    MakeDirty();
+    active = flag;
+
+  }
+
+  SHLightData const& SHLightComponent::GetLightData(void) const noexcept
+  {
+    return lightData;
+  }
+
+  bool SHLightComponent::IsDirty(void) const noexcept
+  {
+    return dirty;
+  }
+
+  bool SHLightComponent::GetBound(void) const noexcept
+  {
+    return bound;
+  }
+
+  uint32_t SHLightComponent::GetIndexInBuffer(void) const noexcept
+  {
+    return indexInBuffer;
+  }
+
+}
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h
new file mode 100644
index 00000000..20ae3892
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightComponent.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "ECS_Base/Components/SHComponent.h"
+#include "SHLightData.h"
+
+namespace SHADE
+{
+
+  class SH_API SHLightComponent final : public SHComponent
+  {
+  private:
+    //! General data for the light. This will purely be CPU bound. Whatever gets sent to the
+    //! GPU depends on the type of the light. 
+    SHLightData lightData;
+
+    //! Since the lighting system is gonna be self contained and light weight, we store this
+    //! so that we only write this to the CPU buffer when this light component change, we don't 
+    //! rewrite everything. However we still write to the GPU buffer when everything changes.
+    uint32_t indexInBuffer;
+
+    //! If the light component changed some value we mark this true.
+    bool dirty;
+
+    //! If the light's data is already in the buffers, this will be set to true.
+    bool bound;
+
+    //! If the light is active, this is true.
+    bool active;
+  	
+  public:
+    /*-----------------------------------------------------------------------*/
+    /* LIFECYCLE FUNCTIONS                                                   */
+    /*-----------------------------------------------------------------------*/
+    void OnCreate  (void) override final;
+    void OnDestroy (void) override final;
+
+    /*-----------------------------------------------------------------------*/
+    /* SETTERS AND GETTERS                                                   */
+    /*-----------------------------------------------------------------------*/
+    void SetPosition     (SHVec3 position) noexcept;
+    void SetType         (SH_LIGHT_TYPE type) noexcept;
+    void SetDirection    (SHVec3 direction) noexcept;
+    void SetDiffuseColor (SHVec4 diffuseColor) noexcept;
+    void ModifyLayer     (uint8_t layerIndex, bool value) noexcept;
+    void SetAllLayers    (void) noexcept;
+    void ClearAllLayers  (void) noexcept;
+    void MakeDirty       (void) noexcept;
+    void ClearDirtyFlag  (void) noexcept;
+    void Unbind          (void) noexcept;
+    void SetBound        (uint32_t inIndexInBuffer) noexcept;
+    void SetActive       (bool flag) noexcept;
+    
+
+    SHLightData const& GetLightData     (void) const noexcept;
+    bool               IsDirty          (void) const noexcept;
+    bool               GetBound         (void) const noexcept;
+    uint32_t           GetIndexInBuffer (void) const noexcept;
+
+  };
+}
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.cpp
new file mode 100644
index 00000000..ba910408
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.cpp
@@ -0,0 +1,21 @@
+#include "SHpch.h"
+#include "SHLightData.h"
+
+namespace SHADE
+{
+  void SHLightData::Reset(void) noexcept
+  {
+    // no culling is done.
+    cullingMask = std::numeric_limits<uint32_t>::max();
+
+    // reset position to 0
+    position = SHVec3::Zero;
+
+    // direction just point in positive z axis
+    direction = SHVec3::Forward; 
+
+    // Diffuse color set to 1
+    diffuseColor = SHVec4::One;
+  }
+
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.h
new file mode 100644
index 00000000..607978a4
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightData.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "Math/Vector/SHVec3.h"
+#include "Math/Vector/SHVec4.h"
+
+namespace SHADE
+{
+  enum class SH_LIGHT_TYPE : uint32_t
+  {
+    DIRECTIONAL = 0,
+    POINT,
+    SPOT,
+    NUM_TYPES
+  };
+
+  /***************************************************************************/
+  /*!
+
+    \class
+      Every light will essentially be using this struct. However, when passing
+      light data over to the GPU, the light data will be split according to 
+      type for more optimal cache access.
+
+  */
+  /***************************************************************************/
+  struct SHLightData
+  {
+    //! position of the light
+    SHVec3 position;
+
+    //! Type of the light
+    SH_LIGHT_TYPE type;
+
+    //! direction of the light
+    SHVec3 direction;
+
+    //! Each bit in this 32 bit field will represent a layer. If the bit is set,
+    //! when a fragment is being evaluated, the shader will use the fragment's
+    //! layer value to AND with the light's. If result is 1, do lighting calculations.
+    uint32_t cullingMask;  
+
+    //! Diffuse color emitted by the light
+    SHVec4 diffuseColor;
+
+    void Reset (void) noexcept;
+    //! TODO: 
+    //! - Add cut off. (inner and outer).
+    //! - Add constant, linear and quadratic for attenuation
+    //! - Specular color if needed. see below.
+
+    //! Specular color
+    //SHVec4 specularColor;
+  };
+
+}
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp
new file mode 100644
index 00000000..8d9efe54
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.cpp
@@ -0,0 +1,431 @@
+#include "SHpch.h"
+#include "SHLightingSubSystem.h"
+#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
+#include "Tools/SHUtilities.h"
+#include "Graphics/Devices/SHVkLogicalDevice.h"
+#include "Graphics/Buffers/SHVkBuffer.h"
+#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
+#include "SHLightComponent.h"
+#include "ECS_Base/Managers/SHComponentManager.h"
+#include "SHLightComponent.h"
+
+namespace SHADE
+{
+  /***************************************************************************/
+  /*! 
+   
+    \brief
+      This function takes an address in the CPU container and writes light
+      component data to it. What gets written depends on the light type.
+    
+    \param address
+      The address to write to.
+
+    \param lightComp
+      The light component with the data to write from.
+
+    \param lightType
+      The type of the light
+   
+    \return 
+  
+  */ 
+  /***************************************************************************/
+  void SHLightingSubSystem::PerTypeData::WriteLightToAddress(void* address, SHLightComponent* lightComp) noexcept
+  {
+    auto const& lightData = lightComp->GetLightData();
+    switch (lightData.type)
+    {
+    case SH_LIGHT_TYPE::DIRECTIONAL:
+    {
+      SHDirectionalLightData* lightPtr = reinterpret_cast<SHDirectionalLightData*>(address);
+
+      lightPtr->cullingMask = lightData.cullingMask;
+      lightPtr->direction = lightData.direction;
+      lightPtr->diffuseColor = lightData.diffuseColor;
+      break;
+    }
+    case SH_LIGHT_TYPE::POINT:
+      break;
+    case SH_LIGHT_TYPE::SPOT:
+      break;
+    case SH_LIGHT_TYPE::NUM_TYPES:
+      break;
+    default:
+      break;
+
+    }
+  }
+
+  /***************************************************************************/
+  /*!
+
+    \brief
+      Initializes type, intermediate data and buffer. dirty will be true.
+
+    \param lightType
+      type of the light. 
+
+  */
+  /***************************************************************************/
+  void SHLightingSubSystem::PerTypeData::InitializeData(Handle<SHVkLogicalDevice> logicalDevice, SH_LIGHT_TYPE type) noexcept
+  {
+    // initialize the type
+    lightType = type;
+
+    // boilerplate
+    intermediateData = nullptr;
+
+    // initialize alignment
+    lightDataAlignmentSize = logicalDevice->PadSSBOSize(GetLightTypeSize(type));
+
+    // So create some data!
+    Expand(logicalDevice);
+  }
+
+  /***************************************************************************/
+  /*!
+  
+    \brief
+      Expands both the CPU container and the GPU buffer when the number of 
+      lights have exceeded the capacity. 
+    
+  */
+  /***************************************************************************/
+  void SHLightingSubSystem::PerTypeData::Expand(Handle<SHVkLogicalDevice> logicalDevice) noexcept
+  {
+    if (lightDataAlignmentSize == 0)
+    {
+      SHLOG_ERROR ("One of the types of lights have not been accounted for. Make sure lightDataAlignmentSize is not nullptr.");
+      return;
+    }
+
+    // we want to wait for the command buffers to finish using the buffers first
+    logicalDevice->WaitIdle();
+
+    // First time we are initializing lights
+    if (intermediateData == nullptr)
+    {
+      // max lights should start of at STARTING_NUM_LIGHTS lights
+      maxLights = STARTING_NUM_LIGHTS;
+      numLights = 0;
+
+      // Initialize the data for lights
+      intermediateData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * maxLights);
+
+      // We want to initialize 3 times the amount of data required.
+      dataBuffer = logicalDevice->CreateBuffer(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, nullptr, maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT);
+    }
+    else
+    {
+      // save old number of lights
+      uint32_t const OLD_MAX_LIGHTS = maxLights;
+
+      // before we increase the number of lights, create space to store old data.
+      std::unique_ptr<uint8_t[]> oldData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * OLD_MAX_LIGHTS);
+
+      // copy data over.
+      std::memcpy (oldData.get(), intermediateData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS);
+
+      // now we start to expand....
+
+      // double space for lights
+      maxLights *= 2;
+
+      // destroy old data and initialize container for double the amount of data.
+      intermediateData = std::make_unique<uint8_t[]>(lightDataAlignmentSize * maxLights);
+
+      // copy old data to new container
+      std::memcpy(intermediateData.get(), oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS);
+
+      // Resize the GPU buffer. TODO: Replace with Resize no copy here
+      dataBuffer->ResizeReplace(maxLights * lightDataAlignmentSize * SHGraphicsConstants::NUM_FRAME_BUFFERS, oldData.get(), lightDataAlignmentSize * OLD_MAX_LIGHTS);
+    }
+
+    
+  }
+
+  /***************************************************************************/
+  /*!
+  
+    \brief
+      Gets the size required to store data for a light type.
+    
+    \param type
+      Type of a light.
+   
+    \return 
+      Size required to store a light based on type.  
+
+  */
+  /***************************************************************************/
+  uint32_t SHLightingSubSystem::PerTypeData::GetLightTypeSize(SH_LIGHT_TYPE type) noexcept
+  {
+    switch (type)
+    {
+    case SH_LIGHT_TYPE::DIRECTIONAL:
+      // TOOD: Change after creating point light struct
+      return sizeof(SHDirectionalLightData);
+    case SH_LIGHT_TYPE::POINT:
+      return 4;
+    case SH_LIGHT_TYPE::SPOT:
+      // TOOD: Change after creating spot light struct
+      return 4; 
+    case SH_LIGHT_TYPE::NUM_TYPES:
+    default:
+      return 4;
+
+    }
+  }
+
+
+  Handle<SHVkBuffer> SHLightingSubSystem::PerTypeData::GetDataBuffer(void) const noexcept
+  {
+    return dataBuffer;
+  }
+
+
+  uint32_t SHLightingSubSystem::PerTypeData::GetAlignmentSize(void) const noexcept
+  {
+    return lightDataAlignmentSize;
+  }
+
+  uint32_t SHLightingSubSystem::PerTypeData::GetNumLights(void) const noexcept
+  {
+    return numLights;
+  }
+
+  uint32_t SHLightingSubSystem::PerTypeData::GetMaxLights(void) const noexcept
+  {
+    return maxLights;
+  }
+
+
+  /***************************************************************************/
+  /*!
+
+    \brief
+      This function takes in a light comp in the event that its data has not
+      been placed in the buffer yet. It also checks if the size of the buffer
+      is big enough to hold the new light. If the buffer is too small, expand
+      it.
+
+    \param lightComp
+      The light component to add.
+
+  */
+  /***************************************************************************/
+  void SHLightingSubSystem::PerTypeData::AddLight(Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept
+  {
+    if (unboundLight)
+    {
+      // capacity is full
+      if (numLights == maxLights)
+      {
+        // expand first
+        Expand(logicalDevice);
+
+        expanded = true;
+      }
+
+      // Now that the container is big enough, bind the new light
+
+      // Get address of write location
+      void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignmentSize * numLights);
+
+      // Write the light data to address
+      WriteLightToAddress(writeLocation, unboundLight);
+
+      // Set the light component to be bound to that location
+      unboundLight->SetBound(numLights);
+
+      // Increase light count
+      ++numLights;
+    }
+  }
+
+  /***************************************************************************/
+  /*! 
+   
+    \brief
+      Modify the data at a specific light address.
+    
+    \param lightComp
+      The light component to write.
+   
+  */ 
+  /***************************************************************************/
+  void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept
+  {
+    void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignmentSize * lightComp->GetIndexInBuffer());
+    WriteLightToAddress(writeLocation, lightComp);
+  }
+
+  void SHLightingSubSystem::PerTypeData::WriteToGPU(uint32_t frameIndex) noexcept
+  {
+    if (intermediateData)
+    {
+      // we want to write to the offset of the current frame
+      dataBuffer->WriteToMemory(intermediateData.get(), lightDataAlignmentSize * numLights, 0, lightDataAlignmentSize * maxLights * frameIndex);
+    }
+  }
+
+  /***************************************************************************/
+  /*! 
+   
+    \brief
+      Update descriptor sets. We want to call this every time we expand buffers.
+    
+    \param binding
+      The binding in the set we want to update.
+   
+  */ 
+  /***************************************************************************/
+  void SHLightingSubSystem::UpdateDescSet(uint32_t binding) noexcept
+  {
+    auto buffer = perTypeData[binding].GetDataBuffer();
+
+    // We bind the buffer with the correct desc set binding
+    lightingDataDescSet->ModifyWriteDescBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS,
+      binding,
+      { &buffer, 1 },
+      0,
+      perTypeData[binding].GetAlignmentSize() * perTypeData[binding].GetMaxLights());
+
+    lightingDataDescSet->UpdateDescriptorSetBuffer(SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, binding);
+  }
+
+  /***************************************************************************/
+  /*!
+
+    \brief
+      Computes dynamic offsets.
+
+  */
+  /***************************************************************************/
+  void SHLightingSubSystem::ComputeDynamicOffsets(void) noexcept
+  {
+    for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
+    {
+      for (uint32_t j = 0; j < dynamicOffsets.size(); ++j)
+      {
+        auto const& typeData = perTypeData[j];
+        {
+          dynamicOffsets[i][j] = j * typeData.GetAlignmentSize() * typeData.GetMaxLights();
+        }
+      }
+    }
+  }
+
+  /***************************************************************************/
+  /*!
+  
+    \brief
+      Initializes per light type data. This includes buffers and descriptor
+      sets.
+    
+  
+  */
+  /***************************************************************************/
+  void SHLightingSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept
+  {
+    SHComponentManager::CreateComponentSparseSet<SHLightComponent>();
+
+    logicalDevice = device;
+    uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES);
+
+    std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES };
+    std::fill (variableSizes.begin(), variableSizes.end(), 1);
+
+    // Create the descriptor set
+    lightingDataDescSet = descPool->Allocate({SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS]}, variableSizes);
+
+
+    for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i)
+    {
+      // initialize all the data first. We add more lights here as we add more types.
+      perTypeData[i].InitializeData(logicalDevice, static_cast<SH_LIGHT_TYPE>(i));
+      UpdateDescSet(i);
+    }
+
+    for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
+    {
+    	dynamicOffsets[i].resize(NUM_LIGHT_TYPES);
+    }
+  }
+
+  /***************************************************************************/
+  /*!
+  
+    \brief
+      Loops through every single light component and checks for dirty light
+      data. If light data is dirty, rewrite to the CPU container. We also want
+      to bind the descriptor set for the light data.
+    
+  */
+  /***************************************************************************/
+  void SHLightingSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
+  {
+    auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
+    bool expanded = false;
+    for (auto& light : lightComps)
+    {
+      auto enumValue = SHUtilities::ToUnderlying(light.GetLightData().type);
+
+      // First we want to make sure the light is already bound to the system. if it
+      // isn't, we write it to the correct buffer.
+      if (!light.GetBound())
+      {
+        perTypeData[enumValue].AddLight(logicalDevice, &light, expanded);
+      }
+
+      // if there was modification to the light data
+      if (light.IsDirty())
+      {
+        // Write the data to the CPU 
+        perTypeData[enumValue].ModifyLight(&light);
+
+        // Light is now updated in the container
+        light.ClearDirtyFlag();
+      }
+    }
+
+    // Write data to GPU
+    for (auto& data : perTypeData)
+    {
+    	data.WriteToGPU(frameIndex);
+    }
+
+    // If any of the buffers got expanded, the descriptor set is invalid because the expanded buffer
+    // is a new buffer. If some expansion was detected, update descriptor sets.
+    if (expanded)
+    {
+      uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES);
+      for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i)
+      {
+      	UpdateDescSet(i);
+      }
+    }
+    
+    // compute dynamic offsets. We don't actually have to compute every frame but its pretty lightweight,
+    // so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing.
+    ComputeDynamicOffsets();
+
+    // Bind descriptor set (We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data).
+    cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, {dynamicOffsets[frameIndex]});
+
+  }
+
+  /***************************************************************************/
+  /*!
+  
+    \brief
+      Does nothing for now.
+    
+  */
+  /***************************************************************************/
+  void SHLightingSubSystem::Exit(void) noexcept
+  {
+
+  }
+}
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h
new file mode 100644
index 00000000..e5336b4e
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Lights/SHLightingSubSystem.h
@@ -0,0 +1,124 @@
+#pragma once
+
+#include "Resource/SHHandle.h"
+#include "Math/Vector/SHVec3.h"
+#include "Math/Vector/SHVec4.h"
+#include "SHLightData.h"
+#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
+
+namespace SHADE
+{
+  class SHVkLogicalDevice;
+  class SHVkDescriptorPool;
+  class SHVkDescriptorSetGroup;
+  class SHVkDescriptorSetLayout;
+  class SHVkBuffer;
+  class SHLightComponent;
+  class SHVkCommandBuffer;
+
+  // Represents how the data will be interpreted in GPU. we want to copy to a container of these before passing to GPU.
+  struct SHDirectionalLightData
+  {
+    //! Direction of the light
+    SHVec3 direction;
+
+    //! Represents if the light is active or not
+    uint32_t active;
+
+    //! Each bit in this 32 bit field will represent a layer. If the bit is set,
+    //! when a fragment is being evaluated, the shader will use the fragment's
+    //! layer value to AND with the light's. If result is 1, do lighting calculations.
+    uint32_t cullingMask;
+
+    //! Diffuse color emitted by the light
+    SHVec4 diffuseColor;
+
+  };
+
+  class SH_API SHLightingSubSystem
+  {
+  private:
+
+    class PerTypeData
+    {
+    private:
+      /*-----------------------------------------------------------------------*/
+      /* STATIC MEMBER VARIABLES                                               */
+      /*-----------------------------------------------------------------------*/
+      static constexpr uint32_t STARTING_NUM_LIGHTS = 20;
+
+      /*-----------------------------------------------------------------------*/
+      /* PRIVATE MEMBER VARIABLES                                              */
+      /*-----------------------------------------------------------------------*/
+      //! Capacity of the container. 
+      uint32_t                   maxLights;
+
+      //! SSBOs need to be aligned. This is to pad lighting structs
+      uint32_t                   lightDataAlignmentSize;
+
+      //! type of the light. Will be used later when we want to expand
+      SH_LIGHT_TYPE              lightType;
+
+      //! number of lights currently alive.
+      uint32_t                   numLights;
+
+      //! GPU buffer required to store GPU data
+      Handle<SHVkBuffer>         dataBuffer;
+
+      //! Before data gets copied to the GPU, it goes into here first. Data here is aligned to whatever struct is
+      //! used to represent data in this container. Note this will store only 1 copy of all the lights, compared
+      //! to the GPU that stores NUM_FRAME_BUFFERS copies. 
+      std::unique_ptr<uint8_t[]> intermediateData;
+
+      void WriteLightToAddress (void* address, SHLightComponent* lightComp) noexcept;
+    public:
+      /*-----------------------------------------------------------------------*/
+      /* PUBLIC MEMBER FUNCTIONS                                               */
+      /*-----------------------------------------------------------------------*/
+      void InitializeData (Handle<SHVkLogicalDevice> logicalDevice, SH_LIGHT_TYPE type) noexcept;
+      void Expand         (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
+      void AddLight       (Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept;
+      void ModifyLight    (SHLightComponent* lightComp) noexcept;
+      void WriteToGPU     (uint32_t frameIndex) noexcept;
+
+      /*-----------------------------------------------------------------------*/
+      /* GETTERS                                                               */
+      /*-----------------------------------------------------------------------*/
+      static uint32_t    GetLightTypeSize (SH_LIGHT_TYPE type) noexcept;
+      Handle<SHVkBuffer> GetDataBuffer    (void) const noexcept;
+      uint32_t           GetAlignmentSize (void) const noexcept;
+      uint32_t           GetNumLights     (void) const noexcept;
+      uint32_t           GetMaxLights     (void) const noexcept;
+    };
+
+  private:
+
+    //! logical device used for creation
+    Handle<SHVkLogicalDevice>                                                 logicalDevice;
+
+    //! The descriptor set that will hold the lighting data. Each binding will hold a buffer, NUM_FRAMES times the size required.
+    Handle<SHVkDescriptorSetGroup>                                            lightingDataDescSet;
+
+    //! Each type will have some data associated with it for processing
+    std::array<PerTypeData, static_cast<uint32_t>(SH_LIGHT_TYPE::NUM_TYPES)>  perTypeData;
+
+    //! Container to store dynamic offsets for binding descriptor sets
+    std::array<std::vector<uint32_t>, static_cast<uint32_t>(SHGraphicsConstants::NUM_FRAME_BUFFERS)> dynamicOffsets;
+
+    /*-----------------------------------------------------------------------*/
+    /* PRIVATE MEMBER FUNCTIONS                                              */
+    /*-----------------------------------------------------------------------*/
+    void UpdateDescSet         (uint32_t binding) noexcept;
+    void ComputeDynamicOffsets (void) noexcept;
+
+  public:
+
+    /*-----------------------------------------------------------------------*/
+    /* PUBLIC MEMBER FUNCTIONS                                               */
+    /*-----------------------------------------------------------------------*/
+    void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept;
+    void Run (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
+    void Exit (void) noexcept;
+
+  };
+}
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp
index 682b549c..495a3d37 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.cpp
@@ -8,7 +8,7 @@
 namespace SHADE
 {
   
-  Handle<SHVkPipeline> SHPipelineLibrary::CreateDrawPipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass) noexcept
+  Handle<SHVkPipeline> SHPipelineLibrary::CreateGraphicsPipelines(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHVkRenderpass> renderpass, Handle<SHSubpass> subpass) noexcept
   {
     SHPipelineLayoutParams params
     {
@@ -52,7 +52,7 @@ namespace SHADE
     newPipeline->ConstructPipeline();
 
     // Emplace the new pipeline
-    pipelines.emplace (vsFsPair, newPipeline);
+    graphicsPipelines.emplace (vsFsPair, newPipeline);
 
     return newPipeline;
   }
@@ -62,19 +62,19 @@ namespace SHADE
     logicalDevice = device;
   }
 
-  Handle<SHVkPipeline> SHPipelineLibrary::GetDrawPipline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
+  Handle<SHVkPipeline> SHPipelineLibrary::GetGraphicsPipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
   {
     // return the pipeline requested for
-    if (pipelines.contains(vsFsPair))
-      return pipelines.at(vsFsPair);
+    if (graphicsPipelines.contains(vsFsPair))
+      return graphicsPipelines.at(vsFsPair);
     else
       return {};
   }
 
-  bool SHPipelineLibrary::CheckDrawPipelineExistence(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
+  bool SHPipelineLibrary::CheckGraphicsPipelineExistence(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept
   {
     // Returns if a pipeline exists or not
-    return pipelines.contains(vsFsPair);
+    return graphicsPipelines.contains(vsFsPair);
   }
 
 }
\ No newline at end of file
diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h
index 9a411d25..aeb023c5 100644
--- a/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h
+++ b/SHADE_Engine/src/Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h
@@ -23,19 +23,19 @@ namespace SHADE
     Handle<SHVkLogicalDevice> logicalDevice;
 
     //! a map of pipelines that are hashed using a pair of shader module handles
-    std::unordered_map<std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>>, Handle<SHVkPipeline>> pipelines;
+    std::unordered_map<std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>>, Handle<SHVkPipeline>> graphicsPipelines;
     
   public:
     void Init (Handle<SHVkLogicalDevice> device) noexcept;
     
     // Draw pipeline functions. used only when creating pipelines for drawing using a vertex and fragment shader
-    Handle<SHVkPipeline> CreateDrawPipeline         (
+    Handle<SHVkPipeline> CreateGraphicsPipelines         (
                                                      std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair,
                                                      Handle<SHVkRenderpass>                                               renderpass,
                                                      Handle<SHSubpass>                                                    subpass
                                                     ) noexcept;
-    Handle<SHVkPipeline> GetDrawPipline             (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
-    bool                 CheckDrawPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
+    Handle<SHVkPipeline> GetGraphicsPipeline             (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
+    bool                 CheckGraphicsPipelineExistence (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair) noexcept;
 
   };
 }
diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp
index f8934bf6..c7ada11f 100644
--- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp
+++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineState.cpp
@@ -142,6 +142,12 @@ namespace SHADE
 
     case SHAttribFormat::UINT32_1D:
       return std::make_tuple(1, 4, vk::Format::eR32Uint);
+    case SHAttribFormat::UINT32_2D:
+      return std::make_tuple(1, 8, vk::Format::eR32G32Uint);
+    case SHAttribFormat::UINT32_3D:
+      return std::make_tuple(1, 12, vk::Format::eR32G32B32Uint);
+    case SHAttribFormat::UINT32_4D:
+      return std::make_tuple(1, 16, vk::Format::eR32G32B32A32Uint);
     }
     return std::make_tuple(0, 0, vk::Format::eR32Sfloat);
   }
diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h
index e7f5b6a8..2c1c80ff 100644
--- a/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h
+++ b/SHADE_Engine/src/Graphics/Pipeline/SHPipelineType.h
@@ -5,9 +5,13 @@ namespace SHADE
 {
   enum class SH_PIPELINE_TYPE
   {
-    GRAPHICS,
+    GRAPHICS = 0,
     COMPUTE,
+    RAY_TRACING,
+    NUM_TYPES,
   };
+
+  
 }
 
 #endif
\ No newline at end of file
diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp
index c03fd2a7..973ae72f 100644
--- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp
+++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.cpp
@@ -4,6 +4,7 @@
 #include "Graphics/Shaders/SHVkShaderModule.h"
 #include "Graphics/Debugging/SHVulkanDebugUtil.h"
 #include "Graphics/RenderGraph/SHRenderGraph.h"
+#include "Graphics/SHVkUtil.h"
 
 namespace SHADE
 {
@@ -171,6 +172,29 @@ namespace SHADE
   
   void SHVkPipeline::CreateComputePipeline(void) noexcept
   {
+    auto shaderModule = pipelineLayout->GetShaderModules()[0];
+
+    vk::PipelineShaderStageCreateInfo shaderStageCreateInfo
+    {
+      .stage = vk::ShaderStageFlagBits::eCompute,
+      .module = shaderModule->GetVkShaderModule(),
+      .pName = shaderModule->GetEntryPoint().c_str(),
+    };
+
+    vk::ComputePipelineCreateInfo cpCreateInfo
+    {
+      .flags = {},
+      .stage = shaderStageCreateInfo,
+      .layout = pipelineLayout->GetVkPipelineLayout(),
+    };
+
+    if (auto result = logicalDeviceHdl->GetVkLogicalDevice().createComputePipelines({}, 1, &cpCreateInfo, nullptr, &vkPipeline); result != vk::Result::eSuccess)
+      SHVulkanDebugUtil::ReportVkError(result, "Failed to create Compute Pipeline. ");
+    else
+    {
+      SHVulkanDebugUtil::ReportVkSuccess("Successfully created a Compute Pipeline. ");
+      created = true;
+    }
 
   }
 
@@ -245,7 +269,7 @@ namespace SHADE
     , logicalDeviceHdl{ rhs.logicalDeviceHdl }
     , pipelineLayout { rhs.pipelineLayout }
   {
-    vkPipeline = VK_NULL_HANDLE;
+    rhs.vkPipeline = VK_NULL_HANDLE;
   }
 
   /***************************************************************************/
@@ -285,7 +309,8 @@ namespace SHADE
   /***************************************************************************/
   SHVkPipeline::~SHVkPipeline(void) noexcept
   {
-    logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr);
+    if (vkPipeline)
+      logicalDeviceHdl->GetVkLogicalDevice().destroyPipeline(vkPipeline, nullptr);
   }
 
   /***************************************************************************/
@@ -313,7 +338,7 @@ namespace SHADE
     created = rhs.created;
     logicalDeviceHdl = rhs.logicalDeviceHdl;
 
-    vkPipeline = VK_NULL_HANDLE;
+    rhs.vkPipeline = VK_NULL_HANDLE;
 
     return *this;
   }
@@ -399,18 +424,7 @@ namespace SHADE
   /***************************************************************************/
   vk::PipelineBindPoint SHVkPipeline::GetPipelineBindPoint(void) const noexcept
   {
-    switch (pipelineType)
-    {
-    case SH_PIPELINE_TYPE::GRAPHICS:
-      return vk::PipelineBindPoint::eGraphics;
-    case SH_PIPELINE_TYPE::COMPUTE:
-      return vk::PipelineBindPoint::eCompute;
-      break;
-    default:
-      return vk::PipelineBindPoint::eGraphics;
-      break;
-
-    }
+    return SHVkUtil::GetPipelineBindPointFromType(pipelineType);
   }
 
   /***************************************************************************/
@@ -450,4 +464,9 @@ namespace SHADE
     return pipelineLayout;
   }
 
+  SH_PIPELINE_TYPE SHVkPipeline::GetPipelineType(void) const noexcept
+  {
+    return pipelineType;
+  }
+
 }
\ No newline at end of file
diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h
index 1103d3d0..7378cc48 100644
--- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h
+++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipeline.h
@@ -77,6 +77,7 @@ namespace SHADE
     vk::Pipeline               GetVkPipeline        (void) const noexcept;
     bool                       GetIsCreated         (void) const noexcept;
     Handle<SHVkPipelineLayout> GetPipelineLayout    (void) const noexcept;
+    SH_PIPELINE_TYPE           GetPipelineType      (void) const noexcept;
   };
 }
 
diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp
index 7a76447d..37d00795 100644
--- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp
+++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp
@@ -216,9 +216,18 @@ namespace SHADE
   /***************************************************************************/
   void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept
   {
+    // pipeline layouts contain global layouts first, then layouts for allocation
     descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
+    vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
 
-    // Settle allocate layouts first
+    // First we insert the global layouts
+    for (auto const& layout : descriptorSetLayoutsGlobal)
+    {
+      descriptorSetLayoutsPipeline.emplace_back(layout);
+      //vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle());
+    }
+
+    // Then the allocate layouts
     vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size());
     for (auto const& layout : descriptorSetLayoutsAllocate)
     {
@@ -226,18 +235,13 @@ namespace SHADE
       vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle());
     }
 
-    // pipeline layouts contain global layouts first, then layouts for allocation
-    vkDescriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size());
-
-    // First we insert the global layouts
-    for (auto const& layout : descriptorSetLayoutsGlobal)
+    for (auto const& layout : descriptorSetLayoutsPipeline)
     {
-      descriptorSetLayoutsPipeline.emplace_back(layout);
       vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle());
     }
 
     // Then we append layouts for allocation at the back of the vector
-    std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline));
+    //std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline));
   }
 
   /***************************************************************************/
@@ -294,6 +298,7 @@ namespace SHADE
     , descriptorSetLayoutsGlobal{pipelineLayoutParams.globalDescSetLayouts } // do a copy, some other pipeline layout might need this
     , descriptorSetLayoutsAllocate{}
     , vkDescriptorSetLayoutsAllocate{}
+    , descriptorSetLayoutsPipeline{}
     , vkDescriptorSetLayoutsPipeline{}
   {
     for (auto& mod : shaderModules)
@@ -318,6 +323,7 @@ namespace SHADE
     , descriptorSetLayoutsGlobal{} 
     , descriptorSetLayoutsAllocate{}
     , vkDescriptorSetLayoutsAllocate{}
+    , descriptorSetLayoutsPipeline{}
     , vkDescriptorSetLayoutsPipeline{}
 
   {
@@ -368,7 +374,8 @@ namespace SHADE
     , descriptorSetLayoutsGlobal    {std::move (rhs.descriptorSetLayoutsGlobal)}
     , descriptorSetLayoutsAllocate  {std::move (rhs.descriptorSetLayoutsAllocate)}
     , vkDescriptorSetLayoutsAllocate{std::move (rhs.vkDescriptorSetLayoutsAllocate)}
-    , vkDescriptorSetLayoutsPipeline{std::move (rhs.vkDescriptorSetLayoutsAllocate)}
+    , descriptorSetLayoutsPipeline  { std::move(rhs.descriptorSetLayoutsPipeline) }
+    , vkDescriptorSetLayoutsPipeline{ std::move(rhs.vkDescriptorSetLayoutsPipeline) }
   {
     rhs.vkPipelineLayout = VK_NULL_HANDLE;
   }
@@ -441,12 +448,12 @@ namespace SHADE
     return {};
   }
 
-  std::vector<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept
+  std::vector<Handle<SHVkDescriptorSetLayout>> const& SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept
   {
     return descriptorSetLayoutsPipeline;
   }
 
-  std::vector<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept
+  std::vector<Handle<SHVkDescriptorSetLayout>> const& SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept
   {
     return descriptorSetLayoutsAllocate;
   }
@@ -464,7 +471,8 @@ namespace SHADE
     descriptorSetLayoutsGlobal     = std::move(rhs.descriptorSetLayoutsGlobal);
     descriptorSetLayoutsAllocate   = std::move(rhs.descriptorSetLayoutsAllocate);
     vkDescriptorSetLayoutsAllocate = std::move(rhs.vkDescriptorSetLayoutsAllocate);
-    vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsAllocate);
+    descriptorSetLayoutsPipeline   = std::move(rhs.descriptorSetLayoutsPipeline);
+    vkDescriptorSetLayoutsPipeline = std::move(rhs.vkDescriptorSetLayoutsPipeline);
 
     rhs.vkPipelineLayout = VK_NULL_HANDLE;
 
diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h
index f5d363fa..b4298e00 100644
--- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h
+++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h
@@ -74,12 +74,12 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     /* SETTERS AND GETTERS                                                   */
     /*-----------------------------------------------------------------------*/
-    std::vector<Handle<SHVkShaderModule>> const& GetShaderModules                (void) const noexcept;
-    vk::PipelineLayout                           GetVkPipelineLayout             (void) const noexcept;
-    SHPushConstantInterface const&               GetPushConstantInterface        (void) const noexcept;
-    Handle<SHShaderBlockInterface>               GetShaderBlockInterface         (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept;
-    std::vector<Handle<SHVkDescriptorSetLayout>> GetDescriptorSetLayoutsPipeline(void) const noexcept;
-    std::vector<Handle<SHVkDescriptorSetLayout>> GetDescriptorSetLayoutsAllocate(void) const noexcept;
+    std::vector<Handle<SHVkShaderModule>> const&        GetShaderModules                (void) const noexcept;
+    vk::PipelineLayout                                  GetVkPipelineLayout             (void) const noexcept;
+    SHPushConstantInterface const&                      GetPushConstantInterface        (void) const noexcept;
+    Handle<SHShaderBlockInterface>                      GetShaderBlockInterface         (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept;
+    std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescriptorSetLayoutsPipeline(void) const noexcept;
+    std::vector<Handle<SHVkDescriptorSetLayout>> const& GetDescriptorSetLayoutsAllocate(void) const noexcept;
   };
 }
 
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h
index 241292d4..c4d44ea8 100644
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHAttachmentDescriptionType.h
@@ -10,6 +10,8 @@ namespace SHADE
     DEPTH = 0x04,
     STENCIL = 0x08,
     DEPTH_STENCIL = 0x10,
-    INPUT = 0x20
+    INPUT = 0x20,
+    STORAGE = 0x40
   };
+
 }
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp
index 0bc2c98b..93be2413 100644
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp
@@ -9,6 +9,8 @@
 #include "Graphics/Buffers/SHVkBuffer.h"
 #include "Tools/SHLogger.h"
 #include "SHAttachmentDescInitParams.h"
+#include "SHRenderGraphStorage.h"
+#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
 
 namespace SHADE
 {
@@ -52,12 +54,12 @@ namespace SHADE
     // If we set to 
     if (w == static_cast<uint32_t>(-1) && h == static_cast<uint32_t>(-1))
     {
-      w = swapchainHdl->GetSwapchainImage(0)->GetWidth();
-      h = swapchainHdl->GetSwapchainImage(0)->GetHeight();
-      format = swapchainHdl->GetSurfaceFormatKHR().format;
+      w = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetWidth();
+      h = renderGraphStorage->swapchain->GetSwapchainImage(0)->GetHeight();
+      format = renderGraphStorage->swapchain->GetSurfaceFormatKHR().format;
     }
 
-    graphResources.try_emplace(resourceName, resourceManager->Create<SHRenderGraphResource>(logicalDeviceHdl, swapchainHdl, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags));
+    renderGraphStorage->graphResources->try_emplace(resourceName, resourceManager->Create<SHRenderGraphResource>(renderGraphStorage, resourceName, typeFlags, format, w, h, levels, usageFlags, createFlags));
   }
 
   /***************************************************************************/
@@ -77,36 +79,38 @@ namespace SHADE
 
     for (uint32_t i = 0; auto& node : nodes)
     {
-      // key is handle ID, value is pair (first is initial layout, second is final layout).
-      std::unordered_map<uint32_t, vk::ImageLayout> resourceAttLayouts;
+      // key is handle ID, value is final layout.
+      std::unordered_map<uint32_t, vk::ImageLayout> resourceAttFinalLayouts;
       if (node->subpasses.empty())
       {
         SHLOG_ERROR("Node does not contain a subpass. Cannot configure attachment descriptions as a result. ");
         return;
       }
 
+      // attempt to get all final layouts for all resources
       for (auto& subpass : node->subpasses)
       {
         for (auto& color : subpass->colorReferences)
         {
+          // If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass
           if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)))
-            resourceAttLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR;
+            resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR;
           else
-            resourceAttLayouts[color.attachment] = color.layout;
+            resourceAttFinalLayouts[color.attachment] = color.layout;
         }
 
         for (auto& depth : subpass->depthReferences)
-          resourceAttLayouts[depth.attachment] = depth.layout;
+          resourceAttFinalLayouts[depth.attachment] = depth.layout;
 
         for (auto& input : subpass->inputReferences)
-          resourceAttLayouts[input.attachment] = input.layout;
+          resourceAttFinalLayouts[input.attachment] = input.layout;
       }
 
       for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j)
       {
         auto& att = node->attachmentDescriptions[j];
         att.initialLayout = vk::ImageLayout::eUndefined;
-        att.finalLayout = resourceAttLayouts[j];
+        att.finalLayout = resourceAttFinalLayouts[j];
       }
       ++i;
     }
@@ -138,6 +142,9 @@ namespace SHADE
             attDesc.loadOp = vk::AttachmentLoadOp::eLoad;
             predAttDesc.storeOp = vk::AttachmentStoreOp::eStore;
 
+            attDesc.stencilLoadOp = vk::AttachmentLoadOp::eLoad;
+            attDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore;
+
             // TODO: Stencil load and store
 
             // When an image is done being used in a renderpass, the image layout will end up being the finalLayout
@@ -292,6 +299,9 @@ namespace SHADE
         dep.dstAccessMask = dstAccess;
 
         dep.srcStageMask = srcStage;
+
+        // initialize input descriptors
+        node->subpasses[i]->CreateInputDescriptors();
       }
     }
   }
@@ -343,10 +353,18 @@ namespace SHADE
 
   */
   /***************************************************************************/
-  void SHRenderGraph::Init(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept
+  void SHRenderGraph::Init(Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkSwapchain> swapchain) noexcept
   {
-    logicalDeviceHdl = logicalDevice;
-    swapchainHdl = swapchain;
+    resourceManager = std::make_shared<SHResourceHub>();
+
+    renderGraphStorage = resourceManager->Create<SHRenderGraphStorage>();
+    renderGraphStorage->graphResources = resourceManager->Create<std::unordered_map<std::string, Handle<SHRenderGraphResource>>>();
+
+    renderGraphStorage->logicalDevice = logicalDevice;
+    renderGraphStorage->swapchain = swapchain;
+
+    renderGraphStorage->resourceManager = resourceManager;
+    renderGraphStorage->descriptorPool = logicalDevice->CreateDescriptorPools();
   }
 
   /***************************************************************************/
@@ -361,24 +379,19 @@ namespace SHADE
   */
   /***************************************************************************/
   SHRenderGraph::SHRenderGraph(void) noexcept
-    : logicalDeviceHdl{ }
-    , swapchainHdl{ }
+    : renderGraphStorage{}
     , nodes{}
-    , graphResources{}
     , resourceManager{nullptr}
   {
-    resourceManager = std::make_shared<SHResourceHub>();
   }
 
   SHRenderGraph::SHRenderGraph(SHRenderGraph&& rhs) noexcept
-    : logicalDeviceHdl{ rhs.logicalDeviceHdl }
-    , swapchainHdl{ rhs.swapchainHdl }
+    : renderGraphStorage{ rhs.renderGraphStorage }
     , nodeIndexing{ std::move(rhs.nodeIndexing) }
     , nodes{ std::move(rhs.nodes) }
-    , graphResources{ std::move(rhs.graphResources) }
     , resourceManager{ std::move(rhs.resourceManager) }
   {
-
+    
   }
 
   SHRenderGraph& SHRenderGraph::operator=(SHRenderGraph&& rhs) noexcept
@@ -386,11 +399,9 @@ namespace SHADE
     if (&rhs == this)
       return *this;
 
-    logicalDeviceHdl = rhs.logicalDeviceHdl;
-    swapchainHdl = rhs.swapchainHdl;
+    renderGraphStorage = rhs.renderGraphStorage;
     nodeIndexing = std::move(rhs.nodeIndexing);
     nodes = std::move(rhs.nodes);
-    graphResources = std::move(rhs.graphResources);
     resourceManager = std::move(rhs.resourceManager);
 
     return *this;
@@ -426,12 +437,12 @@ namespace SHADE
     for (auto const& instruction : resourceInstruction)
     {
       // If the resource that the new node is requesting for exists, allow the graph to reference it
-      if (graphResources.contains(instruction.resourceName))
+      if (renderGraphStorage->graphResources->contains(instruction.resourceName))
       {
         descInitParams.push_back(
           {
-            .resourceHdl = graphResources.at(instruction.resourceName),
-            .dontClearOnLoad = false, 
+            .resourceHdl = renderGraphStorage->graphResources->at(instruction.resourceName),
+            .dontClearOnLoad = instruction.dontClearOnLoad, 
           }
         );
       }
@@ -456,7 +467,7 @@ namespace SHADE
       }
     }
 
-    nodes.emplace_back(resourceManager->Create<SHRenderGraphNode>(resourceManager, logicalDeviceHdl, swapchainHdl, std::move(descInitParams), std::move(predecessors), &graphResources));
+    nodes.emplace_back(resourceManager->Create<SHRenderGraphNode>(renderGraphStorage, std::move(descInitParams), std::move(predecessors)));
     nodeIndexing.emplace(nodeName, static_cast<uint32_t>(nodes.size()) - 1u);
     return nodes.at(nodeIndexing[nodeName]);
   }
@@ -476,12 +487,31 @@ namespace SHADE
   /***************************************************************************/
   void SHRenderGraph::Generate(void) noexcept
   {
+    CheckForNodeComputes();
     ConfigureAttachmentDescriptions();
     ConfigureSubpasses();
     ConfigureRenderpasses();
     ConfigureFramebuffers();
   }
 
+  /***************************************************************************/
+  /*!
+  
+    \brief
+      This function goes through all renderpasses and checks for existence of 
+      node computes. If they exist, adds dummy subpasses to transition resources
+      into general.
+    
+  */
+  /***************************************************************************/
+  void SHRenderGraph::CheckForNodeComputes(void) noexcept
+  {
+    for (auto& node : nodes)
+    {
+    	node->AddDummySubpassIfNeeded();
+    }
+  }
+
   // TODO: The graph scope buffers were meant to bind vertex buffers and index buffers for meshes. Find a 
   // better way to manage these 
   void SHRenderGraph::Execute(uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept
@@ -501,7 +531,7 @@ namespace SHADE
   void SHRenderGraph::HandleResize(uint32_t newWidth, uint32_t newHeight) noexcept
   {
     // resize resources
-    for (auto& [name, resource]: graphResources)
+    for (auto& [name, resource] : *renderGraphStorage->graphResources)
     	resource->HandleResize(newWidth, newHeight);
 
     for (auto& node : nodes)
@@ -521,9 +551,9 @@ namespace SHADE
 
   Handle<SHRenderGraphResource> SHRenderGraph::GetRenderGraphResource(std::string const& resourceName) const noexcept
   {
-    if (graphResources.contains(resourceName))
+    if (renderGraphStorage->graphResources->contains(resourceName))
     {
-      return graphResources.at(resourceName);
+      return renderGraphStorage->graphResources->at(resourceName);
     }
     return {};
   }
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h
index a919c4ff..d90b66df 100644
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h
@@ -30,7 +30,8 @@ namespace SHADE
   class SHVkCommandBuffer;
   class SHRenderGraphNode;
   class SHGraphicsGlobalData;
-
+  class SHVkDescriptorPool;
+  class SHRenderGraphStorage;
 
   class SH_API SHRenderGraph
   {
@@ -56,10 +57,8 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     /* PRIVATE MEMBER VARIABLES                                              */
     /*-----------------------------------------------------------------------*/
-    Handle<SHVkLogicalDevice> logicalDeviceHdl;
 
-    //! swapchain used for querying image count
-    Handle<SHVkSwapchain> swapchainHdl;
+    Handle<SHRenderGraphStorage> renderGraphStorage;
 
     //! For indexing render graph node container
     std::map<std::string, uint32_t> nodeIndexing;
@@ -67,9 +66,6 @@ namespace SHADE
     //! Render graph nodes
     std::vector<Handle<SHRenderGraphNode>> nodes;
 
-    //! Resources that exist for the entire render graph
-    std::unordered_map<std::string, Handle<SHRenderGraphResource>> graphResources;
-
     //! Resource library for graph handles
     std::shared_ptr<SHResourceHub> resourceManager;
 
@@ -85,14 +81,15 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     /* PUBLIC MEMBER FUNCTIONS                                               */
     /*-----------------------------------------------------------------------*/
-    void                      Init (Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain) noexcept;
+    void                      Init (Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkSwapchain> swapchain) noexcept;
     void                      AddResource(std::string resourceName, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, uint32_t w = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageUsageFlagBits usageFlags = {}, vk::ImageCreateFlagBits createFlags = {});
     Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<ResourceInstruction> resourceInstruction, std::initializer_list<std::string> predecessorNodes) noexcept;
     
-    void                      Generate     (void) noexcept;
-    void                      Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept;
-    void                      FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
-    void                      HandleResize (uint32_t newWidth, uint32_t newHeight) noexcept;
+    void                      Generate             (void) noexcept;
+    void                      CheckForNodeComputes (void) noexcept;
+    void                      Execute              (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkDescriptorPool> descPool) noexcept;
+    void                      FinaliseBatch        (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
+    void                      HandleResize         (uint32_t newWidth, uint32_t newHeight) noexcept;
 
     /*-----------------------------------------------------------------------*/
     /* SETTERS AND GETTERS                                                   */
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp
index 5950426e..c315bffd 100644
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp
@@ -6,6 +6,9 @@
 #include "Graphics/Framebuffer/SHVkFramebuffer.h"
 #include "SHRenderGraphResource.h"
 #include "SHSubpass.h"
+#include "SHRenderGraphStorage.h"
+#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
+#include "Graphics/SHVkUtil.h"
 
 namespace SHADE
 {
@@ -21,7 +24,7 @@ namespace SHADE
   /***************************************************************************/
   void SHRenderGraphNode::CreateRenderpass(void) noexcept
   {
-    renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
+    renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
   }
 
   /***************************************************************************/
@@ -53,7 +56,7 @@ namespace SHADE
       }
 
 
-      framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight);
+      framebuffers[i] = graphStorage->logicalDevice->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight);
     }
   }
 
@@ -79,9 +82,18 @@ namespace SHADE
           fbHeight = attResources[j]->height;
       }
 
-
       framebuffers[i]->HandleResize(renderpass, imageViews, fbWidth, fbHeight);
     }
+
+    for (auto& subpass : subpasses)
+    {
+    	subpass->HandleResize();
+    }
+
+    for (auto& nodeCompute : nodeComputes)
+    {
+    	nodeCompute->HandleResize();
+    }
   }
 
   /***************************************************************************/
@@ -104,8 +116,8 @@ namespace SHADE
 
   */
   /***************************************************************************/
-  SHRenderGraphNode::SHRenderGraphNode(std::shared_ptr<SHResourceHub> rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept
-    : logicalDeviceHdl{ logicalDevice }
+  SHRenderGraphNode::SHRenderGraphNode(Handle<SHRenderGraphStorage> renderGraphStorage, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors) noexcept
+    : graphStorage{ renderGraphStorage}
     , renderpass{}
     , framebuffers{}
     , prereqNodes{ std::move(predecessors) }
@@ -115,11 +127,10 @@ namespace SHADE
     , subpasses{}
     , executed{ false }
     , configured{ false }
-    , resourceManager{ rm }
-    , ptrToResources{ resources }
+    , nodeComputes{}
   {
     // pipeline library initialization
-    pipelineLibrary.Init(logicalDeviceHdl);
+    pipelineLibrary.Init(graphStorage->logicalDevice);
 
     // Store all the handles to resources
     attResources.reserve (attDescInitParams.size());
@@ -155,15 +166,14 @@ namespace SHADE
     if (!containsSwapchainImage)
       framebuffers.resize(1);
     else
-      framebuffers.resize(swapchain->GetNumImages());
+      framebuffers.resize(graphStorage->swapchain->GetNumImages());
 
     // At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be
     // deferred to when renderpasses are also created.
   }
 
   SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept
-    : resourceManager{ std::move (rhs.resourceManager) }
-    , logicalDeviceHdl{ rhs.logicalDeviceHdl }
+    : graphStorage{ rhs.graphStorage}
     , renderpass{ rhs.renderpass }
     , framebuffers{ std::move(rhs.framebuffers) }
     , prereqNodes{ std::move(rhs.prereqNodes) }
@@ -174,11 +184,11 @@ namespace SHADE
     , subpassIndexing{ std::move(rhs.subpassIndexing) }
     , configured{ rhs.configured }
     , executed{ rhs.executed }
-    , ptrToResources{ rhs.ptrToResources }
     , pipelineLibrary{ std::move(rhs.pipelineLibrary) }
     , batcher{ std::move(rhs.batcher) }
     , spDescs{ std::move(rhs.spDescs) }
     , spDeps{ std::move(rhs.spDeps) }
+    , nodeComputes{ std::move(rhs.nodeComputes) }
 
   {
     rhs.renderpass = {};
@@ -189,8 +199,7 @@ namespace SHADE
     if (&rhs == this)
       return *this;
 
-    resourceManager = std::move(rhs.resourceManager);
-    logicalDeviceHdl = rhs.logicalDeviceHdl;
+    graphStorage = rhs.graphStorage;
     renderpass = rhs.renderpass;
     framebuffers = std::move(rhs.framebuffers);
     prereqNodes = std::move(rhs.prereqNodes);
@@ -199,11 +208,11 @@ namespace SHADE
     subpasses = std::move(rhs.subpasses);
     resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping);
     subpassIndexing = std::move(rhs.subpassIndexing);
-    ptrToResources = std::move(rhs.ptrToResources);
     pipelineLibrary = std::move(rhs.pipelineLibrary);
     batcher = std::move(rhs.batcher);
     spDescs = std::move(rhs.spDescs);
     spDeps = std::move(rhs.spDeps);
+    nodeComputes = std::move(rhs.nodeComputes);
 
 
     rhs.renderpass = {};
@@ -235,10 +244,10 @@ namespace SHADE
     }
 
     // Add subpass to container and create mapping for it
-    subpasses.emplace_back(resourceManager->Create<SHSubpass>(GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources));
+    subpasses.emplace_back(graphStorage->resourceManager->Create<SHSubpass>(graphStorage, GetHandle(), static_cast<uint32_t>(subpasses.size()), &resourceAttachmentMapping));
     subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
     Handle<SHSubpass> subpass = subpasses.back();
-    subpass->Init(*resourceManager);
+    subpass->Init(*graphStorage->resourceManager);
 
     // Register the SuperBatch
     batcher.RegisterSuperBatch(subpass->GetSuperBatch());
@@ -246,21 +255,84 @@ namespace SHADE
     return subpass;
   }
 
+  Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale/* = 1.0f*/) noexcept
+  {
+    // Look for the required resources in the graph
+    std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{};
+    nodeComputeResources.reserve(resources.size());
+
+    for (auto& resourceName : resources)
+    {
+      auto resource = graphStorage->graphResources->at(resourceName);
+    	nodeComputeResources.push_back(resource);
+    }
+
+    // Create the subpass compute with the resources
+    auto nodeCompute = graphStorage->resourceManager->Create<SHRenderGraphNodeCompute>(graphStorage, computeShaderModule, std::move(nodeComputeResources));
+    nodeComputes.push_back(nodeCompute);
+
+    return nodeCompute;
+  }
+
+  /***************************************************************************/
+  /*!
+  
+    \brief
+      This function checks all node computes and adds a subpass to transition
+      all needed resources to general.
+    
+  */
+  /***************************************************************************/
+  void SHRenderGraphNode::AddDummySubpassIfNeeded(void) noexcept
+  {
+    if (!nodeComputes.empty())
+    {
+      // we save the resource names involved
+      std::unordered_set<std::string> resourcesInvolved;
+      for (auto& compute : nodeComputes)
+      {
+        for (auto& resource : compute->resources)
+        {
+          resourcesInvolved.emplace(resource->GetName());
+        }
+      }
+
+      // insert them all for a subpass to transition them. This subpass is the last subpass
+      auto dummySubpass = AddSubpass("dummy");
+      for (auto& resource : resourcesInvolved)
+      {
+        dummySubpass->AddGeneralInput(resource);
+
+        if (SHVkUtil::IsDepthStencilAttachment(graphStorage->graphResources->at(resource)->GetResourceFormat()))
+          dummySubpass->AddGeneralDepthOutput(resource);
+        else
+          dummySubpass->AddGeneralColorOutput(resource);
+      }
+    }
+  }
+
   void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
   {
-    frameIndex = (framebuffers.size() > 1) ? frameIndex : 0;
-    commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]);
+    uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;
+    commandBuffer->BeginRenderpass(renderpass, framebuffers[framebufferIndex]);
 
     for (uint32_t i = 0; i < subpasses.size(); ++i)
     {
       subpasses[i]->Execute(commandBuffer, descPool, frameIndex);
 
       // Go to next subpass if not last subpass
-      if (i != subpasses.size() - 1)
+      if (i != static_cast<uint32_t>(subpasses.size()) - 1u)
         commandBuffer->NextSubpass();
     }
 
     commandBuffer->EndRenderpass();
+
+
+    // Execute all subpass computes
+    for (auto& sbCompute : nodeComputes)
+    {
+      sbCompute->Execute(commandBuffer, frameIndex);
+    }
   }
 
   Handle<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept
@@ -273,10 +345,10 @@ namespace SHADE
     }
 
 
-    Handle<SHVkPipeline> pipeline = pipelineLibrary.GetDrawPipline(vsFsPair);
+    Handle<SHVkPipeline> pipeline = pipelineLibrary.GetGraphicsPipeline(vsFsPair);
     if (!pipeline)
     {
-      pipeline = pipelineLibrary.CreateDrawPipeline
+      pipeline = pipelineLibrary.CreateGraphicsPipelines
       (
         vsFsPair,
         renderpass,
@@ -289,7 +361,7 @@ namespace SHADE
 
   void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool)
   {
-    batcher.FinaliseBatches(logicalDeviceHdl, descPool, frameIndex);
+    batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex);
   }
 
   /***************************************************************************/
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h
index 3cb1c4ee..16f3f914 100644
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h
@@ -19,6 +19,9 @@ namespace SHADE
   class SHVkLogicalDevice;
   class SHVkRenderpass;
   class SHVkDescriptorPool;
+  class SHGraphicsGlobalData;
+  class SHRenderGraphStorage;
+  class SHRenderGraphNodeCompute;
 
   class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode>
   {
@@ -26,10 +29,9 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     /* PRIVATE MEMBER VARIABLES                                              */
     /*-----------------------------------------------------------------------*/
-    std::shared_ptr<SHResourceHub> resourceManager;
-
     //! For Vulkan object creation
-    Handle<SHVkLogicalDevice> logicalDeviceHdl;
+    //Handle<SHVkLogicalDevice> logicalDeviceHdl;
+    Handle<SHRenderGraphStorage> graphStorage;
 
     //! Each node will have a renderpass and each renderpass will have its own subpasses.
     //! These subpasses will execute sequentially. 
@@ -63,12 +65,13 @@ namespace SHADE
     //! For indexing subpasses
     std::map<std::string, uint32_t> subpassIndexing;
 
-    //! Pointer to resources in the render graph (for getting handle IDs)
-    std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
-
     //! Every renderpass will require a pipeline library that will contain pipelines compatible with this renderpass 
     SHPipelineLibrary pipelineLibrary;
 
+    //! Sometimes we want the subpass to do something to the images instead
+    //! of drawing objects on the image (i.e. compute).
+    std::vector<Handle<SHRenderGraphNodeCompute>> nodeComputes;
+
     //! Whether or not the node has finished execution
     bool executed;
 
@@ -77,6 +80,7 @@ namespace SHADE
 
     SHBatcher batcher;
 
+
     /*-----------------------------------------------------------------------*/
     /* PRIVATE MEMBER FUNCTIONS                                              */
     /*-----------------------------------------------------------------------*/
@@ -88,7 +92,7 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     /* CTORS AND DTORS                                                       */
     /*-----------------------------------------------------------------------*/
-    SHRenderGraphNode(std::shared_ptr<SHResourceHub> rm, Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept;
+    SHRenderGraphNode(Handle<SHRenderGraphStorage> renderGraphStorage, std::vector<SHAttachmentDescInitParams> attDescInitParams, std::vector<Handle<SHRenderGraphNode>> predecessors) noexcept;
     SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept;
     SHRenderGraphNode& operator= (SHRenderGraphNode&& rhs) noexcept;
 
@@ -96,6 +100,9 @@ namespace SHADE
     /* PUBLIC MEMBER FUNCTIONS                                               */
     /*-----------------------------------------------------------------------*/
     Handle<SHSubpass>    AddSubpass(std::string subpassName) noexcept;
+    Handle<SHRenderGraphNodeCompute> AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale = 1.0f) noexcept;
+    void AddDummySubpassIfNeeded (void) noexcept;
+
     // TODO: RemoveSubpass()
     void Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
     Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp
new file mode 100644
index 00000000..a5208fcf
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.cpp
@@ -0,0 +1,109 @@
+#include "SHpch.h"
+#include "SHRenderGraphNodeCompute.h"
+#include "Graphics/Pipeline/SHVkPipeline.h"
+#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
+#include "Graphics/Descriptors/SHVkDescriptorPool.h"
+#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
+#include "Graphics/Devices/SHVkLogicalDevice.h"
+#include "Graphics/Pipeline/SHVkPipelineLayout.h"
+#include "Graphics/MiddleEnd/GlobalData/SHGraphicsGlobalData.h"
+#include "SHRenderGraphStorage.h"
+#include "SHRenderGraphResource.h"
+#include "Graphics/Commands/SHVkCommandBuffer.h"
+
+namespace SHADE
+{
+  SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, float inNumWorkGroupScale/* = 1.0f*/) noexcept
+    : computePipeline{}
+    , pipelineLayout{}
+    , resources{}
+    , groupSizeX{0}
+    , groupSizeY{0}
+    , numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)}
+  {
+    SHPipelineLayoutParams pipelineLayoutParams
+    {
+      .shaderModules = {computeShaderModule},
+      .globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts()
+    };
+
+    // Create pipeline layout from parameters
+    pipelineLayout = graphStorage->logicalDevice->CreatePipelineLayout (pipelineLayoutParams);
+
+    // Create the compute pipeline 
+    computePipeline = graphStorage->logicalDevice->CreateComputePipeline(pipelineLayout);
+
+    // and construct it
+    computePipeline->ConstructPipeline();
+
+    // save the resources
+    resources = std::move (subpassComputeResources);
+
+     //Get the descriptor set layouts required to allocate. We only want the ones for allocate because 
+     //global descriptors are already bound in the main system. 
+    auto const& layouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate();
+
+     //Variable counts for the descriptor sets (all should be 1).
+    std::vector<uint32_t> variableCounts{ static_cast<uint32_t>(layouts.size()) };
+    std::fill(variableCounts.begin(), variableCounts.end(), 0);
+
+    // Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE)
+    for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
+    {
+      descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts);
+    }
+
+
+    HandleResize();
+  }
+
+  void SHRenderGraphNodeCompute::Execute(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
+  {
+    // bind the compute pipeline
+    cmdBuffer->BindPipeline(computePipeline);
+    
+    // bind descriptor sets
+    cmdBuffer->BindDescriptorSet(descSetGroups[frameIndex], SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, {});
+
+    // dispatch compute
+    cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1);
+
+    // TODO: barrier
+
+  }
+
+  void SHRenderGraphNodeCompute::HandleResize(void) noexcept
+  {
+    // Get the layout for the render graph resource. We can index it this way because the container returned is a container of layouts that includes the global ones
+    auto pipelineDescSetLayouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline()[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE];
+
+    // everything below here needs resizing
+    for (uint32_t frameIndex = 0; frameIndex < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++frameIndex)
+    {
+      uint32_t i = 0;
+
+      // loop through bindings and write descriptor sets
+      for (auto& binding : pipelineDescSetLayouts->GetBindings())
+      {
+        uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0;
+
+        SHVkDescriptorSetGroup::viewSamplerLayout vsl = std::make_tuple(resources[i]->GetImageView(imageIndex), Handle<SHVkSampler>{}, vk::ImageLayout::eGeneral);
+        descSetGroups[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 });
+        descSetGroups[frameIndex]->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint);
+        ++i;
+      }
+    }
+
+    // Get the group size from the max width and height
+    uint32_t maxWidth = 0, maxHeight = 0;
+    for (auto& resource : resources)
+    {
+      maxWidth = std::max(resource->GetWidth(), maxWidth);
+      maxHeight = std::max(resource->GetHeight(), maxHeight);
+    }
+
+    groupSizeX = maxWidth / workGroupSizeX;
+    groupSizeY = maxHeight / workGroupSizeY;
+  }
+
+}
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h
new file mode 100644
index 00000000..ba4cf387
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNodeCompute.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "Resource/SHHandle.h"
+#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
+#include <initializer_list>
+#include <string>
+#include <unordered_set>
+
+namespace SHADE
+{
+  class SHVkPipeline;
+  class SHVkDescriptorSetGroup;
+  class SHVkDescriptorPool;
+  class SHVkLogicalDevice;
+  class SHVkPipelineLayout;
+  class SHRenderGraphStorage;
+  class SHRenderGraphResource;
+  class SHVkShaderModule;
+  class SHVkCommandBuffer;
+
+  class SHRenderGraphNodeCompute
+  {
+  private:
+    static constexpr uint32_t workGroupSizeX = 16;
+    static constexpr uint32_t workGroupSizeY = 16;
+
+    //! To run the dispatch command
+    Handle<SHVkPipeline>                       computePipeline;
+
+    //! Pipeline layout for the pipeline creation
+    Handle<SHVkPipelineLayout>                 pipelineLayout;
+
+    //! Descriptor set group to hold the images for reading (STORAGE_IMAGE)
+    std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS> descSetGroups;
+
+    //! vector of resources needed by the subpass compute
+    std::vector<Handle<SHRenderGraphResource>> resources;
+
+    //! X dimension work group size. Should scale with resource size.
+    uint32_t groupSizeX;
+
+    //! Y dimension work group size 
+    uint32_t groupSizeY;
+
+    float numWorkGroupScale;
+
+  public:
+    SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, float inNumWorkGroupScale = 1.0f) noexcept;
+
+    void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
+    void HandleResize (void) noexcept;
+
+    friend class SHRenderGraph;
+    friend class SHRenderGraphNode;
+  };
+}
+
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp
index adf3b6cd..502e09b2 100644
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp
@@ -5,6 +5,7 @@
 #include "Graphics/Images/SHVkImageView.h"
 #include "Graphics/Buffers/SHVkBuffer.h"
 #include "Graphics/SHVkUtil.h"
+#include "SHRenderGraphStorage.h"
 
 namespace SHADE
 {
@@ -45,9 +46,8 @@ namespace SHADE
 
   */
   /***************************************************************************/
-  SHRenderGraphResource::SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept
-    : logicalDevice {logicalDevice}
-    , swapchain{ swapchain }
+  SHRenderGraphResource::SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept
+    : graphStorage{renderGraphStorage}
     , resourceTypeFlags{ }
     , resourceFormat{ format }
     , images{}
@@ -66,7 +66,7 @@ namespace SHADE
       SHImageViewDetails viewDetails
       {
         .viewType = vk::ImageViewType::e2D,
-        .format = swapchain->GetSurfaceFormatKHR().format,
+        .format = graphStorage->swapchain->GetSurfaceFormatKHR().format,
         .imageAspectFlags = vk::ImageAspectFlagBits::eColor,
         .baseMipLevel = 0,
         .mipLevelCount = 1,
@@ -75,13 +75,13 @@ namespace SHADE
       };
 
       // We want an image handle for every swapchain image
-      images.resize(swapchain->GetNumImages());
-      imageViews.resize(swapchain->GetNumImages());
+      images.resize(graphStorage->swapchain->GetNumImages());
+      imageViews.resize(graphStorage->swapchain->GetNumImages());
 
-      for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
+      for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i)
       {
-        images[i] = swapchain->GetSwapchainImage(i);
-        imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails);
+        images[i] = graphStorage->swapchain->GetSwapchainImage(i);
+        imageViews[i] = images[i]->CreateImageView(graphStorage->logicalDevice, images[i], viewDetails);
       }
     }
     else // if swapchain image resource
@@ -117,6 +117,9 @@ namespace SHADE
           usage |= vk::ImageUsageFlagBits::eInputAttachment;
           usage |= vk::ImageUsageFlagBits::eSampled;
           break;
+        case SH_ATT_DESC_TYPE_FLAGS::STORAGE:
+          usage |= vk::ImageUsageFlagBits::eStorage;
+          break;
         case SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT:
           {
             SHLOG_ERROR ("COLOR_PRESENT cannot be with other resource type flags. ");
@@ -126,7 +129,7 @@ namespace SHADE
       }
 
       // The resource is not a swapchain image, just use the first slot of the vector 
-      images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags));
+      images.push_back(graphStorage->logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags));
 
       // prepare image view details
       SHImageViewDetails viewDetails
@@ -141,7 +144,7 @@ namespace SHADE
       };
 
       // just 1 image view created
-      imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails));
+      imageViews.push_back(images[0]->CreateImageView(graphStorage->logicalDevice, images[0], viewDetails));
     }
   }
 
@@ -166,7 +169,7 @@ namespace SHADE
     , height{ rhs.height }
     , mipLevels{ rhs.mipLevels }
     , imageAspectFlags{ rhs.imageAspectFlags }
-    , swapchain {rhs.swapchain}
+    , graphStorage{rhs.graphStorage}
   {
 
   }
@@ -198,7 +201,7 @@ namespace SHADE
     height = rhs.height;
     mipLevels = rhs.mipLevels;
     imageAspectFlags = rhs.imageAspectFlags;
-    swapchain = rhs.swapchain;
+    graphStorage = rhs.graphStorage;
 
     return *this;
   }
@@ -247,7 +250,7 @@ namespace SHADE
       SHImageViewDetails viewDetails
       {
         .viewType = vk::ImageViewType::e2D,
-        .format = swapchain->GetSurfaceFormatKHR().format,
+        .format = graphStorage->swapchain->GetSurfaceFormatKHR().format,
         .imageAspectFlags = vk::ImageAspectFlagBits::eColor,
         .baseMipLevel = 0,
         .mipLevelCount = 1,
@@ -255,9 +258,9 @@ namespace SHADE
         .layerCount = 1,
       };
 
-      for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i)
+      for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i)
       {
-        images[i] = swapchain->GetSwapchainImage(i);
+        images[i] = graphStorage->swapchain->GetSwapchainImage(i);
         imageViews[i]->ViewNewImage(images[i], viewDetails);
       }
     }
@@ -308,6 +311,7 @@ namespace SHADE
     return resourceFormat;
   }
 
+
   uint32_t SHRenderGraphResource::GetWidth(void) const noexcept
   {
     return width;
@@ -323,4 +327,19 @@ namespace SHADE
     return imageViews [index];
   }
 
+  Handle<SHVkImage> SHRenderGraphResource::GetImage(uint32_t index /*= NON_SWAPCHAIN_RESOURCE_INDEX*/) const noexcept
+  {
+    return images[index];
+  }
+
+  uint8_t SHRenderGraphResource::GetMipLevels(void) const noexcept
+  {
+    return mipLevels;
+  }
+
+  std::string SHRenderGraphResource::GetName(void) const noexcept
+  {
+    return resourceName;
+  }
+
 }
\ No newline at end of file
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h
index fc8b05f7..e2fc5d8d 100644
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h
@@ -15,6 +15,7 @@ namespace SHADE
   class SHVkSwapchain;
   class SHVkCommandBuffer;
   class SHVkBuffer;
+  class SHRenderGraphStorage;
 
   static constexpr uint32_t NON_SWAPCHAIN_RESOURCE_INDEX = 0;
 
@@ -24,11 +25,8 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     /* PRIVATE MEMBER VARIABLES                                              */
     /*-----------------------------------------------------------------------*/
-    // for creation/recreation
-    Handle<SHVkLogicalDevice> logicalDevice;
-
-    // for creation/recreation
-    Handle<SHVkSwapchain> swapchain;
+    //! Storage from the render graph
+    Handle<SHRenderGraphStorage> graphStorage;
 
     //! Name of the resource
     std::string resourceName;
@@ -69,7 +67,7 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     /* CTORS AND DTORS                                                       */
     /*-----------------------------------------------------------------------*/
-    SHRenderGraphResource(Handle<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept;
+    SHRenderGraphResource(Handle<SHRenderGraphStorage> renderGraphStorage, std::string const& name, std::initializer_list<SH_ATT_DESC_TYPE_FLAGS> typeFlags, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageUsageFlagBits usageFlags, vk::ImageCreateFlagBits createFlags) noexcept;
     SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept;
     SHRenderGraphResource& operator=(SHRenderGraphResource&& rhs) noexcept;
     ~SHRenderGraphResource(void) noexcept;
@@ -84,12 +82,17 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     /* SETTERS AND GETTERS                                                   */
     /*-----------------------------------------------------------------------*/
-    vk::Format            GetResourceFormat (void) const noexcept;
-    uint32_t              GetWidth          (void) const noexcept;
-    uint32_t              GetHeight         (void) const noexcept;
-    Handle<SHVkImageView> GetImageView      (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept;
+    vk::Format                 GetResourceFormat (void) const noexcept;
+    uint32_t                   GetWidth          (void) const noexcept;
+    uint32_t                   GetHeight         (void) const noexcept;
+    Handle<SHVkImageView>      GetImageView      (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept;
+    Handle<SHVkImage>          GetImage          (uint32_t index = NON_SWAPCHAIN_RESOURCE_INDEX) const noexcept;
+    uint8_t                    GetMipLevels      (void) const noexcept;
+    std::string                GetName           (void) const noexcept;
 
     friend class SHRenderGraphNode;
     friend class SHRenderGraph;
+    friend class SHSubpass;
+    friend class SHRenderGraphNodeCompute;
   };
 }
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h
new file mode 100644
index 00000000..54ef705a
--- /dev/null
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphStorage.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "Resource/SHHandle.h"
+#include <memory>
+
+namespace SHADE
+{
+  class SHVkLogicalDevice;
+  class SHVkSwapchain;
+  class SHGraphicsGlobalData;
+  class SHVkDescriptorPool;
+  class SHRenderGraphResource;
+
+  class SHRenderGraphStorage
+  {
+    //! Logical device for creation of vulkan objects
+    Handle<SHVkLogicalDevice> logicalDevice;
+
+    //! swapchain handle
+    Handle<SHVkSwapchain> swapchain;
+
+    //! Resource manager for creation of objects
+    std::shared_ptr<SHResourceHub> resourceManager;
+
+    //! Descriptor pool for the descriptor sets to be created in the subpasses
+    Handle<SHVkDescriptorPool> descriptorPool;
+
+    //! For accessing resources anywhere in the graph
+    Handle<std::unordered_map<std::string, Handle<SHRenderGraphResource>>> graphResources;
+
+    //SHRenderGraphStorage(void) noexcept;
+    //SHRenderGraphStorage(SHRenderGraphStorage&& rhs) noexcept;
+    //SHRenderGraphStorage& operator=(SHRenderGraphStorage&& rhs) noexcept;
+
+    friend class SHRenderGraph;
+    friend class SHRenderGraphNode;
+    friend class SHSubpass;
+    friend class SHRenderGraphResource;
+    friend class SHRenderGraphNodeCompute;
+  };
+
+
+}
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp
index 7c5021f8..af6f3089 100644
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp
@@ -4,6 +4,13 @@
 #include "Graphics/Devices/SHVkLogicalDevice.h"
 #include "SHRenderGraphNode.h"
 #include "SHRenderGraphResource.h"
+#include "Graphics/Shaders/SHVkShaderModule.h"
+#include "SHRenderGraphNode.h"
+#include "SHRenderGraphStorage.h"
+#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
+#include "Graphics/Swapchain/SHVkSwapchain.h"
+#include "Graphics/Images/SHVkSampler.h"
+#include "SHRenderGraphResource.h"
 
 namespace SHADE
 {
@@ -23,15 +30,16 @@ namespace SHADE
 
   */
   /***************************************************************************/
-  SHSubpass::SHSubpass(Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources) noexcept
+  SHSubpass::SHSubpass(Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping) noexcept
     : resourceAttachmentMapping{ mapping }
-    , ptrToResources{ resources }
     , parentNode{ parent }
     , subpassIndex{ index }
     , superBatch{}
     , colorReferences{}
     , depthReferences{}
     , inputReferences{}
+    , graphStorage{ renderGraphStorage }
+    , inputImageDescriptors {SHGraphicsConstants::NUM_FRAME_BUFFERS}
   {
   }
 
@@ -54,9 +62,14 @@ namespace SHADE
     , depthReferences{ std::move(rhs.depthReferences) }
     , inputReferences{ std::move(rhs.inputReferences) }
     , resourceAttachmentMapping{ rhs.resourceAttachmentMapping }
-    , ptrToResources{ rhs.ptrToResources }
     , descriptorSetLayout{ rhs.descriptorSetLayout }
-    , exteriorDrawCalls{ std::move (rhs.exteriorDrawCalls) }
+    , exteriorDrawCalls{ std::move(rhs.exteriorDrawCalls) }
+    , graphStorage{ rhs.graphStorage }
+    , inputNames{ std::move(rhs.inputNames) }
+    , inputImageDescriptors{ std::move(rhs.inputImageDescriptors) }
+    , inputDescriptorLayout{ rhs.inputDescriptorLayout }
+    , inputSamplers{ rhs.inputSamplers }
+
   {
 
   }
@@ -84,9 +97,13 @@ namespace SHADE
     depthReferences = std::move(rhs.depthReferences);
     inputReferences = std::move(rhs.inputReferences);
     resourceAttachmentMapping = rhs.resourceAttachmentMapping;
-    ptrToResources = rhs.ptrToResources;
     descriptorSetLayout = rhs.descriptorSetLayout;
     exteriorDrawCalls = std::move(rhs.exteriorDrawCalls);
+    graphStorage = rhs.graphStorage;
+    inputNames = std::move(rhs.inputNames);
+    inputImageDescriptors = std::move(rhs.inputImageDescriptors);
+    inputDescriptorLayout = rhs.inputDescriptorLayout;
+    inputSamplers = rhs.inputSamplers;
 
     return *this;
   }
@@ -105,7 +122,12 @@ namespace SHADE
   /***************************************************************************/
   void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept
   {
-    colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal });
+    colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal });
+  }
+
+  void SHSubpass::AddGeneralColorOutput(std::string resourceToReference) noexcept
+  {
+    colorReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral });
   }
 
   /***************************************************************************/
@@ -142,7 +164,13 @@ namespace SHADE
       //Invalid
       return;
     }
-    depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout });
+    depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), imageLayout });
+  }
+
+  void SHSubpass::AddGeneralDepthOutput(std::string resourceToReference) noexcept
+  {
+    depthReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral });
+
   }
 
   /***************************************************************************/
@@ -159,7 +187,14 @@ namespace SHADE
   /***************************************************************************/
   void SHSubpass::AddInput(std::string resourceToReference) noexcept
   {
-    inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal });
+    inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal });
+
+    inputNames.push_back(resourceToReference);
+  }
+
+  void SHSubpass::AddGeneralInput(std::string resourceToReference) noexcept
+  {
+    inputReferences.push_back({ resourceAttachmentMapping->at(graphStorage->graphResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eGeneral });
   }
 
   void SHSubpass::Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
@@ -175,6 +210,12 @@ namespace SHADE
     {
       drawCall(commandBuffer);
     }
+
+  }
+
+  void SHSubpass::HandleResize(void) noexcept
+  {
+    UpdateWriteDescriptors();
   }
 
   void SHSubpass::AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept
@@ -188,6 +229,152 @@ namespace SHADE
 
   }
 
+  void SHSubpass::CreateInputDescriptors(void) noexcept
+  {
+    if (inputNames.empty())
+      return;
+
+    std::vector<SHVkDescriptorSetLayout::Binding> bindings{};
+
+    for (auto& input : inputReferences)
+    {
+      SHVkDescriptorSetLayout::Binding newBinding
+      {
+        .Type = (input.layout == vk::ImageLayout::eShaderReadOnlyOptimal) ? vk::DescriptorType::eInputAttachment : vk::DescriptorType::eStorageImage,
+        .Stage = vk::ShaderStageFlagBits::eFragment,
+        .BindPoint = static_cast<uint32_t>(bindings.size()),
+        .DescriptorCount = 1,
+        .flags = {},
+      };
+
+      bindings.push_back(newBinding);
+    }
+
+    // We build a new descriptor set layout to store our images
+    inputDescriptorLayout = graphStorage->logicalDevice->CreateDescriptorSetLayout(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, bindings);
+
+    // we store a sampler if its an input attachment. if it is storage image, no need sampler, store an empty handle.
+    for (uint32_t i = 0; i < bindings.size(); ++i)
+    {
+      if (bindings[i].Type == vk::DescriptorType::eInputAttachment)
+      {
+        auto newSampler = graphStorage->logicalDevice->CreateSampler(SHVkSamplerParams
+          {
+          .minFilter = vk::Filter::eLinear,
+          .magFilter = vk::Filter::eLinear,
+          .addressMode = vk::SamplerAddressMode::eRepeat,
+          .mipmapMode = vk::SamplerMipmapMode::eLinear,
+          .minLod = -1000,
+          .maxLod = 1000
+          }
+        );
+
+        inputSamplers.push_back(newSampler);
+      }
+      else
+      {
+        inputSamplers.push_back({});
+      }
+    }
+
+    //// maybe do this in handle resize? 
+    //UpdateWriteDescriptors();
+  }
+
+  void SHSubpass::UpdateWriteDescriptors(void) noexcept
+  {
+    if (inputNames.empty())
+      return;
+
+    auto const& bindings = inputDescriptorLayout->GetBindings();
+
+    std::vector<uint32_t> variableCounts{ static_cast<uint32_t>(bindings.size()) };
+    std::fill (variableCounts.begin(), variableCounts.end(), 0u);
+
+
+    // For every frame's descriptor set
+    for (auto& group : inputImageDescriptors)
+    {
+      if (group)
+        group.Free();
+
+      group = graphStorage->descriptorPool->Allocate({ inputDescriptorLayout }, variableCounts);
+
+      uint32_t i = 0;
+      for (auto& binding : bindings)
+      {
+        // get the resource
+        auto resource = graphStorage->graphResources->at(inputNames[binding.BindPoint]);
+
+        // If resource is swapchain image, get the correct image, if not just get 0.
+        uint32_t viewIndex = (resource->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? i : 0; 
+
+        // layout is GENERAL if image is meant to be used as storage image, if not use SHADER_READ_ONLY_OPTINAL
+        vk::ImageLayout descriptorLayout = (binding.Type == vk::DescriptorType::eStorageImage) ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal;
+
+        // Update descriptor sets
+        auto args = std::make_tuple(resource->GetImageView(viewIndex), inputSamplers[i], descriptorLayout);
+        group->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, std::span{&args, 1});
+        group->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint);
+      }
+
+      ++i;
+    }
+  }
+
+  //void SHSubpass::InitComputeBarriers(void) noexcept
+  //{
+  //  std::unordered_set <uint64_t> handleBarriers{};
+
+  //  // we will have swapchainNumImages vectors of vector of barriers 
+  //  subpassComputeBarriers.resize(graphStorage->swapchain->GetNumImages());
+
+  //  for (auto sbCompute : subpassComputes)
+  //  {
+  //    // for every resource the subpass compute is using
+  //  	for (auto resource : sbCompute->resources)
+  //  	{
+  //      // Get the resource handle
+  //      uint64_t resourceRaw = resource.GetId().Raw;
+
+  //      // if the barrier is not registered
+  //      if (!handleBarriers.contains(resourceRaw))
+  //      {
+  //        // If the resource is a swapchain image
+  //        bool isSwapchainImage = (resource->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT));
+  //        for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i)
+  //        {
+  //          // if swapchain image, we want the index of the swapchain image, if not take base image
+  //          uint32_t imageIndex = isSwapchainImage ? i : 0;
+
+  //          // Prepare image barrier
+  //          vk::ImageMemoryBarrier imageBarrier
+  //          {
+  //            .oldLayout = colorReferences[resourceAttachmentMapping->at(resource.GetId().Raw)].layout,
+  //            .newLayout = vk::ImageLayout::eGeneral,
+  //            .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+  //            .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+  //            .image = resource->GetImage(imageIndex)->GetVkImage(),
+  //            .subresourceRange = 
+  //            {
+  //              .aspectMask = resource->imageAspectFlags,
+  //              .levelCount = resource->GetMipLevels(),
+  //              .baseArrayLayer = 0,
+  //              .layerCount = 1
+  //            }
+  //          };
+
+  //          // push the barrier
+  //          subpassComputeBarriers[i].push_back(imageBarrier);
+  //        }
+
+  //        // Image transition registered
+  //        handleBarriers.emplace(resourceRaw);
+  //      }
+  //  	}
+  //  }
+  //}
+
   /***************************************************************************/
   /*!
 
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h
index e5094708..166f0d76 100644
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h
+++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h
@@ -14,7 +14,11 @@ namespace SHADE
   class SHRenderGraphResource;
   class SHVkCommandBuffer;
   class SHVkDescriptorSetLayout;
+  class SHVkDescriptorSetGroup;
   class SHVkDescriptorPool;
+  class SHRenderGraphStorage;
+  class SHVkShaderModule;
+  class SHVkSampler;
 
   class SH_API SHSubpass : public ISelfHandle<SHSubpass>
   {
@@ -22,32 +26,49 @@ namespace SHADE
     /*---------------------------------------------------------------------*/
     /* PRIVATE MEMBER VARIABLES                                            */
     /*---------------------------------------------------------------------*/
+    Handle<SHRenderGraphStorage>                  graphStorage;
+
     //! The index of the subpass in the render graph
-    uint32_t                             subpassIndex;
+    uint32_t                                      subpassIndex;
 
     //! The parent renderpass that this subpass belongs to
-    Handle<SHRenderGraphNode>            parentNode;
+    Handle<SHRenderGraphNode>                     parentNode;
 
     //! 
-    Handle<SHSuperBatch>                 superBatch;
+    Handle<SHSuperBatch>                          superBatch;
 
     //! Descriptor set layout to hold attachments
-    Handle<SHVkDescriptorSetLayout>      descriptorSetLayout;
+    Handle<SHVkDescriptorSetLayout>               descriptorSetLayout;
 
     //! Color attachments
-    std::vector<vk::AttachmentReference> colorReferences;
+    std::vector<vk::AttachmentReference>          colorReferences;
 
     //! Depth attachments
-    std::vector<vk::AttachmentReference> depthReferences;
+    std::vector<vk::AttachmentReference>          depthReferences;
 
     //! Input attachments
-    std::vector<vk::AttachmentReference> inputReferences;
+    std::vector<vk::AttachmentReference>          inputReferences;
+
+    //! This is mainly for when we want to retrieve resources using names.
+    std::vector<std::string>                      inputNames;
 
     //! For getting attachment reference indices using handles
     std::unordered_map<uint64_t, uint32_t> const* resourceAttachmentMapping;
 
-    //! Pointer to resources in the render graph (for getting handle IDs)
-    std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources;
+    //! Descriptor set group to hold the images for input
+    std::vector<Handle<SHVkDescriptorSetGroup>>   inputImageDescriptors;
+
+    //! Descriptor set layout for allocating descriptor set for inputs
+    Handle<SHVkDescriptorSetLayout>               inputDescriptorLayout;
+
+    std::vector<Handle<SHVkSampler>>              inputSamplers;
+
+
+    ////! subpass compute image barriers. We do this because every frame has a different
+    ////! swapchain image. If the resource we want to transition is not a swapchain image,
+    ////! we duplicate the barrier anyway, not much memory wasted. ;)
+    //std::vector<std::vector<vk::ImageMemoryBarrier>> subpassComputeBarriers{};
+
 
     //! Sometimes there exists entities that we want to render onto a render target
     //! but don't want it to come from the batching system. An example would be ImGUI.
@@ -62,7 +83,7 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     /* CTORS AND DTORS                                                       */
     /*-----------------------------------------------------------------------*/
-    SHSubpass(Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* ptrToResources) noexcept;
+    SHSubpass(Handle<SHRenderGraphStorage> renderGraphStorage, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping) noexcept;
     SHSubpass(SHSubpass&& rhs) noexcept;
     SHSubpass& operator=(SHSubpass&& rhs) noexcept;
 
@@ -71,14 +92,22 @@ namespace SHADE
     /*-----------------------------------------------------------------------*/
     // Preparation functions
     void AddColorOutput(std::string resourceToReference) noexcept;
+    void AddGeneralColorOutput(std::string resourceToReference) noexcept;
     void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE_FLAGS attachmentDescriptionType = SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL) noexcept;
+    void AddGeneralDepthOutput(std::string resourceToReference) noexcept;
     void AddInput(std::string resourceToReference) noexcept;
+    void AddGeneralInput (std::string resourceToReference) noexcept;
+    void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept;
 
     // Runtime functions
     void Execute(Handle<SHVkCommandBuffer>& commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
-    void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept;
+    void HandleResize (void) noexcept;
 
     void Init(SHResourceHub& resourceManager) noexcept;
+    
+    //void InitComputeBarriers (void) noexcept;
+    void CreateInputDescriptors (void) noexcept;
+    void UpdateWriteDescriptors (void) noexcept;
 
     /*-----------------------------------------------------------------------*/
     /* GETTERS AND SETTERS                                                   */
@@ -91,5 +120,6 @@ namespace SHADE
 
     friend class SHRenderGraphNode;
     friend class SHRenderGraph;
+    friend class SHSubpass;
   };
 }
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp
deleted file mode 100644
index ccd0e6c3..00000000
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "SHpch.h"
-#include "SHSubpassCompute.h"
-#include "Graphics/Pipeline/SHVkPipeline.h"
-#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
-#include "Graphics/Descriptors/SHVkDescriptorPool.h"
-
-namespace SHADE
-{
-  SHSubpassCompute::SHSubpassCompute(Handle<SHVkPipeline> inPipeline, Handle<SHVkDescriptorPool> descPool) noexcept
-    : pipeline {inPipeline}
-  {
-    // Get the descriptor set layouts required to allocate. we will bind a different pipeline layout, one that includes the layout for global.
-    auto const& layouts = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate();
-
-    // Variable counts for the descriptor sets (all should be 1).
-    std::vector<uint32_t> variableCounts{static_cast<uint32_t>(layouts.size())};
-    std::fill (variableCounts.begin(), variableCounts.end(), 0);
-
-    // Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE)
-    descPool->Allocate(layouts, variableCounts);
-  }
-
-}
diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h
deleted file mode 100644
index 7bbbe051..00000000
--- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#include <Resource/SHHandle.h>
-
-namespace SHADE
-{
-  class SHVkPipeline;
-  class SHVkDescriptorSetGroup;
-  class SHVkDescriptorPool;
-
-  class SHSubpassCompute
-  {
-  private:
-    //! To run the dispatch command
-    Handle<SHVkPipeline>       pipeline;
-
-    //! Descriptor set group
-    Handle<SHVkDescriptorSetGroup> descSetGroup;
-  	
-  public:
-    SHSubpassCompute (Handle<SHVkPipeline> inPipeline, Handle<SHVkDescriptorPool> descPool) noexcept;
-
-  };
-}
-
diff --git a/SHADE_Engine/src/Graphics/SHVkUtil.cpp b/SHADE_Engine/src/Graphics/SHVkUtil.cpp
index c8c563a1..8b21e7d1 100644
--- a/SHADE_Engine/src/Graphics/SHVkUtil.cpp
+++ b/SHADE_Engine/src/Graphics/SHVkUtil.cpp
@@ -51,10 +51,37 @@ namespace SHADE
     case vk::Format::eR32Uint:
     case vk::Format::eR32Sfloat:
       return 4;
+    case vk::Format::eR32G32Sint:
+    case vk::Format::eR32G32Uint:
+    case vk::Format::eR32G32Sfloat:
+      return 8;
+    case vk::Format::eR32G32B32Sint:
+    case vk::Format::eR32G32B32Uint:
+    case vk::Format::eR32G32B32Sfloat:
+      return 12;
+    case vk::Format::eR32G32B32A32Sint:
+    case vk::Format::eR32G32B32A32Uint:
+    case vk::Format::eR32G32B32A32Sfloat:
+      return 16;
     }
     return 0;
   }
 
+  vk::PipelineBindPoint SHVkUtil::GetPipelineBindPointFromType(SH_PIPELINE_TYPE pipelineType) noexcept
+  {
+    switch (pipelineType)
+    {
+    case SH_PIPELINE_TYPE::GRAPHICS:
+      return vk::PipelineBindPoint::eGraphics;
+    case SH_PIPELINE_TYPE::COMPUTE:
+      return vk::PipelineBindPoint::eCompute;
+    case SH_PIPELINE_TYPE::RAY_TRACING:
+      return vk::PipelineBindPoint::eRayTracingKHR;
+    default:
+      return vk::PipelineBindPoint::eGraphics;
+    }
+  }
+
   void SHVkUtil::EnsureBufferAndCopyData(Handle<SHVkLogicalDevice> device, Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHVkBuffer>& bufferHandle, void* src, uint32_t size, vk::BufferUsageFlagBits usage)
   {
       if (bufferHandle)
diff --git a/SHADE_Engine/src/Graphics/SHVkUtil.h b/SHADE_Engine/src/Graphics/SHVkUtil.h
index dbf17826..de700ea5 100644
--- a/SHADE_Engine/src/Graphics/SHVkUtil.h
+++ b/SHADE_Engine/src/Graphics/SHVkUtil.h
@@ -4,6 +4,7 @@
 #include "SHVulkanIncludes.h"
 
 #include "Resource/SHHandle.h"
+#include "Graphics/Pipeline/SHPipelineType.h"
 
 namespace SHADE
 {
@@ -20,11 +21,12 @@ namespace SHADE
   class SHVkUtil
   {
   public:                                  
-    static bool     IsDepthOnlyFormat          (vk::Format format) noexcept;
-    static bool     IsDepthStencilAttachment   (vk::Format format) noexcept;
-    static bool     IsBlendCompatible          (vk::Format format) noexcept;
-    static uint32_t GetBytesPerPixelFromFormat (vk::Format format) noexcept;
-
+    static bool                  IsDepthOnlyFormat            (vk::Format format) noexcept;
+    static bool                  IsDepthStencilAttachment     (vk::Format format) noexcept;
+    static bool                  IsBlendCompatible            (vk::Format format) noexcept;
+    static uint32_t              GetBytesPerPixelFromFormat   (vk::Format format) noexcept;
+    static vk::PipelineBindPoint GetPipelineBindPointFromType (SH_PIPELINE_TYPE pipelineType) noexcept;
+ 
     /***********************************************************************************/
     /*! 
      
diff --git a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp
index 41327988..e635f763 100644
--- a/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp
+++ b/SHADE_Engine/src/Graphics/Shaders/SHShaderReflected.cpp
@@ -177,6 +177,9 @@ namespace SHADE
       return vk::DescriptorType::eStorageBufferDynamic;
     case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
       return vk::DescriptorType::eInputAttachment;
+    case SpvReflectDescriptorType::SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+      return vk::DescriptorType::eStorageImage;
+      break;
     default:
       return vk::DescriptorType::eCombinedImageSampler;
       break;
diff --git a/SHADE_Engine/src/Graphics/VertexDescriptors/SHVertexAttribute.h b/SHADE_Engine/src/Graphics/VertexDescriptors/SHVertexAttribute.h
index b216f5f4..b7191c21 100644
--- a/SHADE_Engine/src/Graphics/VertexDescriptors/SHVertexAttribute.h
+++ b/SHADE_Engine/src/Graphics/VertexDescriptors/SHVertexAttribute.h
@@ -22,6 +22,9 @@ namespace SHADE
 
     // integer formats
     UINT32_1D,
+    UINT32_2D,
+    UINT32_3D,
+    UINT32_4D,
   };
 
   struct SHVertexAttribute
diff --git a/SHADE_Engine/src/Math/SHMatrix.cpp b/SHADE_Engine/src/Math/SHMatrix.cpp
index 571fa4e0..ec3951e2 100644
--- a/SHADE_Engine/src/Math/SHMatrix.cpp
+++ b/SHADE_Engine/src/Math/SHMatrix.cpp
@@ -295,32 +295,33 @@ namespace SHADE
     ) != 0;
   }
 
+  SHMatrix::operator XMMATRIX() const noexcept
+  {
+    return XMLoadFloat4x4(this);
+  }
+
   SHMatrix operator*(float lhs, const SHMatrix& rhs) noexcept
   {
     return rhs * lhs;
   }
 
-
   /*-----------------------------------------------------------------------------------*/
   /* Function Member Definitions                                                       */
   /*-----------------------------------------------------------------------------------*/
 
   void SHMatrix::Transpose() noexcept
   {
-    const XMMATRIX M = XMLoadFloat4x4(this);
-    XMStoreFloat4x4(this, XMMatrixTranspose(M));
+    XMStoreFloat4x4(this, XMMatrixTranspose(*this));
   }
 
   void SHMatrix::Invert() noexcept
   {
-    const XMMATRIX M = XMLoadFloat4x4(this);
-    XMStoreFloat4x4(this, XMMatrixInverse(nullptr, M));
+    XMStoreFloat4x4(this, XMMatrixInverse(nullptr, *this));
   }
 
   float SHMatrix::Determinant() const noexcept
   {
-    const XMMATRIX M = XMLoadFloat4x4(this);
-    return XMVectorGetX(XMMatrixDeterminant(M));
+    return XMVectorGetX(XMMatrixDeterminant(*this));
   }
 
   std::string SHMatrix::ToString() const noexcept
@@ -337,9 +338,8 @@ namespace SHADE
   bool SHMatrix::Decompose(SHVec3& translation, SHVec3& rotation, SHVec3& scale) const noexcept
   {
     XMVECTOR s, r, t;
-    const XMMATRIX M = XMLoadFloat4x4(this);
 
-    if (!XMMatrixDecompose(&s, &r, &t, M))
+    if (!XMMatrixDecompose(&s, &r, &t, *this))
         return false;
 
     SHQuaternion orientation;
@@ -356,9 +356,8 @@ namespace SHADE
   bool SHMatrix::Decompose(SHVec3& translation, SHQuaternion& orientation, SHVec3& scale) const noexcept
   {
     XMVECTOR s, r, t;
-    const XMMATRIX M = XMLoadFloat4x4(this);
 
-    if (!XMMatrixDecompose(&s, &r, &t, M))
+    if (!XMMatrixDecompose(&s, &r, &t, *this))
         return false;
 
     XMStoreFloat3(&scale, s);
@@ -376,8 +375,7 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMMATRIX M = XMLoadFloat4x4(&matrix);
-    XMStoreFloat4x4(&result, XMMatrixTranspose(M));
+    XMStoreFloat4x4(&result, XMMatrixTranspose(matrix));
     return result;
   }
 
@@ -385,8 +383,7 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMMATRIX M = XMLoadFloat4x4(&matrix);
-    XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, M));
+    XMStoreFloat4x4(&result, XMMatrixInverse(nullptr, matrix));
     return result;
   }
 
@@ -401,8 +398,8 @@ namespace SHADE
   SHMatrix SHMatrix::Translate(const SHVec3& pos) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
 
+    XMStoreFloat4x4(&result, XMMatrixTranslation(pos.x, pos.y, pos.z));
     return result;
   }
 
@@ -410,25 +407,23 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMVECTOR A = XMLoadFloat3(&axis);
-    XMStoreFloat4x4(&result, XMMatrixRotationAxis(A, angleInRad));
-
+    XMStoreFloat4x4(&result, XMMatrixRotationAxis(axis, angleInRad));
     return result;
   }
 
   SHMatrix SHMatrix::Rotate(float yaw, float pitch, float roll) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(pitch, yaw, roll));
     return result;
   }
 
   SHMatrix SHMatrix::Rotate(const SHVec3& eulerAngles) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYaw(eulerAngles.x, eulerAngles.y, eulerAngles.z));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationRollPitchYawFromVector(eulerAngles));
     return result;
   }
 
@@ -436,57 +431,55 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMVECTOR Q = XMLoadFloat4(&q);
-    XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(Q));
-
+    XMStoreFloat4x4(&result, XMMatrixRotationQuaternion(q));
     return result;
   }
 
   SHMatrix SHMatrix::RotateX(float angleInRad) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationX(angleInRad));
     return result;
   }
 
   SHMatrix SHMatrix::RotateY(float angleInRad) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationY(angleInRad));
     return result;
   }
 
   SHMatrix SHMatrix::RotateZ(float angleInRad) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
 
+    XMStoreFloat4x4(&result, XMMatrixRotationZ(angleInRad));
     return result;
   }
 
   SHMatrix SHMatrix::Scale(float uniformScaleFactor) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
 
+    XMStoreFloat4x4(&result, XMMatrixScaling(uniformScaleFactor, uniformScaleFactor, uniformScaleFactor));
     return result;
   }
 
   SHMatrix SHMatrix::Scale(float x, float y, float z) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
 
+    XMStoreFloat4x4(&result, XMMatrixScaling(x, y, z));
     return result;
   }
 
   SHMatrix SHMatrix::Scale(const SHVec3& scale) noexcept
   {
     SHMatrix result;
-    XMStoreFloat4x4(&result, XMMatrixScaling(scale.x, scale.y, scale.z));
 
+    XMStoreFloat4x4(&result, XMMatrixScalingFromVector(scale));
     return result;
   }
 
@@ -494,12 +487,7 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMVECTOR EYE  = XMLoadFloat3(&eye);
-    const XMVECTOR TGT  = XMLoadFloat3(&target);
-    const XMVECTOR UP   = XMLoadFloat3(&up);
-
-    XMStoreFloat4x4(&result, XMMatrixLookAtRH(EYE, TGT, UP));
-
+    XMStoreFloat4x4(&result, XMMatrixLookAtRH(eye, target, up));
     return result;
   }
 
@@ -507,12 +495,7 @@ namespace SHADE
   {
     SHMatrix result;
 
-    const XMVECTOR EYE  = XMLoadFloat3(&eye);
-    const XMVECTOR TGT  = XMLoadFloat3(&target);
-    const XMVECTOR UP   = XMLoadFloat3(&up);
-
-    XMStoreFloat4x4(&result, XMMatrixLookAtLH(EYE, TGT, UP));
-
+    XMStoreFloat4x4(&result, XMMatrixLookAtLH(eye, target, up));
     return result;
   }
 
@@ -522,8 +505,8 @@ namespace SHADE
 
     const SHVec3   FWD_HAT  = SHVec3::Normalise(-forward);
 
-    const XMVECTOR Z_HAT    = XMVector3Normalize(XMLoadFloat3(&FWD_HAT));
-    const XMVECTOR X_HAT    = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT));
+    const XMVECTOR Z_HAT    = XMVector3Normalize(FWD_HAT);
+    const XMVECTOR X_HAT    = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
     const XMVECTOR Y_HAT    = XMVector3Cross(Z_HAT, X_HAT);
 
     XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
@@ -543,8 +526,8 @@ namespace SHADE
 
     const SHVec3   FWD_HAT  = SHVec3::Normalise(forward);
 
-    const XMVECTOR Z_HAT    = XMVector3Normalize(XMLoadFloat3(&FWD_HAT));
-    const XMVECTOR X_HAT    = XMVector3Normalize(XMVector3Cross(XMLoadFloat3(&up), Z_HAT));
+    const XMVECTOR Z_HAT    = XMVector3Normalize(FWD_HAT);
+    const XMVECTOR X_HAT    = XMVector3Normalize(XMVector3Cross(up, Z_HAT));
     const XMVECTOR Y_HAT    = XMVector3Cross(Z_HAT, X_HAT);
 
     XMStoreFloat3(reinterpret_cast<XMFLOAT3*>(&result._11), X_HAT);
@@ -563,7 +546,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixPerspectiveFovRH(fov, aspectRatio, nearPlane, farPlane));
-
     return result;
   }
 
@@ -572,7 +554,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixPerspectiveFovLH(fov, aspectRatio, nearPlane, farPlane));
-
     return result;
   }
 
@@ -581,7 +562,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixPerspectiveRH(width, height, nearPlane, farPlane));
-
     return result;
   }
 
@@ -590,7 +570,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixPerspectiveLH(width, height, nearPlane, farPlane));
-
     return result;
   }
 
@@ -599,7 +578,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixOrthographicRH(width, height, nearPlane, farPlane));
-
     return result;
   }
 
@@ -608,7 +586,6 @@ namespace SHADE
     SHMatrix result;
 
     XMStoreFloat4x4(&result, XMMatrixOrthographicLH(width, height, nearPlane, farPlane));
-
     return result;
   }
 
diff --git a/SHADE_Engine/src/Math/SHMatrix.h b/SHADE_Engine/src/Math/SHMatrix.h
index 7a662478..4d8f1bfe 100644
--- a/SHADE_Engine/src/Math/SHMatrix.h
+++ b/SHADE_Engine/src/Math/SHMatrix.h
@@ -77,6 +77,8 @@ namespace SHADE
     SHMatrix&               operator=   (const SHMatrix& rhs) = default;
     SHMatrix&               operator=   (SHMatrix&& rhs)      = default;
 
+    operator DirectX::XMMATRIX          ()                    const noexcept;
+
     SHMatrix&               operator+=  (const SHMatrix& rhs)       noexcept;
     SHMatrix&               operator-=  (const SHMatrix& rhs)       noexcept;
     SHMatrix&               operator*=  (const SHMatrix& rhs)       noexcept;
diff --git a/SHADE_Engine/src/Math/SHQuaternion.cpp b/SHADE_Engine/src/Math/SHQuaternion.cpp
index 33c568a5..3564916a 100644
--- a/SHADE_Engine/src/Math/SHQuaternion.cpp
+++ b/SHADE_Engine/src/Math/SHQuaternion.cpp
@@ -36,44 +36,18 @@ namespace SHADE
   : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
   {}
 
+  SHQuaternion::SHQuaternion(const SHVec4& vec4) noexcept
+  : XMFLOAT4( vec4.x, vec4.y, vec4.z, vec4.w )
+  {}
+
   SHQuaternion::SHQuaternion(float _x, float _y, float _z, float _w) noexcept
   : XMFLOAT4( _x, _y, _z, _w )
   {}
 
-  SHQuaternion::SHQuaternion(float yaw, float pitch, float roll) noexcept
-  : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
-  {
-    XMStoreFloat4(this, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
-  }
-
-  SHQuaternion::SHQuaternion(const SHVec3& eulerAngles) noexcept
-  : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
-  {
-    const XMVECTOR V = XMLoadFloat3(&eulerAngles);
-    XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
-  }
-
-  SHQuaternion::SHQuaternion(const SHVec3& axis, float angleInRad) noexcept
-  : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
-  {
-    const XMVECTOR AXIS = XMLoadFloat3(&axis);
-    XMStoreFloat4(this, XMQuaternionRotationAxis(AXIS, angleInRad));
-  }
-
-  SHQuaternion::SHQuaternion(const SHMatrix& rotationMatrix) noexcept
-  : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
-  {
-    const XMMATRIX M = XMLoadFloat4x4(&rotationMatrix);
-    XMStoreFloat4(this, XMQuaternionRotationMatrix(M));
-  }
-
   SHQuaternion::SHQuaternion(const reactphysics3d::Vector3& rp3dEuler) noexcept
   : XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f )
   {
-    const SHVec3& SHADE_VEC{ rp3dEuler };
-
-    const XMVECTOR V = XMLoadFloat3(&SHADE_VEC);
-    XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(V));
+    XMStoreFloat4(this, XMQuaternionRotationRollPitchYawFromVector(SHVec3 { rp3dEuler }));
   }
 
   SHQuaternion::SHQuaternion(const reactphysics3d::Quaternion& rp3dQuat) noexcept
@@ -113,10 +87,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    XMStoreFloat4(&result, XMVectorAdd(Q1, Q2));
+    XMStoreFloat4(&result, XMVectorAdd(*this, rhs));
     return result;
   }
 
@@ -124,10 +95,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    XMStoreFloat4(&result, XMVectorSubtract(Q1, Q2));
+    XMStoreFloat4(&result, XMVectorSubtract(*this, rhs));
     return result;
   }
 
@@ -135,9 +103,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(this);
-
-    XMStoreFloat4(&result, XMVectorNegate(Q));
+    XMStoreFloat4(&result, XMVectorNegate(*this));
     return result;
   }
 
@@ -145,10 +111,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
+    XMStoreFloat4(&result, XMQuaternionMultiply(*this, rhs));
     return result;
   }
 
@@ -156,9 +119,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(this);
-
-    XMStoreFloat4(&result, XMVectorScale(Q, rhs));
+    XMStoreFloat4(&result, XMVectorScale(*this, rhs));
     return result;
   }
 
@@ -166,27 +127,18 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMQuaternionInverse(XMLoadFloat4(&rhs));
-
-    XMStoreFloat4(&result, XMQuaternionMultiply(Q1, Q2));
+    XMStoreFloat4(&result, XMQuaternionMultiply(*this, XMQuaternionInverse(rhs)));
     return result;
   }
 
   bool SHQuaternion::operator==(const SHQuaternion& rhs) const noexcept
   {
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    return XMQuaternionEqual(Q1, Q2);
+    return XMQuaternionEqual(*this, rhs);
   }
 
   bool SHQuaternion::operator!=(const SHQuaternion& rhs) const noexcept
   {
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    return XMQuaternionNotEqual(Q1, Q2);
+    return XMQuaternionNotEqual(*this, rhs);
   }
 
   SHQuaternion::operator reactphysics3d::Quaternion() const noexcept
@@ -199,6 +151,11 @@ namespace SHADE
     return reactphysics3d::Vector3{ ToEuler() };
   }
 
+  SHQuaternion::operator XMVECTOR() const noexcept
+  {
+    return XMLoadFloat4(this);
+  }
+
   SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept
   {
     return rhs * lhs;
@@ -213,8 +170,7 @@ namespace SHADE
     XMVECTOR axis;
     float angle;
 
-    const XMVECTOR Q = XMLoadFloat4(this);
-    XMQuaternionToAxisAngle(&axis, &angle, Q);
+    XMQuaternionToAxisAngle(&axis, &angle, *this);
     return angle;
   }
 
@@ -223,8 +179,7 @@ namespace SHADE
     XMVECTOR axis;
     float angle;
 
-    const XMVECTOR Q = XMLoadFloat4(this);
-    XMQuaternionToAxisAngle(&axis, &angle, Q);
+    XMQuaternionToAxisAngle(&axis, &angle, *this);
 
 
     return SHVec4{XMVectorGetX(axis), XMVectorGetY(axis), XMVectorGetZ(axis), angle};
@@ -238,64 +193,49 @@ namespace SHADE
 
   void SHQuaternion::Invert() noexcept
   {
-    const XMVECTOR Q = XMLoadFloat4(this);
-    XMStoreFloat4(this, XMQuaternionInverse(Q));
+    XMStoreFloat4(this, XMQuaternionInverse(*this));
   }
 
   float SHQuaternion::Length() const noexcept
   {
-    const XMVECTOR Q = XMLoadFloat4(this);
-    return XMVectorGetX(XMQuaternionLength(Q));
+    return XMVectorGetX(XMQuaternionLength(*this));
   }
 
   float SHQuaternion::LengthSquared() const noexcept
   {
-    const XMVECTOR Q = XMLoadFloat4(this);
-    return XMVectorGetX(XMQuaternionLengthSq(Q));
+    return XMVectorGetX(XMQuaternionLengthSq(*this));
   }
 
   float SHQuaternion::Dot(const SHQuaternion& rhs) const noexcept
   {
-    const XMVECTOR Q1 = XMLoadFloat4(this);
-    const XMVECTOR Q2 = XMLoadFloat4(&rhs);
-
-    return XMVectorGetX(XMQuaternionDot(Q1, Q2));
-  }
-
-  SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion&, float) const noexcept
-  {
-    SHQuaternion result;
-
-    // TODO (Diren)
-
-    return result;
+    return XMVectorGetX(XMQuaternionDot(*this, rhs));
   }
 
   SHVec3 SHQuaternion::ToEuler() const noexcept
   {
-    const float xx = x * x;
-    const float yy = y * y;
-    const float zz = z * z;
+    const float XX = x * x;
+    const float YY = y * y;
+    const float ZZ = z * z;
 
-    const float m31 = 2.f * x * z + 2.f * y * w;
-    const float m32 = 2.f * y * z - 2.f * x * w;
-    const float m33 = 1.f - 2.f * xx - 2.f * yy;
+    const float M_31 = 2.f * x * z + 2.f * y * w;
+    const float M_32 = 2.f * y * z - 2.f * x * w;
+    const float M_33 = 1.f - 2.f * XX - 2.f * YY;
 
-    const float cy = sqrtf(m33 * m33 + m31 * m31);
-    const float cx = atan2f(-m32, cy);
-    if (cy > 16.0f * SHMath::EPSILON)
+    const float CY = sqrtf(M_33 * M_33 + M_31 * M_31);
+    const float CX = atan2f(-M_32, CY);
+    if (CY > 16.0f * SHMath::EPSILON)
     {
-        const float m12 = 2.f * x * y + 2.f * z * w;
-        const float m22 = 1.f - 2.f * xx - 2.f * zz;
+      const float M_12 = 2.f * x * y + 2.f * z * w;
+      const float M_22 = 1.f - 2.f * XX - 2.f * ZZ;
 
-        return SHVec3(cx, atan2f(m31, m33), atan2f(m12, m22));
+      return SHVec3(CX, atan2f(M_31, M_33), atan2f(M_12, M_22));
     }
     else
     {
-        const float m11 = 1.f - 2.f * yy - 2.f * zz;
-        const float m21 = 2.f * x * y - 2.f * z * w;
+      const float m11 = 1.f - 2.f * YY - 2.f * ZZ;
+      const float m21 = 2.f * x * y - 2.f * z * w;
 
-        return SHVec3(cx, 0.f, atan2f(-m21, m11));
+      return SHVec3(CX, 0.f, atan2f(-m21, m11));
     }
   }
 
@@ -311,13 +251,43 @@ namespace SHADE
   /* Static Function Member Definitions                                                */
   /*-----------------------------------------------------------------------------------*/
 
+  SHQuaternion SHQuaternion::FromEuler(const SHVec3& eulerAngles) noexcept
+  {
+    SHQuaternion result;
+
+    XMStoreFloat4(&result, XMQuaternionRotationRollPitchYawFromVector(eulerAngles));
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::FromPitchYawRoll(float pitch, float yaw, float roll) noexcept
+  {
+    SHQuaternion result;
+
+    XMStoreFloat4(&result, XMQuaternionRotationRollPitchYaw(pitch, yaw, roll));
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::FromAxisAngle(const SHVec3& axis, float angle) noexcept
+  {
+    SHQuaternion result;
+
+    XMStoreFloat4(&result, XMQuaternionRotationAxis(axis, angle));
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::FromRotationMatrix(const SHMatrix& rotationMatrix) noexcept
+  {
+    SHQuaternion result;
+
+    XMStoreFloat4(&result, XMQuaternionRotationMatrix(rotationMatrix));
+    return result;
+  }
+
   SHQuaternion SHQuaternion::Normalise(const SHQuaternion& q) noexcept
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(&q);
-    
-    XMStoreFloat4(&result, XMQuaternionNormalize(Q));
+    XMStoreFloat4(&result, XMQuaternionNormalize(q));
     return result;
   }
 
@@ -325,9 +295,7 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(&q);
-    
-    XMStoreFloat4(&result, XMQuaternionConjugate(Q));
+    XMStoreFloat4(&result, XMQuaternionConjugate(q));
     return result;
   }
 
@@ -335,26 +303,37 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q = XMLoadFloat4(&q);
-    XMStoreFloat4(&result, XMQuaternionInverse(Q));
-
+    XMStoreFloat4(&result, XMQuaternionInverse(q));
     return result;
   }
 
 
-  float SHQuaternion::Angle(const SHQuaternion&, const SHQuaternion&) noexcept
+  float SHQuaternion::Angle(const SHQuaternion& q1, const SHQuaternion& q2) noexcept
   {
-    // TODO (Diren)
+    XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(q1), q2);
 
-    return 0.0f;
+    const float RS = XMVectorGetW(R);
+    R = XMVector3Length(R);
+    return 2.0f * atan2f(XMVectorGetX(R), RS);
   }
 
-  SHQuaternion SHQuaternion::Lerp(const SHQuaternion&, const SHQuaternion&, float) noexcept
+  SHQuaternion SHQuaternion::Lerp(const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept
   {
     SHQuaternion result;
 
-    // TODO (Diren)
+    XMVECTOR R = XMVectorZero();
+    if (XMVector4GreaterOrEqual(XMVector4Dot(q1, q2), R))
+    {
+      R = XMVectorLerp(q1, q2, t);
+    }
+    else
+    {
+      const XMVECTOR X0 = XMVectorMultiply(q1, XMVectorReplicate(1.f - t));
+      const XMVECTOR X1 = XMVectorMultiply(q2, XMVectorReplicate(t));
+      R = XMVectorSubtract(X0, X1);
+    }
 
+    XMStoreFloat4(&result, XMQuaternionNormalize(R));
     return result;
   }
 
@@ -362,19 +341,105 @@ namespace SHADE
   {
     SHQuaternion result;
 
-    const XMVECTOR Q1 = XMLoadFloat4(&q1);
-    const XMVECTOR Q2 = XMLoadFloat4(&q2);
-
-    XMStoreFloat4(&result, XMQuaternionSlerp(Q1, Q2, t));
+    XMStoreFloat4(&result, XMQuaternionSlerp(q1, q2, t));
     return result;
   }
 
-  SHQuaternion SHQuaternion::Rotate(const SHVec3& , const SHVec3&) noexcept
+  SHQuaternion SHQuaternion::ClampedLerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
+  {
+    return Lerp(q1, q2, std::clamp(t, tMin, tMax));
+  }
+
+
+  SHQuaternion SHQuaternion::ClampedSlerp(const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin, float tMax) noexcept
+  {
+    return Slerp(q1, q2, std::clamp(t, tMin, tMax));
+  }
+
+  SHQuaternion SHQuaternion::FromToRotation(const SHVec3& from, const SHVec3& to) noexcept
+  {
+    // Melax, "The Shortest Arc Quaternion", Game Programming Gems
+
+    SHQuaternion result;
+
+    const XMVECTOR F = XMVector3Normalize(from);
+    const XMVECTOR T = XMVector3Normalize(to);
+
+    const float dot = XMVectorGetX(XMVector3Dot(F, T));
+    if (dot >= 1.f)
+    {
+        result = Identity;
+    }
+    else if (dot <= -1.f)
+    {
+        XMVECTOR axis = XMVector3Cross(F, SHVec3::Right);
+        if (XMVector3NearEqual(XMVector3LengthSq(axis), g_XMZero, g_XMEpsilon))
+        {
+            axis = XMVector3Cross(F, SHVec3::Up);
+        }
+
+        const XMVECTOR Q = XMQuaternionRotationAxis(axis, XM_PI);
+        XMStoreFloat4(&result, Q);
+    }
+    else
+    {
+        const XMVECTOR C = XMVector3Cross(F, T);
+        XMStoreFloat4(&result, C);
+
+        const float s = sqrtf((1.f + dot) * 2.f);
+        result.x /= s;
+        result.y /= s;
+        result.z /= s;
+        result.w = s * 0.5f;
+    }
+
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::LookRotation(const SHVec3& forward, const SHVec3& up) noexcept
   {
     SHQuaternion result;
 
-    // TODO (Diren)
+    const SHQuaternion Q1 = FromToRotation(SHVec3::Forward, forward);
 
+    const XMVECTOR C = XMVector3Cross(forward, up);
+    if (XMVector3NearEqual(XMVector3LengthSq(C), g_XMZero, g_XMEpsilon))
+    {
+        // forward and up are co-linear
+        return Q1;
+    }
+
+    SHVec3 qU;
+    XMStoreFloat3(&qU, XMQuaternionMultiply(Q1, SHVec3::Up));
+
+    const SHQuaternion Q2 = FromToRotation(qU, up);
+
+    XMStoreFloat4(&result, XMQuaternionMultiply(Q2, Q1));
+
+    return result;
+  }
+
+  SHQuaternion SHQuaternion::RotateTowards(const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept
+  {
+    SHQuaternion result;
+
+    // We can use the conjugate here instead of inverse assuming q1 & q2 are normalized.
+    const XMVECTOR R = XMQuaternionMultiply(XMQuaternionConjugate(from), to);
+
+    const float RS = XMVectorGetW(R);
+    const XMVECTOR L = XMVector3Length(R);
+    const float angle = 2.f * atan2f(XMVectorGetX(L), RS);
+    if (angle > maxAngleInRad)
+    {
+        const XMVECTOR delta = XMQuaternionRotationAxis(R, maxAngleInRad);
+        const XMVECTOR Q = XMQuaternionMultiply(delta, from);
+        XMStoreFloat4(&result, Q);
+    }
+    else
+    {
+        // Don't overshoot.
+        result = to;
+    }
     return result;
   }
 
diff --git a/SHADE_Engine/src/Math/SHQuaternion.h b/SHADE_Engine/src/Math/SHQuaternion.h
index c94907b5..fa5b5d36 100644
--- a/SHADE_Engine/src/Math/SHQuaternion.h
+++ b/SHADE_Engine/src/Math/SHQuaternion.h
@@ -49,11 +49,8 @@ namespace SHADE
     SHQuaternion  (SHQuaternion&& rhs)      = default;
 
     SHQuaternion  ()                                            noexcept;
+    SHQuaternion  (const SHVec4& vec4)                          noexcept;
     SHQuaternion  (float x, float y, float z, float w)          noexcept;
-    SHQuaternion  (float yaw, float pitch, float roll)          noexcept;
-    SHQuaternion  (const SHVec3& eulerAngles)                   noexcept;
-    SHQuaternion  (const SHVec3& axis, float angleInRad)        noexcept;
-    SHQuaternion  (const SHMatrix& rotationMatrix)              noexcept;
 
     // Conversion from other math types
 
@@ -87,6 +84,7 @@ namespace SHADE
 
     operator reactphysics3d::Quaternion       ()                        const noexcept;
     operator reactphysics3d::Vector3          ()                        const noexcept;
+    operator DirectX::XMVECTOR                ()                        const noexcept;
 
     /*---------------------------------------------------------------------------------*/
     /* Getter Functions                                                                */
@@ -99,29 +97,37 @@ namespace SHADE
     /* Function Members                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    void                        Invert        ()                                                      noexcept;
+    void                        Invert        ()  noexcept;
 
-    [[nodiscard]] float         Length        ()                                                const noexcept;
-    [[nodiscard]] float         LengthSquared ()                                                const noexcept;
-    [[nodiscard]] float         Dot           (const SHQuaternion& rhs)                         const noexcept;
-    [[nodiscard]] SHQuaternion  RotateTowards (const SHQuaternion& target, float maxAngleInRad) const noexcept;
+    [[nodiscard]] float         Length        ()  const noexcept;
+    [[nodiscard]] float         LengthSquared ()  const noexcept;
+    [[nodiscard]] float         Dot           (const SHQuaternion& rhs) const noexcept;
 
-    [[nodiscard]] SHVec3        ToEuler       ()                                                const noexcept;
-    [[nodiscard]] std::string   ToString      ()                                                const noexcept;
+    [[nodiscard]] SHVec3        ToEuler       ()  const noexcept;
+    [[nodiscard]] std::string   ToString      ()  const noexcept;
 
     /*---------------------------------------------------------------------------------*/
     /* Static Function Members                                                         */
     /*---------------------------------------------------------------------------------*/
 
-    [[nodiscard]] static SHQuaternion Normalise (const SHQuaternion& q)                                   noexcept;
-    [[nodiscard]] static SHQuaternion Conjugate (const SHQuaternion& q)                                   noexcept;
-    [[nodiscard]] static SHQuaternion Inverse   (const SHQuaternion& q)                                   noexcept;
-    [[nodiscard]] static float        Angle     (const SHQuaternion& q1, const SHQuaternion& q2)          noexcept;
+    [[nodiscard]] static SHQuaternion FromEuler         (const SHVec3& eulerAngles)           noexcept;
+    [[nodiscard]] static SHQuaternion FromPitchYawRoll  (float pitch, float yaw, float roll)  noexcept;
+    [[nodiscard]] static SHQuaternion FromAxisAngle     (const SHVec3& axis, float angle)     noexcept;
+    [[nodiscard]] static SHQuaternion FromRotationMatrix(const SHMatrix& rotationMatrix)      noexcept;
 
-    [[nodiscard]] static SHQuaternion Lerp      (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
-    [[nodiscard]] static SHQuaternion Slerp     (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
+    [[nodiscard]] static SHQuaternion Normalise         (const SHQuaternion& q) noexcept;
+    [[nodiscard]] static SHQuaternion Conjugate         (const SHQuaternion& q) noexcept;
+    [[nodiscard]] static SHQuaternion Inverse           (const SHQuaternion& q) noexcept;
+    [[nodiscard]] static float        Angle             (const SHQuaternion& q1, const SHQuaternion& q2) noexcept;
 
-    [[nodiscard]] static SHQuaternion Rotate    (const SHVec3& from, const SHVec3& to)                    noexcept;
+    [[nodiscard]] static SHQuaternion Lerp              (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
+    [[nodiscard]] static SHQuaternion Slerp             (const SHQuaternion& q1, const SHQuaternion& q2, float t) noexcept;
+    [[nodiscard]] static SHQuaternion ClampedLerp       (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
+    [[nodiscard]] static SHQuaternion ClampedSlerp      (const SHQuaternion& q1, const SHQuaternion& q2, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
+
+    [[nodiscard]] static SHQuaternion FromToRotation  (const SHVec3& from, const SHVec3& to)    noexcept;
+    [[nodiscard]] static SHQuaternion LookRotation    (const SHVec3& forward, const SHVec3& up) noexcept;
+    [[nodiscard]] static SHQuaternion RotateTowards   (const SHQuaternion& from, const SHQuaternion& to, float maxAngleInRad) noexcept;
   };
 
   SHQuaternion operator*(float lhs, const SHQuaternion& rhs) noexcept;
diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.cpp b/SHADE_Engine/src/Math/Transform/SHTransform.cpp
index f51d73ec..ef7c5fda 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransform.cpp
+++ b/SHADE_Engine/src/Math/Transform/SHTransform.cpp
@@ -26,15 +26,15 @@ namespace SHADE
   /*-----------------------------------------------------------------------------------*/
 
   SHTransform::SHTransform() noexcept
-  : position  { SHVec3::Zero }
-  , rotation  { SHVec3::Zero }
-  , scale     { SHVec3::One  }
+  : position    { SHVec3::Zero }
+  , orientation { SHQuaternion::Identity }
+  , scale       { SHVec3::One  }
   {}
 
   SHTransform::SHTransform(const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept
-  : position  { pos }
-  , rotation  { rot }
-  , scale     { scl }
+  : position    { pos }
+  , orientation { SHQuaternion::FromEuler(rot) }
+  , scale       { scl }
   {}
 
   /*-----------------------------------------------------------------------------------*/
@@ -43,12 +43,12 @@ namespace SHADE
 
   bool SHTransform::operator==(const SHTransform& rhs) const noexcept
   {
-    return !(position != rhs.position || rotation != rhs.rotation || scale != rhs.scale);
+    return !(position != rhs.position || orientation != rhs.orientation || scale != rhs.scale);
   }
 
   bool SHTransform::operator!=(const SHTransform& rhs) const noexcept
   {
-    return (position != rhs.position || rotation != rhs.rotation || scale != rhs.scale);
+    return (position != rhs.position || orientation != rhs.orientation || scale != rhs.scale);
   }
 
   /*-----------------------------------------------------------------------------------*/
@@ -59,7 +59,7 @@ namespace SHADE
   {
     
     const SHMatrix T = SHMatrix::Translate(position);
-    const SHMatrix R = SHMatrix::Rotate(rotation);
+    const SHMatrix R = SHMatrix::Rotate(orientation);
     const SHMatrix S = SHMatrix::Scale(scale);
 
     trs = S * R * T;
diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.h b/SHADE_Engine/src/Math/Transform/SHTransform.h
index c1a0e565..2e7d236c 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransform.h
+++ b/SHADE_Engine/src/Math/Transform/SHTransform.h
@@ -12,8 +12,8 @@
 
 // Project Headers
 #include "SH_API.h"
-#include "Math/Vector/SHVec2.h"
 #include "Math/Vector/SHVec3.h"
+#include "Math/SHQuaternion.h"
 #include "Math/SHMatrix.h"
 
 namespace SHADE
@@ -31,22 +31,23 @@ namespace SHADE
 
     static const SHTransform Identity;
 
-    SHVec3    position;
-    SHVec3    rotation;
-    SHVec3    scale;
+    SHVec3        position;
+    SHQuaternion  orientation;
+    SHVec3        scale;
 
-    SHMatrix  trs;
+    SHMatrix      trs;
 
     /*---------------------------------------------------------------------------------*/
     /* Constructors & Destructor                                                       */
     /*---------------------------------------------------------------------------------*/
     
-    SHTransform             (const SHTransform&)  = default;
-    SHTransform             (SHTransform&&)       = default;
-    ~SHTransform            ()                    = default;
+    SHTransform   (const SHTransform&)  = default;
+    SHTransform   (SHTransform&&)       = default;
+    ~SHTransform  ()                    = default;
 
-    SHTransform             ()                                                        noexcept;
-    SHTransform             (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl) noexcept;
+    SHTransform   ()                                                                noexcept;
+    SHTransform   (const SHVec3& pos, const SHVec3& rot, const SHVec3& scl)         noexcept;
+    SHTransform   (const SHVec3& pos, const SHQuaternion& quat, const SHVec3& scl)  noexcept;
 
     /*---------------------------------------------------------------------------------*/
     /* Operator Overloads                                                              */
@@ -63,7 +64,6 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
 
     const SHMatrix& ComputeTRS();
-
   };
 
 } // namespace SHADE
\ No newline at end of file
diff --git a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp
index 949cfa67..e56cbc8d 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp
+++ b/SHADE_Engine/src/Math/Transform/SHTransformComponent.cpp
@@ -12,6 +12,8 @@
 
 // Primary Header
 #include "SHTransformComponent.h"
+// Project Headers
+#include "Math/SHMathHelpers.h"
 
 namespace SHADE
 {
@@ -40,7 +42,12 @@ namespace SHADE
 
   const SHVec3& SHTransformComponent::GetLocalRotation() const noexcept
   {
-    return local.rotation;
+    return localRotation;
+  }
+
+  const SHQuaternion& SHTransformComponent::GetLocalOrientation() const noexcept
+  {
+    return local.orientation;
   }
 
   const SHVec3& SHTransformComponent::GetLocalScale() const noexcept
@@ -55,7 +62,12 @@ namespace SHADE
 
   const SHVec3& SHTransformComponent::GetWorldRotation() const noexcept
   {
-    return world.rotation;
+    return worldRotation;
+  }
+
+  const SHQuaternion& SHTransformComponent::GetWorldOrientation() const noexcept
+  {
+    return world.orientation;
   }
 
   const SHVec3& SHTransformComponent::GetWorldScale() const noexcept
@@ -91,16 +103,28 @@ namespace SHADE
   void SHTransformComponent::SetLocalRotation(const SHVec3& newLocalRotation) noexcept
   {
     dirty = true;
-    local.rotation = newLocalRotation;
+
+    localRotation = newLocalRotation;
+    updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, newLocalRotation });
   }
 
   void SHTransformComponent::SetLocalRotation(float pitch, float yaw, float roll) noexcept
   {
     dirty = true;
 
-    local.rotation.x = pitch;
-    local.rotation.y = yaw;
-    local.rotation.z = roll;
+    localRotation.x = pitch;
+    localRotation.y = yaw;
+    localRotation.z = roll;
+
+    updateQueue.push({ UpdateCommandType::LOCAL_ROTATION, SHVec3{pitch, yaw, roll} });
+  }
+
+  void SHTransformComponent::SetLocalOrientation(const SHQuaternion& newLocalOrientation) noexcept
+  {
+    dirty = true;
+
+    local.orientation = newLocalOrientation;
+    updateQueue.push({ UpdateCommandType::LOCAL_ORIENTATION, newLocalOrientation });
   }
 
   void SHTransformComponent::SetLocalScale(const SHVec3& newLocalScale) noexcept
@@ -121,7 +145,7 @@ namespace SHADE
   {
     dirty = true;
 
-    world.rotation = newWorldRotation;
+    worldRotation = newWorldRotation;
     updateQueue.push({ UpdateCommandType::WORLD_ROTATION, newWorldRotation });
   }
 
@@ -129,13 +153,21 @@ namespace SHADE
   {
     dirty = true;
 
-    world.rotation.x = pitch;
-    world.rotation.y = yaw;
-    world.rotation.z = roll;
+    worldRotation.x = pitch;
+    worldRotation.y = yaw;
+    worldRotation.z = roll;
 
     updateQueue.push({ UpdateCommandType::WORLD_ROTATION, SHVec3{ pitch, yaw, roll} });
   }
 
+  void SHTransformComponent::SetWorldOrientation(const SHQuaternion& newWorldOrientation) noexcept
+  {
+    dirty = true;
+
+    world.orientation = newWorldOrientation;
+    updateQueue.push({ UpdateCommandType::WORLD_ORIENTATION, newWorldOrientation });
+  }
+
   void SHTransformComponent::SetWorldScale(const SHVec3& newWorldScale) noexcept
   {
     dirty = true;
@@ -153,6 +185,6 @@ RTTR_REGISTRATION
 
   registration::class_<SHTransformComponent>("Transform Component")
     .property("Translate" , &SHTransformComponent::GetLocalPosition , &SHTransformComponent::SetLocalPosition                                       )
-    .property("Rotate"    , &SHTransformComponent::GetLocalRotation , select_overload<void(SHVec3 const&)>(&SHTransformComponent::SetLocalRotation) )
+    .property("Rotate"    , &SHTransformComponent::GetLocalRotation , select_overload<void(const SHVec3&)>(&SHTransformComponent::SetLocalRotation) )
     .property("Scale"     , &SHTransformComponent::GetLocalScale    , &SHTransformComponent::SetLocalScale                                          );
 }
\ No newline at end of file
diff --git a/SHADE_Engine/src/Math/Transform/SHTransformComponent.h b/SHADE_Engine/src/Math/Transform/SHTransformComponent.h
index ad355694..2fe67bdd 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransformComponent.h
+++ b/SHADE_Engine/src/Math/Transform/SHTransformComponent.h
@@ -56,42 +56,52 @@ namespace SHADE
     /* Getter Functions                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    [[nodiscard]] bool                HasChanged        ()  const noexcept;
+    [[nodiscard]] bool                HasChanged          ()  const noexcept;
 
-    [[nodiscard]] const SHVec3&       GetLocalPosition  ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetLocalRotation  ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetLocalScale     ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetWorldPosition  ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetWorldRotation  ()  const noexcept;
-    [[nodiscard]] const SHVec3&       GetWorldScale     ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetLocalPosition    ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetLocalRotation    ()  const noexcept;
+    [[nodiscard]] const SHQuaternion& GetLocalOrientation ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetLocalScale       ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetWorldPosition    ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetWorldRotation    ()  const noexcept;
+    [[nodiscard]] const SHQuaternion& GetWorldOrientation ()  const noexcept;
+    [[nodiscard]] const SHVec3&       GetWorldScale       ()  const noexcept;
 
-    [[nodiscard]] const SHMatrix&     GetLocalToWorld   ()  const noexcept;
-    [[nodiscard]] SHMatrix            GetWorldToLocal   ()  const noexcept;
+    [[nodiscard]] const SHMatrix&     GetLocalToWorld     ()  const noexcept;
+    [[nodiscard]] SHMatrix            GetWorldToLocal     ()  const noexcept;
 
-    [[nodiscard]] const SHMatrix&     GetTRS            ()  const noexcept;
+    [[nodiscard]] const SHMatrix&     GetTRS              ()  const noexcept;
 
     /*---------------------------------------------------------------------------------*/
     /* Setter Functions                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    void  SetLocalPosition  (const SHVec3& newLocalPosition)      noexcept;
-    void  SetLocalRotation  (const SHVec3& newLocalRotation)      noexcept;
-    void  SetLocalRotation  (float pitch, float yaw, float roll)  noexcept;
-    void  SetLocalScale     (const SHVec3& newLocalScale)         noexcept;
-    void  SetWorldPosition  (const SHVec3& newWorldPosition)      noexcept;
-    void  SetWorldRotation  (const SHVec3& newWorldRotation)      noexcept;
-    void  SetWorldRotation  (float pitch, float yaw, float roll)  noexcept;
-    void  SetWorldScale     (const SHVec3& newWorldScale)         noexcept;
+    void  SetLocalPosition    (const SHVec3& newLocalPosition)          noexcept;
+    void  SetLocalRotation    (const SHVec3& newLocalRotation)          noexcept;
+    void  SetLocalRotation    (float pitch, float yaw, float roll)      noexcept;
+    void  SetLocalOrientation (const SHQuaternion& newLocalOrientation) noexcept;
+    void  SetLocalScale       (const SHVec3& newLocalScale)             noexcept;
+    void  SetWorldPosition    (const SHVec3& newWorldPosition)          noexcept;
+    void  SetWorldRotation    (const SHVec3& newWorldRotation)          noexcept;
+    void  SetWorldRotation    (float pitch, float yaw, float roll)      noexcept;
+    void  SetWorldOrientation (const SHQuaternion& newWorldOrientation) noexcept;
+    void  SetWorldScale       (const SHVec3& newWorldScale)             noexcept;
 
   private:
     /*---------------------------------------------------------------------------------*/
     /* Type Definitions                                                                */
     /*---------------------------------------------------------------------------------*/
 
+    // Differentiate between rotation and orientation for setters
+    // Setting a quaternion directly is different from using euler angle rotations.
+
     enum class UpdateCommandType
     {
-      WORLD_POSITION
+      LOCAL_ROTATION
+    , LOCAL_ORIENTATION
+    , WORLD_POSITION
     , WORLD_ROTATION
+    , WORLD_ORIENTATION
     , WORLD_SCALE
     };
 
@@ -103,7 +113,7 @@ namespace SHADE
       /*-------------------------------------------------------------------------------*/
 
       UpdateCommandType type;
-      SHVec3            data;
+      SHVec4            data;
     };
 
     using UpdateQueue = std::queue<UpdateCommand>;
@@ -114,6 +124,12 @@ namespace SHADE
 
     bool        dirty;
 
+    // We store euler angle rotations separately to interface with transform quaternions.
+    // Reading quaternions are unreliable.
+
+    SHVec3      localRotation;    // Stored in Radians
+    SHVec3      worldRotation;    // Stored in Radians
+
     SHTransform local;    // Local TRS holds Local To World Transform
     SHTransform world;
 
diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp
index 6b05e323..a2ab6880 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp
+++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.cpp
@@ -17,7 +17,8 @@
 #include "Scene/SHSceneManager.h"
 #include "ECS_Base/Managers/SHComponentManager.h"
 #include "ECS_Base/Managers/SHEntityManager.h"
-#include "Tools/SHException.h"
+#include "ECS_Base/Managers/SHSystemManager.h"
+#include "Math/SHMathHelpers.h"
 
 namespace SHADE
 {
@@ -29,8 +30,12 @@ namespace SHADE
   /* Constructors & Destructor Definitions                                             */
   /*-----------------------------------------------------------------------------------*/
 
-  SHTransformSystem::TransformUpdateRoutine::TransformUpdateRoutine()
-  : SHSystemRoutine { "Transform Update", true }
+  SHTransformSystem::TransformPostLogicUpdate::TransformPostLogicUpdate()
+  : SHSystemRoutine { "Transform Post-Logic Update", true }
+  {}
+
+  SHTransformSystem::TransformPostPhysicsUpdate::TransformPostPhysicsUpdate()
+  : SHSystemRoutine { "Transform Post-Physics Update", false }
   {}
 
 
@@ -38,16 +43,27 @@ namespace SHADE
   /* Public Function Member Definitions                                                */
   /*-----------------------------------------------------------------------------------*/
 
-  void SHTransformSystem::TransformUpdateRoutine::Execute(double) noexcept
+  void SHTransformSystem::TransformPostLogicUpdate::Execute(double) noexcept
   {
     // Get the current scene graph to traverse and update
     const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
-    UpdateEntity(SCENE_GRAPH.GetRoot());
+
+    // TODO(Diren): Consider how to clear dirty in pause / stop mode and update physics, but do not clear in play mode.
+    UpdateEntity(SCENE_GRAPH.GetRoot(), false);
+  }
+
+  void SHTransformSystem::TransformPostPhysicsUpdate::Execute(double) noexcept
+  {
+    // Get the current scene graph to traverse and update
+    const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
+    UpdateEntity(SCENE_GRAPH.GetRoot(), true);
   }
 
   void SHTransformSystem::Init()
   {
-
+    const std::shared_ptr CHANGE_PARENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHTransformSystem>>(this, &SHTransformSystem::ChangeParent) };
+    const ReceiverPtr CHANGE_PARENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(CHANGE_PARENT_RECEIVER);
+    SHEventManager::SubscribeTo(SH_SCENEGRAPH_CHANGE_PARENT_EVENT, CHANGE_PARENT_RECEIVER_PTR);
   }
 
   void SHTransformSystem::Exit()
@@ -59,7 +75,53 @@ namespace SHADE
   /* Private Function Member Definitions                                               */
   /*-----------------------------------------------------------------------------------*/
 
-  void SHTransformSystem::UpdateEntity(const SHSceneNode* node)
+  void SHTransformSystem::UpdateChildrenLocalTransforms(SHSceneNode* node)
+  {
+    // Structure is similar to update entity, albeit without a queue to do being a forced update
+    for (const auto* child : node->GetChildren())
+    {
+      if (auto* childTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(child->GetEntityID()); childTransform)
+      {
+        const bool IS_NODE_ACTIVE = child->IsActive();
+        if (IS_NODE_ACTIVE && childTransform->isActive)
+        {
+          // Recompute local transform and store localToWorld Matrix
+          SHMatrix localToWorld = SHMatrix::Identity; 
+          SHMatrix worldToLocal = SHMatrix::Identity;
+
+          const auto* parent = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
+
+          if (parent != nullptr) // Not the root
+          {
+            localToWorld = parent->GetTRS();
+            worldToLocal = SHMatrix::Inverse(localToWorld);
+          }
+
+          // Maintain World Transform and recompute Local Transform
+
+          // Compute Local Position
+          childTransform->local.position = SHVec3::Transform(childTransform->world.position, worldToLocal);
+
+          
+          childTransform->localRotation = childTransform->worldRotation;
+          childTransform->local.scale   = childTransform->world.scale;
+
+          if (parent)
+          {
+            // Compute Local Rotation
+            childTransform->localRotation -= parent->GetLocalRotation();
+
+            // Compute Local Scale
+            childTransform->local.scale /= parent->GetLocalScale();
+          }
+
+          childTransform->local.trs = localToWorld;
+        }
+      }
+    }
+  }
+
+  void SHTransformSystem::UpdateEntity(const SHSceneNode* node, bool clearDirtyFlag)
   {
     const auto* NODE_TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
     const bool HAS_PARENT_CHANGED = NODE_TRANSFORM && NODE_TRANSFORM->dirty;
@@ -74,14 +136,17 @@ namespace SHADE
         if (IS_NODE_ACTIVE && childTransform->isActive)
         {
           if (childTransform->dirty || HAS_PARENT_CHANGED)
+          {
             UpdateTransform(*childTransform, NODE_TRANSFORM);
+            childTransform->dirty = true;
+          }
         }
       }
 
-      UpdateEntity(child);
+      UpdateEntity(child, clearDirtyFlag);
 
       // Clear dirty flag after all children are updated
-      if (childTransform)
+      if (childTransform && clearDirtyFlag)
         childTransform->dirty = false;
     }
   }
@@ -91,6 +156,8 @@ namespace SHADE
     SHMatrix localToWorld = SHMatrix::Identity;
     SHMatrix worldToLocal = SHMatrix::Identity;
 
+    bool convertRotation = true;
+
     if (parent)
     {
       localToWorld = parent->GetTRS();
@@ -103,22 +170,44 @@ namespace SHADE
 
       switch (UPDATE_COMMAND.type)
       {
+        case SHTransformComponent::UpdateCommandType::LOCAL_ROTATION:
+        {
+          convertRotation = true;
+          break;
+        }
+        case SHTransformComponent::UpdateCommandType::LOCAL_ORIENTATION:
+        {
+          convertRotation = false;
+          break;
+        }
         case SHTransformComponent::UpdateCommandType::WORLD_POSITION:
         {
-          tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data, worldToLocal);
+          tf.local.position = SHVec3::Transform(UPDATE_COMMAND.data.ToVec3(), worldToLocal);
           break;
         }
         case SHTransformComponent::UpdateCommandType::WORLD_ROTATION:
         {
-          tf.local.rotation = tf.world.rotation;
+          tf.localRotation = UPDATE_COMMAND.data.ToVec3();
           if (parent)
-            tf.local.rotation -= parent->GetLocalRotation();
+            tf.localRotation -= parent->GetLocalRotation();
+
+          convertRotation = true;
+
+          break;
+        }
+        case SHTransformComponent::UpdateCommandType::WORLD_ORIENTATION:
+        {
+          tf.local.orientation = UPDATE_COMMAND.data;
+          if (parent)
+            tf.local.orientation /= parent->GetLocalOrientation();
+
+          convertRotation = false;
 
           break;
         }
         case SHTransformComponent::UpdateCommandType::WORLD_SCALE:
         {
-          tf.local.scale = tf.world.scale;
+          tf.local.scale = UPDATE_COMMAND.data.ToVec3();
           if (parent)
             tf.local.scale /= parent->GetLocalScale();
 
@@ -133,15 +222,83 @@ namespace SHADE
 
     tf.local.trs = localToWorld;
 
+    // Compute world transforms
     tf.world.position = SHVec3::Transform(tf.local.position, localToWorld);
-    tf.world.rotation = tf.local.rotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);
     tf.world.scale    = tf.local.scale * (parent ? parent->GetLocalScale() : SHVec3::One);
 
-    tf.world.ComputeTRS();
+    
 
-    // Transpose TRS to column major
-    //tf.local.trs.Transpose();
-    //tf.world.trs.Transpose();
+    if (convertRotation)
+    {
+      tf.worldRotation  = tf.localRotation + (parent ? parent->GetLocalRotation() : SHVec3::Zero);
+
+      // Set the orientation
+      // Wrap rotations between -360 and 360 and convert to radians
+      SHVec3 worldRotRad, localRotRad;
+      for (size_t i = 0; i < SHVec3::SIZE; ++i)
+      {
+        worldRotRad[i] = SHMath::Wrap(tf.worldRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI);
+        localRotRad[i] = SHMath::Wrap(tf.localRotation[i], -SHMath::TWO_PI, SHMath::TWO_PI);
+      }
+
+      tf.world.orientation = SHQuaternion::FromEuler(worldRotRad);
+      tf.local.orientation = SHQuaternion::FromEuler(localRotRad);
+    }
+    else
+    {
+      tf.world.orientation = (parent ? parent->GetLocalOrientation() : SHQuaternion::Identity) * tf.local.orientation;
+
+      // Set the euler angle rotations
+      tf.worldRotation = tf.world.orientation.ToEuler();
+      tf.localRotation = tf.local.orientation.ToEuler();
+    }
+
+    tf.world.ComputeTRS();
+  }
+
+  SHEventHandle SHTransformSystem::ChangeParent(SHEventPtr changeParentEvent)
+  {
+    const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHSceneGraphChangeParentEvent>*>(changeParentEvent.get());
+
+    auto* node = EVENT_DATA->data->node;
+    auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(node->GetEntityID());
+
+    // Recompute local transform and store localToWorld Matrix
+    SHMatrix localToWorld = SHMatrix::Identity; 
+    SHMatrix worldToLocal = SHMatrix::Identity;
+
+    auto* newParent = EVENT_DATA->data->newParent;
+    const auto* PARENT_TF = SHComponentManager::GetComponent_s<SHTransformComponent>(newParent->GetEntityID());
+    if (PARENT_TF != nullptr) // Not the root
+    {
+      localToWorld = PARENT_TF->GetTRS();
+      worldToLocal = SHMatrix::Inverse(localToWorld);
+    }
+
+    // Maintain World Transform and recompute Local Transform
+
+    // Compute Local Position
+    tf->local.position = SHVec3::Transform(tf->world.position, worldToLocal);
+
+          
+    tf->localRotation = tf->worldRotation;
+    tf->local.scale   = tf->world.scale;
+
+    if (PARENT_TF != nullptr)
+    {
+      // Compute Local Rotation
+      tf->localRotation -= PARENT_TF->GetLocalRotation();
+
+      // Compute Local Scale
+      tf->local.scale /= PARENT_TF->GetLocalScale();
+    }
+
+    tf->local.trs = localToWorld;
+
+    // Propagate maintaining world transform down the branch
+    UpdateChildrenLocalTransforms(node);
+
+    return EVENT_DATA->handle;
   }
 
 } // namespace SHADE
\ No newline at end of file
diff --git a/SHADE_Engine/src/Math/Transform/SHTransformSystem.h b/SHADE_Engine/src/Math/Transform/SHTransformSystem.h
index 02c3b6c6..bb373f3a 100644
--- a/SHADE_Engine/src/Math/Transform/SHTransformSystem.h
+++ b/SHADE_Engine/src/Math/Transform/SHTransformSystem.h
@@ -11,9 +11,9 @@
 #pragma once
 
 // Project Headers
-#include "SHTransformComponent.h"
-#include "Scene/SHSceneGraph.h"
 #include "ECS_Base/System/SHSystemRoutine.h"
+#include "Scene/SHSceneGraph.h"
+#include "SHTransformComponent.h"
 
 namespace SHADE
 {
@@ -45,25 +45,30 @@ namespace SHADE
     /* System Routines                                                                 */
     /*---------------------------------------------------------------------------------*/
 
-    class SH_API TransformUpdateRoutine final: public SHSystemRoutine
+    class SH_API TransformPostLogicUpdate final: public SHSystemRoutine
     {
     public:
       /*-------------------------------------------------------------------------------*/
       /* Constructors & Destructor                                                     */
       /*-------------------------------------------------------------------------------*/
 
-      TransformUpdateRoutine   ();
-      ~TransformUpdateRoutine  () = default;
-
-      TransformUpdateRoutine   (const TransformUpdateRoutine&)  = delete;
-      TransformUpdateRoutine   (TransformUpdateRoutine&&)       = delete;
+      TransformPostLogicUpdate   ();
 
       /*-------------------------------------------------------------------------------*/
-      /* Operator Overloads                                                            */
+      /* Function Members                                                              */
       /*-------------------------------------------------------------------------------*/
 
-      TransformUpdateRoutine& operator= (const TransformUpdateRoutine&) = delete;
-      TransformUpdateRoutine& operator= (TransformUpdateRoutine&&)      = delete;
+      void Execute(double dt) noexcept override;
+    };
+
+    class SH_API TransformPostPhysicsUpdate final: public SHSystemRoutine
+    {
+    public:
+      /*-------------------------------------------------------------------------------*/
+      /* Constructors & Destructor                                                     */
+      /*-------------------------------------------------------------------------------*/
+
+      TransformPostPhysicsUpdate   ();
 
       /*-------------------------------------------------------------------------------*/
       /* Function Members                                                              */
@@ -84,8 +89,14 @@ namespace SHADE
     /* Function Members                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    static void UpdateEntity   (const SHSceneNode* node);
-    static void UpdateTransform(SHTransformComponent& tf, const SHTransformComponent* parent = nullptr);
+    static void   UpdateChildrenLocalTransforms (SHSceneNode* node);
+
+    static void   UpdateEntity                  (const SHSceneNode* node, bool clearDirtyFlag);
+    static void   UpdateTransform               (SHTransformComponent& tf, const SHTransformComponent* parent = nullptr);
+
+    // Event Handlers
+
+    SHEventHandle ChangeParent                  (SHEventPtr changeParentEvent);
   };
 
 
diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.cpp b/SHADE_Engine/src/Math/Vector/SHVec4.cpp
index bcf2ef97..9857818a 100644
--- a/SHADE_Engine/src/Math/Vector/SHVec4.cpp
+++ b/SHADE_Engine/src/Math/Vector/SHVec4.cpp
@@ -38,6 +38,10 @@ namespace SHADE
   : XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f )
   {}
 
+  SHVec4::SHVec4(const SHVec3& vec3) noexcept
+  : XMFLOAT4( vec3.x, vec3.y, vec3.z, 1.0f )
+  {}
+
   SHVec4::SHVec4(const XMFLOAT4& xmfloat4) noexcept
   : XMFLOAT4( xmfloat4.x, xmfloat4.y, xmfloat4.z, xmfloat4.w )
   {}
@@ -271,6 +275,11 @@ namespace SHADE
     return result;
   }
 
+  SHVec3 SHVec4::ToVec3() const noexcept
+  {
+    return SHVec3{ x, y, z };
+  }
+
   /*-----------------------------------------------------------------------------------*/
   /* Static Function Member Definitions                                                */
   /*-----------------------------------------------------------------------------------*/
diff --git a/SHADE_Engine/src/Math/Vector/SHVec4.h b/SHADE_Engine/src/Math/Vector/SHVec4.h
index 911a714e..ce341bed 100644
--- a/SHADE_Engine/src/Math/Vector/SHVec4.h
+++ b/SHADE_Engine/src/Math/Vector/SHVec4.h
@@ -16,6 +16,7 @@
 
 // Project Headers
 #include "SH_API.h"
+#include "SHVec3.h"
 
 namespace SHADE
 {
@@ -53,6 +54,7 @@ namespace SHADE
     ~SHVec4 ()                  = default;
 
     SHVec4  ()                                    noexcept;
+    SHVec4  (const SHVec3& vec3)                  noexcept;
     SHVec4  (const XMFLOAT4& xmfloat4)            noexcept;
     SHVec4  (float x, float y, float z, float w)  noexcept;
 
@@ -102,16 +104,18 @@ namespace SHADE
     [[nodiscard]] float         Dot3D           (const SHVec4& rhs)                   const noexcept;
     [[nodiscard]] SHVec4        Cross3D         (const SHVec4& rhs)                   const noexcept;
     [[nodiscard]] SHVec4        Cross           (const SHVec4& v1, const SHVec4& v2)  const noexcept;
+
+    [[nodiscard]] SHVec3        ToVec3          ()                                    const noexcept;
   
     /*---------------------------------------------------------------------------------*/
     /* Static Function Members                                                         */
     /*---------------------------------------------------------------------------------*/
 
-    [[nodiscard]] static SHVec4 Normalise         (const SHVec4& v)                                                              noexcept;
-    [[nodiscard]] static SHVec4 Normalise3D       (const SHVec4& v)                                                              noexcept;
-    [[nodiscard]] static SHVec4 Abs               (const SHVec4& v)                                                              noexcept;
-    [[nodiscard]] static SHVec4 Min               (const std::initializer_list<SHVec4>& vs)                                      noexcept;
-    [[nodiscard]] static SHVec4 Max               (const std::initializer_list<SHVec4>& vs)                                      noexcept;
+    [[nodiscard]] static SHVec4 Normalise         (const SHVec4& v)                                                                 noexcept;
+    [[nodiscard]] static SHVec4 Normalise3D       (const SHVec4& v)                                                                 noexcept;
+    [[nodiscard]] static SHVec4 Abs               (const SHVec4& v)                                                                 noexcept;
+    [[nodiscard]] static SHVec4 Min               (const std::initializer_list<SHVec4>& vs)                                         noexcept;
+    [[nodiscard]] static SHVec4 Max               (const std::initializer_list<SHVec4>& vs)                                         noexcept;
     [[nodiscard]] static SHVec4 Clamp             (const SHVec4& v, const SHVec4& vMin, const SHVec4& vMax)                         noexcept;
     [[nodiscard]] static SHVec4 Lerp              (const SHVec4& a, const SHVec4& b, float t)                                       noexcept;
     [[nodiscard]] static SHVec4 ClampedLerp       (const SHVec4& a, const SHVec4& b, float t, float tMin = 0.0f, float tMax = 1.0f) noexcept;
diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp
index 71183f00..75a00491 100644
--- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp
+++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp
@@ -26,7 +26,6 @@ namespace SHADE
 
   SHColliderComponent::SHColliderComponent() noexcept
   : system    { nullptr }
-  , colliders {}
   {}
 
   /*-----------------------------------------------------------------------------------*/
@@ -69,31 +68,24 @@ namespace SHADE
   void SHColliderComponent::OnCreate()
   {
     system = SHSystemManager::GetSystem<SHPhysicsSystem>();
-    if (!system)
-    {
-      SHLOG_ERROR("Physics system does not exist, Collider Component not added!")
-      return;
-    }
-
-    system->AddCollider(GetEID());
   }
 
   void SHColliderComponent::OnDestroy()
   {
-    if (!system)
-    {
-      SHLOG_ERROR("Physics system does not exist, unable to remove Collider component!")
-      return;
-    }
 
-    system->RemoveCollider(GetEID());
   }
 
   SHBoundingBox* SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset) noexcept
   {
-    const auto TYPE = SHCollider::Type::BOX;
+    if (!system)
+    {
+      SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!")
+      return nullptr;
+    }
 
-    auto boxPair = std::make_pair(SHCollider{TYPE}, true);
+    static constexpr auto TYPE = SHCollider::Type::BOX;
+
+    auto boxPair = std::make_pair(SHCollider{ TYPE }, true);
     auto& collider = colliders.emplace_back(boxPair).first;
 
     const auto* tf = SHComponentManager::GetComponent<SHTransformComponent>(GetEID());
@@ -101,12 +93,6 @@ namespace SHADE
     collider.SetPositionOffset(posOffset);
     collider.SetAsBoundingBox(tf->GetWorldScale() * halfExtents);
 
-    if (!system)
-    {
-      SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!")
-      return nullptr;
-    }
-
     // Notify Physics System
     system->AddCollisionShape(GetEID(), &collider);
 
@@ -115,7 +101,13 @@ namespace SHADE
 
   SHBoundingSphere* SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept
   {
-    const auto TYPE = SHCollider::Type::SPHERE;
+    if (!system)
+    {
+      SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!")
+      return nullptr;
+    }
+
+    static constexpr auto TYPE = SHCollider::Type::SPHERE;
 
     auto spherePair = std::make_pair(SHCollider{ TYPE }, true);
     auto& collider = colliders.emplace_back(spherePair).first;
@@ -126,13 +118,7 @@ namespace SHADE
 
     const SHVec3 TF_WORLD_SCALE = tf->GetWorldScale();
     const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
-    collider.SetAsBoundingSphere(MAX_SCALE * 0.5f);
-
-    if (!system)
-    {
-      SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!")
-      return nullptr;
-    }
+    collider.SetAsBoundingSphere(MAX_SCALE * 0.5f * radius);
 
     // Notify Physics System
     system->AddCollisionShape(GetEID(), &collider);
diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h
index 22d5ceee..4ecd0e93 100644
--- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h
+++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h
@@ -44,7 +44,7 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
 
     using ColliderDirtyPair = std::pair<SHCollider, bool>;
-    using Colliders = std::vector<ColliderDirtyPair>;
+    using Colliders         = std::vector<ColliderDirtyPair>;
 
   public:
 
@@ -81,10 +81,10 @@ namespace SHADE
     /* Function Members                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    void            OnCreate          ()          override;
-    void            OnDestroy         ()          override;
+    void              OnCreate          ()          override;
+    void              OnDestroy         ()          override;
 
-    void            RemoveCollider    (int index);
+    void              RemoveCollider    (int index);
 
     SHBoundingBox*    AddBoundingBox    (const SHVec3& halfExtents = SHVec3::One, const SHVec3& posOffset = SHVec3::Zero) noexcept;
     SHBoundingSphere* AddBoundingSphere (float radius = 1.0f, const SHVec3& posOffset = SHVec3::Zero) noexcept;
diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp
index e5938717..b0172f64 100644
--- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp
+++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp
@@ -28,11 +28,10 @@ namespace SHADE
   , flags       { 0 }
   , dirtyFlags  { 0 }
   , interpolate { true }
-  , system      { nullptr }
+  , rp3dBody    { nullptr }
   , mass        { 1.0f }
   , drag        { 0.01f }
   , angularDrag { 0.01f }
-  
   {
     // Set default flags: Gravity & Sleeping enabled
     flags |= 1U << 0;
@@ -161,7 +160,13 @@ namespace SHADE
 
   void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept
   {
-    constexpr int FLAG_POS = 0;
+    static constexpr int FLAG_POS = 0;
+
+    if (type != Type::DYNAMIC)
+    {
+      SHLOG_WARNING("Cannot enable gravity of a non-dynamic object {}", GetEID())
+      return;
+    }
 
     dirtyFlags |= 1U << FLAG_POS;
     enableGravity ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@@ -169,7 +174,13 @@ namespace SHADE
 
   void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept
   {
-    constexpr int FLAG_POS = 1;
+    static constexpr int FLAG_POS = 1;
+
+    if (type != Type::DYNAMIC)
+    {
+      SHLOG_WARNING("Cannot enable sleeping of a non-dynamic object {}", GetEID())
+      return;
+    }
 
     dirtyFlags |= 1U << 1;
     isAllowedToSleep ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@@ -177,7 +188,13 @@ namespace SHADE
 
   void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept
   {
-    constexpr int FLAG_POS = 2;
+    static constexpr int FLAG_POS = 2;
+
+    if (type == Type::STATIC)
+    {
+      SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
+      return;
+    }
 
     dirtyFlags |= 1U << 2;
     freezePositionX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@@ -185,7 +202,13 @@ namespace SHADE
 
   void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept
   {
-    constexpr int FLAG_POS = 3;
+    static constexpr int FLAG_POS = 3;
+
+    if (type == Type::STATIC)
+    {
+      SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
+      return;
+    }
 
     dirtyFlags |= 1U << 2;
     freezePositionY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@@ -193,7 +216,13 @@ namespace SHADE
 
   void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept
   {
-    constexpr int FLAG_POS = 4;
+    static constexpr int FLAG_POS = 4;
+
+    if (type == Type::STATIC)
+    {
+      SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
+      return;
+    }
 
     dirtyFlags |= 1U << 2;
     freezePositionZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@@ -201,7 +230,13 @@ namespace SHADE
 
   void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept
   {
-    constexpr int FLAG_POS = 5;
+    static constexpr int FLAG_POS = 5;
+
+    if (type == Type::STATIC)
+    {
+      SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
+      return;
+    }
 
     dirtyFlags |= 1U << 3;
     freezeRotationX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@@ -209,7 +244,13 @@ namespace SHADE
 
   void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept
   {
-    constexpr int FLAG_POS = 6;
+    static constexpr int FLAG_POS = 6;
+
+    if (type == Type::STATIC)
+    {
+      SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
+      return;
+    }
 
     dirtyFlags |= 1U << 3;
     freezeRotationY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@@ -217,7 +258,13 @@ namespace SHADE
 
   void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept
   {
-    constexpr int FLAG_POS = 7;
+    static constexpr int FLAG_POS = 7;
+
+    if (type == Type::STATIC)
+    {
+      SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
+      return;
+    }
 
     dirtyFlags |= 1U << 3;
     freezeRotationZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
@@ -230,30 +277,60 @@ namespace SHADE
 
   void SHRigidBodyComponent::SetMass(float newMass) noexcept
   {
+    if (type != Type::DYNAMIC)
+    {
+      SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID())
+      return;
+    }
+
     dirtyFlags |=  1U << 5;
     mass = newMass;
   }
 
   void SHRigidBodyComponent::SetDrag(float newDrag) noexcept
   {
+    if (type != Type::DYNAMIC)
+    {
+      SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID())
+      return;
+    }
+
     dirtyFlags |=  1U << 6;
     drag = newDrag;
   }
 
   void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept
   {
+    if (type != Type::DYNAMIC)
+    {
+      SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID())
+      return;
+    }
+
     dirtyFlags |=  1U << 7;
     angularDrag = newAngularDrag;
   }
 
   void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept
   {
+    if (type == Type::STATIC)
+    {
+      SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID())
+      return;
+    }
+
     dirtyFlags |= 1U << 8;
     linearVelocity = newLinearVelocity;
   }
 
   void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept
   {
+    if (type == Type::STATIC)
+    {
+      SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID())
+      return;
+    }
+
     dirtyFlags |= 1U << 9;
     angularVelocity = newAngularVelocity;
   }
@@ -262,125 +339,92 @@ namespace SHADE
   /* Public Function Member Definitions                                                */
   /*-----------------------------------------------------------------------------------*/
 
-  void SHRigidBodyComponent::OnCreate()
-  {
-    system = SHSystemManager::GetSystem<SHPhysicsSystem>();
-    if (!system)
-    {
-      SHLOG_ERROR("Physics system does not exist, Rigid Body Component not added!")
-      return;
-    }
-
-    // Notify Physics System
-    system->AddRigidBody(GetEID());
-  }
-
-  void SHRigidBodyComponent::OnDestroy()
-  {
-    // Notify Physics System
-    if (!system)
-    {
-      SHLOG_ERROR("Physics system does not exist, unable to remove Rigid Body Component!")
-      return;
-    }
-
-    system->RemoveRigidBody(GetEID());
-  }
-
   void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept
   {
-    if (!system)
+    if (rp3dBody == nullptr)
     {
-      SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
+      SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
       return;
     }
 
-    // Notify Physics Systems
-    system->AddForce(GetEID(), force);
+    rp3dBody->applyWorldForceAtCenterOfMass(force);
   }
 
   void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept
   {
-    if (!system)
+    if (rp3dBody == nullptr)
     {
-      SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
+      SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
       return;
     }
 
-    // Notify Physics Systems
-    system->AddForceAtLocalPos(GetEID(), force, localPos);
+    rp3dBody->applyWorldForceAtLocalPosition(force, localPos);
   }
 
   void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept
   {
-    if (!system)
+    if (rp3dBody == nullptr)
     {
-      SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
+      SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
       return;
     }
 
-    // Notify Physics Systems
-    system->AddForceAtWorldPos(GetEID(), force, worldPos);
+    rp3dBody->applyWorldForceAtWorldPosition(force, worldPos);
   }
 
   void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept
   {
-    if (!system)
+    if (rp3dBody == nullptr)
     {
-      SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
+      SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
       return;
     }
 
-    // Notify Physics Systems
-    system->AddRelativeForce(GetEID(), force);
+    rp3dBody->applyLocalForceAtCenterOfMass(relativeForce);
   }
 
   void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept
   {
-    if (!system)
+    if (rp3dBody == nullptr)
     {
-      SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
+      SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
       return;
     }
 
-    // Notify Physics Systems
-    system->AddRelativeForceAtLocalPos(GetEID(), force, localPos);
+    rp3dBody->applyLocalForceAtLocalPosition(relativeForce, localPos);
   }
 
   void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept
   {
-    if (!system)
+    if (rp3dBody == nullptr)
     {
-      SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
+      SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
       return;
     }
 
-    // Notify Physics Systems
-    system->AddRelativeForceAtWorldPos(GetEID(), force, worldPos);
+    rp3dBody->applyLocalForceAtWorldPosition(relativeForce, worldPos);
   }
 
   void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept
   {
-    if (!system)
+    if (rp3dBody == nullptr)
     {
-      SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
+      SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
       return;
     }
 
-    // Notify Physics Systems
-    system->AddTorque(GetEID(), torque);
+    rp3dBody->applyWorldTorque(torque);
   }
 
   void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept
   {
-    if (!system)
+    if (rp3dBody == nullptr)
     {
-      SHLOG_ERROR("Physics system does not exist, unable to Add Force to a body!")
+      SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
       return;
     }
 
-    // Notify Physics Systems
-    system->AddRelativeTorque(GetEID(), relativeTorque);
+    rp3dBody->applyLocalTorque(relativeTorque);
   }
 
 } // namespace SHADE
diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h
index 03b350e1..78de84e7 100644
--- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h
+++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h
@@ -10,6 +10,7 @@
 
 #pragma once
 
+#include <reactphysics3d/reactphysics3d.h>
 #include <rttr/registration>
 
 // Project Headers
@@ -125,9 +126,6 @@ namespace SHADE
     /* Function Members                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    void  OnCreate                    ()                                                    override;
-    void  OnDestroy                   ()                                                    override;
-
     void  AddForce                    (const SHVec3& force)                                 const noexcept;
     void  AddForceAtLocalPos          (const SHVec3& force, const SHVec3& localPos)         const noexcept;
     void  AddForceAtWorldPos          (const SHVec3& force, const SHVec3& worldPos)         const noexcept;
@@ -155,7 +153,7 @@ namespace SHADE
     uint16_t          dirtyFlags;
     bool              interpolate;
 
-    SHPhysicsSystem*  system;
+    rp3d::RigidBody*  rp3dBody;
 
     float             mass;
     float             drag;
@@ -167,8 +165,6 @@ namespace SHADE
     SHVec3            torque;
     SHVec3            angularVelocity;
 
-    // TODO(Diren): Once quaternions have replaced euler angles in transforms, store it for the rigidbody.
-
     SHVec3            position;
     SHQuaternion      orientation;
 
diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp
index 36f7c57e..986ce503 100644
--- a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp
+++ b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp
@@ -26,8 +26,6 @@ namespace SHADE
 
   SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
   : entityID    { eid }
-  , isRigidBody { false }
-  , hasColliders{ false }
   , factory     { physicsFactory }
   , world       { physicsWorld }
   , rp3dBody    { nullptr }
@@ -130,42 +128,6 @@ namespace SHADE
   /* Public Function Member Definitions                                                */
   /*-----------------------------------------------------------------------------------*/
 
-  void SHPhysicsObject::CreateRigidBody(const SHTransformComponent* tf, SHRigidBodyComponent* rb, SHColliderComponent* c)
-  {
-    // If collider already exists, recreate the collision body as a rigid body
-    if (hasColliders)
-      world->destroyCollisionBody(rp3dBody);
-
-    rp3dBody     = world->createRigidBody(rp3d::Transform{ tf->GetWorldPosition(), tf->GetWorldRotation() });
-    isRigidBody  = true;
-
-    rb->position    = tf->GetWorldPosition();
-    rb->orientation = tf->GetWorldRotation();
-
-    if (hasColliders)
-    {
-      c->position    = tf->GetWorldPosition();
-      c->orientation = tf->GetWorldRotation();
-      // Get array of colliders and add them back into the rigidbody
-      for (auto& collider : c->colliders | std::views::keys)
-        AddCollider(&collider);
-    }
-  }
-
-  void SHPhysicsObject::CreateCollisionBody(const SHTransformComponent* tf, SHColliderComponent* c)
-  {
-    if (rp3dBody == nullptr)
-      rp3dBody = world->createCollisionBody(rp3d::Transform{ tf->GetWorldPosition(), tf->GetWorldRotation() });
-
-    hasColliders = true;
-
-    c->position    = tf->GetWorldPosition();
-    c->orientation = tf->GetWorldRotation();
-
-    for (auto& collider : c->colliders | std::views::keys)
-      AddCollider(&collider);
-  }
-
   int SHPhysicsObject::AddCollider(SHCollider* collider)
   {
     switch (collider->GetType())
@@ -193,31 +155,6 @@ namespace SHADE
     return static_cast<int>(rp3dBody->getNbColliders()) - 1;
   }
 
-  void SHPhysicsObject::DestroyRigidBody(SHColliderComponent* c) noexcept
-  {
-    world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(rp3dBody));
-
-    if (hasColliders)
-    {
-      // Preserve colliders as a collision body
-      rp3dBody = world->createCollisionBody(rp3d::Transform{ c->position, c->orientation });
-      for (auto& collider : c->colliders | std::views::keys)
-        AddCollider(&collider);
-    }
-
-    isRigidBody = false;
-  }
-
-  void SHPhysicsObject::DestroyCollisionBody() noexcept
-  {
-    // Remove all colliders
-    for (uint32_t i = 0; i < rp3dBody->getNbColliders(); ++i)
-    {
-      auto* collider = rp3dBody->getCollider(i);
-      rp3dBody->removeCollider(collider);
-    }
-  }
-
   void SHPhysicsObject::RemoveCollider(int index)
   {
     const int NUM_COLLIDERS = static_cast<int>(rp3dBody->getNbColliders());
diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.h b/SHADE_Engine/src/Physics/SHPhysicsObject.h
index 39a85421..67e5ec64 100644
--- a/SHADE_Engine/src/Physics/SHPhysicsObject.h
+++ b/SHADE_Engine/src/Physics/SHPhysicsObject.h
@@ -69,13 +69,8 @@ namespace SHADE
     /* Function Members                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    void  CreateRigidBody       (const SHTransformComponent* tf, SHRigidBodyComponent* rb, SHColliderComponent* c);
-    void  CreateCollisionBody   (const SHTransformComponent* tf, SHColliderComponent* c);
     int   AddCollider           (SHCollider* collider);
-
-    void  DestroyRigidBody      (SHColliderComponent* c)      noexcept;
     void  RemoveCollider        (int index);
-    void  DestroyCollisionBody  ()                            noexcept;
 
     void  SyncRigidBody         (SHRigidBodyComponent* rb)    const noexcept;
     void  SyncColliders         (SHColliderComponent* c)      const noexcept;
@@ -86,8 +81,6 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
 
     EntityID              entityID;
-    bool                  isRigidBody;
-    bool                  hasColliders;
 
     rp3d::PhysicsCommon*  factory;
     rp3d::PhysicsWorld*   world;
diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp
index 7dc6c44e..1c6e79d7 100644
--- a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp
+++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp
@@ -16,6 +16,9 @@
 // Project Headers
 #include "ECS_Base/Managers/SHComponentManager.h"
 #include "ECS_Base/Managers/SHEntityManager.h"
+#include "ECS_Base/Managers/SHSystemManager.h"
+#include "Editor/SHEditor.hpp"
+#include "Math/SHMathHelpers.h"
 #include "Scene/SHSceneManager.h"
 #include "Math/Transform/SHTransformComponent.h"
 
@@ -174,11 +177,9 @@ namespace SHADE
 
   void SHPhysicsSystem::Init()
   {
-    using namespace rp3d;
-
     // Create a physics world with the default settings
-    PhysicsWorld::WorldSettings settings;
-    settings.gravity                            = Vector3{ 0.0f, -9.81f, 0.0f };
+    rp3d::PhysicsWorld::WorldSettings settings;
+    settings.gravity                            = SHVec3{ 0.0f, -9.81f, 0.0f };
     settings.isSleepingEnabled                  = true;
     settings.defaultVelocitySolverNbIterations  = 8;
     settings.defaultPositionSolverNbIterations  = 3;
@@ -189,6 +190,16 @@ namespace SHADE
 
     // Set up solvers
     world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES);
+
+    // Subscribe to component events
+
+    const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::AddPhysicsComponent) };
+    const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ADD_COMPONENT_RECEIVER);
+    SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR);
+
+    const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::RemovePhysicsComponent) };
+    const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(REMOVE_COMPONENT_RECEIVER);
+    SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR);
   }
 
   void SHPhysicsSystem::Exit()
@@ -196,128 +207,87 @@ namespace SHADE
     factory.destroyPhysicsWorld(world);
   }
 
-  void SHPhysicsSystem::AddRigidBody(EntityID entityID) noexcept
-  {
-    //#ifdef _DEBUG
-    //  SHLOG_INFO("Adding a Rigidbody to the Physics World.")
-    //#endif
-
-    auto* physicsObject = CreatePhysicsObject(entityID);
-
-    physicsObject->CreateRigidBody
-    (
-      EnsureTransform(entityID), 
-      SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID), 
-      SHComponentManager::GetComponent_s<SHColliderComponent>(entityID)
-    );
-  }
-
-  void SHPhysicsSystem::AddCollider(EntityID entityID) noexcept
-  {
-    //#ifdef _DEBUG
-    //  SHLOG_INFO("Adding a Collider to the Physics World.")
-    //#endif
-
-    auto* physicsObject = CreatePhysicsObject(entityID);
-
-    physicsObject->CreateCollisionBody
-    (
-      EnsureTransform(entityID), 
-      SHComponentManager::GetComponent<SHColliderComponent>(entityID)
-    );
-  }
-
-  void SHPhysicsSystem::RemoveRigidBody(EntityID entityID) noexcept
-  {
-    #ifdef _DEBUG
-      SHLOG_INFO("Removing a Rigidbody from the Physics World.")
-    #endif
-
-    auto* physicsObject = GetPhysicsObject(entityID);
-    SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!")
-
-    physicsObject->DestroyRigidBody(SHComponentManager::GetComponent_s<SHColliderComponent>(entityID));
-
-    if (physicsObject->rp3dBody == nullptr)
-      DestroyPhysicsObject(entityID);
-  }
-
-  void SHPhysicsSystem::RemoveCollider(EntityID entityID) noexcept
-  {
-    #ifdef _DEBUG
-      SHLOG_INFO("Removing a Collider from the Physics World.")
-    #endif
-  }
-
-  void SHPhysicsSystem::AddForce(EntityID entityID, const SHVec3& force) const noexcept
-  {
-    
-  }
-
-  void SHPhysicsSystem::AddForceAtLocalPos(EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept
-  {
-    
-  }
-
-  void SHPhysicsSystem::AddForceAtWorldPos(EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept
-  {
-    
-  }
-
-  void SHPhysicsSystem::AddRelativeForce(EntityID entityID, const SHVec3& relativeForce) const noexcept
-  {
-    
-  }
-
-  void SHPhysicsSystem::AddRelativeForceAtLocalPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos) const noexcept
-  {
-    
-  }
-
-  void SHPhysicsSystem::AddRelativeForceAtWorldPos(EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept
-  {
-    
-  }
-
-  void SHPhysicsSystem::AddTorque(EntityID entityID, const SHVec3& torque) const noexcept
-  {
-    
-  }
-
-  void SHPhysicsSystem::AddRelativeTorque(EntityID entityID, const SHVec3& relativeTorque) const noexcept
-  {
-    
-  }
-
   void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHCollider* collider)
   {
     auto* physicsObject = GetPhysicsObject(entityID);
-    physicsObject->AddCollider(collider);
+
+    const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
+    {
+      .entityID       = entityID
+    , .colliderType   = collider->GetType()
+    , .colliderIndex  = physicsObject->AddCollider(collider) 
+    };
+
+    SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
   }
 
   void SHPhysicsSystem::RemoveCollisionShape(EntityID entityID, int index)
   {
-    
+    auto* physicsObject = GetPhysicsObject(entityID);
+    physicsObject->RemoveCollider(index);
+
+    const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA
+    {
+      .entityID       = entityID
+    , .colliderIndex  = index
+    };
+
+    SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
   }
 
   void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept
   {
     auto* system = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
 
+    // Sync transforms
+    for (auto& [entityID, physicsObject] : system->map)
+    {
+      // Ensure a valid physics Object
+      if (physicsObject.rp3dBody == nullptr)
+        continue;
+
+      auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
+
+      // Clear all forces and velocities if editor is not in play
+      if (SHSystemManager::GetSystem<SHEditor>()->editorState == SHEditor::State::STOP)
+      {
+        if (rigidBodyComponent)
+        {
+          auto* rp3dRigidBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject.rp3dBody);
+          rp3dRigidBody->resetForce();
+          rp3dRigidBody->resetTorque();
+          rp3dRigidBody->setLinearVelocity(SHVec3::Zero);
+          rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
+        }
+      }
+
+      const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
+      if (transformComponent && transformComponent->HasChanged())
+      {
+        const auto WORLD_POS = transformComponent->GetWorldPosition();
+        const auto WORLD_ROT = transformComponent->GetWorldOrientation();
+
+        physicsObject.SetPosition(WORLD_POS);
+        physicsObject.SetOrientation(WORLD_ROT);
+
+        if (rigidBodyComponent)
+        {
+          rigidBodyComponent->position    = WORLD_POS;
+          rigidBodyComponent->orientation = WORLD_ROT;
+        }
+
+        auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
+        if (colliderComponent)
+        {
+          colliderComponent->position    = WORLD_POS;
+          colliderComponent->orientation = WORLD_ROT;
+        }
+      }
+    }
+
     // Update bodies and colliders if component is dirty
     system->SyncRigidBodyComponents(SHComponentManager::GetDense<SHRigidBodyComponent>());
     system->SyncColliderComponents(SHComponentManager::GetDense<SHColliderComponent>());
-
-    // Sync transforms
-    for (auto& physicsObject : system->map | std::views::values)
-    {
-      const auto* TF = SHComponentManager::GetComponent<SHTransformComponent>(physicsObject.entityID);
-      if (TF->HasChanged())
-      {
-        physicsObject.SetPosition(TF->GetWorldPosition());
-        physicsObject.SetRotation(TF->GetWorldRotation());
-      }
-    }
   }
 
   void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
@@ -358,7 +328,7 @@ namespace SHADE
   /* Private Function Member Definitions                                               */
   /*-----------------------------------------------------------------------------------*/
 
-  SHPhysicsObject* SHPhysicsSystem::CreatePhysicsObject(EntityID entityID) noexcept
+  SHPhysicsObject* SHPhysicsSystem::EnsurePhysicsObject(EntityID entityID) noexcept
   {
     const auto it = map.find(entityID);
     if (it == map.end())
@@ -450,15 +420,18 @@ namespace SHADE
 
       const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform();
 
+      auto* rigidBodyComponent  = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
+      auto* colliderComponent   = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
+
       // Check if transform should be interpolated
       
-      if (physicsObject.isRigidBody)
+      if (rigidBodyComponent != nullptr)
       {
-        auto* rbComponent = SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID);
-        if (rbComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
+        
+        if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
           continue;
 
-        if (rbComponent->IsInterpolating())
+        if (rigidBodyComponent->IsInterpolating())
         {
           const rp3d::Transform PREV_TF         = physicsObject.prevTransform;
           const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor));
@@ -473,12 +446,12 @@ namespace SHADE
           rp3dRot = CURRENT_TF.getOrientation();
         }
 
-        rbComponent->position     = CURRENT_TF.getPosition();
-        rbComponent->orientation  = CURRENT_TF.getOrientation();
+        rigidBodyComponent->position     = CURRENT_TF.getPosition();
+        rigidBodyComponent->orientation  = CURRENT_TF.getOrientation();
 
-        if (physicsObject.hasColliders)
+        if (colliderComponent != nullptr)
         {
-          auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
+          
           colliderComponent->position     = CURRENT_TF.getPosition();
           colliderComponent->orientation  = CURRENT_TF.getOrientation();
         }
@@ -490,29 +463,148 @@ namespace SHADE
       }
 
       // Convert RP3D Transform to SHADE
-      auto* tfComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
-      tfComponent->SetWorldPosition(rp3dPos);
-      tfComponent->SetWorldRotation(SHQuaternion{ rp3dRot }.ToEuler());
-
+      auto* transformComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
+      transformComponent->SetWorldPosition(rp3dPos);
+      transformComponent->SetWorldOrientation(rp3dRot);
 
       // Cache transforms
       physicsObject.prevTransform = CURRENT_TF;
     }
   }
 
-  SHTransformComponent* SHPhysicsSystem::EnsureTransform(EntityID entityID)
+  SHEventHandle SHPhysicsSystem::AddPhysicsComponent(SHEventPtr addComponentEvent)
   {
-    auto* tf = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
+    const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
 
-    // Possibly redundant
-    if (!tf)
+    static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
+    static const auto COLLIDER_ID   = ComponentFamily::GetID<SHColliderComponent>();
+
+    const auto ADDED_ID = EVENT_DATA->data->addedComponentType;
+    const bool IS_PHYSICS_COMPONENT = ADDED_ID == RIGID_BODY_ID || ADDED_ID == COLLIDER_ID;
+    if (IS_PHYSICS_COMPONENT)
     {
-      SHComponentManager::AddComponent<SHTransformComponent>(entityID);
-      tf = SHComponentManager::GetComponent<SHTransformComponent>(entityID);
+      const EntityID ENTITY_ID = EVENT_DATA->data->eid;
+      auto* physicsObject = EnsurePhysicsObject(ENTITY_ID);
+
+      auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(ENTITY_ID);
+      if (transformComponent == nullptr)
+      {
+        SHLOG_ERROR("Entity {} cannot add a Physics Component without a Transform! Component not created!", ENTITY_ID)
+        return EVENT_DATA->handle;
+      }
+
+      auto* rigidBodyComponent  = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
+      auto* colliderComponent   = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
+
+      if (ADDED_ID == RIGID_BODY_ID)
+      {
+        if (colliderComponent != nullptr)
+        {
+          world->destroyCollisionBody(physicsObject->rp3dBody);
+          physicsObject->rp3dBody = nullptr;
+        }
+
+        rigidBodyComponent->position    = transformComponent->GetWorldPosition();
+        rigidBodyComponent->orientation = transformComponent->GetWorldOrientation();
+
+        physicsObject->rp3dBody = world->createRigidBody
+        (
+          rp3d::Transform{ rigidBodyComponent->position, rigidBodyComponent->orientation }
+        );
+
+        rigidBodyComponent->rp3dBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody);
+
+        // Add collision shapes back into the body
+        if (colliderComponent != nullptr)
+        {
+          for (auto& collider : colliderComponent->colliders | std::views::keys)
+            physicsObject->AddCollider(&collider);
+        }
+      }
+
+      if (ADDED_ID == COLLIDER_ID)
+      {
+        SHASSERT(colliderComponent != nullptr, "Collider Component was not added to Entity " + std::to_string(ENTITY_ID) + "!");
+
+        colliderComponent->position    = transformComponent->GetWorldPosition();
+        colliderComponent->orientation = transformComponent->GetWorldOrientation();
+
+        if (physicsObject->rp3dBody == nullptr)
+        {
+          physicsObject->rp3dBody = world->createCollisionBody
+          (
+            rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
+          );
+        }
+          
+        // Add Collision Shapes
+        for (auto& collider : colliderComponent->colliders | std::views::keys)
+          physicsObject->AddCollider(&collider);
+      }
     }
 
-    return tf;
+    return EVENT_DATA->handle;
   }
 
+  SHEventHandle SHPhysicsSystem::RemovePhysicsComponent(SHEventPtr removeComponentEvent)
+  {
+    const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(removeComponentEvent.get());
+
+    static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
+    static const auto COLLIDER_ID   = ComponentFamily::GetID<SHColliderComponent>();
+
+    const auto REMOVED_ID = EVENT_DATA->data->removedComponentType;
+    const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID;
+    if (IS_PHYSICS_COMPONENT)
+    {
+      const EntityID ENTITY_ID = EVENT_DATA->data->eid;
+      auto* physicsObject = GetPhysicsObject(ENTITY_ID);
+
+      SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!")
+
+      if (REMOVED_ID == RIGID_BODY_ID)
+      {
+        world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody));
+        physicsObject->rp3dBody       = nullptr;
+
+        auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
+        if (colliderComponent != nullptr)
+        {
+          // Preserve colliders as a collision body
+          physicsObject->rp3dBody = world->createCollisionBody
+          (
+            rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
+          );
+
+          for (auto& collider : colliderComponent->colliders | std::views::keys)
+            physicsObject->AddCollider(&collider);
+        }
+
+        // Wake up all physics objects
+        for (auto& [entityID, object] : map)
+        {
+          if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
+            reinterpret_cast<rp3d::RigidBody*>(object.rp3dBody)->setIsSleeping(false);
+        }
+      }
+
+      if (REMOVED_ID == COLLIDER_ID)
+      {
+        // Remove all colliders
+        const int NUM_COLLIDERS = static_cast<int>(physicsObject->rp3dBody->getNbColliders());
+
+        for (int i = NUM_COLLIDERS - 1; i >= 0; --i)
+        {
+          auto* collider = physicsObject->rp3dBody->getCollider(i);
+          physicsObject->rp3dBody->removeCollider(collider);
+        }
+      }
+
+      if (physicsObject->rp3dBody == nullptr)
+          DestroyPhysicsObject(ENTITY_ID);
+    }
+
+    return EVENT_DATA->handle;
+  }
 
 } // namespace SHADE
\ No newline at end of file
diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/SHPhysicsSystem.h
index bc6a1ba2..a3c3bea1 100644
--- a/SHADE_Engine/src/Physics/SHPhysicsSystem.h
+++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.h
@@ -16,14 +16,14 @@
 #include <reactphysics3d/reactphysics3d.h>
 
 // Project Headers
-#include "SHPhysicsObject.h"
 #include "Components/SHRigidBodyComponent.h"
 #include "Components/SHColliderComponent.h"
-#include "Math/Transform/SHTransformComponent.h"
-
-#include "Scene/SHSceneGraph.h"
 #include "ECS_Base/System/SHSystemRoutine.h"
 #include "ECS_Base/System/SHFixedSystemRoutine.h"
+#include "Math/Transform/SHTransformComponent.h"
+#include "Scene/SHSceneGraph.h"
+#include "SHPhysicsObject.h"
+
 
 
 namespace SHADE
@@ -32,7 +32,7 @@ namespace SHADE
   /* Type Definitions                                                                  */
   /*-----------------------------------------------------------------------------------*/
 
-  class SH_API SHPhysicsSystem : public SHSystem
+  class SH_API SHPhysicsSystem final : public SHSystem
   {
   public:
     /*---------------------------------------------------------------------------------*/
@@ -85,21 +85,10 @@ namespace SHADE
     void  Init                         () override;
     void  Exit                         () override;
 
-    void  AddRigidBody                (EntityID entityID) noexcept;
-    void  AddCollider                 (EntityID entityID) noexcept;
-    void  RemoveRigidBody             (EntityID entityID) noexcept;
-    void  RemoveCollider              (EntityID entityID) noexcept;
-
-    void  AddForce                    (EntityID entityID, const SHVec3& force) const noexcept;
-    void  AddForceAtLocalPos          (EntityID entityID, const SHVec3& force, const SHVec3& localPos) const noexcept;
-    void  AddForceAtWorldPos          (EntityID entityID, const SHVec3& force, const SHVec3& worldPos) const noexcept;
-
-    void  AddRelativeForce            (EntityID entityID, const SHVec3& relativeForce) const noexcept;
-    void  AddRelativeForceAtLocalPos  (EntityID entityID, const SHVec3& relativeForce, const SHVec3& localPos)  const noexcept;
-    void  AddRelativeForceAtWorldPos  (EntityID entityID, const SHVec3& relativeForce, const SHVec3& worldPos)  const noexcept;
-
-    void  AddTorque                   (EntityID entityID, const SHVec3& torque) const noexcept;
-    void  AddRelativeTorque           (EntityID entityID, const SHVec3& relativeTorque) const noexcept;
+    //void  AddRigidBody                (EntityID entityID) noexcept;
+    //void  AddCollider                 (EntityID entityID) noexcept;
+    //void  RemoveRigidBody             (EntityID entityID) noexcept;
+    //void  RemoveCollider              (EntityID entityID) noexcept;
 
     void  AddCollisionShape           (EntityID entityID, SHCollider* collider);
     void  RemoveCollisionShape        (EntityID entityID, int index);
@@ -108,10 +97,7 @@ namespace SHADE
     /* System Routines                                                                 */
     /*---------------------------------------------------------------------------------*/
 
-    /**
-     * @brief Synchronises RP3D with SHADE
-    */
-    class SH_API PhysicsPreUpdate : public SHSystemRoutine
+    class SH_API PhysicsPreUpdate final : public SHSystemRoutine
     {
     public:
       /*-------------------------------------------------------------------------------*/
@@ -127,7 +113,7 @@ namespace SHADE
       void Execute(double dt) noexcept override;
     };
 
-    class SH_API PhysicsFixedUpdate : public SHFixedSystemRoutine
+    class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine
     {
     public:
       /*-------------------------------------------------------------------------------*/
@@ -143,7 +129,7 @@ namespace SHADE
       void Execute      (double dt) noexcept override;
     };
 
-    class SH_API PhysicsPostUpdate : public SHSystemRoutine
+    class SH_API PhysicsPostUpdate final : public SHSystemRoutine
     {
     public:
       /*-------------------------------------------------------------------------------*/
@@ -170,15 +156,14 @@ namespace SHADE
     /* Data Members                                                                    */
     /*---------------------------------------------------------------------------------*/
 
-    // TODO(Diren): Store interpFactor
-
     bool                      worldUpdated;
 
     double                    interpolationFactor;
     double                    fixedDT;
-    rp3d::PhysicsWorld*       world;
 
+    rp3d::PhysicsWorld*       world;
     rp3d::PhysicsCommon       factory;
+
     EntityObjectMap           map;
 
 
@@ -186,7 +171,7 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
     /* Function Members                                                                */
     /*---------------------------------------------------------------------------------*/
-    SHPhysicsObject*  CreatePhysicsObject       (EntityID entityID)                                     noexcept;
+    SHPhysicsObject*  EnsurePhysicsObject       (EntityID entityID)                                     noexcept;
     SHPhysicsObject*  GetPhysicsObject          (EntityID entityID)                                     noexcept;
     void              DestroyPhysicsObject      (EntityID entityID)                                     noexcept;
 
@@ -194,11 +179,26 @@ namespace SHADE
     void              SyncRigidBodyComponents   (std::vector<SHRigidBodyComponent>& denseArray)         noexcept;
     void              SyncColliderComponents    (std::vector<SHColliderComponent>& denseArray)          noexcept;
     void              SyncTransforms            ()                                                      noexcept;
-    // TODO(Diren): Trigger handling
 
-    // TODO(Diren): Remove when responsibility shifted to editor
-    SHTransformComponent* EnsureTransform       (EntityID entityID);
+    SHEventHandle     AddPhysicsComponent       (SHEventPtr addComponentEvent);
+    SHEventHandle     RemovePhysicsComponent    (SHEventPtr removeComponentEvent);
   };
 
+  /*-----------------------------------------------------------------------------------*/
+  /* Event Data Definitions                                                            */
+  /*-----------------------------------------------------------------------------------*/
+
+  struct SHPhysicsColliderAddedEvent
+  {
+    EntityID          entityID;
+    SHCollider::Type  colliderType;
+    int               colliderIndex;
+  };
+
+  struct SHPhysicsColliderRemovedEvent
+  {
+    EntityID          entityID;
+    int               colliderIndex;
+  };
 
 } // namespace SHADE
\ No newline at end of file
diff --git a/SHADE_Engine/src/Resource/SHResourceManager.hpp b/SHADE_Engine/src/Resource/SHResourceManager.hpp
index 54ced715..cff4e84b 100644
--- a/SHADE_Engine/src/Resource/SHResourceManager.hpp
+++ b/SHADE_Engine/src/Resource/SHResourceManager.hpp
@@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited.
 #include "SHResourceManager.h"
 // Project Includes
 #include "Assets/SHAssetManager.h"
+#include "Assets/Asset Types/SHAssetIncludes.h"
 #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
 #include "ECS_Base/Managers/SHSystemManager.h"
 #include "Tools/SHLog.h"
@@ -48,7 +49,7 @@ namespace SHADE
         throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
 
       // Load
-      const SHMeshAsset* assetData = SHAssetManager::GetMesh(assetId);
+      const SHMeshAsset* assetData = SHAssetManager::GetData<SHMeshAsset>(assetId);
       if (assetData == nullptr)
       {
         SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID.");
@@ -80,7 +81,7 @@ namespace SHADE
         throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
 
       // Load
-      const SHTextureAsset* assetData = SHAssetManager::GetTexture(assetId);
+      const SHTextureAsset* assetData = SHAssetManager::GetData<SHTextureAsset>(assetId);
       if (assetData == nullptr)
       {
         SHLog::Warning("[SHResourceManager] Attempted to load an asset with an invalid Asset ID.");
@@ -133,7 +134,7 @@ namespace SHADE
   /* Query Functions                                                                   */
   /*-----------------------------------------------------------------------------------*/
   template<typename T>
-  static std::optional<AssetID> SHResourceManager::GetAssetID(Handle<T> handle)
+  std::optional<AssetID> SHResourceManager::GetAssetID(Handle<T> handle)
   {
     const Handle GENERIC_HANDLE = Handle(handle);
     auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<T>();
diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp
index bbbdb7e4..950fd6a0 100644
--- a/SHADE_Engine/src/Scene/SHSceneGraph.cpp
+++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp
@@ -15,6 +15,7 @@
 
 // Project Headers
 #include "ECS_Base/Managers/SHEntityManager.h"
+#include "Events/SHEventManager.hpp"
 #include "Tools/SHLogger.h"
 #include "Tools/SHException.h"
 
@@ -317,6 +318,11 @@ namespace SHADE
     if (parentNode == nullptr)
     {
       SHLOG_WARNING("Removing Entity {}'s parent", entityID)
+
+      if (parent)
+        parent->RemoveChild(this);
+
+      return;
     }
 
     // Handle self assignment
@@ -359,10 +365,19 @@ namespace SHADE
     }
     ////////////////////////////////////////
 
+    const SHSceneGraphChangeParentEvent EVENT_DATA
+    {
+      .node       = NODE_ITER->second
+    , .oldParent  = NODE_ITER->second->GetParent()
+    , .newParent  = parent ? parent : root
+    };
+
     if (parent == nullptr)
       parent = root;
 
     NODE_ITER->second->SetParent(parent);
+
+    SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
   }
 
   void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept
@@ -396,8 +411,17 @@ namespace SHADE
     }
     ////////////////////////////////////////
 
+    const SHSceneGraphChangeParentEvent EVENT_DATA
+    {
+      .node       = NODE_ITER->second
+    , .oldParent  = NODE_ITER->second->GetParent()
+    , .newParent  = PARENT_ITER->second
+    };
+
     SHSceneNode* currentNode = NODE_ITER->second;
     currentNode->SetParent(PARENT_ITER->second);
+
+    SHEventManager::BroadcastEvent<SHSceneGraphChangeParentEvent>(EVENT_DATA, SH_SCENEGRAPH_CHANGE_PARENT_EVENT);
   }
 
   /*-----------------------------------------------------------------------------------*/
@@ -558,7 +582,7 @@ namespace SHADE
       ReleaseNode(node);
   }
 
-  void SHSceneGraph::Traverse (const UnaryPredicate& predicate) const
+  void SHSceneGraph::Traverse (const UnaryFunction& predicate) const
   {
     TraverseAndInvokePredicate(root, predicate);
   }
@@ -597,7 +621,7 @@ namespace SHADE
     delete node;
   }
 
-  void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryPredicate& predicate)
+  void SHSceneGraph::TraverseAndInvokePredicate(const SHSceneNode* node, const UnaryFunction& predicate)
   {
     for (auto* child : node->children)
     { 
diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h
index 3f3ebf92..b52fd1ff 100644
--- a/SHADE_Engine/src/Scene/SHSceneGraph.h
+++ b/SHADE_Engine/src/Scene/SHSceneGraph.h
@@ -97,9 +97,8 @@ namespace SHADE
     /* Type Definitions                                                                */
     /*---------------------------------------------------------------------------------*/
 
-    using EntityNodeMap       = std::unordered_map<EntityID, SHSceneNode*>;
-
-    using UnaryPredicate      = std::function<void(SHSceneNode*)>;
+    using EntityNodeMap = std::unordered_map<EntityID, SHSceneNode*>;
+    using UnaryFunction = std::function<void(SHSceneNode*)>;
     
 
     /*---------------------------------------------------------------------------------*/
@@ -143,8 +142,7 @@ namespace SHADE
     bool          RemoveNode  (SHSceneNode* nodeToRemove)                         noexcept;
     void          Reset       ()                                                  noexcept;
 
-    void          Traverse    (const UnaryPredicate& predicate)                   const;
-    
+    void          Traverse    (const UnaryFunction& predicate)                    const;
 
   private:
     /*---------------------------------------------------------------------------------*/
@@ -160,8 +158,18 @@ namespace SHADE
 
     SHSceneNode*  AllocateNode                (EntityID entityID);
     void          ReleaseNode                 (SHSceneNode* node) noexcept;
-    static void   TraverseAndInvokePredicate  (const SHSceneNode* node, const UnaryPredicate& predicate);
+    static void   TraverseAndInvokeFunction  (const SHSceneNode* node, const UnaryFunction& function);
   };
 
+  /*-----------------------------------------------------------------------------------*/
+  /* Event Data Definitions                                                            */
+  /*-----------------------------------------------------------------------------------*/
+
+  struct SHSceneGraphChangeParentEvent
+  {
+    SHSceneNode* node;
+    SHSceneNode* oldParent;
+    SHSceneNode* newParent;
+  };
 
 } // namespace SHADE
\ No newline at end of file
diff --git a/SHADE_Engine/src/Tools/SHUtilities.h b/SHADE_Engine/src/Tools/SHUtilities.h
index 543c771c..b3d840e7 100644
--- a/SHADE_Engine/src/Tools/SHUtilities.h
+++ b/SHADE_Engine/src/Tools/SHUtilities.h
@@ -42,6 +42,15 @@ namespace SHADE
     template <IsEnum InputType, IsIntegral OutputType = int>
     static constexpr OutputType ConvertEnum(InputType enumClassMember) noexcept;
 
+    /**
+     * @brief     Converts an enum class member from it's type to the underlying type.
+     * @tparam    Enum    Restricted to an enum class
+     * @param[in] value   A member of the specified enum class.
+     * @returns   The value of the enum class member in the output type.
+    */
+    template<typename Enum>
+    static constexpr typename std::underlying_type_t<Enum> ToUnderlying (Enum value) noexcept;
+
   };
 
 } // namespace SHADE
diff --git a/SHADE_Engine/src/Tools/SHUtilities.hpp b/SHADE_Engine/src/Tools/SHUtilities.hpp
index 0e21a9d0..e0404ea1 100644
--- a/SHADE_Engine/src/Tools/SHUtilities.hpp
+++ b/SHADE_Engine/src/Tools/SHUtilities.hpp
@@ -25,4 +25,10 @@ namespace SHADE
       return static_cast<OutputType>(enumClassMember);
   }
 
+  template<typename Enum>
+  constexpr typename std::underlying_type_t<Enum> SHUtilities::ToUnderlying(Enum value) noexcept
+  {
+    return static_cast<typename std::underlying_type_t<Enum>>(value);
+  }
+
 } // namespace SHADE
\ No newline at end of file
diff --git a/SHADE_Managed/src/Components/Transform.cxx b/SHADE_Managed/src/Components/Transform.cxx
index 0f0716dc..98f0da4f 100644
--- a/SHADE_Managed/src/Components/Transform.cxx
+++ b/SHADE_Managed/src/Components/Transform.cxx
@@ -29,13 +29,21 @@ namespace SHADE
     {
         GetNativeComponent()->SetLocalPosition(Convert::ToNative(val));
     }
-    Vector3 Transform::LocalRotation::get()
+    Quaternion Transform::LocalRotation::get()
     {
-        return Convert::ToCLI(GetNativeComponent()->GetLocalRotation());
+        return Convert::ToCLI(GetNativeComponent()->GetLocalOrientation());
     }
-    void Transform::LocalRotation::set(Vector3 val)
+    void Transform::LocalRotation::set(Quaternion val)
     {
-        GetNativeComponent()->SetLocalRotation(Convert::ToNative(val));
+        GetNativeComponent()->SetLocalOrientation(Convert::ToNative(val));
+    }
+    Vector3 Transform::LocalEulerAngles::get()
+    {
+      return Convert::ToCLI(GetNativeComponent()->GetLocalRotation());
+    }
+    void Transform::LocalEulerAngles::set(Vector3 val)
+    {
+      GetNativeComponent()->SetLocalRotation(Convert::ToNative(val));
     }
     Vector3 Transform::LocalScale::get()
     {
@@ -54,13 +62,21 @@ namespace SHADE
     {
         GetNativeComponent()->SetWorldPosition(Convert::ToNative(val));
     }
-    Vector3 Transform::GlobalRotation::get()
+    Quaternion Transform::GlobalRotation::get()
     {
-        return Convert::ToCLI(GetNativeComponent()->GetWorldRotation());
+        return Convert::ToCLI(GetNativeComponent()->GetLocalOrientation());
     }
-    void Transform::GlobalRotation::set(Vector3 val)
+    void Transform::GlobalRotation::set(Quaternion val)
     {
-        GetNativeComponent()->SetWorldRotation(Convert::ToNative(val));
+        GetNativeComponent()->SetWorldOrientation(Convert::ToNative(val));
+    }
+    Vector3 Transform::GlobalEulerAngles::get()
+    {
+      return Convert::ToCLI(GetNativeComponent()->GetWorldRotation());
+    }
+    void Transform::GlobalEulerAngles::set(Vector3 val)
+    {
+      GetNativeComponent()->SetWorldRotation(Convert::ToNative(val));
     }
     Vector3 Transform::GlobalScale::get()
     {
diff --git a/SHADE_Managed/src/Components/Transform.hxx b/SHADE_Managed/src/Components/Transform.hxx
index 9efd2927..bbe9fd19 100644
--- a/SHADE_Managed/src/Components/Transform.hxx
+++ b/SHADE_Managed/src/Components/Transform.hxx
@@ -17,14 +17,14 @@ of DigiPen Institute of Technology is prohibited.
 // Project Includes
 #include "Components/Component.hxx"
 #include "Math/Vector3.hxx"
-#include "Utility/Convert.hxx"
+#include "Math/Quaternion.hxx"
 // External Dependencies
 #include "Math/Transform/SHTransformComponent.h"
 
 namespace SHADE
 {
     /// <summary>
-    /// CLR version of the the SHADE Engine's TransformComponent.
+    /// CLR version of the SHADE Engine's TransformComponent.
     /// </summary>
     public ref class Transform : public Component<SHTransformComponent>
     {
@@ -52,9 +52,17 @@ namespace SHADE
             void set(Vector3 val);
         }
         /// <summary>
-        /// Local Z-axis rotation angle stored by this Transform in Radians.
+        /// Local rotation quaternion stored by this Transform.
         /// </summary>
-        property Vector3 LocalRotation
+        property Quaternion LocalRotation
+        {
+            Quaternion get();
+            void set(Quaternion val);
+        }
+        /// <summary>
+        /// Local euler angle rotations stored by this Transform.
+        /// </summary>
+        property Vector3 LocalEulerAngles
         {
             Vector3 get();
             void set(Vector3 val);
@@ -76,16 +84,23 @@ namespace SHADE
             void set(Vector3 val);
         }
         /// <summary>
-        /// Global Z-axis rotation angle stored by this Transform in Radians.
+        /// Global rotation quaternion stored by this Transform.
         /// </summary>
-        property Vector3 GlobalRotation
+        property Quaternion GlobalRotation
+        {
+            Quaternion get();
+            void set(Quaternion val);
+        }
+        /// <summary>
+        /// Global euler angle rotations stored by this Transform.
+        /// </summary>
+        property Vector3 GlobalEulerAngles
         {
             Vector3 get();
             void set(Vector3 val);
         }
         /// <summary>
         /// Global scale stored by this Transform.
-        /// Note that this operation is expensive.
         /// </summary>
         property Vector3 GlobalScale
         {
diff --git a/SHADE_Managed/src/Math/Math.cxx b/SHADE_Managed/src/Math/Math.cxx
index 5ec850a1..fa72e2b6 100644
--- a/SHADE_Managed/src/Math/Math.cxx
+++ b/SHADE_Managed/src/Math/Math.cxx
@@ -21,7 +21,7 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
     /* Utility Functions                                                               */
     /*---------------------------------------------------------------------------------*/
-    double Math::Wrap(double value, double min, double max)
+    float Math::Wrap(float value, float min, float max)
     {
         while (value < min)
         {
@@ -33,24 +33,24 @@ namespace SHADE
         }
         return value;
     }
-    double Math::DegreesToRadians(double degrees)
+    float Math::DegreesToRadians(float degrees)
     {
         return degrees * Deg2Rad;
     }
-    double Math::RadiansToDegrees(double radians)
+    float Math::RadiansToDegrees(float radians)
     {
         return radians * Rad2Deg;
     }
-    double Math::Lerp(double a, double b, double t)
+    float Math::Lerp(float a, float b, float t)
     {
-        return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0, 1.0));
+        return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0f, 1.0f));
     }
-    double Math::LerpUnclamped(double a, double b, double t)
+    float Math::LerpUnclamped(float a, float b, float t)
     {
         return a + t * (b - a);
     }
 
-    double Math::InverseLerp(double a, double b, double value)
+    float Math::InverseLerp(float a, float b, float value)
     {
         return (value - a) / (b - a);
     }
diff --git a/SHADE_Managed/src/Math/Math.hxx b/SHADE_Managed/src/Math/Math.hxx
index 3ddc5149..1578d97c 100644
--- a/SHADE_Managed/src/Math/Math.hxx
+++ b/SHADE_Managed/src/Math/Math.hxx
@@ -27,11 +27,11 @@ namespace SHADE
         /// <summary>
         /// Degrees-to-radians conversion constant
         /// </summary>
-        static constexpr double Deg2Rad = System::Math::PI / 180.0;
+        static constexpr float Deg2Rad = System::Math::PI / 180.0f;
         /// <summary>
         /// Radians-to-degrees conversion constant
         /// </summary>
-        static constexpr double Rad2Deg = 180.0 / System::Math::PI;
+        static constexpr float Rad2Deg = 180.0f / System::Math::PI;
         /// <summary>
         /// Small value used for single precision floating point comparisons.
         /// </summary>
@@ -47,28 +47,28 @@ namespace SHADE
         /// <param name="min">Minimum value to wrap at.</param>
         /// <param name="max">Maximum value to wrap at.</param>
         /// <returns>Wrapped value.</returns>
-        static double Wrap(double value, double min, double max);
+        static float Wrap(float value, float min, float max);
         /// <summary>
         /// Converts an angle from degree representation to radian representation.
         /// </summary>
         /// <param name="degrees">Degree-based angle to convert.</param>
         /// <returns>The specified angle in radians.</returns>
-        static double DegreesToRadians(double degrees);
+        static float DegreesToRadians(float degrees);
         /// <summary>
         /// Converts an angle from radian representation to degree representation.
         /// </summary>
         /// <param name="radians">Radian-based angle to convert.</param>
         /// <returns>The specified angle in degrees.</returns>
-        static double RadiansToDegrees(double radians);
+        static float RadiansToDegrees(float radians);
         /// <summary>
         /// Linearly interpolates between a and b by t. 
         /// The parameter t is clamped to the range [0, 1].
         /// </summary>
         /// <param name="a">The start value.</param>
         /// <param name="b">The end value.</param>
-        /// <param name="t">The interpolation value between the two double.</param>
-        /// <returns>The interpolated double result between the two double values.</returns>
-        static double Lerp(double a, double b, double t);
+        /// <param name="t">The interpolation value between the two float.</param>
+        /// <returns>The interpolated float result between the two float values.</returns>
+        static float Lerp(float a, float b, float t);
         /// <summary>
         /// Linearly interpolates between a and b by t. 
         /// The parameter t is not clamped and a value based on a and b is supported. 
@@ -77,9 +77,9 @@ namespace SHADE
         /// </summary>
         /// <param name="a">The start value.</param>
         /// <param name="b">The end value.</param>
-        /// <param name="t">The interpolation value between the two double.</param>
-        /// <returns>The interpolated double result between the two double values.</returns>
-        static double LerpUnclamped(double a, double b, double t);
+        /// <param name="t">The interpolation value between the two float.</param>
+        /// <returns>The interpolated float result between the two float values.</returns>
+        static float LerpUnclamped(float a, float b, float t);
         /// <summary>
         /// Calculates the linear parameter t that produces the interpolant value within the range [a, b].
         /// </summary>
@@ -87,6 +87,6 @@ namespace SHADE
         /// <param name="b">End value.</param>
         /// <param name="value">Value between start and end.</param>
         /// <returns>Percentage of value between start and end.</returns>
-        static double InverseLerp(double a, double b, double value);
+        static float InverseLerp(float a, float b, float value);
     };
 }
diff --git a/SHADE_Managed/src/Math/Quaternion.cxx b/SHADE_Managed/src/Math/Quaternion.cxx
new file mode 100644
index 00000000..863241ac
--- /dev/null
+++ b/SHADE_Managed/src/Math/Quaternion.cxx
@@ -0,0 +1,170 @@
+/************************************************************************************//*!
+\file           Quaternion.cxx
+\author         Diren D Bharwani, diren.dbharwani, 390002520
+\par            email: diren.dbharwani\@digipen.edu
+\date           Oct 23, 2022
+\brief          Contains the definitions of functions in the Quaternion struct.
+ 
+                Note: This file is written in C++17/CLI.
+
+Copyright (C) 2021 DigiPen Institute of Technology.
+Reproduction or disclosure of this file or its contents without the prior written consent 
+of DigiPen Institute of Technology is prohibited.
+*//*************************************************************************************/
+
+// Precompiled Headers
+#include "SHpch.h"
+// Primary Header
+#include "Quaternion.hxx"
+// External Dependencies
+#include "Math/SHQuaternion.h"
+#include "Math/Vector/SHVec4.h"
+// Project Headers
+#include "Utility/Convert.hxx"
+#include "Math.hxx"
+
+namespace SHADE
+{
+  /*---------------------------------------------------------------------------------*/
+  /* Constructors                                                                    */
+  /*---------------------------------------------------------------------------------*/
+
+  Quaternion::Quaternion(float _x, float _y, float _z, float _w)
+  : x { _x }
+  , y { _y }
+  , z { _z }
+  , w { _w }
+  {}
+
+  /*---------------------------------------------------------------------------------*/
+  /* Usage Functions                                                                 */
+  /*---------------------------------------------------------------------------------*/
+
+  void Quaternion::SetFromToRotation(Vector3 fromDirection, Vector3 toDirection)
+  {
+    const SHQuaternion R = SHQuaternion::FromToRotation(Convert::ToNative(fromDirection), Convert::ToNative(toDirection));
+    *this = Convert::ToCLI(R);
+  }
+
+  void Quaternion::SetLookRotation(Vector3 view, Vector3 up)
+  {
+    const SHQuaternion R = SHQuaternion::LookRotation(Convert::ToNative(view), Convert::ToNative(up));
+    *this = Convert::ToCLI(R);
+  }
+
+  void Quaternion::ToAngleAxis(float^% angle, Vector3^% axis)
+  {
+    const SHVec4 NATIVE_AXIS_ANGLE = Convert::ToNative(*this).GetAxisAngle();
+    axis = Convert::ToCLI(NATIVE_AXIS_ANGLE.ToVec3());
+    angle = NATIVE_AXIS_ANGLE.w;
+  }
+
+  System::String^ Quaternion::ToString()
+  {
+    return ValueType::ToString();
+  }
+
+  /*---------------------------------------------------------------------------------*/
+  /* IEquatable                                                                      */
+  /*---------------------------------------------------------------------------------*/
+
+  bool Quaternion::Equals(Quaternion other)
+  {
+    const float DOT = Dot(*this, other);
+    return fabs(1.0f - DOT) <= Math::Epsilon;
+  }
+
+  /*---------------------------------------------------------------------------------*/
+  /* Object Overrides                                                                */
+  /*---------------------------------------------------------------------------------*/
+
+  bool Quaternion::Equals(Object^ o)
+  {
+    return ValueType::Equals(o);
+  }
+
+  int Quaternion::GetHashCode()
+  {
+    return ValueType::GetHashCode();
+  }
+
+  /*---------------------------------------------------------------------------------*/
+    /* Static Functions                                                                */
+    /*---------------------------------------------------------------------------------*/
+
+  float Quaternion::Angle(Quaternion a, Quaternion b)
+  {
+    return SHQuaternion::Angle(Convert::ToNative(a), Convert::ToNative(b));
+  }
+
+  Quaternion Quaternion::AngleAxis(float angle, Vector3 axis)
+  {
+    return Convert::ToCLI(SHQuaternion::FromAxisAngle(Convert::ToNative(axis), angle));
+  }
+
+  float Quaternion::Dot(Quaternion a, Quaternion b)
+  {
+    return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w);
+  }
+
+  Quaternion Quaternion::Euler(float _x, float _y, float _z)
+  {
+    return Convert::ToCLI(SHQuaternion::FromPitchYawRoll(_x, _y, _z));
+  }
+
+  Quaternion Quaternion::FromToRotation(Vector3 fromDirection, Vector3 toDirection)
+  {
+    return Convert::ToCLI(SHQuaternion::FromToRotation(Convert::ToNative(fromDirection), Convert::ToNative(toDirection)));
+  }
+
+  Quaternion Quaternion::Inverse(Quaternion rotation)
+  {
+    return Convert::ToCLI(SHQuaternion::Inverse(Convert::ToNative(rotation)));
+  }
+
+  Quaternion Quaternion::Lerp(Quaternion a, Quaternion b, float t)
+  {
+    return Convert::ToCLI(SHQuaternion::ClampedLerp(Convert::ToNative(a), Convert::ToNative(b), t));
+  }
+
+  Quaternion Quaternion::LerpUnclamped(Quaternion a, Quaternion b, float t)
+  {
+    return Convert::ToCLI(SHQuaternion::Lerp(Convert::ToNative(a), Convert::ToNative(b), t));
+  }
+
+  Quaternion Quaternion::LookRotation(Vector3 forward, Vector3 upwards)
+  {
+    return Convert::ToCLI(SHQuaternion::LookRotation(Convert::ToNative(forward), Convert::ToNative(upwards)));
+  }
+
+  Quaternion Quaternion::Normalize(Quaternion q)
+  {
+    return Convert::ToCLI(SHQuaternion::Normalise(Convert::ToNative(q)));
+  }
+
+  Quaternion Quaternion::RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta)
+  {
+    return Convert::ToCLI(SHQuaternion::RotateTowards(Convert::ToNative(from), Convert::ToNative(to), Math::DegreesToRadians(maxDegreesDelta)));
+  }
+
+  Quaternion Quaternion::Slerp(Quaternion a, Quaternion b, float t)
+  {
+    return Convert::ToCLI(SHQuaternion::ClampedSlerp(Convert::ToNative(a), Convert::ToNative(b), t));
+  }
+
+  Quaternion Quaternion::SlerpUnclamped(Quaternion a, Quaternion b, float t)
+  {
+    return Convert::ToCLI(SHQuaternion::Slerp(Convert::ToNative(a), Convert::ToNative(b), t));
+  }
+
+
+  Quaternion Quaternion::operator*(Quaternion lhs, Quaternion rhs)
+  {
+    return Convert::ToCLI(Convert::ToNative(lhs) * Convert::ToNative(rhs));
+  }
+
+  bool Quaternion::operator==(Quaternion lhs, Quaternion rhs)
+  {
+    return lhs.Equals(rhs);
+  }
+}
\ No newline at end of file
diff --git a/SHADE_Managed/src/Math/Quaternion.hxx b/SHADE_Managed/src/Math/Quaternion.hxx
new file mode 100644
index 00000000..783038c9
--- /dev/null
+++ b/SHADE_Managed/src/Math/Quaternion.hxx
@@ -0,0 +1,237 @@
+/************************************************************************************//*!
+\file           Quaternion.hxx
+\author         Diren D Bharwani, diren.dbharwani, 390002520
+\par            email: diren.dbharwani\@digipen.edu
+\date           Oct 23, 2022
+\brief          Contains the definitions of Quaternion struct.
+ 
+                Note: This file is written in C++17/CLI.
+
+Copyright (C) 2021 DigiPen Institute of Technology.
+Reproduction or disclosure of this file or its contents without the prior written consent 
+of DigiPen Institute of Technology is prohibited.
+*//*************************************************************************************/
+
+#pragma once
+
+// Standard Libraries
+#include <limits>
+// Project Includes
+#include "Vector3.hxx"
+
+namespace SHADE
+{
+  ///<summary>
+  /// CLR version of SHADE's Quaternion class that represents an orientation.
+  /// Designed to closely match Unity's Quaternion struct.
+  /// </summary>
+  [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
+  public value struct Quaternion : public System::IEquatable<Quaternion>
+  {
+  public:
+    /*-----------------------------------------------------------------------------*/
+    /* Constants                                                                   */
+    /*-----------------------------------------------------------------------------*/
+#pragma region Constants
+
+    ///<summary>
+    /// Shorthand for writing Quaternion(0, 0, 0, 1).
+    ///</summary>
+    static initonly Quaternion Identity = Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
+
+#pragma endregion
+
+    /*-----------------------------------------------------------------------------*/
+    /* Public Members                                                              */
+    /*-----------------------------------------------------------------------------*/
+
+    ///<summary>
+    /// X-component of the Quaternion.
+    /// Don't modify this directly unless you know quaternions inside out.
+    ///</summary>
+    float x;
+    ///<summary>
+    /// Y-component of the Quaternion.
+    /// Don't modify this directly unless you know quaternions inside out.
+    ///</summary>
+    float y;
+    ///<summary>
+    /// Z-component of the Quaternion.
+    /// Don't modify this directly unless you know quaternions inside out.
+    ///</summary>
+    float z;
+    ///<summary>
+    /// W-component of the Quaternion. Do not directly modify quaternions.
+    ///</summary>
+    float w;
+
+    /*-----------------------------------------------------------------------------*/
+    /* Constructors                                                                */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Constructor to construct a Quaternion with the specified components.
+    /// </summary>
+    /// <param name="_x">X-coordinate to set.</param>
+    /// <param name="_y">Y-coordinate to set.</param>
+    /// <param name="_z">Z-coordinate to set.</param>
+    /// <param name="_z">W-coordinate to set.</param>
+    Quaternion(float _x, float _y, float _z, float _w);
+
+    /*-----------------------------------------------------------------------------*/
+    /* Usage Functions                                                             */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Creates a rotation which rotates from fromDirection to toDirection. <br/>
+    /// Use this to create a rotation which starts at the first Vector (fromDirection) and rotates to the second Vector (toDirection).
+    /// These Vectors must be set up in a script.
+    /// </summary>
+    void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection);
+
+    /// <summary>
+    /// Creates a rotation with the specified forward and upwards directions. <br/>
+    /// The result is applied to this quaternion.
+    /// If used to orient a Transform, the Z axis will be aligned with forward and the Y axis with upwards, assuming these vectors are orthogonal.
+    /// Logs an error if the forward direction is zero.
+    /// </summary>
+    /// <param name="view">The direction to look in.</param>
+    /// <param name="up">The vector that defines in which direction up is.</param>
+    void SetLookRotation(Vector3 view, Vector3 up);
+
+    /// <summary>
+    /// Converts a rotation to angle-axis representation (angles in degrees).
+    /// </summary>
+    void ToAngleAxis(float^% angle, Vector3^% axis);
+    
+    System::String^ ToString() override;
+
+    /*-----------------------------------------------------------------------------*/
+    /* IEquatable                                                                  */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Compares equality with an object of the same type.
+    /// </summary>
+    /// <param name="other">The object to compare with.</param>
+    /// <returns>True if both objects are the same.</returns>
+    virtual bool Equals(Quaternion other);
+
+    /*-----------------------------------------------------------------------------*/
+    /* Object                                                                      */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Compares equality with another unboxed object.
+    /// </summary>
+    /// <param name="o">The unboxed object to compare with.</param>
+    /// <returns>True if both objects are the same.</returns>
+    bool Equals(Object^ o) override;
+
+    /// <summary>
+    /// Gets a unique hash for this object.
+    /// </summary>
+    /// <returns>Unique hash for this object.</returns>
+    int  GetHashCode() override;
+
+    /*-----------------------------------------------------------------------------*/
+    /* Static Functions                                                            */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Returns the angle in degrees between two rotations a and b.<br/>
+    /// </summary>
+    /// <returns>The angle in degrees between the two vectors. </returns>
+    static float Angle(Quaternion a, Quaternion b);
+
+    /// <summary>
+    /// Creates a rotation which rotates angle degrees around axis.
+    /// </summary>
+    static Quaternion AngleAxis(float angle, Vector3 axis);
+
+    /// <summary>
+    /// The dot product between two rotations.
+    /// </summary>
+    static float Dot(Quaternion a, Quaternion b);
+
+    /// <summary>
+    /// Returns a rotation that rotates y degrees around the y axis, x degrees around the x axis, and z degrees around the z axis; applied in that order.
+    /// </summary>
+    static Quaternion Euler(float _x, float _y, float _z);
+
+    /// <summary>
+    /// Creates a rotation which rotates from fromDirection to toDirection.
+    /// </summary>
+    static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection);
+
+    /// <summary>
+    /// Returns the Inverse of rotation.
+    /// </summary>
+    static Quaternion Inverse(Quaternion rotation);
+
+    /// <summary>
+    /// Interpolates between a and b by t and normalizes the result afterwards. The parameter t is clamped to the range [0, 1].
+    /// </summary>
+    /// <param name="a">Start value, returned when t = 0.</param>
+    /// <param name="b">End value, returned when t = 1.</param>
+    /// <param name="t">Interpolation ratio.</param>
+    /// <returns> A quaternion interpolated between quaternions a and b.</returns>
+    static Quaternion Lerp(Quaternion a, Quaternion b, float t);
+
+    /// <summary>
+    /// Interpolates between a and b by t and normalizes the result afterwards. The parameter t is not clamped.
+    /// </summary>
+    static Quaternion LerpUnclamped(Quaternion a, Quaternion b, float t);
+
+    /// <summary>
+    /// Creates a rotation with the specified forward and upwards directions. <br/>
+    /// Z axis will be aligned with forward, X axis aligned with cross product between forward and upwards, and Y axis aligned with cross product between Z and X.
+    /// </summary>
+    static Quaternion LookRotation(Vector3 forward, Vector3 upwards);
+
+    /// <summary>
+    /// Converts this quaternion to one with the same orientation but with a magnitude of 1.
+    /// </summary>
+    static Quaternion Normalize(Quaternion q);
+
+    /// <summary>
+    /// Rotates a rotation from towards to. <br/>
+    /// The from quaternion is rotated towards to by an angular step of maxDegreesDelta (but note that the rotation will not overshoot).
+    /// Negative values of maxDegreesDelta will move away from to until the rotation is exactly the opposite direction.
+    /// </summary>
+    static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta);
+
+    /// <summary>
+    /// Spherically interpolates between quaternions a and b by ratio t. The parameter t is clamped to the range [0, 1].
+    /// </summary>
+    /// <param name="a">Start value, returned when t = 0.</param>
+    /// <param name="b">End value, returned when t = 1.</param>
+    /// <param name="t">Interpolation ratio.</param>
+    /// <returns> A quaternion spherically interpolated between quaternions a and b.</returns>
+    static Quaternion Slerp(Quaternion a, Quaternion b, float t);
+
+    /// <summary>
+    /// Spherically interpolates between a and b by t. The parameter t is not clamped.
+    /// </summary>
+    static Quaternion SlerpUnclamped(Quaternion a, Quaternion b, float t); 
+
+    /*-----------------------------------------------------------------------------*/
+    /* Overloaded Operators                                                        */
+    /*-----------------------------------------------------------------------------*/
+
+    /// <summary>
+    /// Combines rotations lhs and rhs.
+    /// </summary>
+    /// <param name="lhs">Left-hand side quaternion.</param>
+    /// <param name="rhs">Right-hand side quaternion.</param>
+    static Quaternion operator*(Quaternion lhs, Quaternion rhs);
+
+    /// <summary>
+    /// Are two quaternions equal to each other?
+    /// </summary>
+    /// <param name="lhs">Left-hand side quaternion.</param>
+    /// <param name="rhs">Right-hand side quaternion.</param>
+    static bool operator==(Quaternion lhs, Quaternion rhs);
+  };
+
+} // namespace SHADE
diff --git a/SHADE_Managed/src/Math/Vector2.cxx b/SHADE_Managed/src/Math/Vector2.cxx
index d40e2323..b110d4f8 100644
--- a/SHADE_Managed/src/Math/Vector2.cxx
+++ b/SHADE_Managed/src/Math/Vector2.cxx
@@ -26,10 +26,10 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
     /* Constructors                                                                    */
     /*---------------------------------------------------------------------------------*/
-    Vector2::Vector2(double _x) 
-    : Vector2 { _x, 0.0 }
+    Vector2::Vector2(float _x) 
+    : Vector2 { _x, 0.0f }
     {}
-    Vector2::Vector2(double _x, double _y)
+    Vector2::Vector2(float _x, float _y)
     : x { _x }
     , y { _y }
     {}
@@ -47,22 +47,22 @@ namespace SHADE
         return *this / GetMagnitude();
     }
 
-    double Vector2::GetMagnitude()
+    float Vector2::GetMagnitude()
     {
         return sqrt(x * x + y * y);
     }
 
-    double Vector2::GetSqrMagnitude()
+    float Vector2::GetSqrMagnitude()
     {
         return x * x + y * y;
     }
 
-    double Vector2::AngleFromRightRadians()
+    float Vector2::AngleFromRightRadians()
     {
         return atan2(y, x);
     }
 
-    double Vector2::AngleFromRightDegrees()
+    float Vector2::AngleFromRightDegrees()
     {
         return Math::RadiansToDegrees(AngleFromRightRadians());
     }
@@ -72,7 +72,7 @@ namespace SHADE
         return IsNearPoint(point, Math::Epsilon);
     }
 
-    bool Vector2::IsNearPoint(Vector2 point, double tolerance)
+    bool Vector2::IsNearPoint(Vector2 point, float tolerance)
     {
         return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
     }
@@ -113,13 +113,13 @@ namespace SHADE
     {
         return IsNear(lhs, rhs, Math::Epsilon);
     }
-    bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, double tolerance)
+    bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, float tolerance)
     {
         return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
                &&
                (std::abs(lhs.y) - std::abs(rhs.y)) < tolerance;
     }
-    double Vector2::Dot(Vector2 lhs, Vector2 rhs)
+    float Vector2::Dot(Vector2 lhs, Vector2 rhs)
     {
         return lhs.x * rhs.x + lhs.y * rhs.y;
     }
@@ -153,12 +153,12 @@ namespace SHADE
     }
     Vector2 Vector2::Reflect(Vector2 vec, Vector2 normal)
     {
-        return vec - (Project(vec, normal.GetNormalised()) * 2.0);
+        return vec - (Project(vec, normal.GetNormalised()) * 2.0f);
     }
-    Vector2 Vector2::RotateRadians(Vector2 vec, double radians)
+    Vector2 Vector2::RotateRadians(Vector2 vec, float radians)
     {
-        const double SINE   = sin(radians);
-        const double COSINE = cos(radians);
+        const float SINE   = sin(radians);
+        const float COSINE = cos(radians);
 
         return Vector2
         (
@@ -166,35 +166,35 @@ namespace SHADE
             vec.x * SINE   + vec.y * COSINE
         );
     }
-    Vector2 Vector2::RotateDegrees(Vector2 vec, double degrees)
+    Vector2 Vector2::RotateDegrees(Vector2 vec, float degrees)
     {
         return RotateRadians(vec, Math::DegreesToRadians(degrees));
     }
     Vector2 Vector2::Min(Vector2 lhs, Vector2 rhs)
     {
-        double lx = lhs.x, rx = rhs.x;
-        double ly = lhs.y, ry = rhs.y;
+        float lx = lhs.x, rx = rhs.x;
+        float ly = lhs.y, ry = rhs.y;
 
         return Vector2(std::min(lx, rx),
                        std::min(ly, ry));   
     }
     Vector2 Vector2::Max(Vector2 lhs, Vector2 rhs)
     {
-        double lx = lhs.x, rx = rhs.x;
-        double ly = lhs.y, ry = rhs.y;
+        float lx = lhs.x, rx = rhs.x;
+        float ly = lhs.y, ry = rhs.y;
 
         return Vector2(std::max(lx, rx),
                        std::max(ly, ry));  
     }
-    Vector2 Vector2::Lerp(Vector2 a, Vector2 b, double t)
+    Vector2 Vector2::Lerp(Vector2 a, Vector2 b, float t)
     {
-        return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0));
+        return LerpUnclamped(a, b, std::clamp(t, 0.0f, 1.0f));
     }
-    Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, double t)
+    Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, float t)
     {
         return a + ((b - a) * t);
     }
-    Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta)
+    Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta)
     {
         // Ignore if it is exactly on the same point
         if (current == target)
@@ -206,7 +206,7 @@ namespace SHADE
 
         // Check if check if is behind or ahead of target
         Vector2 DIFF = target - newPos;
-        if (Dot(DELTA, DIFF) < 0.0)
+        if (Dot(DELTA, DIFF) < 0.0f)
         {
             newPos = target;
         }
@@ -236,7 +236,7 @@ namespace SHADE
             lhs.y * rhs.y
         );
     }
-    Vector2 Vector2::operator*(Vector2 lhs, double rhs)
+    Vector2 Vector2::operator*(Vector2 lhs, float rhs)
     {
         return Vector2
         (
@@ -244,7 +244,7 @@ namespace SHADE
             lhs.y * rhs
         );
     }
-    Vector2 Vector2::operator/(Vector2 lhs, double rhs)
+    Vector2 Vector2::operator/(Vector2 lhs, float rhs)
     {
         return Vector2
         (
diff --git a/SHADE_Managed/src/Math/Vector2.hxx b/SHADE_Managed/src/Math/Vector2.hxx
index 9253a703..94b1989f 100644
--- a/SHADE_Managed/src/Math/Vector2.hxx
+++ b/SHADE_Managed/src/Math/Vector2.hxx
@@ -19,8 +19,8 @@ of DigiPen Institute of Technology is prohibited.
 namespace SHADE
 {
     ///<summary>
-    /// CLR version of the the SHADE Engine's Vector2 class that represents a 
-    /// 2-Dimensional Vector. Designed to closely match Unity's Vector2 struct.
+    /// CLR version of SHADE Engine's Vector2 class that represents a 2-Dimensional Vector.
+    /// Designed to closely match Unity's Vector2 struct.
     /// </summary>
     [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
     public value struct Vector2 : public System::IEquatable<Vector2>
@@ -33,37 +33,37 @@ namespace SHADE
         ///<summary>
         /// Shorthand for writing Vector2(0, -1).
         ///</summary>
-        static initonly Vector2 Down = Vector2(0.0, -1.0);
+        static initonly Vector2 Down = Vector2(0.0f, -1.0f);
         ///<summary>
         /// Shorthand for writing Vector2(-1, 0).
         ///</summary>
-        static initonly Vector2 Left = Vector2(-1.0, 0.0);
+        static initonly Vector2 Left = Vector2(-1.0f, 0.0f);
         ///<summary>
-        /// Shorthand for writing Vector2(double.NegativeInfinity, 
-        /// double.NegativeInfinity).
+        /// Shorthand for writing Vector2(float.NegativeInfinity, 
+        /// float.NegativeInfinity).
         ///</summary>
-        static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest());
+        static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest());
         ///<summary>
         /// Shorthand for writing Vector2(1, 1).
         ///</summary>
-        static initonly Vector2 One = Vector2(1.0, 1.0);
+        static initonly Vector2 One = Vector2(1.0f, 1.0f);
         ///<summary>
-        /// Shorthand for writing Vector2(double.PositiveInfinity, 
-        /// double.PositiveInfinity).
+        /// Shorthand for writing Vector2(float.PositiveInfinity, 
+        /// float.PositiveInfinity).
         ///</summary>
-        static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
+        static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
         ///<summary>
         /// Shorthand for writing Vector2(1, 0).
         ///</summary>
-        static initonly Vector2 Right = Vector2(1.0, 0.0);
+        static initonly Vector2 Right = Vector2(1.0f, 0.0f);
         ///<summary>
         /// Shorthand for writing Vector2(0, 1).
         ///</summary>
-        static initonly Vector2 Up = Vector2(0.0, 1.0);
+        static initonly Vector2 Up = Vector2(0.0f, 1.0f);
         ///<summary>
         /// Shorthand for writing Vector2(0, 0).
         ///</summary>        
-        static initonly Vector2 Zero = Vector2(0.0, 0.0);
+        static initonly Vector2 Zero = Vector2(0.0f, 0.0f);
         #pragma endregion
 
         /*-----------------------------------------------------------------------------*/
@@ -72,27 +72,27 @@ namespace SHADE
         ///<summary>
         /// X-component of the Vector2.
         ///</summary>
-        double x;
+        float x;
         ///<summary>
         /// Y-component of the Vector2.
         ///</summary>
-        double y;
+        float y;
 
         /*-----------------------------------------------------------------------------*/
         /* Constructors                                                                */
         /*-----------------------------------------------------------------------------*/
         /// <summary>
         /// Constructor to construct a Vector2 with the specified components with the 
-        /// Y-component set to 0.0.
+        /// Y-component set to 0.0f.
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
-        Vector2(double _x);
+        Vector2(float _x);
         /// <summary>
         /// Constructor to construct a Vector2 with the specified components..
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
         /// <param name="_y">Y-coordinate to set.</param>
-        Vector2(double _x, double _y);
+        Vector2(float _x, float _y);
 
         /*-----------------------------------------------------------------------------*/
         /* Usage Functions                                                             */
@@ -117,24 +117,24 @@ namespace SHADE
         /// need the precise magnitude, consider using GetSqrMagnitude() instead.
         /// </summary>
         /// <returns>Returns the length of this Vector2.</returns>
-        double GetMagnitude();
+        float GetMagnitude();
         /// <summary>
         /// Calculates and returns the squared magnitude of this Vector2.
         /// </summary>
         /// <returns>Returns the squared length of this Vector2.</returns>
-        double GetSqrMagnitude();
+        float GetSqrMagnitude();
         /// <summary>
         /// Calculates and returns the angle of this vector from the right vector. This 
         /// function returns values between -Math.PI and Math.PI.
         /// </summary>
         /// <returns>Returns the angle of this vector from the right vector in radians.</returns>
-        double AngleFromRightRadians();
+        float AngleFromRightRadians();
         /// <summary>
         /// Calculates and returns the angle of this vector from the right vector. This 
-        /// function returns values between -180.0 and 180.0.
+        /// function returns values between -180.0f and 180.0f.
         /// </summary>
         /// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
-        double AngleFromRightDegrees();
+        float AngleFromRightDegrees();
         /// <summary>
         /// Checks if a specified point is near this Vector2 that represents a point with
         /// a tolerance value of PLS_EPSILON.
@@ -156,7 +156,7 @@ namespace SHADE
         /// True if this Vector2 representing a point and the specified point are within
         /// the range of the specified tolerance. False otherwise.
         /// </returns>
-        bool IsNearPoint(Vector2 point, double tolerance);
+        bool IsNearPoint(Vector2 point, float tolerance);
 
         /*-----------------------------------------------------------------------------*/
         /* IEquatable                                                                  */
@@ -206,7 +206,7 @@ namespace SHADE
         /// <returns>
         /// True if the two Vector2s are within the tolerance value specified
         /// </returns>
-        static bool IsNear(Vector2 lhs, Vector2 rhs, double tolerance);
+        static bool IsNear(Vector2 lhs, Vector2 rhs, float tolerance);
         /// <summary>
         /// Computes and returns the dot product of 2 specified Vector2s.
         /// </summary>
@@ -215,7 +215,7 @@ namespace SHADE
         /// <returns>
         /// Scalar value representing the dot product of the two Vector2s.
         /// </returns>
-        static double Dot(Vector2 lhs, Vector2 rhs);
+        static float Dot(Vector2 lhs, Vector2 rhs);
         /// <summary>
         /// Computes the inward perpendicular Vector2 to the specified Vector2.
         /// Equivalent to calling Perpendicular(lhs, true). This means, the
@@ -260,7 +260,7 @@ namespace SHADE
         /// Angle to rotate the vector by in an anti-clockwise direction in radians.
         /// </param>
         /// <returns>The Vector2 that represents the rotated vector.</returns>
-        static Vector2 RotateRadians(Vector2 vec, double radians);
+        static Vector2 RotateRadians(Vector2 vec, float radians);
         /// <summary>
         /// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise 
         /// direction.
@@ -270,7 +270,7 @@ namespace SHADE
         /// Angle to rotate the vector by in an anti-clockwise direction in degrees.
         /// </param>
         /// <returns>The Vector2 that represents the rotated vector.</returns>
-        static Vector2 RotateDegrees(Vector2 vec, double degrees);
+        static Vector2 RotateDegrees(Vector2 vec, float degrees);
         /// <summary>
         /// Computes and returns a Vector2 that is made from the smallest components of 
         /// the two specified Vector2s.
@@ -298,25 +298,25 @@ namespace SHADE
         /// This is most commonly used to find a point some fraction of the way along a 
         /// line between two endpoints.
         /// </summary>
-        /// <param name="a">The start Vector2, returned when t = 0.0.</param>
-        /// <param name="b">The end Vector2, returned when t = 1.0.</param>
+        /// <param name="a">The start Vector2, returned when t = 0.0f.</param>
+        /// <param name="b">The end Vector2, returned when t = 1.0f.</param>
         /// <param name="t">
         /// Value used to interpolate between a and b which is clamped to
         /// the range[0, 1].
         /// </param>
         /// <returns>The interpolated Vector2.</returns>
-        static Vector2 Lerp(Vector2 a, Vector2 b, double t);        
+        static Vector2 Lerp(Vector2 a, Vector2 b, float t);        
         /// <summary>
         /// Linearly interpolates between two specified points. 
         /// This is most commonly used to find a point some fraction of the way along a 
         /// line between two endpoints.
         /// Unlike Lerp(), t is not clamped to a range at all.
         /// </summary>
-        /// <param name="a">The start Vector2, returned when t = 0.0.</param>
-        /// <param name="b">The end Vector2, returned when t = 1.0.</param>
+        /// <param name="a">The start Vector2, returned when t = 0.0f.</param>
+        /// <param name="b">The end Vector2, returned when t = 1.0f.</param>
         /// <param name="t">Value used to interpolate between a and b.</param>
         /// <returns>The interpolated Vector2.</returns>
-        static Vector2 LerpUnclamped(Vector2 a, Vector2 b, double t);
+        static Vector2 LerpUnclamped(Vector2 a, Vector2 b, float t);
         /// <summary>
         /// Moves a point current towards target.
         /// Similar to Lerp(), however, the function will ensure that the distance never
@@ -327,7 +327,7 @@ namespace SHADE
         /// <param name="target">The target position to move to.</param>
         /// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
         /// <returns>Vector representing the moved point.</returns>
-        static Vector2 MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta);
+        static Vector2 MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta);
 
         /*-----------------------------------------------------------------------------*/
         /* Overloaded Operators                                                        */
@@ -361,7 +361,7 @@ namespace SHADE
         /// <param name="lhs">Vector2 to multiply with.</param>
         /// <param name="rhs">Scalar to multiply with.</param>
         /// <returns>The result of the scalar multiplication.</returns>
-        static Vector2 operator*(Vector2 lhs, double rhs);
+        static Vector2 operator*(Vector2 lhs, float rhs);
         /// <summary>
         /// Calculates the division of a Vector2 with a scalar value and returns 
         /// the result.
@@ -369,7 +369,7 @@ namespace SHADE
         /// <param name="lhs">Scalar to divide with.</param>
         /// <param name="rhs">Vector2 to divide with.</param>
         /// <returns>The result of the scalar division.</returns>
-        static Vector2 operator/(Vector2 lhs, double rhs);
+        static Vector2 operator/(Vector2 lhs, float rhs);
         /// <summary>
         /// Checks if two Vector2s are approximately equal. This is equivalent to 
         /// calling Vector2.IsNear() with default tolerance values.
diff --git a/SHADE_Managed/src/Math/Vector3.cxx b/SHADE_Managed/src/Math/Vector3.cxx
index 26ff5a72..adbb4d3a 100644
--- a/SHADE_Managed/src/Math/Vector3.cxx
+++ b/SHADE_Managed/src/Math/Vector3.cxx
@@ -11,6 +11,7 @@ Copyright (C) 2021 DigiPen Institute of Technology.
 Reproduction or disclosure of this file or its contents without the prior written consent 
 of DigiPen Institute of Technology is prohibited.
 *//*************************************************************************************/
+
 // Precompiled Headers
 #include "SHpch.h"
 // Primary Header
@@ -26,13 +27,13 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
     /* Constructors                                                                    */
     /*---------------------------------------------------------------------------------*/
-    Vector3::Vector3(double _x) 
-    : Vector3 {_x, 0.0, 0.0}
+    Vector3::Vector3(float _x) 
+    : Vector3 {_x, 0.0f, 0.0f}
     {}
-    Vector3::Vector3(double _x, double _y)
-    : Vector3 {_x, _y, 0.0}
+    Vector3::Vector3(float _x, float _y)
+    : Vector3 {_x, _y, 0.0f}
     {}
-    Vector3::Vector3(double _x, double _y, double _z)
+    Vector3::Vector3(float _x, float _y, float _z)
     : x { _x }
     , y { _y }
     , z { _z }
@@ -54,22 +55,22 @@ namespace SHADE
         return *this / GetSqrMagnitude();
     }
 
-    double Vector3::GetMagnitude()
+    float Vector3::GetMagnitude()
     {
         return sqrt(x * x + y * y + z * z);
     }
 
-    double Vector3::GetSqrMagnitude()
+    float Vector3::GetSqrMagnitude()
     {
         return x * x + y * y + z * z;
     }
 
-    double Vector3::Angle2DFromRightRadians()
+    float Vector3::Angle2DFromRightRadians()
     {
         return atan2(y, x);
     }
 
-    double Vector3::Angle2DFromRightDegrees()
+    float Vector3::Angle2DFromRightDegrees()
     {
         return Math::RadiansToDegrees(Angle2DFromRightRadians());
     }
@@ -79,7 +80,7 @@ namespace SHADE
         return IsNearPoint(point, Math::Epsilon);
     }
 
-    bool Vector3::IsNearPoint(Vector3 point, double tolerance)
+    bool Vector3::IsNearPoint(Vector3 point, float tolerance)
     {
         return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
     }
@@ -121,7 +122,7 @@ namespace SHADE
     {
         return IsNear(lhs, rhs, Math::Epsilon);
     }
-    bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, double tolerance)
+    bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, float tolerance)
     {
         return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
                &&
@@ -129,7 +130,7 @@ namespace SHADE
                &&
                (std::abs(lhs.z) - std::abs(rhs.z)) < tolerance;
     }
-    double Vector3::Dot(Vector3 lhs, Vector3 rhs)
+    float Vector3::Dot(Vector3 lhs, Vector3 rhs)
     {
         return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
     }
@@ -145,12 +146,12 @@ namespace SHADE
     }
     Vector3 Vector3::Reflect(Vector3 vec, Vector3 normal)
     {
-        return vec - (Project(vec, normal.GetNormalised()) * 2.0);
+        return vec - (Project(vec, normal.GetNormalised()) * 2.0f);
     }
-    Vector3 Vector3::RotateRadians(Vector3 vec, double radians)
+    Vector3 Vector3::RotateRadians(Vector3 vec, float radians)
     {
-        const double SINE   = sin(radians);
-        const double COSINE = cos(radians);
+        const float SINE   = sin(radians);
+        const float COSINE = cos(radians);
 
         return Vector3
         (
@@ -159,15 +160,15 @@ namespace SHADE
             vec.z
         );
     }
-    Vector3 Vector3::RotateDegrees(Vector3 vec, double degrees)
+    Vector3 Vector3::RotateDegrees(Vector3 vec, float degrees)
     {
         return RotateRadians(vec, Math::DegreesToRadians(degrees));
     }
     Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs)
     {
-        double lx = lhs.x, rx = rhs.x;
-        double ly = lhs.y, ry = rhs.y;
-        double lz = lhs.z, rz = rhs.z;
+        float lx = lhs.x, rx = rhs.x;
+        float ly = lhs.y, ry = rhs.y;
+        float lz = lhs.z, rz = rhs.z;
 
         return Vector3(std::min(lx, rx),
                        std::min(ly, ry),
@@ -175,23 +176,23 @@ namespace SHADE
     }
     Vector3 Vector3::Max(Vector3 lhs, Vector3 rhs)
     {
-        double lx = lhs.x, rx = rhs.x;
-        double ly = lhs.y, ry = rhs.y;
-        double lz = lhs.z, rz = rhs.z;
+        float lx = lhs.x, rx = rhs.x;
+        float ly = lhs.y, ry = rhs.y;
+        float lz = lhs.z, rz = rhs.z;
 
         return Vector3(std::max(lx, rx),
                        std::max(ly, ry),
                        std::max(lz, rz));  
     }
-    Vector3 Vector3::Lerp(Vector3 a, Vector3 b, double t)
+    Vector3 Vector3::Lerp(Vector3 a, Vector3 b, float t)
     {
-        return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0));
+        return LerpUnclamped(a, b, std::clamp(t, 0.0f, 1.0f));
     }
-    Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, double t)
+    Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, float t)
     {
         return a + ((b - a) * t);
     }
-    Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta)
+    Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta)
     {
         // Ignore if it is exactly on the same point
         if (current == target)
@@ -203,7 +204,7 @@ namespace SHADE
 
         // Check if check if is behind or ahead of target
         Vector3 DIFF = target - newPos;
-        if (Dot(DELTA, DIFF) < 0.0)
+        if (Dot(DELTA, DIFF) < 0.0f)
         {
             newPos = target;
         }
@@ -236,7 +237,7 @@ namespace SHADE
             lhs.z * rhs.z
         );
     }
-    Vector3 Vector3::operator*(Vector3 lhs, double rhs)
+    Vector3 Vector3::operator*(Vector3 lhs, float rhs)
     {
         return Vector3
         (
@@ -245,7 +246,7 @@ namespace SHADE
             lhs.z * rhs
         );
     }
-    Vector3 Vector3::operator/(Vector3 lhs, double rhs)
+    Vector3 Vector3::operator/(Vector3 lhs, float rhs)
     {
         return Vector3
         (
diff --git a/SHADE_Managed/src/Math/Vector3.hxx b/SHADE_Managed/src/Math/Vector3.hxx
index e6cdc7d4..70cff88f 100644
--- a/SHADE_Managed/src/Math/Vector3.hxx
+++ b/SHADE_Managed/src/Math/Vector3.hxx
@@ -11,6 +11,7 @@ Copyright (C) 2021 DigiPen Institute of Technology.
 Reproduction or disclosure of this file or its contents without the prior written consent 
 of DigiPen Institute of Technology is prohibited.
 *//*************************************************************************************/
+
 #pragma once
 
 // Standard Libraries
@@ -21,8 +22,8 @@ of DigiPen Institute of Technology is prohibited.
 namespace SHADE
 {
     ///<summary>
-    /// CLR version of the the PlushieEngine's Vector3 class that represents a 
-    /// 3-Dimensional Vector. Designed to closely match Unity's Vector3 struct.
+    /// CLR version of SHADE Engine's Vector3 class that represents a 3-Dimensional Vector.
+    /// Designed to closely match Unity's Vector3 struct.
     /// </summary>
     [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
     public value struct Vector3 : public System::IEquatable<Vector3>
@@ -35,49 +36,49 @@ namespace SHADE
         ///<summary>
         /// Shorthand for writing Vector3(0, 0, -1).
         ///</summary>
-        static initonly Vector3 Back = Vector3(0.0, 0.0, -1.0);
+        static initonly Vector3 Back = Vector3(0.0f, 0.0f, -1.0f);
         ///<summary>
         /// Shorthand for writing Vector3(0, -1, 0).
         ///</summary>
-        static initonly Vector3 Down = Vector3(0.0, -1.0, 0.0);
+        static initonly Vector3 Down = Vector3(0.0f, -1.0f, 0.0f);
         ///<summary>
         /// Shorthand for writing Vector3(0, 0, 1).
         ///</summary>
-        static initonly Vector3 Forward = Vector3(0.0, 0.0, 1.0);
+        static initonly Vector3 Forward = Vector3(0.0f, 0.0f, 1.0f);
         ///<summary>
         /// Shorthand for writing Vector3(-1, 0, 0).
         ///</summary>
-        static initonly Vector3 Left = Vector3(-1.0, 0.0, 0.0);
+        static initonly Vector3 Left = Vector3(-1.0f, 0.0f, 0.0f);
         ///<summary>
-        /// Shorthand for writing Vector3(double.NegativeInfinity, 
-        /// double.NegativeInfinity, double.NegativeInfinity).
+        /// Shorthand for writing Vector3(float.NegativeInfinity, 
+        /// float.NegativeInfinity, float.NegativeInfinity).
         ///</summary>
-        static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits<double>::lowest(),
-                                                               std::numeric_limits<double>::lowest(), 
-                                                               std::numeric_limits<double>::lowest());
+        static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits<float>::lowest(),
+                                                               std::numeric_limits<float>::lowest(), 
+                                                               std::numeric_limits<float>::lowest());
         ///<summary>
         /// Shorthand for writing Vector3(1, 1, 1).
         ///</summary>
-        static initonly Vector3 One = Vector3(1.0, 1.0, 1.0);
+        static initonly Vector3 One = Vector3(1.0f, 1.0f, 1.0f);
         ///<summary>
-        /// Shorthand for writing Vector3(double.PositiveInfinity, 
-        /// double.PositiveInfinity, double.PositiveInfinity).
+        /// Shorthand for writing Vector3(float.PositiveInfinity, 
+        /// float.PositiveInfinity, float.PositiveInfinity).
         ///</summary>
-        static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits<double>::max(),
-                                                               std::numeric_limits<double>::max(), 
-                                                               std::numeric_limits<double>::max());
+        static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits<float>::max(),
+                                                               std::numeric_limits<float>::max(), 
+                                                               std::numeric_limits<float>::max());
         ///<summary>
         /// Shorthand for writing Vector3(1, 0, 0).
         ///</summary>
-        static initonly Vector3 Right = Vector3(1.0, 0.0, 0.0);
+        static initonly Vector3 Right = Vector3(1.0f, 0.0f, 0.0f);
         ///<summary>
         /// Shorthand for writing Vector3(0, 1, 0).
         ///</summary>
-        static initonly Vector3 Up = Vector3(0.0, 1.0, 0.0);
+        static initonly Vector3 Up = Vector3(0.0f, 1.0f, 0.0f);
         ///<summary>
         /// Shorthand for writing Vector3(0, 0, 0).
         ///</summary>        
-        static initonly Vector3 Zero = Vector3(0.0, 0.0, 0.0);
+        static initonly Vector3 Zero = Vector3(0.0f, 0.0f, 0.0f);
         #pragma endregion
 
         /*-----------------------------------------------------------------------------*/
@@ -86,39 +87,39 @@ namespace SHADE
         ///<summary>
         /// X-component of the Vector3.
         ///</summary>
-        double x;
+        float x;
         ///<summary>
         /// Y-component of the Vector3.
         ///</summary>
-        double y;
+        float y;
         ///<summary>
         /// Z-component of the Vector3.
         ///</summary>
-        double z;
+        float z;
 
         /*-----------------------------------------------------------------------------*/
         /* Constructors                                                                */
         /*-----------------------------------------------------------------------------*/
         /// <summary>
         /// Constructor to construct a Vector3 with the specified components with the 
-        /// Y and Z-component set to 0.0.
+        /// Y and Z-component set to 0.0f.
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
-        Vector3(double _x);
+        Vector3(float _x);
         /// <summary>
         /// Constructor to construct a Vector3 with the specified components with the 
-        /// Z-component set to 0.0.
+        /// Z-component set to 0.0f.
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
         /// <param name="_y">Y-coordinate to set.</param>
-        Vector3(double _x, double _y);
+        Vector3(float _x, float _y);
         /// <summary>
         /// Constructor to construct a Vector3 with the specified components.
         /// </summary>
         /// <param name="_x">X-coordinate to set.</param>
         /// <param name="_y">Y-coordinate to set.</param>
         /// <param name="_z">Z-coordinate to set.</param>
-        Vector3(double _x, double _y, double _z);
+        Vector3(float _x, float _y, float _z);
         /// <summary>
         /// Conversion constructor to construct a Vector3 using a Vector2.
         /// </summary>
@@ -148,24 +149,24 @@ namespace SHADE
         /// need the precise magnitude, consider using GetSqrMagnitude() instead.
         /// </summary>
         /// <returns>Returns the length of this Vector3.</returns>
-        double GetMagnitude();
+        float GetMagnitude();
         /// <summary>
         /// Calculates and returns the squared magnitude of this Vector3.
         /// </summary>
         /// <returns>Returns the squared length of this Vector3.</returns>
-        double GetSqrMagnitude();
+        float GetSqrMagnitude();
         /// <summary>
         /// Calculates and returns the angle of this vector from the right vector. This 
         /// function returns values between -Math.PI and Math.PI.
         /// </summary>
         /// <returns>Returns the angle of this vector from the right vector in radians.</returns>
-        double Angle2DFromRightRadians();
+        float Angle2DFromRightRadians();
         /// <summary>
         /// Calculates and returns the angle of this vector from the right vector. This 
-        /// function returns values between -180.0 and 180.0.
+        /// function returns values between -180.0f and 180.0f.
         /// </summary>
         /// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
-        double Angle2DFromRightDegrees();
+        float Angle2DFromRightDegrees();
         /// <summary>
         /// Checks if a specified point is near this Vector3 that represents a point with
         /// a tolerance value of PLS_EPSILON.
@@ -187,7 +188,7 @@ namespace SHADE
         /// True if this Vector3 representing a point and the specified point are within
         /// the range of the specified tolerance. False otherwise.
         /// </returns>
-        bool IsNearPoint(Vector3 point, double tolerance);
+        bool IsNearPoint(Vector3 point, float tolerance);
 
         /*-----------------------------------------------------------------------------*/
         /* IEquatable                                                                  */
@@ -207,12 +208,12 @@ namespace SHADE
         /// </summary>
         /// <param name="o">The unboxed object to compare with.</param>
         /// <returns>True if both objects are the same.</returns>
-        bool Equals(Object^ o) override; 
+        bool Equals(Object^ o) override;
         /// <summary>
         /// Gets a unique hash for this object.
         /// </summary>
         /// <returns>Unique hash for this object.</returns>
-        int  GetHashCode() override;         
+        int  GetHashCode() override;
 
         /*-----------------------------------------------------------------------------*/
         /* Static Functions                                                            */
@@ -235,14 +236,14 @@ namespace SHADE
         /// <returns>
         /// True if the two Vector3s are within the tolerance value specified
         /// </returns>
-        static bool IsNear(Vector3 lhs, Vector3 rhs, double tolerance);
+        static bool IsNear(Vector3 lhs, Vector3 rhs, float tolerance);
         /// <summary>
         /// Computes and returns the dot product of 2 specified Vector3s.
         /// </summary>
         /// <param name="lhs">Vector3 to calculate dot product with.</param>
         /// <param name="rhs">Another Vector3 to calculate dot product with.</param>
         /// <returns>Scalar value representing the dot product of the two Vector3s.</returns>
-        static double Dot(Vector3 lhs, Vector3 rhs);
+        static float Dot(Vector3 lhs, Vector3 rhs);
         /// <summary>
         /// Computes and returns the cross product of 2 specified Vector3s.
         /// </summary>
@@ -273,7 +274,7 @@ namespace SHADE
         /// Angle to rotate the vector by in an anti-clockwise direction in radians.
         /// </param>
         /// <returns>The Vector3 that represents the rotated vector.</returns>
-        static Vector3 RotateRadians(Vector3 vec, double radians);
+        static Vector3 RotateRadians(Vector3 vec, float radians);
         /// <summary>
         /// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise 
         /// direction.
@@ -283,7 +284,7 @@ namespace SHADE
         /// Angle to rotate the vector by in an anti-clockwise direction in degrees.
         /// </param>
         /// <returns>The Vector3 that represents the rotated vector.</returns>
-        static Vector3 RotateDegrees(Vector3 vec, double degrees);
+        static Vector3 RotateDegrees(Vector3 vec, float degrees);
         /// <summary>
         /// Computes and returns a Vector3 that is made from the smallest components of 
         /// the two specified Vector3s.
@@ -311,25 +312,25 @@ namespace SHADE
         /// This is most commonly used to find a point some fraction of the way along a 
         /// line between two endpoints.
         /// </summary>
-        /// <param name="a">The start Vector3, returned when t = 0.0.</param>
-        /// <param name="b">The end Vector3, returned when t = 1.0.</param>
+        /// <param name="a">The start Vector3, returned when t = 0.0f.</param>
+        /// <param name="b">The end Vector3, returned when t = 1.0f.</param>
         /// <param name="t">
         /// Value used to interpolate between a and b which is clamped to
         /// the range[0, 1].
         /// </param>
         /// <returns>The interpolated Vector3.</returns>
-        static Vector3 Lerp(Vector3 a, Vector3 b, double t);        
+        static Vector3 Lerp(Vector3 a, Vector3 b, float t);        
         /// <summary>
         /// Linearly interpolates between two specified points. 
         /// This is most commonly used to find a point some fraction of the way along a 
         /// line between two endpoints.
         /// Unlike Lerp(), t is not clamped to a range at all.
         /// </summary>
-        /// <param name="a">The start Vector3, returned when t = 0.0.</param>
-        /// <param name="b">The end Vector3, returned when t = 1.0.</param>
+        /// <param name="a">The start Vector3, returned when t = 0.0f.</param>
+        /// <param name="b">The end Vector3, returned when t = 1.0f.</param>
         /// <param name="t">Value used to interpolate between a and b.</param>
         /// <returns>The interpolated Vector3.</returns>
-        static Vector3 LerpUnclamped(Vector3 a, Vector3 b, double t);
+        static Vector3 LerpUnclamped(Vector3 a, Vector3 b, float t);
         /// <summary>
         /// Moves a point current towards target.
         /// Similar to Lerp(), however, the function will ensure that the distance never
@@ -340,7 +341,7 @@ namespace SHADE
         /// <param name="target">The target position to move to.</param>
         /// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
         /// <returns>Vector representing the moved point.</returns>
-        static Vector3 MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta);
+        static Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta);
 
         /*-----------------------------------------------------------------------------*/
         /* Overloaded Operators                                                        */
@@ -374,7 +375,7 @@ namespace SHADE
         /// <param name="lhs">Vector3 to multiply with.</param>
         /// <param name="rhs">Scalar to multiply with.</param>
         /// <returns>The result of the scalar multiplication.</returns>
-        static Vector3 operator*(Vector3 lhs, double rhs);
+        static Vector3 operator*(Vector3 lhs, float rhs);
         /// <summary>
         /// Calculates the division of a Vector3 with a scalar value and returns 
         /// the result.
@@ -382,7 +383,7 @@ namespace SHADE
         /// <param name="lhs">Scalar to divide with.</param>
         /// <param name="rhs">Vector3 to divide with.</param>
         /// <returns>The result of the scalar division.</returns>
-        static Vector3 operator/(Vector3 lhs, double rhs);
+        static Vector3 operator/(Vector3 lhs, float rhs);
         /// <summary>
         /// Checks if two Vector3s are approximately equal. This is equivalent to 
         /// calling Vector3.IsNear() with default tolerance values.
diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx
index 661eb3e4..4646194b 100644
--- a/SHADE_Managed/src/Utility/Convert.cxx
+++ b/SHADE_Managed/src/Utility/Convert.cxx
@@ -35,10 +35,7 @@ namespace SHADE
     /*---------------------------------------------------------------------------------*/
     SHVec3 Convert::ToNative(Vector3 vec)
     {
-        const double X = vec.x;
-        const double Y = vec.y;
-        const double Z = vec.z;
-        return SHVec3(X, Y, Z);
+        return SHVec3(vec.x, vec.y, vec.z);
     }
     Vector3 Convert::ToCLI(const SHVec3& vec)
     {
@@ -46,9 +43,7 @@ namespace SHADE
     }
     SHVec2 Convert::ToNative(Vector2 vec)
     {
-        const double X = vec.x;
-        const double Y = vec.y;
-        return SHVec2(X, Y);
+        return SHVec2(vec.x, vec.y);
     }
 
     Vector2 Convert::ToCLI(const SHVec2& vec)
@@ -56,6 +51,16 @@ namespace SHADE
         return Vector2(vec.x, vec.y);
     }
 
+    SHQuaternion Convert::ToNative(Quaternion quat)
+    {
+      return SHQuaternion{ quat.x, quat.y, quat.z, quat.w };
+    }
+
+    Quaternion   Convert::ToCLI(const SHQuaternion& quat)
+    {
+      return Quaternion{ quat.x, quat.y, quat.z, quat.w };
+    }
+
     /*---------------------------------------------------------------------------------*/
     /* String Conversions                                                              */
     /*---------------------------------------------------------------------------------*/
diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx
index f04cbf4b..d694ca6a 100644
--- a/SHADE_Managed/src/Utility/Convert.hxx
+++ b/SHADE_Managed/src/Utility/Convert.hxx
@@ -18,10 +18,12 @@ of DigiPen Institute of Technology is prohibited.
 #include "ECS_Base/Entity/SHEntity.h"
 #include "Math/Vector/SHVec2.h"
 #include "Math/Vector/SHVec3.h"
+#include "Math/SHQuaternion.h"
 // Project Includes
 #include "Engine/Entity.hxx"
 #include "Math/Vector2.hxx"
 #include "Math/Vector3.hxx"
+#include "Math/Quaternion.hxx"
 
 namespace SHADE
 {
@@ -74,6 +76,18 @@ namespace SHADE
         /// <param name="vec">The native Vector2 to convert from.</param>
         /// <returns>Managed copy of a native Vector2.</returns>
         static Vector2 ToCLI(const SHVec2& vec);
+        /// <summary>
+        /// Converts from a managed Quaternion to a native Quaternion.
+        /// </summary>
+        /// <param name="quat">The managed Quaternion to convert from.</param>
+        /// <returns>Native copy of a managed Quaternion.</returns>
+        static SHQuaternion ToNative(Quaternion quat);
+        /// <summary>
+        /// Converts from a native Quaternion to a managed Quaternion.
+        /// </summary>
+        /// <param name="quat">The native Quaternion to convert from.</param>
+        /// <returns>Managed copy of a native Quaternion.</returns>
+        static Quaternion ToCLI(const SHQuaternion& quat);
 
         /*-----------------------------------------------------------------------------*/
         /* String Conversions                                                          */
diff --git a/TempShaderFolder/KirschCs.glsl b/TempShaderFolder/KirschCs.glsl
new file mode 100644
index 00000000..3dec174d
--- /dev/null
+++ b/TempShaderFolder/KirschCs.glsl
@@ -0,0 +1,167 @@
+//#version 450
+//
+//layout(local_size_x = 16, local_size_y = 16) in;
+//layout(set = 4, binding = 0, rgba8) uniform image2D targetImage;
+//
+//
+//void main()
+//{
+//  ivec2 imageSize = imageSize (targetImage);
+//
+//  if (gl_GlobalInvocationID.x >= imageSize.x && gl_GlobalInvocationID.y >= imageSize.y)
+//    return;
+//
+//  // load the image
+//  vec4 color = imageLoad (targetImage, ivec2 (gl_GlobalInvocationID));
+//  
+//  // get the average
+//  float average = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
+//
+//  // store result into result image
+//  imageStore(targetImage, ivec2(gl_GlobalInvocationID), vec4(average, average, average, 1.0f));
+//
+//}
+//
+//
+//
+//
+
+/* Start Header *****************************************************************/
+
+/*! \file (e.g. kirsch.comp)
+
+     \author William Zheng, william.zheng, 60001906. Brandon Mak, brandon.hao 390003920.
+
+     \par william.zheng\@digipen.edu. brandon.hao\@digipen.edu.
+
+     \date Sept 20, 2022
+
+     \brief Copyright (C) 20xx DigiPen Institute of Technology.
+
+  Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. */
+
+  /* End Header *******************************************************************/
+
+#version 450
+
+#define MASK_WIDTH 3
+#define HALF_M_WIDTH MASK_WIDTH / 2
+#define SHM_WIDTH 18
+#define NUM_MASKS 8
+
+layout(local_size_x = 16, local_size_y = 16) in;
+layout(set = 4, binding = 0, rgba8) uniform image2D inputImage;
+layout(set = 4, binding = 1, rgba8) uniform image2D resultImage;
+
+const    float kirsch[8][3][3] = {
+        {
+         {5, 5, 5},
+         {-3, 0, -3},           /*rotation 1 */
+         {-3, -3, -3}
+         },
+        {
+         {5, 5, -3},
+         {5, 0, -3},            /*rotation 2 */
+         {-3, -3, -3}
+         },
+        {
+         {5, -3, -3},
+         {5, 0, -3},            /*rotation 3 */
+         {5, -3, -3}
+         },
+        {
+         {-3, -3, -3},
+         {5, 0, -3},            /*rotation 4 */
+         {5, 5, -3}
+         },
+        {
+         {-3, -3, -3},
+         {-3, 0, -3},           /*rotation 5 */
+         {5, 5, 5}
+         },
+        {
+         {-3, -3, -3},
+         {-3, 0, 5},            /*rotation 6 */
+         {-3, 5, 5}
+         },
+        {
+         {-3, -3, 5},
+         {-3, 0, 5},            /*rotation 7 */
+         {-3, -3, 5}
+         },
+        {
+         {-3, 5, 5},
+         {-3, 0, 5},            /*rotation 8 */
+         {-3, -3, -3}
+         }
+};
+
+vec3 GetImageValues(ivec2 uv, ivec2 inputImageSize)
+{
+  if (uv.x >= 0 && uv.y >= 0 && uv.x < inputImageSize.x && uv.y < inputImageSize.y)
+  {
+    return imageLoad(inputImage, uv).rgb;
+  }
+  else
+    return vec3(0.0f);
+}
+
+//two extra row/col
+shared vec3 sData[16 + 2][16 + 2];
+
+void main()
+{
+  // convenient variables
+  ivec3 globalThread = ivec3(gl_GlobalInvocationID);
+  ivec3 localThread = ivec3(gl_LocalInvocationID);
+  ivec2 inputImageSize = imageSize(inputImage);
+
+  // load shared memory
+  ivec2 start = ivec2(gl_WorkGroupID) * ivec2(gl_WorkGroupSize) - ivec2(HALF_M_WIDTH);
+  for (int i = localThread.x; i < SHM_WIDTH; i += int(gl_WorkGroupSize.x))
+  {
+    for (int j = localThread.y; j < SHM_WIDTH; j += int(gl_WorkGroupSize.y))
+    {
+      // get from source image (either real values or 0)
+      vec3 sourceValue = GetImageValues(start + ivec2(i, j), inputImageSize);
+      sData[i][j] = sourceValue;
+    }
+  }
+
+  // wait for shared memory to finish loading
+  barrier();
+
+  // max (between all 8 masks)
+  vec3 maxSum = vec3(0.0f);
+
+  // loop through all masks 
+  for (int i = 0; i < NUM_MASKS; ++i)
+  {
+    vec3 sum = vec3(0.0f);
+
+    // start of shared memory
+    ivec2 shmStart = ivec2(localThread + HALF_M_WIDTH);
+    for (int j = -1; j < HALF_M_WIDTH + 1; ++j)
+    {
+      for (int k = -1; k < HALF_M_WIDTH + 1; ++k)
+      {
+        // Perform convolution using shared_memory
+        sum += sData[shmStart.x + j][shmStart.y + k] * kirsch[i][j + 1][k + 1];
+      }
+    }
+
+    // Get highest sum
+    maxSum = max(sum, maxSum);
+  }
+
+  // average the max sum
+  maxSum = min(max(maxSum / 8, 0), 1.0f);
+
+  // store result into result image
+  imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), vec4(maxSum, 1.0f));
+
+}
+
+
+
+
diff --git a/TempShaderFolder/KirschCs.spv b/TempShaderFolder/KirschCs.spv
new file mode 100644
index 00000000..1ae5408b
Binary files /dev/null and b/TempShaderFolder/KirschCs.spv differ
diff --git a/TempShaderFolder/PureCopyCs.glsl b/TempShaderFolder/PureCopyCs.glsl
new file mode 100644
index 00000000..89da6dd9
--- /dev/null
+++ b/TempShaderFolder/PureCopyCs.glsl
@@ -0,0 +1,67 @@
+//#version 450
+//
+//layout(local_size_x = 16, local_size_y = 16) in;
+//layout(set = 4, binding = 0, rgba8) uniform image2D targetImage;
+//
+//
+//void main()
+//{
+//  ivec2 imageSize = imageSize (targetImage);
+//
+//  if (gl_GlobalInvocationID.x >= imageSize.x && gl_GlobalInvocationID.y >= imageSize.y)
+//    return;
+//
+//  // load the image
+//  vec4 color = imageLoad (targetImage, ivec2 (gl_GlobalInvocationID));
+//  
+//  // get the average
+//  float average = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
+//
+//  // store result into result image
+//  imageStore(targetImage, ivec2(gl_GlobalInvocationID), vec4(average, average, average, 1.0f));
+//
+//}
+//
+//
+//
+//
+
+/* Start Header *****************************************************************/
+
+/*! \file (e.g. kirsch.comp)
+
+     \author William Zheng, william.zheng, 60001906. Brandon Mak, brandon.hao 390003920.
+
+     \par william.zheng\@digipen.edu. brandon.hao\@digipen.edu.
+
+     \date Sept 20, 2022
+
+     \brief Copyright (C) 20xx DigiPen Institute of Technology.
+
+  Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. */
+
+  /* End Header *******************************************************************/
+
+#version 450
+
+
+layout(local_size_x = 16, local_size_y = 16) in;
+layout(set = 4, binding = 0, rgba8) uniform image2D inputImage;
+layout(set = 4, binding = 1, rgba8) uniform image2D targetImage;
+
+
+void main()
+{
+  // convenient variables
+  ivec2 globalThread = ivec2(gl_GlobalInvocationID);
+
+  vec3 color = imageLoad (inputImage, globalThread).rgb;
+
+  // store result into result image
+  imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1.0f));
+
+}
+
+
+
+
diff --git a/TempShaderFolder/PureCopyCs.spv b/TempShaderFolder/PureCopyCs.spv
new file mode 100644
index 00000000..bf967bbf
Binary files /dev/null and b/TempShaderFolder/PureCopyCs.spv differ
diff --git a/TempShaderFolder/TestCubeFs.glsl b/TempShaderFolder/TestCubeFs.glsl
index 18890c92..4dc6deca 100644
--- a/TempShaderFolder/TestCubeFs.glsl
+++ b/TempShaderFolder/TestCubeFs.glsl
@@ -23,6 +23,7 @@ layout(location = 2) flat in struct
 {
   int materialIndex;
   uint eid;
+  uint lightLayerIndex;
 } In2;
 
 //layout (set = 0, binding = )
@@ -35,6 +36,7 @@ layout (set = 3, binding = 0) buffer MaterialProperties     // For materials
 
 layout(location = 0) out vec4 outColor;
 layout(location = 1) out uint outEntityID;
+layout(location = 2) out uint lightLayerIndices;
 
 void main()
 {
@@ -42,5 +44,6 @@ void main()
     MatProp.data[In2.materialIndex].color / MatProp.data[In2.materialIndex].alpha;
 
   outEntityID = In2.eid;
+  lightLayerIndices = In2.lightLayerIndex;
   //outColor = vec4 (1.0f);
 }
\ No newline at end of file
diff --git a/TempShaderFolder/TestCubeFs.spv b/TempShaderFolder/TestCubeFs.spv
index bde62136..9955abe5 100644
Binary files a/TempShaderFolder/TestCubeFs.spv and b/TempShaderFolder/TestCubeFs.spv differ
diff --git a/TempShaderFolder/TestCubeVs.glsl b/TempShaderFolder/TestCubeVs.glsl
index b7453f13..7b58d1cf 100644
--- a/TempShaderFolder/TestCubeVs.glsl
+++ b/TempShaderFolder/TestCubeVs.glsl
@@ -3,12 +3,13 @@
 
 //#include "ShaderDescriptorDefinitions.glsl"
 
+
 layout(location = 0) in vec3 aVertexPos;
 layout(location = 1) in vec2 aUV;
 layout(location = 2) in vec3 aNormal;
 layout(location = 3) in vec3 aTangent;
 layout(location = 4) in mat4 worldTransform;
-layout(location = 8) in uint eid;
+layout(location = 8) in uvec2 integerData;
 
 
 layout(location = 0) out struct
@@ -23,6 +24,7 @@ layout(location = 2) out struct
 {
   int materialIndex;
   uint eid;
+  uint lightLayerIndex;
 
 } Out2;
 
@@ -36,7 +38,8 @@ void main()
 {
   Out.uv = aUV;
   Out2.materialIndex = gl_InstanceIndex;
-  Out2.eid = eid;
+  Out2.eid             = integerData[0];
+  Out2.lightLayerIndex = integerData[1];
   gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f);
   Out.vertColor = vec4 (aVertexPos, 1.0f);
 }
\ No newline at end of file
diff --git a/TempShaderFolder/TestCubeVs.spv b/TempShaderFolder/TestCubeVs.spv
index 1662cfbd..731e31d1 100644
Binary files a/TempShaderFolder/TestCubeVs.spv and b/TempShaderFolder/TestCubeVs.spv differ
