diff --git a/Content/Blueprints/OptiXGameModeBP.uasset b/Content/Blueprints/OptiXGameModeBP.uasset
index 5b2607d3c2cf263216f7083f7fc3d4debb774767..ae951950033d707f02c46f2a914cae35f2dc85ba 100644
--- a/Content/Blueprints/OptiXGameModeBP.uasset
+++ b/Content/Blueprints/OptiXGameModeBP.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:ae3a6693695606c4750608c02d5610adeb531c5de788922f1b9efbf5896e6bfd
-size 284450
+oid sha256:9f53ec7062b4c1c64aa484d74e9e3f117a4ae3238c0f9758545c07b2175e167a
+size 286143
diff --git a/Content/Blueprints/OptiXObjects/OptiXLaserActor_Pickup.uasset b/Content/Blueprints/OptiXObjects/OptiXLaserActor_Pickup.uasset
index b8682497aa92a4d08e4d3681b93e1d3038e01c10..60040279be5f144fbde08103eab48d65529094f0 100644
--- a/Content/Blueprints/OptiXObjects/OptiXLaserActor_Pickup.uasset
+++ b/Content/Blueprints/OptiXObjects/OptiXLaserActor_Pickup.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:2e5c573683c34572214d3f50929d99053c950427858f034544591387ecfdad38
-size 277851
+oid sha256:0cb79a5479920528bdef26390ef36c7b3981920bf19f3f5a57d95608201b1343
+size 267740
diff --git a/Content/Blueprints/OptiXObjects/OptiXLaserDetectorActor_Pickup.uasset b/Content/Blueprints/OptiXObjects/OptiXLaserDetectorActor_Pickup.uasset
index 93d53e9dbad4a1593cf6754aea562ffbe39b4af0..1bceaceabd56a40276a959fbe8a23d676c9a3f49 100644
--- a/Content/Blueprints/OptiXObjects/OptiXLaserDetectorActor_Pickup.uasset
+++ b/Content/Blueprints/OptiXObjects/OptiXLaserDetectorActor_Pickup.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:c59b34012e3a1dd3761684c856a18641655ee32dfa5a445913d76ed2fe65df58
-size 282589
+oid sha256:04c47a3ae555daf30650c1c34281f16197d666a2eee45fa990c5cb950ada5743
+size 272239
diff --git a/Content/Blueprints/OptiXObjects/SelectableLensBP.uasset b/Content/Blueprints/OptiXObjects/SelectableLensBP.uasset
index 02caa8f4659fd3d1ec8f806e22e3e87400764d39..a2b053bb275f5423ca218758f47313ea8e7cc420 100644
--- a/Content/Blueprints/OptiXObjects/SelectableLensBP.uasset
+++ b/Content/Blueprints/OptiXObjects/SelectableLensBP.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:9d615e4f0af20def976383139e06e3a697a237c206a1e901e5750ac1d43ffb07
-size 260850
+oid sha256:67b2dba85b56f6c2b3a9ea44dd8d1296ef33b70b7b55d91e6ed0f2d44794a45a
+size 238706
diff --git a/Content/Blueprints/OptiXObjects/SelectableTargetBP.uasset b/Content/Blueprints/OptiXObjects/SelectableTargetBP.uasset
index 65559df6e1af455c69ddf99832a081f3eee7679d..389f44c4ef90cafc1526d73f22da2e18a74266a8 100644
--- a/Content/Blueprints/OptiXObjects/SelectableTargetBP.uasset
+++ b/Content/Blueprints/OptiXObjects/SelectableTargetBP.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:3294b7ed1a325d66a6135185a08b8a449ed54d45f326469103c9868c03183bf7
-size 164473
+oid sha256:ba480d74dc3bd1ca666b506f57377f06f9129a753bfb282d64259e3c3111111a
+size 157315
diff --git a/Content/Blueprints/OptiXObjects/SelectableTargetBP_Black.uasset b/Content/Blueprints/OptiXObjects/SelectableTargetBP_Black.uasset
index 7b4a59e8696922954907b2adcc5f4863ea628391..36ce763da742024d40fdb772df5b67682ae20352 100644
--- a/Content/Blueprints/OptiXObjects/SelectableTargetBP_Black.uasset
+++ b/Content/Blueprints/OptiXObjects/SelectableTargetBP_Black.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:f69cd4fd92ba530eeb4937c3b633ab2f8566c886bb197222411e9866bc6cfe25
-size 165259
+oid sha256:8f31717d1bfcf667b68ced0ecf2f4d34694d514f39e94172dabe4f167b54e276
+size 157122
diff --git a/Content/Blueprints/OptiXObjects/SelectableTargetBP_Circles.uasset b/Content/Blueprints/OptiXObjects/SelectableTargetBP_Circles.uasset
index 67f06c488f638eb2ae66e31b25960f1c1bfc0fb3..fca098ad46c892bf30991319957bbccea533902f 100644
--- a/Content/Blueprints/OptiXObjects/SelectableTargetBP_Circles.uasset
+++ b/Content/Blueprints/OptiXObjects/SelectableTargetBP_Circles.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:43de3a0a069b9de7a6248e89fe02db564eb127c0bbd827d0115333fa59719b14
-size 165285
+oid sha256:74b6519ba9e2883c51c072ce8062e99b6c1bf01263455712435a14b395b469c4
+size 157148
diff --git a/Content/Blueprints/OptiXObjects/SelectableTargetPB_Grid.uasset b/Content/Blueprints/OptiXObjects/SelectableTargetPB_Grid.uasset
index c6aa97f88bacb3eebfaeae5ad5937ff3c144d258..edd433d75493631508d4eaa396ea21a267f16b20 100644
--- a/Content/Blueprints/OptiXObjects/SelectableTargetPB_Grid.uasset
+++ b/Content/Blueprints/OptiXObjects/SelectableTargetPB_Grid.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:90e3243a3688c74a2603865a9c8c97e9b26b817181231897f31c0891a06fefaa
-size 165246
+oid sha256:6ddca510fd1b6b4bca7a153b988090b41d6b8b6e9bfcebbb4c5f5a32b065a016
+size 157109
diff --git a/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset b/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset
index 197055dc288ae653bb9f22f3486f97f8b17c1a2b..c19e5de3f03a431ee9e8d2273421f529d42f0540 100644
--- a/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset
+++ b/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:6fb77af3c598968e9e7466579f14f1a56d797fa9e0130eb1244c4aa534c20f6a
-size 2595921
+oid sha256:db3a337bded9434179bdc7097c53660097a92e095c9a04e2f425bef61997139d
+size 2241302
diff --git a/Content/Blueprints/OpticalTable.uasset b/Content/Blueprints/OpticalTable.uasset
index d8a21f13d53c671ee03f824c50f2e0f97d171c4c..ccd738a0caedf7f8bc7d98d2746e965e3489e202 100644
--- a/Content/Blueprints/OpticalTable.uasset
+++ b/Content/Blueprints/OpticalTable.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:cdcb689ef29696dc5c62dff2670d80bebaeacbeb5d7342ed8e40f2241f9fc3a8
-size 607293
+oid sha256:e0bcfbbaa872e63cfba3ed9f5e964bd3979a6fcead5b556ef8c346979c54a610
+size 582932
diff --git a/Content/Blueprints/Screen_Blueprint.uasset b/Content/Blueprints/Screen_Blueprint.uasset
index 951404297dae59ecd673f4055293ab19bd430517..2191c9b1747f253d1e895e7de53b6a39b95c9132 100644
--- a/Content/Blueprints/Screen_Blueprint.uasset
+++ b/Content/Blueprints/Screen_Blueprint.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:04939607cd3d464216f0377eb424fd24c49988d5fa856eb37750189803d212c1
-size 209199
+oid sha256:c29f56e424b9a133a1e7749b38bcf42d539eab3043d0566ff87096ec3f7fd467
+size 198522
diff --git a/Content/Blueprints/ScreenshotRT.uasset b/Content/Blueprints/ScreenshotRT.uasset
deleted file mode 100644
index 485d1f6f7928f3440b445f5129ab87d316d54d49..0000000000000000000000000000000000000000
--- a/Content/Blueprints/ScreenshotRT.uasset
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:3a6fc60f0f4ab6358de9e15056bf38c67ef517dd7e665e4c7b056fa6b50391bf
-size 90624
diff --git a/Content/Blueprints/SelectableActorBP.uasset b/Content/Blueprints/SelectableActorBP.uasset
index a5c278183abe4457313683aa049402ec6564ed39..61c80f0eb0f6ffcdcb6916c2bded3a75638ebf4f 100644
--- a/Content/Blueprints/SelectableActorBP.uasset
+++ b/Content/Blueprints/SelectableActorBP.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:6957c840c1b7c62dd735531127df344c58ca635fef7e7266a738dabe6a689af9
-size 279646
+oid sha256:91542d558a852b8d4f77624d3e4e7e6fcd3e80c1e011f01e62406ac9ca6bb636
+size 268583
diff --git a/Content/Blueprints/TabletBP.uasset b/Content/Blueprints/TabletBP.uasset
index ecfceadafcf5d06e94fc168ed5c79c2135b9017e..baa2315ae9e09dd456d1186af31f0c7f48f0628b 100644
--- a/Content/Blueprints/TabletBP.uasset
+++ b/Content/Blueprints/TabletBP.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:e9182e76dbf011dd6cf42354b144d5f52be897be52e7e2eaade310e8951d8449
-size 281450
+oid sha256:9d6f8674506e5e493aaac14bc470fe748fa45275db0c8628a9071aabbec90494
+size 274908
diff --git a/Content/Blueprints/TeleportController2.uasset b/Content/Blueprints/TeleportController2.uasset
deleted file mode 100644
index 5ef1f777d8c93c90d2d7de094d129d53a679aa16..0000000000000000000000000000000000000000
--- a/Content/Blueprints/TeleportController2.uasset
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:5f45c590b37dfe655015226d52703388c50f79c1287dfa6f406ed6f4a7771ad3
-size 698528
diff --git a/Content/Blueprints/TeleportControllerBP.uasset b/Content/Blueprints/TeleportControllerBP.uasset
index d0818fdab4a48c872ee8777a72b1f1652a79c750..e119a30f87c965d7b34aa57aef794eaf912950ce 100644
--- a/Content/Blueprints/TeleportControllerBP.uasset
+++ b/Content/Blueprints/TeleportControllerBP.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:1ff820bfe73dfd81c45f3607108f09ee9adde68ab6c267533234ddfeb9b2cbb3
-size 699993
+oid sha256:bdffda756733eecfad9daae14fccd2e23818faeeff218b512bda33cea3309f6d
+size 676709
diff --git a/Content/Laser/LaserMaterial.uasset b/Content/Laser/LaserMaterial.uasset
index 6f30adb84a0b0596447d564d83ace62f0d187ba5..674be9c77b85cc7e1c1c5ea550e7b667e03b375b 100644
--- a/Content/Laser/LaserMaterial.uasset
+++ b/Content/Laser/LaserMaterial.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:3690422396ea2f235d47749a41b8f321de240382ef31671a3ea59b4a456561aa
-size 134743
+oid sha256:5f8291e956bd381752dbacb1f17995c0daae8d2501a667a3e0c0525acd099f90
+size 121423
diff --git a/Content/PPMaterials/Outlines.uasset b/Content/PPMaterials/Outlines.uasset
deleted file mode 100644
index ff3dccb9b6de5b0c6e11549696606be9713ba74d..0000000000000000000000000000000000000000
--- a/Content/PPMaterials/Outlines.uasset
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e7338d5ba376923a738d63f0cbb8f09c93952fb0235260a9199f20c051b0ee2b
-size 97891
diff --git a/Content/PPMaterials/TextureMaterial.uasset b/Content/PPMaterials/TextureMaterial.uasset
index 443a852e393f664b7a15858d94b9b241f68da64f..dc2f0af7829970270697b72d9b68104ad499cff3 100644
--- a/Content/PPMaterials/TextureMaterial.uasset
+++ b/Content/PPMaterials/TextureMaterial.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:546447517431902c9d64751e3e2453b385efbce438b7e21a131985e6159aff1b
-size 127227
+oid sha256:6247837071e758dad320c29053bc100459671654e769795c28d8f76384e9ded4
+size 113386
diff --git a/Content/PPMaterials/TextureMaterialVR.uasset b/Content/PPMaterials/TextureMaterialVR.uasset
index a75bed9cc41a1897a13993e0e0f9be8d41ed8b85..f2ef945e2527ca0677665b7201806d296cd8a31c 100644
--- a/Content/PPMaterials/TextureMaterialVR.uasset
+++ b/Content/PPMaterials/TextureMaterialVR.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:5d15297b401143eea24e05aa81e2a44d31fc96c1114c862ceb322f35099f9d02
-size 82554
+oid sha256:401b46b313926758f7e3d5ba8c5e31344fea702882b90b68570d70578ad488db
+size 96970
diff --git a/Content/Targets/LUT_Test.uasset b/Content/Targets/LUT_Test.uasset
deleted file mode 100644
index bd403b604c79a7d0580433929ad21a2f85c8ab40..0000000000000000000000000000000000000000
--- a/Content/Targets/LUT_Test.uasset
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:b5905d734ac5b83a186c2d95b5e1962f8b0161fc3ec5b194b7d63673a73acced
-size 4489
diff --git a/Content/Targets/Screen.uasset b/Content/Targets/Screen.uasset
index 39495c1bfa99a84eff2ac721091db745a0820696..92c0358c94bd2e271badcc91dda64ab32865290f 100644
--- a/Content/Targets/Screen.uasset
+++ b/Content/Targets/Screen.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:0e95a7dc5ce351652233820b4145b4e1a37ffe9f04f08e845f70a211165d37f5
-size 107272
+oid sha256:1c413dc63020b665db3b1dd891ea29c1990baa8552fc5f33100d1774fa2cf4d1
+size 114263
diff --git a/Content/Targets/Target_LUT.uasset b/Content/Targets/Target_LUT.uasset
index 49f747040d235cc9a39581cc6b092999c0d577c1..025b386ebc597cddfff716629f3b2fc186904501 100644
--- a/Content/Targets/Target_LUT.uasset
+++ b/Content/Targets/Target_LUT.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:9b40a02b730ea48ffc548aa653bd306ac975f93d1dc847685ea14b237c5899d6
-size 4363
+oid sha256:903193146cad1ec26a877029cba6de7ddc44b56ffe1f05e2b6d4e58926c84b6b
+size 4145
diff --git a/Content/UI/PointerMaterial.uasset b/Content/UI/PointerMaterial.uasset
index a48fec053e26b2517f32749648cc6e0d4ff1109d..253eb55ed3f0a7589f40391ef010a1aec975cc47 100644
--- a/Content/UI/PointerMaterial.uasset
+++ b/Content/UI/PointerMaterial.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:416d9eaa23e2e202f2aeeb4083f4b821aeb1421349b1dcfba4f809b65c828bbc
-size 103741
+oid sha256:8d87e21005fbf50445a5461aec28b301b69d308eac36f3a72a677e4cc82686cf
+size 95820
diff --git a/Content/UI/Tablet/DetectorWidget.uasset b/Content/UI/Tablet/DetectorWidget.uasset
deleted file mode 100644
index 51d7fd6218be5ec7d04f433f283cda1cee8e0a0e..0000000000000000000000000000000000000000
--- a/Content/UI/Tablet/DetectorWidget.uasset
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6e0c740d38f04b4d6091fe82b3f1bbdec594c0cecf3f1983a0390dfdbe42c918
-size 116188
diff --git a/Content/UI/Tablet/LaserMenuWidget.uasset b/Content/UI/Tablet/LaserMenuWidget.uasset
index 29c53c7decb8783de0a6b5b55d314016f12b6e5c..623b3867d4d3b6806f5c5caa36efa90bfc592b9f 100644
--- a/Content/UI/Tablet/LaserMenuWidget.uasset
+++ b/Content/UI/Tablet/LaserMenuWidget.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:8c04127519ea1a955ba9a3e312ac850dbc0fdc6681e5aa99680fa05be719633c
-size 541613
+oid sha256:13e6848bb82dda17b7e6c9187f7460f33d478004f96b7257f53d7d1f4f8fcc82
+size 496804
diff --git a/Content/UI/Tablet/LensMenuWidget.uasset b/Content/UI/Tablet/LensMenuWidget.uasset
index ab79e786fbf7b95812814803b3507951ebcdecc1..4cd966dce6e0e73b28767c61149da75fefc365f7 100644
--- a/Content/UI/Tablet/LensMenuWidget.uasset
+++ b/Content/UI/Tablet/LensMenuWidget.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:2811796a539e8c5832d6dfd9497c7c9a35be06daac026c1f0b8be00ee63ec7d8
-size 836578
+oid sha256:8bf4f21307f50b4e094a1bf7dec53e03bdb8695456fa59dce330c4be288afd7b
+size 719903
diff --git a/Content/UI/Tablet/ScreenTexture.uasset b/Content/UI/Tablet/ScreenTexture.uasset
deleted file mode 100644
index dbd5425c9e631eff55bcf8b13df15aad7c9176e5..0000000000000000000000000000000000000000
--- a/Content/UI/Tablet/ScreenTexture.uasset
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:dbb3badfb77bbd48b32c459e650fb572e90c712a0fc5fbb0a20561ad5782076f
-size 4083
diff --git a/Content/UI/Tablet/ScreenWidgetTabs.uasset b/Content/UI/Tablet/ScreenWidgetTabs.uasset
index 3514e003abdd751c531d0923c44d28a7b3f69f01..9cfe9e96d610b3f622f0d45b6689031e248bb177 100644
--- a/Content/UI/Tablet/ScreenWidgetTabs.uasset
+++ b/Content/UI/Tablet/ScreenWidgetTabs.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:4f10c35799d6879a759678db99d3cb4b67a1245faa5e3862cb3a116012dfa319
-size 283317
+oid sha256:b8c8eef6e32db44869e7599ff96965d8ad36477867b824e46188c5bf4108a2ee
+size 255078
diff --git a/Content/UI/Tablet/tablet.uasset b/Content/UI/Tablet/tablet.uasset
index 73f67f8baa4dbcab1dc389e82e94566cd0d48b9f..aec5e8b89345968d9b686570e03f1ed3dea7b205 100644
--- a/Content/UI/Tablet/tablet.uasset
+++ b/Content/UI/Tablet/tablet.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:a19904db28ed46f9ac31aceef131473a0585b1f1d16997b1358c254401dc1461
-size 116147
+oid sha256:20ce7a66ebaba8bb5366e88b1e748998ef5549c31da3077d5895854936fec7e4
+size 183027
diff --git a/Content/UI/UIScreenMaterial.uasset b/Content/UI/UIScreenMaterial.uasset
deleted file mode 100644
index 7d217675a792cd7f77fa2a71f5f0c0ca5952c7b0..0000000000000000000000000000000000000000
--- a/Content/UI/UIScreenMaterial.uasset
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:dcc1a97724f2d36688ade54bfe7eac79171af55103b17c9af6774d5e325d4612
-size 13770
diff --git a/OptiX.uplugin b/OptiX.uplugin
index 7cc74c525ffb9234b15ffe8fb09e2e202836d072..98eb11e3ed7c8108ecc6fe27b7bb0285db847ceb 100644
--- a/OptiX.uplugin
+++ b/OptiX.uplugin
@@ -20,6 +20,17 @@
       "Name": "OptiX",
       "Type": "Runtime",
       "LoadingPhase": "Default"
+    },
+    {
+      "Name": "OptiXEditor",
+      "Type": "Editor",
+      "LoadingPhase": "PostEngineInit"
     }
-  ]
+  ],
+  "PostBuildSteps": 
+  {
+    "Win64": [
+      "FOR %%I in ($(PluginDir)\\Source\\OptiX\\Private\\cuda\\*.cu) DO nvcc -odir $(ProjectDir)\\Content\\ptx\\generated -ccbin \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\VC\\Tools\\MSVC\\14.16.27023\\bin\\Hostx64\\x64\" -ptx %%I -I$(PluginDir)\\Source\\ThirdParty\\OptiXLibrary\\include -use_fast_math"
+    ]
+  }
 }
\ No newline at end of file
diff --git a/Source/OptiX/OptiX.Build.cs b/Source/OptiX/OptiX.Build.cs
index 6de3f36b6ec6ab46fcf5699b4fd3a504eeb96b9d..2769424749469ba63b9229ee616d7536ebe7d9b5 100644
--- a/Source/OptiX/OptiX.Build.cs
+++ b/Source/OptiX/OptiX.Build.cs
@@ -14,7 +14,7 @@ public class OptiX : ModuleRules
         string EnginePath = Path.GetFullPath(Target.RelativeEnginePath);
         string ModulePath = ModuleDirectory;
 
-        PublicDefinitions.Add("MALLOC_LEAKDETECTION=0");
+        Definitions.Add("MALLOC_LEAKDETECTION=0");
 
 
         PublicIncludePaths.AddRange(
@@ -47,11 +47,6 @@ public class OptiX : ModuleRules
                 "UMG",
                 "Slate",
                 "SlateCore",
-                "D3D11RHI",
-                "UtilityShaders",
-                "Analytics",
-                "EngineSettings"
-
             }
             );
         PrivateDependencyModuleNames.AddRange(
@@ -67,11 +62,7 @@ public class OptiX : ModuleRules
                 "Json",
                 "JsonUtilities",
                 "RenderCore",
-                "RHI",
-                "D3D11RHI",
-                "UtilityShaders",
-                "Analytics",
-                "EngineSettings"
+                "RHI"
             }
             );
 
diff --git a/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp b/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp
index c37398ba938365e27240162b3346cbcd19e9dfb6..76182e18793a9c6f793af47421cb076b5d7c798d 100644
--- a/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp
+++ b/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp
@@ -1,5 +1,6 @@
 // Fill out your copyright notice in the Description page of Project Settings.
 
+
 #include "LineInstancedStaticMeshComponent.h"
 
 #include "Components/InstancedStaticMeshComponent.h"
@@ -13,9 +14,6 @@
 #include "OptiXModule.h"
 #include "OptiXContextManager.h"
 
-#include "StatsDefines.h"
-
-
 
 ULineInstancedStaticMeshComponent::ULineInstancedStaticMeshComponent(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -47,7 +45,6 @@ void ULineInstancedStaticMeshComponent::BeginPlay()
 
 FPrimitiveSceneProxy* ULineInstancedStaticMeshComponent::CreateSceneProxy()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ULineInstancedStaticMeshComponent::CreateSceneProxy"))
 
 
 	FPrimitiveSceneProxy* Proxy = Super::CreateSceneProxy();
@@ -85,7 +82,6 @@ FPrimitiveSceneProxy* ULineInstancedStaticMeshComponent::CreateSceneProxy()
 // todo currently copies the array, save a reference/ptr instead
 void ULineInstancedStaticMeshComponent::InitLineSegments(TArray<int32> Indices, int32 NumberOfSegmentsPerLine, float LineW)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ULineInstancedStaticMeshComponent::InitLineSegments"))
 
 	ClearInstances();
 	
@@ -142,7 +138,7 @@ void ULineInstancedStaticMeshComponent::InitLineSegments(TArray<int32> Indices,
 
 		IndexMap = UTexture2D::CreateTransient(1, LineNumber, EPixelFormat::PF_R32_FLOAT);
 		IndexMap->UpdateResource();
-		UE_LOG(LogTemp, Display, TEXT("IndexMap | LineNumber (%i | %i )"), IndexMap->GetSizeX(), LineNumber);
+		UE_LOG(LogTemp, Display, TEXT("IndexMap | LineNumber (%i | %i "), IndexMap->GetSizeX(), LineNumber);
 		IndexMap->UpdateTextureRegions(0, 1, TextureRegion.Get(), sizeof(float), sizeof(float), (uint8*)LaserIndicesFloat.GetData());
 		DynamicLaserMaterial->SetTextureParameterValue("IndexMap", IndexMap);
 
@@ -153,8 +149,6 @@ void ULineInstancedStaticMeshComponent::InitLineSegments(TArray<int32> Indices,
 
 void ULineInstancedStaticMeshComponent::UpdateLines()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ULineInstancedStaticMeshComponent::UpdateLines"))
-
 	LineNumber = LaserIndices.Num();
 
 	for (int32 Line = 0; Line < LineNumber; Line++)
@@ -181,8 +175,6 @@ void ULineInstancedStaticMeshComponent::UpdateLines()
 
 void  ULineInstancedStaticMeshComponent::UpdateLUT(TArray<FColor> ColorMap)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ULineInstancedStaticMeshComponent::UpdateLUT"))
-
 	if (DynamicLaserMaterial != NULL)
 	{
 
@@ -205,8 +197,6 @@ void  ULineInstancedStaticMeshComponent::UpdateLUT(TArray<FColor> ColorMap)
 
 void ULineInstancedStaticMeshComponent::SetLaserMaterial(UMaterialInstanceDynamic * Mat)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ULineInstancedStaticMeshComponent::SetLaserMaterial"))
-
 	// 1 for now, could be #Lines if we want multicolored lines
 	ColorLUT = UTexture2D::CreateTransient(1, LineNumber, EPixelFormat::PF_R32_FLOAT);
 	ColorLUT->UpdateResource();
diff --git a/Source/OptiX/Private/OptiXAcceleration.cpp b/Source/OptiX/Private/OptiXAcceleration.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb6f815ff2fff2724682b3a2ae6950e4ae85b320
--- /dev/null
+++ b/Source/OptiX/Private/OptiXAcceleration.cpp
@@ -0,0 +1,218 @@
+#include "OptiXAcceleration.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+#include "OptiXModule.h"
+
+DEFINE_LOG_CATEGORY(OptiXPluginAcceleration);
+
+void UOptiXAcceleration::BeginDestroy()
+{
+	Super::BeginDestroy();
+	DestroyOptiXObject();
+}
+
+void UOptiXAcceleration::DestroyOptiXObject()
+{
+	if (NativeAcceleration != NULL)
+	{
+		//NativeAcceleration->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->AccelerationsToDeleteQueue.Enqueue(NativeAcceleration);
+	}
+	NativeAcceleration = NULL;
+}
+
+void UOptiXAcceleration::Validate()
+{
+	try
+	{
+		NativeAcceleration->validate();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXAcceleration::MarkDirty()
+{
+	try
+	{
+		NativeAcceleration->markDirty();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+bool UOptiXAcceleration::IsDirty()
+{
+	bool B = false;
+	try
+	{
+		B = NativeAcceleration->isDirty();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return B;
+}
+
+void UOptiXAcceleration::SetProperty(FString Name, FString Value)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		std::string V = std::string(TCHAR_TO_ANSI(*Value));
+
+		NativeAcceleration->setProperty(N, V);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FString UOptiXAcceleration::GetProperty(FString Name)
+{
+	FString Property;
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		std::string V = NativeAcceleration->getProperty(N);
+		Property = FString(V.c_str());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Property;
+}
+
+void UOptiXAcceleration::SetBuilder(FString Builder)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Builder));
+
+		NativeAcceleration->setBuilder(N);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FString UOptiXAcceleration::GetBuilder()
+{
+	FString Property;
+	try
+	{
+		std::string V = NativeAcceleration->getBuilder();
+		Property = FString(V.c_str());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Property;
+}
+
+void UOptiXAcceleration::SetTraverser(FString Traverser)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Traverser));
+
+		NativeAcceleration->setTraverser(N);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FString UOptiXAcceleration::GetTraverser()
+{
+	FString Property;
+	try
+	{
+		std::string V = NativeAcceleration->getTraverser();
+		Property = FString(V.c_str());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Property;
+}
+
+RTsize UOptiXAcceleration::GetDataSize()
+{
+	RTsize Size = 0;
+	try
+	{
+		Size = NativeAcceleration->getDataSize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Size;
+}
+
+void UOptiXAcceleration::GetData(void * Data)
+{
+	try
+	{
+		NativeAcceleration->getData(Data);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXAcceleration::SetData(void * Data, RTsize Size)
+{
+	try
+	{
+		NativeAcceleration->setData(Data, Size);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
diff --git a/Source/OptiX/Private/OptiXBuffer.cpp b/Source/OptiX/Private/OptiXBuffer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..524ae72f911f3b81bc799a9a71553a3186ff3889
--- /dev/null
+++ b/Source/OptiX/Private/OptiXBuffer.cpp
@@ -0,0 +1,700 @@
+#include "OptiXBuffer.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+//#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+#include "OptiXModule.h"
+
+DEFINE_LOG_CATEGORY(OptiXPluginBuffer);
+
+void UOptiXBuffer::BeginDestroy()
+{
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Buffer BeginDestroy"));
+	DestroyOptiXObject();
+	Super::BeginDestroy();
+}
+
+void UOptiXBuffer::DestroyOptiXObject()
+{
+	if (NativeBuffer != NULL)
+	{
+		UE_LOG(LogTemp, Display, TEXT("Buffer Name: %s!"), *Name);
+		try
+		{
+			//NativeBuffer->destroy();
+			FOptiXModule::Get().GetOptiXContextManager()->BuffersToDeleteQueue.Enqueue(NativeBuffer);
+		}
+		catch (optix::Exception& E)
+		{
+			FString Message = FString(E.getErrorString().c_str());
+			UE_LOG(OptiXPluginBuffer, Fatal, TEXT("OptiX Error: %s"), *Message);
+			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		}
+	}
+
+	NativeBuffer = NULL;
+}
+
+void UOptiXBuffer::Validate()
+{
+	try
+	{
+		NativeBuffer->validate();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetFormat(RTformat Format)
+{
+	try
+	{
+		NativeBuffer->setFormat(Format);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTformat UOptiXBuffer::GetFormat()
+{
+	return NativeBuffer->getFormat();
+}
+
+void UOptiXBuffer::SetElementSize(int32 Size)
+{
+	try
+	{
+		NativeBuffer->setElementSize(Size);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetElementSizeNative(RTsize Size)
+{
+	try
+	{
+		NativeBuffer->setElementSize(Size);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+
+RTsize UOptiXBuffer::GetElementSizeNative()
+{
+	RTsize S = 0;
+	try
+	{
+		S = NativeBuffer->getElementSize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return S;
+}
+
+int32 UOptiXBuffer::GetElementSize()
+{
+	int32 S = 0;
+	try
+	{
+		S = NativeBuffer->getElementSize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return S;
+}
+
+void UOptiXBuffer::MarkDirty()
+{
+	try
+	{
+		NativeBuffer->markDirty();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetSize1D(int32 Width)
+{
+	try
+	{
+		NativeBuffer->setSize(Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetSize1DNative(RTsize Width)
+{
+	try
+	{
+		NativeBuffer->setSize(Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTsize UOptiXBuffer::GetSize1DNative()
+{
+	RTsize Width;
+	try
+	{
+		NativeBuffer->getSize(Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Width;
+}
+
+int32 UOptiXBuffer::GetSize1D()
+{
+	RTsize Width;
+	try
+	{
+		NativeBuffer->getSize(Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return static_cast<int32>(Width);
+}
+
+RTsize UOptiXBuffer::GetMipLevelSize1DNative(uint8 Level)
+{
+	RTsize Width;
+	try
+	{
+		NativeBuffer->getMipLevelSize(Level, Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Width;
+}
+
+int32 UOptiXBuffer::GetMipLevelSize1D(uint8 Level)
+{
+	RTsize Width;
+	try
+	{
+		NativeBuffer->getMipLevelSize(Level, Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return static_cast<int32>(Width);
+}
+
+void UOptiXBuffer::SetSize2D(int32 Width, int32 Height)
+{
+	try
+	{
+		NativeBuffer->setSize(Width, Height);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetSize2DNative(RTsize Width, RTsize Height)
+{
+	try
+	{
+		NativeBuffer->setSize(Width, Height);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTsize2 UOptiXBuffer::GetSize2DNative()
+{
+	RTsize2 S;
+	RTsize A;
+	RTsize B;
+	NativeBuffer->getSize(A, B);
+	S.X = A;
+	S.Y = B;
+	return S;
+}
+
+FIntPoint UOptiXBuffer::GetSize2D()
+{
+	FIntPoint S;
+	RTsize A;
+	RTsize B;
+	try
+	{
+		NativeBuffer->getSize(A, B);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;
+	return S;
+}
+
+FIntPoint UOptiXBuffer::GetMipLevelSize2D(uint8 Level)
+{
+	FIntPoint S;
+	RTsize A = 0;
+	RTsize B = 0;
+	try
+	{
+		NativeBuffer->getMipLevelSize(A, B);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}	
+	S.X = A;
+	S.Y = B;
+	return S;
+}
+
+RTsize2 UOptiXBuffer::GetMipLevelSize2DNative(uint8 Level)
+{
+	RTsize2 S;
+	RTsize A = 0;
+	RTsize B = 0;
+	try
+	{
+		NativeBuffer->getMipLevelSize(A, B);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}	
+	S.X = A;
+	S.Y = B;
+	return S;
+}
+
+void UOptiXBuffer::SetSize3DNative(RTsize Width, RTsize Height, RTsize Depth)
+{
+	try
+	{
+		NativeBuffer->setSize(Width, Height, Depth);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetSize3D(int32 Width, int32 Height, int32 Depth)
+{
+	try
+	{
+		NativeBuffer->setSize(Width, Height, Depth);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FIntVector UOptiXBuffer::GetSize3D()
+{
+	FIntVector S;
+	RTsize A;
+	RTsize B;
+	RTsize C;
+	try
+	{
+		NativeBuffer->getSize(A, B, C);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;	
+	S.Z = C;
+	return S;
+}
+
+
+RTsize3 UOptiXBuffer::GetSize3DNative()
+{
+	RTsize3 S;
+	RTsize A;
+	RTsize B;
+	RTsize C;
+	try
+	{
+		NativeBuffer->getSize(A, B, C);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;
+	S.Z = C;
+	return S;
+}
+
+FIntVector UOptiXBuffer::GetMipLevelSize3D(uint8 Level)
+{
+	FIntVector S;
+	RTsize A = 0;
+	RTsize B = 0;
+	RTsize C = 0;
+	try
+	{
+		NativeBuffer->getMipLevelSize(A, B, C);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;
+	S.Z = C;
+	return S;
+}
+
+RTsize3 UOptiXBuffer::GetMipLevelSize3DNative(uint8 Level)
+{
+	RTsize3 S;
+	RTsize A = 0;
+	RTsize B = 0;
+	RTsize C = 0;
+	try
+	{
+		NativeBuffer->getMipLevelSize(A, B, C);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;
+	S.Z = C;
+	return S;
+}
+
+void UOptiXBuffer::SetMipLevelCount(uint8 Count)
+{
+	try
+	{
+		NativeBuffer->setMipLevelCount(Count);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint8 UOptiXBuffer::GetMipLevelCount()
+{
+	uint8 Count = 0;
+	try
+	{
+		Count = NativeBuffer->getMipLevelCount();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Count;
+}
+
+int UOptiXBuffer::GetId()
+{
+	int Id = 0;
+	try
+	{
+		Id = NativeBuffer->getId();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Id;
+}
+
+void UOptiXBuffer::Map(uint8 Level, uint8 MapFlags)
+{
+	try
+	{
+		NativeBuffer->map(Level, MapFlags);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+
+void * UOptiXBuffer::MapNative(uint8 Level, uint8 MapFlags, void * UserOwned)
+{
+	void * Ptr = nullptr;
+	try
+	{
+		Ptr = NativeBuffer->map(Level, MapFlags, UserOwned);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ptr;
+}
+
+void UOptiXBuffer::Unmap(uint8 Level)
+{
+	try
+	{
+		NativeBuffer->unmap(Level);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+// TODO: Wrap those a bit better
+
+void UOptiXBuffer::BindProgressiveStream(UOptiXBuffer * Source)
+{
+	try
+	{
+		NativeBuffer->bindProgressiveStream(Source->GetNativeBuffer());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::GetProgressiveUpdateReady(int * Ready, unsigned int * SubframeCount, unsigned int * MaxSubframes)
+{
+	try
+	{
+		NativeBuffer->getProgressiveUpdateReady(Ready, SubframeCount, MaxSubframes);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+bool UOptiXBuffer::GetProgressiveUpdateReady()
+{
+	bool Ready = false;
+	try
+	{
+		Ready = NativeBuffer->getProgressiveUpdateReady();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ready;
+}
+
+void UOptiXBuffer::GetDevicePointer(int32 OptiXDeviceOrdinal, void ** DevicePointer)
+{
+	try
+	{
+		NativeBuffer->getDevicePointer(OptiXDeviceOrdinal, DevicePointer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void * UOptiXBuffer::GetDevicePointer(int32 OptiXDeviceOrdinal)
+{
+	void* Ptr = nullptr;
+	try
+	{
+		Ptr = NativeBuffer->getDevicePointer(OptiXDeviceOrdinal);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ptr;
+}
+
+void UOptiXBuffer::SetDevicePointer(int32 OptiXDeviceOrdinal, void * DevicePointer)
+{
+	try
+	{
+		NativeBuffer->setDevicePointer(OptiXDeviceOrdinal, DevicePointer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+bool UOptiXBuffer::GetProgressiveUpdateReady(unsigned int & SubframeCount)
+{
+	bool Ready = false;
+	try
+	{
+		Ready = NativeBuffer->getProgressiveUpdateReady(SubframeCount);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ready;
+}
+
+bool UOptiXBuffer::GetProgressiveUpdateReady(unsigned int & SubframeCount, unsigned int & MaxSubframes)
+{
+	bool Ready = false;
+	try
+	{
+		Ready = NativeBuffer->getProgressiveUpdateReady(SubframeCount, MaxSubframes);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ready;
+}
+
+void UOptiXBuffer::SetAttribute(RTbufferattribute Attrib, RTsize Size, void * P)
+{
+	try
+	{
+		NativeBuffer->setAttribute(Attrib, Size, P);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::GetAttribute(RTbufferattribute Attrib, RTsize Size, void * P)
+{
+	try
+	{
+		NativeBuffer->getAttribute(Attrib, Size, P);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
\ No newline at end of file
diff --git a/Source/OptiX/Private/OptiXCameraActor.cpp b/Source/OptiX/Private/OptiXCameraActor.cpp
index 3ff23057e38b63fd560feb6a4e137faf90cd41a2..2a9af01de3f908c477ab47d8f37892e855a58fd5 100644
--- a/Source/OptiX/Private/OptiXCameraActor.cpp
+++ b/Source/OptiX/Private/OptiXCameraActor.cpp
@@ -3,6 +3,7 @@
 #include "OptiXCameraActor.h"
 
 #include "OptiXModule.h"
+#include "OptiXTextureSampler.h"
 #include "OptiXLaserActor.h"
 
 #include "Engine/EngineTypes.h"
@@ -27,8 +28,6 @@
 
 #include "Runtime/Engine/Classes/Camera/CameraActor.h"
 
-#include "StatsDefines.h"
-
 
 DEFINE_LOG_CATEGORY(OptiXPluginCameraActor);
 
@@ -130,8 +129,6 @@ void AOptiXPlayerCameraManager::EndPlay(const EEndPlayReason::Type EndPlayReason
 
 void AOptiXPlayerCameraManager::Tick(float DeltaSeconds)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXPlayerCameraManager::Tick"))
-
 	Super::Tick(DeltaSeconds);
 	if (C == 2)
 	{
@@ -158,7 +155,6 @@ void AOptiXPlayerCameraManager::Init()
 
 void AOptiXPlayerCameraManager::CaptureCubemap()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXPlayerCameraManager::CaptureCubemap"))
 
 	// 2D
 	TArray<FVector> Directions =
diff --git a/Source/OptiX/Private/OptiXContext.cpp b/Source/OptiX/Private/OptiXContext.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..20e2a2eeee7adbfb10284279ff0900fcb537ba45
--- /dev/null
+++ b/Source/OptiX/Private/OptiXContext.cpp
@@ -0,0 +1,1432 @@
+#include "OptiXContext.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginContext);
+
+
+UOptiXContext::UOptiXContext(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+}
+
+optix::Context UOptiXContext::Init()
+{
+	UOptiXGeometryGroup* Group = NewObject<UOptiXGeometryGroup>(this, UOptiXGeometryGroup::StaticClass());
+	try
+	{
+		NativeContext = optix::Context::create();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Fatal, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Context Init"));
+	return NativeContext;
+}
+
+void UOptiXContext::UpdateVariables()
+{
+	check(IsInRenderingThread());
+
+	for (UOptiXTransform* T : TransformMap)
+	{
+		T->UpdateTransform();
+	}
+
+	for (TPair<FString, FVector>& V : VectorCache)
+	{
+		SetFloat3DVector(V.Key, V.Value);
+	}
+	VectorCache.Empty();
+	for (TPair<FString, FMatrix>& M : MatrixCache)
+	{
+		SetMatrix(M.Key, M.Value);
+	}
+	VectorCache.Empty();
+}
+
+void UOptiXContext::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Context BeginDestroy"));
+	
+	Reset();
+
+	if (NativeContext != NULL)
+	{
+		// To make sure the context will be destroyed LAST, after the UObject is gone, the Context Manager needs to make sure 
+		// it actually saves a ptr to the optix::Context and destroys that manually!
+		//NativeContext->destroy();
+
+	}
+	Super::BeginDestroy();
+
+}
+
+/*
+Creator functions. Those functions are used to create the wrapper object and the respective wrapped 
+optix:: object. The UObjects will *not* be saved, so the caller of those functions is responsible
+to keep them from getting eaten by the garbage collection. They can be registered by using the 
+SetObject functions below, which will keep them referenced in the context instance.
+*/
+
+void UOptiXContext::Reset()
+{
+	BufferMap.Empty();
+	MaterialMap.Empty();
+	GeometryMap.Empty();
+	GeometryInstanceMap.Empty();
+	GeometryGroupMap.Empty();
+	GroupMap.Empty();
+	TextureSamplerMap.Empty();
+	RayGenerationPrograms.Empty();
+	ExceptionPrograms.Empty();
+	MissPrograms.Empty();
+	TransformMap.Empty();
+}
+
+UOptiXGeometry* UOptiXContext::CreateGeometry()
+{
+	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
+	UOptiXGeometry* Geometry = NewObject<UOptiXGeometry>(this, UOptiXGeometry::StaticClass());
+	Geometry->SetGeometry(NativeContext->createGeometry());
+	return Geometry;
+}
+
+UOptiXMaterial * UOptiXContext::CreateMaterial()
+{
+	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
+	UOptiXMaterial* Material = NewObject<UOptiXMaterial>(this, UOptiXMaterial::StaticClass());
+	Material->SetMaterial(NativeContext->createMaterial());
+	return Material;
+}
+
+UOptiXGeometryInstance * UOptiXContext::CreateGeometryInstance(UOptiXGeometry* Geometry, TArray<UOptiXMaterial*> Materials)
+{
+	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
+	UOptiXGeometryInstance* Instance = NewObject<UOptiXGeometryInstance>(this, UOptiXGeometryInstance::StaticClass());
+	optix::GeometryInstance NativeInstance = NativeContext->createGeometryInstance();
+	Instance->SetNativeInstance(NativeInstance);
+	Instance->SetGeometry(Geometry);
+	for (UOptiXMaterial* Mat : Materials)
+	{
+		Instance->AddMaterial(Mat);
+	}
+	return Instance;
+}
+
+UOptiXGeometryInstance * UOptiXContext::CreateGeometryInstance(UOptiXGeometry* Geometry, UOptiXMaterial* Material)
+{
+	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
+	UOptiXGeometryInstance* Instance = NewObject<UOptiXGeometryInstance>(this, UOptiXGeometryInstance::StaticClass());
+	optix::GeometryInstance NativeInstance = NativeContext->createGeometryInstance();
+	Instance->SetNativeInstance(NativeInstance);
+	Instance->SetGeometry(Geometry);
+
+	Instance->AddMaterial(Material);
+	return Instance;
+}
+
+UOptiXGeometryGroup * UOptiXContext::CreateGeometryGroup()
+{
+	UOptiXGeometryGroup* Group = NewObject<UOptiXGeometryGroup>(this, UOptiXGeometryGroup::StaticClass());
+	try
+	{
+		Group->SetNativeGroup(NativeContext->createGeometryGroup());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Fatal, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}	
+	return Group;
+}
+
+UOptiXGroup * UOptiXContext::CreateGroup()
+{
+	UOptiXGroup* Group = NewObject<UOptiXGroup>(this, UOptiXGroup::StaticClass());
+	try
+	{
+		Group->SetNativeGroup(NativeContext->createGroup());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Fatal, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Group;
+}
+
+UOptiXTransform * UOptiXContext::CreateTransform()
+{
+	UOptiXTransform* Transform = NewObject<UOptiXTransform>(this, UOptiXTransform::StaticClass());
+	Transform->SetNativeGroup(NativeContext->createTransform());
+	TransformMap.Add(Transform); // TODO Fix me 
+	return Transform;
+}
+
+UOptiXAcceleration * UOptiXContext::CreateAcceleration(FString Builder)
+{
+	std::string B = std::string(TCHAR_TO_ANSI(*Builder));
+
+	UOptiXAcceleration* Accel = NewObject<UOptiXAcceleration>(this, UOptiXAcceleration::StaticClass());
+	Accel->SetNativeAcceleration(NativeContext->createAcceleration(B));
+	return Accel;
+}
+
+/*
+Various setter and getter methods to manipulate the current context and pass variables to the shaders.
+*/
+
+void UOptiXContext::SetFloat(FString string, float Var)
+{
+	try 
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
+	} 
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetFloat2D(FString string, float Var1, float Var2)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+void UOptiXContext::SetFloat3DVector(FString string, FVector Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetFloat3D(FString string, float Var1, float Var2, float Var3)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+void UOptiXContext::SetFloat4DVector(FString string, FVector4 Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetInt(FString string, int32 Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetInt2D(FString string, int32 Var1, int32 Var2)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetInt3DVector(FString string, FIntVector Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+//void UOptiXContext::SetInt4DVector(FString string, FIntVector4 Var)
+//{
+//	NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z, Var.W);
+//
+//}
+
+void UOptiXContext::SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetUint(FString string, uint8 Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetUint2D(FString string, uint8 Var1, uint8 Var2)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetMatrix(FString string, FMatrix Matrix)
+{
+	try
+	{
+		// According to the optix doc false == row major
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setMatrix4x4fv(true, &Matrix.M[0][0]); // TODO - find out if false or true is column or row major
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+float UOptiXContext::GetFloat(FString string)
+{
+	float F = 0;
+	try
+	{
+		F = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return F;
+}
+
+// TODO: COMPLETE ERROR HANDLING
+
+FVector2D UOptiXContext::GetFloat2D(FString string)
+{
+	optix::float2 V = optix::make_float2(0, 0);
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat2();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+	return FVector2D(V.x, V.y);
+}
+
+FVector UOptiXContext::GetFloat3D(FString string)
+{
+	optix::float3 V = optix::make_float3(0, 0, 0);;
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat3();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return FVector(V.x, V.y, V.z);
+}
+
+FVector4 UOptiXContext::GetFloat4D(FString string)
+{
+	optix::float4 V = optix::make_float4(0, 0, 0, 0);
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat4();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return FVector4(V.x, V.y, V.z, V.w);
+}
+
+int32 UOptiXContext::GetInt(FString string)
+{
+	int32 Result = 0;
+	try
+	{
+		Result = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getInt();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Result;
+}
+
+FIntPoint UOptiXContext::GetInt2D(FString string)
+{
+	optix::int2 V = optix::make_int2(0, 0);
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getInt2();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return FIntPoint(V.x, V.y);
+}
+
+FIntVector UOptiXContext::GetInt3D(FString string)
+{
+	optix::int3 V = optix::make_int3(0, 0, 0);
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getInt3();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return FIntVector(V.x, V.y, V.z);
+}
+
+
+void UOptiXContext::Validate()
+{
+	try
+	{
+		NativeContext->validate();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint32 UOptiXContext::GetDeviceCount()
+{
+	uint32 DeviceCount = 0;
+	try
+	{
+		DeviceCount = NativeContext->getDeviceCount();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return DeviceCount;
+}
+
+FString UOptiXContext::GetDeviceName(int32 Ordinal)
+{
+	FString DeviceName = "";
+	try
+	{
+		DeviceName = FString(NativeContext->getDeviceName(Ordinal).c_str());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return DeviceName;
+}
+
+void UOptiXContext::SetStackSize(int32 StackSize)
+{
+	if (StackSize < 0)
+	{
+		FString Message = "Trying to set negative stack size!";
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		return; // TODO Throw error
+	}
+	try
+	{
+		NativeContext->setStackSize(static_cast<uint32>(StackSize));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXContext::GetStackSize()
+{
+	// Casting a uint32 into an int32 is a bit dangerous here...
+	// TODO Check precision
+	int32 Size = 0;
+	try
+	{
+		Size = static_cast<int32>(NativeContext->getStackSize());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Size;
+}
+
+void UOptiXContext::SetStackSize64(uint64 StackSize)
+{
+	try
+	{
+		NativeContext->setStackSize(StackSize);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint64 UOptiXContext::GetStackSize64()
+{
+	uint64 Size = 0;
+	try
+	{
+		Size = NativeContext->getStackSize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Size;
+}
+
+void UOptiXContext::SetEntryPointCount(int32 NumEntryPoints)
+{
+	int32 Diff = NumEntryPoints - GetEntryPointCount();
+	if (Diff > 0)
+	{
+		RayGenerationPrograms.SetNum(NumEntryPoints);
+		ExceptionPrograms.SetNum(NumEntryPoints);
+	}
+	// TODO delete if diff < 0
+	else
+	{
+		for (int32 i = NumEntryPoints; i < GetEntryPointCount(); i++)
+		{
+			RayGenerationPrograms.RemoveAt(i);
+			ExceptionPrograms.RemoveAt(i);
+		}
+		RayGenerationPrograms.SetNum(NumEntryPoints);
+		ExceptionPrograms.SetNum(NumEntryPoints);
+
+		FString Message = FString("Shrinking Entry Point Count!");
+		UE_LOG(OptiXPluginContext, Warning, TEXT("Error: %s"), *Message);
+	}
+	try
+	{
+		NativeContext->setEntryPointCount(static_cast<uint32>(NumEntryPoints));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXContext::GetEntryPointCount()
+{
+	int32 EntryPointCount = 0;
+	try
+	{
+		EntryPointCount = static_cast<int32>(NativeContext->getEntryPointCount());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return EntryPointCount;
+}
+
+
+void UOptiXContext::SetRayGenerationProgram(int32 EntryPointIndex, UOptiXProgram* Program)
+{
+	if (!RayGenerationPrograms.IsValidIndex(EntryPointIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to insert program in non-existing place! \n"));
+		return;
+	}
+	try
+	{
+		NativeContext->setRayGenerationProgram(EntryPointIndex, Program->GetNativeProgram());
+		RayGenerationPrograms.Insert(Program, EntryPointIndex);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+UOptiXProgram* UOptiXContext::GetRayGenerationProgram(int32 EntryPointIndex)
+{
+	UOptiXProgram* Program = nullptr;
+	if (!RayGenerationPrograms.IsValidIndex(EntryPointIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to get ray generation program from non-existing place! \n"));
+	}
+	try
+	{
+		NativeContext->getRayGenerationProgram(EntryPointIndex);
+		Program = RayGenerationPrograms[EntryPointIndex];
+		// Todo: this could use some sweet little love
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Program;
+}
+
+void UOptiXContext::SetExceptionProgram(int32 EntryPointIndex, UOptiXProgram* Program)
+{
+	if (!ExceptionPrograms.IsValidIndex(EntryPointIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to insert program in non-existing place! \n"));
+		return;
+	}
+	try
+	{
+		NativeContext->setExceptionProgram(EntryPointIndex, Program->GetNativeProgram());
+		ExceptionPrograms.Insert(Program, EntryPointIndex);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+UOptiXProgram* UOptiXContext::GetExceptionProgram(int32 EntryPointIndex)
+{
+	UOptiXProgram* Program = nullptr;
+	if (!ExceptionPrograms.IsValidIndex(EntryPointIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to get ray exception program from non-existing place! \n"));
+	}
+	try
+	{
+		NativeContext->getExceptionProgram(EntryPointIndex);
+		Program = ExceptionPrograms[EntryPointIndex];
+		// Todo: this could use some sweet little love
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Program;
+}
+
+void UOptiXContext::SetExceptionEnabled(RTexception Exception, bool Enabled)
+{
+	try
+	{
+		NativeContext->setExceptionEnabled(Exception, Enabled);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+bool UOptiXContext::GetExceptionEnabled(RTexception Exception)
+{
+	bool V = false; // TODO Look at all those shitty default values
+	try
+	{
+		V = NativeContext->getExceptionEnabled(Exception);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return V;
+}
+
+// Uh oh
+
+void UOptiXContext::SetRayTypeCount(int32 NumRayTypes)
+{
+	int32 Diff = NumRayTypes - GetRayTypeCount();
+	if (Diff > 0)
+	{
+		MissPrograms.SetNum(NumRayTypes);
+	}
+	// TODO delete if diff < 0
+	try
+	{
+		NativeContext->setRayTypeCount(static_cast<uint32>(NumRayTypes));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXContext::GetRayTypeCount()
+{
+	// TODO CAST
+	int32 RTC = 0; static_cast<int32>(NativeContext->getRayTypeCount());
+	try
+	{
+		RTC = static_cast<int32>(NativeContext->getRayTypeCount());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return RTC;
+}
+
+
+void UOptiXContext::SetMissProgram(int32 RayTypeIndex, UOptiXProgram* Program)
+{
+	if (!MissPrograms.IsValidIndex(RayTypeIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("UOptiXContext: Trying to insert program in non-existing place! \n"));
+		return;
+	}
+	try
+	{
+		NativeContext->setMissProgram(RayTypeIndex, Program->GetNativeProgram());
+		MissPrograms.Insert(Program, RayTypeIndex);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXProgram* UOptiXContext::GetMissProgram(int32 RayTypeIndex)
+{
+	UOptiXProgram* Program = nullptr;
+	if (!MissPrograms.IsValidIndex(RayTypeIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to get ray miss program from non-existing place! \n"));
+	}
+	try
+	{
+		NativeContext->getMissProgram(RayTypeIndex);
+		Program = MissPrograms[RayTypeIndex];
+		// Todo: this could use some sweet little love
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Program;
+}
+
+void UOptiXContext::Compile()
+{
+	try
+	{
+		NativeContext->compile();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth)
+{
+	try
+	{
+		NativeContext->launch(EntryPointIndex, ImageWidth);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight)
+{
+	//UE_LOG(OptiXPluginContext, Warning, TEXT("Child count: %i"), GeometryGroupMap["top_object"]->GetChildCount());
+
+	try
+	{
+		NativeContext->launch(EntryPointIndex, ImageWidth, ImageHeight);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight, uint64 ImageDepth)
+{
+	try
+	{
+		NativeContext->launch(EntryPointIndex, ImageWidth, ImageHeight, ImageDepth);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetBuffer(FString Name, UOptiXBuffer * Buffer)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeContext[N]->set(Buffer->GetNativeBuffer());
+		Buffer->Name = Name;
+		BufferMap.Add(Name, Buffer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetGeometryGroup(FString Name, UOptiXGeometryGroup * GeoGroup)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeContext[N]->set(GeoGroup->GetNativeGroup());
+		GeometryGroupMap.Add(Name, GeoGroup);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetGroup(FString Name, UOptiXGroup * Group)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeContext[N]->set(Group->GetNativeGroup());
+		GroupMap.Add(Name, Group);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXProgram * UOptiXContext::CreateProgramFromPTXFile(FString Path, FString Name)
+{
+	UOptiXProgram* ProgramPtr = nullptr;
+	try
+	{
+		ProgramPtr = NewObject<UOptiXProgram>(this, UOptiXProgram::StaticClass());
+		std::string P = std::string(TCHAR_TO_ANSI(*Path));
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		optix::Program Prog = NativeContext->createProgramFromPTXFile(P, N);
+		ProgramPtr->SetProgram(Prog);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return ProgramPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBuffer(uint8 Type, RTformat Format, RTsize Width)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, Format, Width));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, Format, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height, RTsize Depth)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, Format, Width, Height, Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferSimple(uint8 Type)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferUByte(uint8 Type)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferUByte1D(uint8 Type, int32 Width)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4, Width));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferUByte2D(uint8 Type, int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferUByte3D(uint8 Type, int32 Width, int32 Height, int32 Depth)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4, Width, Height, Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateOutputBufferIntersections(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+
+UOptiXBuffer * UOptiXContext::CreateOutputBufferColor(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateOutputBufferUByte3D(int32 Width, int32 Height, int32 Depth)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_OUTPUT, RT_FORMAT_UNSIGNED_BYTE4, Width, Height, Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer* UOptiXContext::CreateOutputBufferDepth(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		//BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT, Width, Height));
+		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateInputBufferFloat(int32 Width)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT, Width));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateInputBufferFloat2D(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateInputBufferFloat3D(int32 Width, int32 Height, int32 Depth)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT, Width, Height, Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateCubemapBuffer(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		// https://github.com/nvpro-samples/optix_advanced_samples/blob/master/src/optixIntroduction/optixIntro_07/src/Texture.cpp
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT | RT_BUFFER_CUBEMAP, RT_FORMAT_UNSIGNED_BYTE4, Width, Height, 6)); // 6 slices
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+void UOptiXContext::SetMaxTraceDepth(int32 Depth)
+{
+	try
+	{
+		NativeContext->setMaxTraceDepth(static_cast<unsigned int>(Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXContext::GetMaxTraceDepth()
+{
+	int32 Depth = 0;
+	try
+	{
+		Depth = static_cast<int32>(NativeContext->getMaxTraceDepth()); // Loss of precision but won't happen ever anyway
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Depth;
+}
+
+void UOptiXContext::SetFloat3DVectorThreadsafe(FString string, FVector Var)
+{
+	VectorCache.Add(string, Var);
+}
+
+void UOptiXContext::SetMatrixThreadsafe(FString string, FMatrix Matrix)
+{
+	MatrixCache.Add(string, Matrix);
+}
+
+UOptiXTextureSampler * UOptiXContext::CreateTextureSampler()
+{
+	UOptiXTextureSampler* SamplerPtr = nullptr;
+	try
+	{
+		SamplerPtr = NewObject<UOptiXTextureSampler>(this, UOptiXTextureSampler::StaticClass());
+		SamplerPtr->SetTextureSampler(NativeContext->createTextureSampler());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return SamplerPtr;
+}
+
+void UOptiXContext::SetTextureSampler(FString Name, UOptiXTextureSampler * Sampler)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeContext[N]->set(Sampler->GetNativeTextureSampler());
+		TextureSamplerMap.Add(Name, Sampler);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetSkybox(FString Name, UOptiXTextureSampler * Sampler)
+{
+	SetInt(Name, Sampler->GetId());
+	TextureSamplerMap.Add(Name, Sampler);
+}
+
+UOptiXBuffer * UOptiXContext::GetBuffer(FString Name)
+{
+	if (BufferMap.Contains(Name))
+	{
+		return BufferMap[Name];
+	}
+	else
+	{
+		FString Message = "Buffer doesn't exist!";
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		return nullptr;
+	}
+}
+
+UOptiXGeometryGroup * UOptiXContext::GetGeometryGroup(FString Name)
+{
+	if (GeometryGroupMap.Contains(Name))
+	{
+		// Todo - check if that's actually the correct one! (GetNative etc)
+		return GeometryGroupMap[Name];
+	}
+	else
+	{
+		FString Message = "Geometry Group doesn't exist!";
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		return nullptr;
+	}
+}
+
+UOptiXGroup * UOptiXContext::GetGroup(FString Name)
+{
+	if (GroupMap.Contains(Name))
+	{
+		// Todo - check if that's actually the correct one! (GetNative etc)
+		return GroupMap[Name];
+	}
+	else
+	{
+		FString Message = "Group doesn't exist!";
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		return nullptr;
+	}
+}
+
+// Copy Paste too strong, could have shortened that quite a bit 
diff --git a/Source/OptiX/Private/OptiXContextManager.cpp b/Source/OptiX/Private/OptiXContextManager.cpp
index d71ae3bcb8c116ff15f0cfc41abc315c9c1e1b60..5711237b20fd77f266d534d9158e0db1ade96a97 100644
--- a/Source/OptiX/Private/OptiXContextManager.cpp
+++ b/Source/OptiX/Private/OptiXContextManager.cpp
@@ -2,6 +2,7 @@
 
 #include "OptiXContextManager.h"
 #include "OptiXModule.h"
+#include "OptiXBuffer.h"
 
 #include "RenderCore.h"
 #include "EngineUtils.h"
@@ -25,19 +26,8 @@
 
 #include "Async.h"
 
-#include "StatsDefines.h"
-
-//#include "Runtime/Windows/D3D11RHI/Private/Windows/D3D11RHIBasePrivate.h
-#include "Runtime/Windows/D3D11RHI/Private/D3D11StateCachePrivate.h"
-#include "Runtime/Windows/D3D11RHI/Public/D3D11State.h"
-typedef FD3D11StateCacheBase FD3D11StateCache;
-#include "Runtime/Windows/D3D11RHI/Public/D3D11Resources.h"
-
 // Console variables todo
 
-DEFINE_LOG_CATEGORY(OptiXContextManagerLog);
-
-
 static TAutoConsoleVariable<int32> CVarDisableTrace(
 	TEXT("optix.DisableTrace"),
 	0,
@@ -51,43 +41,13 @@ static TAutoConsoleVariable<int32> CVarDisableLaserTrace(
 	ECVF_Scalability | ECVF_RenderThreadSafe);
 
 
-FOptiXContextUpdateManager::FOptiXContextUpdateManager(const FAutoRegister& AutoRegister)
-	: FSceneViewExtensionBase(AutoRegister)
-{}
-
-void FOptiXContextUpdateManager::SetupViewFamily(FSceneViewFamily& InViewFamily)
-{
-}
-void FOptiXContextUpdateManager::SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView)
-{
-}
-void FOptiXContextUpdateManager::BeginRenderViewFamily(FSceneViewFamily& InViewFamily)
-{
-}
-void FOptiXContextUpdateManager::PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView)
-{
-}
-void FOptiXContextUpdateManager::PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
-{
-	// Hacky hacky
-	FOptiXModule::Get().GetOptiXContextManager()->ExecuteOptiXUpdate_PreLateUpdate(RHICmdList);
-}
-bool FOptiXContextUpdateManager::IsActiveThisFrame(class FViewport* InViewport) const
-{
-	return bIsActive;
-}
-int32 FOptiXContextUpdateManager::GetPriority() const
-{
-	return 100;
-}
-
 
 FOptiXContextManager::FOptiXContextManager(const FAutoRegister& AutoRegister)
 	: FSceneViewExtensionBase(AutoRegister)
 {
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("FOptiXContextManager, is in rendering thread: %i"), static_cast<int32>(IsInRenderingThread()));
+	UE_LOG(LogTemp, Display, TEXT("FOptiXContextManager, is in rendering thread: %i"), static_cast<int32>(IsInRenderingThread()));
 
-	//RTXOn = 0;
+	RTXOn = 0;
 
 	LaserMaxDepth = 20;
 	LaserEntryPoint = 1; // Default, will be overwritten anyway
@@ -97,448 +57,277 @@ FOptiXContextManager::FOptiXContextManager(const FAutoRegister& AutoRegister)
 
 	LaserBufferSize = LaserBufferHeight * LaserBufferWidth;
 
-	OnSceneChangedDelegate.AddRaw(this, &FOptiXContextManager::SceneChangedCallback);
-
-	OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
+	bValidCubemap.AtomicSet(false);
 
-	OptiXContextUpdateManager = FSceneViewExtensions::NewExtension<FOptiXContextUpdateManager>();
-}
+	OnSceneChangedDelegate.AddRaw(this, &FOptiXContextManager::SceneChangedCallback);
 
-int32 FOptiXContextManager::GetPriority() const
-{
-	// FDefaultXRCamera: 0 (does the basic lateupdate)
-	// OculusHMD : -1
-	// SteamVR: seems to be default (0)
-	return 10;
 }
 
 
-// gamethread
 void FOptiXContextManager::SetupViewFamily(FSceneViewFamily & InViewFamily)
-{}
+{
+	//UE_LOG(LogTemp, Warning, TEXT("SetupViewFamily"));
+}
 
 void FOptiXContextManager::SetupView(FSceneViewFamily & InViewFamily, FSceneView & InView)
-{}
+{
+	//UE_LOG(LogTemp, Warning, TEXT("SetupView"));
+
+	// TODO Check Width/Height
+}
 
-// gamethread
 void FOptiXContextManager::BeginRenderViewFamily(FSceneViewFamily & InViewFamily)
-{}
+{
+	//UE_LOG(LogTemp, Warning, TEXT("BeginRenderViewFamily"));
+}
 
 // Called on render thread at the start of rendering, for each view, after PreRenderViewFamily_RenderThread call.
 void FOptiXContextManager::PreRenderView_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneView & InView)
-{}
+{
+}
 
 // Called on render thread at the start of rendering.
 void FOptiXContextManager::PreRenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneViewFamily & InViewFamily)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::PreRenderViewFamily_RenderThread"))
-
-	if (bEndPlayReceived)
+	//UE_LOG(LogTemp, Warning, TEXT("PreRenderViewFamily_RenderThread"));
+	if (!bIsInitialized && bStartTracing)
 	{
-		Cleanup_RenderThread();
-		return;
+		InitCUDADX();
 	}
+}
 
-	// launch the laser trace if needed (todo)
-	LaunchLaser(RHICmdList);
-	//CopyLaserCudaTexture(RHICmdList);
+void FOptiXContextManager::PostRenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneViewFamily & InViewFamily)
+{
+	//UE_LOG(LogTemp, Warning, TEXT("PostRenderViewFamily_RenderThread"));
+		// Laser Test part:
 
 }
 
-void FOptiXContextManager::PostRenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneViewFamily & InViewFamily)
+void FOptiXContextManager::PostRenderView_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneView & InView)
 {
-	// check if compiler optimizes if away
-	if (bWithHMD)
-		LaunchStandardTrace(RHICmdList, InViewFamily);
-	else
-		LaunchMonoscopicTrace(RHICmdList, InViewFamily);
+	//UE_LOG(LogTemp, Warning, TEXT("VPM: PostRenderViewFamily_RenderThread %s"), *InView.ViewMatrices.GetViewProjectionMatrix().ToString());
 
-	// If an ortho pass was previously requested, execute it now and clear the request
-	if (bRequestOrthoPass)
+	if (!bIsInitialized && !bClearToLaunch && !OptiXContext.IsValid() && !bStartTracing)
 	{
-		RenderOrthoPass();
-		bRequestOrthoPass.AtomicSet(false);
+		return;
 	}
-}
 
-void FOptiXContextManager::PostRenderView_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneView & InView)
-{}
+	// Init the yet uninitialized optix components - this queue should be empty and do nothing if no new components are registered.
+	InitOptiXComponents(RHICmdList);
 
-void FOptiXContextManager::ExecuteOptiXUpdate_PreLateUpdate(FRHICommandListImmediate & RHICmdList)
-{
-	// New functions
-	ParseCreationQueue(); // Create new stuff
-	ParseDestroyQueue(); // Get rid of removed objects - this order such that just created objects can be destroyed in the same tick and no ghost objects happen
-	ParseInitQueue();
-	ParseUpdateQueue(RHICmdList);
-	ParseCubemapUpdateQueue(RHICmdList);
-}
+	// Update the remaining variables TODO this needs to be only done once not once per eye!
+	OptiXContext->UpdateVariables();
+	UpdateOptiXComponentVariables();
+	UpdateRequestedCubemaps(RHICmdList);
 
-void FOptiXContextManager::LaunchStandardTrace(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaunchStandardTrace")
+	RemovePendingChildrenFromGroups();
+	// Clean up any dangling optix objects here to not interfere with launch
+	DestroyOptiXObjects();
 
 
-		if (bEndPlayReceived)
-		{
-			return;
-		}
+	OptiXContext->SetMatrix("invViewProjection", InView.ViewMatrices.GetInvViewProjectionMatrix());
+	OptiXContext->SetMatrix("viewProjection", InView.ViewMatrices.GetViewProjectionMatrix());
 
-	if (InViewFamily.Views.Num() < 2)
-		return;
+	FIntPoint Size = OptiXContext->GetBuffer("result_color")->GetSize2D();
 
-	// Get the views for the respective eyes:
-	EStereoscopicPass LeftEye = EStereoscopicPass::eSSP_LEFT_EYE;
-	EStereoscopicPass RightEye = EStereoscopicPass::eSSP_RIGHT_EYE;
+	bIsTracing.AtomicSet(true);
+	OptiXContext->Launch(0, Size.X, Size.Y);
+	bIsTracing.AtomicSet(false);
 
-	const FSceneView& LeftEyeView = InViewFamily.GetStereoEyeView(LeftEye);
-	const FSceneView& RightEyeView = InViewFamily.GetStereoEyeView(RightEye);
 
-	// Set the required matrices
-	NativeContext["invViewProjectionLeft"]->setMatrix4x4fv(true, &LeftEyeView.ViewMatrices.GetInvViewProjectionMatrix().M[0][0]);
-	NativeContext["viewProjectionLeft"]->setMatrix4x4fv(true, &LeftEyeView.ViewMatrices.GetViewProjectionMatrix().M[0][0]);
-	NativeContext["invViewProjectionRight"]->setMatrix4x4fv(true, &RightEyeView.ViewMatrices.GetInvViewProjectionMatrix().M[0][0]);
-	NativeContext["viewProjectionRight"]->setMatrix4x4fv(true, &RightEyeView.ViewMatrices.GetViewProjectionMatrix().M[0][0]);
-	//NativeContext->validate();
+	if (InView.StereoPass == EStereoscopicPass::eSSP_LEFT_EYE) // check validity
+	{		
+		//float* Data2 = static_cast<float*>(OptiXContext->GetBuffer("result_depth")->MapNative());
+		//RHICmdList.UpdateTexture2D(OutputTextureDepthLeftRef, 0, TextureRegion, Size.X * 4, (uint8*)Data2);
+		//OptiXContext->GetBuffer("result_depth")->Unmap();
 
-	{
-		TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::Trace")
-			//bIsTracing.AtomicSet(true);
-			// Execute the actual trace
-			NativeContext->launch(0, Width, Height);
-		//bIsTracing.AtomicSet(false);
-		//return;
-	}
-	{
-		// Check cuda resources for NULL. Shouldn't be needed as they *should* never be NULL.
-		if (Resources[0] == NULL || Resources[1] == NULL || Resources[2] == NULL || Resources[3] == NULL)
+		if (Resources[0] == NULL && Resources[1] == NULL)
 		{
-			UE_LOG(OptiXContextManagerLog, Error, TEXT("CUDA Resources are NULL"));
 			return;
 		}
 
-		// Map the four graphics resources corresponding to color, depth for both eyes.
-		cudaGraphicsMapResources(4, Resources, 0);
+		cudaGraphicsMapResources(2, Resources, 0);
 		PrintLastCudaError("cudaGraphicsMapResources");
 
-		// Map the left eye color resource to a cudaArray 
-		cudaArray *CuArrayColorLeft;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayColorLeft, CudaResourceColorLeft, 0, 0);
-		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-		// Copy the result of the optix 2D color buffer into the mapped array. 
-		// As both passes are written into the same buffer, this copies only the first half corresponding to the left eye.
-		cudaMemcpy2DToArray(
-			CuArrayColorLeft, // dst array
-			0, 0,    // offset
-			CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
-			Width * 4 * sizeof(float), Height, // extent
-			cudaMemcpyDeviceToDevice); // kind
-		PrintLastCudaError("cudaMemcpy2DToArray");
-
-
-		// Copy Color Right
-		cudaArray *CuArrayColorRight;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayColorRight, CudaResourceColorRight, 0, 0);
-		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-		// Copy the result of the optix 2D color buffer into the mapped array. 
-		// As this copies the into the right eye, the buffer pointer needs to be offset by (Height * Width)
-		// to copy the second half.
-		cudaMemcpy2DToArray(
-			CuArrayColorRight, // dst array
-			0, 0,    // offset
-			CudaLinearMemoryColor + (Height * Width), Width * 4 * sizeof(float),       // src
-			Width * 4 * sizeof(float), Height, // extent
-			cudaMemcpyDeviceToDevice); // kind
-		PrintLastCudaError("cudaMemcpy2DToArray");
-
+		if (CudaResourceDepthLeft == NULL)
+		{
+			cudaGraphicsUnmapResources(2, Resources, 0);
+			return;
+		}
 
-		// Copy Depth Left
-		cudaArray *CuArrayDepthLeft;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayDepthLeft, CudaResourceDepthLeft, 0, 0);
+		// Copy Depth
+		cudaArray *CuArrayDepth;
+		cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthLeft, 0, 0);
 		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
 
 		cudaMemcpy2DToArray(
-			CuArrayDepthLeft, // dst array
+			CuArrayDepth, // dst array
 			0, 0,    // offset
 			CudaLinearMemoryDepth, Width * sizeof(float),       // src
 			Width * sizeof(float), Height, // extent
 			cudaMemcpyDeviceToDevice); // kind
 		PrintLastCudaError("cudaMemcpy2DToArray");
 
-		// Copy Depth Right
-		cudaArray *CuArrayDepthRight;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayDepthRight, CudaResourceDepthRight, 0, 0);
+		// Copy Color
+
+		cudaArray *CuArrayColor;
+		cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorLeft, 0, 0);
 		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
 
 		cudaMemcpy2DToArray(
-			CuArrayDepthRight, // dst array
+			CuArrayColor, // dst array
 			0, 0,    // offset
-			CudaLinearMemoryDepth + (Height * Width), Width * sizeof(float),       // src
-			Width * sizeof(float), Height, // extent
+			CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
+			Width * 4 * sizeof(float), Height, // extent
 			cudaMemcpyDeviceToDevice); // kind
 		PrintLastCudaError("cudaMemcpy2DToArray");
 
 
-		cudaGraphicsUnmapResources(4, Resources, 0);
+		cudaGraphicsUnmapResources(2, Resources, 0);
 		PrintLastCudaError("cudaGraphicsUnmapResources");
 
 		//D3DDeviceContext->Flush();
-		//UpdateCubemapBuffer(RHICmdList);
-	}
-	//CopyLaserCudaTexture(RHICmdList);
-}
-
-void FOptiXContextManager::LaunchMonoscopicTrace(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaunchMonoscopicTrace")
-
-
-	if (bEndPlayReceived)
-		{
-			return;
-		}
+		LaunchLaser();
+		UpdateCubemapBuffer(RHICmdList);
 
-	if (InViewFamily.Views.Num() < 2)
-		return;
-
-	// Get the views for the respective eyes:
-	EStereoscopicPass Mono = EStereoscopicPass::eSSP_FULL;
-
-	const FSceneView& MonoView = InViewFamily.GetStereoEyeView(Mono);
-
-	// Set the required matrices
-	NativeContext["invViewProjectionLeft"]->setMatrix4x4fv(true, &MonoView.ViewMatrices.GetInvViewProjectionMatrix().M[0][0]);
-	NativeContext["viewProjectionLeft"]->setMatrix4x4fv(true, &MonoView.ViewMatrices.GetViewProjectionMatrix().M[0][0]);
-
-	//NativeContext->validate();
-
-	{
-		TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::Trace")
-			//bIsTracing.AtomicSet(true);
-			// Execute the actual trace
-		NativeContext->launch(0, Width, Height);
-		//bIsTracing.AtomicSet(false);
-		//return;
 	}
+	else if(InView.StereoPass == EStereoscopicPass::eSSP_RIGHT_EYE)
 	{
-		// Check cuda resources for NULL. Shouldn't be needed as they *should* never be NULL.
-		if (Resources[0] == NULL || Resources[1] == NULL)
+		if (Resources[2] == NULL && Resources[3] == NULL)
 		{
-			UE_LOG(OptiXContextManagerLog, Error, TEXT("CUDA Resources are NULL"));
 			return;
 		}
-
-		// Map the two graphics resources corresponding to color, depth
-		cudaGraphicsMapResources(2, Resources, 0);
+		cudaGraphicsMapResources(2, Resources + 2, 0);
 		PrintLastCudaError("cudaGraphicsMapResources");
 
-		// Map the left eye color resource to a cudaArray 
-		cudaArray* CuArrayColorLeft;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayColorLeft, CudaResourceColorLeft, 0, 0);
+		if (CudaResourceDepthRight == NULL)
+		{
+			cudaGraphicsUnmapResources(2, Resources + 2, 0);
+			return;
+		}
+		// Depth
+		cudaArray *CuArrayDepth;
+		cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthRight, 0, 0);
 		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
 
-		// Copy the result of the optix 2D color buffer into the mapped array. 
-		// As both passes are written into the same buffer, this copies only the first half corresponding to the left eye.
 		cudaMemcpy2DToArray(
-			CuArrayColorLeft, // dst array
+			CuArrayDepth, // dst array
 			0, 0,    // offset
-			CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
-			Width * 4 * sizeof(float), Height, // extent
+			CudaLinearMemoryDepth, Width * sizeof(float),       // src
+			Width * sizeof(float), Height, // extent
 			cudaMemcpyDeviceToDevice); // kind
-		PrintLastCudaError("cudaMemcpy2DToArray");
+		//PrintLastCudaError("cudaMemcpy2DToArray");
+
 
-		// Copy Depth Left
-		cudaArray* CuArrayDepthLeft;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayDepthLeft, CudaResourceDepthLeft, 0, 0);
+		// Color
+		cudaArray *CuArrayColor;
+		cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorRight, 0, 0);
 		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
 
 		cudaMemcpy2DToArray(
-			CuArrayDepthLeft, // dst array
+			CuArrayColor, // dst array
 			0, 0,    // offset
-			CudaLinearMemoryDepth, Width * sizeof(float),       // src
-			Width * sizeof(float), Height, // extent
+			CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
+			Width * 4 * sizeof(float), Height, // extent
 			cudaMemcpyDeviceToDevice); // kind
 		PrintLastCudaError("cudaMemcpy2DToArray");
 
-		cudaGraphicsUnmapResources(2, Resources, 0);
+		cudaGraphicsUnmapResources(2, Resources + 2, 0);
 		PrintLastCudaError("cudaGraphicsUnmapResources");
 	}
 
-	// If an ortho pass was previously requested, execute it now and clear the request
-	if (bRequestOrthoPass)
+	//else if (InView.StereoPass == EStereoscopicPass::eSSP_FULL)
+	//{
+	//	UE_LOG(LogTemp, Display, TEXT("Full Pass"));
+	//}
+
+	//if (bCleanup)
+	//{
+	//	CleanupOptiXOnEnd();
+	//	return;
+	//}
+	//
+
+	if(bRequestOrthoPass)
 	{
 		RenderOrthoPass();
 		bRequestOrthoPass.AtomicSet(false);
 	}
 }
 
-void FOptiXContextManager::CopyLaserCudaTexture(FRHICommandListImmediate & RHICmdList)
+
+void FOptiXContextManager::LaunchLaser()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::CopyLaserCudaTexture")
-	if (/*bSceneChanged &&*/ bIsInitializedLaser && !CVarDisableLaserTrace.GetValueOnRenderThread())
+	if (/*bSceneChanged && */ bLaserIsInitialized && !CVarDisableLaserTrace.GetValueOnRenderThread())
 	{
-		if (Resources[4] == NULL)
-		{
-			return;
-		}
-		{
-			TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::MapAndCopy"))
-
-				cudaGraphicsMapResources(1, Resources + 4, 0);
-			PrintLastCudaError("cudaGraphicsMapResources");
-
-			if (CudaResourceIntersections == NULL)
-			{
-				cudaGraphicsUnmapResources(1, Resources + 4, 0);
-				return;
-			}
-
-			cudaArray *CuArrayIntersections;
-			cudaGraphicsSubResourceGetMappedArray(&CuArrayIntersections, CudaResourceIntersections, 0, 0);
-			PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-			{
-				TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Memcpy"))
-
-					cudaMemcpy2DToArray(
-						CuArrayIntersections, // dst array
-						0, 0,    // offset
-						CudaLinearMemoryIntersections, LaserBufferWidth * 4 * sizeof(float),       // src
-						LaserBufferWidth * 4 * sizeof(float), LaserBufferHeight, // extent
-						cudaMemcpyDeviceToDevice); // kind
-				PrintLastCudaError("cudaMemcpy2DToArray");
-			}
-		}
-		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Unmap"))
-
-		cudaGraphicsUnmapResources(1, Resources + 4, 0);
-		PrintLastCudaError("cudaGraphicsUnmapResources");
+		if (LaserActor.IsValid())
 		{
-			TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaunchLaser::BroadcastFinish")
-
-			//bSceneChanged.AtomicSet(false);
-			for (const auto& Pair : LaserTraceFinishedCallbacks)
-			{
-				optix::TextureSampler Sampler = nullptr;
-				TMap<FString, optix::Buffer>* BufferMap = nullptr;
-				FOptiXObjectData* Data = nullptr;
-				if (OptiXTextureSamplers.Contains(Pair.Key))
-				{
-					Sampler = OptiXTextureSamplers[Pair.Key];
-				}
-				if (OptiXBuffers.Contains(Pair.Key))
-				{
-					BufferMap = &OptiXBuffers[Pair.Key];
-				}
-				if (OptiXObjectData.Contains(Pair.Key))
-				{
-					Data = &OptiXObjectData[Pair.Key];
-				}
-				Pair.Value(Data, BufferMap, Sampler, RHICmdList);
-			}
+			LaserActor->OptiXLaserComponent->UpdateOptiXContextVariables();
 		}
-	}
-}
 
-void FOptiXContextManager::LaunchLaser(FRHICommandListImmediate & RHICmdList)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaunchLaser")
-	if (/*bSceneChanged &&*/ bIsInitializedLaser && !CVarDisableLaserTrace.GetValueOnRenderThread())
-	{
+		// uuuuuuuuh
 		static uint32 RandomSeed = 0;
-		NativeContext["random_frame_seed"]->setUint(RandomSeed++);
+		OptiXContext->SetUint("random_frame_seed", RandomSeed++);
+		//UE_LOG(LogTemp, Warning, TEXT("Launching Laser Trace at Entry Point: %i"), LaserEntryPoint);
+		bIsTracing.AtomicSet(true);
+		OptiXContext->Launch(1, 50, 50, 20);
+		bIsTracing.AtomicSet(false);
+
 
-		TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::NativeContext::launch")
-		NativeContext->launch(1, 50, 50, 20);		
 		if (Resources[4] == NULL)
 		{
 			return;
 		}
+
+		cudaGraphicsMapResources(1, Resources + 4, 0);
+		PrintLastCudaError("cudaGraphicsMapResources");
+
+		if (CudaResourceIntersections == NULL)
 		{
-			TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::MapAndCopy"))
-
-			cudaGraphicsMapResources(1, Resources + 4, 0);
-			PrintLastCudaError("cudaGraphicsMapResources");
-
-			if (CudaResourceIntersections == NULL)
-			{
-				cudaGraphicsUnmapResources(1, Resources + 4, 0);
-				return;
-			}
-
-			cudaArray *CuArrayIntersections;
-			cudaGraphicsSubResourceGetMappedArray(&CuArrayIntersections, CudaResourceIntersections, 0, 0);
-			PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-			{
-				TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Memcpy"))
-
-					cudaMemcpy2DToArray(
-						CuArrayIntersections, // dst array
-						0, 0,    // offset
-						CudaLinearMemoryIntersections, LaserBufferWidth * 4 * sizeof(float),       // src
-						LaserBufferWidth * 4 * sizeof(float), LaserBufferHeight, // extent
-						cudaMemcpyDeviceToDevice); // kind
-				PrintLastCudaError("cudaMemcpy2DToArray");
-			}
+			cudaGraphicsUnmapResources(1, Resources + 4, 0);
+			return;
 		}
-		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Unmap"))
+
+		cudaArray *CuArrayIntersections;
+		cudaGraphicsSubResourceGetMappedArray(&CuArrayIntersections, CudaResourceIntersections, 0, 0);
+		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+		cudaMemcpy2DToArray(
+			CuArrayIntersections, // dst array
+			0, 0,    // offset
+			CudaLinearMemoryIntersections, LaserBufferWidth * 4 * sizeof(float),       // src
+			LaserBufferWidth * 4 * sizeof(float), LaserBufferHeight, // extent
+			cudaMemcpyDeviceToDevice); // kind
+		PrintLastCudaError("cudaMemcpy2DToArray");
+
 
 		cudaGraphicsUnmapResources(1, Resources + 4, 0);
 		PrintLastCudaError("cudaGraphicsUnmapResources");
-		{
-			TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaunchLaser::BroadcastFinish")
-
-			//bSceneChanged.AtomicSet(false);
-			for (const auto& Pair : LaserTraceFinishedCallbacks)
-			{
-				optix::TextureSampler Sampler = nullptr;
-				TMap<FString, optix::Buffer>* BufferMap = nullptr;
-				FOptiXObjectData* Data = nullptr;
-				if (OptiXTextureSamplers.Contains(Pair.Key))
-				{
-					Sampler = OptiXTextureSamplers[Pair.Key];
-				}
-				if (OptiXBuffers.Contains(Pair.Key))
-				{
-					BufferMap = &OptiXBuffers[Pair.Key];
-				}
-				if (OptiXObjectData.Contains(Pair.Key))
-				{
-					Data = &OptiXObjectData[Pair.Key];
-				}
-				Pair.Value(Data, BufferMap, Sampler, RHICmdList);
-			}
-		}
+
+		bSceneChanged.AtomicSet(false);
+		LaserTraceFinishedEvent.Broadcast();
 	}
 }
 
+
 bool FOptiXContextManager::IsActiveThisFrame(FViewport * InViewport) const
 {
-	//UE_LOG(OptiXContextManagerLog, Warning, TEXT("IsActiveThisFrame"));
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::IsActiveThisFrame")
+	//UE_LOG(LogTemp, Warning, TEXT("IsActiveThisFrame"));
 
-	bool bDisableTrace = static_cast<bool>(CVarDisableTrace.GetValueOnGameThread()); // Bad naming fix me
-	return NativeContext != NULL && !bDisableTrace && bIsInitializedAll /*&& !bEndPlayReceived*/ /* && !bEndPlay*//* && TrackingSystem->IsHeadTrackingAllowed()*/;
+	bool bDisableTrace = CVarDisableTrace.GetValueOnGameThread(); // Bad naming fix me
+	return OptiXContext.IsValid() && !bDisableTrace && bStartTracing /* && !bEndPlay*//* && TrackingSystem->IsHeadTrackingAllowed()*/;
 }
 
 void FOptiXContextManager::RenderOrthoPass()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::RenderOrthoPass")
+	OptiXContext->SetMatrix("invViewProjection", OrthoMatrix.Inverse());
+	OptiXContext->SetMatrix("viewProjection", OrthoMatrix);
 
-	if(bWithHMD)
-		NativeContext["is_mono"]->setInt(1);
+	FIntPoint Size = OptiXContext->GetBuffer("result_color")->GetSize2D();
 
-	NativeContext["invViewProjectionLeft"]->setMatrix4x4fv(true, &OrthoMatrix.Inverse().M[0][0]);
-	NativeContext["viewProjectionLeft"]->setMatrix4x4fv(true, &OrthoMatrix.M[0][0]);
-
-	//FIntPoint Size = OptiXContext->GetBuffer("result_color")->GetSize2D();
-
-	//bIsTracing.AtomicSet(true);
-	NativeContext->launch(0, Width, Height);
-	//bIsTracing.AtomicSet(false);
+	bIsTracing.AtomicSet(true);
+	OptiXContext->Launch(0, Size.X, Size.Y);
+	bIsTracing.AtomicSet(false);
 
 	if (Resources[5] == NULL && Resources[6] == NULL)
 	{
@@ -583,15 +372,11 @@ void FOptiXContextManager::RenderOrthoPass()
 
 
 	cudaGraphicsUnmapResources(2, Resources + 5, 0);
-	PrintLastCudaError("cudaGraphicsUnmapResources");
-
-	if (bWithHMD)
-		NativeContext["is_mono"]->setInt(0);
+	PrintLastCudaError("cudaGraphicsUnmapResources");	
 }
 
 void FOptiXContextManager::Init()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::Init")
 
 	// TODO Fix me there's still an optix error in there somewhere
 	//if (CubemapSampler.IsValid())
@@ -616,48 +401,39 @@ void FOptiXContextManager::Init()
 	//}
 
 	// Shouldn't be anything in the queues but clean up anyway just to be sure.
-	//DestroyOptiXObjects();
+	DestroyOptiXObjects();
 
 	//TODO: Shut this thing down correctly - for now just clean up anything when restarting
-	//CleanupOptiXOnEnd();
+	CleanupOptiXOnEnd();
 
-	bEndPlayReceived = false;
-	bValidCubemap = false;
-	bIsInitializedCuda = false;
-	bIsInitializedLaser = false;
-	bIsInitializedAll = false;
-	bSceneChanged = true;
-	bRequestOrthoPass = false;
-
-	InitRendering();
 	InitContext();
-
+	InitRendering();
 	InitBuffers();
 	InitPrograms();
 	InitLaser();
 	InitCubemap();
-
-	InitCUDADX();
-
-	bIsInitializedAll.AtomicSet(true);
-	OptiXContextUpdateManager->bIsActive = true;
+	//InitCUDADX();
+	bIsInitialized = false;
+	bStartTracing = true;
 }
 
 void FOptiXContextManager::SceneChangedCallback()
 {
-	//bSceneChanged.AtomicSet(true);
+	bSceneChanged.AtomicSet(true);
 }
 
 void FOptiXContextManager::InitContext()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::InitContext")
 
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Initializing Context in ContextManager"));
+	UE_LOG(LogTemp, Display, TEXT("Initializing Context in ContextManager"));
 
 	// Needs to be called BEFORE the context is created!
 	//rtGlobalSetAttribute(RT_GLOBAL_ATTRIBUTE_ENABLE_RTX, sizeof(RTXOn), &RTXOn);
 
-	NativeContext =	optix::Context::create();
+	OptiXContext = NewObject<UOptiXContext>(GetTransientPackage(), UOptiXContext::StaticClass());
+	OptiXContext->AddToRoot();
+	NativeContext = OptiXContext->Init();
+
 
 	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_PAYLOAD_ACCESS_OUT_OF_BOUNDS, false);
 	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER_EXCEPTION_CODE_OUT_OF_BOUNDS, true);
@@ -674,48 +450,51 @@ void FOptiXContextManager::InitContext()
 	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER, true);
 	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER_MAX, true);
 
-	NativeContext->setExceptionEnabled(RTexception::RT_EXCEPTION_ALL, false);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_ALL, true);
+
 
-	NativeContext->setPrintEnabled(false);
+
+	//NativeContext->setPrintEnabled(true);
 	//NativeContext->setPrintLaunchIndex(100, 100);
 	// Set some default values, they can (and should) be overwritten in the game mode as they're scene specific
-	NativeContext->setRayTypeCount(2);
-	NativeContext->setEntryPointCount(1);
+	OptiXContext->SetRayTypeCount(2);
+	OptiXContext->SetEntryPointCount(1);
 	//OptiXContext->SetStackSize(4000);
-	NativeContext->setMaxTraceDepth(31);
+	OptiXContext->SetMaxTraceDepth(31);
 
-	NativeContext["max_depth"]->setInt(10);
-	NativeContext["scene_epsilon"]->setFloat(1.e-2f);
+	OptiXContext->SetInt("max_depth", 10);
+	OptiXContext->SetFloat("scene_epsilon", 1.e-2f);
 
-	TopObject = NativeContext->createGroup();
-	TopAcceleration = NativeContext->createAcceleration("Trbvh"); // Here the accel structure seems to be actually needed
-	TopAcceleration->setProperty("refit", "1");
+	TopObject = OptiXContext->CreateGroup();
+	TopAcceleration = OptiXContext->CreateAcceleration("Trbvh"); // Here the accel structure seems to be actually needed
+	//TopAcceleration->AddToRoot();
+	TopAcceleration->SetProperty("refit", "1");
 
-	TopObject->setAcceleration(TopAcceleration);
+	TopObject->SetAcceleration(TopAcceleration.Get());
+
+	OptiXContext->SetGroup("top_object", TopObject.Get());
+
+	// Keep buffers and programs with the camera manager for now, there's no real reason yet to force a refacturing there
 
-	NativeContext["top_object"]->set(TopObject);
-	
-	NativeContext["is_mono"]->setInt(static_cast<int>(!bWithHMD));
 }
 
 
 void FOptiXContextManager::InitRendering()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::InitRendering")
 
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Initializing Rendering in ContextManager"));
+	UE_LOG(LogTemp, Display, TEXT("Initializing Rendering in ContextManager"));
 
 
 	// Are we using an HMD?
 	if (GEngine->XRSystem.IsValid() && GEngine->XRSystem->GetHMDDevice() != nullptr)
 	{
-		UE_LOG(OptiXContextManagerLog, Display, TEXT("Got HMD in ContextManager"));
+		UE_LOG(LogTemp, Display, TEXT("Got HMD in ContextManager"));
 
 		bWithHMD = GEngine->XRSystem->GetHMDDevice()->IsHMDEnabled();
 	}
 	else
 	{
-		UE_LOG(OptiXContextManagerLog, Display, TEXT("Running without HMD in ContextManager"));
+		UE_LOG(LogTemp, Display, TEXT("Running without HMD in ContextManager"));
 
 		bWithHMD = false;
 	}
@@ -726,8 +505,8 @@ void FOptiXContextManager::InitRendering()
 	Width = CurrentViewport->GetSizeXY().X / 2.0;
 	Height = CurrentViewport->GetSizeXY().Y;
 
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Got viewport sizes: %i, %i"), Width, Height);
-	UE_LOG(OptiXContextManagerLog, Warning, TEXT("Full Res: %i %i"), Width * 2, Height);
+	UE_LOG(LogTemp, Display, TEXT("Got viewport sizes: %i, %i"), Width, Height);
+	UE_LOG(LogTemp, Warning, TEXT("Full Res: %i %i"), Width * 2, Height);
 
 
 	// Apparently those can be 0 in a packaged build? 
@@ -737,45 +516,60 @@ void FOptiXContextManager::InitRendering()
 		UGameUserSettings* GameSettings = GEngine->GetGameUserSettings();
 		Width = GameSettings->GetScreenResolution().X;
 		Height = GameSettings->GetScreenResolution().Y;
-		UE_LOG(OptiXContextManagerLog, Display, TEXT("Fallback to viewport size in settings: %i, %i"), Width, Height);
+		UE_LOG(LogTemp, Display, TEXT("Fallback to viewport size in settings: %i, %i"), Width, Height);
+
 	}
 
+
 	// Create the textures:
 
-	OutputTexture2 = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
-	OutputTexture2->AddToRoot();
+	OutputTexture = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
+	OutputTexture->AddToRoot();
 	//// Allocate the texture HRI
-	OutputTexture2->UpdateResource();
+	OutputTexture->UpdateResource();
 
-	DepthTexture2 = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
-	DepthTexture2->AddToRoot();
+	DepthTexture = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
+	DepthTexture->AddToRoot();
 	//// Allocate the texture HRI
-	DepthTexture2->UpdateResource();
+	DepthTexture->UpdateResource();
+
+	OutputTextureColorRightRef = ((FTexture2DResource*)OutputTexture->Resource)->GetTexture2DRHI();
+	OutputTextureDepthRightRef = ((FTexture2DResource*)DepthTexture->Resource)->GetTexture2DRHI();
 
 	if (bWithHMD)
 	{
-		OutputTexture = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
-		OutputTexture->AddToRoot();
+		OutputTexture2 = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
+		OutputTexture2->AddToRoot();
 		//// Allocate the texture HRI
-		OutputTexture->UpdateResource();
+		OutputTexture2->UpdateResource();
 
-		DepthTexture = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
-		DepthTexture->AddToRoot();
+		DepthTexture2 = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
+		DepthTexture2->AddToRoot();
 		//// Allocate the texture HRI
-		DepthTexture->UpdateResource();
-	}
+		DepthTexture2->UpdateResource();
 
-	OutputTextureOrtho = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
-	OutputTextureOrtho->AddToRoot();
-	//// Allocate the texture HRI
-	OutputTextureOrtho->UpdateResource();
-	
-	DepthTextureOrtho = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
-	DepthTextureOrtho->AddToRoot();
-	//// Allocate the texture HRI
-	DepthTextureOrtho->UpdateResource();
+		OutputTextureDepthLeftRef = ((FTexture2DResource*)DepthTexture2->Resource)->GetTexture2DRHI();
+		OutputTextureColorLeftRef = ((FTexture2DResource*)OutputTexture2->Resource)->GetTexture2DRHI();
+
+
+		OutputTextureOrtho = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
+		OutputTextureOrtho->AddToRoot();
+		//// Allocate the texture HRI
+		OutputTextureOrtho->UpdateResource();
+
+		DepthTextureOrtho = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
+		DepthTextureOrtho->AddToRoot();
+		//// Allocate the texture HRI
+		DepthTextureOrtho->UpdateResource();
 
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Created the Textures"));
+		OutputTextureDepthOrthoRef = ((FTexture2DResource*)DepthTextureOrtho->Resource)->GetTexture2DRHI();
+		OutputTextureColorOrthoRef = ((FTexture2DResource*)OutputTextureOrtho->Resource)->GetTexture2DRHI();
+		
+
+		// TODO Maybe we need to do this after setting the parameter?
+	}
+
+	UE_LOG(LogTemp, Display, TEXT("Created the Textures"));
 
 	// Laser Texture
 	LaserIntersectionTexture = UTexture2D::CreateTransient(LaserBufferWidth, LaserBufferHeight, PF_A32B32G32R32F); // TODO Hardcoded values
@@ -783,143 +577,148 @@ void FOptiXContextManager::InitRendering()
 	//// Allocate the texture HRI
 	LaserIntersectionTexture->UpdateResource();
 
+	LaserIntersectionTextureRef = ((FTexture2DResource*)LaserIntersectionTexture->Resource)->GetTexture2DRHI();
+
 	// Set up the material
 
 	// Load the materials
-	MonoMaterial = LoadObject<UMaterial>(GetTransientPackage(), TEXT("Material'/OptiX/PPMaterials/TextureMaterial.TextureMaterial'"));
+	RegularMaterial = LoadObject<UMaterial>(GetTransientPackage(), TEXT("Material'/OptiX/PPMaterials/TextureMaterial.TextureMaterial'"));
 	VRMaterial = LoadObject<UMaterial>(GetTransientPackage(), TEXT("Material'/OptiX/PPMaterials/TextureMaterialVR.TextureMaterialVR'"));
 	LaserMaterial = LoadObject<UMaterial>(GetTransientPackage(), TEXT("Material'/OptiX/Laser/LaserMaterial.LaserMaterial'"));
-	LaserMaterialDynamic = UMaterialInstanceDynamic::Create(LaserMaterial.Get(), GetTransientPackage(), "DynamicLaserMaterial");
+	LaserMaterialDynamic = UMaterialInstanceDynamic::Create(LaserMaterial.Get(), OptiXContext.Get(), "DynamicLaserMaterial");
 
 	LaserMaterialDynamic->SetTextureParameterValue("IntersectionTexture", LaserIntersectionTexture.Get());
 	LaserMaterialDynamic->SetScalarParameterValue("Lines", 50);
 	LaserMaterialDynamic->SetScalarParameterValue("Segments", 20);
 
 
-	if(MonoMaterial == nullptr || VRMaterial == nullptr)
+	if(RegularMaterial == nullptr || VRMaterial == nullptr)
 	{
-		UE_LOG(OptiXContextManagerLog, Error, TEXT("Couldn't load dummy Material!"));
+		UE_LOG(LogTemp, Error, TEXT("Couldn't load dummy Material!"));
 	}
 
 	if (bWithHMD)
 	{
-		DynamicMaterial = UMaterialInstanceDynamic::Create(VRMaterial.Get(), GetTransientPackage(), "DynamicVRMaterial");
+		DynamicMaterial = UMaterialInstanceDynamic::Create(VRMaterial.Get(), OptiXContext.Get(), "DynamicVRMaterial");
 		DynamicMaterial->SetTextureParameterValue("TextureRight", OutputTexture.Get());
 		DynamicMaterial->SetTextureParameterValue("DepthRight", DepthTexture.Get());
 		DynamicMaterial->SetTextureParameterValue("TextureLeft", OutputTexture2.Get());
 		DynamicMaterial->SetTextureParameterValue("DepthLeft", DepthTexture2.Get());
+
+
+		DynamicMaterialOrtho = UMaterialInstanceDynamic::Create(RegularMaterial.Get(), OptiXContext.Get(), "DynamicNonVRMaterial");
+		DynamicMaterialOrtho->SetTextureParameterValue("Texture", OutputTextureOrtho.Get());
+		DynamicMaterialOrtho->SetTextureParameterValue("Depth", DepthTextureOrtho.Get());
+
 	}
 	else
 	{
-		DynamicMaterial = UMaterialInstanceDynamic::Create(MonoMaterial.Get(), GetTransientPackage(), "DynamicNonVRMaterial");
-		DynamicMaterial->SetTextureParameterValue("Texture", OutputTexture2.Get());
-		DynamicMaterial->SetTextureParameterValue("Depth", DepthTexture2.Get());
+		DynamicMaterial = UMaterialInstanceDynamic::Create(RegularMaterial.Get(), OptiXContext.Get(), "DynamicNonVRMaterial");
+		DynamicMaterial->SetTextureParameterValue("Texture", OutputTexture.Get());
+		DynamicMaterial->SetTextureParameterValue("Depth", DepthTexture.Get());
 	}
 
-	DynamicMaterialOrtho = UMaterialInstanceDynamic::Create(MonoMaterial.Get(), GetTransientPackage(), "DynamicOrthoMaterial");
-	DynamicMaterialOrtho->SetTextureParameterValue("Texture", OutputTextureOrtho.Get());
-	DynamicMaterialOrtho->SetTextureParameterValue("Depth", DepthTextureOrtho.Get());
-
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Finished Initializing Rendering in ContextManager"));
-	FlushRenderingCommands();
-
+	UE_LOG(LogTemp, Display, TEXT("Finished Initializing Rendering in ContextManager"));
 }
 
 void FOptiXContextManager::InitBuffers()
 {
-	const int32 Mult = bWithHMD ? 2 : 1;
-	OutputBuffer = NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, Width, Height * Mult);
-	OutputDepthBuffer = NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT, Width, Height * Mult);
+	OutputBuffer = OptiXContext->CreateOutputBufferColor(Width, Height);
+	OutputDepthBuffer = OptiXContext->CreateOutputBufferDepth(Width, Height);
 
-	NativeContext["result_color"]->setBuffer(OutputBuffer);
-	NativeContext["result_depth"]->setBuffer(OutputDepthBuffer);
+	OptiXContext->SetBuffer("result_color", OutputBuffer.Get());
+	OptiXContext->SetBuffer("result_depth", OutputDepthBuffer.Get());
 }
 
 void FOptiXContextManager::InitPrograms()
 {
-	//FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
-
-	std::string Dir = std::string(TCHAR_TO_ANSI(*OptiXPTXDir));
+	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
 
 	// Generation Program
-	RayGenerationProgram = NativeContext->createProgramFromPTXFile
+	RayGenerationProgram = OptiXContext->CreateProgramFromPTXFile
 	(
-		Dir + "generated/perspective_camera.ptx",
+		OptiXPTXDir + "generated/perspective_camera.ptx",
 		"pinhole_camera"
 	);
-	NativeContext->setRayGenerationProgram(0, RayGenerationProgram);
+	OptiXContext->SetRayGenerationProgram(0, RayGenerationProgram.Get());
 
 	// Exception program
-	ExceptionProgram = NativeContext->createProgramFromPTXFile
+	ExceptionProgram = OptiXContext->CreateProgramFromPTXFile
 	(
-		Dir + "generated/exception.ptx",
+		OptiXPTXDir + "generated/exception.ptx",
 		"exception"
 	);
-	NativeContext->setExceptionProgram(0, ExceptionProgram);
+	OptiXContext->SetExceptionProgram(0, ExceptionProgram.Get());
 
 	// Miss Program
-	MissProgram = NativeContext->createProgramFromPTXFile
+	MissProgram = OptiXContext->CreateProgramFromPTXFile
 	(
-		Dir + "generated/skybox.ptx",
+		OptiXPTXDir + "generated/skybox.ptx",
 		"skyboxLookup"
 	);
-	NativeContext->setMissProgram(0, MissProgram);
-	NativeContext["bg_color"]->setFloat(1.0, 1.0, 1.0);
+	OptiXContext->SetMissProgram(0, MissProgram.Get());
+	OptiXContext->SetFloat3DVector("bg_color", FVector(1.0, 1.0, 1.0));
 }
 
+
+
 void FOptiXContextManager::InitLaser()
 {
-	std::string Dir = std::string(TCHAR_TO_ANSI(*OptiXPTXDir));
 
-	LaserEntryPoint = NativeContext->getEntryPointCount();
+	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
+
 
-	int32 RayTypeCount = NativeContext->getRayTypeCount();
-	NativeContext->setRayTypeCount(RayTypeCount + 1);
+	LaserEntryPoint = OptiXContext->GetEntryPointCount();
 
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Setting Laser Entry Point to %i"), LaserEntryPoint);
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Setting Ray Type Index to %i"), RayTypeCount);
+	int32 RayTypeCount = OptiXContext->GetRayTypeCount();
+	OptiXContext->SetRayTypeCount(RayTypeCount + 1);
+
+	UE_LOG(LogTemp, Display, TEXT("Setting Laser Entry Point to %i"), LaserEntryPoint);
+	UE_LOG(LogTemp, Display, TEXT("Setting Ray Type Index to %i"), RayTypeCount);
 
 
 	// Increase EntryPointCount by 1
-	NativeContext->setEntryPointCount(LaserEntryPoint + 1);
+	OptiXContext->SetEntryPointCount(LaserEntryPoint + 1);
 
 	// TODO maybe do this explicitely - loads the same program twice, but at least it's clear which one is used then.
 
-	LaserExceptionProgram = NativeContext->createProgramFromPTXFile
+	LaserExceptionProgram = OptiXContext->CreateProgramFromPTXFile
 	(
-		Dir + "generated/exception.ptx",
+		OptiXPTXDir + "generated/exception.ptx",
 		"exception"
 	);
 
-	NativeContext->setExceptionProgram(1 /* todo- diff between raytypeindex and entrypointcount, this is 1 in the original app*/, LaserExceptionProgram);
+	OptiXContext->SetExceptionProgram(1 /* todo- diff between raytypeindex and entrypointcount, this is 1 in the original app*/, LaserExceptionProgram.Get());
 
-	LaserRayGenerationProgram = NativeContext->createProgramFromPTXFile
+	LaserRayGenerationProgram = OptiXContext->CreateProgramFromPTXFile
 	(
-		Dir + "generated/laser_caster.ptx",
+		OptiXPTXDir + "generated/laser_caster.ptx",
 		"laser_caster"
 	);
-	NativeContext->setRayGenerationProgram(LaserEntryPoint, LaserRayGenerationProgram);
+	OptiXContext->SetRayGenerationProgram(LaserEntryPoint, LaserRayGenerationProgram.Get());
 
-	LaserMissProgram = NativeContext->createProgramFromPTXFile
+	LaserMissProgram = OptiXContext->CreateProgramFromPTXFile
 	(
-		Dir + "generated/miss.ptx",
+		OptiXPTXDir + "generated/miss.ptx",
 		"miss_iterative"
 	);
 
-	NativeContext->setMissProgram(1 /*LaserEntryPoint /* this is 1 in the original application, why? TODO*/, LaserMissProgram);
+	OptiXContext->SetMissProgram(1 /*LaserEntryPoint /* this is 1 in the original application, why? TODO*/, LaserMissProgram.Get());
 
-	LaserOutputBuffer = NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, LaserBufferWidth, LaserBufferHeight);
-	NativeContext["result_laser"]->setBuffer(LaserOutputBuffer);
+	//LaserOutputBuffer = OptiXContext->CreateBuffer(RT_BUFFER_OUTPUT, RT_FORMAT_FLOAT4, LaserBufferSize);
+	LaserOutputBuffer = OptiXContext->CreateOutputBufferIntersections(LaserBufferWidth, LaserBufferHeight);
+	LaserOutputBuffer->AddToRoot();
+	OptiXContext->SetBuffer("result_laser", LaserOutputBuffer.Get());
 
-	NativeContext["max_depth_laser"]->setInt(LaserMaxDepth);
+	OptiXContext->SetInt("max_depth_laser", LaserMaxDepth);
 
-	optix::Buffer LaserIndexBuffer = NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_INT, 50, 50);
-	optix::Buffer LaserDirectionBuffer = NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 50, 50);
-	NativeContext["laserIndex"]->setBuffer(LaserIndexBuffer);
-	NativeContext["laserDir"]->setBuffer(LaserDirectionBuffer);
-	NativeContext["laserSize"]->setFloat(3.5f); // Hardcode this for now
+	UOptiXBuffer* LaserIndexBuffer = OptiXContext->CreateBuffer(RT_BUFFER_INPUT, RT_FORMAT_INT, 50, 50);
+	//LaserIndexBuffer->AddToRoot();
+	UOptiXBuffer* LaserDirectionBuffer = OptiXContext->CreateBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 50, 50);
+	//LaserDirectionBuffer->AddToRoot();
+	OptiXContext->SetBuffer("laserIndex", LaserIndexBuffer);
+	OptiXContext->SetBuffer("laserDir", LaserDirectionBuffer);
 
-	bIsInitializedLaser.AtomicSet(true);
 
 }
 
@@ -934,37 +733,39 @@ void FOptiXContextManager::InitCubemap()
 	// TODO: Try and see if destroying/creating the whole thing and doing a memcpy on the GPU only is 
 	// quicker than updating the cubemap each frame.
 
-	CubemapsInputBuffer = NativeContext->createBuffer(RT_BUFFER_INPUT, RTformat::RT_FORMAT_INT, 10);
-	NativeContext["skyboxBuffer"]->setBuffer(CubemapsInputBuffer);
-	
-	CubemapSampler = NativeContext->createTextureSampler();
-	CubemapSampler->setWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
-	CubemapSampler->setWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
-	CubemapSampler->setWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
-	CubemapSampler->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
-	CubemapSampler->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
-	CubemapSampler->setMaxAnisotropy(1.0f);
-	CubemapSampler->setMipLevelCount(1u);
-	CubemapSampler->setArraySize(1u);
+	CubemapsInputBuffer = OptiXContext->CreateBuffer(RT_BUFFER_INPUT, RTformat::RT_FORMAT_INT, 10);
+	OptiXContext->SetBuffer("skyboxBuffer", CubemapsInputBuffer.Get());
 
+	CubemapSampler = OptiXContext->CreateTextureSampler();
+	//CubemapSampler->AddToRoot();
+	CubemapSampler->SetWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
+	CubemapSampler->SetWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
+	CubemapSampler->SetWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
+	CubemapSampler->SetIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
+	CubemapSampler->SetReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
+	CubemapSampler->SetMaxAnisotropy(1.0f);
+	CubemapSampler->SetMipLevelCount(1u);
+	CubemapSampler->SetArraySize(1u);
 
-	CubemapBuffer = NativeContext->createBuffer(RT_BUFFER_INPUT | RT_BUFFER_CUBEMAP, RT_FORMAT_UNSIGNED_BYTE4, 1024, 1024, 6); // 6 slices
 
-	CubemapSampler->setBuffer(0u, 0u, CubemapBuffer);
-	CubemapSampler->setFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
+	CubemapBuffer = OptiXContext->CreateCubemapBuffer(1024, 1024);
+	//CubemapBuffer->AddToRoot();
 
-	NativeContext["skybox0"]->setInt(CubemapSampler->getId());
+	CubemapSampler->SetBufferWithTextureIndexAndMiplevel(0u, 0u, CubemapBuffer.Get());
+	CubemapSampler->SetFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
 
-	AddCubemapToBuffer(0, CubemapSampler->getId());
+	OptiXContext->SetSkybox("skybox0", CubemapSampler.Get());
+
+	//RequestCubemapId();
+	AddCubemapToBuffer(0, CubemapSampler->GetId());
 	
+	//OptiXContext->SetTextureSampler("skybox", CubemapSampler.Get());
 
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Successfully initialized cubemap."));
+	UE_LOG(LogTemp, Display, TEXT("Successfully initialized cubemap."));
 }
 
 int32 FOptiXContextManager::RequestCubemapId()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::RequestCubemapId"))
-
 	if (UnallocatedCubemapIds.IsEmpty())
 	{
 		return 0;
@@ -976,11 +777,9 @@ int32 FOptiXContextManager::RequestCubemapId()
 
 void FOptiXContextManager::DeleteCubemapId(int32 Id)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::DeleteCubemapId"))
-
 	if (Id <= 10)
 	{
-		UE_LOG(OptiXContextManagerLog, Warning, TEXT("Trying to free a cubemap that isn't there."));
+		UE_LOG(LogTemp, Warning, TEXT("Trying to free a cubemap that isn't there."));
 		return;
 	}
 	// The Component itself should handle deletion of the sampler.
@@ -989,8 +788,6 @@ void FOptiXContextManager::DeleteCubemapId(int32 Id)
 
 void FOptiXContextManager::UpdateCubemapBuffer(FRHICommandListImmediate & RHICmdList)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::UpdateCubemapBuffer"))
-
 	if (!CameraActor.IsValid() || bValidCubemap)
 	{
 		return;
@@ -1008,7 +805,9 @@ void FOptiXContextManager::UpdateCubemapBuffer(FRHICommandListImmediate & RHICmd
 	SurfaceDataCube.Empty();
 	SurfaceDataCube.SetNumZeroed(6);
 
-	optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->map());
+	//TArray<FLinearColor> SD;
+
+	optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->MapNative());
 
 	FTextureRenderTargetCubeResource* RenderTargetCube = static_cast<FTextureRenderTargetCubeResource*>(CameraActor->CubeRenderTarget->GetRenderTargetResource());
 
@@ -1035,17 +834,15 @@ void FOptiXContextManager::UpdateCubemapBuffer(FRHICommandListImmediate & RHICmd
 	FMemory::Memcpy(BufferData + X * Y * 4, SurfaceDataCube[4].GetData(), MemSize); // 
 	FMemory::Memcpy(BufferData + X * Y * 5, SurfaceDataCube[5].GetData(), MemSize); //
 
-	CubemapBuffer->unmap();
+	CubemapBuffer->Unmap();
 	bValidCubemap.AtomicSet(true);
 }
 
 void FOptiXContextManager::AddCubemapToBuffer(int32 CubemapId, int32 SamplerId)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::AddCubemapToBuffer"))
-
-	int32* Data = static_cast<int32*>(CubemapsInputBuffer->map());
+	int32* Data = static_cast<int32*>(CubemapsInputBuffer->MapNative());
 	Data[CubemapId] = SamplerId;
-	CubemapsInputBuffer->unmap();
+	CubemapsInputBuffer->Unmap();
 }
 
 void FOptiXContextManager::InitCUDADX()
@@ -1053,69 +850,120 @@ void FOptiXContextManager::InitCUDADX()
 	
 	// Setup DX:
 
-	check(IsInGameThread());
+	D3DDevice = (ID3D11Device*)GDynamicRHI->RHIGetNativeDevice();
+	D3DDevice->GetImmediateContext(&D3DDeviceContext);
 
-	{
-		FD3D11TextureBase* D3D11TextureDepthLeft = GetD3D11TextureFromRHITexture(DepthTexture2->Resource->TextureRHI);
-		cudaGraphicsD3D11RegisterResource(&CudaResourceDepthLeft, D3D11TextureDepthLeft->GetResource(), cudaGraphicsRegisterFlagsNone);
-		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
-	}
-	{
-		FD3D11TextureBase* D3D11TextureColorLeft = GetD3D11TextureFromRHITexture(OutputTexture2->Resource->TextureRHI);
-		cudaGraphicsD3D11RegisterResource(&CudaResourceColorLeft, D3D11TextureColorLeft->GetResource(), cudaGraphicsRegisterFlagsNone);
-		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
-	}
-	if (bWithHMD)
-	{
-		{
-			FD3D11TextureBase* D3D11TextureDepthRight = GetD3D11TextureFromRHITexture(DepthTexture->Resource->TextureRHI);
-			cudaGraphicsD3D11RegisterResource(&CudaResourceDepthRight, D3D11TextureDepthRight->GetResource(), cudaGraphicsRegisterFlagsNone);
-			PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
-		}
-		{
-			FD3D11TextureBase* D3D11TextureColorRight = GetD3D11TextureFromRHITexture(OutputTexture->Resource->TextureRHI);
-			cudaGraphicsD3D11RegisterResource(&CudaResourceColorRight, D3D11TextureColorRight->GetResource(), cudaGraphicsRegisterFlagsNone);
-			PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
-		}
-	}
-	// Intersection
+	// Create texture for now:
 
-	{
-		FD3D11TextureBase* D3D11TextureIntersections = GetD3D11TextureFromRHITexture(LaserIntersectionTexture->Resource->TextureRHI);
-		cudaGraphicsD3D11RegisterResource(&CudaResourceIntersections, D3D11TextureIntersections->GetResource(), cudaGraphicsRegisterFlagsNone);
-		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
-	}
+	OutputTextureDepthLeftRef = ((FTexture2DResource*)DepthTexture2->Resource)->GetTexture2DRHI();
 
-	// Ortho
-	{
-		FD3D11TextureBase* D3D11TextureOrthoDepth = GetD3D11TextureFromRHITexture(DepthTextureOrtho->Resource->TextureRHI);
-		cudaGraphicsD3D11RegisterResource(&CudaResourceDepthOrtho, D3D11TextureOrthoDepth->GetResource(), cudaGraphicsRegisterFlagsNone);
-		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
-	}
-	{
-		FD3D11TextureBase* D3D11TextureOrthoOutput = GetD3D11TextureFromRHITexture(OutputTextureOrtho->Resource->TextureRHI);
-		cudaGraphicsD3D11RegisterResource(&CudaResourceColorOrtho, D3D11TextureOrthoOutput->GetResource(), cudaGraphicsRegisterFlagsNone);
-		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
-	}
+	// Depth Left
+	D3D11_TEXTURE2D_DESC DescDepthLeft;
+	ZeroMemory(&DescDepthLeft, sizeof(D3D11_TEXTURE2D_DESC));
+	ID3D11Texture2D* D3D11DepthLeftTexture = static_cast<ID3D11Texture2D*>(OutputTextureDepthLeftRef->GetNativeResource());
+	D3D11DepthLeftTexture->GetDesc(&DescDepthLeft);
+	UE_LOG(LogTemp, Display, TEXT("ID3D11Texture2D Info Depth: Format is %i"), int(DescDepthLeft.Format));
+
+	// Depth Right
+	OutputTextureDepthRightRef = ((FTexture2DResource*)DepthTexture->Resource)->GetTexture2DRHI();
+
+	D3D11_TEXTURE2D_DESC DescDepthRight;
+	ZeroMemory(&DescDepthRight, sizeof(D3D11_TEXTURE2D_DESC));
+	ID3D11Texture2D* D3D11DepthRightTexture = static_cast<ID3D11Texture2D*>(OutputTextureDepthRightRef->GetNativeResource());
+	D3D11DepthLeftTexture->GetDesc(&DescDepthRight);
+
+	// Depth Ortho
+	OutputTextureDepthOrthoRef = ((FTexture2DResource*)DepthTextureOrtho->Resource)->GetTexture2DRHI();
+
+	D3D11_TEXTURE2D_DESC DescDepthOrtho;
+	ZeroMemory(&DescDepthOrtho, sizeof(D3D11_TEXTURE2D_DESC));
+	ID3D11Texture2D* D3D11DepthOrthoTexture = static_cast<ID3D11Texture2D*>(OutputTextureDepthOrthoRef->GetNativeResource());
+	D3D11DepthOrthoTexture->GetDesc(&DescDepthOrtho);
+
+	// Color Left
+
+	OutputTextureColorLeftRef = ((FTexture2DResource*)OutputTexture2->Resource)->GetTexture2DRHI();
+
+	D3D11_TEXTURE2D_DESC DescColorLeft;
+	ZeroMemory(&DescColorLeft, sizeof(D3D11_TEXTURE2D_DESC));
+	ID3D11Texture2D* D3D11ColorLeftTexture = static_cast<ID3D11Texture2D*>(OutputTextureColorLeftRef->GetNativeResource());
+	D3D11ColorLeftTexture->GetDesc(&DescColorLeft);
+	UE_LOG(LogTemp, Display, TEXT("ID3D11Texture2D Info Color : Format is %i"), int(DescColorLeft.Format));
+
+
+	//// Color Right
+	OutputTextureColorRightRef = ((FTexture2DResource*)OutputTexture->Resource)->GetTexture2DRHI();
+
+	D3D11_TEXTURE2D_DESC DescColorRight;
+	ZeroMemory(&DescColorRight, sizeof(D3D11_TEXTURE2D_DESC));
+	ID3D11Texture2D* D3D11ColorRightTexture = static_cast<ID3D11Texture2D*>(OutputTextureColorRightRef->GetNativeResource());
+	D3D11ColorRightTexture->GetDesc(&DescColorRight);
+
+	//// Color Right
+	OutputTextureColorOrthoRef = ((FTexture2DResource*)OutputTextureOrtho->Resource)->GetTexture2DRHI();
+
+	D3D11_TEXTURE2D_DESC DescColorOrtho;
+	ZeroMemory(&DescColorOrtho, sizeof(D3D11_TEXTURE2D_DESC));
+	ID3D11Texture2D* D3D11ColorOrthoTexture = static_cast<ID3D11Texture2D*>(OutputTextureColorOrthoRef->GetNativeResource());
+	D3D11ColorOrthoTexture->GetDesc(&DescColorOrtho);
+	
+
+	//// Intersections
+	LaserIntersectionTextureRef = ((FTexture2DResource*)LaserIntersectionTexture->Resource)->GetTexture2DRHI();
+
+	D3D11_TEXTURE2D_DESC DescIntersections;
+	ZeroMemory(&DescIntersections, sizeof(D3D11_TEXTURE2D_DESC));
+	ID3D11Texture2D* D3D11IntersectionTexture = static_cast<ID3D11Texture2D*>(LaserIntersectionTextureRef->GetNativeResource());
+	D3D11IntersectionTexture->GetDesc(&DescIntersections);
 	
-	cudaMalloc((void**)&CudaLinearMemoryDepth, Width * Height * sizeof(float) * 2);
+
+	// Register the unreal textures with cuda
+	cudaGraphicsD3D11RegisterResource(&CudaResourceDepthLeft, D3D11DepthLeftTexture, cudaGraphicsRegisterFlagsNone);
+	PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+
+	cudaGraphicsD3D11RegisterResource(&CudaResourceDepthRight, D3D11DepthRightTexture, cudaGraphicsRegisterFlagsNone);
+	PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+
+	cudaGraphicsD3D11RegisterResource(&CudaResourceColorLeft, D3D11ColorLeftTexture, cudaGraphicsRegisterFlagsNone);
+	PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+
+	cudaGraphicsD3D11RegisterResource(&CudaResourceColorRight, D3D11ColorRightTexture, cudaGraphicsRegisterFlagsNone);
+	PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+
+	cudaGraphicsD3D11RegisterResource(&CudaResourceIntersections, D3D11IntersectionTexture, cudaGraphicsRegisterFlagsNone);
+	PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+
+	cudaGraphicsD3D11RegisterResource(&CudaResourceDepthOrtho, D3D11DepthOrthoTexture, cudaGraphicsRegisterFlagsNone);
+	PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+
+	cudaGraphicsD3D11RegisterResource(&CudaResourceColorOrtho, D3D11ColorOrthoTexture, cudaGraphicsRegisterFlagsNone);
+	PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+
+	// Allocate the buffer memory
+	//cudaMallocPitch(&CudaLinearMemoryDepth, &Pitch, Width * sizeof(float), Height);
+	cudaMalloc(&CudaLinearMemoryDepth, Width * Height * sizeof(float));
 	PrintLastCudaError("cudaMalloc");
 
-	cudaMalloc((void**)&CudaLinearMemoryColor, Width * Height * 4 * sizeof(float) * 2);
+	cudaMalloc(&CudaLinearMemoryColor, Width * Height * 4 * sizeof(float));
 	PrintLastCudaError("cudaMalloc");
 
 	cudaMalloc(&CudaLinearMemoryIntersections, LaserBufferWidth * LaserBufferHeight * 4 * sizeof(float));
 	PrintLastCudaError("cudaMalloc");
-	
-	NativeContext["result_depth"]->getBuffer()->setDevicePointer(0, CudaLinearMemoryDepth);
-	NativeContext["result_color"]->getBuffer()->setDevicePointer(0, CudaLinearMemoryColor);
-	NativeContext["result_laser"]->getBuffer()->setDevicePointer(0, CudaLinearMemoryIntersections);
 
-	FString DeviceName = FString(NativeContext->getDeviceName(0).c_str());
+	//cudaMallocPitch(&CudaLinearMemoryColorRight, &Pitch, Width * sizeof(optix::uchar4), Height);
+	//PrintLastCudaError("cudaMallocPitch");
+
+	//cudaMemset(CudaLinearMemory, 1, Pitch * Height);
+	//PrintLastCudaError("cudaMemset");
+
+	OptiXContext->GetBuffer("result_depth")->SetDevicePointer(0, CudaLinearMemoryDepth);
+	OptiXContext->GetBuffer("result_color")->SetDevicePointer(0, CudaLinearMemoryColor);
+	OptiXContext->GetBuffer("result_laser")->SetDevicePointer(0, CudaLinearMemoryIntersections);
+
+
+	UE_LOG(LogTemp, Display, TEXT("Device Count: %i"), OptiXContext->GetDeviceCount());
+	UE_LOG(LogTemp, Display, TEXT("Device Name 0: %s"), *OptiXContext->GetDeviceName(0));
 
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Device Count: %i"), NativeContext->getDeviceCount());
-	UE_LOG(OptiXContextManagerLog, Display, TEXT("Device Name 0: %s"), *DeviceName);
-	
 
 	Resources[0] = CudaResourceDepthLeft;
 	Resources[1] = CudaResourceColorLeft;
@@ -1125,730 +973,6 @@ void FOptiXContextManager::InitCUDADX()
 	Resources[5] = CudaResourceColorOrtho;
 	Resources[6] = CudaResourceDepthOrtho;
 
-	bIsInitializedCuda.AtomicSet(true);
-}
+	bIsInitialized = true;
 
-void FOptiXContextManager::RequestNewOptiXBuffer(UniqueId ObjectId, FOptiXBufferData BufferData)
-{
-	OptiXBuffersToCreate.Enqueue(TPair<UniqueId, FOptiXBufferData>(ObjectId, BufferData));
 }
-
-
-void FOptiXContextManager::RequestNewOptiXGroup(UniqueId ObjectId)
-{
-
-}
-
-void FOptiXContextManager::RequestNewOptiXTextureSampler(UniqueId ObjectId)
-{
-	OptiXTextureSamplersToCreate.Enqueue(ObjectId);
-}
-
-void FOptiXContextManager::RequestDestroyOptiXObjects(UniqueId ObjectId)
-{
-	if(bIsInitializedAll)
-		OptiXObjectsToDestroy.Enqueue(ObjectId);
-}
-
-void FOptiXContextManager::RequestNewOptiXObject(UniqueId ObjectId, FString Program)
-{
-	OptiXObjectsToCreate.Enqueue(TPair<UniqueId, FString>(ObjectId, Program));
-}
-
-void FOptiXContextManager::RequestLensCubemapUpdate(UniqueId ObjectId, CubemapUpdateFunction UpdateFunction)
-{
-	CubemapsToUpdate.Enqueue(TPair<UniqueId, CubemapUpdateFunction>(ObjectId, UpdateFunction));
-}
-
-void FOptiXContextManager::EnqueueUpdateFunction(UniqueId ObjectId, OptiXObjectUpdateFunction UpdateFunction)
-{
-	OptiXObjectUpdateFunctions.Enqueue(TPair<UniqueId, OptiXObjectUpdateFunction>(ObjectId, UpdateFunction));
-}
-
-void FOptiXContextManager::EnqueueContextUpdateFunction(OptiXContextUpdateFunction UpdateFunction)
-{
-	OptiXContextUpdateQueue.Enqueue(UpdateFunction);
-}
-
-void FOptiXContextManager::EnqueueUpdateFunctionRHI(UniqueId ObjectId, OptiXObjectUpdateFunctionRHI UpdateFunction)
-{
-	OptiXObjectUpdateFunctionsRHI.Enqueue(TPair<UniqueId, OptiXObjectUpdateFunctionRHI>(ObjectId, UpdateFunction));
-}
-
-void FOptiXContextManager::EnqueueInitFunction(UniqueId ObjectId, OptiXObjectInitFunction InitFuntion)
-{
-	OptiXObjectInitFunctions.Enqueue(TPair<UniqueId, OptiXObjectUpdateFunction>(ObjectId, InitFuntion));
-}
-
-void FOptiXContextManager::RegisterLaserTraceCallback(UniqueId ObjectId, LaserTraceFinishedCallback Callback)
-{
-	LaserTraceFinishedCallbacks.Add(ObjectId, Callback);
-}
-
-void FOptiXContextManager::CreateNewOptiXObject(UniqueId ObjectId, FString Program)
-{
-	// Geometry
-	//NativeContext->validate();
-
-	FOptiXObjectData Data;
-
-	Data.OptiXGeometry = NativeContext->createGeometry();
-	Data.OptiXGeometry->setPrimitiveCount(1u);
-
-
-	FString PathGeometryPTX = OptiXPTXDir + "generated/" + Program + ".ptx";
-
-	std::string PG = std::string(TCHAR_TO_ANSI(*PathGeometryPTX));
-	optix::Program NewBoundingBoxProg = NativeContext->createProgramFromPTXFile(PG, "bounds");
-	optix::Program NewIntersectionProg = NativeContext->createProgramFromPTXFile(PG, "intersect");
-
-	// Material 
-	Data.OptiXMaterial = NativeContext->createMaterial();
-
-	FString PathMaterialPTX = OptiXPTXDir + "generated/" + Program + "_material.ptx";
-
-	std::string PM = std::string(TCHAR_TO_ANSI(*PathMaterialPTX));
-
-	optix::Program CHPerspective = NativeContext->createProgramFromPTXFile(PM, "closest_hit_radiance");
-	optix::Program CHIterative = NativeContext->createProgramFromPTXFile(PM, "closest_hit_iterative");
-
-	Data.OptiXPrograms =
-		TTuple<optix::Program, optix::Program, optix::Program, optix::Program>(NewBoundingBoxProg, NewIntersectionProg, CHPerspective, CHIterative);
-
-	Data.OptiXGeometry->setBoundingBoxProgram(NewBoundingBoxProg);
-	Data.OptiXGeometry->setIntersectionProgram(NewIntersectionProg);
-	Data.OptiXMaterial->setClosestHitProgram(0, CHPerspective);
-	Data.OptiXMaterial->setClosestHitProgram(1, CHIterative);
-	// Instance
-	Data.OptiXGeometryInstance = NativeContext->createGeometryInstance();
-	Data.OptiXGeometryInstance->setGeometry(Data.OptiXGeometry);
-	Data.OptiXGeometryInstance->addMaterial(Data.OptiXMaterial);
-
-	// Transform
-	Data.OptiXTransform = NativeContext->createTransform();
-
-	// Acceleration
-	Data.OptiXAcceleration = NativeContext->createAcceleration("NoAccel");
-
-	Data.OptiXGeometryGroup = NativeContext->createGeometryGroup();
-	Data.OptiXGeometryGroup->addChild(Data.OptiXGeometryInstance);
-	Data.OptiXGeometryGroup->setAcceleration(Data.OptiXAcceleration);
-
-	Data.OptiXTransform->setChild(Data.OptiXGeometryGroup);
-
-	TopObject->addChild(Data.OptiXTransform);
-	//TopObject->getAcceleration()->markDirty();
-
-	OptiXObjectData.Add(ObjectId, Data);
-}
-
-void FOptiXContextManager::CreateNewOptiXBuffer(UniqueId ObjectId, FOptiXBufferData BufferData)
-{
-	if (!OptiXBuffers.Contains(ObjectId))
-	{
-		OptiXBuffers.Add(ObjectId, TMap<FString, optix::Buffer>());
-	}
-	optix::Buffer NewBuffer;
-	if (BufferData.BufferHeight == 0)
-	{
-		NewBuffer = NativeContext->createBuffer(BufferData.Type, BufferData.Format, BufferData.BufferWidth);
-	}
-	else if (BufferData.BufferDepth == 0)
-	{
-		NewBuffer = NativeContext->createBuffer(BufferData.Type, BufferData.Format, BufferData.BufferWidth, BufferData.BufferHeight);
-	}
-	else
-	{
-		NewBuffer = NativeContext->createBuffer(BufferData.Type, BufferData.Format, BufferData.BufferWidth, BufferData.BufferHeight, BufferData.BufferDepth);
-	}
-
-	OptiXBuffers[ObjectId].Add(BufferData.Name, NewBuffer);
-}
-
-void FOptiXContextManager::CreateNewOptiXTextureSampler(UniqueId ObjectId)
-{
-	// Find the corresponding sampler
-	optix::TextureSampler Sampler = nullptr;
-	if (OptiXTextureSamplers.Contains(ObjectId))
-	{
-		UE_LOG(OptiXContextManagerLog, Warning, TEXT("A Texture Sampler already exists for %i"), ObjectId);
-		OptiXTextureSamplers[ObjectId]->destroy();
-		OptiXTextureSamplers[ObjectId] = NativeContext->createTextureSampler();
-	}
-	else
-	{
-		optix::TextureSampler NewSampler = NativeContext->createTextureSampler();
-		OptiXTextureSamplers.Add(ObjectId, NewSampler);
-	}
-}
-
-void FOptiXContextManager::ExecuteOptiXUpdate(UniqueId ObjectId, OptiXObjectUpdateFunction UpdateFunction)
-{
-	// Get the required parameters
-
-	optix::TextureSampler Sampler = nullptr;
-	TMap<FString, optix::Buffer>* BufferMap = nullptr;
-	FOptiXObjectData* Data = nullptr;
-	if (OptiXTextureSamplers.Contains(ObjectId))
-	{
-		Sampler = OptiXTextureSamplers[ObjectId];
-	}
-	if (OptiXBuffers.Contains(ObjectId))
-	{
-		BufferMap = &OptiXBuffers[ObjectId];
-	}
-	if (OptiXObjectData.Contains(ObjectId))
-	{
-		Data = &OptiXObjectData[ObjectId];
-	}
-	UpdateFunction(Data, BufferMap, Sampler);
-}
-
-void FOptiXContextManager::ExecuteOptiXUpdateRHI(UniqueId ObjectId, FRHICommandListImmediate& RHICmdList, OptiXObjectUpdateFunctionRHI UpdateFunction)
-{
-	// Get the required parameters
-
-	optix::TextureSampler Sampler = nullptr;
-	TMap<FString, optix::Buffer>* BufferMap = nullptr;
-	FOptiXObjectData* Data = nullptr;
-	if (OptiXTextureSamplers.Contains(ObjectId))
-	{
-		Sampler = OptiXTextureSamplers[ObjectId];
-	}
-	if (OptiXBuffers.Contains(ObjectId))
-	{
-		BufferMap = &OptiXBuffers[ObjectId];
-	}
-	if (OptiXObjectData.Contains(ObjectId))
-	{
-		Data = &OptiXObjectData[ObjectId];
-	}
-	UpdateFunction(Data, BufferMap, Sampler, RHICmdList);
-}
-
-void FOptiXContextManager::ExecuteContextUpdate(OptiXContextUpdateFunction UpdateFunction)
-{
-	UpdateFunction(NativeContext);
-}
-
-
-void FOptiXContextManager::DestroyOptiXObjects(UniqueId ObjectId)
-{
-	// Does the order matter?
-
-	// Remove buffers first, as they can have no children
-	if (OptiXBuffers.Contains(ObjectId))
-	{
-		TMap<FString, optix::Buffer> Buffers = OptiXBuffers.FindAndRemoveChecked(ObjectId);
-		for (TPair<FString, optix::Buffer>& Pair : Buffers)
-		{
-			Pair.Value->destroy();
-			Pair.Value = NULL;
-		}
-	}
-
-	// Remove callbacks
-	if (LaserTraceFinishedCallbacks.Contains(ObjectId))
-	{
-		LaserTraceFinishedCallbacks.FindAndRemoveChecked(ObjectId);
-	}
-
-	// Remove any texture samplers
-	if (OptiXTextureSamplers.Contains(ObjectId))
-	{
-		optix::TextureSampler Sampler = OptiXTextureSamplers.FindAndRemoveChecked(ObjectId);
-		Sampler->destroy();
-	}
-
-	// Clean up the ObjectData
-	if (OptiXObjectData.Contains(ObjectId))
-	{
-		FOptiXObjectData Data = OptiXObjectData.FindAndRemoveChecked(ObjectId);
-		
-
-		TopObject->removeChild(Data.OptiXTransform);
-
-		Data.OptiXTransform->destroy();
-		Data.OptiXTransform = NULL;
-
-		Data.OptiXGeometryGroup->removeChild(0);
-
-		Data.OptiXGeometryGroup->destroy();
-		Data.OptiXGeometryGroup = NULL;
-
-		Data.OptiXGeometryInstance->destroy();
-		Data.OptiXGeometryInstance = NULL;
-
-		Data.OptiXAcceleration->destroy();
-		Data.OptiXAcceleration = NULL;
-
-		Data.OptiXMaterial->destroy();
-		Data.OptiXMaterial = NULL;
-
-		Data.OptiXGeometry->destroy();
-		Data.OptiXGeometry = NULL;
-
-		Data.OptiXPrograms.Get<0>()->destroy();
-		Data.OptiXPrograms.Get<0>() = NULL;
-
-		Data.OptiXPrograms.Get<1>()->destroy();
-		Data.OptiXPrograms.Get<1>() = NULL;
-
-		Data.OptiXPrograms.Get<2>()->destroy();
-		Data.OptiXPrograms.Get<2>() = NULL;
-
-		Data.OptiXPrograms.Get<3>()->destroy();
-		Data.OptiXPrograms.Get<3>() = NULL;
-
-		TopAcceleration->markDirty();
-
-	}
-	// This should never happen
-	if (OptiXGroups.Contains(ObjectId))
-	{
-		optix::Group Group = OptiXGroups.FindAndRemoveChecked(ObjectId);
-		Group->destroy();
-	}
-}
-
-void FOptiXContextManager::InitializeOptiXObject(UniqueId ObjectId, OptiXObjectInitFunction InitFunction)
-{
-	// Get the required parameters
-
-	optix::TextureSampler Sampler = nullptr;
-	TMap<FString, optix::Buffer>* BufferMap = nullptr;
-	FOptiXObjectData* Data = nullptr;
-	if (OptiXTextureSamplers.Contains(ObjectId))
-	{
-		Sampler = OptiXTextureSamplers[ObjectId];
-	}
-	if (OptiXBuffers.Contains(ObjectId))
-	{
-		BufferMap = &OptiXBuffers[ObjectId];
-	}
-	if (OptiXObjectData.Contains(ObjectId))
-	{
-		Data = &OptiXObjectData[ObjectId];
-	}
-	InitFunction(Data, BufferMap, Sampler);
-}
-
-void FOptiXContextManager::UpdateCubemap(UniqueId ObjectId, FRHICommandListImmediate & RHICmdList, CubemapUpdateFunction UpdateFunction)
-{
-	if (OptiXBuffers.Contains(ObjectId))
-	{
-		optix::Buffer Buffer = OptiXBuffers[ObjectId]["texture_buffer"];
-		UpdateFunction(Buffer, RHICmdList);
-	}		
-}
-
-
-void FOptiXContextManager::ParseCreationQueue()
-{
-	for (uint32 i = 0; i < 100 && !OptiXObjectsToCreate.IsEmpty(); i++)
-	{
-		TPair<UniqueId, FString> QueueItem;
-		if (OptiXObjectsToCreate.Dequeue(QueueItem))
-		{
-			CreateNewOptiXObject(QueueItem.Get<0>(), QueueItem.Get<1>());
-		}
-	}
-	for (uint32 i = 0; i < 100 && !OptiXBuffersToCreate.IsEmpty(); i++)
-	{
-		TPair<UniqueId, FOptiXBufferData> QueueItem;
-		if (OptiXBuffersToCreate.Dequeue(QueueItem))
-		{
-			CreateNewOptiXBuffer(QueueItem.Get<0>(), QueueItem.Get<1>());
-		}
-	}
-	for (uint32 i = 0; i < 100 && !OptiXTextureSamplersToCreate.IsEmpty(); i++)
-	{
-		UniqueId QueueItem;
-		if (OptiXTextureSamplersToCreate.Dequeue(QueueItem))
-		{
-			CreateNewOptiXTextureSampler(QueueItem);
-		}
-	}
-}
-void FOptiXContextManager::ParseInitQueue()
-{
-	for (uint32 i = 0; i < 100 && !OptiXObjectInitFunctions.IsEmpty(); i++)
-	{
-		TPair<UniqueId, OptiXObjectInitFunction> QueueItem;
-		if (OptiXObjectInitFunctions.Dequeue(QueueItem))
-		{
-			InitializeOptiXObject(QueueItem.Key, QueueItem.Value);
-		}
-	}
-}
-void FOptiXContextManager::ParseUpdateQueue(FRHICommandListImmediate & RHICmdList)
-{
-	for (uint32 i = 0; i < 100 && !OptiXObjectUpdateFunctions.IsEmpty(); i++)
-	{
-		TPair<UniqueId, OptiXObjectUpdateFunction> QueueItem;
-		if (OptiXObjectUpdateFunctions.Dequeue(QueueItem))
-		{
-			ExecuteOptiXUpdate(QueueItem.Key, QueueItem.Value);
-		}
-	}
-	for (uint32 i = 0; i < 100 && !OptiXObjectUpdateFunctionsRHI.IsEmpty(); i++)
-	{
-		TPair<UniqueId, OptiXObjectUpdateFunctionRHI> QueueItem;
-		if (OptiXObjectUpdateFunctionsRHI.Dequeue(QueueItem))
-		{
-			ExecuteOptiXUpdateRHI(QueueItem.Key, RHICmdList, QueueItem.Value);
-		}
-	}
-	for (uint32 i = 0; i < 100 && !OptiXContextUpdateQueue.IsEmpty(); i++)
-	{
-		OptiXContextUpdateFunction QueueItem;
-		if (OptiXContextUpdateQueue.Dequeue(QueueItem))
-		{
-			ExecuteContextUpdate(QueueItem);
-		}
-	}
-}
-void FOptiXContextManager::ParseDestroyQueue()
-{
-	for (uint32 i = 0; i < 100 && !OptiXObjectsToDestroy.IsEmpty(); i++)
-	{
-		UniqueId QueueItem;
-		if (OptiXObjectsToDestroy.Dequeue(QueueItem))
-		{
-			DestroyOptiXObjects(QueueItem);
-		}
-	}
-}
-
-void FOptiXContextManager::ParseCubemapUpdateQueue(FRHICommandListImmediate & RHICmdList)
-{
-	for (uint32 i = 0; i < 100 && !CubemapsToUpdate.IsEmpty(); i++)
-	{
-		TPair<UniqueId, CubemapUpdateFunction> QueueItem;
-		if (CubemapsToUpdate.Dequeue(QueueItem))
-		{
-			UpdateCubemap(QueueItem.Key, RHICmdList, QueueItem.Value);
-		}
-	}
-}
-
-
-void FOptiXContextManager::LaserPositionLateUpdate_RenderThread(const FTransform LateUpdateTransform)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaserPositionLateUpdate_RenderThread")
-
-	FVector Translation = LateUpdateTransform.GetTranslation();
-	FVector Forward = LateUpdateTransform.GetUnitAxis(EAxis::X);
-	FVector Right = LateUpdateTransform.GetUnitAxis(EAxis::Y);
-	FVector Up = LateUpdateTransform.GetUnitAxis(EAxis::Z);
-	FMatrix Rotation = LateUpdateTransform.ToMatrixNoScale();
-
-	// Only late-update the origin. Grabbing something with the motion controller should only change the translational part anyway,
-	// NEVER the rotation. 
-
-	NativeContext["laser_origin"]->setFloat(Translation.X, Translation.Y, Translation.Z);
-	NativeContext["laser_forward"]->setFloat(Forward.X, Forward.Y, Forward.Z);
-	NativeContext["laser_right"]->setFloat(Right.X, Right.Y, Right.Z);
-	NativeContext["laser_up"]->setFloat(Up.X, Up.Y, Up.Z);
-
-	NativeContext["laser_rot"]->setMatrix4x4fv(true, &Rotation.M[0][0]);
-}
-
-void FOptiXContextManager::ObjectPositionLateUpdate_RenderThread(UniqueId ObjectId, const FMatrix LateUpdateTransform)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::ObjectPositionLateUpdate_RenderThread")	
-	if (OptiXObjectData.Contains(ObjectId))
-	{
-		FMatrix Update = FMatrix(LateUpdateTransform);
-		FMatrix Inverse = Update.Inverse();
-		FOptiXObjectData Data = OptiXObjectData[ObjectId];
-		Data.OptiXTransform->setMatrix(true, &Update.M[0][0], &Inverse.M[0][0]);
-		Data.OptiXAcceleration->markDirty();
-		Data.OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-	}
-}
-
-// Cleanup functions
-
-void FOptiXContextManager::CleanupCuda()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::CleanupCuda"))
-
-	if (CudaResourceDepthLeft != NULL)
-		cudaGraphicsUnregisterResource(CudaResourceDepthLeft);
-	PrintLastCudaError("cudaGraphicsUnregisterResource");
-
-	if (CudaResourceColorLeft != NULL)
-		cudaGraphicsUnregisterResource(CudaResourceColorLeft);
-	PrintLastCudaError("cudaGraphicsUnregisterResource");
-
-	if (bWithHMD)
-	{
-		if (CudaResourceDepthRight != NULL)
-			cudaGraphicsUnregisterResource(CudaResourceDepthRight);
-		PrintLastCudaError("cudaGraphicsUnregisterResource");
-
-		if (CudaResourceColorRight != NULL)
-			cudaGraphicsUnregisterResource(CudaResourceColorRight);
-		PrintLastCudaError("cudaGraphicsUnregisterResource");
-	}
-		
-	if (CudaResourceDepthOrtho != NULL)
-		cudaGraphicsUnregisterResource(CudaResourceDepthOrtho);
-	PrintLastCudaError("cudaGraphicsUnregisterResource");
-
-	if (CudaResourceColorOrtho != NULL)
-		cudaGraphicsUnregisterResource(CudaResourceColorOrtho);
-	PrintLastCudaError("cudaGraphicsUnregisterResource");
-
-	if (CudaResourceIntersections != NULL)
-		cudaGraphicsUnregisterResource(CudaResourceIntersections);
-	PrintLastCudaError("cudaGraphicsUnregisterResource");
-
-	if (CudaLinearMemoryDepth != NULL)
-		cudaFree(CudaLinearMemoryDepth);
-	if (CudaLinearMemoryColor != NULL)
-		cudaFree(CudaLinearMemoryColor);
-	if (CudaLinearMemoryIntersections != NULL)
-		cudaFree(CudaLinearMemoryIntersections);
-	PrintLastCudaError("cudaFree");
-}
-
-void FOptiXContextManager::CleanupLocalOptiXObjects()
-{
-	if (LaserOutputBuffer != NULL)
-	{
-		LaserOutputBuffer->destroy();
-		LaserOutputBuffer = NULL;
-	}
-	if (LaserRayGenerationProgram != NULL)
-	{
-		LaserRayGenerationProgram->destroy();
-		LaserRayGenerationProgram = NULL;
-	}
-	if (LaserMissProgram != NULL)
-	{
-		LaserMissProgram->destroy();
-		LaserMissProgram = NULL;
-	}
-	if (LaserExceptionProgram != NULL)
-	{
-		LaserExceptionProgram->destroy();
-		LaserExceptionProgram = NULL;
-	}
-
-
-	if (RayGenerationProgram != NULL)
-	{
-		RayGenerationProgram->destroy();
-		RayGenerationProgram = NULL;
-	}
-	if (MissProgram != NULL)
-	{
-		MissProgram->destroy();
-		MissProgram = NULL;
-	}
-	if (ExceptionProgram != NULL)
-	{
-		ExceptionProgram->destroy();
-		ExceptionProgram = NULL;
-	}
-
-	if (CubemapSampler != NULL)
-	{
-		CubemapSampler->destroy();
-		CubemapSampler = NULL;
-	}
-	if (CubemapBuffer != NULL)
-	{
-		CubemapBuffer->destroy();
-		CubemapBuffer = NULL;
-	}
-	if (CubemapsInputBuffer != NULL)
-	{
-		CubemapsInputBuffer->destroy();
-		CubemapsInputBuffer = NULL;
-	}
-
-	if (OutputBuffer != NULL)
-	{
-		OutputBuffer->destroy();
-		OutputBuffer = NULL;
-	}
-	if (OutputDepthBuffer != NULL)
-	{
-		OutputDepthBuffer->destroy();
-		OutputDepthBuffer = NULL;
-	}
-
-	if (TopAcceleration != NULL)
-	{
-		TopAcceleration->destroy();
-		TopAcceleration = NULL;
-	}
-	if (TopObject != NULL)
-	{
-		TopObject->destroy();
-		TopObject = NULL;
-	}
-
-	if (NativeContext != NULL)
-	{
-		NativeContext->destroy();
-		NativeContext = NULL;
-	}
-}
-
-void FOptiXContextManager::Cleanup_RenderThread()
-{
-	bIsInitializedAll.AtomicSet(false);
-	OptiXContextUpdateManager->bIsActive = false;
-	CleanupCuda();
-
-
-	for (auto& Pair : OptiXBuffers)
-	{
-		for (TPair<FString, optix::Buffer>& BufferPair : Pair.Value)
-		{
-			BufferPair.Value->destroy();
-			BufferPair.Value = NULL;
-		}
-		Pair.Value.Empty();
-	}
-	OptiXBuffers.Empty();
-
-	for (auto& Pair : OptiXTextureSamplers)
-	{
-		Pair.Value->destroy();
-		Pair.Value = NULL;
-	}
-	OptiXTextureSamplers.Empty();
-
-	for (auto& Pair : OptiXObjectData)
-	{
-		Pair.Value.OptiXTransform->destroy();
-		Pair.Value.OptiXTransform = NULL;
-
-		Pair.Value.OptiXGeometryGroup->destroy();
-		Pair.Value.OptiXGeometryGroup = NULL;
-
-		Pair.Value.OptiXGeometryInstance->destroy();
-		Pair.Value.OptiXGeometryInstance = NULL;
-
-		Pair.Value.OptiXAcceleration->destroy();
-		Pair.Value.OptiXAcceleration = NULL;
-
-		Pair.Value.OptiXMaterial->destroy();
-		Pair.Value.OptiXMaterial = NULL;
-
-		Pair.Value.OptiXGeometry->destroy();
-		Pair.Value.OptiXGeometry = NULL;
-
-		Pair.Value.OptiXPrograms.Get<0>()->destroy();
-		Pair.Value.OptiXPrograms.Get<0>() = NULL;
-
-		Pair.Value.OptiXPrograms.Get<1>()->destroy();
-		Pair.Value.OptiXPrograms.Get<1>() = NULL;
-
-		Pair.Value.OptiXPrograms.Get<2>()->destroy();
-		Pair.Value.OptiXPrograms.Get<2>() = NULL;
-
-		Pair.Value.OptiXPrograms.Get<3>()->destroy();
-		Pair.Value.OptiXPrograms.Get<3>() = NULL;
-	}
-	OptiXObjectData.Empty();
-
-	for (auto& Pair : OptiXGroups)
-	{		
-		Pair.Value->destroy();
-		Pair.Value = NULL;
-	}
-	OptiXGroups.Empty();
-
-	CleanupLocalOptiXObjects();
-
-	// Empty queues
-	OptiXObjectsToCreate.Empty();
-	OptiXObjectInitFunctions.Empty();
-	OptiXObjectUpdateFunctions.Empty();
-	OptiXObjectUpdateFunctionsRHI.Empty();
-
-	OptiXBuffersToCreate.Empty();
-	OptiXTextureSamplersToCreate.Empty();
-	CubemapsToUpdate.Empty();
-	OptiXContextUpdateQueue.Empty();
-	OptiXObjectsToDestroy.Empty();
-}
-
-void FOptiXContextManager::Cleanup_GameThread()
-{
-	// Laser stuff
-	IntersectionData.Empty();
-	OldIntersectionData.Empty();
-	LaserIntersectionQueue.Empty();
-	PreviousLaserResults.Empty();
-	
-	LaserIntersectionTexture->RemoveFromRoot();
-	LaserMaterialDynamic->RemoveFromRoot();
-	LaserMaterial->RemoveFromRoot();
-
-	LaserIntersectionTexture->ConditionalBeginDestroy();
-	//LaserMaterialDynamic->ConditionalBeginDestroy();
-	//LaserMaterial->ConditionalBeginDestroy();
-
-	LaserIntersectionTexture.Reset();
-	LaserMaterialDynamic.Reset();
-	LaserMaterial.Reset();
-
-	// Rendering
-
-	if (bWithHMD)
-	{
-		OutputTexture->RemoveFromRoot();
-		DepthTexture->RemoveFromRoot();
-	}
-	OutputTexture2->RemoveFromRoot();
-	DepthTexture2->RemoveFromRoot();
-	OutputTextureOrtho->RemoveFromRoot();
-	DepthTextureOrtho->RemoveFromRoot();
-	DynamicMaterial->RemoveFromRoot();
-	DynamicMaterialOrtho->RemoveFromRoot();
-	MonoMaterial->RemoveFromRoot();
-	VRMaterial->RemoveFromRoot();
-
-	if (bWithHMD)
-	{
-		OutputTexture->ConditionalBeginDestroy();
-		DepthTexture->ConditionalBeginDestroy();
-	}
-	OutputTexture2->ConditionalBeginDestroy();
-	DepthTexture2->ConditionalBeginDestroy();
-	OutputTextureOrtho->ConditionalBeginDestroy();
-	DepthTextureOrtho->ConditionalBeginDestroy();
-	//DynamicMaterial->ConditionalBeginDestroy();
-	//DynamicMaterialOrtho->ConditionalBeginDestroy();
-	//RegularMaterial->ConditionalBeginDestroy();
-	//VRMaterial->ConditionalBeginDestroy();
-
-	OutputTexture.Reset();
-	DepthTexture.Reset();
-	OutputTexture2.Reset();
-	DepthTexture2.Reset();
-	OutputTextureOrtho.Reset();
-	DepthTextureOrtho.Reset();
-	DynamicMaterial.Reset();
-	DynamicMaterialOrtho.Reset();
-	MonoMaterial.Reset();
-	VRMaterial.Reset();
-
-	// Other
-	LaserActor.Reset();
-	CameraActor.Reset();
-
-	UnallocatedCubemapIds.Empty();
-	SurfaceDataCube.Empty();
-
-	LaserTraceFinishedCallbacks.Empty();
-
-}
-
diff --git a/Source/OptiX/Private/OptiXCubemapLateUpdateComponent.cpp b/Source/OptiX/Private/OptiXCubemapLateUpdateComponent.cpp
deleted file mode 100644
index fd4ef9d69842aff9cb24995d89f65784f5f87bc6..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/OptiXCubemapLateUpdateComponent.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-
-#include "OptiXCubemapLateUpdateComponent.h"
-
-#include "PrimitiveSceneProxy.h"
-#include "OptiXModule.h"
-
-FPrimitiveSceneProxy* UOptiXCubemapLateUpdateComponent::CreateSceneProxy()
-{
-	class FOptiXCubemapComponentSceneProxy final : public FPrimitiveSceneProxy
-	{
-	public:
-		SIZE_T GetTypeHash() const override
-		{
-			static size_t UniquePointer;
-			return reinterpret_cast<size_t>(&UniquePointer);
-		}
-
-		/** Initialization constructor. */
-		FOptiXCubemapComponentSceneProxy(const UOptiXCubemapLateUpdateComponent* InComponent)
-			: FPrimitiveSceneProxy(InComponent), UniqueId(InComponent->GetOptiXComponentId())
-		{
-		}
-
-		// FPrimitiveSceneProxy interface.
-
-		virtual void ApplyLateUpdateTransform(const FMatrix& LateUpdateTransform) override
-		{
-
-			FMatrix NewTransform = GetLocalToWorld() * LateUpdateTransform;
-			FVector OriginChange = NewTransform.GetOrigin() - GetLocalToWorld().GetOrigin();
-			FMatrix ReducedLateUpdate = FMatrix::Identity;
-			ReducedLateUpdate.SetOrigin(OriginChange);
-
-			FPrimitiveSceneProxy::ApplyLateUpdateTransform(ReducedLateUpdate);
-
-
-			//FMatrix CachedTransform = GetLocalToWorld();
-			//FPrimitiveSceneProxy::ApplyLateUpdateTransform(LateUpdateTransform);
-			//CachedTransform.SetOrigin(GetLocalToWorld().GetOrigin());
-			////UE_LOG(LogTemp, Display, TEXT("Transform on late update: %s"), *UpdatedTransform.ToString());
-			FOptiXModule::Get().GetOptiXContextManager()->ObjectPositionLateUpdate_RenderThread(*UniqueId, GetLocalToWorld().GetMatrixWithoutScale());
-		}
-
-		virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
-		uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
-	private:
-		const uint32* UniqueId;
-	};
-
-	return new FOptiXCubemapComponentSceneProxy(this);
-}
-
-void UOptiXCubemapLateUpdateComponent::LinkOptiXComponent(UOptiXCubemapComponent* OptiXComponent)
-{
-	OptiXComponentId = OptiXComponent->GetUniqueID();
-	UE_LOG(LogTemp, Display, TEXT("Setting Unique id on UOptiXCubemapComponent: %i"), OptiXComponentId);
-}
diff --git a/Source/OptiX/Private/OptiXGeometry.cpp b/Source/OptiX/Private/OptiXGeometry.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec657381107bba516c233ac7069fc389b889f005
--- /dev/null
+++ b/Source/OptiX/Private/OptiXGeometry.cpp
@@ -0,0 +1,628 @@
+#include "OptiXGeometry.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXGeometry.h"
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginGeometry);
+
+void UOptiXGeometry::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Display, TEXT("OptiX Geometry BeginDestroy"));
+	// Remove all the children:
+	DestroyOptiXObject();
+	Super::BeginDestroy();
+}
+
+void UOptiXGeometry::DestroyOptiXObject()
+{
+	if (NativeGeometry != NULL)
+	{
+		//NativeGeometry->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->GeometriesToDeleteQueue.Enqueue(NativeGeometry);
+
+	}
+
+	BufferMap.Empty();
+	IntersectionProgram = nullptr;
+	BoundingBoxProgram = nullptr;
+	NativeGeometry = NULL;
+}
+
+void UOptiXGeometry::SetFloat(FString string, float Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat2D(FString string, float Var1, float Var2)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat3DVector(FString string, FVector Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat3D(FString string, float Var1, float Var2, float Var3)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat4DVector(FString string, FVector4 Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetInt(FString string, int32 Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetInt2D(FString string, int32 Var1, int32 Var2)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetInt3DVector(FString string, FIntVector Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+//void UOptiXGeometry::SetInt4DVector(FString string, FIntVector4 Var)
+//{
+//	NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z, Var.W);
+//
+//}
+
+void UOptiXGeometry::SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetUint(FString string, uint8 Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetUint2D(FString string, uint8 Var1, uint8 Var2)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+// Todo: try-catch stuff for getters. Pretty low prio all in all
+
+float UOptiXGeometry::GetFloat(FString string)
+{
+	return NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat();
+}
+
+FVector2D UOptiXGeometry::GetFloat2D(FString string)
+{
+	optix::float2 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat2();
+	return FVector2D(V.x, V.y);
+}
+
+FVector UOptiXGeometry::GetFloat3D(FString string)
+{
+	optix::float3 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat3();
+	return FVector(V.x, V.y, V.z);
+}
+
+FVector4 UOptiXGeometry::GetFloat4D(FString string)
+{
+	optix::float4 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat4();
+	return FVector4(V.x, V.y, V.z, V.w);
+}
+
+int32 UOptiXGeometry::GetInt(FString string)
+{
+	return NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt();
+}
+
+FIntPoint UOptiXGeometry::GetInt2D(FString string)
+{
+	optix::int2 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt2();
+	return FIntPoint(V.x, V.y);
+}
+
+FIntVector UOptiXGeometry::GetInt3D(FString string)
+{
+	optix::int3 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt3();
+	return FIntVector(V.x, V.y, V.z);
+}
+
+//FIntVector4 UOptiXGeometry::GetInt4D(FString string)
+//{
+//	optix::int4 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt4();
+//	return FIntVector4(V.x, V.y, V.z, V.w);
+//}
+
+//uint8 UOptiXGeometry::GetUint(FString string)
+//{
+//	return static_cast<uint8>(NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint());
+//}
+//
+//void UOptiXGeometry::GetUint2D(FString & string, uint8 & Var1, uint8 & Var2)
+//{
+//	NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2);
+//
+//}
+//
+//void UOptiXGeometry::GetUint3D(FString string, uint8 & Var1, uint8 & Var2, uint8 & Var3)
+//{
+//	NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2, Var3);
+//}
+//
+//FUintVector4 UOptiXGeometry::GetUint4D(FString string)
+//{
+//	optix::uint4 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint4();
+//	return FUintVector4(V.x, V.y, V.z, V.w);
+//}
+
+
+optix::Geometry UOptiXGeometry::GetNativeGeometry()
+{
+	return NativeGeometry;
+}
+
+void UOptiXGeometry::SetPrimitiveCount(int32 NumPrimitives)
+{
+	if (NumPrimitives < 0)
+	{
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("Trying to set negative primitive count in geometry: %s"));
+		return;
+	}
+	try
+	{
+		NativeGeometry->setPrimitiveCount(static_cast<uint32>(NumPrimitives));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXGeometry::GetPrimitiveCount()
+{
+	int32 PrimitiveCount = 0;
+	try
+	{
+		PrimitiveCount = static_cast<int32>(NativeGeometry->getPrimitiveCount());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return PrimitiveCount;
+}
+
+void UOptiXGeometry::SetPrimitiveIndexOffset(int32 IndexOffsets)
+{
+	if (IndexOffsets < 0)
+	{
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("Trying to set negative primitive index offset in geometry!"));
+		return; // TODO Throw error
+	}
+	try
+	{
+		NativeGeometry->setPrimitiveIndexOffset(static_cast<uint32>(IndexOffsets));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXGeometry::GetPrimitiveIndexOffset()
+{
+	int32 PrimitiveIndexOffset = 0;
+	try
+	{
+		PrimitiveIndexOffset = static_cast<int32>(NativeGeometry->getPrimitiveIndexOffset());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return PrimitiveIndexOffset;
+}
+
+void UOptiXGeometry::SetPrimitiveCountUint(uint32 NumPrimitives)
+{
+	try
+	{
+		NativeGeometry->setPrimitiveCount(NumPrimitives);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint32 UOptiXGeometry::GetPrimitiveCountUint()
+{
+	uint32 PrimitiveCount = 0;
+	try
+	{
+		PrimitiveCount = NativeGeometry->getPrimitiveCount();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return PrimitiveCount;
+}
+
+void UOptiXGeometry::SetPrimitiveIndexOffsetUint(uint32 IndexOffsets)
+{
+	try
+	{
+		NativeGeometry->setPrimitiveIndexOffset(IndexOffsets);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint32 UOptiXGeometry::GetPrimitiveIndexOffsetUint()
+{
+	uint32 PrimitiveIndexOffset = 0;
+	try
+	{
+		PrimitiveIndexOffset = NativeGeometry->getPrimitiveIndexOffset();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return PrimitiveIndexOffset;
+}
+
+void UOptiXGeometry::SetMotionRange(float TimeBegin, float TimeEnd)
+{
+	try
+	{
+		NativeGeometry->setMotionRange(TimeBegin, TimeEnd);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+// Todo: Add try-catch stuff, but the motion range things are fairly low prio as well for now.
+
+FVector2D UOptiXGeometry::GetMotionRange()
+{
+	float f1, f2;
+	NativeGeometry->getMotionRange(f1, f2);
+	return FVector2D(f1, f2);
+}
+
+void UOptiXGeometry::SetMotionBorderMode(RTmotionbordermode BeginMode, RTmotionbordermode EndMode)
+{
+	NativeGeometry->setMotionBorderMode(BeginMode, EndMode);
+}
+
+void UOptiXGeometry::GetMotionBorderMode(RTmotionbordermode & BeginMode, RTmotionbordermode & EndMode)
+{
+	NativeGeometry->getMotionBorderMode(BeginMode, EndMode);
+}
+
+void UOptiXGeometry::SetMotionSteps(int32 N)
+{
+	if (N < 0)
+	{
+		return; // TODO Throw error
+	}
+	NativeGeometry->setMotionSteps(static_cast<uint32>(N));
+}
+
+int32 UOptiXGeometry::GetMotionSteps()
+{
+	return static_cast<int32>(NativeGeometry->getMotionSteps());
+}
+
+void UOptiXGeometry::SetMotionStepsUint(uint32 N)
+{
+	NativeGeometry->setMotionSteps(N);
+}
+
+uint32 UOptiXGeometry::GetMotionStepsUint()
+{
+	return NativeGeometry->getMotionSteps();
+}
+
+void UOptiXGeometry::SetBoundingBoxProgram(UOptiXProgram* Program)
+{
+	try
+	{
+		BoundingBoxProgram = Program;
+		NativeGeometry->setBoundingBoxProgram(Program->GetNativeProgram());	
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXProgram* UOptiXGeometry::GetBoundingBoxProgram()
+{
+	// Done to see if the optix bb prog is actually valid.
+	UOptiXProgram* Prog = nullptr;
+	try
+	{
+		NativeGeometry->getBoundingBoxProgram(); // todo: comparison check
+		Prog = BoundingBoxProgram;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Prog;
+}
+
+void UOptiXGeometry::SetIntersectionProgram(UOptiXProgram* Program)
+{
+	try
+	{
+		IntersectionProgram = Program;
+		NativeGeometry->setIntersectionProgram(Program->GetNativeProgram());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXProgram* UOptiXGeometry::GetIntersectionProgram()
+{
+	UOptiXProgram* Prog = nullptr;
+	try
+	{
+		NativeGeometry->getIntersectionProgram(); // todo: comparison check
+		Prog = IntersectionProgram;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Prog;
+}
+
+void UOptiXGeometry::MarkDirty()
+{
+	try
+	{
+		NativeGeometry->markDirty();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+bool UOptiXGeometry::IsDirty()
+{
+	bool Dirty = false;
+	try
+	{
+		Dirty = NativeGeometry->isDirty();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Dirty;
+}
+
+void UOptiXGeometry::SetBuffer(FString Name, UOptiXBuffer* Buffer)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeGeometry[N]->setBuffer(Buffer->GetNativeBuffer());
+		BufferMap.Add(Name, Buffer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
diff --git a/Source/OptiX/Private/OptiXGeometryGroup.cpp b/Source/OptiX/Private/OptiXGeometryGroup.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..240c8458ecdabea18d7729c40591e61ddae06144
--- /dev/null
+++ b/Source/OptiX/Private/OptiXGeometryGroup.cpp
@@ -0,0 +1,205 @@
+#include "OptiXGeometryGroup.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXGeometryGroup.h"
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginGeometryGroup);
+
+// TODO LOOK INTO CONSTRUCTORS
+
+void UOptiXGeometryGroup::BeginDestroy()
+{
+	Super::BeginDestroy();
+
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Geometry Group BeginDestroy"));
+	// Remove all the children:
+	DestroyOptiXObject();
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Geometry Group Finished BeginDestroy"));
+
+}
+
+void UOptiXGeometryGroup::DestroyOptiXObject()
+{
+	for (UOptiXGeometryInstance* I : OptiXGeometryInstances)
+	{
+		//RemoveChild(I);
+		// For some godforsaken reason this crashes optix...
+	}
+
+	if (NativeGeometryGroup != NULL)
+	{
+		//NativeGeometryGroup->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->GeometryGroupToDeleteQueue.Enqueue(NativeGeometryGroup);
+
+	}
+
+	OptiXGeometryInstances.Empty();
+	NativeGeometryGroup = NULL;
+}
+
+void UOptiXGeometryGroup::SetAcceleration(UOptiXAcceleration* Accel)
+{
+	try
+	{
+		NativeGeometryGroup->setAcceleration(Accel->GetNativeAcceleration());
+		Acceleration = Accel;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXAcceleration* UOptiXGeometryGroup::GetAcceleration()
+{
+	UOptiXAcceleration* Ptr = nullptr;
+	try
+	{
+		optix::Acceleration Native = NativeGeometryGroup->getAcceleration();
+
+		if (Native != Acceleration->GetNativeAcceleration())
+		{
+			FString Message = "Acceleration Mismatch in Geometry Group!";
+			UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
+			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		}
+
+		Ptr = Acceleration;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ptr;
+}
+
+void UOptiXGeometryGroup::SetChildCount(uint8 Count)
+{
+	NativeGeometryGroup->setChildCount(Count);
+	ChildCount = Count;
+
+	int32 Diff = Count - OptiXGeometryInstances.Num();
+
+	if (Diff > 0)
+	{
+		OptiXGeometryInstances.SetNum(Count);
+	}
+	else if (Diff < 0)
+	{
+		// Theoretically remove children but don't do this for now! TODOOOO
+	}
+}
+
+uint8 UOptiXGeometryGroup::GetChildCount()
+{
+	// Check if our count is the same
+	uint8 OptiXCount = NativeGeometryGroup->getChildCount();
+	if (OptiXCount != ChildCount)
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup Child Counts are mismatched: Native: %i - %i UObject \n"), OptiXCount, ChildCount);
+	}
+	return OptiXCount;
+}
+
+void UOptiXGeometryGroup::SetChild(uint8 Index, UOptiXGeometryInstance * Child)
+{
+	// This will probably mess with child counts but shouldn't.
+
+	if (!OptiXGeometryInstances.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Trying to insert child in non-existing place! \n"));
+		return;
+	}
+	NativeGeometryGroup->setChild(Index, Child->GetNativeInstance());
+	OptiXGeometryInstances.Insert(Child, Index);
+}
+
+UOptiXGeometryInstance * UOptiXGeometryGroup::GetChild(uint8 Index)
+{
+	if (!OptiXGeometryInstances.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Child does not exist! \n"));
+	}
+
+	return OptiXGeometryInstances[Index];
+}
+
+uint8 UOptiXGeometryGroup::AddChild(UOptiXGeometryInstance * Child)
+{
+	ChildCount++;
+	uint8 NativeIndex = static_cast<uint8>(NativeGeometryGroup->addChild(Child->GetNativeInstance()));
+	uint8 Index = OptiXGeometryInstances.Add(Child);
+	if (NativeIndex != Index)
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Index Mismatch while adding! \n"));
+	}
+	return Index;
+}
+
+uint8 UOptiXGeometryGroup::RemoveChild(UOptiXGeometryInstance * Child)
+{
+	uint8 Index = GetChildIndex(Child);
+	RemoveChildByIndex(Index);
+	return Index;
+}
+
+void UOptiXGeometryGroup::RemoveChildByIndex(uint8 Index)
+{
+	if (!OptiXGeometryInstances.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Index Mismatch while removing!"));
+		return;
+	}
+
+	UE_LOG(LogTemp, Display, TEXT("OptiXGeometryGroup: Removing optix child!"));
+	UE_LOG(LogTemp, Display, TEXT("Child Count: %i "), GetChildCount());
+	UE_LOG(LogTemp, Display, TEXT("Index to remove: %i "), Index);
+	UE_LOG(LogTemp, Display, TEXT("Size of TArray: %i "), OptiXGeometryInstances.Num());
+
+
+	try
+	{
+		if (IsInGameThread())
+		{
+			FOptiXModule::Get().GetOptiXContextManager()->GeometryGroupChildrenToRemoveQueue.Enqueue(TPair<optix::GeometryGroup, uint32>(NativeGeometryGroup, Index));
+		}
+		else
+		{
+			NativeGeometryGroup->removeChild(static_cast<unsigned int>(Index));
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	ChildCount--; // Not sure if OptiX internally resizes the array or if the child count stays the same?
+
+	UE_LOG(LogTemp, Display, TEXT("Done Removing Native"), OptiXGeometryInstances.Num());
+	UE_LOG(LogTemp, Display, TEXT("Child Count After remove native: %i "), GetChildCount());
+	FName Name = OptiXGeometryInstances[Index]->GetFName();
+	UE_LOG(LogTemp, Display, TEXT("Name of child to remove: %s"), *Name.ToString());
+
+	OptiXGeometryInstances.RemoveAt(Index); // Will shuffle the remaining indices correctly - hopefully.
+	UE_LOG(LogTemp, Display, TEXT("Finished Removing \n"));
+
+}
+
+uint8 UOptiXGeometryGroup::GetChildIndex(UOptiXGeometryInstance * Child)
+{
+	return OptiXGeometryInstances.Find(Child);
+}
diff --git a/Source/OptiX/Private/OptiXGeometryInstance.cpp b/Source/OptiX/Private/OptiXGeometryInstance.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1c594a09c8312d5a66d0ab1c6dc41de504c9d494
--- /dev/null
+++ b/Source/OptiX/Private/OptiXGeometryInstance.cpp
@@ -0,0 +1,174 @@
+#include "OptiXGeometryInstance.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+#include "OptiXGeometryInstance.h"
+
+// TODO LOOK INTO CONSTRUCTORS
+
+void UOptiXGeometryInstance::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Geometry Instance BeginDestroy"));
+	// This should also remove the optix::geometry if nowhere referenced
+	DestroyOptiXObject();
+	Super::BeginDestroy();
+}
+
+void UOptiXGeometryInstance::DestroyOptiXObject()
+{
+	if (NativeGeometryInstance != NULL)
+	{
+		//NativeGeometryInstance->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->GeometryInstancesToDeleteQueue.Enqueue(NativeGeometryInstance);
+	}
+
+	BufferMap.Empty();
+	OptiXMaterials.Empty();
+	TextureSamplerMap.Empty();
+	NativeGeometryInstance = NULL;
+}
+
+void UOptiXGeometryInstance::SetGeometry(UOptiXGeometry * OptiXGeometryPtr)
+{
+	OptiXGeometry = OptiXGeometryPtr;
+	NativeGeometryInstance->setGeometry(OptiXGeometryPtr->GetNativeGeometry()); // I hate passing the native geometry around here
+}
+
+UOptiXGeometry * UOptiXGeometryInstance::GetGeometry()
+{
+	return OptiXGeometry;
+}
+
+void UOptiXGeometryInstance::SetMaterialCount(uint8 Count)
+{
+	NativeGeometryInstance->setMaterialCount(Count);
+}
+
+uint8 UOptiXGeometryInstance::GetMaterialCount()
+{
+	return static_cast<uint8>(NativeGeometryInstance->getMaterialCount());
+}
+
+void UOptiXGeometryInstance::SetMaterial(uint8 Idx, UOptiXMaterial * Material)
+{
+	if (!OptiXMaterials.IsValidIndex(Idx))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryInstance: Trying to insert Material in non-existing place! \n"));
+		return;
+	}
+	NativeGeometryInstance->setMaterial(Idx, Material->GetNativeMaterial());
+	OptiXMaterials.Insert(Material, Idx);
+}
+
+UOptiXMaterial * UOptiXGeometryInstance::GetMaterial(uint8 Idx)
+{
+	if (!OptiXMaterials.IsValidIndex(Idx))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryInstance: Trying to get Material in non-existing place! \n"));
+		return nullptr;
+	}
+	return OptiXMaterials[Idx];
+}
+
+uint8 UOptiXGeometryInstance::AddMaterial(UOptiXMaterial * OptiXMaterialPtr)
+{
+	NativeGeometryInstance->addMaterial(OptiXMaterialPtr->GetNativeMaterial());
+	return OptiXMaterials.Add(OptiXMaterialPtr);
+}
+
+
+// Setters - ugh
+
+void UOptiXGeometryInstance::SetFloat(FString string, float Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
+}
+
+void UOptiXGeometryInstance::SetFloat2D(FString string, float Var1, float Var2)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
+
+}
+
+void UOptiXGeometryInstance::SetFloat3DVector(FString string, FVector Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
+
+}
+
+void UOptiXGeometryInstance::SetFloat3D(FString string, float Var1, float Var2, float Var3)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
+
+}
+
+void UOptiXGeometryInstance::SetFloat4DVector(FString string, FVector4 Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
+
+}
+
+void UOptiXGeometryInstance::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
+
+}
+
+void UOptiXGeometryInstance::SetInt(FString string, int32 Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
+
+}
+
+void UOptiXGeometryInstance::SetInt2D(FString string, int32 Var1, int32 Var2)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
+
+}
+
+void UOptiXGeometryInstance::SetInt3DVector(FString string, FIntVector Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
+
+}
+
+void UOptiXGeometryInstance::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
+
+}
+
+void UOptiXGeometryInstance::SetTextureSampler(FString Name, UOptiXTextureSampler * Sampler)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeGeometryInstance[N]->set(Sampler->GetNativeTextureSampler());
+		TextureSamplerMap.Add(Name, Sampler);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
+	}
+}
+
+void UOptiXGeometryInstance::SetBuffer(FString Name, UOptiXBuffer* Buffer)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeGeometryInstance[N]->setBuffer(Buffer->GetNativeBuffer());
+		BufferMap.Add(Name, Buffer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
+	}
+}
diff --git a/Source/OptiX/Private/OptiXGroup.cpp b/Source/OptiX/Private/OptiXGroup.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2fa1e2a4c544a71dc1e82913e2dcbf6593424a45
--- /dev/null
+++ b/Source/OptiX/Private/OptiXGroup.cpp
@@ -0,0 +1,238 @@
+#include "OptiXGroup.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginGroup);
+
+// TODO LOOK INTO CONSTRUCTORS
+
+void UOptiXGroup::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Group BeginDestroy"));
+
+	DestroyOptiXObject();
+
+	Super::BeginDestroy();
+}
+
+
+void UOptiXGroup::DestroyOptiXObject()
+{
+	for (UObject* I : Children)
+	{
+		//RemoveChild(I);
+	}
+
+	if (NativeGroup != NULL)
+	{
+		//NativeGroup->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->GroupsToDeleteQueue.Enqueue(NativeGroup);
+	}
+
+	Children.Empty();
+	NativeGroup = NULL;
+}
+
+void UOptiXGroup::SetAcceleration(UOptiXAcceleration * Accel)
+{
+	try
+	{
+		NativeGroup->setAcceleration(Accel->GetNativeAcceleration());
+		Acceleration = Accel;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXAcceleration * UOptiXGroup::GetAcceleration()
+{
+	UOptiXAcceleration* Ptr = nullptr;
+	try
+	{
+		optix::Acceleration Native = NativeGroup->getAcceleration();
+
+		if (Native != Acceleration->GetNativeAcceleration())
+		{
+			FString Message = "Acceleration Mismatch in Group!";
+			UE_LOG(OptiXPluginGroup, Error, TEXT("OptiX Error: %s"), *Message);
+			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		}
+
+		Ptr = Acceleration;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ptr;
+}
+
+void UOptiXGroup::SetChildCount(uint8 Count)
+{
+	NativeGroup->setChildCount(Count);
+	ChildCount = Count;
+
+	int32 Diff = Count - Children.Num();
+
+	if (Diff > 0)
+	{
+		Children.SetNum(Count);
+	}
+	else if (Diff < 0)
+	{
+		// Theoretically remove children but don't do this for now! TODOOOO
+	}
+}
+
+uint8 UOptiXGroup::GetChildCount()
+{
+	// Check if our count is the same
+	uint8 OptiXCount = NativeGroup->getChildCount();
+	if (OptiXCount != ChildCount)
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup Child Counts are mismatched! \n"));
+	}
+	return OptiXCount;
+}
+
+void UOptiXGroup::SetChild(uint8 Index, UObject * Child)
+{
+	// This will probably mess with child counts but shouldn't.
+
+	if (!Children.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Trying to insert child in non-existing place! \n"));
+		return;
+	}
+
+	// Check the different child types - don't do all for now just add the code when needed
+	// Doing GeometryGroup, GeometryInstance and Transform for now
+
+	if (UOptiXGeometryGroup* GeomGroup = Cast<UOptiXGeometryGroup>(Child))
+	{
+		NativeGroup->setChild(Index, GeomGroup->GetNativeGroup());
+		Children.Insert(Child, Index);
+	}
+	else if (UOptiXGeometryInstance* GeomInstance = Cast<UOptiXGeometryInstance>(Child))
+	{
+		NativeGroup->setChild(Index, GeomInstance->GetNativeInstance());
+		Children.Insert(Child, Index);
+	}
+	else if (UOptiXTransform* Transform = Cast<UOptiXTransform>(Child))
+	{
+		NativeGroup->setChild(Index, Transform->GetNativeTransform());
+		Children.Insert(Child, Index);
+	}
+}
+
+RTobjecttype UOptiXGroup::GetChildType(uint8 Index)
+{
+	RTobjecttype Type = RT_OBJECTTYPE_UNKNOWN;
+	if (!Children.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Trying to get child type in non-existing place! \n"));
+		return Type;
+	}
+	
+	return NativeGroup->getChildType(Index);
+}
+
+UObject * UOptiXGroup::GetChild(uint8 Index)
+{
+	if (!Children.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Child does not exist! \n"));
+	}
+
+	return Children[Index];
+}
+
+uint8 UOptiXGroup::AddChild(UObject * Child)
+{
+	if (UOptiXGeometryGroup* GeomGroup = Cast<UOptiXGeometryGroup>(Child))
+	{
+		uint8 NativeIndex = static_cast<uint8>(NativeGroup->addChild(GeomGroup->GetNativeGroup()));
+		uint8 Index = Children.Add(Child);
+		if (NativeIndex != Index)
+		{
+			UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while adding! \n"));
+		}
+		return Index;
+	}
+	else if (UOptiXGeometryInstance* GeomInstance = Cast<UOptiXGeometryInstance>(Child))
+	{
+		uint8 NativeIndex = static_cast<uint8>(NativeGroup->addChild(GeomInstance->GetNativeInstance()));
+		uint8 Index = Children.Add(Child);
+		if (NativeIndex != Index)
+		{
+			UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while adding! \n"));
+		}
+		return Index;
+	}
+	else if (UOptiXTransform* Transform = Cast<UOptiXTransform>(Child))
+	{
+		uint8 NativeIndex = static_cast<uint8>(NativeGroup->addChild(Transform->GetNativeTransform()));
+		uint8 Index = Children.Add(Child);
+		if (NativeIndex != Index)
+		{
+			UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while adding! \n"));
+		}
+		return Index;
+	}
+	else return 0; // Dangerous!	
+}
+
+uint8 UOptiXGroup::RemoveChild(UObject * Child)
+{
+	uint8 Index = GetChildIndex(Child);
+	RemoveChildByIndex(Index);
+	return Index;
+}
+
+void UOptiXGroup::RemoveChildByIndex(uint8 Index)
+{
+	if (!Children.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while removing! \n"));
+		return;
+	}
+
+	if (NativeGroup == NULL)
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Native group is NULL when removing child! \n"));
+		return;
+	}
+
+	ChildCount--; // Not sure if OptiX internally resizes the array or if the child count stays the same?
+	Children.RemoveAt(Index); // Will shuffle the remaining indices correctly - hopefully.
+
+	// Can't do that in game thread!
+	if (IsInGameThread())
+	{
+		FOptiXModule::Get().GetOptiXContextManager()->GroupChildrenToRemoveQueue.Enqueue(TPair<optix::Group, uint32>(NativeGroup, Index ));
+	}
+	else
+	{
+		NativeGroup->removeChild(static_cast<unsigned int>(Index));
+	}
+}
+
+uint8 UOptiXGroup::GetChildIndex(UObject * Child)
+{
+	return Children.Find(Child);
+}
diff --git a/Source/OptiX/Private/OptiXLaserComponent.cpp b/Source/OptiX/Private/OptiXLaserComponent.cpp
index d1e756e61c1e7f25f0201496f033c03d2003c749..ca13843f606914468fb1405ffaa42e9e75259f6e 100644
--- a/Source/OptiX/Private/OptiXLaserComponent.cpp
+++ b/Source/OptiX/Private/OptiXLaserComponent.cpp
@@ -1,12 +1,10 @@
 // Fill out your copyright notice in the Description page of Project Settings.
 
 #include "OptiXLaserComponent.h"
+#include "OptiXModule.h"
 
 #include "UObject/ConstructorHelpers.h"
 
-#include "OptiXModule.h"
-#include "StatsDefines.h"
-
 
 // Sets default values for this component's properties
 UOptiXLaserComponent::UOptiXLaserComponent()
@@ -14,7 +12,7 @@ UOptiXLaserComponent::UOptiXLaserComponent()
 	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
 	// off to improve performance if you don't need them.
 	PrimaryComponentTick.bCanEverTick = false; 
-	bWantsOnUpdateTransform = false; // why the hell do I need this here but not on the others?
+	bWantsOnUpdateTransform = true; // why the hell do I need this here but not on the others?
 
 	// ...
 
@@ -135,51 +133,180 @@ UOptiXLaserComponent::UOptiXLaserComponent()
 }
 
 
-FPrimitiveSceneProxy* UOptiXLaserComponent::CreateSceneProxy()
+// Called when the game starts
+void UOptiXLaserComponent::BeginPlay()
+{
+	Super::BeginPlay();
+	Init();
+}
+
+void UOptiXLaserComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
+{
+	Super::EndPlay(EndPlayReason);
+
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component EndPlay"));
+
+	CleanOptiXObjects();
+}
+
+
+void UOptiXLaserComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport/* = ETeleportType::None*/)
 {
-	class FLaserComponentSceneProxy final : public FPrimitiveSceneProxy
+	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
+	UpdateLaserPosition();
+}
+
+void UOptiXLaserComponent::UpdateOptiXContextVariables()
+{
+	check(IsInRenderingThread());
+
+	if (bUpdateQueued)
 	{
-	public:
-		SIZE_T GetTypeHash() const override
-		{
-			static size_t UniquePointer;
-			return reinterpret_cast<size_t>(&UniquePointer);
-		}
+		OptiXContext->SetInt("allowTir", RayTIR);
+		OptiXContext->SetInt("targetBufferWrite", static_cast<int32>(TargetBufferWrite));
+		OptiXContext->SetFloat("laserWaveLength", Wavelength);
+
+		OptiXContext->SetFloat("laserSize", 3.5f); // Hardcode this for now
+
+		OptiXContext->SetFloat("laserBeamWidth", LaserWidth);
 
-		/** Initialization constructor. */
-		FLaserComponentSceneProxy(const UOptiXLaserComponent* InComponent)
-			: FPrimitiveSceneProxy(InComponent)
-		{}
 
-		// FPrimitiveSceneProxy interface.
+		// Upload buffer data
 
-		virtual void ApplyLateUpdateTransform(const FMatrix& LateUpdateTransform) override
+		if (bPatternChanged)
 		{
-			FMatrix CachedTransform = GetLocalToWorld();
-			FPrimitiveSceneProxy::ApplyLateUpdateTransform(LateUpdateTransform);
-			CachedTransform.SetOrigin(GetLocalToWorld().GetOrigin());
-			FTransform UpdatedTransform(CachedTransform.GetMatrixWithoutScale());
-			//UE_LOG(LogTemp, Display, TEXT("Transform on late update: %s"), *UpdatedTransform.ToString());
-			FOptiXModule::Get().GetOptiXContextManager()->LaserPositionLateUpdate_RenderThread(UpdatedTransform);
+
+			int X = Patterns[CurrentLaserPattern]->GetSizeX();
+			int Y = Patterns[CurrentLaserPattern]->GetSizeY();
+
+			// Those get set on the game thread already
+			//LaserIndices.Empty();
+			//LaserIndexColorMap.Empty();
+
+
+			UOptiXBuffer* LaserIndexBuffer = OptiXContext->GetBuffer("laserIndex");
+			UOptiXBuffer* LaserDirectionBuffer = OptiXContext->GetBuffer("laserDir");
+			{
+				UE_LOG(LogTemp, Display, TEXT("New Pattern: %i"), static_cast<uint8>(CurrentLaserPattern));
+
+				int32* BufferIndexData = static_cast<int32*>(LaserIndexBuffer->MapNative(0, RT_BUFFER_MAP_WRITE));
+				// Reset the buffer explicitly 
+				FMemory::Memset(BufferIndexData, 0u, X * Y * 4);
+
+				FTexture2DMipMap& IndexMip = Patterns[CurrentLaserPattern]->PlatformData->Mips[0];
+
+				FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_WRITE));
+
+				// Save the texture indices for the direction:
+
+				TArray<int32> TextureIndices;
+
+				// Texture index conversion is a real pain...
+				for (int32 i = 0; i < X; ++i) {
+					for (int32 j = 0; j < Y; ++j) {
+
+						int32 TextureIndex = (X * Y - 1) - i * X - j;
+						int32 BufferIndex = ((j)*(X)+i);
+
+						BufferIndexData[BufferIndex] = 0;
+
+						if (TextureData[TextureIndex].R || TextureData[TextureIndex].G || TextureData[TextureIndex].B)
+						{
+							BufferIndexData[BufferIndex] = 1;
+							//LaserIndices.Add(BufferIndex);
+							TextureIndices.Add(TextureIndex);
+							//LaserIndexColorMap.Add(BufferIndex, TextureData[TextureIndex]);
+						}
+						else
+						{
+							BufferIndexData[BufferIndex] = -1; // do not cast ray
+						}
+					}
+				}
+
+				UE_LOG(LogTemp, Display, TEXT("# Ray Indices in Pattern %i"), static_cast<uint8>(TextureIndices.Num()));
+
+				IndexMip.BulkData.Unlock();
+				LaserIndexBuffer->Unmap();
+			}
+
+			{
+
+				// TODO: It should really suffice to just copy the respective texture index. If we don't shoot a ray, the direction won't matter anyway
+
+				float* BufferDirectionData = static_cast<float*>(LaserDirectionBuffer->MapNative(0, RT_BUFFER_MAP_WRITE));
+
+				FTexture2DMipMap& DirectionMip = PatternDirections[CurrentLaserPattern]->PlatformData->Mips[0];
+
+				FColor* TextureData = static_cast<FColor*>(DirectionMip.BulkData.Lock(LOCK_READ_WRITE));
+
+				// Texture index conversion is a real pain...
+				for (int32 i = 0; i < X; ++i) {
+					for (int32 j = 0; j < Y; ++j) {
+
+						int32 TextureIndex = (X * Y - 1) - i * X - j;
+						int32 BufferIndex = ((j)*(X)+i) * 3;
+
+						//UE_LOG(LogTemp, Display, TEXT("Values: %i"), TextureData[BufferIndex]);
+
+						FVector DirNormalSpace = FVector();
+						DirNormalSpace.X = (TextureData[TextureIndex].R / 256.0f) * 2.0f - 1.0f;
+						DirNormalSpace.Y = (TextureData[TextureIndex].G / 256.0f) * 2.0f - 1.0f;
+						DirNormalSpace.Z = (TextureData[TextureIndex].B / 256.0f);
+
+						// We need to rotate this to face forward (1, 0, 0):
+
+						FMatrix Mat = FRotationMatrix::MakeFromX(FVector(0, 0, 1));
+						FVector Dir = Mat.TransformVector(DirNormalSpace);
+
+						BufferDirectionData[BufferIndex] = Dir.X;
+						BufferDirectionData[BufferIndex + 1] = Dir.Y;
+						BufferDirectionData[BufferIndex + 2] = Dir.Z;
+
+					}
+				}
+				DirectionMip.BulkData.Unlock();
+				LaserDirectionBuffer->Unmap();
+			}
+			bPatternChanged.AtomicSet(false);
 		}
 
-		virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
-		uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
-	};
 
-	return new FLaserComponentSceneProxy(this);
-}
+		FTransform CurrentTransform = GetComponentTransform();
+		FVector Translation = CurrentTransform.GetTranslation();
+		FVector Forward = GetForwardVector();
+		FVector Right = GetRightVector();
+		FVector Up = GetUpVector();
+			//FMatrix Rotation = GetComponentRotation().;
 
+			// Hard code this for now: laser is around 10x10x10 cube
 
-// Called when the game starts
-void UOptiXLaserComponent::BeginPlay()
+		OptiXContext->SetFloat3DVectorThreadsafe("laser_origin", Translation);
+		OptiXContext->SetFloat3DVectorThreadsafe("laser_forward", Forward);
+		OptiXContext->SetFloat3DVectorThreadsafe("laser_right", Right);
+		OptiXContext->SetFloat3DVectorThreadsafe("laser_up", Up);
+
+
+		OptiXContext->SetMatrixThreadsafe("laser_rot", CurrentTransform.ToMatrixNoScale());
+
+
+		FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+
+		bUpdateQueued.AtomicSet(false);
+
+	}
+}
+
+void UOptiXLaserComponent::Init()
 {
-	Super::BeginPlay();
-	bWantsOnUpdateTransform = true;
+	OptiXContext = FOptiXModule::Get().GetContext();
+	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
 
-	UE_LOG(LogTemp, Display, TEXT("Initializing OptiX Laser"));
+	UE_LOG(LogTemp, Display, TEXT("Init Laser, got context instance."));
+
+	// Setup buffers and stuff, make sure to make this compatible with an arbitrary # of lasers.
+	// Use the entry points to do this?
 
-	SetLaserPattern(CurrentLaserPattern);
 
 	SetRayTIR(RayTIR);
 	SetTargetBufferWrite(TargetBufferWrite);
@@ -187,45 +314,25 @@ void UOptiXLaserComponent::BeginPlay()
 	SetWavelength(Wavelength);
 	SetLaserWidth(LaserWidth);
 
-	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
-	//FOptiXModule::Get().GetOptiXContextManager()->bIsInitializedLaser.AtomicSet(true);
-
-	UpdateLaserPosition();
+	OptiXContext->SetInt("allowTir", RayTIR);
+	OptiXContext->SetInt("targetBufferWrite", static_cast<int>(TargetBufferWrite));
+	OptiXContext->SetFloat("laserWaveLength", Wavelength);
 
-}
+	OptiXContext->SetFloat("laserSize", 3.5f); // Hardcode this for now
 
-void UOptiXLaserComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
-{
-	Super::EndPlay(EndPlayReason);
+	OptiXContext->SetFloat("laserBeamWidth", LaserWidth);
 
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component EndPlay"));
+	SetLaserPattern(CurrentLaserPattern);
 
-	CleanOptiXObjects();
-}
+	FOptiXModule::Get().GetOptiXContextManager()->bLaserIsInitialized.AtomicSet(true);
 
-void UOptiXLaserComponent::CleanOptiXObjects()
-{
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component Cleaning up")); // TODO
-	FOptiXModule::Get().GetOptiXContextManager()->RequestDestroyOptiXObjects(GetUniqueID());
 }
 
 
-void UOptiXLaserComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport/* = ETeleportType::None*/)
-{
-	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
-	UpdateLaserPosition();
-}
-
 void UOptiXLaserComponent::SetRayTIR(bool Active)
 {
 	RayTIR = Active;
-	OptiXContextUpdateFunction UpdateFunction =
-		[RayTIR = RayTIR](optix::Context Context)
-	{
-		Context["allowTir"]->setInt(static_cast<int>(RayTIR));
-	};
-
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+	bUpdateQueued.AtomicSet(true);
 }
 
 bool UOptiXLaserComponent::GetRayTIR() const
@@ -236,13 +343,7 @@ bool UOptiXLaserComponent::GetRayTIR() const
 void UOptiXLaserComponent::SetTargetBufferWrite(bool Flag)
 {
 	TargetBufferWrite = Flag;
-	OptiXContextUpdateFunction UpdateFunction =
-		[TargetBufferWrite = TargetBufferWrite](optix::Context Context)
-	{
-		Context["targetBufferWrite"]->setInt(static_cast<int>(TargetBufferWrite));
-	};
-
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+	bUpdateQueued.AtomicSet(true);
 }
 
 bool UOptiXLaserComponent::GetTargetBufferWrite() const
@@ -253,13 +354,7 @@ bool UOptiXLaserComponent::GetTargetBufferWrite() const
 void UOptiXLaserComponent::SetTargetColorMode(bool Flag)
 {
 	TargetColorMode = Flag;
-	//OptiXContextUpdateFunction UpdateFunction =
-	//	[TargetBufferWrite = TargetBufferWrite](optix::Context Context)
-	//{
-	//	Context["targetBufferWrite"]->setInt(static_cast<int>(TargetBufferWrite));
-	//};
-
-	//FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+	bUpdateQueued.AtomicSet(true);
 }
 
 bool UOptiXLaserComponent::GetTargetColorMode() const
@@ -271,13 +366,7 @@ void UOptiXLaserComponent::SetWavelength(float WL)
 {
 	Wavelength = WL;
 	FOptiXModule::Get().GetOptiXContextManager()->BroadcastWavelengthChange(WL);
-	OptiXContextUpdateFunction UpdateFunction =
-		[Wavelength = Wavelength](optix::Context Context)
-	{
-		Context["laserWaveLength"]->setInt(static_cast<int>(Wavelength));
-	};
-
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+	bUpdateQueued.AtomicSet(true);
 }
 
 float UOptiXLaserComponent::GetWavelength() const
@@ -288,12 +377,7 @@ float UOptiXLaserComponent::GetWavelength() const
 void UOptiXLaserComponent::SetLaserWidth(float Width)
 {
 	LaserWidth = Width;
-	OptiXContextUpdateFunction UpdateFunction =
-		[LaserWidth = LaserWidth](optix::Context Context)
-	{
-		Context["laserBeamWidth"]->setFloat(LaserWidth);
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+	bUpdateQueued.AtomicSet(true);
 }
 
 float UOptiXLaserComponent::GetLaserWidth() const
@@ -313,106 +397,12 @@ void UOptiXLaserComponent::SetLaserPattern(EPatternTypes Pattern)
 	UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Queuing Laser Pattern Change"));
 
 	CurrentLaserPattern = Pattern;
-	UE_LOG(LogTemp, Display, TEXT("New Pattern queued: %i"), static_cast<uint8>(CurrentLaserPattern));
-
-
-	int X = Patterns[CurrentLaserPattern]->GetSizeX();
-	int Y = Patterns[CurrentLaserPattern]->GetSizeY();
-
-	UTexture2D* NewPattern = Patterns[CurrentLaserPattern];
-	UTexture2D* NewDirectionPattern = PatternDirections[CurrentLaserPattern];
-
-	OptiXContextUpdateFunction UpdateFunction =
-		[X, Y, NewPattern, NewDirectionPattern](optix::Context Context)
-	{
-		TRACE_CPUPROFILER_EVENT_SCOPE("UOptiXLaserComponent::LaserPatternUpdate")
-		//UE_LOG(LogTemp, Display, TEXT("Changing to new laser pattern: %i"), static_cast<uint8>(CurrentLaserPattern));
-
-		{
-			optix::Buffer LaserIndexBuffer = Context["laserIndex"]->getBuffer();
-
-			int32* BufferIndexData = static_cast<int32*>(LaserIndexBuffer->map(0, RT_BUFFER_MAP_WRITE));
-			// Reset the buffer explicitly 
-			FMemory::Memset(BufferIndexData, 0u, X * Y * 4);
-
-			FTexture2DMipMap& IndexMip = NewPattern->PlatformData->Mips[0];
-
-			FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_WRITE));
-
-			TArray<int32> TextureIndices;
-
-			// Texture index conversion is a real pain...
-			for (int32 i = 0; i < X; ++i) {
-				for (int32 j = 0; j < Y; ++j) {
-
-					int32 TextureIndex = (X * Y - 1) - i * X - j;
-					int32 BufferIndex = ((j)*(X)+i);
-
-					BufferIndexData[BufferIndex] = 0;
-
-					if (TextureData[TextureIndex].R || TextureData[TextureIndex].G || TextureData[TextureIndex].B)
-					{
-						BufferIndexData[BufferIndex] = 1;
-						//LaserIndices.Add(BufferIndex);
-						TextureIndices.Add(TextureIndex);
-						//LaserIndexColorMap.Add(BufferIndex, TextureData[TextureIndex]);
-					}
-					else
-					{
-						BufferIndexData[BufferIndex] = -1; // do not cast ray
-					}
-				}
-			}
-
-			UE_LOG(LogTemp, Display, TEXT("# Ray Indices in Pattern %i"), static_cast<uint8>(TextureIndices.Num()));
-
-			IndexMip.BulkData.Unlock();
-			LaserIndexBuffer->unmap();
-		}
-		{
-			optix::Buffer LaserDirectionBuffer = Context["laserDir"]->getBuffer();
-			float* BufferDirectionData = static_cast<float*>(LaserDirectionBuffer->map(0, RT_BUFFER_MAP_WRITE));
-
-			FTexture2DMipMap& DirectionMip = NewDirectionPattern->PlatformData->Mips[0];
-
-			FColor* TextureData = static_cast<FColor*>(DirectionMip.BulkData.Lock(LOCK_READ_WRITE));
-
-			// Texture index conversion is a real pain...
-			for (int32 i = 0; i < X; ++i) {
-				for (int32 j = 0; j < Y; ++j) {
-
-					int32 TextureIndex = (X * Y - 1) - i * X - j;
-					int32 BufferIndex = ((j)*(X)+i) * 3;
-
-					//UE_LOG(LogTemp, Display, TEXT("Values: %i"), TextureData[BufferIndex]);
-
-					FVector DirNormalSpace = FVector();
-					DirNormalSpace.X = (TextureData[TextureIndex].R / 256.0f) * 2.0f - 1.0f;
-					DirNormalSpace.Y = (TextureData[TextureIndex].G / 256.0f) * 2.0f - 1.0f;
-					DirNormalSpace.Z = (TextureData[TextureIndex].B / 256.0f);
-					DirNormalSpace.Normalize();
-
-					// We need to rotate this to face forward (1, 0, 0):
-
-					//FMatrix Mat = FRotationMatrix::MakeFromX(FVector(0, 0, 1));
-					//FVector Dir = Mat.TransformVector(DirNormalSpace);
 
-					FVector Dir;
-					Dir.X = DirNormalSpace.Z;
-					Dir.Y = DirNormalSpace.Y;
-					Dir.Z = DirNormalSpace.X;
-
-					BufferDirectionData[BufferIndex] = Dir.X;
-					BufferDirectionData[BufferIndex + 1] = Dir.Y;
-					BufferDirectionData[BufferIndex + 2] = Dir.Z;
-
-				}
-			}
-			DirectionMip.BulkData.Unlock();
-			LaserDirectionBuffer->unmap();
-		}
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+	// Update the base indices first so that the game thread can directly create the insanced lines instead of having to wait for the render thread
+	// The actual positions will get updated when the render thread catches up.
+	
+	bUpdateQueued.AtomicSet(true);
+	bPatternChanged.AtomicSet(true);
 }
 
 void UOptiXLaserComponent::PreparePatternChange(EPatternTypes Pattern)
@@ -458,31 +448,6 @@ EPatternTypes UOptiXLaserComponent::GetLaserPattern() const
 void UOptiXLaserComponent::UpdateLaserPosition()
 {
 	//UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component Updating Position"));
-	FTransform CurrentTransform = GetComponentTransform();
-	FVector Translation = CurrentTransform.GetTranslation();
-	FVector Forward = GetForwardVector();
-	FVector Right = GetRightVector();
-	FVector Up = GetUpVector();
-	FMatrix Rotation = CurrentTransform.ToMatrixNoScale();
-	Rotation = FMatrix::Identity;
-	//UE_LOG(LogTemp, Display, TEXT("Transform on update: %s"), *GetComponentTransform().ToString());
-
-
-	// Hard code this for now: laser is around 10x10x10 cube
-	   	  
-	OptiXContextUpdateFunction UpdateFunction =
-		[Translation, Forward, Right, Up, Rotation](optix::Context Context)
-	{
-		Context["laser_origin"]->setFloat(Translation.X, Translation.Y, Translation.Z);
-		Context["laser_forward"]->setFloat(Forward.X, Forward.Y, Forward.Z);
-		Context["laser_right"]->setFloat(Right.X, Right.Y, Right.Z);
-		Context["laser_up"]->setFloat(Up.X, Up.Y, Up.Z);
-
-		Context["laser_rot"]->setMatrix4x4fv(true, &Rotation.M[0][0]);		
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
-
-
-	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+	bUpdateQueued.AtomicSet(true);
 }
 
diff --git a/Source/OptiX/Private/OptiXLaserDetectorActor.cpp b/Source/OptiX/Private/OptiXLaserDetectorActor.cpp
index 1739e32b88387558d3946d35fae57823123e4f68..c3e75b437824297538fbf7205de4e6e0c0ff7673 100644
--- a/Source/OptiX/Private/OptiXLaserDetectorActor.cpp
+++ b/Source/OptiX/Private/OptiXLaserDetectorActor.cpp
@@ -11,16 +11,6 @@
 
 #include "OptiXModule.h"
 #include "OptiXLaserActor.h"
-#include "StatsDefines.h"
-
-#include "Materials/MaterialInstance.h"
-
-#include "ImageUtils.h"
-#include "Misc/DateTime.h"
-#include "HAL/FileManager.h"
-#include "Serialization/BufferArchive.h"
-
-
 
 AOptiXLaserDetectorActor::AOptiXLaserDetectorActor(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -57,26 +47,12 @@ void AOptiXLaserDetectorActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
 
 void AOptiXLaserDetectorActor::Tick(float DeltaTime)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::Tick")
-
 	Super::Tick(DeltaTime);
-	//OnLaserTraceFinished(); // todo
+	OnLaserTraceFinished();
 }
 
 void AOptiXLaserDetectorActor::Init()
 {
-	int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
-
-
-	TextureRegion = MakeUnique<FUpdateTextureRegion2D>();
-	TextureRegion->Height = Size;
-	TextureRegion->Width = Size;
-	TextureRegion->SrcX = 0;
-	TextureRegion->SrcY = 0;
-	TextureRegion->DestX = 0;
-	TextureRegion->DestY = 0;
-
-
 	// Subscribe to the laser actor:
 	TArray<AActor*> FoundLaserActors;
 	UGameplayStatics::GetAllActorsOfClass(GetWorld(), AOptiXLaserActor::StaticClass(), FoundLaserActors);
@@ -90,95 +66,29 @@ void AOptiXLaserDetectorActor::Init()
 
 	// Set up the texture
 
+	int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+
 	DetectorResultTexture = UTexture2D::CreateTransient(Size, Size, PF_R32_FLOAT);
 	//OutputTexture->AddToRoot();
 	//// Allocate the texture HRI
 	DetectorResultTexture->UpdateResource();
 
-	ResultRenderTarget = NewObject<UTextureRenderTarget2D>();
-	ResultRenderTarget->InitCustomFormat(512, 512, EPixelFormat::PF_B8G8R8A8, true);
-	ResultRenderTarget->bAutoGenerateMips = 0;
-	//ResultRenderTarget->SRGB = 0;
-
-	//ResultRenderTarget->bForceLinearGamma = 1;
-	//ResultRenderTarget->OverrideFormat = EPixelFormat::PF_R8G8B8A8;
-	//ResultRenderTarget->RenderTargetFormat = ETextureRenderTargetFormat::RTF_RGBA8;
-	//ResultRenderTarget->SizeX = 512;
-	//ResultRenderTarget->SizeY = 512;
 
+	TextureRegion = MakeUnique<FUpdateTextureRegion2D>();
+	TextureRegion->Height = Size;
+	TextureRegion->Width = Size;
+	TextureRegion->SrcX = 0;
+	TextureRegion->SrcY = 0;
+	TextureRegion->DestX = 0;
+	TextureRegion->DestY = 0;
 
+	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
 
-	LaserTraceFinishedCallback Callback =
-		[&MaxRef = Max, &bIsColorMode = bIsColorMode, &HighlightColor = HighlightColor, TargetRes = Size, &DynamicScreenMaterial = DynamicScreenMaterial, TextureRegion = TextureRegion.Get(), DetectorResultTexture = DetectorResultTexture]
-	(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler, FRHICommandListImmediate& RHICmdList)
-	{
-		TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback")
-
-			// Get Max
-		float Max;
-		{
-			TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback::GetMax")
-
-			optix::Buffer BufferMax = *Buffers->Find("target_buffer_max");
-			Max = (float)*static_cast<unsigned int*>(BufferMax->map(0, RT_BUFFER_MAP_READ));
-			BufferMax->unmap();
-			if (Max == 0)
-			{
-				Max = 1; // TODO WHY?
-			}
-		}
-		MaxRef = Max;
-		//UE_LOG(LogTemp, Display, TEXT("MAX: %f"), Max);
-
-		FTexture2DRHIRef TextureRef = ((FTexture2DResource*)DetectorResultTexture->Resource)->GetTexture2DRHI();
-
-		{
-			TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback::GetTargetBuffer")
-
-			optix::Buffer Buffer = *Buffers->Find("target_buffer");
-			float* DataPtr = static_cast<float*>(Buffer->map(0, RT_BUFFER_MAP_READ));
-
-			//float M2 = 0;
-
-			//for (int32 i = 0; i < DetectorResultTexture->GetSizeX(); ++i)
-			//{
-			//	for (int32 j = 0; j < DetectorResultTexture->GetSizeY(); ++j)
-			//	{
-			//		M2 = FMath::Max(M2, DataPtr[i * j]);
-			//	}
-			//}
-			//UE_LOG(LogTemp, Display, TEXT("MAX2: %f"), M2);
-
-
-			//DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion, TargetRes * 4, 4, (uint8*)DataPtr);
-			{
-				TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback::GetTargetBuffer::UpdateTexture2D")
-
-				RHICmdList.UpdateTexture2D(TextureRef, 0, *TextureRegion, TargetRes * 4, (uint8*)DataPtr);
-			}
-			Buffer->unmap();
-		}
-		// todo
-		//DynamicScreenMaterial->Resource->RenderThread_UpdateParameter()
-
-		if (DynamicScreenMaterial != nullptr)
-		{
-			TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback::UpdateMaterial")
-
-			DynamicScreenMaterial->SetScalarParameterValue("ColorMode", bIsColorMode ? 1.0f : 0.0f);
-			DynamicScreenMaterial->SetVectorParameterValue("ColorMode", HighlightColor);
-			DynamicScreenMaterial->SetTextureParameterValue("ResultTexture", DetectorResultTexture);
-			DynamicScreenMaterial->SetScalarParameterValue("ResultMax", Max);
-		}
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->RegisterLaserTraceCallback(OptiXLaserTargetComponent->GetUniqueID(), Callback);
-	//FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
 }
 
 void AOptiXLaserDetectorActor::OnLaserTraceFinished()
 {
 	//UE_LOG(LogTemp, Warning, TEXT("lasertracefinished"));
-	TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::OnLaserTraceFinished")
 
 	if (bIsEnabled)
 	{
@@ -189,17 +99,29 @@ void AOptiXLaserDetectorActor::OnLaserTraceFinished()
 
 void AOptiXLaserDetectorActor::RenderDataToTarget()
 {		
-	TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::RenderDataToTarget")
-			   
-	//int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
 
-	//Max = OptiXLaserTargetComponent->GetMaxFromBuffer();
+	// Let's try something else:
 
-	//float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
-	//DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Data);
-	//OptiXLaserTargetComponent->TargetBuffer->Unmap();
+	if (OptiXLaserTargetComponent->OptiXContext == nullptr)
+	{
+		return;
+	}
 
+	int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+
+	Max = OptiXLaserTargetComponent->GetMaxFromBuffer();
 
+	float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
+	DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Data);
+	OptiXLaserTargetComponent->TargetBuffer->Unmap();
+
+	if (DynamicScreenMaterial != nullptr)
+	{
+		DynamicScreenMaterial->SetScalarParameterValue("ColorMode", bIsColorMode ? 1.0f : 0.0f);
+		DynamicScreenMaterial->SetVectorParameterValue("ColorMode", HighlightColor);
+		DynamicScreenMaterial->SetTextureParameterValue("ResultTexture", DetectorResultTexture);
+		DynamicScreenMaterial->SetScalarParameterValue("ResultMax", Max);
+	}
 
 	//int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
 	//DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)OptiXLaserTargetComponent->ColorData.GetData());
@@ -209,94 +131,41 @@ void AOptiXLaserDetectorActor::RenderDataToTarget()
 	//	DynamicScreenMaterial->SetTextureParameterValue("Texture", DetectorResultTexture);
 	//}
 
-	//if (DynamicScreenMaterial != nullptr)
-	//{
-	//	DynamicScreenMaterial->SetScalarParameterValue("ColorMode", bIsColorMode ? 1.0f : 0.0f);
-	//	DynamicScreenMaterial->SetVectorParameterValue("ColorMode", HighlightColor);
-	//}
-
-
-
-
-	//FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunctionRHI(OptiXLaserTargetComponent->GetUniqueID(), UpdateFunction);
-
 }
 
 void AOptiXLaserDetectorActor::Clear()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::Clear")
+	uint32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+
+	TArray<FColor> Black;
+	Black.AddZeroed(Size * Size);
 
-		//uint32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+	DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Black.GetData());
 
-		//TArray<FColor> Black;
-		//Black.AddZeroed(Size * Size);
+	if (DynamicScreenMaterial != nullptr)
+	{
+		DynamicScreenMaterial->SetTextureParameterValue("ResultTexture", DetectorResultTexture);
+		DynamicScreenMaterial->SetScalarParameterValue("ResultMax", 0);
+	}
 
-		//DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Black.GetData());
+	float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_WRITE));
+	FMemory::Memset(Data, 0u, Size * Size * 4);
+	OptiXLaserTargetComponent->TargetBuffer->Unmap();
 
-		//if (DynamicScreenMaterial != nullptr)
-		//{
-		//	DynamicScreenMaterial->SetTextureParameterValue("ResultTexture", DetectorResultTexture);
-		//	DynamicScreenMaterial->SetScalarParameterValue("ResultMax", 0);
-		//}
-	Max = 0.0f;
-	OptiXLaserTargetComponent->ClearOptiXBuffer();
 }
 
 void AOptiXLaserDetectorActor::Save()
 {
-	//// Hope this makes a copy - it doesn't
-	//UTexture2D* NewTexture = UTexture2D::CreateTransient(DetectorResultTexture->GetSizeX(), DetectorResultTexture->GetSizeY(), DetectorResultTexture->GetPixelFormat());
-	//NewTexture->UpdateResource();
-	//
-	//int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
-	////Max = OptiXLaserTargetComponent->GetMaxFromBuffer();
-
-	//float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
-	//NewTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Data);
-	//OptiXLaserTargetComponent->TargetBuffer->Unmap();
-
-	//SavedDetectorTextures.Add(NewTexture);
-
-
-	// For some reason just calling the export to png method doesn't save it as a working png.
-	// This is ugly, but read data manually.
-
-	FString SavedDir = FPaths::ProjectSavedDir();
-	FDateTime Time = FDateTime::Now();
-
-	FString FileName;
-	FileName.Append("DetectorScreen_");
-	FileName.Append(FString::Printf(TEXT("%d-%d_%d-%d.bmp"), Time.GetMonth(), Time.GetDay(), Time.GetHour(), Time.GetMinute()));
-	FString Path = SavedDir / FileName;
-
-
-	TArray<FColor> Pixels;
-
-	FTextureRenderTarget2DResource* Resource = (FTextureRenderTarget2DResource*)ResultRenderTarget->Resource;
+	// Hope this makes a copy - it doesn't
+	UTexture2D* NewTexture = UTexture2D::CreateTransient(DetectorResultTexture->GetSizeX(), DetectorResultTexture->GetSizeY(), DetectorResultTexture->GetPixelFormat());
+	NewTexture->UpdateResource();
+	
+	int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+	//Max = OptiXLaserTargetComponent->GetMaxFromBuffer();
 
-	if (Resource != NULL)
-	{
-		if (Resource->ReadPixels(Pixels))
-		{
-			UE_LOG(LogTemp, Display, TEXT("Successfully read pixel data from detector."));
-			FFileHelper::CreateBitmap(
-				*Path,
-				ResultRenderTarget->SizeX,
-				ResultRenderTarget->SizeY,
-				Pixels.GetData(), //const struct FColor* Data, 
-				nullptr,//struct FIntRect* SubRectangle = NULL, 
-				&IFileManager::Get(),
-				nullptr, //out filename info only 
-				false //bool bInWriteAlpha 
-			);
-			UE_LOG(LogTemp, Display, TEXT("Saved Detector Texture to %s."), *Path);
-			return;
-		}
-		else
-			UE_LOG(LogTemp, Warning, TEXT("Grabbed detector texture resource, but failed to read pixels."));
-	}
-	else
-		UE_LOG(LogTemp, Warning, TEXT("Failed to grab detector texture resource."));
+	float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
+	NewTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Data);
+	OptiXLaserTargetComponent->TargetBuffer->Unmap();
 
-	UE_LOG(LogTemp, Warning, TEXT("Failed to save detector texture."));
+	SavedDetectorTextures.Add(NewTexture);
 }
diff --git a/Source/OptiX/Private/OptiXLaserTargetComponent.cpp b/Source/OptiX/Private/OptiXLaserTargetComponent.cpp
index 4dfa1b079df02bb57cb299304eb4b6c4de8870ff..3c565dbde114aa32382365d02ba2cd3714bae370 100644
--- a/Source/OptiX/Private/OptiXLaserTargetComponent.cpp
+++ b/Source/OptiX/Private/OptiXLaserTargetComponent.cpp
@@ -8,7 +8,6 @@
 #include "Runtime/Engine/Classes/Components/StaticMeshComponent.h"
 #include "Runtime/Engine/Classes/Engine/StaticMesh.h"
 #include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
-#include "StatsDefines.h"
 
 
 UOptiXLaserTargetComponent::UOptiXLaserTargetComponent(const FObjectInitializer& ObjectInitializer)
@@ -37,9 +36,97 @@ UOptiXLaserTargetComponent::UOptiXLaserTargetComponent(const FObjectInitializer&
 
 }
 
-void UOptiXLaserTargetComponent::BeginPlay()
+void UOptiXLaserTargetComponent::UpdateOptiXComponentVariables()
 {
-	Super::BeginPlay();
+}
+
+void UOptiXLaserTargetComponent::UpdateOptiXComponent()
+{
+	if (OptiXGeometry != nullptr && OptiXTransform != nullptr && OptiXAcceleration != nullptr)
+	{
+		FMatrix T = GetComponentToWorld().ToMatrixNoScale();
+		OptiXTransform->SetMatrix(T);
+		//OptiXAcceleration->MarkDirty();
+		OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
+		FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+	}
+}
+
+void UOptiXLaserTargetComponent::InitOptiXGeometry()
+{
+	OptiXGeometry = OptiXContext->CreateGeometry();
+	OptiXGeometry->SetPrimitiveCount(1u);
+	UOptiXProgram* BB = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/laser_target.ptx", "bounds");
+	UOptiXProgram* IP = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/laser_target.ptx", "intersect");
+
+	OptiXGeometry->SetBoundingBoxProgram(BB);
+	OptiXGeometry->SetIntersectionProgram(IP);
+}
+
+void UOptiXLaserTargetComponent::InitOptiXMaterial()
+{
+	UOptiXProgram* AHPerspective = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/laser_target_material.ptx", "any_hit_radiance");
+	UOptiXProgram* CHIterative = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/laser_target_material.ptx", "closest_hit_iterative");
+
+	OptiXMaterial = OptiXContext->CreateMaterial();
+	OptiXMaterial->SetAnyHitProgram(0, AHPerspective);
+	OptiXMaterial->SetClosestHitProgram(1, CHIterative);
+}
+
+void UOptiXLaserTargetComponent::InitOptiXGroups()
+{
+	// Buffers:
+
+	TargetBuffer = OptiXContext->CreateBuffer(RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, TargetRes, TargetRes);
+	TargetBufferMax = OptiXContext->CreateBuffer(RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_UNSIGNED_INT, 1);
+
+	// Clear target buffers?
+
+	// Color lookup table here
+
+
+	OptiXGeometryInstance = OptiXContext->CreateGeometryInstance(OptiXGeometry, OptiXMaterial);
+	//OptiXAcceleration->SetProperty("refit", "1");
+
+
+
+	FVector P1 = FVector(2.89f, 0.0f, 0.0f); // TODO WHAT IS THIS THING
+
+	FVector P2 = FVector(-0.129f, 0.0f, 0.08f) * 1; // TODO WHAT IS THIS THING
+
+	OptiXGeometryInstance->SetFloat3DVector("p1", P1 * 1.0f); // Detector
+	OptiXGeometryInstance->SetFloat3DVector("p2", P2 * 1000); 
+
+	OptiXGeometryInstance->SetFloat2D("stretchXY1", 0.05f * 100.0f, 0.05f * 100.0f); // Detector
+	OptiXGeometryInstance->SetFloat2D("stretchXZ2", 0.05f * 10.0f, 0.05f * 10.0f); // Corresponds to P2
+
+	//OptiXGeometryInstance->SetInt("targetBufferWrite", 1);
+
+	OptiXGeometryInstance->SetBuffer("targetBuffer", TargetBuffer);
+	OptiXGeometryInstance->SetBuffer("targetBufferMax", TargetBufferMax);
+
+	OptiXGeometryInstance->SetFloat2D("targetBufferDim", TargetRes, TargetRes);
+
+	OptiXTransform = OptiXContext->CreateTransform();
+
+	FMatrix WorldTransform = GetComponentToWorld().ToMatrixNoScale();
+	OptiXTransform->SetMatrix(WorldTransform);
+
+	OptiXGeometryGroup = OptiXContext->CreateGeometryGroup();
+	OptiXGeometryGroup->AddChild(OptiXGeometryInstance);
+
+	OptiXAcceleration = OptiXContext->CreateAcceleration("NoAccel"); // Seems to be faster for now
+	OptiXGeometryGroup->SetAcceleration(OptiXAcceleration);
+	OptiXTransform->SetChild(OptiXGeometryGroup);
+
+	OptiXContext->GetGroup("top_object")->AddChild(OptiXTransform);
+	//FMatrix T = GetComponentToWorld().ToMatrixNoScale();
+	//OptiXTransform->SetMatrix(T);
+
+	OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
+
+
+	// Init LUT:
 
 	FTexture2DMipMap& IndexMip = LUTTexture->PlatformData->Mips[0];
 
@@ -51,129 +138,71 @@ void UOptiXLaserTargetComponent::BeginPlay()
 	}
 	IndexMip.BulkData.Unlock();
 	UE_LOG(LogTemp, Display, TEXT("Finished filling color LUT for the laser target"));
-		   
-	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXObject(GetUniqueID(), "laser_target");
-
-	FOptiXBufferData TargetBufferData;
-	TargetBufferData.Name = "target_buffer";
-	TargetBufferData.Type = RT_BUFFER_INPUT_OUTPUT;
-	TargetBufferData.Format = RT_FORMAT_FLOAT;
-	TargetBufferData.BufferWidth = TargetRes;
-	TargetBufferData.BufferHeight = TargetRes;
-
-	FOptiXBufferData TargetBufferMaxData;
-	TargetBufferMaxData.Name = "target_buffer_max";
-	TargetBufferMaxData.Type = RT_BUFFER_INPUT_OUTPUT;
-	TargetBufferMaxData.Format = RT_FORMAT_UNSIGNED_INT;
-	TargetBufferMaxData.BufferWidth = 1;
-
-	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXBuffer(GetUniqueID(), TargetBufferData);
-	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXBuffer(GetUniqueID(), TargetBufferMaxData);
-
-	FMatrix Transform = GetComponentToWorld().ToMatrixNoScale();
-	FMatrix Inverse = Transform.Inverse();
-
-	OptiXObjectInitFunction InitFunction =
-		[Transform, Inverse, &TargetRes = TargetRes]
-	(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		//FVector P1 = FVector(2.89f, 0.0f, 0.0f);
-		//FVector P2 = FVector(-0.129f, 0.0f, 0.08f) * 1;
-
-		Data->OptiXGeometryInstance["p1"]->setFloat(2.89f, 0.0f, 0.0f); // Detector
-		Data->OptiXGeometryInstance["p2"]->setFloat(-0.129f * 1000, 0.0f * 1000, 0.08f * 1000);
 
-		Data->OptiXGeometryInstance["stretchXY1"]->setFloat(0.05f * 100.0f, 0.05f * 100.0f); // Detector
-		Data->OptiXGeometryInstance["stretchXZ2"]->setFloat(0.05f * 10.0f, 0.05f * 10.0f); // Corresponds to P2
-
-		//OptiXGeometryInstance->SetInt("targetBufferWrite", 1);
-
-		Data->OptiXGeometryInstance["targetBuffer"]->setBuffer(*Buffers->Find("target_buffer"));
-		Data->OptiXGeometryInstance["targetBufferMax"]->setBuffer(*Buffers->Find("target_buffer_max"));
+}
 
-		Data->OptiXGeometryInstance["targetBufferDim"]->setFloat(TargetRes, TargetRes);
-	};
+void UOptiXLaserTargetComponent::CleanOptiXComponent()
+{
+	if(OptiXContext->GetGroup("top_object") != NULL)
+		OptiXContext->GetGroup("top_object")->RemoveChild(OptiXTransform);
 
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueInitFunction(GetUniqueID(), InitFunction);
+	OptiXTransform = nullptr;
+	Super::CleanOptiXComponent();
+	OptiXGeometryGroup = nullptr;
 }
 
-//float UOptiXLaserTargetComponent::GetMaxFromBuffer()
-//{
-//	//check(IsInRenderingThread());
-//
-//
-//	//float Max = (float)*static_cast<unsigned int*>(TargetBufferMax->MapNative(0, RT_BUFFER_MAP_READ));
-//	//TargetBufferMax->Unmap();
-//	//if (Max == 0)
-//	//{
-//	//	Max = 1; // TODO WHY?
-//	//}
-//	//return Max;
-//}
-
-void UOptiXLaserTargetComponent::ClearOptiXBuffer()
+float UOptiXLaserTargetComponent::GetMaxFromBuffer()
 {
-	OptiXObjectUpdateFunction UpdateFunction =
-		[&TargetRes =TargetRes](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	float Max = (float)*static_cast<unsigned int*>(TargetBufferMax->MapNative(0, RT_BUFFER_MAP_READ));
+	TargetBufferMax->Unmap();
+	if (Max == 0)
 	{
-		optix::Buffer Buffer = *Buffers->Find("target_buffer");
-		float* DataPtr = static_cast<float*>(Buffer->map(0, RT_BUFFER_MAP_WRITE));
-		FMemory::Memset(DataPtr, 0u, TargetRes * TargetRes * 4);
-		Buffer->unmap();
-
-
-		optix::Buffer BufferMax = *Buffers->Find("target_buffer_max");
-		*static_cast<unsigned int*>(BufferMax->map(0, RT_BUFFER_MAP_WRITE)) = 0;
-		BufferMax->unmap();
-	};
-
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+		Max = 1; // TODO WHY?
+	}
+	return Max;
 }
 
-//void UOptiXLaserTargetComponent::UpdateBufferData()
-//{
-
-
-	//TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXLaserTargetComponent::UpdateBufferData"))
+void UOptiXLaserTargetComponent::UpdateBufferData()
+{
 
-	//check(IsInRenderingThread());
+	check(IsInRenderingThread());
 
-	//float Max = GetMaxFromBuffer();
-	//UE_LOG(LogTemp, Warning, TEXT("UPDATING DEPRECATED BUFFER DATA"));
+	float Max = GetMaxFromBuffer();
+	UE_LOG(LogTemp, Warning, TEXT("UPDATING DEPRECATED BUFFER DATA"));
 
 
-	//float* Data = static_cast<float*>(TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
+	float* Data = static_cast<float*>(TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
 
-	//// Just use the previous algorithm for now without thinking too much about it
-	//// But honestly doing this on the cpu hurts so much...
-	//// TODO: Either
-	//// 1) Make optix just output the correct colors directly OR
-	//// 2) move the LUT stuff into the actual material...
+	// Just use the previous algorithm for now without thinking too much about it
+	// But honestly doing this on the cpu hurts so much...
+	// TODO: Either
+	// 1) Make optix just output the correct colors directly OR
+	// 2) move the LUT stuff into the actual material...
 
-	//float CurrentVal = 0;
-	//FColor CurrentColor;
-	//bool Tmp = false;
+	float CurrentVal = 0;
+	FColor CurrentColor;
+	bool Tmp = false;
 
-	//if (!bIsColorMode)
-	//{
-	//	for (uint32 i = 0; i < TargetRes * TargetRes; i++)
-	//	{
-	//		CurrentVal = Data[i] / Max;
-	//		Tmp = (CurrentVal >= HighlightColorValue);
-	//		ColorData[i] = (Tmp) ? HighlightColor : FLinearColor(CurrentVal, CurrentVal, CurrentVal).ToFColor(false);
-	//	}
-	//}
-	//else
-	//{
-	//	for (uint32 i = 0; i < TargetRes * TargetRes; i++)
-	//	{
-	//		CurrentVal = Data[i] / Max;
+	if (!bIsColorMode)
+	{
+		for (uint32 i = 0; i < TargetRes * TargetRes; i++)
+		{
+			CurrentVal = Data[i] / Max;
+			Tmp = (CurrentVal >= HighlightColorValue);
+			ColorData[i] = (Tmp) ? HighlightColor : FLinearColor(CurrentVal, CurrentVal, CurrentVal).ToFColor(false);
+		}
+	}
+	else
+	{
+		for (uint32 i = 0; i < TargetRes * TargetRes; i++)
+		{
+			CurrentVal = Data[i] / Max;
 
-	//		CurrentColor = ColorLUT[(int)(255.0f * CurrentVal)]; // Uh oh todo
-	//		ColorData[i] = CurrentColor;
-	//	}
+			CurrentColor = ColorLUT[(int)(255.0f * CurrentVal)]; // Uh oh todo
+			ColorData[i] = CurrentColor;
+		}
 
-	//}
-	//TargetBuffer->Unmap();
-//}
+	}
+	TargetBuffer->Unmap();
+}
 
diff --git a/Source/OptiX/Private/OptiXLensComponent.cpp b/Source/OptiX/Private/OptiXLensComponent.cpp
index 1959c9a2ee5a047383892a1faf8872b85a8fd591..7db0c253b0ce28b51d99e16a10e787a11b37f60d 100644
--- a/Source/OptiX/Private/OptiXLensComponent.cpp
+++ b/Source/OptiX/Private/OptiXLensComponent.cpp
@@ -6,7 +6,6 @@
 
 
 #include "OptiXModule.h"
-#include "StatsDefines.h"
 
 UOptiXLensComponent::UOptiXLensComponent(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -40,26 +39,32 @@ void UOptiXLensComponent::BeginPlay()
 	//UE_LOG(LogTemp, Display, TEXT("Begin Play on LensComponent, GameThread"));
 
 	FOptiXModule::Get().GetOptiXContextManager()->WavelengthChangedEvent.AddUFunction(this, "OnWavelengthChangedEvent");
+}
+
+
+void UOptiXLensComponent::UpdateOptiXComponentVariables()
+{
+	check(IsInRenderingThread());
+
 
+	OptiXGeometryInstance->SetFloat("radius", Radius1);
+	//UE_LOG(LogTemp, Display, TEXT("radius1 : %f"), Radius1);
 
-	// New functions
+	OptiXGeometryInstance->SetFloat("radius2", Radius2);
+	//UE_LOG(LogTemp, Display, TEXT("radius2 : %f"), Radius2);
 
-	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXObject(GetUniqueID(), "lens_parametric");
+	OptiXGeometryInstance->SetFloat("lensRadius", LensRadius);
+	//UE_LOG(LogTemp, Display, TEXT("lensradius : %f"), LensRadius);
 
-	// Create the required buffer and sampler 
-	FOptiXBufferData BufferData;
-	BufferData.Name = "texture_buffer";
-	BufferData.Type = RT_BUFFER_INPUT | RT_BUFFER_CUBEMAP;
-	BufferData.Format = RT_FORMAT_UNSIGNED_BYTE4;
-	BufferData.BufferWidth = 1024;
-	BufferData.BufferHeight = 1024;
-	BufferData.BufferDepth = 6;
+	OptiXGeometryInstance->SetFloat("halfCylinderLength", GetCylinderLength(LensThickness) / 2.0f);
+	//UE_LOG(LogTemp, Display, TEXT("halfCylinderLength : %f"), GetCylinderLength(LensThickness) / 2.0f);
 
-	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXBuffer(GetUniqueID(), BufferData);
-	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXTextureSampler(GetUniqueID());
+	OptiXGeometryInstance->SetInt("side1Type", static_cast<int32>(LensType1));
+	//UE_LOG(LogTemp, Display, TEXT("type1 : %i"), static_cast<int32>(LensType1));
+
+	OptiXGeometryInstance->SetInt("side2Type", static_cast<int32>(LensType2));
+	//UE_LOG(LogTemp, Display, TEXT("type2 : %i"), static_cast<int32>(LensType2));
 
-	FMatrix T = GetComponentToWorld().ToMatrixNoScale();
-	FMatrix I = T.Inverse();
 
 	double WL2 = FMath::Pow(CurrentWavelength / 1000.0, 2.0f);
 	FGlassDefinition Def = FOptiXModule::Get().GetGlassDefinitions()[GlassType];
@@ -70,71 +75,191 @@ void UOptiXLensComponent::BeginPlay()
 		Def.B.Y * WL2 / (WL2 - Def.C.Y) +
 		Def.B.Z * WL2 / (WL2 - Def.C.Z));
 
-	float HalfCylinderHeight = GetCylinderLength(LensThickness) / 2.0f;
+	OptiXMaterial->SetFloat("refraction_index", Index);
+
+	MarkDirty();
+}
 
-	// Could just capture this as well
-	OptiXObjectInitFunction InitFunction =
-		[&OptiXCubemapId = OptiXCubemapId, Transform = T, Inverse = I, 
-			Index, &Radius1 = Radius1, &Radius2 = Radius2, &LensRadius = LensRadius, 
-			HalfCylinderHeight, &LensType1 = LensType1, &LensType2 = LensType2]
-	(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+
+void UOptiXLensComponent::UpdateOptiXComponent()
+{
+	if (OptiXGeometry != nullptr && OptiXTransform != nullptr && OptiXAcceleration != nullptr)
 	{
-		// Material stuff:
-		Data->OptiXMaterial["importance_cutoff"]->setFloat(1e-2f);
-		Data->OptiXMaterial["cutoff_color"]->setFloat(0.035f, 0.102f, 0.169f);
-		Data->OptiXMaterial["fresnel_exponent"]->setFloat(3.0f);
-		Data->OptiXMaterial["fresnel_minimum"]->setFloat(0.1f);
-		Data->OptiXMaterial["fresnel_maximum"]->setFloat(1.0f);
-		//Data->OptiXMaterial["refraction_index"]->setFloat(1.4f);
-		Data->OptiXMaterial["refraction_color"]->setFloat(1.0f, 1.0f, 1.0f);
-		Data->OptiXMaterial["reflection_color"]->setFloat(1.0f, 1.0f, 1.0f);
-		Data->OptiXMaterial["refraction_maxdepth"]->setInt(10);
-		Data->OptiXMaterial["reflection_maxdepth"]->setInt(5);
-		Data->OptiXMaterial["extinction_constant"]->setFloat(FMath::Loge(0.83f), FMath::Loge(0.83f), FMath::Loge(0.83f));
+		FMatrix T = GetComponentToWorld().ToMatrixNoScale();
+		OptiXTransform->SetMatrix(T);
+		//OptiXAcceleration->MarkDirty();
+		OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
+		FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+	}
+}
+
+void UOptiXLensComponent::InitOptiXGeometry()
+{
+	OptiXGeometry = OptiXContext->CreateGeometry();
+	OptiXGeometry->SetPrimitiveCount(1u);
+	UOptiXProgram* BB = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/lens_parametric.ptx", "bounds");
+	UOptiXProgram* IP = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/lens_parametric.ptx", "intersect");
+
+	OptiXGeometry->SetBoundingBoxProgram(BB);
+	OptiXGeometry->SetIntersectionProgram(IP);
+}
+
+void UOptiXLensComponent::InitOptiXMaterial()
+{
+	UOptiXProgram* CHPerspective = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/glass_perspective_camera.ptx", "closest_hit_radiance");
+	UOptiXProgram* CHIterative = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/glass_iterative_camera.ptx", "closest_hit_radiance");
+
+	OptiXMaterial = OptiXContext->CreateMaterial();
+	OptiXMaterial->SetClosestHitProgram(0, CHPerspective);
+	OptiXMaterial->SetClosestHitProgram(1, CHIterative);
+
+	OptiXMaterial->SetFloat("importance_cutoff", 1e-2f);
+	OptiXMaterial->SetFloat3D("cutoff_color", 0.035f, 0.102f, 0.169f);
+	OptiXMaterial->SetFloat("fresnel_exponent", 3.0f);
+	OptiXMaterial->SetFloat("fresnel_minimum", 0.1f);
+	OptiXMaterial->SetFloat("fresnel_maximum", 1.0f);
+	OptiXMaterial->SetFloat("refraction_index", 1.4f);
+
+	OptiXMaterial->SetFloat3D("refraction_color", 1.0f, 1.0f, 1.0f);
+	OptiXMaterial->SetFloat3D("reflection_color", 1.0f, 1.0f, 1.0f);
+
+	OptiXMaterial->SetInt("refraction_maxdepth", 10);
+	OptiXMaterial->SetInt("reflection_maxdepth", 5);
+
+	OptiXMaterial->SetFloat3D("extinction_constant", FMath::Loge(0.83f), FMath::Loge(0.83f), FMath::Loge(0.83f));
+
+	OptiXMaterial->SetInt("lens_id", OptiXCubemapId);
+
+}
+
+void UOptiXLensComponent::InitOptiXGroups()
+{
+	OptiXGeometryInstance = OptiXContext->CreateGeometryInstance(OptiXGeometry, OptiXMaterial);
+
+	OptiXGeometryInstance->SetFloat3D("center", 0.0f, 0.0f, 0.0f);
+
+	OptiXGeometryInstance->SetFloat3DVector("orientation", {0, 0, -1}); // TODO Why this vector?!?!
+
+
+	SetRadius1(Radius1);
+	SetRadius2(Radius2);
+	SetLensRadius(LensRadius);
+	SetThickness(LensThickness);
+	SetLensType1(LensType1);
+	SetLensType2(LensType2);
+	SetWavelength(CurrentWavelength); // min value
+
+	OptiXTransform = OptiXContext->CreateTransform();
+
+	FMatrix WorldTransform = GetComponentToWorld().ToMatrixNoScale();
+	OptiXTransform->SetMatrix(WorldTransform);
+
+	OptiXGeometryGroup = OptiXContext->CreateGeometryGroup();
+	OptiXGeometryGroup->AddChild(OptiXGeometryInstance);
+
+	OptiXAcceleration = OptiXContext->CreateAcceleration("NoAccel"); // Seems to be faster for now
+	//OptiXAcceleration->SetProperty("refit", "1");
 
-		Data->OptiXMaterial["lens_id"]->setInt(OptiXCubemapId); // todo
-		Data->OptiXMaterial["refraction_index"]->setFloat(Index);
+	OptiXGeometryGroup->SetAcceleration(OptiXAcceleration);
 
-		// General stuff
+	OptiXTransform->SetChild(OptiXGeometryGroup);
 
-		Data->OptiXGeometryInstance["center"]->setFloat(0.0f, 0.0f, 0.0f);		
-		Data->OptiXGeometryInstance["orientation"]->setFloat(0, 0, -1); 
-		Data->OptiXGeometryInstance["radius"]->setFloat(Radius1);
-		Data->OptiXGeometryInstance["radius2"]->setFloat(Radius2);
-		Data->OptiXGeometryInstance["lensRadius"]->setFloat(LensRadius);
-		Data->OptiXGeometryInstance["halfCylinderLength"]->setFloat(HalfCylinderHeight);
-		Data->OptiXGeometryInstance["side1Type"]->setInt(static_cast<int32>(LensType1));
-		Data->OptiXGeometryInstance["side2Type"]->setInt(static_cast<int32>(LensType2));
-		Data->OptiXTransform->setMatrix(true, &Transform.M[0][0], &Inverse.M[0][0]);
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
 
-		// Texture Sampler and Buffer
-		TextureSampler->setWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
-		TextureSampler->setWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
-		TextureSampler->setWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
-		TextureSampler->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
-		TextureSampler->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
-		TextureSampler->setMaxAnisotropy(1.0f);
-		TextureSampler->setMipLevelCount(1u);
-		TextureSampler->setArraySize(1u);
+	OptiXContext->GetGroup("top_object")->AddChild(OptiXTransform);
+	MarkDirty();
+}
 
-		optix::Buffer TextureBuffer = *Buffers->Find("texture_buffer");
+void UOptiXLensComponent::InitCubemap(FRHICommandListImmediate & RHICmdList)
+{
+	UE_LOG(LogTemp, Display, TEXT("Init Cubemap"));
 
-		TextureSampler->setBuffer(0u, 0u, TextureBuffer);
-		TextureSampler->setFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
+	//OptiXContext->SetBuffer("skyboxBuffer", CubemapBuffer);
 
-		FOptiXModule::Get().GetOptiXContextManager()->AddCubemapToBuffer(OptiXCubemapId, TextureSampler->getId());
+	CubemapSampler = OptiXContext->CreateTextureSampler();
+	//CubemapSampler->AddToRoot();
+	CubemapSampler->SetWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
+	CubemapSampler->SetWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
+	CubemapSampler->SetWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
+	CubemapSampler->SetIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
+	CubemapSampler->SetReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
+	CubemapSampler->SetMaxAnisotropy(1.0f);
+	CubemapSampler->SetMipLevelCount(1u);
+	CubemapSampler->SetArraySize(1u);
 
-		UE_LOG(LogTemp, Display, TEXT("Finished Init Cubemap"));
 
-	};
+	CubemapBuffer = OptiXContext->CreateCubemapBuffer(1024, 1024);
+	//CubemapBuffer->AddToRoot();
 
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueInitFunction(GetUniqueID(), InitFunction);
+	CubemapSampler->SetBufferWithTextureIndexAndMiplevel(0u, 0u, CubemapBuffer);
+	CubemapSampler->SetFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
+	
 
-	RequestCubemapUpdate();
+	UpdateCubemap(RHICmdList);
 
-	UE_LOG(LogTemp, Display, TEXT("Enqueued Cubemap Init"));
+
+	// Writes the variable into the input buffer
+	FOptiXModule::Get().GetOptiXContextManager()->AddCubemapToBuffer(OptiXCubemapId, CubemapSampler->GetId());
+	UE_LOG(LogTemp, Display, TEXT("Finished Init Cubemap"));
+
+}
+
+void UOptiXLensComponent::UpdateCubemap(FRHICommandListImmediate & RHICmdList)
+{
+
+	UE_LOG(LogTemp, Display, TEXT("Updating Cubemap"));
+
+
+	int32 X = 1024; // todo hardcoded
+	int32 Y = X;
+
+	TArray<TArray<FColor>> SurfaceDataCube;
+	SurfaceDataCube.SetNumZeroed(6);
+
+	//TArray<FLinearColor> SD;
+
+	optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->MapNative());
+
+	FTextureRenderTargetCubeResource* RenderTargetCube = static_cast<FTextureRenderTargetCubeResource*>(CubeRenderTarget->GetRenderTargetResource());
+
+	FIntRect InRectCube = FIntRect(0, 0, RenderTargetCube->GetSizeXY().X, RenderTargetCube->GetSizeXY().Y);
+	FReadSurfaceDataFlags FlagsCube0(RCM_UNorm, CubeFace_PosX);
+	FReadSurfaceDataFlags FlagsCube1(RCM_UNorm, CubeFace_NegX);
+	FReadSurfaceDataFlags FlagsCube2(RCM_UNorm, CubeFace_PosY);
+	FReadSurfaceDataFlags FlagsCube3(RCM_UNorm, CubeFace_NegY);
+	FReadSurfaceDataFlags FlagsCube4(RCM_UNorm, CubeFace_PosZ);
+	FReadSurfaceDataFlags FlagsCube5(RCM_UNorm, CubeFace_NegZ);
+
+	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[0], FlagsCube0);
+	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[1], FlagsCube1);
+	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[2], FlagsCube2);
+	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[3], FlagsCube3);
+	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[4], FlagsCube4);
+	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[5], FlagsCube5);
+
+	uint32 MemSize = (X * Y * sizeof(FColor));
+	FMemory::Memcpy(BufferData, SurfaceDataCube[0].GetData(), MemSize); // front
+	FMemory::Memcpy(BufferData + X * Y * 1, SurfaceDataCube[1].GetData(), MemSize); // back
+	FMemory::Memcpy(BufferData + X * Y * 2, SurfaceDataCube[2].GetData(), MemSize); // 
+	FMemory::Memcpy(BufferData + X * Y * 3, SurfaceDataCube[3].GetData(), MemSize); // 
+	FMemory::Memcpy(BufferData + X * Y * 4, SurfaceDataCube[4].GetData(), MemSize); // 
+	FMemory::Memcpy(BufferData + X * Y * 5, SurfaceDataCube[5].GetData(), MemSize); //
+
+	CubemapBuffer->Unmap();
+
+	UE_LOG(LogTemp, Display, TEXT("Finished Updating Cubemap"));
+
+
+}
+
+
+void UOptiXLensComponent::CleanOptiXComponent()
+{
+	if(OptiXContext != NULL && OptiXContext->GetGroup("top_object") != NULL)
+		OptiXContext->GetGroup("top_object")->RemoveChild(OptiXTransform);
+	OptiXTransform = nullptr;
+
+	Super::CleanOptiXComponent();
+	OptiXGeometryGroup = nullptr;
 
 }
 
@@ -153,18 +278,9 @@ void UOptiXLensComponent::SetThickness(float Thickness)
 {
 	UE_LOG(LogTemp, Display, TEXT("Setting Thickness: %f"), Thickness);
 	LensThickness = Thickness;
-	float HalfCylinderHeight = GetCylinderLength(LensThickness) / 2.0f;
-
-	OptiXObjectUpdateFunction UpdateFunction =
-		[HalfCylinderHeight](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		Data->OptiXGeometryInstance["halfCylinderLength"]->setFloat(HalfCylinderHeight);
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
-
-	OnLensThicknessChanged.Broadcast(LensThickness);
+	QueueOptiXContextUpdate();
+	if(IsInGameThread())
+		OnLensThicknessChanged.Broadcast(LensThickness);
 }
 
 float UOptiXLensComponent::GetThickness() const
@@ -173,57 +289,11 @@ float UOptiXLensComponent::GetThickness() const
 	return LensThickness;
 }
 
-float UOptiXLensComponent::GetThicknessForCylinderLength(float Length) const
-{
-	// With silly conversions:
-		// Halfsphere thickness
-	float HalfThickness1;
-	float HalfThickness2;
-
-	// Side 1
-	if (LensType1 == ELensSideType::PLANE)
-	{
-		HalfThickness1 = 0;
-	}
-	else
-	{
-		HalfThickness1 = Radius1 - FMath::Sqrt(-LensRadius * LensRadius + Radius1 * Radius1);
-		if (LensType1 == ELensSideType::CONCAVE)
-		{
-			HalfThickness1 *= -1;
-		}
-	}
-
-	// Side 2
-	if (LensType2 == ELensSideType::PLANE)
-	{
-		HalfThickness2 = 0;
-	}
-	else
-	{
-		HalfThickness2 = Radius2 - FMath::Sqrt(-LensRadius * LensRadius + Radius2 * Radius2);
-		if (LensType2 == ELensSideType::CONCAVE)
-		{
-			HalfThickness2 *= -1;
-		}
-	}
-	return Length + HalfThickness1 + HalfThickness2;
-}
-
 void UOptiXLensComponent::SetRadius1(float Radius)
 {
 	UE_LOG(LogTemp, Display, TEXT("Setting Radius 1: %f"), Radius);
 	Radius1 = Radius;
-	OptiXObjectUpdateFunction UpdateFunction =
-		[&Radius1 = Radius1](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		Data->OptiXGeometryInstance["radius"]->setFloat(Radius1);
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
-
+	QueueOptiXContextUpdate();
 }
 
 float UOptiXLensComponent::GetRadius1() const
@@ -236,15 +306,7 @@ void UOptiXLensComponent::SetRadius2(float Radius)
 
 	UE_LOG(LogTemp, Display, TEXT("Setting Radius 2: %f"), Radius);
 	Radius2 = Radius;
-	OptiXObjectUpdateFunction UpdateFunction =
-		[&Radius2 = Radius2](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		Data->OptiXGeometryInstance["radius2"]->setFloat(Radius2);
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+	QueueOptiXContextUpdate();
 }
 
 float UOptiXLensComponent::GetRadius2() const
@@ -256,18 +318,9 @@ void UOptiXLensComponent::SetLensRadius(float Radius)
 {
 	UE_LOG(LogTemp, Display, TEXT("Setting Lens Radius: %f"), Radius);
 	LensRadius = Radius;
-	
-	OptiXObjectUpdateFunction UpdateFunction =
-		[&LensRadius = LensRadius](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		Data->OptiXGeometryInstance["lensRadius"]->setFloat(LensRadius);
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
-
-	OnLensRadiusChanged.Broadcast(Radius);
+	QueueOptiXContextUpdate();
+	if (IsInGameThread())
+		OnLensRadiusChanged.Broadcast(Radius);
 }
 
 float UOptiXLensComponent::GetLensRadius() const
@@ -280,16 +333,9 @@ void UOptiXLensComponent::SetLensType1(ELensSideType Type)
 	UE_LOG(LogTemp, Display, TEXT("Setting Lens Side 1 Type: %i"), static_cast<int>(Type));
 
 	LensType1 = Type;
-	OptiXObjectUpdateFunction UpdateFunction =
-		[&LensType1 = LensType1](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		Data->OptiXGeometryInstance["side1Type"]->setInt(static_cast<int>(LensType1));
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
-	SetThickness(LensThickness);
+	// Recalculate Thickness and set new half cylinder length
+	//SetThickness(LensThickness);
+	QueueOptiXContextUpdate();
 }
 
 ELensSideType UOptiXLensComponent::GetLensType1() const
@@ -302,16 +348,9 @@ void UOptiXLensComponent::SetLensType2(ELensSideType Type)
 	UE_LOG(LogTemp, Display, TEXT("Setting Lens Side 2 Type: %i"), static_cast<int>(Type));
 
 	LensType2 = Type;
-	OptiXObjectUpdateFunction UpdateFunction =
-		[&LensType2 = LensType2](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		Data->OptiXGeometryInstance["side2Type"]->setInt(static_cast<int>(LensType2));
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
-	SetThickness(LensThickness);
+	// Recalculate Thickness and set new half cylinder length
+	//SetThickness(LensThickness);
+	QueueOptiXContextUpdate();
 }
 
 ELensSideType UOptiXLensComponent::GetLensType2() const
@@ -325,6 +364,7 @@ void UOptiXLensComponent::SetGlassType(FString Type)
 
 	GlassType = Type;
 	SetWavelength(CurrentWavelength); // ???
+	QueueOptiXContextUpdate();
 }
 
 FString UOptiXLensComponent::GetGlassType() const
@@ -336,30 +376,38 @@ void UOptiXLensComponent::SetWavelength(float WL)
 {
 	UE_LOG(LogTemp, Display, TEXT("Setting new WL in lens: %s"), *GetName());
 	CurrentWavelength = WL;
+	QueueOptiXContextUpdate();
+}
 
-	double WL2 = FMath::Pow(CurrentWavelength / 1000.0, 2.0f);
-	FGlassDefinition Def = FOptiXModule::Get().GetGlassDefinitions()[GlassType];
-	//UE_LOG(LogTemp, Display, TEXT("Glass Def: %f, %f, %F"), Def.B.X, Def.B.Y, Def.B.Z);
+float UOptiXLensComponent::GetWavelength() const
+{
+	return CurrentWavelength;
+}
+
+void UOptiXLensComponent::MarkDirty()
+{
+
+	UE_LOG(LogTemp, Display, TEXT("Marking Dirty"));
 
-	float Index = FMath::Sqrt(1 +
-		Def.B.X * WL2 / (WL2 - Def.C.X) +
-		Def.B.Y * WL2 / (WL2 - Def.C.Y) +
-		Def.B.Z * WL2 / (WL2 - Def.C.Z));
 
-	OptiXObjectUpdateFunction UpdateFunction =
-		[Index](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	if (OptiXGeometry != nullptr)
 	{
-		Data->OptiXGeometryInstance["refraction_index"]->setFloat(Index);
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+		OptiXGeometry->MarkDirty();
+	}
+	if (OptiXAcceleration != nullptr)
+	{
+		OptiXAcceleration->MarkDirty();
+	}
 
-	};
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
-}
+	//manager_->TopAccelerationMarkDirty();
+	UOptiXAcceleration* TopAccel = OptiXContext->GetGroup("top_object")->GetAcceleration();
+	if (TopAccel != nullptr)
+	{
+		TopAccel->MarkDirty(); // This should never be null, but check anyway
+	}
+
+	//RecalculateBoundingBox(); // TODO
 
-float UOptiXLensComponent::GetWavelength() const
-{
-	return CurrentWavelength;
 }
 
 
@@ -400,6 +448,24 @@ float UOptiXLensComponent::GetCylinderLength(float Thickness) const
 }
 
 
+void UOptiXLensComponent::RecalculateBoundingBox()
+{
+
+	// Do we even need this? Seems like it was just used for phoenix stuff TODO
+	return;
+
+	// TODO Shouldn't have to call the getter here - this should just be the actor rotation transform?
+	/*FVector Orientation = OptiXGeometry->GetFloat3D("orientation");
+	float HalfThickness1;	
+	LensType1 == ELensSideType::CONVEX ? HalfThickness1 = Radius1 - FMath::Sqrt(-LensRadius * LensRadius + Radius1 * Radius1) : HalfThickness1 = 0;
+
+	float HalfThickness2;
+	LensType2 == ELensSideType::CONVEX ? HalfThickness2 = Radius2 - FMath::Sqrt(-LensRadius * LensRadius + Radius2 * Radius2) : HalfThickness2 = 0;
+*/
+	// TODO
+
+}
+
 TArray<FString> UOptiXLensComponent::GetGlassDefinitionNames()
 {
 	TArray<FString> Names;
diff --git a/Source/OptiX/Private/OptiXMaterial.cpp b/Source/OptiX/Private/OptiXMaterial.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..af91ecdc28e65d03191c0a195a99d39d048c1745
--- /dev/null
+++ b/Source/OptiX/Private/OptiXMaterial.cpp
@@ -0,0 +1,251 @@
+#include "OptiXMaterial.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+
+
+void UOptiXMaterial::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Material BeginDestroy"));
+
+	DestroyOptiXObject();
+
+	Super::BeginDestroy();
+}
+
+void UOptiXMaterial::DestroyOptiXObject()
+{
+	if (NativeMaterial != NULL)
+	{
+		//NativeMaterial->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->MaterialsToDeleteQueue.Enqueue(NativeMaterial);
+	}
+
+	NativeMaterial = NULL;
+	ClosestHitPrograms.Empty();
+	AnyHitProgram = nullptr;
+}
+
+void UOptiXMaterial::SetFloat(FString string, float Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
+}
+
+void UOptiXMaterial::SetFloat2D(FString string, float Var1, float Var2)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
+
+}
+
+void UOptiXMaterial::SetFloat3DVector(FString string, FVector Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
+
+}
+
+void UOptiXMaterial::SetFloat3D(FString string, float Var1, float Var2, float Var3)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
+
+}
+
+void UOptiXMaterial::SetFloat4DVector(FString string, FVector4 Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
+
+}
+
+void UOptiXMaterial::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
+
+}
+
+void UOptiXMaterial::SetInt(FString string, int32 Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
+
+}
+
+void UOptiXMaterial::SetInt2D(FString string, int32 Var1, int32 Var2)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
+
+}
+
+void UOptiXMaterial::SetInt3DVector(FString string, FIntVector Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
+
+}
+
+void UOptiXMaterial::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
+
+}
+
+//void UOptiXMaterial::SetInt4DVector(FString string, FIntVector4 Var)
+//{
+//	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z, Var.W);
+//
+//}
+
+void UOptiXMaterial::SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3, Var4);
+
+}
+
+void UOptiXMaterial::SetUint(FString string, uint8 Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var);
+}
+
+void UOptiXMaterial::SetUint2D(FString string, uint8 Var1, uint8 Var2)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2);
+
+}
+
+void UOptiXMaterial::SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3);
+
+}
+
+void UOptiXMaterial::SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3, Var4);
+
+}
+
+float UOptiXMaterial::GetFloat(FString string)
+{
+	return NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat();
+}
+
+FVector2D UOptiXMaterial::GetFloat2D(FString string)
+{
+	optix::float2 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat2();
+	return FVector2D(V.x, V.y);
+}
+
+FVector UOptiXMaterial::GetFloat3D(FString string)
+{
+	optix::float3 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat3();
+	return FVector(V.x, V.y, V.z);
+}
+
+FVector4 UOptiXMaterial::GetFloat4D(FString string)
+{
+	optix::float4 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat4();
+	return FVector4(V.x, V.y, V.z, V.w);
+}
+
+int32 UOptiXMaterial::GetInt(FString string)
+{
+	return NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt();
+}
+
+FIntPoint UOptiXMaterial::GetInt2D(FString string)
+{
+	optix::int2 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt2();
+	return FIntPoint(V.x, V.y);
+}
+
+FIntVector UOptiXMaterial::GetInt3D(FString string)
+{
+	optix::int3 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt3();
+	return FIntVector(V.x, V.y, V.z);
+}
+
+//FIntVector4 UOptiXMaterial::GetInt4D(FString string)
+//{
+//	optix::int4 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt4();
+//	return FIntVector4(V.x, V.y, V.z, V.w);
+//}
+
+//uint8 UOptiXMaterial::GetUint(FString string)
+//{
+//	return static_cast<uint8>(NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint());
+//}
+//
+//void UOptiXMaterial::GetUint2D(FString & string, uint8 & Var1, uint8 & Var2)
+//{
+//	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2);
+//
+//}
+//
+//void UOptiXMaterial::GetUint3D(FString string, uint8 & Var1, uint8 & Var2, uint8 & Var3)
+//{
+//	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2, Var3);
+//}
+//
+//FUintVector4 UOptiXMaterial::GetUint4D(FString string)
+//{
+//	optix::uint4 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint4();
+//	return FUintVector4(V.x, V.y, V.z, V.w);
+//}
+
+
+void UOptiXMaterial::SetClosestHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program)
+{
+	try
+	{
+		NativeMaterial->setClosestHitProgram(RayTypeIndex, Program->GetNativeProgram());
+		if (ClosestHitPrograms.IsValidIndex(RayTypeIndex))
+		{
+			ClosestHitPrograms[RayTypeIndex] = Program;
+		}
+		else
+		{
+			ClosestHitPrograms.SetNum(RayTypeIndex + 1);
+			ClosestHitPrograms[RayTypeIndex] = Program;
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
+	}
+}
+
+UOptiXProgram* UOptiXMaterial::GetClosestHitProgram(uint32 RayTypeIndex)
+{
+	UOptiXProgram* P = nullptr;
+	try
+	{
+		optix::Program Native = NativeMaterial->getClosestHitProgram(RayTypeIndex);
+		if (ClosestHitPrograms.IsValidIndex(RayTypeIndex))
+		{
+			P = ClosestHitPrograms[RayTypeIndex];
+		}
+		else
+		{
+			UE_LOG(LogTemp, Error, TEXT("OptiX Error: Wrong index in GetClosestHitProgram"));
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
+	}
+	return P;
+}
+
+void UOptiXMaterial::SetAnyHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program)
+{
+	AnyHitProgram = Program;
+	NativeMaterial->setAnyHitProgram(RayTypeIndex, Program->GetNativeProgram());
+}
+
+UOptiXProgram* UOptiXMaterial::GetAnyHitProgram(uint32 RayTypeIndex)
+{
+	return AnyHitProgram;
+}
diff --git a/Source/OptiX/Private/OptiXModule.cpp b/Source/OptiX/Private/OptiXModule.cpp
index 8d3c9c95377369925ed8be46dff73e7468538e1a..7632bd4ecb4b82a96c7dcf816985bbbc9da2162a 100644
--- a/Source/OptiX/Private/OptiXModule.cpp
+++ b/Source/OptiX/Private/OptiXModule.cpp
@@ -207,7 +207,7 @@ void FOptiXModule::LoadSceneData()
 				if (bFirstSide) // Gathering values for side 1 of the lense
 				{
 					// Check if we have gathered all values
-					if (!isnan(Curvature) && !isnan(Diameter) && GlassType.Len() > 0 && !isinf(Pos))
+					if (!isnan(Curvature) && !isnan(Diameter) && GlassType.Len() > 0)
 						bFirstSide = false; // Start gathering data for second side
 					else // reset, not a lens
 					{
@@ -223,7 +223,7 @@ void FOptiXModule::LoadSceneData()
 				}
 				else // first side is completed, check if second side is valid
 				{
-					if (!isnan(Curvature2) && !isnan(Diameter2) && !isnan(Thickness) && GlassType.Len() > 0 && !isinf(Pos))
+					if (!isnan(Curvature2) && !isnan(Diameter2) && !isnan(Thickness) && GlassType.Len() > 0)
 					{
 						FLensData LensData;
 						LensData.GlassType = GlassType;
@@ -265,9 +265,9 @@ void FOptiXModule::LoadSceneData()
 				if (Arguments.IsValidIndex(1))
 				{
 					if (bFirstSide)
-						Curvature = FCString::Atof(*Arguments[1]) * 10;  // apparently curvature is in mm?
+						Curvature = FCString::Atof(*Arguments[1]);
 					else 
-						Curvature2 = FCString::Atof(*Arguments[1]) * 10; // apparently curvature is in mm?
+						Curvature2 = FCString::Atof(*Arguments[1]);
 				}
 				else
 					UE_LOG(LogTemp, Warning, TEXT("Could not parse curvature, Line is: '%s'."), *Line);
@@ -278,18 +278,13 @@ void FOptiXModule::LoadSceneData()
 				{
 					if (bFirstSide)
 					{
-						Thickness = FCString::Atof(*Arguments[1]) / 10.0f;	// in cm (was 1000)
+						Thickness = FCString::Atof(*Arguments[1]) / 10.0f;	// in cm
 						Pos = isnan(AccDist) ? 0 : AccDist;
 					}
-					float AccNew = FCString::Atof(*Arguments[1]) / 10.0f;
-					if (isinf(AccNew))
-						AccNew = 100; // in cm, this should be the end of the table but need to adjust capture for that
-					if (isnan(AccDist))
-						AccDist = AccNew;	// in cm (was 1000)
-					else if (isinf(AccDist)) // infinity is tricky, not sure what it's supposed to mean. 
-						AccDist = AccNew;	// in cm (was 1000)
+					if(isnan(AccDist))
+						AccDist = FCString::Atof(*Arguments[1]) / 10.0f;	// in cm
 					else
-						AccDist += AccNew;	
+						AccDist += FCString::Atof(*Arguments[1]) / 10.0f;	// in cm
 				}
 				else
 					UE_LOG(LogTemp, Warning, TEXT("Could not parse disz, Line is: '%s'."), *Line);
@@ -299,9 +294,9 @@ void FOptiXModule::LoadSceneData()
 				if (Arguments.IsValidIndex(1))
 				{
 					if (bFirstSide)
-						Diameter = FCString::Atof(*Arguments[1]) / 10.0f; // in cm (was 1000)
+						Diameter = FCString::Atof(*Arguments[1]) / 10.0f; // in cm
 					else
-						Diameter2 = FCString::Atof(*Arguments[1]) / 10.0f;	// in cm (was 1000)
+						Diameter2 = FCString::Atof(*Arguments[1]) / 10.0f;	// in cm
 				}
 				else
 					UE_LOG(LogTemp, Warning, TEXT("Could not parse diameter, Line is: '%s'."), *Line);
@@ -311,11 +306,6 @@ void FOptiXModule::LoadSceneData()
 				if (Arguments.IsValidIndex(1))
 				{
 					GlassType = Arguments[1];
-					if (!GlassDefinitionsMap.Contains(GlassType))
-					{
-						UE_LOG(LogTemp, Warning, TEXT("    Glass Type not found in definitions! Falling back to BK7!"), *GlassType);
-						GlassType = "BK7";
-					}
 				}
 				else
 					UE_LOG(LogTemp, Warning, TEXT("Could not parse glass, Line is: '%s'."), *Line);
@@ -354,7 +344,6 @@ void FOptiXModule::LoadSceneData()
 			UE_LOG(LogTemp, Display, TEXT("    Lens Type Side 2: %s"), *Type2);
 			UE_LOG(LogTemp, Display, TEXT("    Lens Thickness: %f"), Lens.Thickness);
 			UE_LOG(LogTemp, Display, TEXT("    Lens Glass: %s"), *Lens.GlassType);
-
 			UE_LOG(LogTemp, Display, TEXT("    ---------------------------------------------------"));
 		}
 	}
diff --git a/Source/OptiX/Private/OptiXMotionControllerComponent.cpp b/Source/OptiX/Private/OptiXMotionControllerComponent.cpp
deleted file mode 100644
index 30f24c1290384220af5557628b759b2ef08eac74..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/OptiXMotionControllerComponent.cpp
+++ /dev/null
@@ -1,704 +0,0 @@
-
-// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
-//
-#include "OptiXMotionControllerComponent.h"
-#include "GameFramework/Pawn.h"
-#include "PrimitiveSceneProxy.h"
-#include "Misc/ScopeLock.h"
-#include "EngineGlobals.h"
-#include "Engine/Engine.h"
-#include "Features/IModularFeatures.h"
-#include "IMotionController.h"
-#include "PrimitiveSceneInfo.h"
-#include "Engine/World.h"
-#include "GameFramework/WorldSettings.h"
-#include "IXRSystemAssets.h"
-#include "Components/StaticMeshComponent.h"
-#include "MotionDelayBuffer.h"
-#include "UObject/VRObjectVersion.h"
-#include "UObject/UObjectGlobals.h" // for FindObject<>
-#include "XRMotionControllerBase.h"
-#include "IXRTrackingSystem.h"
-
-DEFINE_LOG_CATEGORY_STATIC(LogMotionControllerComponent, Log, All);
-
-namespace {
-	/** This is to prevent destruction of motion controller components while they are
-		in the middle of being accessed by the render thread */
-	FCriticalSection CritSect;
-
-	/** Console variable for specifying whether motion controller late update is used */
-	TAutoConsoleVariable<int32> CVarEnableMotionControllerLateUpdate(
-		TEXT("vr.EnableMotionControllerLateUpdate"),
-		1,
-		TEXT("This command allows you to specify whether the motion controller late update is applied.\n")
-		TEXT(" 0: don't use late update\n")
-		TEXT(" 1: use late update (default)"),
-		ECVF_Cheat);
-} // anonymous namespace
-
-FName UOptiXMotionControllerComponent::CustomModelSourceId(TEXT("Custom"));
-
-
-//=============================================================================
-UOptiXMotionControllerComponent::UOptiXMotionControllerComponent(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-	, RenderThreadComponentScale(1.0f, 1.0f, 1.0f)
-{
-	PrimaryComponentTick.bCanEverTick = true;
-	PrimaryComponentTick.bStartWithTickEnabled = true;
-	PrimaryComponentTick.TickGroup = TG_PrePhysics;
-	PrimaryComponentTick.bTickEvenWhenPaused = true;
-
-	PlayerIndex = 0;
-	MotionSource = FXRMotionControllerBase::LeftHandSourceId;
-	bDisableLowLatencyUpdate = false;
-	bHasAuthority = false;
-	bAutoActivate = true;
-
-	// ensure InitializeComponent() gets called
-	bWantsInitializeComponent = true;
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::BeginDestroy()
-{
-	Super::BeginDestroy();
-	if (ViewExtension.IsValid())
-	{
-		{
-			// This component could be getting accessed from the render thread so it needs to wait
-			// before clearing MotionControllerComponent and allowing the destructor to continue
-			FScopeLock ScopeLock(&CritSect);
-			ViewExtension->MotionControllerComponent = NULL;
-		}
-
-		ViewExtension.Reset();
-	}
-}
-
-void UOptiXMotionControllerComponent::CreateRenderState_Concurrent()
-{
-	Super::CreateRenderState_Concurrent();
-	RenderThreadRelativeTransform = GetRelativeTransform();
-	RenderThreadComponentScale = GetComponentScale();
-}
-
-void UOptiXMotionControllerComponent::SendRenderTransform_Concurrent()
-{
-	struct FPrimitiveUpdateRenderThreadRelativeTransformParams
-	{
-		FTransform RenderThreadRelativeTransform;
-		FVector RenderThreadComponentScale;
-	};
-
-	FPrimitiveUpdateRenderThreadRelativeTransformParams UpdateParams;
-	UpdateParams.RenderThreadRelativeTransform = GetRelativeTransform();
-	UpdateParams.RenderThreadComponentScale = GetComponentScale();
-
-	ENQUEUE_RENDER_COMMAND(UpdateRTRelativeTransformCommand)(
-		[UpdateParams, this](FRHICommandListImmediate& RHICmdList)
-	{
-		RenderThreadRelativeTransform = UpdateParams.RenderThreadRelativeTransform;
-		RenderThreadComponentScale = UpdateParams.RenderThreadComponentScale;
-	});
-
-	Super::SendRenderTransform_Concurrent();
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
-{
-	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
-
-	if (bIsActive)
-	{
-		FVector Position;
-		FRotator Orientation;
-		float WorldToMeters = GetWorld() ? GetWorld()->GetWorldSettings()->WorldToMeters : 100.0f;
-		const bool bNewTrackedState = PollControllerState(Position, Orientation, WorldToMeters);
-		if (bNewTrackedState)
-		{
-			SetRelativeLocationAndRotation(Position, Orientation);
-		}
-
-		// if controller tracking just kicked in 
-		if (!bTracked && bNewTrackedState && bDisplayDeviceModel && DisplayModelSource != UOptiXMotionControllerComponent::CustomModelSourceId)
-		{
-			RefreshDisplayComponent();
-		}
-		bTracked = bNewTrackedState;
-
-		if (!ViewExtension.IsValid() && GEngine)
-		{
-			ViewExtension = FSceneViewExtensions::NewExtension<FViewExtension>(this);
-		}
-	}
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::SetShowDeviceModel(const bool bShowDeviceModel)
-{
-	if (bDisplayDeviceModel != bShowDeviceModel)
-	{
-		bDisplayDeviceModel = bShowDeviceModel;
-#if WITH_EDITORONLY_DATA
-		const UWorld* MyWorld = GetWorld();
-		const bool bIsGameInst = MyWorld && MyWorld->WorldType != EWorldType::Editor && MyWorld->WorldType != EWorldType::EditorPreview;
-
-		if (!bIsGameInst)
-		{
-			// tear down and destroy the existing component if we're an editor inst
-			RefreshDisplayComponent(/*bForceDestroy =*/true);
-		}
-		else
-#endif
-			if (DisplayComponent)
-			{
-				DisplayComponent->SetHiddenInGame(bShowDeviceModel, /*bPropagateToChildren =*/false);
-			}
-			else if (!bShowDeviceModel)
-			{
-				RefreshDisplayComponent();
-			}
-	}
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::SetDisplayModelSource(const FName NewDisplayModelSource)
-{
-	if (NewDisplayModelSource != DisplayModelSource)
-	{
-		DisplayModelSource = NewDisplayModelSource;
-		RefreshDisplayComponent();
-	}
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::SetCustomDisplayMesh(UStaticMesh* NewDisplayMesh)
-{
-	if (NewDisplayMesh != CustomDisplayMesh)
-	{
-		CustomDisplayMesh = NewDisplayMesh;
-		if (DisplayModelSource == UOptiXMotionControllerComponent::CustomModelSourceId)
-		{
-			if (UStaticMeshComponent* AsMeshComponent = Cast<UStaticMeshComponent>(DisplayComponent))
-			{
-				AsMeshComponent->SetStaticMesh(NewDisplayMesh);
-			}
-			else
-			{
-				RefreshDisplayComponent();
-			}
-		}
-	}
-}
-
-//=============================================================================
-//void UOptiXMotionControllerComponent::SetTrackingSource(const EControllerHand NewSource)
-//{
-//	bool bSuccess = false;
-//	UEnum* HandEnum = StaticEnum<EControllerHand>();
-//	if (HandEnum)
-//	{
-//		FString ValueName = HandEnum->GetNameStringByValue((int64)NewSource);
-//		if (!ValueName.IsEmpty())
-//		{
-//			MotionSource = *ValueName;
-//			bSuccess = true;
-//		}
-//	}
-//	bSuccess = false;
-//
-//
-//	if (bSuccess)
-//	{
-//		UWorld* MyWorld = GetWorld();
-//		if (MyWorld && MyWorld->IsGameWorld() && HasBeenInitialized())
-//		{
-//			FMotionDelayService::RegisterDelayTarget(this, PlayerIndex, MotionSource);
-//		}
-//	}
-//}
-
-//=============================================================================
-//EControllerHand UOptiXMotionControllerComponent::GetTrackingSource() const
-//{
-//	EControllerHand Hand = EControllerHand::Left;
-//	FXRMotionControllerBase::GetHandEnumForSourceName(MotionSource, Hand);
-//	return Hand;
-//}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::SetTrackingMotionSource(const FName NewSource)
-{
-	MotionSource = NewSource;
-
-	UWorld* MyWorld = GetWorld();
-	if (MyWorld && MyWorld->IsGameWorld() && HasBeenInitialized())
-	{
-		FMotionDelayService::RegisterDelayTarget(this, PlayerIndex, NewSource);
-	}
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::SetAssociatedPlayerIndex(const int32 NewPlayer)
-{
-	PlayerIndex = NewPlayer;
-
-	UWorld* MyWorld = GetWorld();
-	if (MyWorld && MyWorld->IsGameWorld() && HasBeenInitialized())
-	{
-		FMotionDelayService::RegisterDelayTarget(this, NewPlayer, MotionSource);
-	}
-}
-
-void UOptiXMotionControllerComponent::Serialize(FArchive& Ar)
-{
-	Ar.UsingCustomVersion(FVRObjectVersion::GUID);
-
-	Super::Serialize(Ar);
-
-	//if (Ar.CustomVer(FVRObjectVersion::GUID) < FVRObjectVersion::UseFNameInsteadOfEControllerHandForMotionSource)
-	//{
-	//	UEnum* HandEnum = StaticEnum<EControllerHand>();
-	//	if (HandEnum)
-	//	{
-	//		FString ValueName = HandEnum->GetNameStringByValue((int64)Hand_DEPRECATED);
-	//		if (!ValueName.IsEmpty())
-	//		{
-	//			MotionSource = *ValueName;
-	//		}
-	//	}
-	//	//LegacyMotionSources::GetSourceNameForHand(Hand_DEPRECATED, MotionSource);
-	//}
-}
-
-#if WITH_EDITOR
-//=============================================================================
-void UOptiXMotionControllerComponent::PreEditChange(UProperty* PropertyAboutToChange)
-{
-	PreEditMaterialCount = DisplayMeshMaterialOverrides.Num();
-	Super::PreEditChange(PropertyAboutToChange);
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
-{
-	Super::PostEditChangeProperty(PropertyChangedEvent);
-
-	UProperty* PropertyThatChanged = PropertyChangedEvent.Property;
-	const FName PropertyName = (PropertyThatChanged != nullptr) ? PropertyThatChanged->GetFName() : NAME_None;
-
-	if (PropertyName == GET_MEMBER_NAME_CHECKED(UOptiXMotionControllerComponent, bDisplayDeviceModel))
-	{
-		RefreshDisplayComponent(/*bForceDestroy =*/true);
-	}
-	else if (PropertyName == GET_MEMBER_NAME_CHECKED(UOptiXMotionControllerComponent, DisplayMeshMaterialOverrides))
-	{
-		RefreshDisplayComponent(/*bForceDestroy =*/DisplayMeshMaterialOverrides.Num() < PreEditMaterialCount);
-	}
-	else if (PropertyName == GET_MEMBER_NAME_CHECKED(UOptiXMotionControllerComponent, CustomDisplayMesh))
-	{
-		RefreshDisplayComponent(/*bForceDestroy =*/false);
-	}
-}
-#endif
-
-//=============================================================================
-void UOptiXMotionControllerComponent::OnRegister()
-{
-	Super::OnRegister();
-
-	if (DisplayComponent == nullptr)
-	{
-		RefreshDisplayComponent();
-	}
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::InitializeComponent()
-{
-	Super::InitializeComponent();
-
-	UWorld* MyWorld = GetWorld();
-	if (MyWorld && MyWorld->IsGameWorld())
-	{
-		FMotionDelayService::RegisterDelayTarget(this, PlayerIndex, MotionSource);
-	}
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::OnComponentDestroyed(bool bDestroyingHierarchy)
-{
-	Super::OnComponentDestroyed(bDestroyingHierarchy);
-
-	if (DisplayComponent)
-	{
-		DisplayComponent->DestroyComponent();
-	}
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::RefreshDisplayComponent(const bool bForceDestroy)
-{
-	if (IsRegistered())
-	{
-		TArray<USceneComponent*> DisplayAttachChildren;
-		auto DestroyDisplayComponent = [this, &DisplayAttachChildren]()
-		{
-			DisplayDeviceId.Clear();
-
-			if (DisplayComponent)
-			{
-				// @TODO: save/restore socket attachments as well
-				DisplayAttachChildren = DisplayComponent->GetAttachChildren();
-
-				DisplayComponent->DestroyComponent(/*bPromoteChildren =*/true);
-				DisplayComponent = nullptr;
-			}
-		};
-		if (bForceDestroy)
-		{
-			DestroyDisplayComponent();
-		}
-
-		UPrimitiveComponent* NewDisplayComponent = nullptr;
-		if (bDisplayDeviceModel)
-		{
-			const EObjectFlags SubObjFlags = RF_Transactional | RF_TextExportTransient;
-
-			if (DisplayModelSource == UOptiXMotionControllerComponent::CustomModelSourceId)
-			{
-				UStaticMeshComponent* MeshComponent = nullptr;
-				if ((DisplayComponent == nullptr) || (DisplayComponent->GetClass() != UStaticMeshComponent::StaticClass()))
-				{
-					DestroyDisplayComponent();
-
-					const FName SubObjName = MakeUniqueObjectName(this, UStaticMeshComponent::StaticClass(), TEXT("MotionControllerMesh"));
-					MeshComponent = NewObject<UStaticMeshComponent>(this, SubObjName, SubObjFlags);
-				}
-				else
-				{
-					MeshComponent = CastChecked<UStaticMeshComponent>(DisplayComponent);
-				}
-				NewDisplayComponent = MeshComponent;
-
-				if (ensure(MeshComponent))
-				{
-					if (CustomDisplayMesh)
-					{
-						MeshComponent->SetStaticMesh(CustomDisplayMesh);
-					}
-					else
-					{
-						UE_LOG(LogMotionControllerComponent, Warning, TEXT("Failed to create a custom display component for the MotionController since no mesh was specified."));
-					}
-				}
-			}
-			else
-			{
-				TArray<IXRSystemAssets*> XRAssetSystems = IModularFeatures::Get().GetModularFeatureImplementations<IXRSystemAssets>(IXRSystemAssets::GetModularFeatureName());
-				for (IXRSystemAssets* AssetSys : XRAssetSystems)
-				{
-					if (!DisplayModelSource.IsNone() && AssetSys->GetSystemName() != DisplayModelSource)
-					{
-						continue;
-					}
-
-					int32 DeviceId = INDEX_NONE;
-					if (MotionSource == FXRMotionControllerBase::HMDSourceId)
-					{
-						DeviceId = IXRTrackingSystem::HMDDeviceId;
-					}
-					else
-					{
-						EControllerHand ControllerHandIndex;
-						if (!FXRMotionControllerBase::GetHandEnumForSourceName(MotionSource, ControllerHandIndex))
-						{
-							break;
-						}
-						DeviceId = AssetSys->GetDeviceId(ControllerHandIndex);
-					}
-
-					if (DisplayComponent && DisplayDeviceId.IsOwnedBy(AssetSys) && DisplayDeviceId.DeviceId == DeviceId)
-					{
-						// assume that the current DisplayComponent is the same one we'd get back, so don't recreate it
-						// @TODO: maybe we should add a IsCurrentlyRenderable(int32 DeviceId) to IXRSystemAssets to confirm this in some manner
-						break;
-					}
-
-					// needs to be set before CreateRenderComponent() since the LoadComplete callback may be triggered before it returns (for syncrounous loads)
-					DisplayModelLoadState = EModelLoadStatus::Pending;
-					FXRComponentLoadComplete LoadCompleteDelegate = FXRComponentLoadComplete::CreateUObject(this, &UOptiXMotionControllerComponent::OnDisplayModelLoaded);
-
-					NewDisplayComponent = AssetSys->CreateRenderComponent(DeviceId, GetOwner(), SubObjFlags, /*bForceSynchronous=*/false, LoadCompleteDelegate);
-					if (NewDisplayComponent != nullptr)
-					{
-						if (DisplayModelLoadState != EModelLoadStatus::Complete)
-						{
-							DisplayModelLoadState = EModelLoadStatus::InProgress;
-						}
-						DestroyDisplayComponent();
-						DisplayDeviceId = FXRDeviceId(AssetSys, DeviceId);
-						break;
-					}
-					else
-					{
-						DisplayModelLoadState = EModelLoadStatus::Unloaded;
-					}
-				}
-			}
-
-			if (NewDisplayComponent == nullptr)
-			{
-				UE_CLOG(!DisplayComponent, LogMotionControllerComponent, Warning, TEXT("Failed to create a display component for the MotionController - no XR system (if there were any) had a model for the specified source ('%s')"), *MotionSource.ToString());
-			}
-			else if (NewDisplayComponent != DisplayComponent)
-			{
-				NewDisplayComponent->SetupAttachment(this);
-				// force disable collision - if users wish to use collision, they can setup their own sub-component
-				NewDisplayComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
-				NewDisplayComponent->RegisterComponent();
-
-				for (USceneComponent* Child : DisplayAttachChildren)
-				{
-					Child->SetupAttachment(NewDisplayComponent);
-				}
-
-				DisplayComponent = NewDisplayComponent;
-			}
-
-			if (DisplayComponent)
-			{
-				if (DisplayModelLoadState != EModelLoadStatus::InProgress)
-				{
-					OnDisplayModelLoaded(DisplayComponent);
-				}
-
-				DisplayComponent->SetHiddenInGame(bHiddenInGame);
-				DisplayComponent->SetVisibility(bVisible);
-			}
-		}
-		else if (DisplayComponent)
-		{
-			DisplayComponent->SetHiddenInGame(true, /*bPropagateToChildren =*/false);
-		}
-	}
-}
-
-//=============================================================================
-bool UOptiXMotionControllerComponent::PollControllerState(FVector& Position, FRotator& Orientation, float WorldToMetersScale)
-{
-	if (IsInGameThread())
-	{
-		// Cache state from the game thread for use on the render thread
-		const AActor* MyOwner = GetOwner();
-		bHasAuthority = MyOwner->HasLocalNetOwner();
-	}
-
-	if (bHasAuthority)
-	{
-		TArray<IMotionController*> MotionControllers = IModularFeatures::Get().GetModularFeatureImplementations<IMotionController>(IMotionController::GetModularFeatureName());
-		for (auto MotionController : MotionControllers)
-		{
-			if (MotionController == nullptr)
-			{
-				continue;
-			}
-
-			CurrentTrackingStatus = MotionController->GetControllerTrackingStatus(PlayerIndex, MotionSource);
-			if (MotionController->GetControllerOrientationAndPosition(PlayerIndex, MotionSource, Orientation, Position, WorldToMetersScale))
-			{
-				if (IsInGameThread())
-				{
-					InUseMotionController = MotionController;
-					OnMotionControllerUpdated();
-					InUseMotionController = nullptr;
-				}
-				return true;
-			}
-		}
-
-		if (MotionSource == FXRMotionControllerBase::HMDSourceId)
-		{
-			IXRTrackingSystem* TrackingSys = GEngine->XRSystem.Get();
-			if (TrackingSys)
-			{
-				FQuat OrientationQuat;
-				if (TrackingSys->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, OrientationQuat, Position))
-				{
-					Orientation = OrientationQuat.Rotator();
-					return true;
-				}
-			}
-		}
-	}
-	return false;
-}
-
-//=============================================================================
-UOptiXMotionControllerComponent::FViewExtension::FViewExtension(const FAutoRegister& AutoRegister, UOptiXMotionControllerComponent* InMotionControllerComponent)
-	: FSceneViewExtensionBase(AutoRegister)
-	, MotionControllerComponent(InMotionControllerComponent)
-{}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::FViewExtension::BeginRenderViewFamily(FSceneViewFamily& InViewFamily)
-{
-	if (!MotionControllerComponent)
-	{
-		return;
-	}
-
-	// Set up the late update state for the controller component
-	LateUpdate.Setup(MotionControllerComponent->CalcNewComponentToWorld(FTransform()), MotionControllerComponent, false);
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::FViewExtension::PostRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
-{
-	if (!MotionControllerComponent)
-	{
-		return;
-	}
-
-	FTransform OldTransform;
-	FTransform NewTransform;
-	{
-		FScopeLock ScopeLock(&CritSect);
-		if (!MotionControllerComponent)
-		{
-			return;
-		}
-
-		// Find a view that is associated with this player.
-		float WorldToMetersScale = -1.0f;
-		for (const FSceneView* SceneView : InViewFamily.Views)
-		{
-			if (SceneView && SceneView->PlayerIndex == MotionControllerComponent->PlayerIndex)
-			{
-				WorldToMetersScale = SceneView->WorldToMetersScale;
-				break;
-			}
-		}
-		// If there are no views associated with this player use view 0.
-		if (WorldToMetersScale < 0.0f)
-		{
-			check(InViewFamily.Views.Num() > 0);
-			WorldToMetersScale = InViewFamily.Views[0]->WorldToMetersScale;
-		}
-
-		// Poll state for the most recent controller transform
-		FVector Position = MotionControllerComponent->RenderThreadRelativeTransform.GetTranslation();
-		FRotator Orientation = MotionControllerComponent->RenderThreadRelativeTransform.GetRotation().Rotator();
-		if (!MotionControllerComponent->PollControllerState(Position, Orientation, WorldToMetersScale))
-		{
-			return;
-		}
-
-		OldTransform = MotionControllerComponent->RenderThreadRelativeTransform;
-		NewTransform = FTransform(Orientation, Position, MotionControllerComponent->RenderThreadComponentScale);
-	} // Release the lock on the MotionControllerComponent
-
-	// Tell the late update manager to apply the offset to the scene components
-	LateUpdate.Apply_RenderThread(InViewFamily.Scene, OldTransform, NewTransform);
-}
-
-//=============================================================================
-void UOptiXMotionControllerComponent::FViewExtension::PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
-{
-	if (!MotionControllerComponent)
-	{
-		return;
-	}
-
-	FTransform OldTransform;
-	FTransform NewTransform;
-	{
-		FScopeLock ScopeLock(&CritSect);
-		if (!MotionControllerComponent)
-		{
-			return;
-		}
-
-		// Find a view that is associated with this player.
-		float WorldToMetersScale = -1.0f;
-		for (const FSceneView* SceneView : InViewFamily.Views)
-		{
-			if (SceneView && SceneView->PlayerIndex == MotionControllerComponent->PlayerIndex)
-			{
-				WorldToMetersScale = SceneView->WorldToMetersScale;
-				break;
-			}
-		}
-		// If there are no views associated with this player use view 0.
-		if (WorldToMetersScale < 0.0f)
-		{
-			check(InViewFamily.Views.Num() > 0);
-			WorldToMetersScale = InViewFamily.Views[0]->WorldToMetersScale;
-		}
-
-		// Poll state for the most recent controller transform
-		FVector Position = MotionControllerComponent->RenderThreadRelativeTransform.GetTranslation();
-		FRotator Orientation = MotionControllerComponent->RenderThreadRelativeTransform.GetRotation().Rotator();
-		if (!MotionControllerComponent->PollControllerState(Position, Orientation, WorldToMetersScale))
-		{
-			return;
-		}
-
-		OldTransform = MotionControllerComponent->RenderThreadRelativeTransform;
-		NewTransform = FTransform(Orientation, Position, MotionControllerComponent->RenderThreadComponentScale);
-	} // Release the lock on the MotionControllerComponent
-
-	// Tell the late update manager to apply the offset to the scene components
-	LateUpdate.Apply_RenderThread(InViewFamily.Scene, OldTransform, NewTransform);
-}
-
-bool UOptiXMotionControllerComponent::FViewExtension::IsActiveThisFrame(class FViewport* InViewport) const
-{
-	check(IsInGameThread());
-	return MotionControllerComponent && !MotionControllerComponent->bDisableLowLatencyUpdate && CVarEnableMotionControllerLateUpdate.GetValueOnGameThread();
-}
-
-float UOptiXMotionControllerComponent::GetParameterValue(FName InName, bool& bValueFound)
-{
-	if (InUseMotionController)
-	{
-		return InUseMotionController->GetCustomParameterValue(MotionSource, InName, bValueFound);
-	}
-	bValueFound = false;
-	return 0.f;
-}
-
-FVector UOptiXMotionControllerComponent::GetHandJointPosition(int jointIndex, bool& bValueFound)
-{
-	FVector outPosition;
-	if (InUseMotionController && InUseMotionController->GetHandJointPosition(MotionSource, jointIndex, outPosition))
-	{
-		bValueFound = true;
-		return outPosition;
-	}
-	else
-	{
-		bValueFound = false;
-		return FVector::ZeroVector;
-	}
-}
-
-
-void UOptiXMotionControllerComponent::OnDisplayModelLoaded(UPrimitiveComponent* InDisplayComponent)
-{
-	if (InDisplayComponent == DisplayComponent || DisplayModelLoadState == EModelLoadStatus::Pending)
-	{
-		if (InDisplayComponent)
-		{
-			const int32 MatCount = FMath::Min(InDisplayComponent->GetNumMaterials(), DisplayMeshMaterialOverrides.Num());
-			for (int32 MatIndex = 0; MatIndex < MatCount; ++MatIndex)
-			{
-				InDisplayComponent->SetMaterial(MatIndex, DisplayMeshMaterialOverrides[MatIndex]);
-			}
-		}
-		DisplayModelLoadState = EModelLoadStatus::Complete;
-	}
-}
diff --git a/Source/OptiX/Private/OptiXObjectComponent.cpp b/Source/OptiX/Private/OptiXObjectComponent.cpp
index 9fc83963055f637f126ed9e401449a578387922a..12a9da996a981f25d5dab29c190d061eb90473cd 100644
--- a/Source/OptiX/Private/OptiXObjectComponent.cpp
+++ b/Source/OptiX/Private/OptiXObjectComponent.cpp
@@ -9,7 +9,6 @@
 #include "OptiXLaserActor.h"
 #include "OptiXTargetComponent.h"
 #include "OptiXModule.h"
-#include "StatsDefines.h"
 
 UOptiXObjectComponent::UOptiXObjectComponent(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -21,59 +20,56 @@ UOptiXObjectComponent::UOptiXObjectComponent(const FObjectInitializer& ObjectIni
 
 	// Only as a safety measure because I have no idea how the editor factory actually sets this stuff.
 
+	bIsInitialized = false;
+
 	UE_LOG(LogTemp, Display, TEXT("OptiX Component Constructor"));
 	PrimaryComponentTick.bCanEverTick = false; // Don't need to tick 
-	bWantsOnUpdateTransform = false;
+	bWantsOnUpdateTransform = true;
 
 }
 
-FPrimitiveSceneProxy* UOptiXObjectComponent::CreateSceneProxy()
-{
-	class FOptiXObjectComponentSceneProxy final : public FPrimitiveSceneProxy
-	{
-	public:
-		SIZE_T GetTypeHash() const override
-		{
-			static size_t UniquePointer;
-			return reinterpret_cast<size_t>(&UniquePointer);
-		}
-
-		/** Initialization constructor. */
-		FOptiXObjectComponentSceneProxy(const UOptiXObjectComponent* InComponent)
-			: FPrimitiveSceneProxy(InComponent)
-		{
-			UniqueId = InComponent->GetUniqueID();
-		}
 
-		// FPrimitiveSceneProxy interface.
+void UOptiXObjectComponent::OnUnregister()
+{
+	UE_LOG(LogTemp, Display, TEXT("OptiX Component OnUnregister"));
 
-		virtual void ApplyLateUpdateTransform(const FMatrix& LateUpdateTransform) override
-		{
-			//FTransform UpdatedTransform = FTransform(LocalToWorld * LateUpdateTransform);
-			//UE_LOG(LogTemp, Display, TEXT("Applying late update to laser"));
-			FMatrix CachedTransform = GetLocalToWorld();
-			FPrimitiveSceneProxy::ApplyLateUpdateTransform(LateUpdateTransform);			
-			CachedTransform.SetOrigin(GetLocalToWorld().GetOrigin());
-			//UE_LOG(LogTemp, Display, TEXT("Transform on late update: %s"), *UpdatedTransform.ToString());
-			FOptiXModule::Get().GetOptiXContextManager()->ObjectPositionLateUpdate_RenderThread(UniqueId, CachedTransform.GetMatrixWithoutScale());
-		}
+	Super::OnUnregister();
 
-		virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
-		uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
-	private:
-		int32 UniqueId;
-	};
+	//if (OptiXGeometryGroup != nullptr)
+	//{
+	//	OptiXGeometryGroup->RemoveChild(OptiXGeometryInstance);
+	//}
 
-	return new FOptiXObjectComponentSceneProxy(this);
+	//OptiXGeometry = nullptr;
+	//OptiXContext = nullptr;
+	//OptiXGeometryGroup = nullptr; // Dunno if that's needed?
+	//OptiXGeometryInstance = nullptr; // Dunno if that's needed?
 }
 
+
 void UOptiXObjectComponent::BeginPlay()
 {
 	Super::BeginPlay();
 	UE_LOG(LogTemp, Display, TEXT("OptiX Component BeginPlay"));
 
-	bWantsOnUpdateTransform = true;
-	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+	// Create and Init the optix stuff here
+
+	//InitOptiXComponent();	
+	RegisterOptiXComponent();
+	QueueOptiXContextUpdate();
+}
+
+void UOptiXObjectComponent::RegisterOptiXComponent()
+{
+	FOptiXModule::Get().GetOptiXContextManager()->RegisterOptiXComponent(this);
+}
+
+void UOptiXObjectComponent::QueueOptiXContextUpdate()
+{
+	if (!bUpdateQueued)
+	{
+		FOptiXModule::Get().GetOptiXContextManager()->QueueComponentUpdate(this);
+	}
 }
 
 void UOptiXObjectComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
@@ -88,27 +84,54 @@ void UOptiXObjectComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransf
 {
 	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
 
-	FMatrix T = GetComponentToWorld().ToMatrixNoScale();
-	FMatrix Inverse = T.Inverse();
-	OptiXObjectUpdateFunction UpdateFunction =
-		[Transform = T, Inverse](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		//OptiXGeometryInstance->SetFloat3DVector("size", TargetSize);
-		Data->OptiXTransform->setMatrix(true, &Transform.M[0][0], &Inverse.M[0][0]);
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-	};
-
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+	UpdateOptiXComponent();
 }
 
 
+void UOptiXObjectComponent::InitOptiXComponent(FRHICommandListImmediate & RHICmdList)
+{
+	check(IsInRenderingThread());
+
+	OptiXContext = FOptiXModule::Get().GetContext();
+	OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
+
+	IOptiXComponentInterface::InitOptiXComponent(RHICmdList); // Calls the other stuff
+
+	bIsInitialized = true;
+	SetComponentTickEnabled(false);
+	UE_LOG(LogTemp, Display, TEXT("Initialized Object Component"));
+}
+
 void UOptiXObjectComponent::CleanOptiXComponent()
 {
-	FOptiXModule::Get().GetOptiXContextManager()->RequestDestroyOptiXObjects(GetUniqueID());
+
+	// Remove all the optix stuff again here from top to bottom
+
+
+	OptiXGeometryGroup->RemoveChild(OptiXGeometryInstance);
+	//OptiXGeometryGroup = nullptr; // This should trigger the GC and eat the object if this is the last reference
+
+	OptiXGeometryInstance->RemoveFromRoot();
+	//OptiXGeometryInstance->DestroyOptiXObject();
+	OptiXGeometryInstance = nullptr;
+
+	OptiXGeometry->RemoveFromRoot();
+	OptiXGeometry->DestroyOptiXObject();
+	OptiXGeometry = nullptr;
+
+	OptiXMaterial->RemoveFromRoot();
+	OptiXMaterial->DestroyOptiXObject();
+	OptiXMaterial = nullptr;
+}
+
+void UOptiXObjectComponent::SetUpdateQueued(bool UpdateQueued)
+{
+	bUpdateQueued.AtomicSet(UpdateQueued);
 }
 
 
+
+
 UOptiXCubemapComponent::UOptiXCubemapComponent(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
 {
@@ -119,24 +142,43 @@ UOptiXCubemapComponent::UOptiXCubemapComponent(const FObjectInitializer& ObjectI
 
 	// Only as a safety measure because I have no idea how the editor factory actually sets this stuff.
 
-	//bIsInitialized = false;
+	bIsInitialized = false;
 
 	UE_LOG(LogTemp, Display, TEXT("OptiX Cubemap Component Constructor"));
 	PrimaryComponentTick.bCanEverTick = false; // Don't need to tick 
-	bWantsOnUpdateTransform = false;
+	bWantsOnUpdateTransform = true;
 
 
 	bCaptureEveryFrame = false;
 	bCaptureOnMovement = false;
+
+
+}
+
+
+void UOptiXCubemapComponent::OnUnregister()
+{
+	UE_LOG(LogTemp, Display, TEXT("OptiX Component OnUnregister"));
+
+	Super::OnUnregister();
+
+	//if (OptiXGeometryGroup != nullptr)
+	//{
+	//	OptiXGeometryGroup->RemoveChild(OptiXGeometryInstance);
+	//}
+
+	//OptiXGeometry = nullptr;
+	//OptiXContext = nullptr;
+	//OptiXGeometryGroup = nullptr; // Dunno if that's needed?
+	//OptiXGeometryInstance = nullptr; // Dunno if that's needed?
 }
 
+
 void UOptiXCubemapComponent::BeginPlay()
 {
 	Super::BeginPlay();
 	UE_LOG(LogTemp, Display, TEXT("OptiX Component BeginPlay"));
 
-	OptiXCubemapId = FOptiXModule::Get().GetOptiXContextManager()->RequestCubemapId();
-
 	// Create and Init the optix stuff here
 
 	TArray<AActor*> FoundLaserActors;
@@ -197,11 +239,23 @@ void UOptiXCubemapComponent::BeginPlay()
 	bCubemapCaptured.AtomicSet(true);
 
 	//InitOptiXComponent();	
-	//RegisterOptiXComponent();
-	//QueueOptiXContextUpdate();
+	RegisterOptiXComponent();
+	QueueOptiXContextUpdate();
 
-	bWantsOnUpdateTransform = true;
-	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+
+}
+
+void UOptiXCubemapComponent::RegisterOptiXComponent()
+{
+	FOptiXModule::Get().GetOptiXContextManager()->RegisterOptiXComponent(this);
+}
+
+void UOptiXCubemapComponent::QueueOptiXContextUpdate()
+{
+	if (!bUpdateQueued)
+	{
+		FOptiXModule::Get().GetOptiXContextManager()->QueueComponentUpdate(this);
+	}
 }
 
 void UOptiXCubemapComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
@@ -216,81 +270,59 @@ void UOptiXCubemapComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTrans
 {
 	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
 
+	UpdateOptiXComponent();
+}
 
-	FMatrix T = GetComponentToWorld().ToMatrixNoScale();
-	FMatrix Inverse = T.Inverse();
-	OptiXObjectUpdateFunction UpdateFunction =
-		[Transform = T, Inverse](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		//OptiXGeometryInstance->SetFloat3DVector("size", TargetSize);
-		Data->OptiXTransform->setMatrix(true, &Transform.M[0][0], &Inverse.M[0][0]);
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-	};
 
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+void UOptiXCubemapComponent::InitOptiXComponent(FRHICommandListImmediate & RHICmdList)
+{
+	check(IsInRenderingThread());
+
+	OptiXContext = FOptiXModule::Get().GetContext();
+	OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
+
+	OptiXCubemapId = FOptiXModule::Get().GetOptiXContextManager()->RequestCubemapId();
+
+
+	IOptiXComponentInterface::InitOptiXComponent(RHICmdList); // Calls the other stuff
+	InitCubemap(RHICmdList);
+
+	bIsInitialized = true;
+	SetComponentTickEnabled(false);
+	UE_LOG(LogTemp, Display, TEXT("Initialized Object Component"));
 }
 
 void UOptiXCubemapComponent::CleanOptiXComponent()
 {
+
 	FOptiXModule::Get().GetOptiXContextManager()->DeleteCubemapId(OptiXCubemapId);
-	FOptiXModule::Get().GetOptiXContextManager()->RequestDestroyOptiXObjects(GetUniqueID());
-}
 
-void UOptiXCubemapComponent::RequestCubemapUpdate()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXCubemapComponent::RequestCubemapUpdate"))
+	// Remove all the optix stuff again here from top to bottom
 
-	CaptureScene();
-	
-	UE_LOG(LogTemp, Display, TEXT("Requesting Cubemap Update"));
+	if (OptiXContext == NULL)
+		return;
+	//OptiXGeometryGroup = nullptr; // This should trigger the GC and eat the object if this is the last reference
 
+	OptiXGeometryInstance->RemoveFromRoot();
+	OptiXGeometryInstance->DestroyOptiXObject();
+	OptiXGeometryInstance = nullptr;
 
-	//int32 X = 1024; // todo hardcoded
-	//int32 Y = X;
+	OptiXGeometry->RemoveFromRoot();
+	OptiXGeometry->DestroyOptiXObject();
+	OptiXGeometry = nullptr;
 
-	CubemapUpdateFunction UpdateFunction =
-		[&CubeRenderTarget = CubeRenderTarget]
-	(optix::Buffer CubemapBuffer, FRHICommandListImmediate & RHICmdList)
-	{
-		TArray<TArray<FColor>> SurfaceDataCube;
-		SurfaceDataCube.SetNumZeroed(6);
-		//TArray<FLinearColor> SD;
-
-		int32 X = 1024; // todo hardcoded
-		int32 Y = X;
-
-		optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->map());
-
-		FTextureRenderTargetCubeResource* RenderTargetCube = static_cast<FTextureRenderTargetCubeResource*>(CubeRenderTarget->GetRenderTargetResource());
-
-		FIntRect InRectCube = FIntRect(0, 0, RenderTargetCube->GetSizeXY().X, RenderTargetCube->GetSizeXY().Y);
-		FReadSurfaceDataFlags FlagsCube0(RCM_UNorm, CubeFace_PosX);
-		FReadSurfaceDataFlags FlagsCube1(RCM_UNorm, CubeFace_NegX);
-		FReadSurfaceDataFlags FlagsCube2(RCM_UNorm, CubeFace_PosY);
-		FReadSurfaceDataFlags FlagsCube3(RCM_UNorm, CubeFace_NegY);
-		FReadSurfaceDataFlags FlagsCube4(RCM_UNorm, CubeFace_PosZ);
-		FReadSurfaceDataFlags FlagsCube5(RCM_UNorm, CubeFace_NegZ);
-
-		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[0], FlagsCube0);
-		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[1], FlagsCube1);
-		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[2], FlagsCube2);
-		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[3], FlagsCube3);
-		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[4], FlagsCube4);
-		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[5], FlagsCube5);
-
-		uint32 MemSize = (X * Y * sizeof(FColor));
-		FMemory::Memcpy(BufferData, SurfaceDataCube[0].GetData(), MemSize); // front
-		FMemory::Memcpy(BufferData + X * Y * 1, SurfaceDataCube[1].GetData(), MemSize); // back
-		FMemory::Memcpy(BufferData + X * Y * 2, SurfaceDataCube[2].GetData(), MemSize); // 
-		FMemory::Memcpy(BufferData + X * Y * 3, SurfaceDataCube[3].GetData(), MemSize); // 
-		FMemory::Memcpy(BufferData + X * Y * 4, SurfaceDataCube[4].GetData(), MemSize); // 
-		FMemory::Memcpy(BufferData + X * Y * 5, SurfaceDataCube[5].GetData(), MemSize); //
-
-		CubemapBuffer->unmap();
-
-		UE_LOG(LogTemp, Display, TEXT("Finished Updating Cubemap"));
-	};
-
-	FOptiXModule::Get().GetOptiXContextManager()->RequestLensCubemapUpdate(GetUniqueID(), UpdateFunction);
+	OptiXMaterial->RemoveFromRoot();
+	OptiXMaterial->DestroyOptiXObject();
+	OptiXMaterial = nullptr;
+}
+
+void UOptiXCubemapComponent::SetUpdateQueued(bool UpdateQueued)
+{
+	bUpdateQueued.AtomicSet(UpdateQueued);
+}
+
+void UOptiXCubemapComponent::RequestCubemapUpdate()
+{
+	CaptureScene();
+	FOptiXModule::Get().GetOptiXContextManager()->RequestCubemapUpdate(this);
 }
diff --git a/Source/OptiX/Private/OptiXTargetComponent.cpp b/Source/OptiX/Private/OptiXTargetComponent.cpp
index 6c2f1fab13e138cbe39e3a3cfa9b913b0ac1a5e3..8669dfeb4e3b876872e5f9dba4b8fb1032eaa29b 100644
--- a/Source/OptiX/Private/OptiXTargetComponent.cpp
+++ b/Source/OptiX/Private/OptiXTargetComponent.cpp
@@ -7,6 +7,7 @@
 #include "OptiXModule.h"
 
 
+
 UOptiXTargetComponent::UOptiXTargetComponent(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
 {	
@@ -46,104 +47,186 @@ void UOptiXTargetComponent::BeginPlay()
 	Texture = LoadObject<UTexture2D>(this, *N);
 	TextureSize = FIntPoint(Texture->GetSizeX(), Texture->GetSizeY());
 	TargetSize = FVector(2.0f, 20.0f, 20.0f * static_cast<float>(TextureSize.Y) / static_cast<float>(TextureSize.X));
-
 	Super::BeginPlay();
 
+}
 
-	// Request creation of the optix objects
-	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXObject(GetUniqueID(), "box_intersect");
+void UOptiXTargetComponent::UpdateOptiXComponent()
+{
+	if (OptiXGeometry != nullptr && OptiXTransform != nullptr && OptiXAcceleration != nullptr)
+	{
+		FMatrix T = GetComponentToWorld().ToMatrixNoScale();
+		OptiXTransform->SetMatrix(T);
+		//OptiXAcceleration->MarkDirty();
+		OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
+		FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+	}
 
-	// Init them
+}
+
+void UOptiXTargetComponent::InitOptiXGeometry()
+{
+	OptiXGeometry = OptiXContext->CreateGeometry();
+	OptiXGeometry->SetPrimitiveCount(1u);
+	UOptiXProgram* BB = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/box_intersect.ptx", "bounds");
+	UOptiXProgram* IP = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/box_intersect.ptx", "intersect");
+
+	OptiXGeometry->SetBoundingBoxProgram(BB);
+	OptiXGeometry->SetIntersectionProgram(IP);
+}
+
+void UOptiXTargetComponent::InitOptiXMaterial()
+{
+	UOptiXProgram* CHPerspective = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/frame_material.ptx", "closest_hit_radiance");
+	UOptiXProgram* CHIterative = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/frame_material.ptx", "closest_hit_iterative");
+
+	OptiXMaterial = OptiXContext->CreateMaterial();
+	OptiXMaterial->SetClosestHitProgram(0, CHPerspective);
+	OptiXMaterial->SetClosestHitProgram(1, CHIterative);
+
+	/*OptiXMaterial->SetFloat("importance_cutoff", 1e-2f);
+	OptiXMaterial->SetFloat3D("cutoff_color", 0.035f, 0.102f, 0.169f);
+	OptiXMaterial->SetFloat("fresnel_exponent", 3.0f);
+	OptiXMaterial->SetFloat("fresnel_minimum", 0.1f);
+	OptiXMaterial->SetFloat("fresnel_maximum", 1.0f);
+	OptiXMaterial->SetFloat("refraction_index", 1.4f);
+
+	OptiXMaterial->SetFloat3D("refraction_color", 1.0f, 1.0f, 1.0f);
+	OptiXMaterial->SetFloat3D("reflection_color", 1.0f, 1.0f, 1.0f);
+
+	OptiXMaterial->SetInt("refraction_maxdepth", 10);
+	OptiXMaterial->SetInt("reflection_maxdepth", 5);
+
+	OptiXMaterial->SetFloat3D("extinction_constant", FMath::Loge(0.83f), FMath::Loge(0.83f), FMath::Loge(0.83f));*/
+}
+
+void UOptiXTargetComponent::InitOptiXGroups()
+{
+	OptiXGeometryInstance = OptiXContext->CreateGeometryInstance(OptiXGeometry, OptiXMaterial);
+	
 	SetSize(TargetSize);
 
-	// Create the required buffer and sampler
-	FOptiXBufferData BufferData;
-	BufferData.Name = "texture_buffer";
-	BufferData.Type = RT_BUFFER_INPUT;
-	BufferData.Format = RT_FORMAT_UNSIGNED_BYTE4;
-	BufferData.BufferWidth = TextureSize.X;
-	BufferData.BufferHeight = TextureSize.Y;
-	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXBuffer(GetUniqueID(), BufferData);
+	UOptiXTextureSampler* Sampler = OptiXContext->CreateTextureSampler();
+	//Sampler->AddToRoot();
+	Sampler->SetWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
+	Sampler->SetWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
+	Sampler->SetWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
+	Sampler->SetIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
+	Sampler->SetReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
+	Sampler->SetMaxAnisotropy(1.0f);
+	Sampler->SetMipLevelCount(1u);
+	Sampler->SetArraySize(1u);
 
+
+
+	UE_LOG(LogTemp, Display, TEXT("Texture with Size: (%i, %i)"), TextureSize.X, TextureSize.Y);
+
+	TextureBuffer = OptiXContext->CreateBufferUByte2D(RT_BUFFER_INPUT, TextureSize.X, TextureSize.Y);
+	
 	TextureSize = FIntPoint(Texture->GetSizeX(), Texture->GetSizeY());
 	TargetSize = FVector(2.0f, 20.0f, 20.0f * static_cast<float>(TextureSize.Y) / static_cast<float>(TextureSize.X));
 
-	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXTextureSampler(GetUniqueID());
+	optix::uchar4* BufferData = static_cast<optix::uchar4*>(TextureBuffer->MapNative());
 
-	FMatrix Transform = GetComponentToWorld().ToMatrixNoScale();
-	FMatrix Inverse = Transform.Inverse();
 
-	OptiXObjectInitFunction InitFunction =
-		[&TextureSize = TextureSize, &TargetSize = TargetSize, &Texture = Texture, Transform, Inverse]
-	(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
-	{
-		TextureSampler->setWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
-		TextureSampler->setWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
-		TextureSampler->setWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
-		TextureSampler->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
-		TextureSampler->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
-		TextureSampler->setMaxAnisotropy(1.0f);
-		TextureSampler->setMipLevelCount(1u);
-		TextureSampler->setArraySize(1u);
+	FTexture2DMipMap& Mip = Texture->PlatformData->Mips[0];
 
-		UE_LOG(LogTemp, Display, TEXT("Texture with Size: (%i, %i)"), TextureSize.X, TextureSize.Y);
+	FColor* TextureData = static_cast<FColor*>(Mip.BulkData.Lock(LOCK_READ_WRITE));
 
-		optix::Buffer TextureBuffer = *Buffers->Find("texture_buffer");
-		optix::uchar4* BufferData = static_cast<optix::uchar4*>(TextureBuffer->map());
+	// Texture index conversion is a real pain...
+	for (int32 i = 0; i < TextureSize.X; ++i) {
+		for (int32 j = 0; j < TextureSize.Y; ++j) {
 
-		FTexture2DMipMap& Mip = Texture->PlatformData->Mips[0];
+			int32 TextureIndex = (TextureSize.X * TextureSize.Y - 1) - i * TextureSize.X - j;
+			int32 BufferIndex = ((j)*(TextureSize.X) + i);
+			//UE_LOG(LogTemp, Display, TEXT("Values: %i"), TextureData[BufferIndex]);
 
-		FColor* TextureData = static_cast<FColor*>(Mip.BulkData.Lock(LOCK_READ_WRITE));
+			BufferData[BufferIndex].x = TextureData[TextureIndex].R;
+			BufferData[BufferIndex].y = TextureData[TextureIndex].G;
+			BufferData[BufferIndex].z = TextureData[TextureIndex].B;
+			BufferData[BufferIndex].w = TextureData[TextureIndex].A;
 
-		// Texture index conversion is a real pain...
-		for (int32 i = 0; i < TextureSize.X; ++i) {
-			for (int32 j = 0; j < TextureSize.Y; ++j) {
+		}
+	}
 
-				int32 TextureIndex = (TextureSize.X * TextureSize.Y - 1) - i * TextureSize.X - j;
-				int32 BufferIndex = ((j)*(TextureSize.X) + i);
-				//UE_LOG(LogTemp, Display, TEXT("Values: %i"), TextureData[BufferIndex]);
+	// TODO: Check if we can copy automatically via Memcpy
+	//FMemory::Memcpy(BufferData + (X * Y), TextureData, (X * Y * sizeof(FColor))); // Try copying the buffer data directly here TODO
+	Mip.BulkData.Unlock();
+	TextureBuffer->Unmap();
+	
 
-				BufferData[BufferIndex].x = TextureData[TextureIndex].R;
-				BufferData[BufferIndex].y = TextureData[TextureIndex].G;
-				BufferData[BufferIndex].z = TextureData[TextureIndex].B;
-				BufferData[BufferIndex].w = TextureData[TextureIndex].A;
+	Sampler->SetBufferWithTextureIndexAndMiplevel(0u, 0u, TextureBuffer);
+	Sampler->SetFilteringModes(RT_FILTER_NEAREST, RT_FILTER_NEAREST, RT_FILTER_NONE);
 
-			}
-		}
+	OptiXGeometryInstance->SetTextureSampler("frameTexture", Sampler);
+
+	FMatrix T = GetComponentToWorld().ToMatrixNoScale();
+	OptiXTransform = OptiXContext->CreateTransform();
+	OptiXTransform->SetMatrix(T);
+
+	OptiXGeometryGroup = OptiXContext->CreateGeometryGroup();
+	OptiXGeometryGroup->AddChild(OptiXGeometryInstance);
 
-		// TODO: Check if we can copy automatically via Memcpy
-		//FMemory::Memcpy(BufferData + (X * Y), TextureData, (X * Y * sizeof(FColor))); // Try copying the buffer data directly here TODO
-		Mip.BulkData.Unlock();
-		TextureBuffer->unmap();
+	OptiXAcceleration = OptiXContext->CreateAcceleration("NoAccel"); // This should be faster
+	//OptiXAcceleration->SetProperty("refit", "1");
+	//OptiXAcceleration->MarkDirty();
 
-		TextureSampler->setBuffer(0u, 0u, TextureBuffer);
-		TextureSampler->setFilteringModes(RT_FILTER_NEAREST, RT_FILTER_NEAREST, RT_FILTER_NONE);
+	OptiXGeometryGroup->SetAcceleration(OptiXAcceleration);
 
-		Data->OptiXGeometryInstance["frameTexture"]->setTextureSampler(TextureSampler);
+	OptiXTransform->SetChild(OptiXGeometryGroup);
 
-		Data->OptiXTransform->setMatrix(true, &Transform.M[0][0], &Inverse.M[0][0]);
-		Data->OptiXAcceleration->markDirty();
-		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+	OptiXContext->GetGroup("top_object")->AddChild(OptiXTransform);
+	OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
+
+}
+
+void UOptiXTargetComponent::UpdateOptiXComponentVariables()
+{
+	check(IsInRenderingThread());
+
+
+	// Size
+	OptiXGeometryInstance->SetFloat3DVector("size", TargetSize);	
+}
+
+
+//// TODO: Do it this way for now, alternatively custom getters and setters might be better/less clutter-y?
+//void UOptiXLensComponent::PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent)
+//{
+//
+//	FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None;
+//
+//	// Huge case distinction coming now, I don't really like this, seems like a lot of boilerplate code compared to setters/getters but w/e
+//
+//
+//
+//
+//
+//	Super::PostEditChangeProperty(PropertyChangedEvent);
+//}
+
+void UOptiXTargetComponent::CleanOptiXComponent()
+{
+	if (OptiXContext == NULL)
+	{
+		Super::CleanOptiXComponent();
+		return;
+	}
 
-	};
+	OptiXContext->GetGroup("top_object")->RemoveChild(OptiXTransform);
+	
+	OptiXTransform = nullptr;
+	OptiXAcceleration = nullptr;
 
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueInitFunction(GetUniqueID(), InitFunction);
+	Super::CleanOptiXComponent();
 
+	OptiXGeometryGroup = nullptr;
 }
 
 void UOptiXTargetComponent::SetSize(FVector NewSize)
 {
 	TargetSize = NewSize;
-	OptiXObjectUpdateFunction UpdateFunction = 
-		[&TargetSize = TargetSize](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler) 
-		{
-			//OptiXGeometryInstance->SetFloat3DVector("size", TargetSize);
-			Data->OptiXGeometryInstance["size"]->setFloat(TargetSize.X, TargetSize.Y, TargetSize.Z);
-			Data->OptiXAcceleration->markDirty();
-			Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
-		};
-
-	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+	QueueOptiXContextUpdate();
 }
 
 FVector UOptiXTargetComponent::GetSize()
diff --git a/Source/OptiX/Private/OptiXTextureSampler.cpp b/Source/OptiX/Private/OptiXTextureSampler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..afd1e83871eb3c72fe93cb3747cfc5dec171abdd
--- /dev/null
+++ b/Source/OptiX/Private/OptiXTextureSampler.cpp
@@ -0,0 +1,416 @@
+#include "OptiXTextureSampler.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginTextureSampler);
+
+void UOptiXTextureSampler::BeginDestroy()
+{
+	DestroyOptiXObject();
+
+	Super::BeginDestroy();
+}
+
+void UOptiXTextureSampler::DestroyOptiXObject()
+{
+	if (NativeTextureSampler != NULL)
+	{
+		try
+		{
+			FOptiXModule::Get().GetOptiXContextManager()->TextureSamplersToDeleteQueue.Enqueue(NativeTextureSampler);
+			//NativeTextureSampler->destroy();
+		}
+		catch (optix::Exception& E)
+		{
+			FString Message = FString(E.getErrorString().c_str());
+			UE_LOG(OptiXPluginTextureSampler, Fatal, TEXT("OptiX Error: %s"), *Message);
+			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		}
+	}
+	OptiXBuffer = nullptr; // Don't explicitly destroy the buffer here
+	NativeTextureSampler = NULL;
+}
+
+void UOptiXTextureSampler::Validate()
+{
+	try
+	{
+		NativeTextureSampler->validate();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXTextureSampler::SetMipLevelCount(uint8 NumMipLevels)
+{
+	try
+	{
+		NativeTextureSampler->setMipLevelCount(NumMipLevels);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint8 UOptiXTextureSampler::GetMipLevelCount()
+{
+	uint8 Count = 0;
+	try
+	{
+		Count = NativeTextureSampler->getMipLevelCount();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Count;
+}
+
+void UOptiXTextureSampler::SetArraySize(int32 NumTexturesInArray)
+{
+	try
+	{
+		NativeTextureSampler->setArraySize(NumTexturesInArray);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXTextureSampler::GetArraySize()
+{
+	int32 Count = 0;
+	try
+	{
+		Count = NativeTextureSampler->getArraySize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Count;
+}
+
+void UOptiXTextureSampler::SetWrapMode(int32 Dim, RTwrapmode Wrapmode)
+{
+	try
+	{
+		NativeTextureSampler->setWrapMode(Dim, Wrapmode);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTwrapmode UOptiXTextureSampler::GetWrapMode(int32 Dim)
+{
+	RTwrapmode Mode = RT_WRAP_REPEAT;
+	try
+	{
+		Mode = NativeTextureSampler->getWrapMode(Dim);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Mode;
+}
+
+void UOptiXTextureSampler::SetFilteringModes(RTfiltermode Minification, RTfiltermode Magnification, RTfiltermode Mipmapping)
+{
+	try
+	{
+		NativeTextureSampler->setFilteringModes(Minification, Magnification, Mipmapping);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXTextureSampler::GetFilteringModes(RTfiltermode & Minification, RTfiltermode & Magnification, RTfiltermode & Mipmapping)
+{
+	try
+	{
+		NativeTextureSampler->getFilteringModes(Minification, Magnification, Mipmapping);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXTextureSampler::SetMaxAnisotropy(float Value)
+{
+	try
+	{
+		NativeTextureSampler->setMaxAnisotropy(Value);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+float UOptiXTextureSampler::GetMaxAnisotropy()
+{
+	float Count = 0;
+	try
+	{
+		Count = NativeTextureSampler->getMaxAnisotropy();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Count;
+}
+
+void UOptiXTextureSampler::SetMipLevelClamp(float Min, float Max)
+{
+	try
+	{
+		NativeTextureSampler->setMipLevelClamp(Min, Max);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FVector2D UOptiXTextureSampler::GetMipLevelClamp()
+{
+	float Min;
+	float Max;
+	FVector2D MinMax;
+	try
+	{
+		NativeTextureSampler->getMipLevelClamp(Min, Max);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	MinMax.X = Min;
+	MinMax.Y = Max;
+	return MinMax;
+}
+
+void UOptiXTextureSampler::SetMipLevelBias(float Value)
+{
+	try
+	{
+		NativeTextureSampler->setMipLevelBias(Value);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+float UOptiXTextureSampler::GetMipLevelBias()
+{
+	float Bias = 0;
+	try
+	{
+		Bias = NativeTextureSampler->getMipLevelBias();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Bias;
+}
+
+int32 UOptiXTextureSampler::GetId()
+{
+	int32 Id = 0;
+	try
+	{
+		Id = NativeTextureSampler->getId();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Id;
+}
+
+void UOptiXTextureSampler::SetReadMode(RTtexturereadmode Readmode)
+{
+	try
+	{
+		NativeTextureSampler->setReadMode(Readmode);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTtexturereadmode UOptiXTextureSampler::GetReadMode()
+{
+	RTtexturereadmode Mode = RT_TEXTURE_READ_ELEMENT_TYPE;
+	try
+	{
+		Mode = NativeTextureSampler->getReadMode();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Mode;
+}
+
+void UOptiXTextureSampler::SetIndexingMode(RTtextureindexmode Mode)
+{
+	try
+	{
+		NativeTextureSampler->setIndexingMode(Mode);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTtextureindexmode UOptiXTextureSampler::GetIndexingMode()
+{
+	RTtextureindexmode Mode = RT_TEXTURE_INDEX_NORMALIZED_COORDINATES;
+	try
+	{
+		Mode = NativeTextureSampler->getIndexingMode();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Mode;
+}
+
+void UOptiXTextureSampler::SetBufferWithTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel, UOptiXBuffer * Buffer)
+{
+	try
+	{
+		NativeTextureSampler->setBuffer(TextureArrayIndex, MipLevel, Buffer->GetNativeBuffer());
+		OptiXBuffer = Buffer;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXBuffer * UOptiXTextureSampler::GetBufferByTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel)
+{
+	UE_LOG(OptiXPluginTextureSampler, Error, 
+		TEXT("GetBufferByTextureIndexAndMiplevel not implemented yet. Returning regular buffer."));
+	try
+	{
+		// Just check if it's actually possible to get the buffer - maybe do an equals here:
+		optix::Buffer B = NativeTextureSampler->getBuffer(TextureArrayIndex, MipLevel);
+		if (B != OptiXBuffer->GetNativeBuffer())
+		{
+			UE_LOG(OptiXPluginTextureSampler, Error, TEXT("Buffer Mismatch in Texture Sampler"));
+			//return nullptr;
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return OptiXBuffer;
+}
+
+void UOptiXTextureSampler::SetBuffer(UOptiXBuffer * Buffer)
+{
+	try
+	{
+		NativeTextureSampler->setBuffer(Buffer->GetNativeBuffer());
+		OptiXBuffer = Buffer;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXBuffer * UOptiXTextureSampler::GetBuffer()
+{
+	try
+	{
+		// Just check if it's actually possible to get the buffer - maybe do an equals here:
+		optix::Buffer B = NativeTextureSampler->getBuffer();
+		if (B != OptiXBuffer->GetNativeBuffer())
+		{
+			UE_LOG(OptiXPluginTextureSampler, Error, TEXT("Buffer Mismatch in Texture Sampler"));
+			return nullptr;
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return OptiXBuffer;
+}
diff --git a/Source/OptiX/Private/OptiXTransform.cpp b/Source/OptiX/Private/OptiXTransform.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a361e5036fa9662ce750f67c34e35bfb114b16b0
--- /dev/null
+++ b/Source/OptiX/Private/OptiXTransform.cpp
@@ -0,0 +1,143 @@
+#include "OptiXTransform.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginTransform);
+
+void UOptiXTransform::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Transform BeginDestroy"));
+
+	DestroyOptiXObject();
+	Super::BeginDestroy();
+}
+
+void UOptiXTransform::DestroyOptiXObject()
+{
+	if (NativeTransform != NULL)
+	{
+		FOptiXModule::Get().GetOptiXContextManager()->TransformsToDeleteQueue.Enqueue(NativeTransform);
+		//NativeTransform->destroy();
+	}
+
+	OptiXChild = nullptr; // Don't explicitly delete the child, maybe we should TODO
+	NativeTransform = NULL;
+}
+
+void UOptiXTransform::UpdateTransform()
+{
+	check(IsInRenderingThread());
+	try
+	{
+		// According to the optix doc false == row major
+		FMatrix Inverse = TransformMatrix.Inverse();
+		NativeTransform->setMatrix(true, &TransformMatrix.M[0][0], &Inverse.M[0][0]); // TODO - find out if false or true is column or row major
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+void UOptiXTransform::SetChild(UObject * Child)
+{
+	if (UOptiXGeometryGroup* GeomGroup = Cast<UOptiXGeometryGroup>(Child))
+	{
+		NativeTransform->setChild(GeomGroup->GetNativeGroup());
+		OptiXChild = Child;
+	}
+	else if (UOptiXGeometryInstance* GeomInstance = Cast<UOptiXGeometryInstance>(Child))
+	{
+		NativeTransform->setChild(GeomInstance->GetNativeInstance());
+		OptiXChild = Child;
+	}
+	else return;
+}
+
+RTobjecttype UOptiXTransform::GetChildType()
+{
+	return NativeTransform->getChildType();
+}
+
+UObject * UOptiXTransform::GetChild()
+{
+	return OptiXChild;
+}
+
+void UOptiXTransform::SetMatrix(FMatrix Matrix)
+{	
+	// TODO This should maybe be a critical section?
+	TransformMatrix = Matrix;
+}
+
+
+void UOptiXTransform::SetMatrixImmediate(FMatrix Matrix)
+{
+	// WARNING! NON THREAD SAFE
+	try
+	{
+		// According to the optix doc false == row major
+		TransformMatrix = Matrix;
+		FMatrix Inverse = TransformMatrix.Inverse();
+		NativeTransform->setMatrix(true, &TransformMatrix.M[0][0], &Inverse.M[0][0]); // TODO - find out if false or true is column or row major
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+
+FMatrix UOptiXTransform::GetMatrix()
+{
+	return TransformMatrix;
+}
+
+void UOptiXTransform::SetMotionRange(float TimeBegin, float TimeEnd)
+{
+	try
+	{
+		NativeTransform->setMotionRange(TimeBegin, TimeEnd);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FVector2D UOptiXTransform::GetMotionRange()
+{
+	FVector2D V = FVector2D();
+	float X;
+	float Y;
+	try
+	{
+		NativeTransform->getMotionRange(X, Y);
+		V.X = X;
+		V.Y = Y;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+	return V;
+}
diff --git a/Source/OptiX/Private/OptiXVRPawn.cpp b/Source/OptiX/Private/OptiXVRPawn.cpp
index 672302c48f361d832670b133fed9838b0604713f..9a7358c59905f855b08d2b30902d85d36bfcc356 100644
--- a/Source/OptiX/Private/OptiXVRPawn.cpp
+++ b/Source/OptiX/Private/OptiXVRPawn.cpp
@@ -7,7 +7,6 @@
 #include "PickupActorInterface.h"
 #include "OptiXModule.h"
 
-#include "StatsDefines.h"
 
 
 // Sets default values
@@ -15,20 +14,19 @@ AOptiXVRPawn::AOptiXVRPawn()
 {
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
 	PrimaryActorTick.bCanEverTick = true;
+
 }
 
 // Called when the game starts or when spawned
 void AOptiXVRPawn::BeginPlay()
 {
 	Super::BeginPlay();
-	//HMDLocation = UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetViewTarget()->GetActorLocation();
+
 }
 
 // Called every frame
 void AOptiXVRPawn::Tick(float DeltaTime)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::Tick"))
-
 	Super::Tick(DeltaTime);
 
 }
@@ -37,12 +35,11 @@ void AOptiXVRPawn::Tick(float DeltaTime)
 void AOptiXVRPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
 {
 	Super::SetupPlayerInputComponent(PlayerInputComponent);
+
 }
 
 void AOptiXVRPawn::UpdateTranslation(UPrimitiveComponent* Interaction)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::UpdateTranslation"))
-
 	if (GrabbedLever == NULL)
 	{
 		return;
@@ -108,7 +105,6 @@ UMaterialInstanceDynamic* AOptiXVRPawn::GetMIDOrtho()
 
 void AOptiXVRPawn::RequestOrthoPass(const FMinimalViewInfo& ViewInfo)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::RequestOrthoPass"))
 
 	FSceneViewProjectionData ProjectionData;
 	ProjectionData.ViewOrigin = ViewInfo.Location;
@@ -127,8 +123,6 @@ void AOptiXVRPawn::RequestOrthoPass(const FMinimalViewInfo& ViewInfo)
 
 UStaticMeshComponent * AOptiXVRPawn::GetNearestMeshComponent(UPrimitiveComponent * Other)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::GetNearestMeshComponent"))
-
 	TArray<UPrimitiveComponent*> OverlappingComponents;
 	Other->GetOverlappingComponents(OverlappingComponents);
 
@@ -154,7 +148,6 @@ UStaticMeshComponent * AOptiXVRPawn::GetNearestMeshComponent(UPrimitiveComponent
 
 AActor * AOptiXVRPawn::GetActorNearHand(UPrimitiveComponent * Hand)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::GetActorNearHand"))
 	TArray<AActor*> OverlappingActors;
 	Hand->GetOverlappingActors(OverlappingActors);
 
@@ -181,4 +174,4 @@ AActor * AOptiXVRPawn::GetActorNearHand(UPrimitiveComponent * Hand)
 void AOptiXVRPawn::CaptureDeferredHelper(USceneCaptureComponent2D* SceneCapture)
 {
 	SceneCapture->CaptureSceneDeferred();
-}
+}
\ No newline at end of file
diff --git a/Source/OptiX/Private/OutlineStaticMeshComponent.cpp b/Source/OptiX/Private/OutlineStaticMeshComponent.cpp
deleted file mode 100644
index 206d64f83061a82f32152c785b0818c305f4b9f1..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/OutlineStaticMeshComponent.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-
-#include "OutlineStaticMeshComponent.h"
-#include "PrimitiveSceneProxy.h"
-#include "StaticMeshResources.h"
-#include "Engine/StaticMesh.h"
-
-
-FPrimitiveSceneProxy* UOutlineStaticMeshComponent::CreateSceneProxy()
-{
-
-	class FOutlineStaticMeshProxy final : public FStaticMeshSceneProxy
-	{
-	public:
-		SIZE_T GetTypeHash() const override
-		{
-			static size_t UniquePointer;
-			return reinterpret_cast<size_t>(&UniquePointer);
-		}
-
-		/** Initialization constructor. */
-		FOutlineStaticMeshProxy(UOutlineStaticMeshComponent* InComponent)
-			: FStaticMeshSceneProxy(InComponent, false)
-		{}
-
-		virtual void ApplyLateUpdateTransform(const FMatrix& LateUpdateTransform) override
-		{
-			// As the SetTransform function is private, this needs to be a little hacky
-
-			FMatrix NewTransform = GetLocalToWorld() * LateUpdateTransform;
-			FVector OriginChange = NewTransform.GetOrigin() - GetLocalToWorld().GetOrigin();
-			FMatrix ReducedLateUpdate = FMatrix::Identity;
-			ReducedLateUpdate.SetOrigin(OriginChange);
-
-			FStaticMeshSceneProxy::ApplyLateUpdateTransform(ReducedLateUpdate);
-		}
-	};
-
-	if (GetStaticMesh() == nullptr || GetStaticMesh()->RenderData == nullptr)
-	{
-		return nullptr;
-	}
-
-	const TIndirectArray<FStaticMeshLODResources>& LODResources = GetStaticMesh()->RenderData->LODResources;
-	if (LODResources.Num() == 0 || LODResources[FMath::Clamp<int32>(GetStaticMesh()->MinLOD.Default, 0, LODResources.Num() - 1)].VertexBuffers.StaticMeshVertexBuffer.GetNumVertices() == 0)
-	{
-		return nullptr;
-	}
-	LLM_SCOPE(ELLMTag::StaticMesh);
-
-	FPrimitiveSceneProxy* Proxy = ::new FOutlineStaticMeshProxy(this);
-#if STATICMESH_ENABLE_DEBUG_RENDERING
-	SendRenderDebugPhysics(Proxy);
-#endif
-
-	return Proxy;
-}
\ No newline at end of file
diff --git a/Source/OptiX/Private/SelectableActorBase.cpp b/Source/OptiX/Private/SelectableActorBase.cpp
index e5e9eac2cc9de8f87b5acdc145c87cc1b5031ad4..62a140be01870ed14f27836307974d2a36a8bf3f 100644
--- a/Source/OptiX/Private/SelectableActorBase.cpp
+++ b/Source/OptiX/Private/SelectableActorBase.cpp
@@ -6,12 +6,8 @@
 #include "Kismet/GameplayStatics.h"
 #include "Blueprint/UserWidget.h"
 #include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
-#include "UObject/FrameworkObjectVersion.h"
 
-#include "OutlineStaticMeshComponent.h"
-
-
-#include "StatsDefines.h"
+#include "OptiXVRPawn.h"
 
 ASelectableActorBase::ASelectableActorBase(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -19,22 +15,10 @@ ASelectableActorBase::ASelectableActorBase(const FObjectInitializer& ObjectIniti
 
 	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor Start"));
 
-	bCanBeDamaged = false;
-
-	StaticMeshComponent = CreateDefaultSubobject<UOutlineStaticMeshComponent>(TEXT("StaticMeshComponent0"));
-	StaticMeshComponent->SetCollisionProfileName(UCollisionProfile::BlockAll_ProfileName);
-	StaticMeshComponent->Mobility = EComponentMobility::Static;
-	StaticMeshComponent->SetGenerateOverlapEvents(false);
-	StaticMeshComponent->bUseDefaultCollision = true;
-
-	RootComponent = StaticMeshComponent;
-
 	SetMobility(EComponentMobility::Movable);
 
 	GetStaticMeshComponent()->SetGenerateOverlapEvents(true);
 	GetStaticMeshComponent()->CastShadow = 0;
-	GetStaticMeshComponent()->SetHiddenInGame(false);
-	GetStaticMeshComponent()->SetRenderInMainPass(false);
 
 	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor Component Setup Start"));
 
@@ -363,8 +347,6 @@ void ASelectableActorBase::BeginPlay()
 {
 	Super::BeginPlay();
 
-	OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
-
 	ArrowX->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowX->GetMaterial(0));
 	ArrowX->CreateAndSetMaterialInstanceDynamicFromMaterial(1, ArrowX->GetMaterial(1));
 	ArrowY->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowY->GetMaterial(0));
@@ -395,10 +377,9 @@ void ASelectableActorBase::BeginPlay()
 void ASelectableActorBase::Tick(float DeltaTime)
 {
 	Super::Tick(DeltaTime);
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ASelectableActorBase::Tick"))
+	
 
-	//FVector PlayerLocation = UGameplayStatics::GetPlayerPawn(GetWorld(), 0)->GetActorLocation();
-	FVector PlayerLocation = OptiXVRPawn->HMDLocation;
+	FVector PlayerLocation = UGameplayStatics::GetPlayerPawn(GetWorld(), 0)->GetActorLocation();
 	{
 		FVector Diff = PlayerLocation - DegreeWidgetV->GetComponentTransform().GetLocation();
 		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
@@ -453,6 +434,7 @@ void ASelectableActorBase::EnableTranslation()
 	ArrowY->SetGenerateOverlapEvents(true);
 	ArrowZ->SetGenerateOverlapEvents(true);
 
+	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
 	if (OptiXVRPawn)
 	{
 		OptiXVRPawn->UIEventTranslation();
@@ -471,6 +453,7 @@ void ASelectableActorBase::EnableRotation()
 	ArrowY->SetGenerateOverlapEvents(false);
 	ArrowZ->SetGenerateOverlapEvents(false);
 
+	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
 	if (OptiXVRPawn)
 	{
 		OptiXVRPawn->UIEventRotation();
@@ -479,6 +462,7 @@ void ASelectableActorBase::EnableRotation()
 
 void ASelectableActorBase::DeselectActor()
 {
+	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
 	if (OptiXVRPawn)
 	{
 		OptiXVRPawn->UIEventDeselect();
@@ -488,6 +472,7 @@ void ASelectableActorBase::DeselectActor()
 
 void ASelectableActorBase::DeleteActor()
 {
+	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
 	if (OptiXVRPawn)
 	{
 		OptiXVRPawn->UIEventDelete();
@@ -498,7 +483,6 @@ void ASelectableActorBase::DeleteActor()
 
 void ASelectableActorBase::SetRodPosition(FVector TablePosition)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ASelectableActorBase::SetRodPosition"))
 
 	// Flip socket?
 	if (Socket->GetComponentLocation().Z > GetActorLocation().Z)
@@ -563,25 +547,3 @@ void ASelectableActorBase::OnOverlapEnd_Implementation(UPrimitiveComponent* Over
 	//	Cast<UMaterialInstanceDynamic>(OverlappedComp->GetMaterial(i))->SetVectorParameterValue("Color", FLinearColor(0.4, 0.4, 0.4));
 	//}
 }
-
-FString ASelectableActorBase::GetDetailedInfoInternal() const
-{
-	return StaticMeshComponent ? StaticMeshComponent->GetDetailedInfoInternal() : TEXT("No_StaticMeshComponent");
-}
-
-void ASelectableActorBase::SetMobility(EComponentMobility::Type InMobility)
-{
-	if (StaticMeshComponent)
-	{
-		StaticMeshComponent->SetMobility(InMobility);
-	}
-}
-
-void ASelectableActorBase::Serialize(FArchive& Ar)
-{
-	Super::Serialize(Ar);
-#if WITH_EDITOR
-	Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID);
-#endif
-}
-
diff --git a/Source/OptiX/Private/cuda/box_intersect.cu b/Source/OptiX/Private/cuda/box_intersect.cu
deleted file mode 100644
index d6d7dbadce8f8a2d96fca5fca423ca8d142dee24..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/box_intersect.cu
+++ /dev/null
@@ -1,74 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optix_world.h>
-#include "lens_intersections.h"
-
-using namespace optix;
-
-rtDeclareVariable(float3,  size, , );
-rtDeclareVariable(float,   scene_epsilon, , );
-
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-
-RT_PROGRAM void intersect(int primIdx)
-{
-	float3 bounds[] = {-size/2.0f, size/2.0f};
-	float3 invDir = 1.0f / ray.direction;
-	uint3 sign = {invDir.x < 0, invDir.y < 0, invDir.z < 0};
-
-	float tmin = (bounds[sign.x].x - ray.origin.x) * invDir.x;
-	float tmax = (bounds[1 - sign.x].x - ray.origin.x) * invDir.x;
-	float tymin = (bounds[sign.y].y - ray.origin.y) * invDir.y;
-	float tymax = (bounds[1 - sign.y].y - ray.origin.y) * invDir.y;
-
-	if ((tmin > tymax) || (tymin > tmax)) return;
-	if (tymin > tmin) tmin = tymin;
-	if (tymax < tmax) tmax = tymax;
-
-	float tzmin = (bounds[sign.z].z - ray.origin.z) * invDir.z;
-	float tzmax = (bounds[1 - sign.z].z - ray.origin.z) * invDir.z;
-
-	if ((tmin > tzmax) || (tzmin > tmax)) return;
-	if (tzmin > tmin) tmin = tzmin;
-	//if (tzmax < tmax) tmax = tzmax;
-	
-	if(rtPotentialIntersection(tmin)) {
-		float3 hit_point = ray.origin + ray.direction * tmin;
-		texture_coord = make_float2(-1.0f, -1.0f);
-		if(tmin != tzmin && tmin != tymin){ //x-side
-			texture_coord = (make_float2(hit_point.y, hit_point.z) - make_float2(-size.y / 2.0f, -size.z / 2.0f))
-							/make_float2(size.y, size.z);
-			//rtPrintf("%f, %f\n", texture_coord.x, texture_coord.y);
-		}
-		rtReportIntersection(0);
-	}
-}
-
-RT_PROGRAM void bounds (int, optix::Aabb* aabb)
-{
-	aabb->m_min = -size/2.0f;
-	aabb->m_max = size/2.0f;
-}
diff --git a/Source/OptiX/Private/cuda/box_intersect_material.cu b/Source/OptiX/Private/cuda/box_intersect_material.cu
deleted file mode 100644
index 644fe03ab14429c8c10f57b86da18eae0e74f39b..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/box_intersect_material.cu
+++ /dev/null
@@ -1,49 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix_world.h>
-#include "prd.h"
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
-rtTextureSampler<float4, 2> frameTexture;
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-RT_PROGRAM void closest_hit_radiance()
-{ 
-	if(texture_coord.x >= 0 && texture_coord.y >= 0){
-		prd_radiance.result = make_float3(tex2D(frameTexture, texture_coord.x, texture_coord.y)); 	
-	}else{
-		prd_radiance.result = make_float3(1.0f);
-	}
-	
-	prd_radiance.hit_depth = hit_depth;
-}
-
-RT_PROGRAM void closest_hit_iterative()
-{ 
-	float3 hit_point = ray.origin + hit_depth * ray.direction;
-	prd_radiance_it.origin = hit_point;
-	prd_radiance_it.done = true;
-}
diff --git a/Source/OptiX/Private/cuda/exception.cu b/Source/OptiX/Private/cuda/exception.cu
deleted file mode 100644
index 06d8fb5f17a908f9707c7b33f3950bb76e9ca9b5..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/exception.cu
+++ /dev/null
@@ -1,33 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-
-using namespace optix;
-
-rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
-
-RT_PROGRAM void exception()
-{
-  const unsigned int code = rtGetExceptionCode();
-  rtPrintf( "Caught exception 0x%X at launch index (%d,%d)\n", code, launch_index.x, launch_index.y );
-}
\ No newline at end of file
diff --git a/Source/OptiX/Private/cuda/glass_iterative_camera.cu b/Source/OptiX/Private/cuda/glass_iterative_camera.cu
deleted file mode 100644
index 633bff9266f222fd7a993ffc2a4a89a28f69ef89..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/glass_iterative_camera.cu
+++ /dev/null
@@ -1,76 +0,0 @@
-/* 
- * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of NVIDIA CORPORATION nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "prd.h"
-#include "random.h"
-
-using namespace optix;
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 
-rtDeclareVariable(float3, front_hit_point, attribute front_hit_point, );
-rtDeclareVariable(float3, back_hit_point, attribute back_hit_point, );
-
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-rtDeclareVariable(float, t_hit, rtIntersectionDistance, );
-
-rtDeclareVariable(int, allowTir, , );
-
-rtDeclareVariable(float, refraction_index, , );
-rtDeclareVariable(float, laserWaveLength, , );
-
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance, rtPayload, );
-
-RT_PROGRAM void closest_hit_iterative()
-{
-	prd_radiance.hit_lens = 1;
-
-	const float3 w_out = -ray.direction;
-	float3 normal = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal));
-
-	float cos_theta_i = optix::dot( w_out, normal );
-	float eta = ( cos_theta_i > 0.0f ) * refraction_index + ( cos_theta_i <= 0.0f ) * 1.0f / refraction_index;
-	normal =  ( cos_theta_i > 0.0f ) * normal + ( cos_theta_i <= 0.0f ) * -normal;
-	
-	float3 w_t;
-	const bool tir = !optix::refract( w_t, -w_out, normal, eta );
-	
-	const float3 w_in = (tir > 0) * optix::reflect( -w_out, normal ) + (tir <= 0) * w_t; 
-	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
-	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
-	
-	prd_radiance.origin = (tir > 0) * fhp + (tir <= 0) * bhp;
-	prd_radiance.direction = w_in; 
-	prd_radiance.done = !allowTir && tir;
-
- // Note: we do not trace the ray for the next bounce here, we just set it up for
- // the ray-gen program using per-ray data.
-}
-
-
diff --git a/Source/OptiX/Private/cuda/laser_caster.cu b/Source/OptiX/Private/cuda/laser_caster.cu
index ea4a2766e5983924ed900376d2b35d6fcbfc6c0c..36fe02f4a3444fe9b9933ecdb0644039a72bbeb4 100644
--- a/Source/OptiX/Private/cuda/laser_caster.cu
+++ b/Source/OptiX/Private/cuda/laser_caster.cu
@@ -80,8 +80,7 @@ RT_PROGRAM void laser_caster(){
 
 	Matrix3x3 laser_rot3x3 = make_matrix3x3(laser_rot);
 
-	//prd.direction = laser_rot3x3 * normalize(make_float3(1,1,-1)*laserDir[make_uint2(launch_index)]);		   
-	prd.direction = laser_rot3x3 * laserDir[make_uint2(launch_index)];		   
+	prd.direction = laser_rot3x3 * normalize(make_float3(1,1,-1)*laserDir[make_uint2(launch_index)]);		   
 
 
 	unsigned int widthIndex = launch_index.y * 50 + launch_index.x;
diff --git a/Source/OptiX/Private/cuda/laser_target.cu b/Source/OptiX/Private/cuda/laser_target.cu
deleted file mode 100644
index 8ce954c1e78d8610faaf8936306803dde9e9701a..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/laser_target.cu
+++ /dev/null
@@ -1,79 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optix_world.h>
-
-using namespace optix;
-
-rtDeclareVariable(float3,  p1, , );
-rtDeclareVariable(float3,  p2, , );
-rtDeclareVariable(float2,  stretchXY1, , );
-rtDeclareVariable(float2,  stretchXZ2, , );
-
-rtDeclareVariable(float,   scene_epsilon, , );
-
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-rtDeclareVariable(int, writeable_surface, attribute writeable_surface, );
-
-RT_PROGRAM void intersect(int primIdx)
-{
-	//Hit Z?
-	float t_1 = (p1.x - ray.origin.x) * (1.0f / ray.direction.x);
-	float3 hp = ray.origin + ray.direction * t_1;
-	float2 rel_size_z = (make_float2(hp.y, hp.z) - (make_float2(p1.y, p1.z) - stretchXY1/2))/stretchXY1;
-	bool hit_z = rel_size_z.x < 1 && rel_size_z.y < 1 && rel_size_z.x >= 0 && rel_size_z.y >= 0;
-	
-	//Hit X? - ignore this for now
-	//float t_2 = (p2.x - ray.origin.x) * (1.0f / ray.direction.x);
-	//float3 hp = ray.origin + ray.direction * t_2;
-	//float2 rel_size_x = (make_float2(hp.z, hp.y) - (make_float2(p2.z, p2.y) - stretchXZ2/2))/stretchXZ2;
-	//bool hit_x = rel_size_x.x < 1 && rel_size_x.y < 1 && rel_size_x.x >= 0 && rel_size_x.y >= 0;
-	
-	//Which one is closer
-	//float tmin = fminf(t_1 + (!hit_z > 0)*0x7f800000 , t_2 + (!hit_x > 0)*100000); //0x7f800000 == +INFINITY
-	//float2 rel_size = (tmin == t_1) * rel_size_z + (tmin == t_2) * rel_size_x;
-	if((hit_z) && rtPotentialIntersection(t_1)) {
-		texture_coord = make_float2(1 - rel_size_z.x, 1 - rel_size_z.y);
-		writeable_surface = 1; // don't need this as well
-		rtReportIntersection(0);
-	}
-}
-
-RT_PROGRAM void bounds (int, optix::Aabb* aabb)
-{
-
-	// Make this a plane with x == 0
-
-	//float min_x = fminf(p1.x - stretchXY1.x/2, p2.x);
-	//float min_y = fminf(p1.y, p2.y - stretchXY1.x / 2);
-	//float min_z = fminf(p1.z - stretchXY1.y / 2, p2.z - stretchXZ2.y / 2);
-	////
-	//float max_x = fmaxf(p1.x + stretchXY1.x/2, p2.x);
-	//float max_y = fmaxf(p1.y, p2.y - stretchXY1.y / 2);
-	//float max_z = fmaxf(p1.z - stretchXY1.y / 2, p2.z - stretchXZ2.y / 2);
-
-	aabb->m_min = make_float3(-0.01, p1.y - stretchXY1.x / 2, p1.z - stretchXY1.y / 2);
-	aabb->m_max = make_float3(0.01, p1.y + stretchXY1.x / 2, p1.z + stretchXY1.y / 2);
-}
diff --git a/Source/OptiX/Private/cuda/laser_target_material.cu b/Source/OptiX/Private/cuda/laser_target_material.cu
deleted file mode 100644
index da69dda159754a1b2c14db8619bffed793c033d6..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/laser_target_material.cu
+++ /dev/null
@@ -1,65 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix_world.h>
-#include "prd.h"
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-rtDeclareVariable(int, writeable_surface, attribute writeable_surface, );
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
-
-rtDeclareVariable(float, max_power, , );
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-rtBuffer<unsigned int, 1> targetBufferMax;
-rtBuffer<float, 2> targetBuffer;
-rtDeclareVariable(float2, targetBufferDim, , );
-rtDeclareVariable(int, targetBufferWrite, , );
-
-RT_PROGRAM void any_hit_radiance(){ 
-	rtIgnoreIntersection();
-	
-	//for debugging
-	//rtPrintf("executed \n");
-
-	//prd_radiance.result = make_float3(1.0f, 0.0f, 0.0f);
-	//prd_radiance.hit_depth = hit_depth;
-}
-
-RT_PROGRAM void closest_hit_radiance()
-{ 
-	//rtIgnoreIntersection();
-}
-
-RT_PROGRAM void closest_hit_iterative()
-{ 
-	float3 hit_point = ray.origin + hit_depth * ray.direction;
-	prd_radiance_it.origin = hit_point;
-	prd_radiance_it.done = true;
-	
-	if(targetBufferWrite && writeable_surface){
-		atomicAdd(&targetBuffer[make_uint2(texture_coord * targetBufferDim)], prd_radiance_it.power);
-		atomicMax(&targetBufferMax[0], (unsigned int) targetBuffer[make_uint2(texture_coord * targetBufferDim)]);
-	}
-}
diff --git a/Source/OptiX/Private/cuda/lens_parametric.cu b/Source/OptiX/Private/cuda/lens_parametric.cu
deleted file mode 100644
index b85ba9fa40ba31dffb9375b7689decc9bbe39c09..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/lens_parametric.cu
+++ /dev/null
@@ -1,110 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optix_world.h>
-#include "lens_intersections.h"
-
-using namespace optix;
-
-rtDeclareVariable(float,  lensRadius, , );
-rtDeclareVariable(float3,  orientation, , );
-rtDeclareVariable(float3,  center, , );
-rtDeclareVariable(float,   radius, , );
-rtDeclareVariable(float,   radius2, , );
-rtDeclareVariable(float,   halfCylinderLength, , );
-rtDeclareVariable(float,   scene_epsilon, , );
-
-//1==convex, 2==concave, 0==plane
-rtDeclareVariable(int,   side1Type, , );
-rtDeclareVariable(int,   side2Type, , );
-
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, ); 
-rtDeclareVariable(float3, shading_normal, attribute shading_normal, );
-rtDeclareVariable(float3, front_hit_point, attribute front_hit_point, ); 
-rtDeclareVariable(float3, back_hit_point, attribute back_hit_point, );
-
-RT_PROGRAM void intersect(int primIdx)
-{
-	perHitData h1;
-	if(side1Type != 0){
-		int mult = side1Type;
-		if (side1Type == 2) mult = -1;
-
-		float dist = -sqrtf(radius*radius - powf(lensRadius,2)) + mult*halfCylinderLength;
-		float3 nCenter = center + mult *orientation*dist;
-		h1.t = circleIntersect(radius, nCenter, ray, mult*orientation, lensRadius, scene_epsilon);
-		h1.p = ray.origin + h1.t*ray.direction;
-		h1.normal = mult *(h1.p - nCenter) / radius;
-	} else{
-		h1.t = intersectPlane(center + orientation*(halfCylinderLength), ray, -orientation, lensRadius, scene_epsilon);
-		h1.p = ray.origin + h1.t*ray.direction;
-		h1.normal = orientation;
-	}	
-	
-	perHitData h2;
-	if(side2Type != 0){
-		int mult = side2Type;
-		if (side2Type == 2) mult = -1;
-		float dist = -sqrtf(radius2*radius2 - powf(lensRadius,2)) + mult *halfCylinderLength;
-		float3 nCenter = center - mult *orientation*dist;
-		h2.t = circleIntersect(radius2, nCenter, ray, -mult *orientation, lensRadius, scene_epsilon);
-		h2.p = ray.origin + h2.t*ray.direction;
-		h2.normal = mult *(h2.p - nCenter) / radius2;
-	} else{
-		h2.t = intersectPlane(center - orientation*(halfCylinderLength), ray, orientation, lensRadius, scene_epsilon);
-		h2.p = ray.origin + h2.t*ray.direction;
-		h2.normal = -orientation;
-	}
-
-	perHitData h3;
-	h3.t = cylinderIntersect(halfCylinderLength*2, center, ray, orientation, lensRadius, scene_epsilon);	
-	h3.p = ray.origin + h3.t*ray.direction;
-	float3 inner = dot(h3.p - center, orientation) * orientation + center;
-	h3.normal = normalize(h3.p - inner);
-	
-	perHitData closest = nearestButPositivHit(h1, h2, scene_epsilon);
-	closest = nearestButPositivHit(closest, h3, scene_epsilon);
-	
-	if(rtPotentialIntersection(closest.t) ) {
-		int b = (dot(closest.p - ray.origin, closest.normal) > 0.0f) * 2 - 1; //look from inside out yes == 1, no == -1
-	
-		front_hit_point = closest.p + -b * closest.normal * scene_epsilon;
-		back_hit_point = closest.p + b * closest.normal * scene_epsilon;
-		
-		shading_normal = geometric_normal = closest.normal;
-		rtReportIntersection( 0 );
-	}
-}
-
-RT_PROGRAM void bounds (int, optix::Aabb* aabb)
-{
-	//Size for double convex case should be the biggest
-	float halfSphere1 = (radius - sqrtf(radius*radius - lensRadius*lensRadius))*(side1Type == 1);
-	float halfSphere2 = (radius2 - sqrtf(radius2*radius2 - lensRadius*lensRadius))*(side2Type == 1);
-	maxMinSet res = getAABBFromCylinder(center, orientation, halfCylinderLength + halfSphere1 + scene_epsilon, halfCylinderLength + halfSphere2 + scene_epsilon, lensRadius);
-	
-	aabb->m_min = res.min;
-	aabb->m_max = res.max;
-}
diff --git a/Source/OptiX/Private/cuda/lens_parametric_material.cu b/Source/OptiX/Private/cuda/lens_parametric_material.cu
deleted file mode 100644
index eef16660083386510a8bf20f229cfdf90107d2f6..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/lens_parametric_material.cu
+++ /dev/null
@@ -1,176 +0,0 @@
-/* 
- * Copyright(c)2017 NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of NVIDIA CORPORATION nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "helpers.h"
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(rtObject, top_object, ,);
-rtDeclareVariable(float, scene_epsilon, ,);
-rtDeclareVariable(int, max_depth, ,);
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal,); 
-rtDeclareVariable(float3, front_hit_point, attribute front_hit_point,);
-rtDeclareVariable(float3, back_hit_point, attribute back_hit_point,);
-
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance,);
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay,);
-
-rtDeclareVariable(float, importance_cutoff, ,);
-rtDeclareVariable(float3, cutoff_color, ,);
-rtDeclareVariable(float, fresnel_exponent, ,);
-rtDeclareVariable(float, fresnel_minimum, ,);
-rtDeclareVariable(float, fresnel_maximum, ,);
-rtDeclareVariable(float, refraction_index, ,);
-rtDeclareVariable(int, refraction_maxdepth, ,);
-rtDeclareVariable(int, reflection_maxdepth, ,);
-rtDeclareVariable(float3, refraction_color, ,);
-rtDeclareVariable(float3, reflection_color, ,);
-rtDeclareVariable(float3, extinction_constant, ,);
-rtDeclareVariable(int, lens_id, ,);
-
-rtDeclareVariable(int, allowTir, , );
-rtDeclareVariable(float, laserWaveLength, , );
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload,);
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
-
-// -----------------------------------------------------------------------------
-
-static __device__ __inline__ float3 TraceRay(float3 origin, float3 direction, int depth, float importance, float hit_depth, unsigned int flags, int last_lens_id)
-{
- optix::Ray ray = optix::make_Ray(origin, direction, 0, 0.0f, RT_DEFAULT_MAX);
- PerRayData_radiance prd;
- prd.depth = depth;
- prd.importance = importance;
- prd.hit_depth = hit_depth;
- prd.flags = flags;
- prd.last_lens_id = last_lens_id;
- 
- rtTrace(top_object, ray, prd);
- return prd.result;
-}
-
-static __device__ __inline__ float3 exp(const float3& x){
- return make_float3(exp(x.x), exp(x.y), exp(x.z));
-}
-
-// -----------------------------------------------------------------------------
-
-RT_PROGRAM void closest_hit_radiance(){
-
-	unsigned int hit_lens = (prd_radiance.flags >> 1);
-	if(hit_lens == 0) prd_radiance.hit_depth = hit_depth;
-	prd_radiance.flags = prd_radiance.flags | 2;
-	prd_radiance.last_lens_id = lens_id;
-
-	// intersection vectors
-	const float3 n = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal)); // normal
-	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
-	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
-	const float3 i = ray.direction; // incident direction
-	float3 t; // transmission direction
-	float3 r; // reflection direction
-
-	float reflection = 1.0f;
-	float3 result = make_float3(0.0f);
-
-	const int depth = prd_radiance.depth;
-
-	float3 beer_attenuation;
-	if(dot(n, ray.direction) > 0){
-		// Beer's law attenuation
-		beer_attenuation = exp(extinction_constant * (hit_depth / 100));
-	} else {
-		beer_attenuation = make_float3(1);
-	}
-
-	// refraction
-	if(depth < min(refraction_maxdepth, max_depth)){
-		if(refract(t, i, n, refraction_index)){
-			// check for external or internal reflection
-			float cos_theta = dot(i, n);
-			cos_theta = (cos_theta < 0.0f) * -cos_theta + (cos_theta >= 0.0f) * dot(t, n);
-			
-			reflection = fresnel_schlick(cos_theta, fresnel_exponent, fresnel_minimum, fresnel_maximum);
-
-			float importance = prd_radiance.importance * (1.0f-reflection) * optix::luminance(refraction_color * beer_attenuation);
-			float3 color = cutoff_color;
-			if(importance > importance_cutoff){
-				color = TraceRay(bhp, t, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
-			}
-			result +=(1.0f - reflection)* refraction_color * color;
-		}
-		// else TIR
-	} // else reflection==1 so refraction has 0 weight
-
-	// reflection
-	float3 color = cutoff_color;
-	if(depth < min(reflection_maxdepth, max_depth)){
-		r = reflect(i, n);
-
-		float importance = prd_radiance.importance * reflection * optix::luminance(reflection_color * beer_attenuation);
-		if(importance > importance_cutoff){
-			color = TraceRay(fhp, r, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
-		}
-	}
-	result += reflection * reflection_color * color;
-
-	result = result * beer_attenuation;
-
-	prd_radiance.result = result;
-}
-
-RT_PROGRAM void closest_hit_iterative()
-{
-	prd_radiance_it.hit_lens = 1;
-
-	const float3 w_out = -ray.direction;
-	float3 normal = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal));
-
-	float cos_theta_i = optix::dot( w_out, normal );
-	float eta = ( cos_theta_i > 0.0f ) * refraction_index + ( cos_theta_i <= 0.0f ) * 1.0f / refraction_index;
-	normal =  ( cos_theta_i > 0.0f ) * normal + ( cos_theta_i <= 0.0f ) * -normal;
-	
-	float3 w_t;
-	const bool tir = !optix::refract( w_t, -w_out, normal, eta );
-	
-	const float3 w_in = (tir > 0) * optix::reflect( -w_out, normal ) + (tir <= 0) * w_t; 
-	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
-	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
-	
-	prd_radiance_it.origin = (tir > 0) * fhp + (tir <= 0) * bhp;
-	prd_radiance_it.direction = w_in; 
-	prd_radiance_it.done = !allowTir && tir;
-
- // Note: we do not trace the ray for the next bounce here, we just set it up for
- // the ray-gen program using per-ray data.
-}
\ No newline at end of file
diff --git a/Source/OptiX/Private/cuda/normal_shader.cu b/Source/OptiX/Private/cuda/normal_shader.cu
deleted file mode 100644
index fc128891e916010c0120959a33ec54e998da1a9f..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/normal_shader.cu
+++ /dev/null
@@ -1,46 +0,0 @@
-/* 
- * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *  * Neither the name of NVIDIA CORPORATION nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 
-
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-
-
-RT_PROGRAM void closest_hit_radiance()
-{
-  prd_radiance.result = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal))*0.5f + 0.5f;
-  prd_radiance.hit_depth = hit_depth;
-}
diff --git a/Source/OptiX/Private/cuda/normal_shader_new.cu b/Source/OptiX/Private/cuda/normal_shader_new.cu
deleted file mode 100644
index a9a74f05451de67497bd4313969bfb4837a9eb73..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/normal_shader_new.cu
+++ /dev/null
@@ -1,37 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 
-
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance, rtPayload, );
-
-RT_PROGRAM void closest_hit_radiance()
-{
-  prd_radiance.power = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal)).x * 0.5f + 0.5f;
-  prd_radiance.done = true;
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/box_intersect.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/box_intersect.cu
deleted file mode 100644
index d6d7dbadce8f8a2d96fca5fca423ca8d142dee24..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/box_intersect.cu
+++ /dev/null
@@ -1,74 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optix_world.h>
-#include "lens_intersections.h"
-
-using namespace optix;
-
-rtDeclareVariable(float3,  size, , );
-rtDeclareVariable(float,   scene_epsilon, , );
-
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-
-RT_PROGRAM void intersect(int primIdx)
-{
-	float3 bounds[] = {-size/2.0f, size/2.0f};
-	float3 invDir = 1.0f / ray.direction;
-	uint3 sign = {invDir.x < 0, invDir.y < 0, invDir.z < 0};
-
-	float tmin = (bounds[sign.x].x - ray.origin.x) * invDir.x;
-	float tmax = (bounds[1 - sign.x].x - ray.origin.x) * invDir.x;
-	float tymin = (bounds[sign.y].y - ray.origin.y) * invDir.y;
-	float tymax = (bounds[1 - sign.y].y - ray.origin.y) * invDir.y;
-
-	if ((tmin > tymax) || (tymin > tmax)) return;
-	if (tymin > tmin) tmin = tymin;
-	if (tymax < tmax) tmax = tymax;
-
-	float tzmin = (bounds[sign.z].z - ray.origin.z) * invDir.z;
-	float tzmax = (bounds[1 - sign.z].z - ray.origin.z) * invDir.z;
-
-	if ((tmin > tzmax) || (tzmin > tmax)) return;
-	if (tzmin > tmin) tmin = tzmin;
-	//if (tzmax < tmax) tmax = tzmax;
-	
-	if(rtPotentialIntersection(tmin)) {
-		float3 hit_point = ray.origin + ray.direction * tmin;
-		texture_coord = make_float2(-1.0f, -1.0f);
-		if(tmin != tzmin && tmin != tymin){ //x-side
-			texture_coord = (make_float2(hit_point.y, hit_point.z) - make_float2(-size.y / 2.0f, -size.z / 2.0f))
-							/make_float2(size.y, size.z);
-			//rtPrintf("%f, %f\n", texture_coord.x, texture_coord.y);
-		}
-		rtReportIntersection(0);
-	}
-}
-
-RT_PROGRAM void bounds (int, optix::Aabb* aabb)
-{
-	aabb->m_min = -size/2.0f;
-	aabb->m_max = size/2.0f;
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/exception.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/exception.cu
deleted file mode 100644
index 06d8fb5f17a908f9707c7b33f3950bb76e9ca9b5..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/exception.cu
+++ /dev/null
@@ -1,33 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-
-using namespace optix;
-
-rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
-
-RT_PROGRAM void exception()
-{
-  const unsigned int code = rtGetExceptionCode();
-  rtPrintf( "Caught exception 0x%X at launch index (%d,%d)\n", code, launch_index.x, launch_index.y );
-}
\ No newline at end of file
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/frame_material.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/frame_material.cu
deleted file mode 100644
index 644fe03ab14429c8c10f57b86da18eae0e74f39b..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/frame_material.cu
+++ /dev/null
@@ -1,49 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix_world.h>
-#include "prd.h"
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
-rtTextureSampler<float4, 2> frameTexture;
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-RT_PROGRAM void closest_hit_radiance()
-{ 
-	if(texture_coord.x >= 0 && texture_coord.y >= 0){
-		prd_radiance.result = make_float3(tex2D(frameTexture, texture_coord.x, texture_coord.y)); 	
-	}else{
-		prd_radiance.result = make_float3(1.0f);
-	}
-	
-	prd_radiance.hit_depth = hit_depth;
-}
-
-RT_PROGRAM void closest_hit_iterative()
-{ 
-	float3 hit_point = ray.origin + hit_depth * ray.direction;
-	prd_radiance_it.origin = hit_point;
-	prd_radiance_it.done = true;
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/glass_iterative_camera.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/glass_iterative_camera.cu
deleted file mode 100644
index e0754b8d479ae2e23a084f017888fb62c501fec4..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/glass_iterative_camera.cu
+++ /dev/null
@@ -1,76 +0,0 @@
-/* 
- * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of NVIDIA CORPORATION nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "prd.h"
-#include "random.h"
-
-using namespace optix;
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 
-rtDeclareVariable(float3, front_hit_point, attribute front_hit_point, );
-rtDeclareVariable(float3, back_hit_point, attribute back_hit_point, );
-
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-rtDeclareVariable(float, t_hit, rtIntersectionDistance, );
-
-rtDeclareVariable(int, allowTir, , );
-
-rtDeclareVariable(float, refraction_index, , );
-rtDeclareVariable(float, laserWaveLength, , );
-
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance, rtPayload, );
-
-RT_PROGRAM void closest_hit_radiance()
-{
-	prd_radiance.hit_lens = 1;
-
-	const float3 w_out = -ray.direction;
-	float3 normal = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal));
-
-	float cos_theta_i = optix::dot( w_out, normal );
-	float eta = ( cos_theta_i > 0.0f ) * refraction_index + ( cos_theta_i <= 0.0f ) * 1.0f / refraction_index;
-	normal =  ( cos_theta_i > 0.0f ) * normal + ( cos_theta_i <= 0.0f ) * -normal;
-	
-	float3 w_t;
-	const bool tir = !optix::refract( w_t, -w_out, normal, eta );
-	
-	const float3 w_in = (tir > 0) * optix::reflect( -w_out, normal ) + (tir <= 0) * w_t; 
-	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
-	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
-	
-	prd_radiance.origin = (tir > 0) * fhp + (tir <= 0) * bhp;
-	prd_radiance.direction = w_in; 
-	prd_radiance.done = !allowTir && tir;
-
- // Note: we do not trace the ray for the next bounce here, we just set it up for
- // the ray-gen program using per-ray data.
-}
-
-
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/glass_perspective_camera.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/glass_perspective_camera.cu
deleted file mode 100644
index 0aa2de5376091b3f99a0fedbc0a6f5a781703f21..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/glass_perspective_camera.cu
+++ /dev/null
@@ -1,146 +0,0 @@
-/* 
- * Copyright(c)2017 NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of NVIDIA CORPORATION nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "helpers.h"
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(rtObject, top_object, ,);
-rtDeclareVariable(float, scene_epsilon, ,);
-rtDeclareVariable(int, max_depth, ,);
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal,); 
-rtDeclareVariable(float3, front_hit_point, attribute front_hit_point,);
-rtDeclareVariable(float3, back_hit_point, attribute back_hit_point,);
-
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance,);
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay,);
-
-rtDeclareVariable(float, importance_cutoff, ,);
-rtDeclareVariable(float3, cutoff_color, ,);
-rtDeclareVariable(float, fresnel_exponent, ,);
-rtDeclareVariable(float, fresnel_minimum, ,);
-rtDeclareVariable(float, fresnel_maximum, ,);
-rtDeclareVariable(float, refraction_index, ,);
-rtDeclareVariable(int, refraction_maxdepth, ,);
-rtDeclareVariable(int, reflection_maxdepth, ,);
-rtDeclareVariable(float3, refraction_color, ,);
-rtDeclareVariable(float3, reflection_color, ,);
-rtDeclareVariable(float3, extinction_constant, ,);
-rtDeclareVariable(int, lens_id, ,);
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload,);
-
-// -----------------------------------------------------------------------------
-
-static __device__ __inline__ float3 TraceRay(float3 origin, float3 direction, int depth, float importance, float hit_depth, int miss, int hit_lens, int last_lens_id)
-{
- optix::Ray ray = optix::make_Ray(origin, direction, 0, 0.0f, RT_DEFAULT_MAX);
- PerRayData_radiance prd;
- prd.depth = depth;
- prd.importance = importance;
- prd.miss = miss;
- prd.hit_depth = hit_depth;
- prd.hit_lens = hit_lens; 
- prd.last_lens_id = last_lens_id;
- 
- rtTrace(top_object, ray, prd);
- return prd.result;
-}
-
-static __device__ __inline__ float3 exp(const float3& x){
- return make_float3(exp(x.x), exp(x.y), exp(x.z));
-}
-
-// -----------------------------------------------------------------------------
-
-RT_PROGRAM void closest_hit_radiance(){
-
-	if(prd_radiance.hit_lens == 0) prd_radiance.hit_depth = hit_depth;
-	prd_radiance.hit_lens = 1;
-	prd_radiance.last_lens_id = lens_id;
-
-	// intersection vectors
-	const float3 n = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal)); // normal
-	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
-	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
-	const float3 i = ray.direction; // incident direction
-	float3 t; // transmission direction
-	float3 r; // reflection direction
-
-	float reflection = 1.0f;
-	float3 result = make_float3(0.0f);
-
-	const int depth = prd_radiance.depth;
-
-	float3 beer_attenuation;
-	if(dot(n, ray.direction) > 0){
-		// Beer's law attenuation
-		beer_attenuation = exp(extinction_constant * (hit_depth / 100));
-	} else {
-		beer_attenuation = make_float3(1);
-	}
-
-	// refraction
-	if(depth < min(refraction_maxdepth, max_depth)){
-		if(refract(t, i, n, refraction_index)){
-			// check for external or internal reflection
-			float cos_theta = dot(i, n);
-			cos_theta = (cos_theta < 0.0f) * -cos_theta + (cos_theta >= 0.0f) * dot(t, n);
-			
-			reflection = fresnel_schlick(cos_theta, fresnel_exponent, fresnel_minimum, fresnel_maximum);
-
-			float importance = prd_radiance.importance * (1.0f-reflection) * optix::luminance(refraction_color * beer_attenuation);
-			float3 color = cutoff_color;
-			if(importance > importance_cutoff){
-				color = TraceRay(bhp, t, depth+1, importance, prd_radiance.hit_depth, prd_radiance.miss, prd_radiance.hit_lens, prd_radiance.last_lens_id);
-			}
-			result +=(1.0f - reflection)* refraction_color * color;
-		}
-		// else TIR
-	} // else reflection==1 so refraction has 0 weight
-
-	// reflection
-	float3 color = cutoff_color;
-	if(depth < min(reflection_maxdepth, max_depth)){
-		r = reflect(i, n);
-
-		float importance = prd_radiance.importance * reflection * optix::luminance(reflection_color * beer_attenuation);
-		if(importance > importance_cutoff){
-			color = TraceRay(fhp, r, depth+1, importance, prd_radiance.hit_depth, prd_radiance.miss, prd_radiance.hit_lens, prd_radiance.last_lens_id);
-		}
-	}
-	result += reflection * reflection_color * color;
-
-	result = result * beer_attenuation;
-
-	prd_radiance.result = result;
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_caster.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_caster.cu
deleted file mode 100644
index 36fe02f4a3444fe9b9933ecdb0644039a72bbeb4..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_caster.cu
+++ /dev/null
@@ -1,107 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include <optixu/optixu_matrix_namespace.h>
-#include "prd.h"
-#include "helpers.h"
-#include "random.h"
-
-
-#define PERCENTILE 1.47579f
-
-using namespace optix;
-
-rtDeclareVariable(uint3, launch_index, rtLaunchIndex, );
-rtDeclareVariable(uint3, launch_dim,   rtLaunchDim, );
-rtDeclareVariable(rtObject,      top_object, , );
-rtDeclareVariable(float,         scene_epsilon, , );
-rtDeclareVariable(int,           max_depth_laser, , );
-
-rtDeclareVariable(unsigned int,           random_frame_seed, , );
-
-rtDeclareVariable(float3,         laser_origin, , );
-rtDeclareVariable(float3,         laser_forward, , );
-rtDeclareVariable(float3,         laser_right, , );
-rtDeclareVariable(float3,         laser_up, , );
-rtDeclareVariable(Matrix4x4,      laser_rot, , );
-
-rtDeclareVariable(float,          laserBeamWidth, , );
-rtDeclareVariable(float,          laserSize, , );
-
-rtBuffer<int, 2>   			laserIndex;
-rtBuffer<float3, 2>   		laserDir;
-rtBuffer<float4, 2>			result_laser;
-
-
-RT_PROGRAM void laser_caster(){
-
-	float2 d = make_float2(launch_index.x, launch_index.y) / make_float2(launch_dim.x, launch_dim.y) - make_float2(0.5f, 0.5f);
-	float3 ray_origin = laser_origin + laser_right * laserSize * d.x + laser_up * laserSize * d.y;
-
-	//Uniform random
-	unsigned int seed = tea<16>(launch_dim.x*launch_index.y+launch_index.x*launch_index.z, random_frame_seed);
-	float2 random = make_float2(rnd(seed), rnd(seed));
-	//convert to normal distrubution
-	float r = sqrtf(-2*log(random.x));
-	float theta = 2*3.141592654f*random.y;
-	random = clamp(make_float2(r*cosf(theta), r*sinf(theta)), -4.5f, 4.5f) * laserBeamWidth * 0.5 /PERCENTILE;
-	ray_origin += (launch_index.z != 0) * (laser_right * random.x + laser_up * random.y);
-	
-	PerRayData_radiance_iterative prd;
-	optix::Ray ray(ray_origin, laser_forward, /*ray type*/ 1, scene_epsilon );
-	prd.depth = 0;
-	prd.done = false;
-	prd.hit_lens = 0; //track if the ray ever hit the lens
-	prd.power = (launch_index.z > 0) * 1; //No power for launch index 0
-	
-	// next ray to be traced
-	prd.origin = ray_origin;
-
-	Matrix3x3 laser_rot3x3 = make_matrix3x3(laser_rot);
-
-	prd.direction = laser_rot3x3 * normalize(make_float3(1,1,-1)*laserDir[make_uint2(launch_index)]);		   
-
-
-	unsigned int widthIndex = launch_index.y * 50 + launch_index.x;
-	//unsigned int startIndex = widthIndex * max_depth_laser * 2;
-	
-	bool cast_ray = laserIndex[make_uint2(launch_index)] < 0;
-	for(int i = 0; i < max_depth_laser * 2; i += 2){
-		//Determine if this launch_index, depth or last ray should trigger new cast
-		if(cast_ray || prd.done || prd.depth >= max_depth_laser){ // just write rest of data as "invalid"
-			if(launch_index.z == 0) result_laser[make_uint2(widthIndex, i)] = make_float4(0,-1,0,1);
-			if(launch_index.z == 0) result_laser[make_uint2(widthIndex, i + 1)] = make_float4(0,-1,0,1);
-			continue;
-		}
-		if(launch_index.z == 0) result_laser[make_uint2(widthIndex, i)] = make_float4(prd.origin,1);
-		
-		ray.origin = prd.origin;
-		ray.direction = prd.direction;
-		rtTrace(top_object, ray, prd);
-		
-		// Update ray data for the next path segment
-		prd.depth++;
-		if(launch_index.z == 0) result_laser[make_uint2(widthIndex, i + 1)] = make_float4(prd.origin,1);
-	}
-}
\ No newline at end of file
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_target.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_target.cu
deleted file mode 100644
index 8ce954c1e78d8610faaf8936306803dde9e9701a..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_target.cu
+++ /dev/null
@@ -1,79 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optix_world.h>
-
-using namespace optix;
-
-rtDeclareVariable(float3,  p1, , );
-rtDeclareVariable(float3,  p2, , );
-rtDeclareVariable(float2,  stretchXY1, , );
-rtDeclareVariable(float2,  stretchXZ2, , );
-
-rtDeclareVariable(float,   scene_epsilon, , );
-
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-rtDeclareVariable(int, writeable_surface, attribute writeable_surface, );
-
-RT_PROGRAM void intersect(int primIdx)
-{
-	//Hit Z?
-	float t_1 = (p1.x - ray.origin.x) * (1.0f / ray.direction.x);
-	float3 hp = ray.origin + ray.direction * t_1;
-	float2 rel_size_z = (make_float2(hp.y, hp.z) - (make_float2(p1.y, p1.z) - stretchXY1/2))/stretchXY1;
-	bool hit_z = rel_size_z.x < 1 && rel_size_z.y < 1 && rel_size_z.x >= 0 && rel_size_z.y >= 0;
-	
-	//Hit X? - ignore this for now
-	//float t_2 = (p2.x - ray.origin.x) * (1.0f / ray.direction.x);
-	//float3 hp = ray.origin + ray.direction * t_2;
-	//float2 rel_size_x = (make_float2(hp.z, hp.y) - (make_float2(p2.z, p2.y) - stretchXZ2/2))/stretchXZ2;
-	//bool hit_x = rel_size_x.x < 1 && rel_size_x.y < 1 && rel_size_x.x >= 0 && rel_size_x.y >= 0;
-	
-	//Which one is closer
-	//float tmin = fminf(t_1 + (!hit_z > 0)*0x7f800000 , t_2 + (!hit_x > 0)*100000); //0x7f800000 == +INFINITY
-	//float2 rel_size = (tmin == t_1) * rel_size_z + (tmin == t_2) * rel_size_x;
-	if((hit_z) && rtPotentialIntersection(t_1)) {
-		texture_coord = make_float2(1 - rel_size_z.x, 1 - rel_size_z.y);
-		writeable_surface = 1; // don't need this as well
-		rtReportIntersection(0);
-	}
-}
-
-RT_PROGRAM void bounds (int, optix::Aabb* aabb)
-{
-
-	// Make this a plane with x == 0
-
-	//float min_x = fminf(p1.x - stretchXY1.x/2, p2.x);
-	//float min_y = fminf(p1.y, p2.y - stretchXY1.x / 2);
-	//float min_z = fminf(p1.z - stretchXY1.y / 2, p2.z - stretchXZ2.y / 2);
-	////
-	//float max_x = fmaxf(p1.x + stretchXY1.x/2, p2.x);
-	//float max_y = fmaxf(p1.y, p2.y - stretchXY1.y / 2);
-	//float max_z = fmaxf(p1.z - stretchXY1.y / 2, p2.z - stretchXZ2.y / 2);
-
-	aabb->m_min = make_float3(-0.01, p1.y - stretchXY1.x / 2, p1.z - stretchXY1.y / 2);
-	aabb->m_max = make_float3(0.01, p1.y + stretchXY1.x / 2, p1.z + stretchXY1.y / 2);
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_target_material.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_target_material.cu
deleted file mode 100644
index 7739c000b421241aafca5fc4cfb309451abc7482..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_target_material.cu
+++ /dev/null
@@ -1,60 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix_world.h>
-#include "prd.h"
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-rtDeclareVariable(int, writeable_surface, attribute writeable_surface, );
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
-
-rtDeclareVariable(float, max_power, , );
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-rtBuffer<unsigned int, 1> targetBufferMax;
-rtBuffer<float, 2> targetBuffer;
-rtDeclareVariable(float2, targetBufferDim, , );
-rtDeclareVariable(int, targetBufferWrite, , );
-
-RT_PROGRAM void any_hit_radiance(){ 
-	rtIgnoreIntersection();
-	
-	//for debugging
-	//rtPrintf("executed \n");
-
-	//prd_radiance.result = make_float3(1.0f, 0.0f, 0.0f);
-	//prd_radiance.hit_depth = hit_depth;
-}
-
-RT_PROGRAM void closest_hit_iterative()
-{ 
-	float3 hit_point = ray.origin + hit_depth * ray.direction;
-	prd_radiance_it.origin = hit_point;
-	prd_radiance_it.done = true;
-	
-	if(targetBufferWrite && writeable_surface){
-		atomicAdd(&targetBuffer[make_uint2(texture_coord * targetBufferDim)], prd_radiance_it.power);
-		atomicMax(&targetBufferMax[0], (unsigned int) targetBuffer[make_uint2(texture_coord * targetBufferDim)]);
-	}
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/lens_intersections.h b/Source/OptiX/Private/cuda/optical-bench-2020-backup/lens_intersections.h
deleted file mode 100644
index 02c4f489675d9a7b7de8069d0f2599719f0e98b6..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/lens_intersections.h
+++ /dev/null
@@ -1,175 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#ifndef OPTICAL_BENCH_LENS_INTERSECTIONS_H_
-#define OPTICAL_BENCH_LENS_INTERSECTIONS_H_
-
-#include <optix.h>
-#include <optix_world.h>
-
-struct perHitData{
-	float 	t;
-	float3  normal;
-	float3 	p;
-};
-
-struct maxMinSet{
-	float3 max;
-	float3 min;
-};
-
-__device__ perHitData operator*(perHitData a, const int& b){
-	a.t *= b;
-	a.normal *= b;
-	a.p *= b;
-	return a;
-}
-
-__device__ perHitData operator*(const int& b, perHitData a){
-	a.t *= b;
-	a.normal *= b;
-	a.p *= b;
-	return a;
-}
-
-__device__ perHitData operator+(perHitData a, const perHitData& b){
-	a.t += b.t;
-	a.normal += b.normal;
-	a.p += b.p;
-	return a;
-}
-
-static __device__ float smallerButPositiv(float a, float b, float scene_epsilon){
-	return (a > scene_epsilon && b > scene_epsilon) * fminf(a,b) +
-	(a > scene_epsilon && b < -scene_epsilon) * a +
-	(a < -scene_epsilon && b > scene_epsilon) * b +
-	(a < scene_epsilon && b < scene_epsilon) * -1.0f; // all rest
-}
-
-static __device__ perHitData nearestButPositivHit(perHitData h1, perHitData h2, float scene_epsilon){
-	perHitData r;
-	r.t = -1.0f;
-	
-	return (h1.t > scene_epsilon && h2.t > scene_epsilon) *	(h1 * (h1.t <= h2.t) + h2 * (h1.t > h2.t))
-	+ (h1.t > scene_epsilon && h2.t < -scene_epsilon) * h1
-	+ (h1.t < -scene_epsilon && h2.t > scene_epsilon) * h2
-	+ (h1.t < -scene_epsilon && h2.t < -scene_epsilon) * r;
-}
-
-static __device__ float circleIntersect(float radius, float3 center, optix::Ray ray, float3 orientation, float lensRadius, float scene_epsilon){
-	using namespace optix;
-	
-	float3 L = ray.origin - center;
-	float3 D = ray.direction;
-
-	float tca = dot(L, D);
-	
-	float tch2 = tca*tca - dot(L, L) + radius*radius;
-	
-	if(tch2 > 0.0f){
-		float t1 = -tca - sqrtf(tch2);
-		if(t1 > 0.0f){ //check for actual hit in lens front, else discard hit
-			float3 p1 = ray.origin + t1*ray.direction;
-			float projection1 = dot(p1 - center, orientation);
-			float3 belowP1 = projection1 * orientation + center;
-			if(projection1 < 0.0f || length(p1 - belowP1) >= lensRadius) t1 = -1.0f;
-		}
-		float t2 = -tca + sqrtf(tch2);
-		if(t2 > 0.0f){ //check for actual hit in lens front, else discard hit
-			float3 p2 = ray.origin + t2*ray.direction;
-			float projection2 = dot(p2 - center, orientation);
-			float3 belowP2 = projection2 * orientation + center;
-			if(projection2 < 0.0f || length(p2 - belowP2) >= lensRadius) t2 = -1.0f;
-		}
-	
-		float t = smallerButPositiv(t1, t2, scene_epsilon);
-		return (t < 0.0f) * -1.0f + (t >= 0.0f) * t;
-	}
-	return -1.0f;
-}
-
-static __device__ float cylinderIntersect(float length, float3 center, optix::Ray ray, float3 orientation, float lensRadius, float scene_epsilon){
-	using namespace optix;
-	
-	float3 dp = ray.origin - center;
-	
-	float3 A = ray.direction - dot(ray.direction, orientation) * orientation;
-	float a = dot(A,A);
-	float b = dot(ray.direction - dot(ray.direction, orientation)*orientation, dp - dot(dp, orientation)*orientation);
-	float3 C = (dp - dot(dp, orientation)*orientation);
-	float c = dot(C,C) - lensRadius*lensRadius;
-	
-	float discriminant = b*b - a*c;
-	if(discriminant > 0.0f){
-		float t1 = (-b - sqrtf(discriminant))/a;
-		if(fabs(dot((ray.origin + t1 * ray.direction) - center, orientation)) > length / 2) t1 = -1.0f;
-		float t2 = (-b + sqrtf(discriminant))/a;
-		if(fabs(dot((ray.origin + t2 * ray.direction) - center, orientation)) > length / 2) t2 = -1.0f;
-		
-		return smallerButPositiv(t1, t2, scene_epsilon);
-	}
-	
-	return -1.0f;
-}
-
-static __device__ float intersectPlane(float3 center, optix::Ray ray, float3 orientation, float lensRadius, float scene_epsilon){
-	using namespace optix;
-	
-	float denom = dot(orientation, ray.direction);
-	
-	if(fabs(denom) > scene_epsilon){
-		float t = dot(center - ray.origin, orientation) / denom;
-		float3 p = ray.origin + t*ray.direction;
-		return (length(p - center) <= lensRadius) * t + (length(p - center) > lensRadius) * -1.0f;
-	}
-
-	return -1.0f; 
-}
-
-static __device__ maxMinSet getAABBFromCylinder(float3 center, float3 orientation, float halfLength1, float halfLength2, float radius){
-	using namespace optix;
-	
-	float3 sideVector = normalize(cross(orientation, make_float3(0.0f, 1.0f, 0.0f)));
-	float3 newUp = normalize(cross(sideVector, orientation));
-	sideVector = sideVector * radius;
-	newUp = newUp * radius;
-	float3 depthVector = normalize(orientation);
-	
-	maxMinSet r;
-	r.min = make_float3(+10000000000); //+INFINITY
-	r.max = make_float3(-10000000000); //-INFINITY
-	float3 testVector = make_float3(0.0f);
-	
-	testVector = center + depthVector*halfLength1 + sideVector + newUp; r.max = fmaxf(r.max, testVector); r.min = fminf(r.min, testVector);
-	testVector = center + depthVector*halfLength1 + sideVector - newUp; r.max = fmaxf(r.max, testVector); r.min = fminf(r.min, testVector);
-	testVector = center + depthVector*halfLength1 - sideVector + newUp; r.max = fmaxf(r.max, testVector); r.min = fminf(r.min, testVector);
-	testVector = center + depthVector*halfLength1 - sideVector - newUp; r.max = fmaxf(r.max, testVector); r.min = fminf(r.min, testVector);
-	
-	testVector = center - depthVector*halfLength2 + sideVector + newUp; r.max = fmaxf(r.max, testVector); r.min = fminf(r.min, testVector);
-	testVector = center - depthVector*halfLength2 + sideVector - newUp; r.max = fmaxf(r.max, testVector); r.min = fminf(r.min, testVector);
-	testVector = center - depthVector*halfLength2 - sideVector + newUp; r.max = fmaxf(r.max, testVector); r.min = fminf(r.min, testVector);
-	testVector = center - depthVector*halfLength2 - sideVector - newUp; r.max = fmaxf(r.max, testVector); r.min = fminf(r.min, testVector);
-	
-	return r;
-}
-
-#endif  // OPTICAL_BENCH_LENS_INTERSECTIONS_H_
\ No newline at end of file
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/lens_parametric.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/lens_parametric.cu
deleted file mode 100644
index b85ba9fa40ba31dffb9375b7689decc9bbe39c09..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/lens_parametric.cu
+++ /dev/null
@@ -1,110 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optix_world.h>
-#include "lens_intersections.h"
-
-using namespace optix;
-
-rtDeclareVariable(float,  lensRadius, , );
-rtDeclareVariable(float3,  orientation, , );
-rtDeclareVariable(float3,  center, , );
-rtDeclareVariable(float,   radius, , );
-rtDeclareVariable(float,   radius2, , );
-rtDeclareVariable(float,   halfCylinderLength, , );
-rtDeclareVariable(float,   scene_epsilon, , );
-
-//1==convex, 2==concave, 0==plane
-rtDeclareVariable(int,   side1Type, , );
-rtDeclareVariable(int,   side2Type, , );
-
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, ); 
-rtDeclareVariable(float3, shading_normal, attribute shading_normal, );
-rtDeclareVariable(float3, front_hit_point, attribute front_hit_point, ); 
-rtDeclareVariable(float3, back_hit_point, attribute back_hit_point, );
-
-RT_PROGRAM void intersect(int primIdx)
-{
-	perHitData h1;
-	if(side1Type != 0){
-		int mult = side1Type;
-		if (side1Type == 2) mult = -1;
-
-		float dist = -sqrtf(radius*radius - powf(lensRadius,2)) + mult*halfCylinderLength;
-		float3 nCenter = center + mult *orientation*dist;
-		h1.t = circleIntersect(radius, nCenter, ray, mult*orientation, lensRadius, scene_epsilon);
-		h1.p = ray.origin + h1.t*ray.direction;
-		h1.normal = mult *(h1.p - nCenter) / radius;
-	} else{
-		h1.t = intersectPlane(center + orientation*(halfCylinderLength), ray, -orientation, lensRadius, scene_epsilon);
-		h1.p = ray.origin + h1.t*ray.direction;
-		h1.normal = orientation;
-	}	
-	
-	perHitData h2;
-	if(side2Type != 0){
-		int mult = side2Type;
-		if (side2Type == 2) mult = -1;
-		float dist = -sqrtf(radius2*radius2 - powf(lensRadius,2)) + mult *halfCylinderLength;
-		float3 nCenter = center - mult *orientation*dist;
-		h2.t = circleIntersect(radius2, nCenter, ray, -mult *orientation, lensRadius, scene_epsilon);
-		h2.p = ray.origin + h2.t*ray.direction;
-		h2.normal = mult *(h2.p - nCenter) / radius2;
-	} else{
-		h2.t = intersectPlane(center - orientation*(halfCylinderLength), ray, orientation, lensRadius, scene_epsilon);
-		h2.p = ray.origin + h2.t*ray.direction;
-		h2.normal = -orientation;
-	}
-
-	perHitData h3;
-	h3.t = cylinderIntersect(halfCylinderLength*2, center, ray, orientation, lensRadius, scene_epsilon);	
-	h3.p = ray.origin + h3.t*ray.direction;
-	float3 inner = dot(h3.p - center, orientation) * orientation + center;
-	h3.normal = normalize(h3.p - inner);
-	
-	perHitData closest = nearestButPositivHit(h1, h2, scene_epsilon);
-	closest = nearestButPositivHit(closest, h3, scene_epsilon);
-	
-	if(rtPotentialIntersection(closest.t) ) {
-		int b = (dot(closest.p - ray.origin, closest.normal) > 0.0f) * 2 - 1; //look from inside out yes == 1, no == -1
-	
-		front_hit_point = closest.p + -b * closest.normal * scene_epsilon;
-		back_hit_point = closest.p + b * closest.normal * scene_epsilon;
-		
-		shading_normal = geometric_normal = closest.normal;
-		rtReportIntersection( 0 );
-	}
-}
-
-RT_PROGRAM void bounds (int, optix::Aabb* aabb)
-{
-	//Size for double convex case should be the biggest
-	float halfSphere1 = (radius - sqrtf(radius*radius - lensRadius*lensRadius))*(side1Type == 1);
-	float halfSphere2 = (radius2 - sqrtf(radius2*radius2 - lensRadius*lensRadius))*(side2Type == 1);
-	maxMinSet res = getAABBFromCylinder(center, orientation, halfCylinderLength + halfSphere1 + scene_epsilon, halfCylinderLength + halfSphere2 + scene_epsilon, lensRadius);
-	
-	aabb->m_min = res.min;
-	aabb->m_max = res.max;
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/miss.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/miss.cu
deleted file mode 100644
index 6cc7415f2f0dd6e19d2af3f546974549241a496f..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/miss.cu
+++ /dev/null
@@ -1,33 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix_world.h>
-#include "prd.h"
-
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-RT_PROGRAM void miss_iterative()
-{
-	prd_radiance_it.origin = ray.origin + ray.direction * 1500.0f;
-	prd_radiance_it.done = true;
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/normal_shader.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/normal_shader.cu
deleted file mode 100644
index fc128891e916010c0120959a33ec54e998da1a9f..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/normal_shader.cu
+++ /dev/null
@@ -1,46 +0,0 @@
-/* 
- * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *  * Neither the name of NVIDIA CORPORATION nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 
-
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-
-
-RT_PROGRAM void closest_hit_radiance()
-{
-  prd_radiance.result = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal))*0.5f + 0.5f;
-  prd_radiance.hit_depth = hit_depth;
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/normal_shader_new.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/normal_shader_new.cu
deleted file mode 100644
index a9a74f05451de67497bd4313969bfb4837a9eb73..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/normal_shader_new.cu
+++ /dev/null
@@ -1,37 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 
-
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance, rtPayload, );
-
-RT_PROGRAM void closest_hit_radiance()
-{
-  prd_radiance.power = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal)).x * 0.5f + 0.5f;
-  prd_radiance.done = true;
-}
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/perspective_camera.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/perspective_camera.cu
deleted file mode 100644
index da7a7cb90519cbc9ceed4fb339d864ceedc77587..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/perspective_camera.cu
+++ /dev/null
@@ -1,117 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include <optixu/optixu_matrix_namespace.h>
-#include "helpers.h"
-#include "random.h"
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(Matrix4x4,     invViewProjection, , );
-rtDeclareVariable(Matrix4x4,     viewProjection, , );
-
-rtDeclareVariable(float,         scene_epsilon, , );
-rtDeclareVariable(rtObject,      top_object, , );
-
-rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
-rtDeclareVariable(uint2, launch_dim,   rtLaunchDim, );
-
-rtBuffer<float4, 2>   result_color;
-rtBuffer<float, 2>   result_depth;
-
-//Do not need to be the real far/near values, just need to be the same as in the opengl rendering
-__device__ float convertZToLinear(float depth)
-{	
-	float n = 0.1f; // camera z near
-	float f = 1000.0f; // camera z far
-	return (2.0f * n) / (f + n - depth * (f - n));	
-}
-
-RT_PROGRAM void pinhole_camera()
-{
-
-	float2 d = make_float2(launch_index) / make_float2(launch_dim);
-	float dx = d.x * 2 - 1.0f;
-	float dy = ((1.0f - d.y) - 0.5f) * 2.0f;
-
-	float4 ray_start_4 = invViewProjection * make_float4(dx, dy, 1.0f, 1.0f);
-	float4 ray_end_4 = invViewProjection * make_float4(dx, dy, 0.5f, 1.0f);
-
-	float3 ray_origin = make_float3(ray_start_4.x, ray_start_4.y, ray_start_4.z);
-	float3 ray_end = make_float3(ray_end_4.x, ray_end_4.y, ray_end_4.z);
-	
-	if (ray_start_4.w != 0)
-	{
-		ray_origin = (ray_origin / ray_start_4.w);
-	}
-	if (ray_end_4.w != 0)
-	{
-		ray_end = (ray_end / ray_end_4.w);
-	}
-
-	float3 ray_direction = normalize(ray_end - ray_origin);
-
-	optix::Ray ray(ray_origin, ray_direction, 0, scene_epsilon);
-
-	PerRayData_radiance prd;
-	prd.importance = 1.f;
-	prd.depth = 0;
-	prd.miss = 0;
-	prd.hit_depth = 900.0f;
-	prd.hit_lens = 0; //track if the ray ever hit the lens
-	prd.last_lens_id = 0;
-
-	rtTrace(top_object, ray, prd);
-	
-	float4 hitpoint = viewProjection * make_float4(ray_origin + ray_direction * prd.hit_depth, 1.0f);
-	hitpoint = hitpoint / hitpoint.w;
-
-	//unsigned char a = 255u;
-
-	//rtPrintf("miss-top: %d\n", (prd.miss));
-
-	//if (prd.miss)
-	//{
-	//	a = 0u;
-	//}
-
-	//uchar4 final_result =
-	//	make_uchar4(			
-	//		static_cast<unsigned char>(__saturatef(prd.result.x)*255.99f),  /* R */
-	//		static_cast<unsigned char>(__saturatef(prd.result.y)*255.99f),  /* G */
-	//		static_cast<unsigned char>(__saturatef(prd.result.z)*255.99f),  /* B */			
-	//		a);
-
-	float4 final_result = make_float4(
-		prd.result.x,
-		prd.result.y,
-		prd.result.z,
-		static_cast<float>(1 - prd.miss)
-	);
-
-	
-	result_color[launch_index] = final_result;
-	result_depth[launch_index] = hitpoint.z; //convertZToLinear(hitpoint.z *0.5f + 0.5f);
-}
\ No newline at end of file
diff --git a/Source/OptiX/Private/cuda/optical-bench-2020-backup/skybox.cu b/Source/OptiX/Private/cuda/optical-bench-2020-backup/skybox.cu
deleted file mode 100644
index fc4db6b2a726df5aad49b063fac78d94d6b88409..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/optical-bench-2020-backup/skybox.cu
+++ /dev/null
@@ -1,41 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix_world.h>
-#include "prd.h"
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-rtDeclareVariable(int, skybox, , );
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-rtBuffer<int> skyboxBuffer;
-
-RT_PROGRAM void skyboxLookup()
-{ 
-	//rtPrintf("hit_lens: %d\n", prd_radiance.hit_lens);
-	//rtPrintf("!hit_lens: %d\n", (!prd_radiance.hit_lens));
-
-	prd_radiance.miss = 1 - prd_radiance.hit_lens;//(prd_radiance.hit_lens == prd_radiance.hit_lens);
-	float3 temp =  make_float3(optix::rtTexCubemap<float4>(skyboxBuffer[prd_radiance.last_lens_id], ray.direction.x, ray.direction.y, ray.direction.z));  
-	//rtPrintf("miss: %d\n", (prd_radiance.miss));
-	prd_radiance.result = make_float3(temp.z, temp.y, temp.x);/* prd_radiance.hit_lens * */
-
-}
diff --git a/Source/OptiX/Private/cuda/perspective_camera.cu b/Source/OptiX/Private/cuda/perspective_camera.cu
deleted file mode 100644
index 8d67213ebe404ad7f3cbdea8ba9c639170b0fad2..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/perspective_camera.cu
+++ /dev/null
@@ -1,150 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include <optixu/optixu_matrix_namespace.h>
-#include "helpers.h"
-#include "random.h"
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(Matrix4x4,    invViewProjectionLeft, , );
-rtDeclareVariable(Matrix4x4,    viewProjectionLeft, , );
-rtDeclareVariable(Matrix4x4,	invViewProjectionRight, , );
-rtDeclareVariable(Matrix4x4,	viewProjectionRight, , );
-
-rtDeclareVariable(float,         scene_epsilon, , );
-rtDeclareVariable(int,			 is_mono, , );
-
-rtDeclareVariable(rtObject,      top_object, , );
-
-rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
-rtDeclareVariable(uint2, launch_dim,   rtLaunchDim, );
-
-rtBuffer<float4, 2>   result_color;
-rtBuffer<float, 2>   result_depth;
-
-//Do not need to be the real far/near values, just need to be the same as in the opengl rendering
-__device__ float convertZToLinear(float depth)
-{	
-	float n = 0.1f; // camera z near
-	float f = 1000.0f; // camera z far
-	return (2.0f * n) / (f + n - depth * (f - n));	
-}
-
-RT_PROGRAM void pinhole_camera()
-{
-	float2 d = make_float2(launch_index) / make_float2(launch_dim);
-	float dx = d.x * 2 - 1.0f;
-	float dy = ((1.0f - d.y) - 0.5f) * 2.0f;
-
-	// shooting two rays per pass, one for left and one for right
-
-	float4 ray_start_4_left = invViewProjectionLeft * make_float4(dx, dy, 1.0f, 1.0f);
-	float4 ray_end_4_left = invViewProjectionLeft * make_float4(dx, dy, 0.5f, 1.0f);
-
-	float3 ray_origin_left = make_float3(ray_start_4_left.x, ray_start_4_left.y, ray_start_4_left.z);
-	float3 ray_end_left = make_float3(ray_end_4_left.x, ray_end_4_left.y, ray_end_4_left.z);
-	
-	if (ray_start_4_left.w != 0)
-	{
-		ray_origin_left = (ray_origin_left / ray_start_4_left.w);
-	}
-	if (ray_end_4_left.w != 0)
-	{
-		ray_end_left = (ray_end_left / ray_end_4_left.w);
-	}
-	   	 
-	float3 ray_direction_left = normalize(ray_end_left - ray_origin_left);
-
-	optix::Ray ray_left(ray_origin_left, ray_direction_left, 0, scene_epsilon);
-
-	// Right
-
-	float4 ray_start_4_right = invViewProjectionRight * make_float4(dx, dy, 1.0f, 1.0f);
-	float4 ray_end_4_right = invViewProjectionRight * make_float4(dx, dy, 0.5f, 1.0f);
-
-	float3 ray_origin_right = make_float3(ray_start_4_right.x, ray_start_4_right.y, ray_start_4_right.z);
-	float3 ray_end_right = make_float3(ray_end_4_right.x, ray_end_4_right.y, ray_end_4_right.z);
-
-	if (ray_start_4_right.w != 0)
-	{
-		ray_origin_right = (ray_origin_right / ray_start_4_right.w);
-	}
-	if (ray_end_4_right.w != 0)
-	{
-		ray_end_right = (ray_end_right / ray_end_4_right.w);
-	}
-
-	float3 ray_direction_right = normalize(ray_end_right - ray_origin_right);
-
-	optix::Ray ray_right(ray_origin_right, ray_direction_right, 0, scene_epsilon);
-
-	PerRayData_radiance prd_left;
-	prd_left.importance = 1.f;
-	prd_left.depth = 0;
-	prd_left.hit_depth = 900.0f;
-	prd_left.flags = 0;
-	prd_left.last_lens_id = 0;
-
-	PerRayData_radiance prd_right;
-	prd_right.importance = 1.f;
-	prd_right.depth = 0;
-	prd_right.hit_depth = 900.0f;
-	prd_right.flags = 0;
-	prd_right.last_lens_id = 0;
-
-	
-	{
-		rtTrace(top_object, ray_left, prd_left);
-
-		float4 hitpoint_left = viewProjectionLeft * make_float4(ray_origin_left + ray_direction_left * prd_left.hit_depth, 1.0f);
-		hitpoint_left = hitpoint_left / hitpoint_left.w;
-	
-		result_color[launch_index] = make_float4(
-			prd_left.result.x,
-			prd_left.result.y,
-			prd_left.result.z,
-			static_cast<float>(1 - static_cast<unsigned int>(prd_left.flags & 1)) // 1 - miss
-		);
-
-		result_depth[launch_index] = hitpoint_left.z; //convertZToLinear(hitpoint.z *0.5f + 0.5f);
-	}
-	if (is_mono != 1)
-	{
-		rtTrace(top_object, ray_right, prd_right);
-
-		float4 hitpoint_right = viewProjectionRight * make_float4(ray_origin_right + ray_direction_right * prd_right.hit_depth, 1.0f);
-		hitpoint_right = hitpoint_right / hitpoint_right.w;
-
-		result_color[launch_index + make_uint2(0, launch_dim.y)] = make_float4(
-			prd_right.result.x,
-			prd_right.result.y,
-			prd_right.result.z,
-			static_cast<float>(1 - (static_cast<unsigned int>(prd_right.flags & 1))) // 1 - miss
-		);
-		result_depth[launch_index + make_uint2(0, launch_dim.y)] = hitpoint_right.z; //convertZToLinear(hitpoint.z *0.5f + 0.5f);
-
-	}
-}
\ No newline at end of file
diff --git a/Source/OptiX/Private/cuda/prd.h b/Source/OptiX/Private/cuda/prd.h
index 96d8855a9ca2675cc2e4f692221cd62fd1c70fc1..6968f60fc1913039d9868046b9e0f2d56b8e5e3c 100644
--- a/Source/OptiX/Private/cuda/prd.h
+++ b/Source/OptiX/Private/cuda/prd.h
@@ -36,15 +36,14 @@ struct PerRayData_radiance_iterative{
 };
 
 struct PerRayData_radiance{
-	float3	result;
-	float	hit_depth;
-	float	importance;
-	int		depth;
-
-	// 32 bit
-	// ... | hit_lens | miss
-	unsigned int flags;
-	int last_lens_id; // todo might need to get rid of this one
+  float3	result;
+  float		hit_depth;
+  float		importance;
+  int		depth;
+  
+  int		miss;
+  int 		hit_lens;
+  int		last_lens_id;
 };
 
 #endif  // OPTICAL_BENCH_PRD_H_
diff --git a/Source/OptiX/Private/cuda/skybox.cu b/Source/OptiX/Private/cuda/skybox.cu
deleted file mode 100644
index df15d49b30d208f7a66beee3de4d34c98b6a3939..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/skybox.cu
+++ /dev/null
@@ -1,44 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix_world.h>
-#include "prd.h"
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-rtDeclareVariable(int, skybox, , );
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-rtBuffer<int> skyboxBuffer;
-
-RT_PROGRAM void skyboxLookup()
-{ 
-	//rtPrintf("hit_lens: %d\n", prd_radiance.hit_lens);
-	//rtPrintf("!hit_lens: %d\n", (!prd_radiance.hit_lens));
-
-	unsigned int hit_lens = static_cast<unsigned int>((prd_radiance.flags >> 1));
-	//prd_radiance.miss = 1 - prd_radiance.hit_lens;//(prd_radiance.hit_lens == prd_radiance.hit_lens);
-	prd_radiance.flags = prd_radiance.flags | ( 1 - hit_lens); // miss = 1 - hit_lens
-
-	float3 temp =  make_float3(optix::rtTexCubemap<float4>(skyboxBuffer[prd_radiance.last_lens_id], ray.direction.x, ray.direction.y, ray.direction.z));  
-	//rtPrintf("miss: %d\n", (prd_radiance.miss));
-	prd_radiance.result = make_float3(temp.z, temp.y, temp.x);/* prd_radiance.hit_lens * */
-
-}
diff --git a/Source/OptiX/Private/cuda/tmp/frame_material.cu b/Source/OptiX/Private/cuda/tmp/frame_material.cu
deleted file mode 100644
index 644fe03ab14429c8c10f57b86da18eae0e74f39b..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/tmp/frame_material.cu
+++ /dev/null
@@ -1,49 +0,0 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix_world.h>
-#include "prd.h"
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
-rtTextureSampler<float4, 2> frameTexture;
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-RT_PROGRAM void closest_hit_radiance()
-{ 
-	if(texture_coord.x >= 0 && texture_coord.y >= 0){
-		prd_radiance.result = make_float3(tex2D(frameTexture, texture_coord.x, texture_coord.y)); 	
-	}else{
-		prd_radiance.result = make_float3(1.0f);
-	}
-	
-	prd_radiance.hit_depth = hit_depth;
-}
-
-RT_PROGRAM void closest_hit_iterative()
-{ 
-	float3 hit_point = ray.origin + hit_depth * ray.direction;
-	prd_radiance_it.origin = hit_point;
-	prd_radiance_it.done = true;
-}
diff --git a/Source/OptiX/Private/cuda/tmp/glass_iterative_camera.cu b/Source/OptiX/Private/cuda/tmp/glass_iterative_camera.cu
deleted file mode 100644
index e0754b8d479ae2e23a084f017888fb62c501fec4..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/tmp/glass_iterative_camera.cu
+++ /dev/null
@@ -1,76 +0,0 @@
-/* 
- * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of NVIDIA CORPORATION nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "prd.h"
-#include "random.h"
-
-using namespace optix;
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 
-rtDeclareVariable(float3, front_hit_point, attribute front_hit_point, );
-rtDeclareVariable(float3, back_hit_point, attribute back_hit_point, );
-
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-rtDeclareVariable(float, t_hit, rtIntersectionDistance, );
-
-rtDeclareVariable(int, allowTir, , );
-
-rtDeclareVariable(float, refraction_index, , );
-rtDeclareVariable(float, laserWaveLength, , );
-
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance, rtPayload, );
-
-RT_PROGRAM void closest_hit_radiance()
-{
-	prd_radiance.hit_lens = 1;
-
-	const float3 w_out = -ray.direction;
-	float3 normal = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal));
-
-	float cos_theta_i = optix::dot( w_out, normal );
-	float eta = ( cos_theta_i > 0.0f ) * refraction_index + ( cos_theta_i <= 0.0f ) * 1.0f / refraction_index;
-	normal =  ( cos_theta_i > 0.0f ) * normal + ( cos_theta_i <= 0.0f ) * -normal;
-	
-	float3 w_t;
-	const bool tir = !optix::refract( w_t, -w_out, normal, eta );
-	
-	const float3 w_in = (tir > 0) * optix::reflect( -w_out, normal ) + (tir <= 0) * w_t; 
-	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
-	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
-	
-	prd_radiance.origin = (tir > 0) * fhp + (tir <= 0) * bhp;
-	prd_radiance.direction = w_in; 
-	prd_radiance.done = !allowTir && tir;
-
- // Note: we do not trace the ray for the next bounce here, we just set it up for
- // the ray-gen program using per-ray data.
-}
-
-
diff --git a/Source/OptiX/Private/cuda/tmp/glass_perspective_camera.cu b/Source/OptiX/Private/cuda/tmp/glass_perspective_camera.cu
deleted file mode 100644
index a72b2a83229ab654dc59f952a0ed3bb7a9db8e43..0000000000000000000000000000000000000000
--- a/Source/OptiX/Private/cuda/tmp/glass_perspective_camera.cu
+++ /dev/null
@@ -1,146 +0,0 @@
-/* 
- * Copyright(c)2017 NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of NVIDIA CORPORATION nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "helpers.h"
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(rtObject, top_object, ,);
-rtDeclareVariable(float, scene_epsilon, ,);
-rtDeclareVariable(int, max_depth, ,);
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal,); 
-rtDeclareVariable(float3, front_hit_point, attribute front_hit_point,);
-rtDeclareVariable(float3, back_hit_point, attribute back_hit_point,);
-
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance,);
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay,);
-
-rtDeclareVariable(float, importance_cutoff, ,);
-rtDeclareVariable(float3, cutoff_color, ,);
-rtDeclareVariable(float, fresnel_exponent, ,);
-rtDeclareVariable(float, fresnel_minimum, ,);
-rtDeclareVariable(float, fresnel_maximum, ,);
-rtDeclareVariable(float, refraction_index, ,);
-rtDeclareVariable(int, refraction_maxdepth, ,);
-rtDeclareVariable(int, reflection_maxdepth, ,);
-rtDeclareVariable(float3, refraction_color, ,);
-rtDeclareVariable(float3, reflection_color, ,);
-rtDeclareVariable(float3, extinction_constant, ,);
-rtDeclareVariable(int, lens_id, ,);
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload,);
-
-// -----------------------------------------------------------------------------
-
-static __device__ __inline__ float3 TraceRay(float3 origin, float3 direction, int depth, float importance, float hit_depth, unsigned int flags, int last_lens_id)
-{
- optix::Ray ray = optix::make_Ray(origin, direction, 0, 0.0f, RT_DEFAULT_MAX);
- PerRayData_radiance prd;
- prd.depth = depth;
- prd.importance = importance;
- prd.hit_depth = hit_depth;
- prd.flags = flags;
- prd.last_lens_id = last_lens_id;
- 
- rtTrace(top_object, ray, prd);
- return prd.result;
-}
-
-static __device__ __inline__ float3 exp(const float3& x){
- return make_float3(exp(x.x), exp(x.y), exp(x.z));
-}
-
-// -----------------------------------------------------------------------------
-
-RT_PROGRAM void closest_hit_radiance(){
-
-	unsigned int hit_lens = (prd_radiance.flags >> 1);
-	if(hit_lens == 0) prd_radiance.hit_depth = hit_depth;
-	prd_radiance.flags = prd_radiance.flags | 2;
-	prd_radiance.last_lens_id = lens_id;
-
-	// intersection vectors
-	const float3 n = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal)); // normal
-	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
-	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
-	const float3 i = ray.direction; // incident direction
-	float3 t; // transmission direction
-	float3 r; // reflection direction
-
-	float reflection = 1.0f;
-	float3 result = make_float3(0.0f);
-
-	const int depth = prd_radiance.depth;
-
-	float3 beer_attenuation;
-	if(dot(n, ray.direction) > 0){
-		// Beer's law attenuation
-		beer_attenuation = exp(extinction_constant * (hit_depth / 100));
-	} else {
-		beer_attenuation = make_float3(1);
-	}
-
-	// refraction
-	if(depth < min(refraction_maxdepth, max_depth)){
-		if(refract(t, i, n, refraction_index)){
-			// check for external or internal reflection
-			float cos_theta = dot(i, n);
-			cos_theta = (cos_theta < 0.0f) * -cos_theta + (cos_theta >= 0.0f) * dot(t, n);
-			
-			reflection = fresnel_schlick(cos_theta, fresnel_exponent, fresnel_minimum, fresnel_maximum);
-
-			float importance = prd_radiance.importance * (1.0f-reflection) * optix::luminance(refraction_color * beer_attenuation);
-			float3 color = cutoff_color;
-			if(importance > importance_cutoff){
-				color = TraceRay(bhp, t, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
-			}
-			result +=(1.0f - reflection)* refraction_color * color;
-		}
-		// else TIR
-	} // else reflection==1 so refraction has 0 weight
-
-	// reflection
-	float3 color = cutoff_color;
-	if(depth < min(reflection_maxdepth, max_depth)){
-		r = reflect(i, n);
-
-		float importance = prd_radiance.importance * reflection * optix::luminance(reflection_color * beer_attenuation);
-		if(importance > importance_cutoff){
-			color = TraceRay(fhp, r, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
-		}
-	}
-	result += reflection * reflection_color * color;
-
-	result = result * beer_attenuation;
-
-	prd_radiance.result = result;
-}
diff --git a/Source/OptiX/Public/OptiXAcceleration.h b/Source/OptiX/Public/OptiXAcceleration.h
new file mode 100644
index 0000000000000000000000000000000000000000..eadfcc7783761f61a3a9f11faeb3a5c3f1207c13
--- /dev/null
+++ b/Source/OptiX/Public/OptiXAcceleration.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXAcceleration.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginAcceleration, Log, All);
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXAcceleration : public UObject
+{
+	GENERATED_BODY()
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::Acceleration GetNativeAcceleration()
+	{
+		return NativeAcceleration;
+	}
+
+	void SetNativeAcceleration(optix::Acceleration A)
+	{
+		NativeAcceleration = A;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void Validate();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void MarkDirty();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		bool IsDirty();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void SetProperty(FString Name, FString Value);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		FString GetProperty(FString Name);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void SetBuilder(FString Builder);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		FString GetBuilder();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void SetTraverser(FString Traverser);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		FString GetTraverser();
+
+	RTsize GetDataSize();
+	void GetData(void* Data);
+	void SetData(void* Data, RTsize Size);
+
+protected:
+
+	optix::Acceleration NativeAcceleration;
+
+};
diff --git a/Source/OptiX/Public/OptiXBuffer.h b/Source/OptiX/Public/OptiXBuffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c6bc3023b9a9476818a39841585aad7e5b41ef6
--- /dev/null
+++ b/Source/OptiX/Public/OptiXBuffer.h
@@ -0,0 +1,173 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXDeclarations.h"
+
+#include "OptiXBuffer.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginBuffer, Log, All);
+
+
+// We probably don't need such huge buffers anyway (way too slow etc), so int32 *should* be enough for everything.
+// That way, the whole thing becomes blueprint-able
+
+
+struct RTsize2
+{
+public:
+	RTsize X;
+	RTsize Y;
+};
+
+struct RTsize3
+{
+public:
+	RTsize X;
+	RTsize Y;
+	RTsize Z;
+};
+
+
+/*
+A Wrapper for the optix::Buffer class. Keep this as simple wrapper for now, 
+but it should probably be changed to allow Unreal to access the buffer data
+in a more native format.
+*/
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXBuffer : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::Buffer GetNativeBuffer()
+	{
+		return NativeBuffer;
+	}
+
+	void SetBuffer(optix::Buffer B)
+	{
+		NativeBuffer = B;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void Validate();
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetFormat(RTformat Format); // TODO Enum
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	RTformat GetFormat();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetElementSize(int32 Size);
+
+	void SetElementSizeNative(RTsize Size);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	int32 GetElementSize();
+
+	RTsize GetElementSizeNative();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void MarkDirty();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetSize1D(int32 Width);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	int32 GetSize1D();
+
+
+	void SetSize1DNative(RTsize Width);
+	RTsize GetSize1DNative();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	int32 GetMipLevelSize1D(uint8 Level);
+
+	RTsize GetMipLevelSize1DNative(uint8 Level);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetSize2D(int32 Width, int32 Height);
+	
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	FIntPoint GetSize2D();
+
+	void SetSize2DNative(RTsize Width, RTsize Height);
+	RTsize2 GetSize2DNative();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	FIntPoint GetMipLevelSize2D(uint8 Level);
+
+	RTsize2 GetMipLevelSize2DNative(uint8 Level);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetSize3D(int32 Width, int32 Height, int32 Depth);
+	FIntVector GetSize3D();
+
+	void SetSize3DNative(RTsize Width, RTsize Height, RTsize Depth);
+	RTsize3 GetSize3DNative();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	FIntVector GetMipLevelSize3D(uint8 Level);
+
+
+	RTsize3 GetMipLevelSize3DNative(uint8 Level);
+
+	// No support for more than 3 dimensions for now!
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetMipLevelCount(uint8 Count);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	uint8 GetMipLevelCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	int GetId();
+
+	// TODO: LOOK INTO WHAT THIS RETURNS AND IF WE NEED IT! RETURNS A void* ORIGINALLY
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void Map(uint8 Level = 0, uint8 MapFlags = 2);
+
+	void* MapNative(uint8 Level = 0, uint8 MapFlags = RT_BUFFER_MAP_READ_WRITE, void* UserOwned = 0);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void Unmap(uint8 Level = 0);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void BindProgressiveStream(UOptiXBuffer* Source);
+
+	void GetProgressiveUpdateReady(int* Ready, unsigned int* SubframeCount, unsigned int* MaxSubframes);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	bool GetProgressiveUpdateReady();
+
+	void GetDevicePointer(int32 OptiXDeviceOrdinal, void** DevicePointer);
+	void* GetDevicePointer(int32 OptiXDeviceOrdinal);
+
+	void SetDevicePointer(int32 OptiXDeviceOrdinal, void* DevicePointer);
+
+	bool GetProgressiveUpdateReady(unsigned int& SubframeCount);
+	bool GetProgressiveUpdateReady(unsigned int& SubframeCount, unsigned int& MaxSubframes);
+
+	void SetAttribute(RTbufferattribute Attrib, RTsize Size, void *P);
+	void GetAttribute(RTbufferattribute Attrib, RTsize Size, void *P);
+
+	FString Name; // TODO DEBUG ONLY
+
+protected:
+
+	optix::Buffer NativeBuffer;
+
+
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXCameraActor.h b/Source/OptiX/Public/OptiXCameraActor.h
index ec8765ad12865cd74ca2792018477cf7753281e8..86e5336755612e10b37aeb8a882eed6e697abb0a 100644
--- a/Source/OptiX/Public/OptiXCameraActor.h
+++ b/Source/OptiX/Public/OptiXCameraActor.h
@@ -3,7 +3,7 @@
 #include "CoreMinimal.h"
 #include "UObject/ObjectMacros.h"
 #include "Runtime/Engine/Classes/Camera/PlayerCameraManager.h"
-//#include "OptiXContext.h"
+#include "OptiXContext.h"
 #include "Runtime/Engine/Classes/Components/SceneCaptureComponent2D.h"
 #include "Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h"
 #include "Runtime/Engine/Classes/Components/SceneCaptureComponentCube.h"
diff --git a/Source/OptiX/Public/OptiXContext.h b/Source/OptiX/Public/OptiXContext.h
new file mode 100644
index 0000000000000000000000000000000000000000..03ed1f73207191de24b6d29019b082a2656227b2
--- /dev/null
+++ b/Source/OptiX/Public/OptiXContext.h
@@ -0,0 +1,451 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXGeometry.h"
+#include "OptiXGeometryInstance.h"
+#include "OptiXGeometryGroup.h"
+#include "OptiXMaterial.h"
+#include "OptiXBuffer.h"
+#include "OptiXProgram.h"
+#include "OptiXTextureSampler.h"
+#include "OptiXAcceleration.h"
+#include "OptiXTransform.h"
+#include "OptiXGroup.h"
+
+
+#include "OptiXContext.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginContext, Log, All);
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXContext : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+	// We can have a lot of functions here which can interact with OptiX. 
+	// As mentioned in the OptiXObjects file, it might be really worth to keep those in the backend (FOptiXContextInstance e.g.)
+	// The real issue is kind of the nature of the optix framework, as the variables can be completely arbitrary and dependent on the
+	// shaders. Therefore there's no fixed set of UPROPERTYs which could act as an interface.
+	// I *could* write another layer here which caches the variables in a TArray and then pushes them through, but this would require 
+	// a lot of type-magic as the variables can be any type pretty much.
+
+	// Setter Functions - apparently overloading isn't actually possible so I need to restructure EVERYTHING again
+	// Only do the important ones for now as I might need to scrap that again.
+public:
+
+	UOptiXContext(const FObjectInitializer& ObjectInitializer);
+
+	// Unreal Constructors are scary, evil and do their own magic in the background.
+	// Use Init functions for everything until one day I maybe understand what Unreal is doing exactly...
+	optix::Context Init();
+
+	virtual void BeginDestroy() override;
+
+	// Called by the rendering thread to savely update the variables that need to be updated each tick.
+	// This is mostly just going to be the transforms.
+	void UpdateVariables();
+
+	// TODO Begin play?
+
+	// TODO 
+	optix::Context GetNativeContext()
+	{
+		return NativeContext;
+	}
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void Reset();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGeometry* CreateGeometry();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXMaterial* CreateMaterial();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGeometryInstance* CreateGeometryInstance(UOptiXGeometry* Geometry, TArray<UOptiXMaterial*> Materials);
+
+	UOptiXGeometryInstance* CreateGeometryInstance(UOptiXGeometry* Geometry, UOptiXMaterial* Material);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGeometryGroup* CreateGeometryGroup();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGroup* CreateGroup();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXTransform* CreateTransform();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXAcceleration* CreateAcceleration(FString Builder);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat(FString string, float Var);
+
+	//void SetFloat2D(FString string, FVector2D Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat2D(FString string, float Var1, float Var2);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat3DVector(FString string, FVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat3D(FString string, float Var1, float Var2, float Var3);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat4DVector(FString string, FVector4 Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
+
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt(FString string, int32 Var);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	//void SetInt2D(FString string, FIntPoint Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt2D(FString string, int32 Var1, int32 Var2);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt3DVector(FString string, FIntVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//void SetInt4DVector(FString string, FIntVector4 Var);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4);
+
+	// 1D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetUint(FString string, uint8 Var);
+
+	// 2D Uint - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetUint2D(FString string, uint8 Var1, uint8 Var2);
+
+	// 3D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3);
+
+	// 4D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4);
+
+
+	// Matrices - careful Unreal uses ROW_MAJOR LAYOUT
+	// TODO They will be a pain
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetMatrix(FString string, FMatrix Matrix);
+
+
+	////
+	//// Getters (gotta love wrappers)
+	////
+
+	// Can't overload return type so this is going to be ugly
+
+	// Floats
+	// 1D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	float GetFloat(FString string);
+
+	// 2D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FVector2D GetFloat2D(FString string);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FVector GetFloat3D(FString string);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FVector4 GetFloat4D(FString string);
+
+
+	//// Ints
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetInt(FString string);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FIntPoint GetInt2D(FString string);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FIntVector GetInt3D(FString string);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//FIntVector4 GetInt4D(FString string);
+
+
+
+	//// UInts are bad
+
+	// 1D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//uint8 GetUint(FString string);
+
+	//// 2D UInt
+	//// Have to do it per reference, TODO test me
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//void GetUint2D(FString& string, uint8& Var1, uint8& Var2);
+
+	//// 3D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//void GetUint3D(FString string, uint8& Var1, uint8& Var2, uint8& Var3);
+
+	//// 4D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//FUintVector4 GetUint4D(FString string);
+
+
+	//// BUFFER FUNCTIONALITY
+
+	// A lot of those are using higher uints and ints, which is a bit iffy in blueprints.
+	// Keep the higher types as C++ functions.
+
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void Validate();
+
+	// Lots of "Create" methods now, dunno if I really want them here or in the manager
+	// - they shouldn't be needlessly exposed outside of this plugin.
+	// CreateBuffer etc
+
+	uint32 GetDeviceCount();
+	FString GetDeviceName(int32 Ordinal);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetStackSize(int32 StackSize);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetStackSize();
+
+	void SetStackSize64(uint64 StackSize);
+	uint64 GetStackSize64();
+
+	// TODO TimeoutCallback
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetEntryPointCount(int32 NumEntryPoints);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetEntryPointCount();
+
+
+	// Program wrapper needed!
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetRayGenerationProgram(int32 EntryPointIndex, UOptiXProgram* Program);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXProgram* GetRayGenerationProgram(int32 EntryPointIndex);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetExceptionProgram(int32 EntryPointIndex, UOptiXProgram* Program);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXProgram* GetExceptionProgram(int32 EntryPointIndex);
+
+	// TODO RTexception
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetExceptionEnabled(RTexception Exception, bool Enabled);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	bool GetExceptionEnabled(RTexception Exception);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetRayTypeCount(int32 NumRayTypes);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetRayTypeCount();
+
+	// TODO
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetMissProgram(int32 RayTypeIndex, UOptiXProgram* Program);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXProgram* GetMissProgram(int32 RayTypeIndex);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void Compile();
+
+	// Do not expose those for now!
+	void Launch(int32 EntryPointIndex, uint64 ImageWidth);
+	void Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight);
+	void Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight, uint64 ImageDepth);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetGeometryGroup(FString Name, UOptiXGeometryGroup* GeoGroup);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetGroup(FString Name, UOptiXGroup* Group);
+
+	// TODO: Create Program Functions
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXProgram* CreateProgramFromPTXFile(FString Path, FString Name);
+
+	// TODO: Create Buffer Functions
+
+	// General, non-blueprint buffer function
+
+	UOptiXBuffer* CreateBuffer(uint8 Type, RTformat Format, RTsize Width);
+	UOptiXBuffer* CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height );
+	UOptiXBuffer* CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height, RTsize Depth );
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferSimple(uint8 Type);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferUByte(uint8 Type);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferUByte1D(uint8 Type, int32 Width);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferUByte2D(uint8 Type, int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferUByte3D(uint8 Type, int32 Width, int32 Height, int32 Depth);
+
+	// More Buffer Functions to avoid huge enums in blueprints:
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateOutputBufferColor(int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateOutputBufferUByte3D(int32 Width, int32 Height, int32 Depth);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateOutputBufferDepth(int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateOutputBufferIntersections(int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateInputBufferFloat(int32 Width);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateInputBufferFloat2D(int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateInputBufferFloat3D(int32 Width, int32 Height, int32 Depth);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateCubemapBuffer(int32 Width, int32 Height);
+
+	// Texture Sampler
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXTextureSampler* CreateTextureSampler();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetTextureSampler(FString Name, UOptiXTextureSampler* Sampler);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetSkybox(FString Name, UOptiXTextureSampler* Sampler);
+
+	// Getters
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* GetBuffer(FString Name);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGeometryGroup* GetGeometryGroup(FString Name);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGroup* GetGroup(FString Name);
+
+	// OptiX 6.0
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetMaxTraceDepth(int32 Depth);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetMaxTraceDepth();
+
+
+
+
+
+	// TODO: ALL ABOVE FUNCTIONS ARE NOT THREAD-SAFE, DO NOT USE WHEN CALLING THEM EVERY FRAME
+	//	     USE THE CACHED ONES INSTEAD:
+
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat3DVectorThreadsafe(FString string, FVector Var);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetMatrixThreadsafe(FString string, FMatrix Matrix);
+
+// In case I use this as a base class? TODO
+private:
+
+	/*
+	Objects will not be added to the maps on creation but only on Set___().
+	As the GeometryInstance keeps a reference to the underlying set of Geometries and 
+	Materials, this should be safe from being GC'd.
+	*/
+
+
+	optix::Context NativeContext;
+
+	UPROPERTY() // Just here for now so we the objects don't ge GC'd
+	TMap<FString, UOptiXBuffer*> BufferMap;
+
+	UPROPERTY() // Just here for now so we the objects don't ge GC'd
+	TMap<FString, UOptiXMaterial*> MaterialMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXGeometry*> GeometryMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXGeometryInstance*> GeometryInstanceMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXGeometryGroup*> GeometryGroupMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXGroup*> GroupMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXTextureSampler*> TextureSamplerMap;
+
+	UPROPERTY() // Keep those here on creation so we can update their transforms.
+	TArray<UOptiXTransform*> TransformMap;
+
+	//UPROPERTY() // Just here for now so the objects don't ge GC'd
+	//TMap<FString, UOptiXProgram*> ProgramMap;
+	UPROPERTY()
+	TArray<UOptiXProgram*> RayGenerationPrograms;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TArray<UOptiXProgram*> ExceptionPrograms;	
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TArray<UOptiXProgram*> MissPrograms;
+
+	UPROPERTY()
+	TMap<FString, FVector> VectorCache;
+
+	UPROPERTY()
+	TMap<FString, FMatrix> MatrixCache;
+	// TODO:
+	// Need maps for all data types tbh
+
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXContextManager.h b/Source/OptiX/Public/OptiXContextManager.h
index 99425eb6ca407271a66aa6be5795b450bc108518..c7646b598abdeb74b0c12d5b9b4a0b3b6232c235 100644
--- a/Source/OptiX/Public/OptiXContextManager.h
+++ b/Source/OptiX/Public/OptiXContextManager.h
@@ -11,16 +11,13 @@
 #include "Materials/MaterialInstance.h"
 #include "Delegates/Delegate.h"
 
-//#include "OptiXContext.h"
-#include "OptiXIncludes.h"
-
+#include "OptiXContext.h"
 #include "OptiXObjectComponent.h"
 #include "OptiXLaserComponent.h"
 #include "OptiXLaserActor.h"
 #include "OptiXCameraActor.h"
-#include "StatsDefines.h"
 
-DECLARE_LOG_CATEGORY_EXTERN(OptiXContextManagerLog, Log, All);
+
 
 // Let's try some events!
 
@@ -38,9 +35,8 @@ DECLARE_MULTICAST_DELEGATE(FOnSceneChangedDelegate);
 #include "HideWindowsPlatformTypes.h"
 #endif
 
-/**
-* Cuda error print function. Polls the latest cuda error and logs it. 
-*/
+// print cuda error helper:
+
 inline void PrintLastCudaError(FString Msg)
 {
 	cudaError_t Err = cudaGetLastError();
@@ -49,108 +45,54 @@ inline void PrintLastCudaError(FString Msg)
 	}
 }
 
-/**
-* Struct storing the optix objects that typically form an unreal optix object component.
-*/
-struct FOptiXObjectData
-{
-	optix::Acceleration			OptiXAcceleration;
-	optix::Geometry				OptiXGeometry;
-	optix::GeometryGroup		OptiXGeometryGroup;
-	optix::GeometryInstance		OptiXGeometryInstance;
-	optix::Transform			OptiXTransform;
-	optix::Material				OptiXMaterial;
-	/**
-	* First and second program correspond to perspective and iterative trace for the optix geometry, while the third and fourth correspond to perspective and iterative
-	* programs for the optix material. Anyhit programs need to be added differently.
-	*/
-	TTuple<optix::Program, optix::Program, optix::Program, optix::Program>	OptiXPrograms;
-};
-
-/**
-* Struct storing the data needed to create an optix buffer. Used to prevent overlong constructors.
-*/
-struct FOptiXBufferData
-{
-	FString Name;
-	unsigned int Type;
-	RTformat Format;
-	RTsize BufferWidth = 0;
-	RTsize BufferHeight = 0;
-	RTsize BufferDepth = 0;
-};
-
-/**
-* Typdef for the callback function to update corresponding optix variables from a game-thread owned UObject in the scene.
-*/
-typedef TFunction<void(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)> OptiXObjectUpdateFunction;
-
-/**
-* Typdef for the callback function to update corresponding optix variables from a game-thread owned UObject in the scene. Additionally contains the RHICmdList as a parameter
-* so that textures and materials can be updated directly.
-*/
-typedef TFunction<void(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler, FRHICommandListImmediate & RHICmdList)> OptiXObjectUpdateFunctionRHI;
-
-/**
-* Typdef for the callback function to initialize optix objects from the corresponding gamethread UObject.
-*/
-typedef TFunction<void(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)> OptiXObjectInitFunction;
-
-/**
-* Typdef for the callback function to update a cubemap for a lens. Additionally contains the RHICmdList as a parameter
-* so that textures and materials can be updated directly.
-*/
-typedef TFunction<void(optix::Buffer CubemapBuffer, FRHICommandListImmediate& RHICmdList)> CubemapUpdateFunction;
-
-/**
-* Typdef for the callback function to update general optix context variables.
-*/
-typedef TFunction<void(optix::Context Context)> OptiXContextUpdateFunction;
-
-/**
-* Typdef for the callback function executed after the laser trace finished.
-*/
-typedef TFunction<void(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler, FRHICommandListImmediate & RHICmdList)> LaserTraceFinishedCallback;
-
-/**
-* Unique Id for a UObject in the scene. Used to map a UObject to a corresponding set of optix objects.
-*/
-typedef uint32 UniqueId;
-
-
-class OPTIX_API FOptiXContextUpdateManager : public FSceneViewExtensionBase
-{
-
-public:
-
-	// The auto register parameter is used to make sure this constructor is only called via the NewExtension function
-	FOptiXContextUpdateManager(const FAutoRegister& AutoRegister);
-
-	virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override;
-	virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override;
-	virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override;
-	virtual void PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override;
-	virtual void PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
-	virtual bool IsActiveThisFrame(class FViewport* InViewport) const override;
-	virtual int32 GetPriority() const override;
-
-	// ISceneViewExtension interface end
-	bool bIsActive = false;
-};
-
-
 
 class OPTIX_API FOptiXContextManager : public FSceneViewExtensionBase
 {
 
 public:
 
-	// The auto register parameter is used to make sure this constructor is only called via the NewExtension function
+	// The auto register thing is used to make sure this constructor is only called via the NewExtension function
 	FOptiXContextManager(const FAutoRegister& AutoRegister);
 
 	~FOptiXContextManager() 
 	{
-		// TODO
+		if (bIsInitialized)
+		{
+			cudaGraphicsUnregisterResource(CudaResourceDepthLeft);
+			cudaGraphicsUnregisterResource(CudaResourceDepthRight);
+			cudaGraphicsUnregisterResource(CudaResourceColorLeft);
+			cudaGraphicsUnregisterResource(CudaResourceColorRight);
+			cudaGraphicsUnregisterResource(CudaResourceIntersections);
+			cudaGraphicsUnregisterResource(CudaResourceColorOrtho);
+			cudaGraphicsUnregisterResource(CudaResourceDepthOrtho);
+
+			PrintLastCudaError("cudaGraphicsUnregisterResource");
+			cudaFree(CudaLinearMemoryDepth);
+			cudaFree(CudaLinearMemoryColor);
+			cudaFree(CudaLinearMemoryIntersections);
+			PrintLastCudaError("cudaFree");
+		}
+
+		AccelerationsToDeleteQueue.Empty();
+		BuffersToDeleteQueue.Empty();
+		GeometriesToDeleteQueue.Empty();
+		GeometryGroupToDeleteQueue.Empty();
+		GeometryInstancesToDeleteQueue.Empty();
+		GroupsToDeleteQueue.Empty();
+		MaterialsToDeleteQueue.Empty();
+		ProgramToDeleteQueue.Empty();
+		TextureSamplersToDeleteQueue.Empty();
+		TransformsToDeleteQueue.Empty();
+
+		GroupChildrenToRemoveQueue.Empty();
+		GeometryGroupChildrenToRemoveQueue.Empty();
+
+		ComponentsToInitializeQueue.Empty();
+		ComponentsToUpdateQueue.Empty();
+		CubemapComponentsToUpdateQueue.Empty();
+
+		LaserActor.Reset();
+		CameraActor.Reset();
 	}
 
 	// ISceneViewExtension interface start, called by the render thread:
@@ -163,10 +105,9 @@ public:
 	virtual void PostRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
 	virtual bool IsActiveThisFrame(class FViewport* InViewport) const override;
 	virtual void PostRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override;
-	virtual int32 GetPriority() const override;
-
 	// ISceneViewExtension interface end
 
+
 	void RenderOrthoPass();
 	
 	// Initialization methods, called by the GAME thread	
@@ -174,8 +115,17 @@ public:
 
 	void EndPlay()
 	{
-		bEndPlayReceived.AtomicSet(true);
-		Cleanup_GameThread();
+		//bEndPlay.AtomicSet(true);
+
+		//CleanupOptiXOnEnd();
+		//bCleanup.AtomicSet(true);
+		//bStartTracing.AtomicSet(false);
+		//bCleanup.AtomicSet(false);
+	}
+
+	UOptiXContext* GetOptiXContext()
+	{
+		return OptiXContext.Get();
 	}
 
 	UMaterialInstanceDynamic* GetOptiXMID() // Used to set up the post process
@@ -190,6 +140,26 @@ public:
 
 	void SceneChangedCallback();
 
+	// The OptiX context is not thread-safe, so any changes to variables/properties on the game thread 
+	// while a trace is running will lead to errors. Game thread objects push their requested updates into several queues,
+	// which then get updated just before the trace runs on the render thread.
+	// TQueue is guaranteed to be thread-safe.
+	// There is probably a better and faster way of doing this.
+
+	void RegisterOptiXComponent(IOptiXComponentInterface* Component)
+	{
+		ComponentsToInitializeQueue.Enqueue(Component);
+	}
+
+	void QueueComponentUpdate(IOptiXComponentInterface* Component)
+	{
+		ComponentsToUpdateQueue.Enqueue(Component);
+	}
+
+	void RequestCubemapUpdate(UOptiXCubemapComponent* Component)
+	{
+		CubemapComponentsToUpdateQueue.Enqueue(Component);
+	}
 
 	void SetActiveLaserActor(AOptiXLaserActor* Laser)
 	{
@@ -224,52 +194,44 @@ public:
 	{
 		WavelengthChangedEvent.Broadcast(WL);
 		//UE_LOG(LogTemp, Error, TEXT("LaserMaterialDynamic is invalid!"));
+
 	}
 
-	void ExecuteOptiXUpdate_PreLateUpdate(FRHICommandListImmediate & RHICmdList);
 
 public:
 	
-	FThreadSafeBool bEndPlayReceived = false;
-
-	FThreadSafeBool bValidCubemap = false;
-	FThreadSafeBool bIsInitializedCuda = false;
-	FThreadSafeBool bIsInitializedLaser = false;
-	FThreadSafeBool bIsInitializedAll = false;
-
+	FThreadSafeBool bStartTracing = false;
+	FThreadSafeBool bIsInitialized = false;
+	FThreadSafeBool bLaserIsInitialized = false;
 	FThreadSafeBool bSceneChanged = true;
+	FThreadSafeBool bIsTracing = false;
+	FThreadSafeBool bClearToLaunch = true;
+	FThreadSafeBool bCleanup = false;
+	FThreadSafeBool bValidCubemap = false;
 	FThreadSafeBool bRequestOrthoPass = false;
-
-	//FThreadSafeBool bStartTracing = false;
-	//FThreadSafeBool bIsInitialized = false;
-	//FThreadSafeBool bIsTracing = false;
-	//FThreadSafeBool bClearToLaunch = true;
-	//FThreadSafeBool bCleanup = false;
-	//FThreadSafeBool bRequestOrthoPass = false;
 	//FThreadSafeBool bEndPlay = false;
 
-	/**
-	* Delegate that broadcasts every time the laser trace finishes. Required to update the detector texture.
-	*/
 	FLaserTraceFinishedEvent LaserTraceFinishedEvent;
-
-	/**
-	* Delegate that broadcasts every time the wavelength changes. Required for recomputation of the refractive indices of the lenses. 
-	*/
 	FWavelengthChangedEvent WavelengthChangedEvent;
-
-	/**
-	* Delegate that broadcasts every time the scene changes, e.g. when a lens is moved. This should imply a new laser trace.
-	*/
 	FOnSceneChangedDelegate OnSceneChangedDelegate;
 
-	/**
-	* Path to the pre-compiled ptx files that contains the optix shaders.
-	*/
-	FString OptiXPTXDir;
 
+public:
 
-public:	
+	// This is so ugly but the optix api structure doesn't really allow anything more abstract.
+	TQueue<optix::Acceleration>			AccelerationsToDeleteQueue;
+	TQueue<optix::Buffer>				BuffersToDeleteQueue;
+	TQueue<optix::Geometry>				GeometriesToDeleteQueue;
+	TQueue<optix::GeometryGroup>		GeometryGroupToDeleteQueue;
+	TQueue<optix::GeometryInstance>		GeometryInstancesToDeleteQueue;
+	TQueue<optix::Group>				GroupsToDeleteQueue;
+	TQueue<optix::Material>				MaterialsToDeleteQueue;
+	TQueue<optix::Program>				ProgramToDeleteQueue;
+	TQueue<optix::TextureSampler>		TextureSamplersToDeleteQueue;
+	TQueue<optix::Transform>			TransformsToDeleteQueue;
+
+	TQueue<TPair<optix::Group, uint32>> GroupChildrenToRemoveQueue;
+	TQueue<TPair<optix::GeometryGroup, uint32>> GeometryGroupChildrenToRemoveQueue;
 
 	FMatrix OrthoMatrix;
 
@@ -280,75 +242,487 @@ private:
 	void InitPrograms();
 	void InitLaser();
 
-	void LaunchLaser(FRHICommandListImmediate & RHICmdList);
-
-	void LaunchStandardTrace(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily);
+	void LaunchLaser();
 
-	void LaunchMonoscopicTrace(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily);
+	void InitCubemap();
 
-	void CopyLaserCudaTexture(FRHICommandListImmediate & RHICmdList);
+	void InitOptiXComponents(FRHICommandListImmediate & RHICmdList)
+	{
+		// Possibly dangerous? Use limited for instead of while in case something goes wrong and we deadlock
+		for (uint32 i = 0; i < 100 && !ComponentsToInitializeQueue.IsEmpty(); i++)
+		{
+			IOptiXComponentInterface* Component;
+			if (ComponentsToInitializeQueue.Dequeue(Component))
+			{
+				Component->InitOptiXComponent(RHICmdList);				
+			}
+		}
+	}
 
-	void InitCubemap();
+	void UpdateOptiXComponentVariables()
+	{
+		for (uint32 i = 0; i < 100 && !ComponentsToUpdateQueue.IsEmpty(); i++)
+		{
+			IOptiXComponentInterface* Component;
+			if (ComponentsToUpdateQueue.Dequeue(Component))
+			{
+				if (Component != nullptr)
+				{
+					Component->UpdateOptiXComponentVariables();
+					Component->SetUpdateQueued(false);//   bUpdateQueued.AtomicSet(false);
+				}
+			}
+		}
+	}
 
-	void CleanupCuda();
+	void RemovePendingChildrenFromGroups()
+	{
+		for (uint32 i = 0; i < 100 && !GroupChildrenToRemoveQueue.IsEmpty(); i++)
+		{
+			TPair<optix::Group, uint32> Pair;
+			if (GroupChildrenToRemoveQueue.Dequeue(Pair))
+			{
+				if (Pair.Key != NULL)
+				{
+					Pair.Key->removeChild(Pair.Value); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to remove optix child in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GeometryGroupChildrenToRemoveQueue.IsEmpty(); i++)
+		{
+			TPair<optix::GeometryGroup, uint32> Pair;
+			if (GeometryGroupChildrenToRemoveQueue.Dequeue(Pair))
+			{
+				if (Pair.Key != NULL)
+				{
+					Pair.Key->removeChild(Pair.Value); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to remove optix child in queue: Object was NULL"));
+				}
+			}
+		}
+	}
 
-	void CleanupLocalOptiXObjects();
+	void DestroyOptiXObjects()
+	{
+		for (uint32 i = 0; i < 100 && !AccelerationsToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Acceleration NativeObj;
+			if (AccelerationsToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					if(NativeObj->getContext() != NULL)
+						NativeObj->destroy(); // TODO do we need to do anything else here?
+					else
+					{
+						UE_LOG(LogTemp, Warning, TEXT("Context already destroyed but somehow this buffer handle is still valid"));
+					}
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}			
+		}
+		for (uint32 i = 0; i < 100 && !BuffersToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Buffer NativeObj;
+			if (BuffersToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					try
+					{
+						NativeObj->destroy(); // TODO do we need to do anything else here?
+					}
+					catch (optix::Exception& E)
+					{
+						FString Message = FString(E.getErrorString().c_str());
+						UE_LOG(LogTemp, Error, TEXT("Trying to remove buffer: OptiX Error: %s"), *Message);
+						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+					}
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GeometriesToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Geometry NativeObj;
+			if (GeometriesToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GeometryInstancesToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::GeometryInstance NativeObj;
+			if (GeometryInstancesToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GeometryGroupToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::GeometryGroup NativeObj;
+			if (GeometryGroupToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GroupsToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Group NativeObj;
+			if (GroupsToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !MaterialsToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Material NativeObj;
+			if (MaterialsToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !ProgramToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Program NativeObj;
+			if (ProgramToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !TextureSamplersToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::TextureSampler NativeObj;
+			if (TextureSamplersToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					try
+					{
+						NativeObj->destroy(); // TODO do we need to do anything else here?
+					}
+					catch (optix::Exception& E)
+					{
+						FString Message = FString(E.getErrorString().c_str());
+						UE_LOG(LogTemp, Error, TEXT("Trying to remove texture sampler: OptiX Error: %s"), *Message);
+						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+					}
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !TransformsToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Transform NativeObj;
+			if (TransformsToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+	}
 
-	void Cleanup_RenderThread();
+	void UpdateRequestedCubemaps(FRHICommandListImmediate & RHICmdList)
+	{
+		// update only the first for now, shouldn't be more than 1 in queue anyway:
 
-	void Cleanup_GameThread();
+		if (!CubemapComponentsToUpdateQueue.IsEmpty())
+		{
+			UOptiXCubemapComponent* Comp;
+			if (CubemapComponentsToUpdateQueue.Dequeue(Comp))
+			{
+				Comp->UpdateCubemap(RHICmdList);
+			}
+		}
+	}
 
 	void UpdateCubemapBuffer(FRHICommandListImmediate & RHICmdList);
+
+	void CleanupOptiXOnEnd()
+	{
+
+		UE_LOG(LogTemp, Display, TEXT("Starting Cleanup in Context Manager"));
+
+
+		if (bIsInitialized)
+		{
+			if(CudaResourceDepthLeft != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceDepthLeft);
+			if (CudaResourceDepthRight != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceDepthRight);
+			if (CudaResourceColorLeft != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceColorLeft);
+			if(CudaResourceColorRight != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceColorRight);
+			if(CudaResourceIntersections != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceIntersections);
+			if (CudaResourceDepthOrtho != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceDepthOrtho);
+			if (CudaResourceColorOrtho != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceColorOrtho);
+			PrintLastCudaError("cudaGraphicsUnregisterResource");
+			if(CudaLinearMemoryDepth != NULL)
+				cudaFree(CudaLinearMemoryDepth);
+
+			if (CudaLinearMemoryColor != NULL)
+				cudaFree(CudaLinearMemoryColor);
+
+			if (CudaLinearMemoryIntersections != NULL)
+				cudaFree(CudaLinearMemoryIntersections);
+
+			PrintLastCudaError("cudaFree");
+		}
+
+
+
+		//check(IsInRenderingThread());
+		bStartTracing.AtomicSet(false);
+		//bEndPlay.AtomicSet(false);
+		bIsInitialized.AtomicSet(false);
+		bLaserIsInitialized.AtomicSet(false);
+		bSceneChanged.AtomicSet(true);
+		bIsTracing.AtomicSet(false);
+		bClearToLaunch.AtomicSet(true);
+		bCleanup.AtomicSet(false);
+		bValidCubemap.AtomicSet(false);
+
+		// Clear the queue
+		DestroyOptiXObjects();
+
+		if (OptiXContext.IsValid())
+		{
+			OptiXContext->RemoveFromRoot();
+		}
+		if (LaserOutputBuffer.IsValid())
+		{
+			LaserOutputBuffer->RemoveFromRoot();
+		}
+		if (OutputTexture.IsValid())
+		{
+			OutputTexture->RemoveFromRoot();
+		}
+		if (OutputTexture2.IsValid())
+		{
+			OutputTexture2->RemoveFromRoot();
+		}
+		if (DepthTexture.IsValid())
+		{
+			DepthTexture->RemoveFromRoot();
+		}
+		if (DepthTexture2.IsValid())
+		{
+			DepthTexture2->RemoveFromRoot();
+		}
+		if (CubemapSampler.IsValid())
+		{
+			CubemapSampler->RemoveFromRoot();
+		}
+		if (CubemapBuffer.IsValid())
+		{
+			CubemapBuffer->RemoveFromRoot();
+		}
+
+		OutputBuffer.Reset();
+		OutputDepthBuffer.Reset();
+
+		OutputTexture.Reset();
+		DepthTexture.Reset();
+		OutputTexture2.Reset();
+		DepthTexture2.Reset();
+		LaserIntersectionTexture.Reset();
+
+		DynamicMaterial.Reset();
+		DynamicMaterialOrtho.Reset();
+		RegularMaterial.Reset();
+		VRMaterial.Reset();
+		LaserMaterial.Reset();
+
+		LaserMaterialDynamic.Reset();		
+
+		LaserActor.Reset();
+
+		TopObject.Reset();
+		TopAcceleration.Reset();
+		OptiXContext.Reset();
+
+		if (NativeContext != NULL)
+		{
+			NativeContext->destroy();
+			NativeContext = NULL;
+		}
+
+		/*{
+			
+			OptiXContext->RemoveFromRoot();
+			LaserOutputBuffer->RemoveFromRoot();
+			OutputTexture->RemoveFromRoot();
+			OutputTexture2->RemoveFromRoot();
+			DepthTexture->RemoveFromRoot();
+			DepthTexture2->RemoveFromRoot();
+
+		
+
+			OutputBuffer.Reset();
+			OutputDepthBuffer.Reset();
+
+			OutputTexture.Reset();
+			DepthTexture.Reset();
+			OutputTexture2.Reset();
+			DepthTexture2.Reset();
+
+			DynamicMaterial.Reset();
+			RegularMaterial.Reset();
+			VRMaterial.Reset();
+
+
+			TopObject.Reset();
+			TopAcceleration.Reset();
+			OptiXContext.Reset();
+
+			if (NativeContext != NULL)
+			{
+				NativeContext->destroy();
+			}
+		}*/
+	}
+
 	
 private:
+	// OptiX Part
 
-	TSharedPtr<FOptiXContextUpdateManager, ESPMode::ThreadSafe> OptiXContextUpdateManager;
+	// Todo: refactor this to delegates maybe?
+	TQueue<IOptiXComponentInterface*> ComponentsToInitializeQueue;
+	TQueue<IOptiXComponentInterface*> ComponentsToUpdateQueue;
+	TQueue<UOptiXCubemapComponent*> CubemapComponentsToUpdateQueue;
 
 	TWeakObjectPtr<AOptiXLaserActor> LaserActor;
 
 	TWeakObjectPtr<AOptiXPlayerCameraManager> CameraActor;
 
+	// OptiX Objects to be kept in the context manager, TODO triple check that the GC doesn't nab them.
+	// Those are always required, but some should also be changeable! TODO make custom setters for them later.
+	TWeakObjectPtr<UOptiXContext> OptiXContext;
+	TWeakObjectPtr<UOptiXProgram> RayGenerationProgram;
+	TWeakObjectPtr<UOptiXProgram> MissProgram;
+	TWeakObjectPtr<UOptiXProgram> ExceptionProgram;
+
+	TWeakObjectPtr<UOptiXGroup> TopObject;
+	TWeakObjectPtr<UOptiXAcceleration> TopAcceleration;
+
+	TWeakObjectPtr<UOptiXBuffer> OutputBuffer;
+	TWeakObjectPtr<UOptiXBuffer> OutputDepthBuffer;
+
+	TWeakObjectPtr<UOptiXTextureSampler> CubemapSampler;
+	TWeakObjectPtr<UOptiXBuffer> CubemapBuffer;
+	TWeakObjectPtr<UOptiXBuffer> CubemapsInputBuffer;
+
 	TQueue<int32> UnallocatedCubemapIds;
 
 	TArray<TArray<FColor>> SurfaceDataCube;
 
-	/**
-	* Viewport width and height
-	*/
+	optix::Context NativeContext;
+
+
+	// Laser Part
+	TWeakObjectPtr<UOptiXBuffer> LaserOutputBuffer;
+	TWeakObjectPtr<UOptiXProgram> LaserRayGenerationProgram;
+	TWeakObjectPtr<UOptiXProgram> LaserMissProgram;
+	TWeakObjectPtr<UOptiXProgram> LaserExceptionProgram;
+
+
+
+	// Rendering Part
+
+	//FUpdateTextureRegion2D TextureRegion;
+
+	//UTextureCube* TextureCube;
+
 	int32 Width;
 	int32 Height;
 
-	/**
-	* Right eye color texture used for post processing. Cuda copies the optix results into this texture.
-	*/
+	FTexture2DRHIRef OutputTextureColorRightRef;
+	FTexture2DRHIRef OutputTextureColorLeftRef;
+	FTexture2DRHIRef OutputTextureDepthRightRef;
+	FTexture2DRHIRef OutputTextureDepthLeftRef;
+	
+	FTexture2DRHIRef OutputTextureColorOrthoRef;
+	FTexture2DRHIRef OutputTextureDepthOrthoRef;
+
 	TWeakObjectPtr<UTexture2D> OutputTexture;
-	/**
-	* Right eye depth texture used for post processing. Cuda copies the optix results into this texture.
-	*/
 	TWeakObjectPtr<UTexture2D> DepthTexture;
-
-	/**
-	* Left eye color texture used for post processing. Cuda copies the optix results into this texture.
-	*/
 	TWeakObjectPtr<UTexture2D> OutputTexture2;
-	/**
-	* Left eye depth texture used for post processing. Cuda copies the optix results into this texture.
-	*/
 	TWeakObjectPtr<UTexture2D> DepthTexture2;
 
-	/**
-	* Ortho pass texture used for post processing. Cuda copies the optix results into this texture.
-	* The ortho pass is used for single eye orthogonal rendering.
-	*/
 	TWeakObjectPtr<UTexture2D> OutputTextureOrtho;
 	TWeakObjectPtr<UTexture2D> DepthTextureOrtho;
 
-	/**
-	* Pointers to the post processing materials used to blend the optix results with the unreal scene.
-	*/
 	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterial;
 	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterialOrtho;
-	TWeakObjectPtr<UMaterial> MonoMaterial;
+	TWeakObjectPtr<UMaterial> RegularMaterial;
 	TWeakObjectPtr<UMaterial> VRMaterial;
 	bool bWithHMD;
 
@@ -357,13 +731,13 @@ private:
 	// Laser stuff
 	// ---------------------------------------------------------------------------------------------------
 
+	FTexture2DRHIRef LaserIntersectionTextureRef;
+
 	TWeakObjectPtr<UTexture2D> LaserIntersectionTexture;
 	TWeakObjectPtr<UMaterial> LaserMaterial;
 	TWeakObjectPtr<UMaterialInstanceDynamic> LaserMaterialDynamic;
 
 
-
-
 public:
 
 	TQueue<TPair<uint32, TArray<FVector>>> LaserIntersectionQueue;
@@ -378,6 +752,8 @@ private:
 
 	FThreadSafeBool bTracingLaser;
 
+	FCriticalSection CriticalSection;
+
 	int32 LaserMaxDepth;
 	int32 LaserEntryPoint;
 	int32 LaserBufferSize;
@@ -390,15 +766,23 @@ private:
 	// DX <-> CUDA stuff
 	// ---------------------------------------------------------------------------------------------------
 
+
+public:
+	// I'm not sure which ones I actually need
+	IDXGIAdapter			*CudaCapableAdapter = NULL;		// Adapter to use
+	ID3D11Device			*D3DDevice = NULL;				// Rendering device
+	ID3D11DeviceContext		*D3DDeviceContext = NULL;
+
+	// RTX mode
+	int RTXOn = 1;
+
+
 private:
-	/**
-	* Initialization function for Cuda. Needs to be called from the gamethread.
-	*/
+
 	void InitCUDADX();
 
-	/**
-	* Cuda graphic resources associated with the corresponding unreal textures.
-	*/
+
+	//ID3D11Texture2D* D3D11Texture;
 	cudaGraphicsResource* CudaResourceDepthLeft;
 	cudaGraphicsResource* CudaResourceDepthRight;
 	cudaGraphicsResource* CudaResourceColorLeft;
@@ -406,278 +790,11 @@ private:
 	cudaGraphicsResource* CudaResourceIntersections;
 	cudaGraphicsResource* CudaResourceColorOrtho;
 	cudaGraphicsResource* CudaResourceDepthOrtho;
-
-	/**
-	* Cuda memory allocated and used to copy the optix results into the direct x textures.
-	*/
-	float* CudaLinearMemoryDepth;
-	float4* CudaLinearMemoryColor;
+	void* CudaLinearMemoryDepth;
+	void* CudaLinearMemoryColor;
 	void* CudaLinearMemoryIntersections;
-
 	size_t Pitch; // fix me
 	size_t PitchLaser;
 
-	/**
-	* Cuda resource array used for easy mapping. Duplicate to above direct pointers.
-	*/
 	cudaGraphicsResource *Resources[7];
-
-	// Refactor stuff
-
-public:
-
-	/*
-	* Request functions used by UObjects to request the creation/destruction of the corresponding optix object.
-	* The objects are stored here as accessing them directly is not threadsafe. 
-	*/
-
-	////////////////////////////////////////////////////////////////
-	//  Request functions used by UObjects to request the creation/destruction of the corresponding optix object.
-	//	The objects are stored here as accessing them directly is not threadsafe.
-	////////////////////////////////////////////////////////////////
-
-	/**
-	* Requests a new optix::Buffer object to be created and associated with the calling object's Id. 
-	*
-	* @param ObjectId - The unique object Id this buffer should be associated with.
-	* @param BufferData - The FOptiXBufferData storing the parameters with which the buffer should be initialized.
-	*/
-	void RequestNewOptiXBuffer(UniqueId ObjectId, FOptiXBufferData BufferData);
-
-	/**
-	* Requests a new optix::Group object to be created and associated with the calling object's Id.
-	*
-	* @param ObjectId - The unique object Id this Group should be associated with.
-	* @warning Not Implemented yet!
-	*/
-	void RequestNewOptiXGroup(UniqueId ObjectId);
-
-	/**
-	* Requests a new optix::TextureSampler object to be created and associated with the calling object's Id.
-	*
-	* @param ObjectId - The unique object Id this TextureSampler should be associated with.
-	*/
-	void RequestNewOptiXTextureSampler(UniqueId ObjectId);
-
-	/**
-	* Requests the creation of a fully usable optix object used for targets and lenses. 
-	* The object consists of a optix::Geometry and optix::Material with respective perspective and iterative programs.
-	* Geometry and Material are combined in an optix::GeometryInstance which is added to a optix::GeometryGroup.
-	* A optix::Transform is created for the GeometryGroup and attached to the top object. This function only requests
-	* the creation of this object, which will then be executed on the next render thread tick.
-	*
-	* @param ObjectId - The unique object Id these objects should be associated with.
-	* @param Program - The name of the programs associated with the Geometry and Material. 
-	*/
-	void RequestNewOptiXObject(UniqueId ObjectId, FString Program);
-
-	/**
-	* Requests the destruction of all optix objects associated with the Id. 
-	*
-	* @param ObjectId - The unique object Id.
-	*/
-	void RequestDestroyOptiXObjects(UniqueId ObjectId);
-
-
-	////////////////////////////////////////////////////////////////
-	//   Enqueue functions used by UObjects to enqueue an update lambda function that is then executed by the rendering thread for threadsafety.
-	////////////////////////////////////////////////////////////////
-
-	/**
-	* Requests and enqueues an update of the cubemap for a lens. 
-	*
-	* @param ObjectId - The unique object Id for the lens which needs to be updated.
-	* @param UpdateFunction - The callback function that is called from the render thread to execute the cubemap update.
-	*/
-	void RequestLensCubemapUpdate(UniqueId ObjectId, CubemapUpdateFunction UpdateFunction);
-
-	/**
-	* Requests and enqueues the initialization of an optix object component.
-	*
-	* @param ObjectId - The unique object Id for the object component which needs to be initialized.
-	* @param InitFuntion - The callback function that is called from the render thread to execute the initialization.
-	*/
-	void EnqueueInitFunction(UniqueId ObjectId, OptiXObjectInitFunction InitFuntion);
-
-	/**
-	* Requests and enqueues the update of an optix object.
-	*
-	* @param ObjectId - The unique object Id for the object requesting the update.
-	* @param UpdateFunction - The callback function that is called from the render thread to execute the update.
-	*/
-	void EnqueueUpdateFunction(UniqueId ObjectId, OptiXObjectUpdateFunction UpdateFunction);
-
-	/**
-	* Requests and enqueues a general optix context update.
-	*
-	* @param UpdateFunction - The callback function that is called from the render thread to execute the update.
-	*/
-	void EnqueueContextUpdateFunction(OptiXContextUpdateFunction UpdateFunction);
-
-	/**
-	* Requests and enqueues the update of an optix object. The update function gets called with the RHICmdList for texture manipulation.
-	*
-	* @param ObjectId - The unique object Id for the object requesting the update.
-	* @param UpdateFunction - The callback function that is called from the render thread with the RHICmdList to execute the update.
-	*/
-	void EnqueueUpdateFunctionRHI(UniqueId ObjectId, OptiXObjectUpdateFunctionRHI UpdateFunction);
-
-	/**
-	* Registers a callback to be called each time after a laser trace has finished
-	*
-	* @param ObjectId - The unique object Id for the object registering the callback.
-	* @param Callback - The callback function that is called from the render thread with the RHICmdList and respective laser buffers.
-	*/
-	void RegisterLaserTraceCallback(UniqueId ObjectId, LaserTraceFinishedCallback Callback);
-
-	/**
-	* Updates the laser position/orientations variables that get modified by the controller late update in case the laser is attached to the motion controller
-	*
-	* @param LateUpdateTransform - The newly updated transform.
-	*/
-	void LaserPositionLateUpdate_RenderThread(const FTransform LateUpdateTransform);
-
-	/**
-	* Updates the laser position/orientations variables that get modified by the controller late update in case the laser is attached to the motion controller
-	*
-	* @param LateUpdateTransform - The newly updated transform.
-	*/
-	void ObjectPositionLateUpdate_RenderThread(UniqueId ObjectId, const FMatrix LateUpdateTransform);
-
-private:
-
-	/*
-	Creation/Destruction/Update functions that are called by the context manager if a UObject previously requested them. 
-	*/
-	void CreateNewOptiXObject(UniqueId ObjectId, FString Program);
-	void CreateNewOptiXBuffer(UniqueId ObjectId, FOptiXBufferData BufferData);
-	void CreateNewOptiXTextureSampler(UniqueId ObjectId);
-	void DestroyOptiXObjects(UniqueId ObjectId);
-
-	void ExecuteOptiXUpdate(UniqueId ObjectId, OptiXObjectUpdateFunction UpdateFunction);
-	void ExecuteOptiXUpdateRHI(UniqueId ObjectId, FRHICommandListImmediate& RHICmdList, OptiXObjectUpdateFunctionRHI UpdateFunction);
-	void ExecuteContextUpdate(OptiXContextUpdateFunction UpdateFunction);
-	   
-	void InitializeOptiXObject(UniqueId ObjectId, OptiXObjectInitFunction InitFunction);
-
-	void UpdateCubemap(UniqueId ObjectId, FRHICommandListImmediate & RHICmdList, CubemapUpdateFunction UpdateFunction);
-
-	/**
-	* Functions that parse the respective queues to see if any request has been queued by a game-thread UObject. If there are any in the queues, 
-	* the respective Creation/Destruction/Update functions are executed.
-	*/
-	void ParseCreationQueue();
-	void ParseInitQueue();
-	void ParseUpdateQueue(FRHICommandListImmediate & RHICmdList);
-	void ParseDestroyQueue();
-	void ParseCubemapUpdateQueue(FRHICommandListImmediate & RHICmdList);
-
-
-private:
-	/**
-	* Queues to guarantee thread-safety between the optix native objects and the corresponding UObjects that represent them in the unreal scene. 
-	*/
-	TQueue<UniqueId>					OptiXObjectsToDestroy;
-	TQueue<TPair<UniqueId, FString>>	OptiXObjectsToCreate;
-	TQueue<TPair<UniqueId, OptiXObjectInitFunction>> OptiXObjectInitFunctions;
-	TQueue<TPair<UniqueId, OptiXObjectUpdateFunction>>	OptiXObjectUpdateFunctions;
-	TQueue<TPair<UniqueId, OptiXObjectUpdateFunctionRHI>>	OptiXObjectUpdateFunctionsRHI;
-
-	TQueue<TPair<UniqueId, FOptiXBufferData>>	OptiXBuffersToCreate;
-	TQueue<UniqueId>	OptiXTextureSamplersToCreate;
-	TQueue<TPair<UniqueId, CubemapUpdateFunction>>	CubemapsToUpdate;
-	TQueue<OptiXContextUpdateFunction>	OptiXContextUpdateQueue;
-
-	/**
-	* Map storing callbacks that are executed as soon as the laser trace finishes.
-	* Could probably be used via delegates/events as well.
-	*/
-	TMap<UniqueId, LaserTraceFinishedCallback> LaserTraceFinishedCallbacks;
-
-
-	////////////////////////////////////////////////////////////////
-	//   OptiX API objects
-	////////////////////////////////////////////////////////////////
-
-	/**
-	* Maps which store the optix objects mapped to a unique object id as keys.
-	* Currently, multiple named buffers can be associated with one UObject, while only one group, sampler and object collection is supported.
-	*/
-	TMap<UniqueId, TMap<FString, optix::Buffer>>	OptiXBuffers;
-	TMap<UniqueId, optix::Group>					OptiXGroups;
-	TMap<UniqueId, optix::TextureSampler>			OptiXTextureSamplers;
-	TMap<UniqueId, FOptiXObjectData>				OptiXObjectData;
-
-	// Context Manager local objects
-
-	/**
-	* The optix context is the core handle on the whole optix framework. It's used to create and manipulate all other objects and
-	* is the main entry point into the optix trace.
-	*/
-	optix::Context NativeContext;
-
-	/**
-	* The ray generation program is the main optix device shader program. 
-	* It generates the rays and executes the trace, writing the result in the respective buffers.
-	*/
-	optix::Program RayGenerationProgram;
-
-	/**
-	* The miss program is executed on the device in case a ray misses any optix object. Generally, a cubemap is used to look up
-	* environment data.
-	*/
-	optix::Program MissProgram;
-
-	/**
-	* The exception program is executed when optix exceptions are enabled and is used only for debugging. Printing needs to be explicitly enabled as well
-	* to actually print the exceptions. 
-	*
-	* @warning The rtPrints executed by optix will NOT print to UE_LOG! They will be streamed to the standard cout, which requires executing the unreal executable
-	* via the command line!
-	*/
-	optix::Program ExceptionProgram;
-
-	/**
-	* The top group of the optix scenegraph. This is the group that will be traced on, so all other scene objects need to be children.
-	*/
-	optix::Group TopObject;
-
-	/**
-	* The main acceleration of the top-level scenegraph. Each group can have a custom acceleration, this is the initial acceleration structure.
-	*/
-	optix::Acceleration TopAcceleration;
-
-	/**
-	* The main output buffer for color values. OptiX writes the color result into the first 3 float components, followed by a 4th component denoting the hit value.
-	* If nothing has been hit for a given pixel, the post process material picks the unreal scene layer. 
-	*/
-	optix::Buffer OutputBuffer;
-
-	/**
-	* The main output buffer for the depth value, storing the depth as a single float per pixel.
-	*/
-	optix::Buffer OutputDepthBuffer;
-
-	// Cubemap stuff
-
-	/**
-	* ContextManager local optix buffer and sampler that handle the initial cubemap. 
-	*/
-	optix::TextureSampler	CubemapSampler;
-	optix::Buffer			CubemapBuffer;
-
-	/**
-	* optix buffer storing the texture sampler ids (integers) corresponding to a certain lens. 
-	* The number of cubemaps is limited to 10, so ids have to be recycled. The ids are used as indices to the buffer
-	* for quick and easy access in the optix shaders.
-	*/
-	optix::Buffer			CubemapsInputBuffer;
-
-
-	// Laser Part
-
-	optix::Buffer  LaserOutputBuffer;
-	optix::Program LaserRayGenerationProgram;
-	optix::Program LaserMissProgram;
-	optix::Program LaserExceptionProgram;
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXCubemapLateUpdateComponent.h b/Source/OptiX/Public/OptiXCubemapLateUpdateComponent.h
deleted file mode 100644
index f4a1c5f7f6800321d6493348205d919cc6af5132..0000000000000000000000000000000000000000
--- a/Source/OptiX/Public/OptiXCubemapLateUpdateComponent.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#pragma once
-
-#include "CoreMinimal.h"
-#include "Components/PrimitiveComponent.h"
-#include "OptiXContextManager.h"
-
-#include "OptiXCubemapLateUpdateComponent.generated.h"
-
-/**
- * Literally only here to update the lenses on applylateupdate, as the scene capture component is a USceneCompoenent and NOT 
- * a UPrimitiveComponent and can therefore not receive the lateupdate. This is incredibly annoying. 
- */
-UCLASS(Blueprintable, hidecategories = (Object), meta = (BlueprintSpawnableComponent))
-class OPTIX_API UOptiXCubemapLateUpdateComponent : public UPrimitiveComponent
-{
-	GENERATED_BODY()
-	
-public:
-
-	virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXCubemapLateUpdateComponent")
-	void LinkOptiXComponent(UOptiXCubemapComponent* OptiXComponent);
-
-	//UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXCubemapLateUpdateComponent")
-	const uint32* GetOptiXComponentId() const
-	{
-		return &OptiXComponentId;
-	}
-
-	uint32 OptiXComponentId;
-};
diff --git a/Source/OptiX/Public/OptiXDeclarations.h b/Source/OptiX/Public/OptiXDeclarations.h
new file mode 100644
index 0000000000000000000000000000000000000000..c3ce6c81399dcccd50f5f4e64ffe196da4910a84
--- /dev/null
+++ b/Source/OptiX/Public/OptiXDeclarations.h
@@ -0,0 +1,55 @@
+#pragma once
+/*
+
+See optix_declarations.h
+
+This defines the same enums as UENUMS to be used in blueprints. I hope this actually works.
+
+*/
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+//
+//
+//UENUM()
+//enum class URTformat : int32
+//{
+//	RT_FORMAT_UNKNOWN = 0x100,				/*!< Format unknown       */
+//	RT_FORMAT_FLOAT,                        /*!< Float                */
+//	RT_FORMAT_FLOAT2,                       /*!< sizeof(float)*2      */
+//	RT_FORMAT_FLOAT3,                       /*!< sizeof(float)*3      */
+//	RT_FORMAT_FLOAT4,                       /*!< sizeof(float)*4      */
+//	RT_FORMAT_BYTE,                         /*!< BYTE                 */
+//	RT_FORMAT_BYTE2,                        /*!< sizeof(CHAR)*2       */
+//	RT_FORMAT_BYTE3,                        /*!< sizeof(CHAR)*3       */
+//	RT_FORMAT_BYTE4,                        /*!< sizeof(CHAR)*4       */
+//	RT_FORMAT_UNSIGNED_BYTE,                /*!< UCHAR                */
+//	RT_FORMAT_UNSIGNED_BYTE2,               /*!< sizeof(UCHAR)*2      */
+//	RT_FORMAT_UNSIGNED_BYTE3,               /*!< sizeof(UCHAR)*3      */
+//	RT_FORMAT_UNSIGNED_BYTE4,               /*!< sizeof(UCHAR)*4      */
+//	RT_FORMAT_SHORT,                        /*!< SHORT                */
+//	RT_FORMAT_SHORT2,                       /*!< sizeof(SHORT)*2      */
+//	RT_FORMAT_SHORT3,                       /*!< sizeof(SHORT)*3      */
+//	RT_FORMAT_SHORT4,                       /*!< sizeof(SHORT)*4      */
+//	RT_FORMAT_UNSIGNED_SHORT,               /*!< USHORT               */
+//	RT_FORMAT_UNSIGNED_SHORT2,              /*!< sizeof(USHORT)*2     */
+//	RT_FORMAT_UNSIGNED_SHORT3,              /*!< sizeof(USHORT)*3     */
+//	RT_FORMAT_UNSIGNED_SHORT4,              /*!< sizeof(USHORT)*4     */
+//	RT_FORMAT_INT,                          /*!< INT                  */
+//	RT_FORMAT_INT2,                         /*!< sizeof(INT)*2        */
+//	RT_FORMAT_INT3,                         /*!< sizeof(INT)*3        */
+//	RT_FORMAT_INT4,                         /*!< sizeof(INT)*4        */
+//	RT_FORMAT_UNSIGNED_INT,                 /*!< sizeof(UINT)         */
+//	RT_FORMAT_UNSIGNED_INT2,                /*!< sizeof(UINT)*2       */
+//	RT_FORMAT_UNSIGNED_INT3,                /*!< sizeof(UINT)*3       */
+//	RT_FORMAT_UNSIGNED_INT4,                /*!< sizeof(UINT)*4       */
+//	RT_FORMAT_USER,                         /*!< User Format          */
+//	RT_FORMAT_BUFFER_ID,                    /*!< Buffer Id            */
+//	RT_FORMAT_PROGRAM_ID,                   /*!< Program Id           */
+//	RT_FORMAT_HALF,                         /*!< half float           */
+//	RT_FORMAT_HALF2,                        /*!< sizeof(half float)*2 */
+//	RT_FORMAT_HALF3,                        /*!< sizeof(half float)*3 */
+//	RT_FORMAT_HALF4                         /*!< sizeof(half float)*4 */
+//};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXGeometry.h b/Source/OptiX/Public/OptiXGeometry.h
new file mode 100644
index 0000000000000000000000000000000000000000..08d20b4ac9b726a2e81159d162949670538e0a14
--- /dev/null
+++ b/Source/OptiX/Public/OptiXGeometry.h
@@ -0,0 +1,238 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXProgram.h"
+#include "OptiXBuffer.h"
+
+#include "OptiXGeometry.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginGeometry, Log, All);
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXGeometry : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	void SetGeometry(optix::Geometry Geom)
+	{
+		NativeGeometry = Geom;
+	}
+
+	void DestroyOptiXObject();
+
+	// Setter Functions - apparently overloading isn't actually possible so I need to restructure EVERYTHING again
+	// Only do the important ones for now as I might need to scrap that again.
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat(FString string, float Var);
+
+	//void SetFloat2D(FString string, FVector2D Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat2D(FString string, float Var1, float Var2);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat3DVector(FString string, FVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat3D(FString string, float Var1, float Var2, float Var3);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat4DVector(FString string, FVector4 Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
+
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt(FString string, int32 Var);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	//void SetInt2D(FString string, FIntPoint Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt2D(FString string, int32 Var1, int32 Var2);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt3DVector(FString string, FIntVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//void SetInt4DVector(FString string, FIntVector4 Var);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4);
+
+
+
+	// 1D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetUint(FString string, uint8 Var);
+
+	// 2D Uint - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetUint2D(FString string, uint8 Var1, uint8 Var2);
+
+	// 3D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3);
+
+	// 4D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4);
+
+
+	// Matrices - careful Unreal uses ROW_MAJOR LAYOUT
+	// TODO They will be a pain
+
+	////
+	//// Getters (gotta love wrappers)
+	////
+
+	// Can't overload return type so this is going to be ugly
+
+	// Floats
+	// 1D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	float GetFloat(FString string);
+
+	// 2D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FVector2D GetFloat2D(FString string);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FVector GetFloat3D(FString string);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FVector4 GetFloat4D(FString string);
+
+
+	//// Ints
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	int32 GetInt(FString string);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FIntPoint GetInt2D(FString string);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FIntVector GetInt3D(FString string);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//FIntVector4 GetInt4D(FString string);
+
+
+
+	//// UInts are bad
+
+	// 1D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//uint8 GetUint(FString string);
+
+	//// 2D UInt
+	//// Have to do it per reference, TODO test me
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//void GetUint2D(FString& string, uint8& Var1, uint8& Var2);
+
+	//// 3D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//void GetUint3D(FString string, uint8& Var1, uint8& Var2, uint8& Var3);
+
+	//// 4D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//FUintVector4 GetUint4D(FString string);
+
+
+	// Geometry specific functions
+
+	// Sadly we still need this!
+	optix::Geometry GetNativeGeometry();
+
+	// Not sure which of those are actually needed, but let's add a few:
+	// Setters and getters are interleaved.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetPrimitiveCount(int32 NumPrimitives);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	int32 GetPrimitiveCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetPrimitiveIndexOffset(int32 IndexOffsets);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	int32 GetPrimitiveIndexOffset();
+
+
+	void SetPrimitiveCountUint(uint32 NumPrimitives);
+	uint32 GetPrimitiveCountUint();
+
+	void SetPrimitiveIndexOffsetUint(uint32 IndexOffsets);
+	uint32 GetPrimitiveIndexOffsetUint();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetMotionRange(float TimeBegin, float TimeEnd);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FVector2D GetMotionRange();
+
+	//TODO: As those two take and return two optix-specific types, either wrap those or
+	// make the whole thing only accessible through the actual optix object, as there's no real sense in wrapping this.
+	void SetMotionBorderMode(RTmotionbordermode BeginMode, RTmotionbordermode EndMode);
+	void GetMotionBorderMode(RTmotionbordermode& BeginMode, RTmotionbordermode& EndMode);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetMotionSteps(int32 N);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	int32 GetMotionSteps();
+
+
+	void SetMotionStepsUint(uint32 N);
+	uint32 GetMotionStepsUint();
+
+	// Todo: Program def. needs to be wrapped as well and made available to the blueprint editor even!
+	void SetBoundingBoxProgram(UOptiXProgram* Program);
+	UOptiXProgram* GetBoundingBoxProgram();
+
+	void SetIntersectionProgram(UOptiXProgram* Program);
+	UOptiXProgram* GetIntersectionProgram();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void MarkDirty();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	bool IsDirty();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
+
+	// In case I use this as a base class? TODO
+protected:
+
+	optix::Geometry NativeGeometry;
+	
+	UPROPERTY()
+	UOptiXProgram* IntersectionProgram;
+
+	UPROPERTY()
+	UOptiXProgram* BoundingBoxProgram;
+
+	UPROPERTY() // Just here for now so we the objects don't ge GC'd
+	TMap<FString, UOptiXBuffer*> BufferMap;
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXGeometryGroup.h b/Source/OptiX/Public/OptiXGeometryGroup.h
new file mode 100644
index 0000000000000000000000000000000000000000..4b0a13b32643c7865ab029afcc36d3ddea1fc090
--- /dev/null
+++ b/Source/OptiX/Public/OptiXGeometryGroup.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXGeometryInstance.h"
+#include "OptiXAcceleration.h"
+
+#include "OptiXGeometryGroup.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginGeometryGroup, Log, All);
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXGeometryGroup : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::GeometryGroup GetNativeGroup()
+	{
+		return NativeGeometryGroup;
+	}
+
+	void SetNativeGroup(optix::GeometryGroup Group)
+	{
+		NativeGeometryGroup = Group;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	void SetAcceleration(UOptiXAcceleration* Accel);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	UOptiXAcceleration* GetAcceleration();
+	
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	void SetChildCount(uint8 Count);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	uint8 GetChildCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	void SetChild(uint8 Index, UOptiXGeometryInstance* Child);
+
+	////// Adds the material and returns the index to the added material.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	UOptiXGeometryInstance* GetChild(uint8 Index);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	uint8 AddChild(UOptiXGeometryInstance* Child);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	uint8 RemoveChild(UOptiXGeometryInstance* Child);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	void RemoveChildByIndex(uint8 Index);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	uint8 GetChildIndex(UOptiXGeometryInstance* Child);
+
+	UPROPERTY(BlueprintReadOnly, Category = "OptiXGeometryGroup")
+	int32 ChildCount = 0;
+
+	//// TODO Check if UPROPERTY is fine with the TARRAY
+	UPROPERTY()
+	TArray<UOptiXGeometryInstance*> OptiXGeometryInstances;
+
+	UPROPERTY()
+	UOptiXAcceleration* Acceleration;
+
+protected:
+
+
+
+	optix::GeometryGroup NativeGeometryGroup;
+
+
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXGeometryInstance.h b/Source/OptiX/Public/OptiXGeometryInstance.h
new file mode 100644
index 0000000000000000000000000000000000000000..17540059b8e4472611ba717c9ff7775b972c026b
--- /dev/null
+++ b/Source/OptiX/Public/OptiXGeometryInstance.h
@@ -0,0 +1,119 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXMaterial.h"
+#include "OptiXGeometry.h"
+#include "OptiXTextureSampler.h"
+#include "OptiXBuffer.h"
+
+#include "OptiXGeometryInstance.generated.h"
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXGeometryInstance : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::GeometryInstance GetNativeInstance()
+	{
+		return NativeGeometryInstance;
+	}
+
+	void SetNativeInstance(optix::GeometryInstance Instance)
+	{
+		NativeGeometryInstance = Instance;
+	}
+
+	void DestroyOptiXObject();
+
+	// Maybe keep this but tbh we don't want to have an optix::Geometry object running around without an associated wrapper
+	//void SetNativeGeometry(Geometry Geometry);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetGeometry(UOptiXGeometry* OptiXGeometryPtr);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	UOptiXGeometry* GetGeometry();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetMaterialCount(uint8 Count);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	uint8 GetMaterialCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetMaterial(uint8 Idx, UOptiXMaterial*  Material);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	UOptiXMaterial* GetMaterial(uint8 Idx);
+
+	////// Adds the material and returns the index to the added material.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	uint8 AddMaterial(UOptiXMaterial* OptiXMaterialPtr);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat(FString string, float Var);
+
+	//void SetFloat2D(FString string, FVector2D Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat2D(FString string, float Var1, float Var2);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat3DVector(FString string, FVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat3D(FString string, float Var1, float Var2, float Var3);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat4DVector(FString string, FVector4 Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
+
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetInt(FString string, int32 Var);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	//void SetInt2D(FString string, FIntPoint Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetInt2D(FString string, int32 Var1, int32 Var2);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetInt3DVector(FString string, FIntVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetTextureSampler(FString Name, UOptiXTextureSampler* Sampler);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
+
+	UPROPERTY()
+	UOptiXGeometry* OptiXGeometry; // Maybe make this a weak obj pointer?
+
+	//// TODO Check if UPROPERTY is fine with the TARRAY
+	UPROPERTY()
+	TArray<UOptiXMaterial*> OptiXMaterials;
+
+protected:
+
+	optix::GeometryInstance NativeGeometryInstance;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXTextureSampler*> TextureSamplerMap;
+
+	UPROPERTY() // Just here for now so we the objects don't ge GC'd
+	TMap<FString, UOptiXBuffer*> BufferMap;
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXGroup.h b/Source/OptiX/Public/OptiXGroup.h
new file mode 100644
index 0000000000000000000000000000000000000000..124863fd9d4f9b4136b0d1fe85b1dae5b790b55a
--- /dev/null
+++ b/Source/OptiX/Public/OptiXGroup.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXAcceleration.h"
+#include "OptiXTransform.h"
+#include "OptiXGeometryInstance.h"
+#include "OptiXGeometryGroup.h"
+
+#include "OptiXGroup.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginGroup, Log, All);
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXGroup : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::Group GetNativeGroup()
+	{
+		return NativeGroup;
+	}
+
+	void SetNativeGroup(optix::Group Group)
+	{
+		NativeGroup = Group;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	void SetAcceleration(UOptiXAcceleration* Accel);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	UOptiXAcceleration* GetAcceleration();
+
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	void SetChildCount(uint8 Count);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	uint8 GetChildCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	void SetChild(uint8 Index, UObject* Child);
+
+	RTobjecttype GetChildType(uint8 Index);
+	
+	////// Adds the material and returns the index to the added material.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	UObject* GetChild(uint8 Index);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	uint8 AddChild(UObject* Child);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	uint8 RemoveChild(UObject* Child);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	void RemoveChildByIndex(uint8 Index);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	uint8 GetChildIndex(UObject* Child);
+
+
+	UPROPERTY(BlueprintReadOnly, Category = "OptiXGroup")
+	int32 ChildCount = 0;
+
+	// TODO Set up some nice inheritance so we don't need to use UObject here but maybe UOptiXObject
+	// or some kind of interface.
+	UPROPERTY()
+	TArray<UObject*> Children;
+
+	UPROPERTY()
+	UOptiXAcceleration* Acceleration;
+
+protected:
+
+	optix::Group NativeGroup;
+
+
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXLaserComponent.h b/Source/OptiX/Public/OptiXLaserComponent.h
index e9cb49c1a1a99d0cf3d79993586f0f7ac142324d..c8a4306927a6124bffd24b83e399f328e1e4935e 100644
--- a/Source/OptiX/Public/OptiXLaserComponent.h
+++ b/Source/OptiX/Public/OptiXLaserComponent.h
@@ -3,11 +3,10 @@
 #pragma once
 
 #include "CoreMinimal.h"
-#include "Components/PrimitiveComponent.h"
+#include "Components/SceneComponent.h"
 #include "Runtime/Engine/Classes/Engine/Texture2D.h"
-#include "PrimitiveSceneProxy.h"
 
-//#include "OptiXContext.h"
+#include "OptiXContext.h"
 
 #include "OptiXLaserComponent.generated.h"
 
@@ -23,7 +22,7 @@ enum class EPatternTypes : uint8
 
 
 UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
-class OPTIX_API UOptiXLaserComponent : public UPrimitiveComponent
+class OPTIX_API UOptiXLaserComponent : public USceneComponent
 {
 	GENERATED_BODY()
 
@@ -44,10 +43,18 @@ public:
 
 	virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
 
-	virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void CleanOptiXObjects()
+	{
+		//FOptiXModule::Get().GetOptiXContextManager()->bLaserIsInitialized.AtomicSet(true);
+
+		UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component Cleaning up")); // TODO
+	}
+
+	void UpdateOptiXContextVariables();
 
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void CleanOptiXObjects();
+	void Init();
 
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
 	void UpdateLaserPosition();
@@ -91,7 +98,10 @@ public:
 	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
 	EPatternTypes GetLaserPattern() const;
 
-public:	
+public:
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	UOptiXContext* OptiXContext;	
 
 	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
 	int32 LaserMaxDepth;
@@ -143,4 +153,8 @@ public:
 	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetLaserPattern, BlueprintSetter = SetLaserPattern) // todo
 	EPatternTypes CurrentLaserPattern;
 
+private:
+	FThreadSafeBool bUpdateQueued = true;	
+	FThreadSafeBool bPatternChanged = true;
+
 };
diff --git a/Source/OptiX/Public/OptiXLaserDetectorActor.h b/Source/OptiX/Public/OptiXLaserDetectorActor.h
index 0e69ea4cf180fc4a814299ee22ffb61a70552f8a..b272d5076dc64fd392fc618439bb0c5907eb420d 100644
--- a/Source/OptiX/Public/OptiXLaserDetectorActor.h
+++ b/Source/OptiX/Public/OptiXLaserDetectorActor.h
@@ -62,9 +62,6 @@ public:
 	UPROPERTY(BlueprintReadOnly, Category = "OptiXDetectorActor")
 	UTexture2D* DetectorResultTexture;
 
-	UPROPERTY(BlueprintReadOnly, Category = "OptiXDetectorActor")
-	UTextureRenderTarget2D* ResultRenderTarget;
-
 	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OptiXDetectorActor")
 	UMaterialInstanceDynamic* DynamicScreenMaterial;
 	
diff --git a/Source/OptiX/Public/OptiXLaserTargetComponent.h b/Source/OptiX/Public/OptiXLaserTargetComponent.h
index b59854b567c6c7ab5defca90f5b23eb82f0cd3cf..23b017674b6ec4fceefe5105f9a60f8b2997c4c2 100644
--- a/Source/OptiX/Public/OptiXLaserTargetComponent.h
+++ b/Source/OptiX/Public/OptiXLaserTargetComponent.h
@@ -4,6 +4,7 @@
 
 #include "CoreMinimal.h"
 #include "OptiXObjectComponent.h"
+#include "OptiXBuffer.h"
 #include "OptiXLaserTargetComponent.generated.h"
 
 /**
@@ -17,25 +18,53 @@ class OPTIX_API UOptiXLaserTargetComponent : public UOptiXObjectComponent
 public:
 	UOptiXLaserTargetComponent(const FObjectInitializer& ObjectInitializer);
 	
-	virtual void BeginPlay() override;
+	virtual void UpdateOptiXComponentVariables() override;
 
-	/*OptiXObjectComponent Interface End*/
+	/* OptiXObjectComponent Interface Start */
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void UpdateOptiXComponent() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGeometry() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXMaterial() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGroups() override;
 
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	//float GetMaxFromBuffer();
+	virtual void CleanOptiXComponent() override;
+	/*OptiXObjectComponent Interface End*/
 
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	//void UpdateBufferData();
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	float GetMaxFromBuffer();
 
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	void ClearOptiXBuffer();
+	void UpdateBufferData();
 
+	/* Standard Component Interface Start */
+	//virtual void BeginPlay() override;
+	//virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
+	//virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
+	/* Standard Component Interface End */
 
 public:
 
 	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OptiX")
 	bool bIsColorMode;
-	
+
+	UPROPERTY(BlueprintReadOnly, Category = "OptiX")
+	UOptiXTransform* OptiXTransform;
+
+	UPROPERTY(BlueprintReadOnly, Category = "OptiX")
+	UOptiXAcceleration* OptiXAcceleration;
+
+	UPROPERTY(BlueprintReadOnly, Category = "OptiX")
+	UOptiXBuffer* TargetBuffer;
+
+	UPROPERTY(BlueprintReadOnly, Category = "OptiX")
+	UOptiXBuffer* TargetBufferMax;
+
 	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OptiX")
 	float TargetRes;
 
diff --git a/Source/OptiX/Public/OptiXLensComponent.h b/Source/OptiX/Public/OptiXLensComponent.h
index 5ec46ec7a3ba0c7fcdd5f9d84bb4b04976d009f8..b6953a3755e871fe5d1ff673f85a0f82f0c882bf 100644
--- a/Source/OptiX/Public/OptiXLensComponent.h
+++ b/Source/OptiX/Public/OptiXLensComponent.h
@@ -41,8 +41,30 @@ public:
 
 	virtual void BeginPlay() override;
 
+	// UOptiXObjectComponent Interface Start
+
+	virtual void UpdateOptiXComponentVariables() override;
+	
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void UpdateOptiXComponent() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGeometry() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXMaterial() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGroups() override;
+
+	virtual void CleanOptiXComponent() override;
 	// UOptiXObjectComponent Interface End
 
+	virtual void InitCubemap(FRHICommandListImmediate & RHICmdList) override;
+
+	virtual void UpdateCubemap(FRHICommandListImmediate & RHICmdList) override;
+
+
 	// This sadly only works in the editor itself, leave it for now
 	//virtual void PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent) override;
 
@@ -54,9 +76,6 @@ public:
 	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
 		float GetThickness() const;
 
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		float GetThicknessForCylinderLength(float Length) const;
-
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
 		void SetRadius1(float Radius);
 	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
@@ -93,6 +112,9 @@ public:
 	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
 		float GetWavelength() const;
 
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent") // TODO
+	void MarkDirty();
+
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent") // TODO
 	TArray<FString> GetGlassDefinitionNames();
 
@@ -137,7 +159,47 @@ public:
 	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetWavelength, BlueprintSetter=SetWavelength)
 	float CurrentWavelength;
 
+
+
 	// Helper functions
 	float GetCylinderLength(float Thickness) const;
 
+private:
+
+	// Not sure if we need to even save them here.
+	UPROPERTY()
+	UOptiXTransform* OptiXTransform;
+
+	UPROPERTY()
+	UOptiXAcceleration* OptiXAcceleration;
+
+	UPROPERTY()
+	UOptiXBuffer* CubemapBuffer;
+
+	UPROPERTY()
+	UOptiXTextureSampler* CubemapSampler;
+
+	void RecalculateBoundingBox();
+
+
+
+
+	// Okay, for some crazy reason glass definitions have been originally saved here... TODOOOOO
+	//struct GlassDefinition
+	//{
+	//	FVector B;
+	//	FVector C;
+	//	GlassDefinition(FVector b, FVector c) : B(b), C(c)
+	//	{}
+	//};
+
+	//const TArray<GlassDefinition> GlassDefinitions =
+	//{
+	//	GlassDefinition(FVector(1.03961212f, 0.231792344f, 1.01046945f), FVector(0.00600069867f, 0.0200179144f, 103.560653f)),	// BK7
+	//	GlassDefinition(FVector(1.52481889f, 0.187085527f, 1.42729015f), FVector(0.011254756f, 0.0588995392f, 129.141675f)),	// SF5
+	//	GlassDefinition(FVector(1.73759695f, 0.313747346f, 1.89878101f), FVector(0.013188707f, 0.0623068142f, 155.23629f)),		// SF11
+	//	GlassDefinition(FVector(0.6961663f, 0.4079426f, 0.8974794f), FVector(0.0684043f, 0.1162414f, 9.896161f)),				// Fused S.
+	//	GlassDefinition(FVector(1.34317774f, 0.241144399f, 0.994317969f), FVector(0.00704687339f, 0.0229005f, 92.7508526f)),	// SK16
+	//	GlassDefinition(FVector(1.34533359f, 0.209073176f, 0.937357162f), FVector(0.00997743871f, 0.0470450767f, 111.886764f)),	// F2
+	//};
 };
diff --git a/Source/OptiX/Public/OptiXMaterial.h b/Source/OptiX/Public/OptiXMaterial.h
new file mode 100644
index 0000000000000000000000000000000000000000..5bbec39de26bb3faeb8bf821bdf4eee4bece5482
--- /dev/null
+++ b/Source/OptiX/Public/OptiXMaterial.h
@@ -0,0 +1,182 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXProgram.h"
+//#include "OptiXModule.h"
+
+#include "OptiXMaterial.generated.h"
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXMaterial : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	void SetMaterial(optix::Material Mat)
+	{
+		NativeMaterial = Mat;
+	}
+
+	void DestroyOptiXObject();
+
+	optix::Material GetNativeMaterial()
+	{
+		return NativeMaterial;
+	}
+	// Setter Functions - apparently overloading isn't actually possible so I need to restructure EVERYTHING again
+	// Only do the important ones for now as I might need to scrap that again.
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat(FString string, float Var);
+
+	//void SetFloat2D(FString string, FVector2D Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat2D(FString string, float Var1, float Var2);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat3DVector(FString string, FVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat3D(FString string, float Var1, float Var2, float Var3);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat4DVector(FString string, FVector4 Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
+
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt(FString string, int32 Var);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	//void SetInt2D(FString string, FIntPoint Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt2D(FString string, int32 Var1, int32 Var2);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt3DVector(FString string, FIntVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//void SetInt4DVector(FString string, FIntVector4 Var);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4);
+
+
+
+	// 1D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetUint(FString string, uint8 Var);
+
+	// 2D Uint - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetUint2D(FString string, uint8 Var1, uint8 Var2);
+
+	// 3D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3);
+
+	// 4D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4);
+
+
+	// Matrices - careful Unreal uses ROW_MAJOR LAYOUT
+	// TODO They will be a pain
+
+	////
+	//// Getters (gotta love wrappers)
+	////
+
+	// Can't overload return type so this is going to be ugly
+
+	// Floats
+	// 1D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		float GetFloat(FString string);
+
+	// 2D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FVector2D GetFloat2D(FString string);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FVector GetFloat3D(FString string);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FVector4 GetFloat4D(FString string);
+
+
+	//// Ints
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		int32 GetInt(FString string);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FIntPoint GetInt2D(FString string);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FIntVector GetInt3D(FString string);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//FIntVector4 GetInt4D(FString string);
+
+
+
+	//// UInts are bad
+
+	// 1D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//uint8 GetUint(FString string);
+
+	//// 2D UInt
+	//// Have to do it per reference, TODO test me
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//void GetUint2D(FString& string, uint8& Var1, uint8& Var2);
+
+	//// 3D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//void GetUint3D(FString string, uint8& Var1, uint8& Var2, uint8& Var3);
+
+	//// 4D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//FUintVector4 GetUint4D(FString string);
+
+
+
+
+	// Todo: Program def. needs to be wrapped as well and made available to the blueprint editor even!
+	void SetClosestHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program);
+	UOptiXProgram* GetClosestHitProgram(uint32 RayTypeIndex);
+
+	void SetAnyHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program);
+	UOptiXProgram* GetAnyHitProgram(uint32 RayTypeIndex);
+
+protected:
+
+	optix::Material NativeMaterial;
+
+	UPROPERTY()
+	TArray<UOptiXProgram*> ClosestHitPrograms;
+
+	UPROPERTY()
+	UOptiXProgram* AnyHitProgram;
+
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXModule.h b/Source/OptiX/Public/OptiXModule.h
index c0d92508e9fac58b11aa9f2c0e0d5098c664de72..cacb573a7caea71905b9f1f7000ee771b9cb0483 100644
--- a/Source/OptiX/Public/OptiXModule.h
+++ b/Source/OptiX/Public/OptiXModule.h
@@ -36,6 +36,11 @@ public:
 
 	void Init();
 
+	UOptiXContext* GetContext()
+	{
+		return GetOptiXContextManager()->GetOptiXContext();
+	}
+
 	TMap<FString, FGlassDefinition>& GetGlassDefinitions()
 	{
 		return GlassDefinitionsMap;
diff --git a/Source/OptiX/Public/OptiXMotionControllerComponent.h b/Source/OptiX/Public/OptiXMotionControllerComponent.h
deleted file mode 100644
index 8bb0156e3019e71ae054a2140c24cc85749452c2..0000000000000000000000000000000000000000
--- a/Source/OptiX/Public/OptiXMotionControllerComponent.h
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
-
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Components/PrimitiveComponent.h"
-#include "SceneViewExtension.h"
-#include "IMotionController.h"
-#include "LateUpdateManager.h"
-#include "IIdentifiableXRDevice.h" // for FXRDeviceId
-#include "OptiXMotionControllerComponent.generated.h"
-
-class FPrimitiveSceneInfo;
-class FRHICommandListImmediate;
-class FSceneView;
-class FSceneViewFamily;
-
-
-UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = MotionController)
-class OPTIX_API UOptiXMotionControllerComponent : public UPrimitiveComponent
-{
-	GENERATED_UCLASS_BODY()
-
-		void BeginDestroy() override;
-
-	/** Which player index this motion controller should automatically follow */
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintSetter = SetAssociatedPlayerIndex, Category = "MotionController")
-		int32 PlayerIndex;
-
-	/** DEPRECATED (use MotionSource instead) Which hand this component should automatically follow */
-	//UPROPERTY(BlueprintSetter = SetTrackingSource, BlueprintGetter = GetTrackingSource, Category = "MotionController")
-	//	EControllerHand Hand_DEPRECATED;
-
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintSetter = SetTrackingMotionSource, Category = "MotionController")
-		FName MotionSource;
-
-	/** If false, render transforms within the motion controller hierarchy will be updated a second time immediately before rendering. */
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MotionController")
-		uint32 bDisableLowLatencyUpdate : 1;
-
-	/** The tracking status for the device (e.g. full tracking, inertial tracking only, no tracking) */
-	UPROPERTY(BlueprintReadOnly, Category = "MotionController")
-		ETrackingStatus CurrentTrackingStatus;
-
-	void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
-
-	/** Whether or not this component had a valid tracked device this frame */
-	UFUNCTION(BlueprintPure, Category = "MotionController")
-		bool IsTracked() const
-	{
-		return bTracked;
-	}
-
-	/** Used to automatically render a model associated with the set hand. */
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintSetter = SetShowDeviceModel, Category = "Visualization")
-		bool bDisplayDeviceModel;
-
-	UFUNCTION(BlueprintSetter)
-		void SetShowDeviceModel(const bool bShowControllerModel);
-
-	/** Determines the source of the desired model. By default, the active XR system(s) will be queried and (if available) will provide a model for the associated device. NOTE: this may fail if there's no default model; use 'Custom' to specify your own. */
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintSetter = SetDisplayModelSource, Category = "Visualization", meta = (editcondition = "bDisplayDeviceModel"))
-		FName DisplayModelSource;
-
-	static FName CustomModelSourceId;
-	UFUNCTION(BlueprintSetter)
-		void SetDisplayModelSource(const FName NewDisplayModelSource);
-
-	/** A mesh override that'll be displayed attached to this MotionController. */
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, BlueprintSetter = SetCustomDisplayMesh, Category = "Visualization", meta = (editcondition = "bDisplayDeviceModel"))
-		UStaticMesh* CustomDisplayMesh;
-
-	UFUNCTION(BlueprintSetter)
-		void SetCustomDisplayMesh(UStaticMesh* NewDisplayMesh);
-
-	/** Material overrides for the specified display mesh. */
-	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Visualization", meta = (editcondition = "bDisplayDeviceModel"))
-		TArray<UMaterialInterface*> DisplayMeshMaterialOverrides;
-
-	//UFUNCTION(BlueprintSetter, meta = (DeprecatedFunction, DeprecationMessage = "Please use the Motion Source property instead of Hand"))
-	//	void SetTrackingSource(const EControllerHand NewSource);
-
-	//UFUNCTION(BlueprintGetter, meta = (DeprecatedFunction, DeprecationMessage = "Please use the Motion Source property instead of Hand"))
-	//	EControllerHand GetTrackingSource() const;
-
-	UFUNCTION(BlueprintSetter)
-		void SetTrackingMotionSource(const FName NewSource);
-
-	UFUNCTION(BlueprintSetter)
-		void SetAssociatedPlayerIndex(const int32 NewPlayer);
-
-public:
-	//~ UObject interface
-	virtual void Serialize(FArchive& Ar) override;
-
-#if WITH_EDITOR
-	virtual void PreEditChange(UProperty* PropertyAboutToChange) override;
-	virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
-#endif 
-
-public:
-	//~ UActorComponent interface
-	virtual void OnRegister() override;
-	virtual void InitializeComponent() override;
-	virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;
-
-protected:
-	//~ Begin UActorComponent Interface.
-	virtual void CreateRenderState_Concurrent() override;
-	virtual void SendRenderTransform_Concurrent() override;
-	//~ End UActorComponent Interface.
-
-	void RefreshDisplayComponent(const bool bForceDestroy = false);
-
-	// Cached Motion Controller that can be read by GetParameterValue. Only valid for the duration of OnMotionControllerUpdated
-	IMotionController* InUseMotionController;
-
-	/** Blueprint Implementable function for reponding to updated data from a motion controller (so we can use custom paramater values from it) */
-	UFUNCTION(BlueprintImplementableEvent, Category = "Motion Controller Update")
-		void OnMotionControllerUpdated();
-
-	// Returns the value of a custom parameter on the current in use Motion Controller (see member InUseMotionController). Only valid for the duration of OnMotionControllerUpdated 
-	UFUNCTION(BlueprintCallable, Category = "Motion Controller Update")
-		float GetParameterValue(FName InName, bool& bValueFound);
-
-	UFUNCTION(BlueprintCallable, Category = "Motion Controller Update")
-		FVector GetHandJointPosition(int jointIndex, bool& bValueFound);
-
-private:
-
-	/** Whether or not this component had a valid tracked controller associated with it this frame*/
-	bool bTracked;
-
-	/** Whether or not this component has authority within the frame*/
-	bool bHasAuthority;
-
-	/** If true, the Position and Orientation args will contain the most recent controller state */
-	bool PollControllerState(FVector& Position, FRotator& Orientation, float WorldToMetersScale);
-
-	FTransform RenderThreadRelativeTransform;
-	FVector RenderThreadComponentScale;
-
-	/** View extension object that can persist on the render thread without the motion controller component */
-	class FViewExtension : public FSceneViewExtensionBase
-	{
-	public:
-		FViewExtension(const FAutoRegister& AutoRegister, UOptiXMotionControllerComponent* InMotionControllerComponent);
-		virtual ~FViewExtension() {}
-
-		/** ISceneViewExtension interface */
-		virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override {}
-		virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override {}
-		virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override;
-		virtual void PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override {}
-		virtual void PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
-		virtual void PostRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
-
-		virtual int32 GetPriority() const override { return -10; }
-		virtual bool IsActiveThisFrame(class FViewport* InViewport) const;
-
-	private:
-		friend class UOptiXMotionControllerComponent;
-
-		/** Motion controller component associated with this view extension */
-		UOptiXMotionControllerComponent* MotionControllerComponent;
-		FLateUpdateManager LateUpdate;
-	};
-	TSharedPtr< FViewExtension, ESPMode::ThreadSafe > ViewExtension;
-
-	UPROPERTY(Transient, BlueprintReadOnly, Category = Visualization, meta = (AllowPrivateAccess = "true"))
-		UPrimitiveComponent* DisplayComponent;
-
-	/** Callback for asynchronous display model loads (to set materials, etc.) */
-	void OnDisplayModelLoaded(UPrimitiveComponent* DisplayComponent);
-
-	enum class EModelLoadStatus : uint8
-	{
-		Unloaded,
-		Pending,
-		InProgress,
-		Complete
-	};
-	EModelLoadStatus DisplayModelLoadState = EModelLoadStatus::Unloaded;
-
-	FXRDeviceId DisplayDeviceId;
-#if WITH_EDITOR
-	int32 PreEditMaterialCount = 0;
-#endif
-};
diff --git a/Source/OptiX/Public/OptiXObjectComponent.h b/Source/OptiX/Public/OptiXObjectComponent.h
index c03d696bf96c885c82175e776cb280ec9a08acb8..87d15c4a5020fe79a258117a8a27fd279427798b 100644
--- a/Source/OptiX/Public/OptiXObjectComponent.h
+++ b/Source/OptiX/Public/OptiXObjectComponent.h
@@ -5,8 +5,8 @@
 #include "Components/PrimitiveComponent.h"
 #include "Runtime/Engine/Classes/Components/SceneCaptureComponentCube.h"
 
-//#include "OptiXContext.h"
-//#include "OptiXComponentInterface.h"
+#include "OptiXContext.h"
+#include "OptiXComponentInterface.h"
 
 #include "OptiXObjectComponent.generated.h"
 
@@ -14,7 +14,7 @@
 // The interface is sadly useless as unreal doesn't let me do what's possible in standard c++.
 
 UCLASS(abstract) //Blueprintable, hidecategories = (Object), meta=(BlueprintSpawnableComponent)) // TODO Many things
-class OPTIX_API UOptiXObjectComponent : public UPrimitiveComponent
+class OPTIX_API UOptiXObjectComponent : public USceneComponent, public IOptiXComponentInterface
 {
 	GENERATED_BODY()
 
@@ -24,7 +24,10 @@ public:
 
 	UOptiXObjectComponent(const FObjectInitializer& ObjectInitializer);
 
-	virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
+
+	virtual void OnUnregister() override;
+
+	//virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
 
 
 	// End of UObject interface
@@ -34,16 +37,63 @@ public:
 	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
 	// End UActorComponent interface
 
-		//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	void CleanOptiXComponent();
-
 	// USceneComponent interface
 	virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	void InitOptiXComponent(FRHICommandListImmediate & RHICmdList) override;
+
+	virtual void RegisterOptiXComponent() override;
+
+	virtual void QueueOptiXContextUpdate() override;
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void CleanOptiXComponent() override;
+
+	virtual void SetUpdateQueued(bool UpdateQueued) override;
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void UpdateOptiXComponent() override {};
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGeometry() override {};
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXMaterial() override {};
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGroups() override {};
+
+	FString OptiXPTXDir;
+
+public:
+
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXContext* OptiXContext;
+
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXGeometryGroup* OptiXGeometryGroup;
+
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXGeometryInstance* OptiXGeometryInstance;
+
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXGeometry* OptiXGeometry;
+
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXMaterial* OptiXMaterial;
+
+protected:
+
+	UPROPERTY(BlueprintReadOnly)
+	bool bIsInitialized = false;
+
+	FThreadSafeBool bUpdateQueued = false;
 };
 
 
 UCLASS(abstract) //Blueprintable, hidecategories = (Object), meta=(BlueprintSpawnableComponent)) // TODO Many things
-class OPTIX_API UOptiXCubemapComponent : public USceneCaptureComponentCube
+class OPTIX_API UOptiXCubemapComponent : public USceneCaptureComponentCube, public IOptiXComponentInterface
 {
 	GENERATED_BODY()
 
@@ -53,6 +103,9 @@ public:
 
 	UOptiXCubemapComponent(const FObjectInitializer& ObjectInitializer);
 
+
+	virtual void OnUnregister() override;
+
 	// End of UObject interface
 
 	// Begin UActorComponent interface
@@ -64,13 +117,57 @@ public:
 	virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
 
 	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	void CleanOptiXComponent();	
+	void InitOptiXComponent(FRHICommandListImmediate & RHICmdList) override;
+
+
+	virtual void RegisterOptiXComponent() override;
+
+	virtual void QueueOptiXContextUpdate() override;
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void CleanOptiXComponent() override;
+
+	virtual void SetUpdateQueued(bool UpdateQueued) override;
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void UpdateOptiXComponent() override {};
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGeometry() override {};
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXMaterial() override {};
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGroups() override {};
+
+	virtual void InitCubemap(FRHICommandListImmediate & RHICmdList) {};
+	virtual void UpdateCubemap(FRHICommandListImmediate & RHICmdList) {};
 
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXCubemapComponent")
-	virtual void RequestCubemapUpdate();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	void RequestCubemapUpdate();
+
+
+	FString OptiXPTXDir;
 
 public:
 
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXContext* OptiXContext;
+
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXGeometryGroup* OptiXGeometryGroup;
+
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXGeometryInstance* OptiXGeometryInstance;
+
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXGeometry* OptiXGeometry;
+
+	UPROPERTY(BlueprintReadOnly)
+	UOptiXMaterial* OptiXMaterial;
+
 	UPROPERTY(BlueprintReadOnly)
 	int32 OptiXCubemapId;
 
@@ -80,6 +177,13 @@ public:
 	UTextureRenderTargetCube* CubeRenderTarget;
 
 	FThreadSafeBool bCubemapCaptured = false;
+
+protected:
+
+	UPROPERTY(BlueprintReadOnly)
+	bool bIsInitialized = false;
+
+	FThreadSafeBool bUpdateQueued = false;
 };
 
 
diff --git a/Source/OptiX/Public/OptiXProgram.h b/Source/OptiX/Public/OptiXProgram.h
new file mode 100644
index 0000000000000000000000000000000000000000..0530517d28778f6ab9d8688d311d9887ef58c081
--- /dev/null
+++ b/Source/OptiX/Public/OptiXProgram.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXProgram.generated.h"
+/*
+
+Simple Program wrapper, should move to own file.
+Needs some functionality!
+
+*/
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXProgram : public UObject
+{
+	GENERATED_BODY()
+public:
+
+	void SetProgram(optix::Program Prog)
+	{
+		NativeProgram = Prog;
+	}
+
+	optix::Program GetNativeProgram()
+	{
+		return NativeProgram;
+	}
+
+	virtual void BeginDestroy() override
+	{
+		UE_LOG(LogTemp, Warning, TEXT("OptiX Program BeginDestroy %s"), *this->GetFullName());
+		//DestroyOptiXObject();
+
+
+		//void UOptiXProgram::DestroyOptiXObject()
+		//{
+		//	if (NativeProgram != NULL)
+		//	{
+		//		FOptiXModule::Get().GetOptiXContextManager()->QueueNativeObjectForDestruction(NativeProgram);
+		//		//NativeProgram->destroy();
+		//	}
+
+		//	NativeProgram = NULL;
+		//}
+
+
+		Super::BeginDestroy();
+	}
+
+	//void DestroyOptiXObject();
+
+
+
+protected:
+
+	optix::Program NativeProgram;
+
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXTargetComponent.h b/Source/OptiX/Public/OptiXTargetComponent.h
index 210b499d09e6fa9c8a67b909c7d9775268e503ec..3e56c2c93fae1aaa0ca36ad3aa73dfbe5ec3a867 100644
--- a/Source/OptiX/Public/OptiXTargetComponent.h
+++ b/Source/OptiX/Public/OptiXTargetComponent.h
@@ -30,6 +30,22 @@ public:
 	UOptiXTargetComponent(const FObjectInitializer& ObjectInitializer);
 
 	virtual void BeginPlay() override;
+	
+	virtual void UpdateOptiXComponentVariables() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void UpdateOptiXComponent() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGeometry() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXMaterial() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	virtual void InitOptiXGroups() override;
+
+	virtual void CleanOptiXComponent() override;
 
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTargetComponent")
 	void SetSize(FVector NewSize);
@@ -50,6 +66,15 @@ public:
 
 private:
 
+	UPROPERTY()
+	UOptiXTransform* OptiXTransform;
+
+	UPROPERTY()
+	UOptiXAcceleration* OptiXAcceleration;
+
+	UPROPERTY()
+	UOptiXBuffer* TextureBuffer;
+
 	UPROPERTY()
 	UTexture2D* Texture;
 };
diff --git a/Source/OptiX/Public/OptiXTextureSampler.h b/Source/OptiX/Public/OptiXTextureSampler.h
new file mode 100644
index 0000000000000000000000000000000000000000..dac62c0911cb95f6687344abffca3ac19b38c39e
--- /dev/null
+++ b/Source/OptiX/Public/OptiXTextureSampler.h
@@ -0,0 +1,120 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXDeclarations.h"
+#include "OptiXBuffer.h"
+
+#include "OptiXTextureSampler.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginTextureSampler, Log, All);
+
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXTextureSampler : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::TextureSampler GetNativeTextureSampler()
+	{
+		return NativeTextureSampler;
+	}
+
+	void SetTextureSampler(optix::TextureSampler S)
+	{
+		NativeTextureSampler = S;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void Validate();
+	
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetMipLevelCount(uint8 NumMipLevels);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	uint8 GetMipLevelCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetArraySize(int32 NumTexturesInArray);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	int32 GetArraySize();
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetWrapMode(int32 Dim, RTwrapmode Wrapmode);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	RTwrapmode GetWrapMode(int32 Dim);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetFilteringModes(RTfiltermode Minification, RTfiltermode Magnification, RTfiltermode Mipmapping);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void GetFilteringModes(RTfiltermode& Minification, RTfiltermode& Magnification, RTfiltermode& Mipmapping);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetMaxAnisotropy(float Value);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	float GetMaxAnisotropy();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetMipLevelClamp(float Min, float Max);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	FVector2D GetMipLevelClamp();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetMipLevelBias(float Value);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	float GetMipLevelBias();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	int32 GetId();
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetReadMode(RTtexturereadmode Readmode);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	RTtexturereadmode GetReadMode();
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetIndexingMode(RTtextureindexmode Mode);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	RTtextureindexmode GetIndexingMode();
+
+	// Damn blueprints don't allow overloading :|
+	// TODO Look into this and how it's actually used.
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetBufferWithTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel, UOptiXBuffer* Buffer);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	UOptiXBuffer* GetBufferByTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetBuffer(UOptiXBuffer* Buffer);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	UOptiXBuffer* GetBuffer();
+
+protected:
+
+	optix::TextureSampler NativeTextureSampler;
+
+	UPROPERTY()
+	UOptiXBuffer* OptiXBuffer;
+
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXTransform.h b/Source/OptiX/Public/OptiXTransform.h
new file mode 100644
index 0000000000000000000000000000000000000000..752dc9363329ac3fc37bc95edcd66a75bc113207
--- /dev/null
+++ b/Source/OptiX/Public/OptiXTransform.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXAcceleration.h"
+#include "OptiXGeometryInstance.h"
+#include "OptiXGeometryGroup.h"
+
+#include "OptiXTransform.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginTransform, Log, All);
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXTransform : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::Transform GetNativeTransform()
+	{
+		return NativeTransform;
+	}
+
+	void SetNativeGroup(optix::Transform T)
+	{
+		NativeTransform = T;
+	}
+
+	void DestroyOptiXObject();
+
+	void UpdateTransform();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	void SetChild(UObject* Child);
+
+	RTobjecttype GetChildType();
+
+	////// Adds the material and returns the index to the added material.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	UObject* GetChild();
+
+	// Sets and caches the matrix, the rendering thread will then pass it to the optix context.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	void SetMatrix(FMatrix Matrix);
+
+	// WARNING: NOT THREADSAFE
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	void SetMatrixImmediate(FMatrix Matrix);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	FMatrix GetMatrix();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	void SetMotionRange(float TimeBegin, float TimeEnd);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	FVector2D GetMotionRange();
+
+	// MotionBorderMode TODO but who needs that even
+
+	// TODO Set up some nice inheritance so we don't need to use UObject here but maybe UOptiXObject
+	// or some kind of interface.
+	UPROPERTY()
+	UObject* OptiXChild;
+
+	UPROPERTY()
+	FMatrix TransformMatrix;
+
+protected:
+
+	optix::Transform NativeTransform;
+
+};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXVRPawn.h b/Source/OptiX/Public/OptiXVRPawn.h
index a8e181766206871d01d4e0736782a6fec4cbe6cd..111f301317b55f1c67231291c4becc9cad7591a3 100644
--- a/Source/OptiX/Public/OptiXVRPawn.h
+++ b/Source/OptiX/Public/OptiXVRPawn.h
@@ -5,8 +5,6 @@
 #include "CoreMinimal.h"
 #include "GameFramework/Pawn.h"
 #include "Components/SceneCaptureComponent2D.h"
-#include "Camera/CameraComponent.h"
-
 #include "OptiXVRPawn.generated.h"
 
 
@@ -86,8 +84,4 @@ public:
 
 	UPROPERTY(BlueprintReadWrite, EditAnywhere)
 	float Damping = 0.1f;
-
-	// Hacky but who cares, BP write into this
-	UPROPERTY(BlueprintReadWrite, EditAnywhere)
-	FVector HMDLocation;
 };
diff --git a/Source/OptiX/Public/OutlineStaticMeshComponent.h b/Source/OptiX/Public/OutlineStaticMeshComponent.h
deleted file mode 100644
index 6ae4fc366ec2bb692042b943d1e58827e7745bac..0000000000000000000000000000000000000000
--- a/Source/OptiX/Public/OutlineStaticMeshComponent.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#pragma once
-
-#include "CoreMinimal.h"
-#include "Components/StaticMeshComponent.h"
-#include "OutlineStaticMeshComponent.generated.h"
-
-/**
- * 
- */
-UCLASS(ClassGroup = (Rendering, Common), hidecategories = (Object, Activation, "Components|Activation"), ShowCategories = (Mobility), editinlinenew, meta = (BlueprintSpawnableComponent))
-class OPTIX_API UOutlineStaticMeshComponent : public UStaticMeshComponent
-{
-	GENERATED_BODY()
-
-	virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
-
-};
diff --git a/Source/OptiX/Public/SelectableActorBase.h b/Source/OptiX/Public/SelectableActorBase.h
index f31db63a006bd6a218b4f1c1732d61d5060ac7be..068d93a2ab701d56fce54fe9d74b7523d1f05bb0 100644
--- a/Source/OptiX/Public/SelectableActorBase.h
+++ b/Source/OptiX/Public/SelectableActorBase.h
@@ -3,20 +3,17 @@
 #pragma once
 
 #include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
 #include "Engine/StaticMeshActor.h"
-#include "GameFramework/Actor.h"
-
 #include "Components/WidgetComponent.h"
-#include "OptiXVRPawn.h"
+
 
 #include "SelectableActorBase.generated.h"
 
 /**
  * 
  */
-UCLASS(hidecategories = (Input), showcategories = ("Input|MouseInput", "Input|TouchInput"), ConversionRoot, ComponentWrapperClass, meta = (ChildCanTick))
-class OPTIX_API ASelectableActorBase : public AActor
+UCLASS()
+class OPTIX_API ASelectableActorBase : public AStaticMeshActor
 {
 	GENERATED_BODY()
 
@@ -27,15 +24,6 @@ public:
 	virtual void BeginPlay() override;
 	virtual void Tick(float DeltaTime) override;
 
-	virtual void Serialize(FArchive& Ar) override;
-
-	/** Returns StaticMeshComponent subobject **/
-	class UStaticMeshComponent* GetStaticMeshComponent() const { return StaticMeshComponent; }
-
-	/** Function to change mobility type */
-	UFUNCTION(BlueprintCallable, Category = Mobility)
-	void SetMobility(EComponentMobility::Type InMobility);
-
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXActor")
 	void SetScaleV(FRotator Rot);
 	
@@ -75,10 +63,9 @@ public:
 	UFUNCTION(BlueprintNativeEvent)
 	void OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
 
-public:
 
-	UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
-	AOptiXVRPawn* OptiXVRPawn;
+
+public:
 
 	UPROPERTY(BlueprintReadWrite, EditAnywhere)
 	USceneComponent* Gizmo;
@@ -154,16 +141,4 @@ public:
 
 	UPROPERTY(BlueprintReadWrite, EditAnywhere)
 	UStaticMeshComponent* Socket;
-
-private:
-	UPROPERTY(Category = StaticMeshActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Mesh,Rendering,Physics,Components|StaticMesh", AllowPrivateAccess = "true"))
-	class UStaticMeshComponent* StaticMeshComponent;
-
-
-protected:
-
-	//~ Begin UObject Interface.
-	virtual FString GetDetailedInfoInternal() const override;
-
-
 };
diff --git a/Source/OptiX/Public/StatsDefines.h b/Source/OptiX/Public/StatsDefines.h
deleted file mode 100644
index 04a54c3e11327d8ac475eb592d6527f98b802c18..0000000000000000000000000000000000000000
--- a/Source/OptiX/Public/StatsDefines.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#pragma once
-#ifndef TRACE_CPUPROFILER_EVENT_SCOPE
-	#define TRACE_CPUPROFILER_EVENT_SCOPE(Name)
-#endif
\ No newline at end of file
diff --git a/Source/ThirdParty/OptiXLibrary/OptiXLibrary.Build.cs b/Source/ThirdParty/OptiXLibrary/OptiXLibrary.Build.cs
index 71536edf23542ad3bc8897eb7bbe65b5da8e5545..bb2277699bdc28c5a81305d90551220fa139c30d 100644
--- a/Source/ThirdParty/OptiXLibrary/OptiXLibrary.Build.cs
+++ b/Source/ThirdParty/OptiXLibrary/OptiXLibrary.Build.cs
@@ -40,6 +40,25 @@ public class OptiXLibrary : ModuleRules
 
             PublicDefinitions.Add("NOMINMAX");
 
+            // OptiX
+            //PublicLibraryPaths.Add(BaseLibDir + "/win64-old");
+            //PublicAdditionalLibraries.Add("optix.51.lib");
+            //PublicDelayLoadDLLs.Add("optix.51.dll");
+
+            //// OptiX Prime
+            //PublicLibraryPaths.Add(BaseLibDir + "/win64-old");
+            //PublicAdditionalLibraries.Add("optix_prime.1.lib");
+            //PublicDelayLoadDLLs.Add("optix_prime.1.dll");
+
+            //// OptiXU
+
+            //PublicLibraryPaths.Add(BaseLibDir + "/win64-old");
+            //PublicAdditionalLibraries.Add("optixu.1.lib");
+            //PublicDelayLoadDLLs.Add("optixu.1.dll");
+
+
+
+
             //// OptiX
             PublicLibraryPaths.Add(BaseLibDir + "/win64");
             PublicAdditionalLibraries.Add("optix.6.5.0.lib");