diff --git a/Content/Blueprints/TeleportControllerBP.uasset b/Content/Blueprints/TeleportControllerBP.uasset
index f7deaf6c057a530dd037b9592afd28725eafde2e..a2296b49b8034c87edd3151b99b69ce104b8bbca 100644
Binary files a/Content/Blueprints/TeleportControllerBP.uasset and b/Content/Blueprints/TeleportControllerBP.uasset differ
diff --git a/Content/PPMaterials/TextureMaterialVR.uasset b/Content/PPMaterials/TextureMaterialVR.uasset
index aef62a489091f6f6a400336c022374b8a42808b2..9ecd3c4d36e382ab28692683a948638a3dfcd3c1 100644
Binary files a/Content/PPMaterials/TextureMaterialVR.uasset and b/Content/PPMaterials/TextureMaterialVR.uasset differ
diff --git a/OptiX.uplugin b/OptiX.uplugin
index 98eb11e3ed7c8108ecc6fe27b7bb0285db847ceb..f2c4ea5136eb1254aef580365be83b1dd66ab894 100644
--- a/OptiX.uplugin
+++ b/OptiX.uplugin
@@ -1,36 +1,36 @@
-{
-  "FileVersion": 3,
-  "Version": 1,
-  "VersionName": "1.0",
-  "FriendlyName": "OptiX",
-  "Description": "",
-  "Category": "Other",
-  "CreatedBy": "",
-  "CreatedByURL": "",
-  "DocsURL": "",
-  "MarketplaceURL": "",
-  "SupportURL": "",
-  "CanContainContent": true,
-  "IsBetaVersion": false,
-  "Installed": false,
-  "EnabledByDefault": true,
-
-  "Modules": [
-    {
-      "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"
-    ]
-  }
+{
+  "FileVersion": 3,
+  "Version": 1,
+  "VersionName": "1.0",
+  "FriendlyName": "OptiX",
+  "Description": "",
+  "Category": "Other",
+  "CreatedBy": "",
+  "CreatedByURL": "",
+  "DocsURL": "",
+  "MarketplaceURL": "",
+  "SupportURL": "",
+  "CanContainContent": true,
+  "IsBetaVersion": false,
+  "Installed": false,
+  "EnabledByDefault": true,
+
+  "Modules": [
+    {
+      "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 2769424749469ba63b9229ee616d7536ebe7d9b5..1cd1fc5737369172e3e9ab6f2e59e975b1d2168d 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;
 
-        Definitions.Add("MALLOC_LEAKDETECTION=0");
+        PublicDefinitions.Add("MALLOC_LEAKDETECTION=0");
 
 
         PublicIncludePaths.AddRange(
@@ -47,6 +47,8 @@ public class OptiX : ModuleRules
                 "UMG",
                 "Slate",
                 "SlateCore",
+                "D3D11RHI"
+
             }
             );
         PrivateDependencyModuleNames.AddRange(
@@ -62,7 +64,8 @@ public class OptiX : ModuleRules
                 "Json",
                 "JsonUtilities",
                 "RenderCore",
-                "RHI"
+                "RHI",
+                "D3D11RHI"
             }
             );
 
diff --git a/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp b/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp
index 76182e18793a9c6f793af47421cb076b5d7c798d..c37398ba938365e27240162b3346cbcd19e9dfb6 100644
--- a/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp
+++ b/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp
@@ -1,6 +1,5 @@
 // Fill out your copyright notice in the Description page of Project Settings.
 
-
 #include "LineInstancedStaticMeshComponent.h"
 
 #include "Components/InstancedStaticMeshComponent.h"
@@ -14,6 +13,9 @@
 #include "OptiXModule.h"
 #include "OptiXContextManager.h"
 
+#include "StatsDefines.h"
+
+
 
 ULineInstancedStaticMeshComponent::ULineInstancedStaticMeshComponent(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -45,6 +47,7 @@ void ULineInstancedStaticMeshComponent::BeginPlay()
 
 FPrimitiveSceneProxy* ULineInstancedStaticMeshComponent::CreateSceneProxy()
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ULineInstancedStaticMeshComponent::CreateSceneProxy"))
 
 
 	FPrimitiveSceneProxy* Proxy = Super::CreateSceneProxy();
@@ -82,6 +85,7 @@ 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();
 	
@@ -138,7 +142,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);
 
@@ -149,6 +153,8 @@ 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++)
@@ -175,6 +181,8 @@ void ULineInstancedStaticMeshComponent::UpdateLines()
 
 void  ULineInstancedStaticMeshComponent::UpdateLUT(TArray<FColor> ColorMap)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ULineInstancedStaticMeshComponent::UpdateLUT"))
+
 	if (DynamicLaserMaterial != NULL)
 	{
 
@@ -197,6 +205,8 @@ 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/OptiXCameraActor.cpp b/Source/OptiX/Private/OptiXCameraActor.cpp
index 2a9af01de3f908c477ab47d8f37892e855a58fd5..fb472b14bafe6679d0e6dd6869c27ecf2488a929 100644
--- a/Source/OptiX/Private/OptiXCameraActor.cpp
+++ b/Source/OptiX/Private/OptiXCameraActor.cpp
@@ -28,6 +28,8 @@
 
 #include "Runtime/Engine/Classes/Camera/CameraActor.h"
 
+#include "StatsDefines.h"
+
 
 DEFINE_LOG_CATEGORY(OptiXPluginCameraActor);
 
@@ -129,6 +131,8 @@ 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)
 	{
@@ -155,6 +159,7 @@ 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
index 20e2a2eeee7adbfb10284279ff0900fcb537ba45..92b7a3a423b62c86b25c8e22b9d1622ec1920e1e 100644
--- a/Source/OptiX/Private/OptiXContext.cpp
+++ b/Source/OptiX/Private/OptiXContext.cpp
@@ -8,6 +8,9 @@
 #include <EngineGlobals.h>
 #include <Runtime/Engine/Classes/Engine/Engine.h>
 
+#include "StatsDefines.h"
+
+
 DEFINE_LOG_CATEGORY(OptiXPluginContext);
 
 
@@ -35,6 +38,8 @@ optix::Context UOptiXContext::Init()
 
 void UOptiXContext::UpdateVariables()
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::UpdateVariables"))
+
 	check(IsInRenderingThread());
 
 	for (UOptiXTransform* T : TransformMap)
@@ -901,22 +906,10 @@ UOptiXProgram* UOptiXContext::GetMissProgram(int32 RayTypeIndex)
 	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)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::Launch1D"))
+
 	try
 	{
 		NativeContext->launch(EntryPointIndex, ImageWidth);
@@ -932,6 +925,7 @@ void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth)
 void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight)
 {
 	//UE_LOG(OptiXPluginContext, Warning, TEXT("Child count: %i"), GeometryGroupMap["top_object"]->GetChildCount());
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::Launch2D"))
 
 	try
 	{
@@ -947,6 +941,8 @@ void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 Imag
 
 void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight, uint64 ImageDepth)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::Launch3D"))
+
 	try
 	{
 		NativeContext->launch(EntryPointIndex, ImageWidth, ImageHeight, ImageDepth);
diff --git a/Source/OptiX/Private/OptiXContextManager.cpp b/Source/OptiX/Private/OptiXContextManager.cpp
index 5711237b20fd77f266d534d9158e0db1ade96a97..e6046a7a90227e4968ba3615a7e41458323815d5 100644
--- a/Source/OptiX/Private/OptiXContextManager.cpp
+++ b/Source/OptiX/Private/OptiXContextManager.cpp
@@ -1,978 +1,1074 @@
-//#undef UpdateResource
-
-#include "OptiXContextManager.h"
-#include "OptiXModule.h"
-#include "OptiXBuffer.h"
-
-#include "RenderCore.h"
-#include "EngineUtils.h"
-
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-#include "Runtime/Engine/Public/SceneView.h"
-#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
-
-#include "Runtime/Engine/Classes/Engine/TextureCube.h"
-#include "Runtime/Engine/Public/TextureResource.h"
-#include "Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h"
-#include "Runtime/Engine/Classes/Engine/TextureRenderTargetCube.h"
-
-// VR
-#include "Runtime/HeadMountedDisplay/Public/IHeadMountedDisplay.h"
-#include "Runtime/HeadMountedDisplay/Public/IXRTrackingSystem.h"
-#include "Runtime/HeadMountedDisplay/Public/IXRCamera.h"
-
-
-#include "Runtime/Engine/Classes/GameFramework/GameUserSettings.h"
-
-#include "Async.h"
-
-// Console variables todo
-
-static TAutoConsoleVariable<int32> CVarDisableTrace(
-	TEXT("optix.DisableTrace"),
-	0,
-	TEXT("Defines if Optix should perform a constant trace.\n"),
-	ECVF_Scalability | ECVF_RenderThreadSafe);
-
-static TAutoConsoleVariable<int32> CVarDisableLaserTrace(
-	TEXT("optix.DisableLaserTrace"),
-	0,
-	TEXT("Defines if Optix should perform a constant trace.\n"),
-	ECVF_Scalability | ECVF_RenderThreadSafe);
-
-
-
-FOptiXContextManager::FOptiXContextManager(const FAutoRegister& AutoRegister)
-	: FSceneViewExtensionBase(AutoRegister)
-{
-	UE_LOG(LogTemp, Display, TEXT("FOptiXContextManager, is in rendering thread: %i"), static_cast<int32>(IsInRenderingThread()));
-
-	RTXOn = 0;
-
-	LaserMaxDepth = 20;
-	LaserEntryPoint = 1; // Default, will be overwritten anyway
-
-	LaserBufferWidth = 50 * 50;
-	LaserBufferHeight = LaserMaxDepth * 2;
-
-	LaserBufferSize = LaserBufferHeight * LaserBufferWidth;
-
-	bValidCubemap.AtomicSet(false);
-
-	OnSceneChangedDelegate.AddRaw(this, &FOptiXContextManager::SceneChangedCallback);
-
-}
-
-
-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
-}
-
-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)
-{
-	//UE_LOG(LogTemp, Warning, TEXT("PreRenderViewFamily_RenderThread"));
-	if (!bIsInitialized && bStartTracing)
-	{
-		InitCUDADX();
-	}
-}
-
-void FOptiXContextManager::PostRenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneViewFamily & InViewFamily)
-{
-	//UE_LOG(LogTemp, Warning, TEXT("PostRenderViewFamily_RenderThread"));
-		// Laser Test part:
-
-}
-
-void FOptiXContextManager::PostRenderView_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneView & InView)
-{
-	//UE_LOG(LogTemp, Warning, TEXT("VPM: PostRenderViewFamily_RenderThread %s"), *InView.ViewMatrices.GetViewProjectionMatrix().ToString());
-
-	if (!bIsInitialized && !bClearToLaunch && !OptiXContext.IsValid() && !bStartTracing)
-	{
-		return;
-	}
-
-	// Init the yet uninitialized optix components - this queue should be empty and do nothing if no new components are registered.
-	InitOptiXComponents(RHICmdList);
-
-	// Update the remaining variables TODO this needs to be only done once not once per eye!
-	OptiXContext->UpdateVariables();
-	UpdateOptiXComponentVariables();
-	UpdateRequestedCubemaps(RHICmdList);
-
-	RemovePendingChildrenFromGroups();
-	// Clean up any dangling optix objects here to not interfere with launch
-	DestroyOptiXObjects();
-
-
-	OptiXContext->SetMatrix("invViewProjection", InView.ViewMatrices.GetInvViewProjectionMatrix());
-	OptiXContext->SetMatrix("viewProjection", InView.ViewMatrices.GetViewProjectionMatrix());
-
-	FIntPoint Size = OptiXContext->GetBuffer("result_color")->GetSize2D();
-
-	bIsTracing.AtomicSet(true);
-	OptiXContext->Launch(0, Size.X, Size.Y);
-	bIsTracing.AtomicSet(false);
-
-
-	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();
-
-		if (Resources[0] == NULL && Resources[1] == NULL)
-		{
-			return;
-		}
-
-		cudaGraphicsMapResources(2, Resources, 0);
-		PrintLastCudaError("cudaGraphicsMapResources");
-
-		if (CudaResourceDepthLeft == NULL)
-		{
-			cudaGraphicsUnmapResources(2, Resources, 0);
-			return;
-		}
-
-		// Copy Depth
-		cudaArray *CuArrayDepth;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthLeft, 0, 0);
-		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-		cudaMemcpy2DToArray(
-			CuArrayDepth, // dst array
-			0, 0,    // offset
-			CudaLinearMemoryDepth, Width * sizeof(float),       // src
-			Width * sizeof(float), Height, // extent
-			cudaMemcpyDeviceToDevice); // kind
-		PrintLastCudaError("cudaMemcpy2DToArray");
-
-		// Copy Color
-
-		cudaArray *CuArrayColor;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorLeft, 0, 0);
-		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-		cudaMemcpy2DToArray(
-			CuArrayColor, // dst array
-			0, 0,    // offset
-			CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
-			Width * 4 * sizeof(float), Height, // extent
-			cudaMemcpyDeviceToDevice); // kind
-		PrintLastCudaError("cudaMemcpy2DToArray");
-
-
-		cudaGraphicsUnmapResources(2, Resources, 0);
-		PrintLastCudaError("cudaGraphicsUnmapResources");
-
-		//D3DDeviceContext->Flush();
-		LaunchLaser();
-		UpdateCubemapBuffer(RHICmdList);
-
-	}
-	else if(InView.StereoPass == EStereoscopicPass::eSSP_RIGHT_EYE)
-	{
-		if (Resources[2] == NULL && Resources[3] == NULL)
-		{
-			return;
-		}
-		cudaGraphicsMapResources(2, Resources + 2, 0);
-		PrintLastCudaError("cudaGraphicsMapResources");
-
-		if (CudaResourceDepthRight == NULL)
-		{
-			cudaGraphicsUnmapResources(2, Resources + 2, 0);
-			return;
-		}
-		// Depth
-		cudaArray *CuArrayDepth;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthRight, 0, 0);
-		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-		cudaMemcpy2DToArray(
-			CuArrayDepth, // dst array
-			0, 0,    // offset
-			CudaLinearMemoryDepth, Width * sizeof(float),       // src
-			Width * sizeof(float), Height, // extent
-			cudaMemcpyDeviceToDevice); // kind
-		//PrintLastCudaError("cudaMemcpy2DToArray");
-
-
-		// Color
-		cudaArray *CuArrayColor;
-		cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorRight, 0, 0);
-		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-		cudaMemcpy2DToArray(
-			CuArrayColor, // dst array
-			0, 0,    // offset
-			CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
-			Width * 4 * sizeof(float), Height, // extent
-			cudaMemcpyDeviceToDevice); // kind
-		PrintLastCudaError("cudaMemcpy2DToArray");
-
-		cudaGraphicsUnmapResources(2, Resources + 2, 0);
-		PrintLastCudaError("cudaGraphicsUnmapResources");
-	}
-
-	//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::LaunchLaser()
-{
-	if (/*bSceneChanged && */ bLaserIsInitialized && !CVarDisableLaserTrace.GetValueOnRenderThread())
-	{
-		if (LaserActor.IsValid())
-		{
-			LaserActor->OptiXLaserComponent->UpdateOptiXContextVariables();
-		}
-
-		// uuuuuuuuh
-		static uint32 RandomSeed = 0;
-		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);
-
-
-		if (Resources[4] == NULL)
-		{
-			return;
-		}
-
-		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");
-
-		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");
-
-		bSceneChanged.AtomicSet(false);
-		LaserTraceFinishedEvent.Broadcast();
-	}
-}
-
-
-bool FOptiXContextManager::IsActiveThisFrame(FViewport * InViewport) const
-{
-	//UE_LOG(LogTemp, Warning, TEXT("IsActiveThisFrame"));
-
-	bool bDisableTrace = CVarDisableTrace.GetValueOnGameThread(); // Bad naming fix me
-	return OptiXContext.IsValid() && !bDisableTrace && bStartTracing /* && !bEndPlay*//* && TrackingSystem->IsHeadTrackingAllowed()*/;
-}
-
-void FOptiXContextManager::RenderOrthoPass()
-{
-	OptiXContext->SetMatrix("invViewProjection", OrthoMatrix.Inverse());
-	OptiXContext->SetMatrix("viewProjection", OrthoMatrix);
-
-	FIntPoint Size = OptiXContext->GetBuffer("result_color")->GetSize2D();
-
-	bIsTracing.AtomicSet(true);
-	OptiXContext->Launch(0, Size.X, Size.Y);
-	bIsTracing.AtomicSet(false);
-
-	if (Resources[5] == NULL && Resources[6] == NULL)
-	{
-		return;
-	}
-
-	cudaGraphicsMapResources(2, Resources + 5, 0);
-	PrintLastCudaError("cudaGraphicsMapResources");
-
-	if (CudaResourceDepthOrtho == NULL)
-	{
-		cudaGraphicsUnmapResources(2, Resources + 5, 0);
-		return;
-	}
-
-	// Copy Depth
-	cudaArray *CuArrayDepth;
-	cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthOrtho, 0, 0);
-	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-	cudaMemcpy2DToArray(
-		CuArrayDepth, // dst array
-		0, 0,    // offset
-		CudaLinearMemoryDepth, Width * sizeof(float),       // src
-		Width * sizeof(float), Height, // extent
-		cudaMemcpyDeviceToDevice); // kind
-	PrintLastCudaError("cudaMemcpy2DToArray");
-
-	// Copy Color
-
-	cudaArray *CuArrayColor;
-	cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorOrtho, 0, 0);
-	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-	cudaMemcpy2DToArray(
-		CuArrayColor, // dst array
-		0, 0,    // offset
-		CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
-		Width * 4 * sizeof(float), Height, // extent
-		cudaMemcpyDeviceToDevice); // kind
-	PrintLastCudaError("cudaMemcpy2DToArray");
-
-
-	cudaGraphicsUnmapResources(2, Resources + 5, 0);
-	PrintLastCudaError("cudaGraphicsUnmapResources");	
-}
-
-void FOptiXContextManager::Init()
-{
-
-	// TODO Fix me there's still an optix error in there somewhere
-	//if (CubemapSampler.IsValid())
-	//{
-	//	CubemapSampler->RemoveFromRoot();
-	//	CubemapSampler->GetNativeTextureSampler()->destroy();
-	//	CubemapSampler->MarkPendingKill();
-	//	CubemapSampler.Reset();
-	//}
-	//if (CubemapBuffer.IsValid())
-	//{
-	//	CubemapBuffer->RemoveFromRoot();
-	//	CubemapBuffer->GetNativeBuffer()->destroy();
-	//	CubemapBuffer->MarkPendingKill();
-	//	CubemapBuffer.Reset();
-	//}
-
-	// Probably don't need this at all
-	//if (GEngine)
-	//{
-		//GEngine->ForceGarbageCollection();
-	//}
-
-	// Shouldn't be anything in the queues but clean up anyway just to be sure.
-	DestroyOptiXObjects();
-
-	//TODO: Shut this thing down correctly - for now just clean up anything when restarting
-	CleanupOptiXOnEnd();
-
-	InitContext();
-	InitRendering();
-	InitBuffers();
-	InitPrograms();
-	InitLaser();
-	InitCubemap();
-	//InitCUDADX();
-	bIsInitialized = false;
-	bStartTracing = true;
-}
-
-void FOptiXContextManager::SceneChangedCallback()
-{
-	bSceneChanged.AtomicSet(true);
-}
-
-void FOptiXContextManager::InitContext()
-{
-
-	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);
-
-	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);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_TRACE_DEPTH_EXCEEDED, true);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_PROGRAM_ID_INVALID, true);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_TEXTURE_ID_INVALID, true);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_BUFFER_ID_INVALID, true);
-	
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_INDEX_OUT_OF_BOUNDS, true);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_STACK_OVERFLOW, true);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_INVALID_RAY, true);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_INTERNAL_ERROR, true);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_BUFFER_INDEX_OUT_OF_BOUNDS, true);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER, true);
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER_MAX, true);
-
-	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_ALL, true);
-
-
-
-	//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
-	OptiXContext->SetRayTypeCount(2);
-	OptiXContext->SetEntryPointCount(1);
-	//OptiXContext->SetStackSize(4000);
-	OptiXContext->SetMaxTraceDepth(31);
-
-	OptiXContext->SetInt("max_depth", 10);
-	OptiXContext->SetFloat("scene_epsilon", 1.e-2f);
-
-	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.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
-
-}
-
-
-void FOptiXContextManager::InitRendering()
-{
-
-	UE_LOG(LogTemp, Display, TEXT("Initializing Rendering in ContextManager"));
-
-
-	// Are we using an HMD?
-	if (GEngine->XRSystem.IsValid() && GEngine->XRSystem->GetHMDDevice() != nullptr)
-	{
-		UE_LOG(LogTemp, Display, TEXT("Got HMD in ContextManager"));
-
-		bWithHMD = GEngine->XRSystem->GetHMDDevice()->IsHMDEnabled();
-	}
-	else
-	{
-		UE_LOG(LogTemp, Display, TEXT("Running without HMD in ContextManager"));
-
-		bWithHMD = false;
-	}
-
-	// Viewport size:
-	FViewport* CurrentViewport = GEngine->GameViewport->Viewport;
-
-	Width = CurrentViewport->GetSizeXY().X / 2.0;
-	Height = CurrentViewport->GetSizeXY().Y;
-
-	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? 
-	// Catch that case:
-	if (Width == 0 || Height == 0)
-	{
-		UGameUserSettings* GameSettings = GEngine->GetGameUserSettings();
-		Width = GameSettings->GetScreenResolution().X;
-		Height = GameSettings->GetScreenResolution().Y;
-		UE_LOG(LogTemp, Display, TEXT("Fallback to viewport size in settings: %i, %i"), Width, Height);
-
-	}
-
-
-	// Create the textures:
-
-	OutputTexture = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
-	OutputTexture->AddToRoot();
-	//// Allocate the texture HRI
-	OutputTexture->UpdateResource();
-
-	DepthTexture = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
-	DepthTexture->AddToRoot();
-	//// Allocate the texture HRI
-	DepthTexture->UpdateResource();
-
-	OutputTextureColorRightRef = ((FTexture2DResource*)OutputTexture->Resource)->GetTexture2DRHI();
-	OutputTextureDepthRightRef = ((FTexture2DResource*)DepthTexture->Resource)->GetTexture2DRHI();
-
-	if (bWithHMD)
-	{
-		OutputTexture2 = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
-		OutputTexture2->AddToRoot();
-		//// Allocate the texture HRI
-		OutputTexture2->UpdateResource();
-
-		DepthTexture2 = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
-		DepthTexture2->AddToRoot();
-		//// Allocate the texture HRI
-		DepthTexture2->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();
-
-		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
-	LaserIntersectionTexture->AddToRoot();
-	//// Allocate the texture HRI
-	LaserIntersectionTexture->UpdateResource();
-
-	LaserIntersectionTextureRef = ((FTexture2DResource*)LaserIntersectionTexture->Resource)->GetTexture2DRHI();
-
-	// Set up the material
-
-	// Load the materials
-	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(), OptiXContext.Get(), "DynamicLaserMaterial");
-
-	LaserMaterialDynamic->SetTextureParameterValue("IntersectionTexture", LaserIntersectionTexture.Get());
-	LaserMaterialDynamic->SetScalarParameterValue("Lines", 50);
-	LaserMaterialDynamic->SetScalarParameterValue("Segments", 20);
-
-
-	if(RegularMaterial == nullptr || VRMaterial == nullptr)
-	{
-		UE_LOG(LogTemp, Error, TEXT("Couldn't load dummy Material!"));
-	}
-
-	if (bWithHMD)
-	{
-		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(RegularMaterial.Get(), OptiXContext.Get(), "DynamicNonVRMaterial");
-		DynamicMaterial->SetTextureParameterValue("Texture", OutputTexture.Get());
-		DynamicMaterial->SetTextureParameterValue("Depth", DepthTexture.Get());
-	}
-
-	UE_LOG(LogTemp, Display, TEXT("Finished Initializing Rendering in ContextManager"));
-}
-
-void FOptiXContextManager::InitBuffers()
-{
-	OutputBuffer = OptiXContext->CreateOutputBufferColor(Width, Height);
-	OutputDepthBuffer = OptiXContext->CreateOutputBufferDepth(Width, Height);
-
-	OptiXContext->SetBuffer("result_color", OutputBuffer.Get());
-	OptiXContext->SetBuffer("result_depth", OutputDepthBuffer.Get());
-}
-
-void FOptiXContextManager::InitPrograms()
-{
-	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
-
-	// Generation Program
-	RayGenerationProgram = OptiXContext->CreateProgramFromPTXFile
-	(
-		OptiXPTXDir + "generated/perspective_camera.ptx",
-		"pinhole_camera"
-	);
-	OptiXContext->SetRayGenerationProgram(0, RayGenerationProgram.Get());
-
-	// Exception program
-	ExceptionProgram = OptiXContext->CreateProgramFromPTXFile
-	(
-		OptiXPTXDir + "generated/exception.ptx",
-		"exception"
-	);
-	OptiXContext->SetExceptionProgram(0, ExceptionProgram.Get());
-
-	// Miss Program
-	MissProgram = OptiXContext->CreateProgramFromPTXFile
-	(
-		OptiXPTXDir + "generated/skybox.ptx",
-		"skyboxLookup"
-	);
-	OptiXContext->SetMissProgram(0, MissProgram.Get());
-	OptiXContext->SetFloat3DVector("bg_color", FVector(1.0, 1.0, 1.0));
-}
-
-
-
-void FOptiXContextManager::InitLaser()
-{
-
-	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
-
-
-	LaserEntryPoint = OptiXContext->GetEntryPointCount();
-
-	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
-	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 = OptiXContext->CreateProgramFromPTXFile
-	(
-		OptiXPTXDir + "generated/exception.ptx",
-		"exception"
-	);
-
-	OptiXContext->SetExceptionProgram(1 /* todo- diff between raytypeindex and entrypointcount, this is 1 in the original app*/, LaserExceptionProgram.Get());
-
-	LaserRayGenerationProgram = OptiXContext->CreateProgramFromPTXFile
-	(
-		OptiXPTXDir + "generated/laser_caster.ptx",
-		"laser_caster"
-	);
-	OptiXContext->SetRayGenerationProgram(LaserEntryPoint, LaserRayGenerationProgram.Get());
-
-	LaserMissProgram = OptiXContext->CreateProgramFromPTXFile
-	(
-		OptiXPTXDir + "generated/miss.ptx",
-		"miss_iterative"
-	);
-
-	OptiXContext->SetMissProgram(1 /*LaserEntryPoint /* this is 1 in the original application, why? TODO*/, LaserMissProgram.Get());
-
-	//LaserOutputBuffer = OptiXContext->CreateBuffer(RT_BUFFER_OUTPUT, RT_FORMAT_FLOAT4, LaserBufferSize);
-	LaserOutputBuffer = OptiXContext->CreateOutputBufferIntersections(LaserBufferWidth, LaserBufferHeight);
-	LaserOutputBuffer->AddToRoot();
-	OptiXContext->SetBuffer("result_laser", LaserOutputBuffer.Get());
-
-	OptiXContext->SetInt("max_depth_laser", LaserMaxDepth);
-
-	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);
-
-
-}
-
-void FOptiXContextManager::InitCubemap()
-{
-	// todo max # cubemaps
-	for (int32 i = 1; i < 10; i++) // 0 is reserved for this (player camera)
-	{
-		UnallocatedCubemapIds.Enqueue(i);
-	}
-
-	// 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 = 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 = OptiXContext->CreateCubemapBuffer(1024, 1024);
-	//CubemapBuffer->AddToRoot();
-
-	CubemapSampler->SetBufferWithTextureIndexAndMiplevel(0u, 0u, CubemapBuffer.Get());
-	CubemapSampler->SetFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
-
-	OptiXContext->SetSkybox("skybox0", CubemapSampler.Get());
-
-	//RequestCubemapId();
-	AddCubemapToBuffer(0, CubemapSampler->GetId());
-	
-	//OptiXContext->SetTextureSampler("skybox", CubemapSampler.Get());
-
-	UE_LOG(LogTemp, Display, TEXT("Successfully initialized cubemap."));
-}
-
-int32 FOptiXContextManager::RequestCubemapId()
-{
-	if (UnallocatedCubemapIds.IsEmpty())
-	{
-		return 0;
-	}
-	int32 Id;
-	UnallocatedCubemapIds.Dequeue(Id);
-	return Id;
-}
-
-void FOptiXContextManager::DeleteCubemapId(int32 Id)
-{
-	if (Id <= 10)
-	{
-		UE_LOG(LogTemp, Warning, TEXT("Trying to free a cubemap that isn't there."));
-		return;
-	}
-	// The Component itself should handle deletion of the sampler.
-	UnallocatedCubemapIds.Enqueue(Id);
-}
-
-void FOptiXContextManager::UpdateCubemapBuffer(FRHICommandListImmediate & RHICmdList)
-{
-	if (!CameraActor.IsValid() || bValidCubemap)
-	{
-		return;
-	}
-
-	if (!CameraActor->bCubemapCaptured)
-	{
-		return;
-	}
-
-
-	int32 X = CameraActor->CubeRenderTarget->SizeX;
-	int32 Y = X;
-
-	SurfaceDataCube.Empty();
-	SurfaceDataCube.SetNumZeroed(6);
-
-	//TArray<FLinearColor> SD;
-
-	optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->MapNative());
-
-	FTextureRenderTargetCubeResource* RenderTargetCube = static_cast<FTextureRenderTargetCubeResource*>(CameraActor->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();
-	bValidCubemap.AtomicSet(true);
-}
-
-void FOptiXContextManager::AddCubemapToBuffer(int32 CubemapId, int32 SamplerId)
-{
-	int32* Data = static_cast<int32*>(CubemapsInputBuffer->MapNative());
-	Data[CubemapId] = SamplerId;
-	CubemapsInputBuffer->Unmap();
-}
-
-void FOptiXContextManager::InitCUDADX()
-{
-	
-	// Setup DX:
-
-	D3DDevice = (ID3D11Device*)GDynamicRHI->RHIGetNativeDevice();
-	D3DDevice->GetImmediateContext(&D3DDeviceContext);
-
-	// Create texture for now:
-
-	OutputTextureDepthLeftRef = ((FTexture2DResource*)DepthTexture2->Resource)->GetTexture2DRHI();
-
-	// 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);
-	
-
-	// 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(&CudaLinearMemoryColor, Width * Height * 4 * sizeof(float));
-	PrintLastCudaError("cudaMalloc");
-
-	cudaMalloc(&CudaLinearMemoryIntersections, LaserBufferWidth * LaserBufferHeight * 4 * sizeof(float));
-	PrintLastCudaError("cudaMalloc");
-
-	//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));
-
-
-	Resources[0] = CudaResourceDepthLeft;
-	Resources[1] = CudaResourceColorLeft;
-	Resources[2] = CudaResourceDepthRight;
-	Resources[3] = CudaResourceColorRight;
-	Resources[4] = CudaResourceIntersections;
-	Resources[5] = CudaResourceColorOrtho;
-	Resources[6] = CudaResourceDepthOrtho;
-
-	bIsInitialized = true;
-
-}
+//#undef UpdateResource
+
+#include "OptiXContextManager.h"
+#include "OptiXModule.h"
+#include "OptiXBuffer.h"
+
+#include "RenderCore.h"
+#include "EngineUtils.h"
+
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+#include "Runtime/Engine/Public/SceneView.h"
+#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
+
+#include "Runtime/Engine/Classes/Engine/TextureCube.h"
+#include "Runtime/Engine/Public/TextureResource.h"
+#include "Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h"
+#include "Runtime/Engine/Classes/Engine/TextureRenderTargetCube.h"
+
+// VR
+#include "Runtime/HeadMountedDisplay/Public/IHeadMountedDisplay.h"
+#include "Runtime/HeadMountedDisplay/Public/IXRTrackingSystem.h"
+#include "Runtime/HeadMountedDisplay/Public/IXRCamera.h"
+
+
+#include "Runtime/Engine/Classes/GameFramework/GameUserSettings.h"
+
+#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
+
+static TAutoConsoleVariable<int32> CVarDisableTrace(
+	TEXT("optix.DisableTrace"),
+	0,
+	TEXT("Defines if Optix should perform a constant trace.\n"),
+	ECVF_Scalability | ECVF_RenderThreadSafe);
+
+static TAutoConsoleVariable<int32> CVarDisableLaserTrace(
+	TEXT("optix.DisableLaserTrace"),
+	0,
+	TEXT("Defines if Optix should perform a constant trace.\n"),
+	ECVF_Scalability | ECVF_RenderThreadSafe);
+
+
+
+FOptiXContextManager::FOptiXContextManager(const FAutoRegister& AutoRegister)
+	: FSceneViewExtensionBase(AutoRegister)
+{
+	UE_LOG(LogTemp, Display, TEXT("FOptiXContextManager, is in rendering thread: %i"), static_cast<int32>(IsInRenderingThread()));
+
+	RTXOn = 0;
+
+	LaserMaxDepth = 20;
+	LaserEntryPoint = 1; // Default, will be overwritten anyway
+
+	LaserBufferWidth = 50 * 50;
+	LaserBufferHeight = LaserMaxDepth * 2;
+
+	LaserBufferSize = LaserBufferHeight * LaserBufferWidth;
+
+	bValidCubemap.AtomicSet(false);
+	OnSceneChangedDelegate.AddRaw(this, &FOptiXContextManager::SceneChangedCallback);
+
+}
+
+
+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
+}
+
+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)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::PreRenderView_RenderThread"))
+	return;
+
+	//OptiXContext->SetMatrix("invViewProjection", InView.ViewMatrices.GetInvViewProjectionMatrix());
+	//OptiXContext->SetMatrix("viewProjection", InView.ViewMatrices.GetViewProjectionMatrix());
+
+	////FIntPoint Size = OptiXContext->GetBuffer("result_color")->GetSize2D();
+
+	//bIsTracing.AtomicSet(true);
+	//OptiXContext->Launch(0, Width, Height);
+	//bIsTracing.AtomicSet(false);
+
+
+	//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();
+
+	//	if (Resources[0] == NULL && Resources[1] == NULL)
+	//	{
+	//		return;
+	//	}
+
+	//	cudaGraphicsMapResources(2, Resources, 0);
+	//	PrintLastCudaError("cudaGraphicsMapResources");
+
+	//	if (CudaResourceDepthLeft == NULL)
+	//	{
+	//		cudaGraphicsUnmapResources(2, Resources, 0);
+	//		return;
+	//	}
+
+	//	// Copy Depth
+	//	cudaArray *CuArrayDepth;
+	//	cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthLeft, 0, 0);
+	//	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+	//	cudaMemcpy2DToArray(
+	//		CuArrayDepth, // dst array
+	//		0, 0,    // offset
+	//		CudaLinearMemoryDepth, Width * sizeof(float),       // src
+	//		Width * sizeof(float), Height, // extent
+	//		cudaMemcpyDeviceToDevice); // kind
+	//	PrintLastCudaError("cudaMemcpy2DToArray");
+
+	//	// Copy Color
+
+	//	cudaArray *CuArrayColor;
+	//	cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorLeft, 0, 0);
+	//	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+	//	cudaMemcpy2DToArray(
+	//		CuArrayColor, // dst array
+	//		0, 0,    // offset
+	//		CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
+	//		Width * 4 * sizeof(float), Height, // extent
+	//		cudaMemcpyDeviceToDevice); // kind
+	//	PrintLastCudaError("cudaMemcpy2DToArray");
+
+
+	//	cudaGraphicsUnmapResources(2, Resources, 0);
+	//	PrintLastCudaError("cudaGraphicsUnmapResources");
+
+	//	//D3DDeviceContext->Flush();
+	//	LaunchLaser();
+	//	UpdateCubemapBuffer(RHICmdList);
+
+	//}
+	//else if (InView.StereoPass == EStereoscopicPass::eSSP_RIGHT_EYE)
+	//{
+	//	if (Resources[2] == NULL && Resources[3] == NULL)
+	//	{
+	//		return;
+	//	}
+	//	cudaGraphicsMapResources(2, Resources + 2, 0);
+	//	PrintLastCudaError("cudaGraphicsMapResources");
+
+	//	if (CudaResourceDepthRight == NULL)
+	//	{
+	//		cudaGraphicsUnmapResources(2, Resources + 2, 0);
+	//		return;
+	//	}
+	//	// Depth
+	//	cudaArray *CuArrayDepth;
+	//	cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthRight, 0, 0);
+	//	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+	//	cudaMemcpy2DToArray(
+	//		CuArrayDepth, // dst array
+	//		0, 0,    // offset
+	//		CudaLinearMemoryDepth, Width * sizeof(float),       // src
+	//		Width * sizeof(float), Height, // extent
+	//		cudaMemcpyDeviceToDevice); // kind
+	//	//PrintLastCudaError("cudaMemcpy2DToArray");
+
+
+	//	// Color
+	//	cudaArray *CuArrayColor;
+	//	cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorRight, 0, 0);
+	//	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+	//	cudaMemcpy2DToArray(
+	//		CuArrayColor, // dst array
+	//		0, 0,    // offset
+	//		CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
+	//		Width * 4 * sizeof(float), Height, // extent
+	//		cudaMemcpyDeviceToDevice); // kind
+	//	PrintLastCudaError("cudaMemcpy2DToArray");
+
+	//	cudaGraphicsUnmapResources(2, Resources + 2, 0);
+	//	PrintLastCudaError("cudaGraphicsUnmapResources");
+	//}
+	//if (bRequestOrthoPass)
+	//{
+	//	RenderOrthoPass();
+	//	bRequestOrthoPass.AtomicSet(false);
+	//}
+}
+
+// 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 (!bIsInitialized && !bClearToLaunch && !OptiXContext.IsValid() && !bStartTracing)
+	{
+		return;
+	}
+	if (InViewFamily.Views.Num() < 2)
+		return;
+
+	
+
+	// Init the yet uninitialized optix components - this queue should be empty and do nothing if no new components are registered.
+	InitOptiXComponents(RHICmdList);
+
+	// Update the remaining variables TODO this needs to be only done once not once per eye!
+	OptiXContext->UpdateVariables();
+	UpdateOptiXComponentVariables();
+	UpdateRequestedCubemaps(RHICmdList);
+
+	RemovePendingChildrenFromGroups();
+	// Clean up any dangling optix objects here to not interfere with launch
+	DestroyOptiXObjects();	
+
+	// Get the views for the respective eyes:
+	EStereoscopicPass LeftEye = EStereoscopicPass::eSSP_LEFT_EYE;
+	EStereoscopicPass RightEye = EStereoscopicPass::eSSP_RIGHT_EYE;
+
+	const FSceneView& LeftEyeView = InViewFamily.GetStereoEyeView(LeftEye);
+	const FSceneView& RightEyeView = InViewFamily.GetStereoEyeView(RightEye);
+
+	OptiXContext->SetMatrix("invViewProjectionLeft", LeftEyeView.ViewMatrices.GetInvViewProjectionMatrix());
+	OptiXContext->SetMatrix("viewProjectionLeft", LeftEyeView.ViewMatrices.GetViewProjectionMatrix());
+	OptiXContext->SetMatrix("invViewProjectionRight", RightEyeView.ViewMatrices.GetInvViewProjectionMatrix());
+	OptiXContext->SetMatrix("viewProjectionRight", RightEyeView.ViewMatrices.GetViewProjectionMatrix());
+
+	//UE_LOG(LogTemp, Warning, TEXT("Child count: %i"), TopObject->GetNativeGroup()->getChildCount());
+
+
+	{
+		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::Trace"))
+		OptiXContext->Validate();
+		bIsTracing.AtomicSet(true);
+		OptiXContext->Launch(0, Width, Height);
+		bIsTracing.AtomicSet(false);
+		//return;
+	}
+	{
+		if (Resources[0] == NULL || Resources[1] == NULL || Resources[2] == NULL || Resources[3] == NULL)
+		{
+			UE_LOG(LogTemp, Warning, TEXT("CUDA Resources are NULL"));
+			return;
+		}
+
+		cudaGraphicsMapResources(4, Resources, 0);
+		PrintLastCudaError("cudaGraphicsMapResources");
+
+		// Copy Color Left
+		cudaArray *CuArrayColorLeft;
+		cudaGraphicsSubResourceGetMappedArray(&CuArrayColorLeft, CudaResourceColorLeft, 0, 0);
+		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+		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");
+
+		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");
+
+
+		// Copy Depth Left
+		cudaArray *CuArrayDepthLeft;
+		cudaGraphicsSubResourceGetMappedArray(&CuArrayDepthLeft, CudaResourceDepthLeft, 0, 0);
+		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+		cudaMemcpy2DToArray(
+			CuArrayDepthLeft, // 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);
+		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+		cudaMemcpy2DToArray(
+			CuArrayDepthRight, // dst array
+			0, 0,    // offset
+			CudaLinearMemoryDepth + (Height * Width), Width * sizeof(float),       // src
+			Width * sizeof(float), Height, // extent
+			cudaMemcpyDeviceToDevice); // kind
+		PrintLastCudaError("cudaMemcpy2DToArray");		
+
+
+		cudaGraphicsUnmapResources(4, Resources, 0);
+		PrintLastCudaError("cudaGraphicsUnmapResources");
+
+		//D3DDeviceContext->Flush();
+		UpdateCubemapBuffer(RHICmdList);
+	}
+
+	if (bRequestOrthoPass)
+	{
+		RenderOrthoPass();
+		bRequestOrthoPass.AtomicSet(false);
+	}
+	//LaunchLaser();
+
+}
+
+void FOptiXContextManager::PostRenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneViewFamily & InViewFamily)
+{
+	//UE_LOG(LogTemp, Warning, TEXT("PostRenderViewFamily_RenderThread"));
+		// Laser Test part:
+
+}
+
+void FOptiXContextManager::PostRenderView_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneView & InView)
+{
+	//UE_LOG(LogTemp, Warning, TEXT("VPM: PostRenderViewFamily_RenderThread %s"), *InView.ViewMatrices.GetViewProjectionMatrix().ToString());
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::PostRenderView_RenderThread"))
+
+
+
+	//else if (InView.StereoPass == EStereoscopicPass::eSSP_FULL)
+	//{
+	//	UE_LOG(LogTemp, Display, TEXT("Full Pass"));
+	//}
+
+	//if (bCleanup)
+	//{
+	//	CleanupOptiXOnEnd();
+	//	return;
+	//}
+}
+
+
+void FOptiXContextManager::LaunchLaser()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser"))
+	if (/*bSceneChanged && */ bLaserIsInitialized && !CVarDisableLaserTrace.GetValueOnRenderThread())
+	{
+		if (LaserActor.IsValid())
+		{
+			LaserActor->OptiXLaserComponent->UpdateOptiXContextVariables();
+		}
+
+
+		// Analyze this
+		
+		// uuuuuuuuh
+		static uint32 RandomSeed = 0;
+		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(TEXT("FOptiXContextManager::LaunchLaser::CudaScope"))
+
+			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");
+
+		}
+		{
+			TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::BroadcastFinish"))
+
+			bSceneChanged.AtomicSet(false);
+			LaserTraceFinishedEvent.Broadcast();
+		}
+	}
+}
+
+
+bool FOptiXContextManager::IsActiveThisFrame(FViewport * InViewport) const
+{
+	//UE_LOG(LogTemp, Warning, TEXT("IsActiveThisFrame"));
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::IsActiveThisFrame"))
+
+	bool bDisableTrace = CVarDisableTrace.GetValueOnGameThread(); // Bad naming fix me
+	return OptiXContext.IsValid() && !bDisableTrace && bStartTracing /* && !bEndPlay*//* && TrackingSystem->IsHeadTrackingAllowed()*/;
+}
+
+void FOptiXContextManager::RenderOrthoPass()
+{
+	return;
+
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::RenderOrthoPass"))
+
+	OptiXContext->SetInt("is_ortho", 1);
+
+	OptiXContext->SetMatrix("invViewProjectionLeft", OrthoMatrix.Inverse());
+	OptiXContext->SetMatrix("viewProjectionLeft", OrthoMatrix);
+
+	//FIntPoint Size = OptiXContext->GetBuffer("result_color")->GetSize2D();
+
+	bIsTracing.AtomicSet(true);
+	OptiXContext->Launch(0, Width, Height);
+	bIsTracing.AtomicSet(false);
+
+	if (Resources[5] == NULL && Resources[6] == NULL)
+	{
+		return;
+	}
+
+	cudaGraphicsMapResources(2, Resources + 5, 0);
+	PrintLastCudaError("cudaGraphicsMapResources");
+
+	if (CudaResourceDepthOrtho == NULL)
+	{
+		cudaGraphicsUnmapResources(2, Resources + 5, 0);
+		return;
+	}
+
+	// Copy Depth
+	cudaArray *CuArrayDepth;
+	cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthOrtho, 0, 0);
+	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+	cudaMemcpy2DToArray(
+		CuArrayDepth, // dst array
+		0, 0,    // offset
+		CudaLinearMemoryDepth, Width * sizeof(float),       // src
+		Width * sizeof(float), Height, // extent
+		cudaMemcpyDeviceToDevice); // kind
+	PrintLastCudaError("cudaMemcpy2DToArray");
+
+	// Copy Color
+
+	cudaArray *CuArrayColor;
+	cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorOrtho, 0, 0);
+	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+	cudaMemcpy2DToArray(
+		CuArrayColor, // dst array
+		0, 0,    // offset
+		CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
+		Width * 4 * sizeof(float), Height, // extent
+		cudaMemcpyDeviceToDevice); // kind
+	PrintLastCudaError("cudaMemcpy2DToArray");
+
+
+	cudaGraphicsUnmapResources(2, Resources + 5, 0);
+	PrintLastCudaError("cudaGraphicsUnmapResources");
+
+	OptiXContext->SetInt("is_ortho", 0);
+
+}
+
+void FOptiXContextManager::Init()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::Init"))
+
+	// TODO Fix me there's still an optix error in there somewhere
+	//if (CubemapSampler.IsValid())
+	//{
+	//	CubemapSampler->RemoveFromRoot();
+	//	CubemapSampler->GetNativeTextureSampler()->destroy();
+	//	CubemapSampler->MarkPendingKill();
+	//	CubemapSampler.Reset();
+	//}
+	//if (CubemapBuffer.IsValid())
+	//{
+	//	CubemapBuffer->RemoveFromRoot();
+	//	CubemapBuffer->GetNativeBuffer()->destroy();
+	//	CubemapBuffer->MarkPendingKill();
+	//	CubemapBuffer.Reset();
+	//}
+
+	// Probably don't need this at all
+	//if (GEngine)
+	//{
+		//GEngine->ForceGarbageCollection();
+	//}
+
+	// Shouldn't be anything in the queues but clean up anyway just to be sure.
+	DestroyOptiXObjects();
+
+	//TODO: Shut this thing down correctly - for now just clean up anything when restarting
+	CleanupOptiXOnEnd();
+
+	InitContext();
+	InitRendering();
+	InitBuffers();
+	InitPrograms();
+	InitLaser();
+	InitCubemap();
+
+	InitCUDADX();
+
+	bIsInitialized = false;
+	bStartTracing = true;
+}
+
+void FOptiXContextManager::SceneChangedCallback()
+{
+	bSceneChanged.AtomicSet(true);
+}
+
+void FOptiXContextManager::InitContext()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::InitContext"))
+
+	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);
+
+	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);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_TRACE_DEPTH_EXCEEDED, true);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_PROGRAM_ID_INVALID, true);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_TEXTURE_ID_INVALID, true);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_BUFFER_ID_INVALID, true);
+	
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_INDEX_OUT_OF_BOUNDS, true);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_STACK_OVERFLOW, true);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_INVALID_RAY, true);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_INTERNAL_ERROR, true);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_BUFFER_INDEX_OUT_OF_BOUNDS, true);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER, true);
+	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER_MAX, true);
+
+	OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_ALL, true);
+
+	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
+	OptiXContext->SetRayTypeCount(2);
+	OptiXContext->SetEntryPointCount(1);
+	//OptiXContext->SetStackSize(4000);
+	OptiXContext->SetMaxTraceDepth(31);
+
+	OptiXContext->SetInt("max_depth", 10);
+	OptiXContext->SetFloat("scene_epsilon", 1.e-2f);
+
+	TopObject = OptiXContext->CreateGroup();
+	TopAcceleration = OptiXContext->CreateAcceleration("NoAccel"); // Here the accel structure seems to be actually needed
+	//TopAcceleration->AddToRoot();
+	TopAcceleration->SetProperty("refit", "1");
+
+	TopObject->SetAcceleration(TopAcceleration.Get());
+
+	UE_LOG(LogTemp, Warning, TEXT("Child count: %i"), TopObject->GetNativeGroup()->getChildCount());
+
+
+	OptiXContext->SetGroup("top_object", TopObject.Get());
+	
+	OptiXContext->SetInt("is_ortho", 0);
+	// Keep buffers and programs with the camera manager for now, there's no real reason yet to force a refacturing there
+
+}
+
+
+void FOptiXContextManager::InitRendering()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::InitRendering"))
+
+	UE_LOG(LogTemp, Display, TEXT("Initializing Rendering in ContextManager"));
+
+
+	// Are we using an HMD?
+	if (GEngine->XRSystem.IsValid() && GEngine->XRSystem->GetHMDDevice() != nullptr)
+	{
+		UE_LOG(LogTemp, Display, TEXT("Got HMD in ContextManager"));
+
+		bWithHMD = GEngine->XRSystem->GetHMDDevice()->IsHMDEnabled();
+	}
+	else
+	{
+		UE_LOG(LogTemp, Display, TEXT("Running without HMD in ContextManager"));
+
+		bWithHMD = false;
+	}
+
+	// Viewport size:
+	FViewport* CurrentViewport = GEngine->GameViewport->Viewport;
+
+	Width = CurrentViewport->GetSizeXY().X / 2.0;
+	Height = CurrentViewport->GetSizeXY().Y;
+
+	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? 
+	// Catch that case:
+	if (Width == 0 || Height == 0)
+	{
+		UGameUserSettings* GameSettings = GEngine->GetGameUserSettings();
+		Width = GameSettings->GetScreenResolution().X;
+		Height = GameSettings->GetScreenResolution().Y;
+		UE_LOG(LogTemp, Display, TEXT("Fallback to viewport size in settings: %i, %i"), Width, Height);
+
+	}
+
+	// Create the textures:
+
+	OutputTexture = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
+	OutputTexture->AddToRoot();
+	//// Allocate the texture HRI
+	OutputTexture->UpdateResource();
+
+	DepthTexture = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
+	DepthTexture->AddToRoot();
+	//// Allocate the texture HRI
+	DepthTexture->UpdateResource();
+
+	//OutputTextureColorRightRef = ((FTexture2DResource*)OutputTexture->Resource)->GetTexture2DRHI();
+	//OutputTextureDepthRightRef = ((FTexture2DResource*)DepthTexture->Resource)->GetTexture2DRHI();
+
+	if (bWithHMD)
+	{
+		OutputTexture2 = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
+		OutputTexture2->AddToRoot();
+		//// Allocate the texture HRI
+		OutputTexture2->UpdateResource();
+
+		DepthTexture2 = UTexture2D::CreateTransient(Width, Height, PF_R32_FLOAT);
+		DepthTexture2->AddToRoot();
+		//// Allocate the texture HRI
+		DepthTexture2->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();
+
+		//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
+	LaserIntersectionTexture->AddToRoot();
+	//// Allocate the texture HRI
+	LaserIntersectionTexture->UpdateResource();
+
+	//LaserIntersectionTextureRef = ((FTexture2DResource*)LaserIntersectionTexture->Resource)->GetTexture2DRHI();
+
+	// Set up the material
+
+	// Load the materials
+	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(), OptiXContext.Get(), "DynamicLaserMaterial");
+
+	LaserMaterialDynamic->SetTextureParameterValue("IntersectionTexture", LaserIntersectionTexture.Get());
+	LaserMaterialDynamic->SetScalarParameterValue("Lines", 50);
+	LaserMaterialDynamic->SetScalarParameterValue("Segments", 20);
+
+
+	if(RegularMaterial == nullptr || VRMaterial == nullptr)
+	{
+		UE_LOG(LogTemp, Error, TEXT("Couldn't load dummy Material!"));
+	}
+
+	if (bWithHMD)
+	{
+		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(RegularMaterial.Get(), OptiXContext.Get(), "DynamicNonVRMaterial");
+		DynamicMaterial->SetTextureParameterValue("Texture", OutputTexture.Get());
+		DynamicMaterial->SetTextureParameterValue("Depth", DepthTexture.Get());
+	}
+
+	UE_LOG(LogTemp, Display, TEXT("Finished Initializing Rendering in ContextManager"));
+	FlushRenderingCommands();
+
+}
+
+void FOptiXContextManager::InitBuffers()
+{
+	OutputBuffer = OptiXContext->CreateOutputBufferColor(Width, Height * 2);
+	OutputDepthBuffer = OptiXContext->CreateOutputBufferDepth(Width, Height * 2);
+
+	OptiXContext->SetBuffer("result_color", OutputBuffer.Get());
+	OptiXContext->SetBuffer("result_depth", OutputDepthBuffer.Get());
+}
+
+void FOptiXContextManager::InitPrograms()
+{
+	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
+
+	// Generation Program
+	RayGenerationProgram = OptiXContext->CreateProgramFromPTXFile
+	(
+		OptiXPTXDir + "generated/perspective_camera.ptx",
+		"pinhole_camera"
+	);
+	OptiXContext->SetRayGenerationProgram(0, RayGenerationProgram.Get());
+
+	// Exception program
+	ExceptionProgram = OptiXContext->CreateProgramFromPTXFile
+	(
+		OptiXPTXDir + "generated/exception.ptx",
+		"exception"
+	);
+	OptiXContext->SetExceptionProgram(0, ExceptionProgram.Get());
+
+	// Miss Program
+	MissProgram = OptiXContext->CreateProgramFromPTXFile
+	(
+		OptiXPTXDir + "generated/skybox.ptx",
+		"skyboxLookup"
+	);
+	OptiXContext->SetMissProgram(0, MissProgram.Get());
+	OptiXContext->SetFloat3DVector("bg_color", FVector(1.0, 1.0, 1.0));
+}
+
+
+
+void FOptiXContextManager::InitLaser()
+{
+
+	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
+
+
+	LaserEntryPoint = OptiXContext->GetEntryPointCount();
+
+	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
+	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 = OptiXContext->CreateProgramFromPTXFile
+	(
+		OptiXPTXDir + "generated/exception.ptx",
+		"exception"
+	);
+
+	OptiXContext->SetExceptionProgram(1 /* todo- diff between raytypeindex and entrypointcount, this is 1 in the original app*/, LaserExceptionProgram.Get());
+
+	LaserRayGenerationProgram = OptiXContext->CreateProgramFromPTXFile
+	(
+		OptiXPTXDir + "generated/laser_caster.ptx",
+		"laser_caster"
+	);
+	OptiXContext->SetRayGenerationProgram(LaserEntryPoint, LaserRayGenerationProgram.Get());
+
+	LaserMissProgram = OptiXContext->CreateProgramFromPTXFile
+	(
+		OptiXPTXDir + "generated/miss.ptx",
+		"miss_iterative"
+	);
+
+	OptiXContext->SetMissProgram(1 /*LaserEntryPoint /* this is 1 in the original application, why? TODO*/, LaserMissProgram.Get());
+
+	//LaserOutputBuffer = OptiXContext->CreateBuffer(RT_BUFFER_OUTPUT, RT_FORMAT_FLOAT4, LaserBufferSize);
+	LaserOutputBuffer = OptiXContext->CreateOutputBufferIntersections(LaserBufferWidth, LaserBufferHeight);
+	LaserOutputBuffer->AddToRoot();
+	OptiXContext->SetBuffer("result_laser", LaserOutputBuffer.Get());
+
+	OptiXContext->SetInt("max_depth_laser", LaserMaxDepth);
+
+	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);
+
+
+}
+
+void FOptiXContextManager::InitCubemap()
+{
+	// todo max # cubemaps
+	for (int32 i = 1; i < 10; i++) // 0 is reserved for this (player camera)
+	{
+		UnallocatedCubemapIds.Enqueue(i);
+	}
+
+	// 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 = 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 = OptiXContext->CreateCubemapBuffer(1024, 1024);
+	//CubemapBuffer->AddToRoot();
+
+	CubemapSampler->SetBufferWithTextureIndexAndMiplevel(0u, 0u, CubemapBuffer.Get());
+	CubemapSampler->SetFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
+
+	OptiXContext->SetSkybox("skybox0", CubemapSampler.Get());
+
+	//RequestCubemapId();
+	AddCubemapToBuffer(0, CubemapSampler->GetId());
+	
+	//OptiXContext->SetTextureSampler("skybox", CubemapSampler.Get());
+
+	UE_LOG(LogTemp, Display, TEXT("Successfully initialized cubemap."));
+}
+
+int32 FOptiXContextManager::RequestCubemapId()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::RequestCubemapId"))
+
+	if (UnallocatedCubemapIds.IsEmpty())
+	{
+		return 0;
+	}
+	int32 Id;
+	UnallocatedCubemapIds.Dequeue(Id);
+	return Id;
+}
+
+void FOptiXContextManager::DeleteCubemapId(int32 Id)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::DeleteCubemapId"))
+
+	if (Id <= 10)
+	{
+		UE_LOG(LogTemp, Warning, TEXT("Trying to free a cubemap that isn't there."));
+		return;
+	}
+	// The Component itself should handle deletion of the sampler.
+	UnallocatedCubemapIds.Enqueue(Id);
+}
+
+void FOptiXContextManager::UpdateCubemapBuffer(FRHICommandListImmediate & RHICmdList)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::UpdateCubemapBuffer"))
+
+	if (!CameraActor.IsValid() || bValidCubemap)
+	{
+		return;
+	}
+
+	if (!CameraActor->bCubemapCaptured)
+	{
+		return;
+	}
+
+
+	int32 X = CameraActor->CubeRenderTarget->SizeX;
+	int32 Y = X;
+
+	SurfaceDataCube.Empty();
+	SurfaceDataCube.SetNumZeroed(6);
+
+	//TArray<FLinearColor> SD;
+
+	optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->MapNative());
+
+	FTextureRenderTargetCubeResource* RenderTargetCube = static_cast<FTextureRenderTargetCubeResource*>(CameraActor->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();
+	bValidCubemap.AtomicSet(true);
+}
+
+void FOptiXContextManager::AddCubemapToBuffer(int32 CubemapId, int32 SamplerId)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::AddCubemapToBuffer"))
+
+	int32* Data = static_cast<int32*>(CubemapsInputBuffer->MapNative());
+	Data[CubemapId] = SamplerId;
+	CubemapsInputBuffer->Unmap();
+}
+
+void FOptiXContextManager::InitCUDADX()
+{
+	
+	// Setup DX:
+
+	check(IsInGameThread());
+
+	D3DDevice = (ID3D11Device*)GDynamicRHI->RHIGetNativeDevice();
+	D3DDevice->GetImmediateContext(&D3DDeviceContext);
+
+
+	// Depth
+	{
+		FD3D11TextureBase* D3D11TextureDepthLeft = GetD3D11TextureFromRHITexture(DepthTexture2->Resource->TextureRHI);
+		cudaGraphicsD3D11RegisterResource(&CudaResourceDepthLeft, D3D11TextureDepthLeft->GetResource(), cudaGraphicsRegisterFlagsNone);
+		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+	}
+	{
+		FD3D11TextureBase* D3D11TextureDepthRight = GetD3D11TextureFromRHITexture(DepthTexture->Resource->TextureRHI);
+		cudaGraphicsD3D11RegisterResource(&CudaResourceDepthRight, D3D11TextureDepthRight->GetResource(), cudaGraphicsRegisterFlagsNone);
+		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+	}
+	// Color
+	{
+		FD3D11TextureBase* D3D11TextureColorLeft = GetD3D11TextureFromRHITexture(OutputTexture2->Resource->TextureRHI);
+		cudaGraphicsD3D11RegisterResource(&CudaResourceColorLeft, D3D11TextureColorLeft->GetResource(), cudaGraphicsRegisterFlagsNone);
+		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+	}
+	{
+		FD3D11TextureBase* D3D11TextureColorRight = GetD3D11TextureFromRHITexture(OutputTexture->Resource->TextureRHI);
+		cudaGraphicsD3D11RegisterResource(&CudaResourceColorRight, D3D11TextureColorRight->GetResource(), cudaGraphicsRegisterFlagsNone);
+		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+	}
+	// 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");
+	}
+	
+	cudaMalloc((void**)&CudaLinearMemoryDepth, Width * Height * sizeof(float) * 2);
+	PrintLastCudaError("cudaMalloc");
+
+	cudaMalloc((void**)&CudaLinearMemoryColor, Width * Height * 4 * sizeof(float) * 2);
+	PrintLastCudaError("cudaMalloc");
+
+	cudaMalloc(&CudaLinearMemoryIntersections, LaserBufferWidth * LaserBufferHeight * 4 * sizeof(float));
+	PrintLastCudaError("cudaMalloc");
+	
+	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));
+	
+
+	Resources[0] = CudaResourceDepthLeft;
+	Resources[1] = CudaResourceColorLeft;
+	Resources[2] = CudaResourceDepthRight;
+	Resources[3] = CudaResourceColorRight;
+	Resources[4] = CudaResourceIntersections;
+	Resources[5] = CudaResourceColorOrtho;
+	Resources[6] = CudaResourceDepthOrtho;
+
+	bIsInitialized = true;
+}
diff --git a/Source/OptiX/Private/OptiXGeometry.cpp b/Source/OptiX/Private/OptiXGeometry.cpp
index ec657381107bba516c233ac7069fc389b889f005..bd9e0b259308d41c192066d85672290f0fd753d3 100644
--- a/Source/OptiX/Private/OptiXGeometry.cpp
+++ b/Source/OptiX/Private/OptiXGeometry.cpp
@@ -581,36 +581,6 @@ UOptiXProgram* UOptiXGeometry::GetIntersectionProgram()
 	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
diff --git a/Source/OptiX/Private/OptiXLaserComponent.cpp b/Source/OptiX/Private/OptiXLaserComponent.cpp
index ca13843f606914468fb1405ffaa42e9e75259f6e..1f0b3e2f40b4dbc4d090db87de2b71ee3fa86886 100644
--- a/Source/OptiX/Private/OptiXLaserComponent.cpp
+++ b/Source/OptiX/Private/OptiXLaserComponent.cpp
@@ -4,6 +4,7 @@
 #include "OptiXModule.h"
 
 #include "UObject/ConstructorHelpers.h"
+#include "StatsDefines.h"
 
 
 // Sets default values for this component's properties
@@ -158,6 +159,8 @@ void UOptiXLaserComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransfo
 
 void UOptiXLaserComponent::UpdateOptiXContextVariables()
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::UpdateOptiXContextVariables"))
+
 	check(IsInRenderingThread());
 
 	if (bUpdateQueued)
diff --git a/Source/OptiX/Private/OptiXLaserDetectorActor.cpp b/Source/OptiX/Private/OptiXLaserDetectorActor.cpp
index c3e75b437824297538fbf7205de4e6e0c0ff7673..75bbc9a556c27c15cfd639af7c2464493e610b8d 100644
--- a/Source/OptiX/Private/OptiXLaserDetectorActor.cpp
+++ b/Source/OptiX/Private/OptiXLaserDetectorActor.cpp
@@ -11,6 +11,7 @@
 
 #include "OptiXModule.h"
 #include "OptiXLaserActor.h"
+#include "StatsDefines.h"
 
 AOptiXLaserDetectorActor::AOptiXLaserDetectorActor(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -47,8 +48,10 @@ void AOptiXLaserDetectorActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
 
 void AOptiXLaserDetectorActor::Tick(float DeltaTime)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXLaserDetectorActor::Tick"))
+
 	Super::Tick(DeltaTime);
-	OnLaserTraceFinished();
+	//OnLaserTraceFinished();
 }
 
 void AOptiXLaserDetectorActor::Init()
@@ -89,6 +92,7 @@ void AOptiXLaserDetectorActor::Init()
 void AOptiXLaserDetectorActor::OnLaserTraceFinished()
 {
 	//UE_LOG(LogTemp, Warning, TEXT("lasertracefinished"));
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXLaserDetectorActor::OnLaserTraceFinished"))
 
 	if (bIsEnabled)
 	{
@@ -99,6 +103,7 @@ void AOptiXLaserDetectorActor::OnLaserTraceFinished()
 
 void AOptiXLaserDetectorActor::RenderDataToTarget()
 {		
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXLaserDetectorActor::RenderDataToTarget"))
 
 	// Let's try something else:
 
@@ -135,6 +140,8 @@ void AOptiXLaserDetectorActor::RenderDataToTarget()
 
 void AOptiXLaserDetectorActor::Clear()
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXLaserDetectorActor::Clear"))
+
 	uint32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
 
 	TArray<FColor> Black;
diff --git a/Source/OptiX/Private/OptiXLaserTargetComponent.cpp b/Source/OptiX/Private/OptiXLaserTargetComponent.cpp
index 3c565dbde114aa32382365d02ba2cd3714bae370..fa1780cac9c086b14f658e4899649595af6b2e66 100644
--- a/Source/OptiX/Private/OptiXLaserTargetComponent.cpp
+++ b/Source/OptiX/Private/OptiXLaserTargetComponent.cpp
@@ -8,6 +8,7 @@
 #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)
@@ -164,6 +165,7 @@ float UOptiXLaserTargetComponent::GetMaxFromBuffer()
 
 void UOptiXLaserTargetComponent::UpdateBufferData()
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXLaserTargetComponent::UpdateBufferData"))
 
 	check(IsInRenderingThread());
 
diff --git a/Source/OptiX/Private/OptiXLensComponent.cpp b/Source/OptiX/Private/OptiXLensComponent.cpp
index 7db0c253b0ce28b51d99e16a10e787a11b37f60d..68277c3b22019511e2e6d5eed4b077604c42c4e9 100644
--- a/Source/OptiX/Private/OptiXLensComponent.cpp
+++ b/Source/OptiX/Private/OptiXLensComponent.cpp
@@ -6,6 +6,7 @@
 
 
 #include "OptiXModule.h"
+#include "StatsDefines.h"
 
 UOptiXLensComponent::UOptiXLensComponent(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -44,6 +45,8 @@ void UOptiXLensComponent::BeginPlay()
 
 void UOptiXLensComponent::UpdateOptiXComponentVariables()
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXLensComponent::UpdateOptiXComponentVariables"))
+
 	check(IsInRenderingThread());
 
 
@@ -205,6 +208,7 @@ void UOptiXLensComponent::InitCubemap(FRHICommandListImmediate & RHICmdList)
 
 void UOptiXLensComponent::UpdateCubemap(FRHICommandListImmediate & RHICmdList)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXLensComponent::UpdateCubemap"))
 
 	UE_LOG(LogTemp, Display, TEXT("Updating Cubemap"));
 
@@ -389,11 +393,6 @@ void UOptiXLensComponent::MarkDirty()
 
 	UE_LOG(LogTemp, Display, TEXT("Marking Dirty"));
 
-
-	if (OptiXGeometry != nullptr)
-	{
-		OptiXGeometry->MarkDirty();
-	}
 	if (OptiXAcceleration != nullptr)
 	{
 		OptiXAcceleration->MarkDirty();
diff --git a/Source/OptiX/Private/OptiXObjectComponent.cpp b/Source/OptiX/Private/OptiXObjectComponent.cpp
index 12a9da996a981f25d5dab29c190d061eb90473cd..8bfff78f7b50aeaf0c90f3d97fbb8a9b7d428623 100644
--- a/Source/OptiX/Private/OptiXObjectComponent.cpp
+++ b/Source/OptiX/Private/OptiXObjectComponent.cpp
@@ -9,6 +9,7 @@
 #include "OptiXLaserActor.h"
 #include "OptiXTargetComponent.h"
 #include "OptiXModule.h"
+#include "StatsDefines.h"
 
 UOptiXObjectComponent::UOptiXObjectComponent(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -66,6 +67,8 @@ void UOptiXObjectComponent::RegisterOptiXComponent()
 
 void UOptiXObjectComponent::QueueOptiXContextUpdate()
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXObjectComponent::QueueOptiXContextUpdate"))
+
 	if (!bUpdateQueued)
 	{
 		FOptiXModule::Get().GetOptiXContextManager()->QueueComponentUpdate(this);
@@ -82,6 +85,8 @@ void UOptiXObjectComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
 
 void UOptiXObjectComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport/* = ETeleportType::None*/)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXObjectComponent::OnUpdateTransform"))
+
 	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
 
 	UpdateOptiXComponent();
@@ -323,6 +328,8 @@ void UOptiXCubemapComponent::SetUpdateQueued(bool UpdateQueued)
 
 void UOptiXCubemapComponent::RequestCubemapUpdate()
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXCubemapComponent::RequestCubemapUpdate"))
+
 	CaptureScene();
 	FOptiXModule::Get().GetOptiXContextManager()->RequestCubemapUpdate(this);
 }
diff --git a/Source/OptiX/Private/OptiXVRPawn.cpp b/Source/OptiX/Private/OptiXVRPawn.cpp
index 9a7358c59905f855b08d2b30902d85d36bfcc356..869b3d81896b32d81b1babc51531a2bbbb3f333b 100644
--- a/Source/OptiX/Private/OptiXVRPawn.cpp
+++ b/Source/OptiX/Private/OptiXVRPawn.cpp
@@ -7,6 +7,7 @@
 #include "PickupActorInterface.h"
 #include "OptiXModule.h"
 
+#include "StatsDefines.h"
 
 
 // Sets default values
@@ -27,6 +28,8 @@ void AOptiXVRPawn::BeginPlay()
 // Called every frame
 void AOptiXVRPawn::Tick(float DeltaTime)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::Tick"))
+
 	Super::Tick(DeltaTime);
 
 }
@@ -40,6 +43,8 @@ void AOptiXVRPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputCompone
 
 void AOptiXVRPawn::UpdateTranslation(UPrimitiveComponent* Interaction)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::UpdateTranslation"))
+
 	if (GrabbedLever == NULL)
 	{
 		return;
@@ -105,6 +110,7 @@ UMaterialInstanceDynamic* AOptiXVRPawn::GetMIDOrtho()
 
 void AOptiXVRPawn::RequestOrthoPass(const FMinimalViewInfo& ViewInfo)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::RequestOrthoPass"))
 
 	FSceneViewProjectionData ProjectionData;
 	ProjectionData.ViewOrigin = ViewInfo.Location;
@@ -123,6 +129,8 @@ void AOptiXVRPawn::RequestOrthoPass(const FMinimalViewInfo& ViewInfo)
 
 UStaticMeshComponent * AOptiXVRPawn::GetNearestMeshComponent(UPrimitiveComponent * Other)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::GetNearestMeshComponent"))
+
 	TArray<UPrimitiveComponent*> OverlappingComponents;
 	Other->GetOverlappingComponents(OverlappingComponents);
 
@@ -148,6 +156,7 @@ UStaticMeshComponent * AOptiXVRPawn::GetNearestMeshComponent(UPrimitiveComponent
 
 AActor * AOptiXVRPawn::GetActorNearHand(UPrimitiveComponent * Hand)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXVRPawn::GetActorNearHand"))
 	TArray<AActor*> OverlappingActors;
 	Hand->GetOverlappingActors(OverlappingActors);
 
diff --git a/Source/OptiX/Private/SelectableActorBase.cpp b/Source/OptiX/Private/SelectableActorBase.cpp
index ad331cddddcf0a42930d2bdd8f12b801cba27a07..d8ef4014198a59cf828610d16dcaf43cf4ec5aed 100644
--- a/Source/OptiX/Private/SelectableActorBase.cpp
+++ b/Source/OptiX/Private/SelectableActorBase.cpp
@@ -8,6 +8,7 @@
 #include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
 
 #include "OptiXVRPawn.h"
+#include "StatsDefines.h"
 
 ASelectableActorBase::ASelectableActorBase(const FObjectInitializer& ObjectInitializer)
 	: Super(ObjectInitializer)
@@ -377,7 +378,8 @@ 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();
 	{
@@ -483,6 +485,7 @@ void ASelectableActorBase::DeleteActor()
 
 void ASelectableActorBase::SetRodPosition(FVector TablePosition)
 {
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ASelectableActorBase::SetRodPosition"))
 
 	// Flip socket?
 	if (Socket->GetComponentLocation().Z > GetActorLocation().Z)
diff --git a/Source/OptiX/Private/cuda/box_intersect.cu b/Source/OptiX/Private/cuda/box_intersect.cu
new file mode 100644
index 0000000000000000000000000000000000000000..5085aa4320c33eac9cf9ae553ccf9070a6db8144
--- /dev/null
+++ b/Source/OptiX/Private/cuda/box_intersect.cu
@@ -0,0 +1,74 @@
+//------------------------------------------------------------------------------
+// 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/exception.cu b/Source/OptiX/Private/cuda/exception.cu
new file mode 100644
index 0000000000000000000000000000000000000000..a659a2ad5f93ad8199bf8f6b07b13a6161c9a40f
--- /dev/null
+++ b/Source/OptiX/Private/cuda/exception.cu
@@ -0,0 +1,33 @@
+//------------------------------------------------------------------------------
+// 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/frame_material.cu b/Source/OptiX/Private/cuda/frame_material.cu
new file mode 100644
index 0000000000000000000000000000000000000000..ed30232bca8f77163174630d4d64992dca991e95
--- /dev/null
+++ b/Source/OptiX/Private/cuda/frame_material.cu
@@ -0,0 +1,49 @@
+//------------------------------------------------------------------------------
+// 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/glass_iterative_camera.cu b/Source/OptiX/Private/cuda/glass_iterative_camera.cu
new file mode 100644
index 0000000000000000000000000000000000000000..d00726dd26d909997b3f9d7f24b43e2f1d327e47
--- /dev/null
+++ b/Source/OptiX/Private/cuda/glass_iterative_camera.cu
@@ -0,0 +1,76 @@
+/* 
+ * 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/glass_perspective_camera.cu b/Source/OptiX/Private/cuda/glass_perspective_camera.cu
new file mode 100644
index 0000000000000000000000000000000000000000..91ed1655d1bbdf504cd5803d9f0eb5db3946895c
--- /dev/null
+++ b/Source/OptiX/Private/cuda/glass_perspective_camera.cu
@@ -0,0 +1,146 @@
+/* 
+ * 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/Private/cuda/laser_target.cu b/Source/OptiX/Private/cuda/laser_target.cu
new file mode 100644
index 0000000000000000000000000000000000000000..088ec88eb2d8c8cd347739230037a997e20955a3
--- /dev/null
+++ b/Source/OptiX/Private/cuda/laser_target.cu
@@ -0,0 +1,79 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..a6d5695810e30579edff85c420bf13085f71380f
--- /dev/null
+++ b/Source/OptiX/Private/cuda/laser_target_material.cu
@@ -0,0 +1,60 @@
+//------------------------------------------------------------------------------
+// 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/lens_parametric.cu b/Source/OptiX/Private/cuda/lens_parametric.cu
new file mode 100644
index 0000000000000000000000000000000000000000..e81771f833fe2ccd150e7a1b2f102e8c6dc002b5
--- /dev/null
+++ b/Source/OptiX/Private/cuda/lens_parametric.cu
@@ -0,0 +1,110 @@
+//------------------------------------------------------------------------------
+// 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/normal_shader.cu b/Source/OptiX/Private/cuda/normal_shader.cu
new file mode 100644
index 0000000000000000000000000000000000000000..1902378a3097b0b7025329d4d3d8d03fd511b1db
--- /dev/null
+++ b/Source/OptiX/Private/cuda/normal_shader.cu
@@ -0,0 +1,46 @@
+/* 
+ * 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
new file mode 100644
index 0000000000000000000000000000000000000000..1f292e1dbdaadae8d8faf0bc5581ffd09d24c599
--- /dev/null
+++ b/Source/OptiX/Private/cuda/normal_shader_new.cu
@@ -0,0 +1,37 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..5085aa4320c33eac9cf9ae553ccf9070a6db8144
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/box_intersect.cu
@@ -0,0 +1,74 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..a659a2ad5f93ad8199bf8f6b07b13a6161c9a40f
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/exception.cu
@@ -0,0 +1,33 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..ed30232bca8f77163174630d4d64992dca991e95
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/frame_material.cu
@@ -0,0 +1,49 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..d00726dd26d909997b3f9d7f24b43e2f1d327e47
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/glass_iterative_camera.cu
@@ -0,0 +1,76 @@
+/* 
+ * 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
new file mode 100644
index 0000000000000000000000000000000000000000..e9b074b425807c8444d8f9881aef8c58ae186cab
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/glass_perspective_camera.cu
@@ -0,0 +1,146 @@
+/* 
+ * 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
new file mode 100644
index 0000000000000000000000000000000000000000..bd184b9159e5f24994be25a626dd4a433b5f39e5
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_caster.cu
@@ -0,0 +1,107 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..088ec88eb2d8c8cd347739230037a997e20955a3
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_target.cu
@@ -0,0 +1,79 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..a6d5695810e30579edff85c420bf13085f71380f
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/laser_target_material.cu
@@ -0,0 +1,60 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..cc35d606c6d32aa5124065e54b5ef61370cf8f62
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/lens_intersections.h
@@ -0,0 +1,175 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..e81771f833fe2ccd150e7a1b2f102e8c6dc002b5
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/lens_parametric.cu
@@ -0,0 +1,110 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..172acc7cf1b7144a3d05c1a4764678429812fc05
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/miss.cu
@@ -0,0 +1,33 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..1902378a3097b0b7025329d4d3d8d03fd511b1db
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/normal_shader.cu
@@ -0,0 +1,46 @@
+/* 
+ * 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
new file mode 100644
index 0000000000000000000000000000000000000000..1f292e1dbdaadae8d8faf0bc5581ffd09d24c599
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/normal_shader_new.cu
@@ -0,0 +1,37 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..8e6bfc66056e2eaa9d6791035c492e6f56bf0165
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/perspective_camera.cu
@@ -0,0 +1,117 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..8e1ef8b3c7f78a5fd5e814992e63654ad5c19b59
--- /dev/null
+++ b/Source/OptiX/Private/cuda/optical-bench-2020-backup/skybox.cu
@@ -0,0 +1,41 @@
+//------------------------------------------------------------------------------
+// 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
new file mode 100644
index 0000000000000000000000000000000000000000..418bcb36f53cd360d1e2ed5aa6c9fa93d2761c47
--- /dev/null
+++ b/Source/OptiX/Private/cuda/perspective_camera.cu
@@ -0,0 +1,150 @@
+//------------------------------------------------------------------------------
+// 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_ortho, , );
+
+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_ortho != 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 6968f60fc1913039d9868046b9e0f2d56b8e5e3c..96d8855a9ca2675cc2e4f692221cd62fd1c70fc1 100644
--- a/Source/OptiX/Private/cuda/prd.h
+++ b/Source/OptiX/Private/cuda/prd.h
@@ -36,14 +36,15 @@ struct PerRayData_radiance_iterative{
 };
 
 struct PerRayData_radiance{
-  float3	result;
-  float		hit_depth;
-  float		importance;
-  int		depth;
-  
-  int		miss;
-  int 		hit_lens;
-  int		last_lens_id;
+	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
 };
 
 #endif  // OPTICAL_BENCH_PRD_H_
diff --git a/Source/OptiX/Private/cuda/skybox.cu b/Source/OptiX/Private/cuda/skybox.cu
new file mode 100644
index 0000000000000000000000000000000000000000..a87efac8f05fe958f109d356c218c2fc45dd8034
--- /dev/null
+++ b/Source/OptiX/Private/cuda/skybox.cu
@@ -0,0 +1,44 @@
+//------------------------------------------------------------------------------
+// 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/Public/OptiXContext.h b/Source/OptiX/Public/OptiXContext.h
index 03ed1f73207191de24b6d29019b082a2656227b2..500342e92ab3b83e919c2b00d8c221ee8e1c0200 100644
--- a/Source/OptiX/Public/OptiXContext.h
+++ b/Source/OptiX/Public/OptiXContext.h
@@ -279,9 +279,6 @@ public:
 	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);
diff --git a/Source/OptiX/Public/OptiXContextManager.h b/Source/OptiX/Public/OptiXContextManager.h
index a76d4f0516ea452fa62749b51eba4e3d7b4e563b..75528d9269447fdb7eb3a3d04097a1816ac26c7a 100644
--- a/Source/OptiX/Public/OptiXContextManager.h
+++ b/Source/OptiX/Public/OptiXContextManager.h
@@ -16,6 +16,7 @@
 #include "OptiXLaserComponent.h"
 #include "OptiXLaserActor.h"
 #include "OptiXCameraActor.h"
+#include "StatsDefines.h"
 
 
 
@@ -248,6 +249,8 @@ private:
 
 	void InitOptiXComponents(FRHICommandListImmediate & RHICmdList)
 	{
+		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::InitOptiXComponents"))
+
 		// 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++)
 		{
@@ -261,6 +264,8 @@ private:
 
 	void UpdateOptiXComponentVariables()
 	{
+		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::UpdateOptiXComponentVariables"))
+
 		for (uint32 i = 0; i < 100 && !ComponentsToUpdateQueue.IsEmpty(); i++)
 		{
 			IOptiXComponentInterface* Component;
@@ -277,6 +282,8 @@ private:
 
 	void RemovePendingChildrenFromGroups()
 	{
+		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::RemovePendingChildrenFromGroups"))
+
 		for (uint32 i = 0; i < 100 && !GroupChildrenToRemoveQueue.IsEmpty(); i++)
 		{
 			TPair<optix::Group, uint32> Pair;
@@ -311,6 +318,8 @@ private:
 
 	void DestroyOptiXObjects()
 	{
+		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::DestroyOptiXObjects"))
+
 		for (uint32 i = 0; i < 100 && !AccelerationsToDeleteQueue.IsEmpty(); i++)
 		{
 			optix::Acceleration NativeObj;
@@ -489,6 +498,7 @@ private:
 	void UpdateRequestedCubemaps(FRHICommandListImmediate & RHICmdList)
 	{
 		// update only the first for now, shouldn't be more than 1 in queue anyway:
+		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::UpdateRequestedCubemaps"))
 
 		if (!CubemapComponentsToUpdateQueue.IsEmpty())
 		{
@@ -504,6 +514,7 @@ private:
 
 	void CleanupOptiXOnEnd()
 	{
+		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::CleanupOptiXOnEnd"))
 
 		UE_LOG(LogTemp, Display, TEXT("Starting Cleanup in Context Manager"));
 
@@ -704,13 +715,13 @@ private:
 	int32 Width;
 	int32 Height;
 
-	FTexture2DRHIRef OutputTextureColorRightRef;
-	FTexture2DRHIRef OutputTextureColorLeftRef;
-	FTexture2DRHIRef OutputTextureDepthRightRef;
-	FTexture2DRHIRef OutputTextureDepthLeftRef;
-	
-	FTexture2DRHIRef OutputTextureColorOrthoRef;
-	FTexture2DRHIRef OutputTextureDepthOrthoRef;
+	//FTexture2DRHIRef OutputTextureColorRightRef;
+	//FTexture2DRHIRef OutputTextureColorLeftRef;
+	//FTexture2DRHIRef OutputTextureDepthRightRef;
+	//FTexture2DRHIRef OutputTextureDepthLeftRef;
+	//
+	//FTexture2DRHIRef OutputTextureColorOrthoRef;
+	//FTexture2DRHIRef OutputTextureDepthOrthoRef;
 
 	TWeakObjectPtr<UTexture2D> OutputTexture;
 	TWeakObjectPtr<UTexture2D> DepthTexture;
@@ -720,6 +731,8 @@ private:
 	TWeakObjectPtr<UTexture2D> OutputTextureOrtho;
 	TWeakObjectPtr<UTexture2D> DepthTextureOrtho;
 
+	UTexture2D* TestTexture;
+
 	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterial;
 	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterialOrtho;
 	TWeakObjectPtr<UMaterial> RegularMaterial;
@@ -790,8 +803,9 @@ private:
 	cudaGraphicsResource* CudaResourceIntersections;
 	cudaGraphicsResource* CudaResourceColorOrtho;
 	cudaGraphicsResource* CudaResourceDepthOrtho;
-	void* CudaLinearMemoryDepth;
-	void* CudaLinearMemoryColor;
+
+	float* CudaLinearMemoryDepth;
+	float4* CudaLinearMemoryColor;
 	void* CudaLinearMemoryIntersections;
 	size_t Pitch; // fix me
 	size_t PitchLaser;
diff --git a/Source/OptiX/Public/OptiXGeometry.h b/Source/OptiX/Public/OptiXGeometry.h
index 08d20b4ac9b726a2e81159d162949670538e0a14..db967677ffc6d4804e45d01c6669530440e075cc 100644
--- a/Source/OptiX/Public/OptiXGeometry.h
+++ b/Source/OptiX/Public/OptiXGeometry.h
@@ -211,13 +211,7 @@ public:
 	UOptiXProgram* GetBoundingBoxProgram();
 
 	void SetIntersectionProgram(UOptiXProgram* Program);
-	UOptiXProgram* GetIntersectionProgram();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void MarkDirty();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	bool IsDirty();
+	UOptiXProgram* GetIntersectionProgram();	
 
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
 	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
diff --git a/Source/OptiX/Public/StatsDefines.h b/Source/OptiX/Public/StatsDefines.h
new file mode 100644
index 0000000000000000000000000000000000000000..04a54c3e11327d8ac475eb592d6527f98b802c18
--- /dev/null
+++ b/Source/OptiX/Public/StatsDefines.h
@@ -0,0 +1,4 @@
+#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 bb2277699bdc28c5a81305d90551220fa139c30d..71536edf23542ad3bc8897eb7bbe65b5da8e5545 100644
--- a/Source/ThirdParty/OptiXLibrary/OptiXLibrary.Build.cs
+++ b/Source/ThirdParty/OptiXLibrary/OptiXLibrary.Build.cs
@@ -40,25 +40,6 @@ 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");