diff --git a/Content/LaserOffsetMaterial.uasset b/Content/LaserOffsetMaterial.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..e68f40395f82230da3b352a22927aae7592df0f4
Binary files /dev/null and b/Content/LaserOffsetMaterial.uasset differ
diff --git a/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp b/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp
index 612ff057db825b6b3ec1acdd05cb393c4b711e08..1ec0d34099f84ee1c6870128e537ec15b5e6b0a9 100644
--- a/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp
+++ b/Source/OptiX/Private/LineInstancedStaticMeshComponent.cpp
@@ -41,25 +41,6 @@ ULineInstancedStaticMeshComponent::ULineInstancedStaticMeshComponent(const FObje
 void ULineInstancedStaticMeshComponent::BeginPlay()
 {
 	Super::BeginPlay();
-
-	// 1 for now, could be #Lines if we want multicolored lines
-	ColorLUT = UTexture2D::CreateTransient(1, LineNumber);
-	ColorLUT->UpdateResource();
-
-	DynamicLaserMaterial = UMaterialInstanceDynamic::Create(GetMaterial(0), this);
-	SetMaterial(0, DynamicLaserMaterial);
-
-	DynamicLaserMaterial->SetTextureParameterValue("LUT", ColorLUT);
-	DynamicLaserMaterial->SetScalarParameterValue("Segments", SegmentsPerLine);
-	DynamicLaserMaterial->SetScalarParameterValue("Lines", LineNumber);
-
-	TextureRegion = MakeUnique<FUpdateTextureRegion2D>();
-	TextureRegion->Height = LineNumber;
-	TextureRegion->Width = 1;
-	TextureRegion->SrcX = 0;
-	TextureRegion->SrcY = 0;
-	TextureRegion->DestX = 0;
-	TextureRegion->DestY = 0;
 }
 
 FPrimitiveSceneProxy* ULineInstancedStaticMeshComponent::CreateSceneProxy()
@@ -126,30 +107,60 @@ void ULineInstancedStaticMeshComponent::InitLineSegments(int32 NumberOfLines, in
 
 			int32 Index = AddInstanceWorldSpace(LineTransform);
 		}
-	}	
+	}
 
-	DynamicLaserMaterial->SetScalarParameterValue("Segments", SegmentsPerLine);
-	DynamicLaserMaterial->SetScalarParameterValue("Lines", LineNumber);
+	if (DynamicLaserMaterial != NULL)
+	{
+		DynamicLaserMaterial->SetScalarParameterValue("Segments", SegmentsPerLine);
+		DynamicLaserMaterial->SetScalarParameterValue("Lines", LineNumber);
 
 
-	TextureRegion->Height = LineNumber;
-	TextureRegion->Width = 1;
+		TextureRegion->Height = LineNumber;
+		TextureRegion->Width = 1;
+
+	}
 }
 
 void  ULineInstancedStaticMeshComponent::UpdateLUT(TArray<FColor> ColorMap)
 {
-	ColorArray = ColorMap;
+	if (DynamicLaserMaterial != NULL)
+	{
+
+		ColorArray = ColorMap;
+
+		ColorLUT = UTexture2D::CreateTransient(1, LineNumber);
+		ColorLUT->UpdateResource();
+
+		UE_LOG(LogTemp, Display, TEXT("ColorLUT | LineNumber (%i | %i "), ColorLUT->GetSizeX(), LineNumber);
+
+		ColorLUT->UpdateTextureRegions(0, 1, TextureRegion.Get(), sizeof(FColor), sizeof(FColor), (uint8*)ColorArray.GetData());
 
+		DynamicLaserMaterial->SetTextureParameterValue("LUT", ColorLUT);
+		UE_LOG(LogTemp, Display, TEXT("#Colors: %i"), ColorArray.Num());
+	}
+
+}
+
+void ULineInstancedStaticMeshComponent::SetLaserMaterial(UMaterialInstanceDynamic * Mat)
+{
+	// 1 for now, could be #Lines if we want multicolored lines
 	ColorLUT = UTexture2D::CreateTransient(1, LineNumber);
 	ColorLUT->UpdateResource();
 
-	UE_LOG(LogTemp, Display, TEXT("ColorLUT | LineNumber (%i | %i "), ColorLUT->GetSizeX(), LineNumber);
-
-	ColorLUT->UpdateTextureRegions(0, 1, TextureRegion.Get(), sizeof(FColor), sizeof(FColor), (uint8*)ColorArray.GetData());
+	DynamicLaserMaterial = Mat;
+	SetMaterial(0, DynamicLaserMaterial);
 
 	DynamicLaserMaterial->SetTextureParameterValue("LUT", ColorLUT);
-	UE_LOG(LogTemp, Display, TEXT("#Colors: %i"), ColorArray.Num());
-
+	/*DynamicLaserMaterial->SetScalarParameterValue("Segments", SegmentsPerLine);
+	DynamicLaserMaterial->SetScalarParameterValue("Lines", LineNumber);
+*/
+	TextureRegion = MakeUnique<FUpdateTextureRegion2D>();
+	TextureRegion->Height = LineNumber;
+	TextureRegion->Width = 1;
+	TextureRegion->SrcX = 0;
+	TextureRegion->SrcY = 0;
+	TextureRegion->DestX = 0;
+	TextureRegion->DestY = 0;
 }
 
 void ULineInstancedStaticMeshComponent::UpdateLines(float NewLineWidth)
diff --git a/Source/OptiX/Private/OptiXContext.cpp b/Source/OptiX/Private/OptiXContext.cpp
index b327d08dc35199fbd4365d083e996f6405efa1ff..1c1ed34d2cef79c6b5020a0d5a04a20d94ae727f 100644
--- a/Source/OptiX/Private/OptiXContext.cpp
+++ b/Source/OptiX/Private/OptiXContext.cpp
@@ -1155,6 +1155,24 @@ UOptiXBuffer * UOptiXContext::CreateBufferUByte3D(uint8 Type, int32 Width, int32
 	return BufferPtr;
 }
 
+UOptiXBuffer * UOptiXContext::CreateOutputBufferIntersections(int32 Width)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, Width));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+
 UOptiXBuffer * UOptiXContext::CreateOutputBufferColor(int32 Width, int32 Height)
 {
 	UOptiXBuffer* BufferPtr = nullptr;
diff --git a/Source/OptiX/Private/OptiXContextManager.cpp b/Source/OptiX/Private/OptiXContextManager.cpp
index 157941f95173f8a97e023002a295defa6568f17e..43436c30df5660c517ffbaa74d2180bc311c7935 100644
--- a/Source/OptiX/Private/OptiXContextManager.cpp
+++ b/Source/OptiX/Private/OptiXContextManager.cpp
@@ -44,7 +44,6 @@ FOptiXContextManager::FOptiXContextManager(const FAutoRegister& AutoRegister)
 	: FSceneViewExtensionBase(AutoRegister)
 {
 	UE_LOG(LogTemp, Display, TEXT("FOptiXContextManager, is in rendering thread: %i"), static_cast<int32>(IsInRenderingThread()));
-	TextureRegion = FUpdateTextureRegion2D();
 
 	RTXOn = 0;
 
@@ -271,9 +270,9 @@ void FOptiXContextManager::LaunchLaser()
 {
 	if (/*bSceneChanged && */ bLaserIsInitialized && !CVarDisableLaserTrace.GetValueOnRenderThread())
 	{
-		if (LaserComponent.IsValid())
+		if (LaserActor.IsValid())
 		{
-			LaserComponent->UpdateOptiXContextVariables();
+			LaserActor->OptiXLaserComponent->UpdateOptiXContextVariables();
 		}
 
 		// uuuuuuuuh
@@ -285,53 +284,82 @@ void FOptiXContextManager::LaunchLaser()
 		bIsTracing.AtomicSet(false);
 
 
-		optix::float4* DataLaser = static_cast<optix::float4*>(LaserOutputBuffer->MapNative(0, RT_BUFFER_MAP_READ));
-		//FMemory::Memcpy(IntersectionData.GetData(), DataLaser, LaserOutputBuffer->GetSize1D() * sizeof(FVector4));
-
-		if (DataLaser == nullptr)
+		if (Resources[4] == NULL)
 		{
-			UE_LOG(LogTemp, Error, TEXT("Error when trying to map laser output buffer: Got NULL"));
 			return;
 		}
 
-		optix::float4 invData = optix::make_float4(0, -1, 0, 1);
+		cudaGraphicsMapResources(1, Resources + 4, 0);
+		//PrintLastCudaError("cudaGraphicsMapResources");
 
-		uint32 N = 0;
-		// Loop over indices
-		for (uint32 i = 0; i < 50 * 50; ++i)
+		if (CudaResourceIntersections == NULL)
 		{
-			if (DataLaser[i * 20 * 2].x == invData.x && DataLaser[i * 20 * 2].y == invData.y && DataLaser[i * 20 * 2].z == invData.z)
-			{
-				continue;
-			}
-
-			//if (!PreviousLaserResults.IsValidIndex(N))
-			//{
-			//	PreviousLaserResults.AddDefaulted(1);
-			//	PreviousLaserResults[N].AddZeroed(20 * 2);
-			//}
-
-
-			TPair<uint32, TArray<FVector>> QueueItem;
-			QueueItem.Key = N;
-			N++;
-			bool bEnqueue = false;
-			for (uint32 Intersection = i * 20 * 2; Intersection < i * 20 * 2 + 20 * 2; ++Intersection)
-			{
-				FVector Pos(DataLaser[Intersection].x, DataLaser[Intersection].y, DataLaser[Intersection].z);
-				//if (Pos != PreviousLaserResults[N][Intersection - i * 20 * 2])
-				//{
-				//	PreviousLaserResults[N][Intersection - i * 20 * 2] = Pos;
-				//	bEnqueue = true;
-				//}
-				QueueItem.Value.Add(Pos);
-			}
-			//N++;
-			//if(bEnqueue)
-			LaserIntersectionQueue.Enqueue(QueueItem);
+			cudaGraphicsUnmapResources(1, Resources + 4, 0);
+			return;
 		}
 
-		LaserOutputBuffer->Unmap();
+		cudaArray *CuArrayIntersections;
+		cudaGraphicsSubResourceGetMappedArray(&CuArrayIntersections, CudaResourceIntersections, 0, 0);
+		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
+
+		cudaMemcpy2DToArray(
+			CuArrayIntersections, // dst array
+			0, 0,    // offset
+			CudaLinearMemoryColor, LaserBufferSize * 4 * sizeof(float),       // src
+			LaserBufferSize * 4 * sizeof(float), 1, // extent
+			cudaMemcpyDeviceToDevice); // kind
+		//PrintLastCudaError("cudaMemcpy2DToArray");
+
+
+		cudaGraphicsUnmapResources(1, Resources + 4, 0);
+
+		//optix::float4* DataLaser = static_cast<optix::float4*>(LaserOutputBuffer->MapNative(0, RT_BUFFER_MAP_READ));
+		////FMemory::Memcpy(IntersectionData.GetData(), DataLaser, LaserOutputBuffer->GetSize1D() * sizeof(FVector4));
+
+		//if (DataLaser == nullptr)
+		//{
+		//	UE_LOG(LogTemp, Error, TEXT("Error when trying to map laser output buffer: Got NULL"));
+		//	return;
+		//}
+
+		//optix::float4 invData = optix::make_float4(0, -1, 0, 1);
+
+		//uint32 N = 0;
+		//// Loop over indices
+		//for (uint32 i = 0; i < 50 * 50; ++i)
+		//{
+		//	if (DataLaser[i * 20 * 2].x == invData.x && DataLaser[i * 20 * 2].y == invData.y && DataLaser[i * 20 * 2].z == invData.z)
+		//	{
+		//		continue;
+		//	}
+
+		//	//if (!PreviousLaserResults.IsValidIndex(N))
+		//	//{
+		//	//	PreviousLaserResults.AddDefaulted(1);
+		//	//	PreviousLaserResults[N].AddZeroed(20 * 2);
+		//	//}
+
+
+		//	TPair<uint32, TArray<FVector>> QueueItem;
+		//	QueueItem.Key = N;
+		//	N++;
+		//	bool bEnqueue = false;
+		//	for (uint32 Intersection = i * 20 * 2; Intersection < i * 20 * 2 + 20 * 2; ++Intersection)
+		//	{
+		//		FVector Pos(DataLaser[Intersection].x, DataLaser[Intersection].y, DataLaser[Intersection].z);
+		//		//if (Pos != PreviousLaserResults[N][Intersection - i * 20 * 2])
+		//		//{
+		//		//	PreviousLaserResults[N][Intersection - i * 20 * 2] = Pos;
+		//		//	bEnqueue = true;
+		//		//}
+		//		QueueItem.Value.Add(Pos);
+		//	}
+		//	//N++;
+		//	//if(bEnqueue)
+		//	LaserIntersectionQueue.Enqueue(QueueItem);
+		//}
+
+		//LaserOutputBuffer->Unmap();
 
 		bSceneChanged.AtomicSet(false);
 		LaserTraceFinishedEvent.Broadcast();
@@ -530,13 +558,25 @@ void FOptiXContextManager::InitRendering()
 
 	UE_LOG(LogTemp, Display, TEXT("Created the Textures"));
 
+	// Laser Texture
+	LaserIntersectionTexture = UTexture2D::CreateTransient(50, 20, 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/LaserMaterialOffset.LaserMaterialOffset'"));
+	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)
@@ -551,9 +591,6 @@ void FOptiXContextManager::InitRendering()
 		DynamicMaterial->SetTextureParameterValue("DepthRight", DepthTexture.Get());
 		DynamicMaterial->SetTextureParameterValue("TextureLeft", OutputTexture2.Get());
 		DynamicMaterial->SetTextureParameterValue("DepthLeft", DepthTexture2.Get());
-
-
-
 	}
 	else
 	{
@@ -574,10 +611,6 @@ void FOptiXContextManager::InitRendering()
 
 void FOptiXContextManager::InitBuffers()
 {
-
-	//UE_LOG(OptiXPluginCameraActor, Display, TEXT("Initializing output buffers with dims: %i, %i"), Width, Height);
-
-
 	OutputBuffer = OptiXContext->CreateOutputBufferColor(Width, Height);
 	OutputDepthBuffer = OptiXContext->CreateOutputBufferDepth(Width, Height);
 
@@ -660,7 +693,8 @@ void FOptiXContextManager::InitLaser()
 
 	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->CreateBuffer(RT_BUFFER_OUTPUT, RT_FORMAT_FLOAT4, LaserBufferSize);
+	LaserOutputBuffer = OptiXContext->CreateOutputBufferIntersections(LaserBufferSize);
 	LaserOutputBuffer->AddToRoot();
 	OptiXContext->SetBuffer("result_laser", LaserOutputBuffer.Get());
 
@@ -812,7 +846,6 @@ void FOptiXContextManager::InitCUDADX()
 	Width = Width;
 	Height = Height;
 
-
 	OutputTextureDepthLeftRef = ((FTexture2DResource*)DepthTexture2->Resource)->GetTexture2DRHI();
 
 	// Depth Left
@@ -849,25 +882,15 @@ void FOptiXContextManager::InitCUDADX()
 	ID3D11Texture2D* D3D11ColorRightTexture = static_cast<ID3D11Texture2D*>(OutputTextureColorRightRef->GetNativeResource());
 	D3D11ColorRightTexture->GetDesc(&DescColorRight);
 
-	//Desc.Width = Width;
-	//Desc.Height = Height;
-	//Desc.MipLevels = 1;
-	//Desc.ArraySize = 1;
-	//Desc.Format = DXGI_FORMAT_R16_FLOAT;
-	//Desc.SampleDesc.Count = 1;
-	//Desc.Usage = D3D11_USAGE_DEFAULT;
-	//Desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
 
-	//if (FAILED(D3DDevice->CreateTexture2D(&Desc, NULL, &D3D11Texture)))
-	//{
-	//	UE_LOG(LogTemp, Fatal, TEXT("FAILED"));
-	//}
+	//// Intersections
+	LaserIntersectionTextureRef = ((FTexture2DResource*)LaserIntersectionTexture->Resource)->GetTexture2DRHI();
 
-
-	// Register the new texture with cuda
-	//cudaGraphicsD3D11RegisterResource(&InteropTexture.CudaResource, InteropTexture.D3D11Texture, cudaGraphicsRegisterFlagsNone);
-	//cudaMallocPitch(&InteropTexture.CudaLinearMemory, &InteropTexture.Pitch, InteropTexture.Width * sizeof(optix::uchar4), InteropTexture.Height);
-	//cudaMemset(InteropTexture.CudaLinearMemory, 1, InteropTexture.Pitch * InteropTexture.Height);
+	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);
@@ -882,6 +905,8 @@ void FOptiXContextManager::InitCUDADX()
 	cudaGraphicsD3D11RegisterResource(&CudaResourceColorRight, D3D11ColorRightTexture, cudaGraphicsRegisterFlagsNone);
 	PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
 
+	cudaGraphicsD3D11RegisterResource(&CudaResourceIntersections, D3D11IntersectionTexture, cudaGraphicsRegisterFlagsNone);
+	PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
 
 	// Allocate the buffer memory
 	//cudaMallocPitch(&CudaLinearMemoryDepth, &Pitch, Width * sizeof(float), Height);
@@ -891,6 +916,8 @@ void FOptiXContextManager::InitCUDADX()
 	cudaMalloc(&CudaLinearMemoryColor, Width * Height * 4 * sizeof(float));
 	PrintLastCudaError("cudaMalloc");
 
+	cudaMalloc(&CudaLinearMemoryIntersections, LaserBufferSize * 4 * sizeof(float));
+	PrintLastCudaError("cudaMalloc");
 
 	//cudaMallocPitch(&CudaLinearMemoryColorRight, &Pitch, Width * sizeof(optix::uchar4), Height);
 	//PrintLastCudaError("cudaMallocPitch");
@@ -900,6 +927,8 @@ void FOptiXContextManager::InitCUDADX()
 
 	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));
@@ -909,6 +938,7 @@ void FOptiXContextManager::InitCUDADX()
 	Resources[1] = CudaResourceColorLeft;
 	Resources[2] = CudaResourceDepthRight;
 	Resources[3] = CudaResourceColorRight;
+	Resources[4] = CudaResourceIntersections;
 
 	bIsInitialized = true;
 
diff --git a/Source/OptiX/Private/OptiXLaserActor.cpp b/Source/OptiX/Private/OptiXLaserActor.cpp
index bcdf94d49cdb2560a960191c96f83251a6245d97..9ac19d0d521c4fb66978721ee6c05ac13843113b 100644
--- a/Source/OptiX/Private/OptiXLaserActor.cpp
+++ b/Source/OptiX/Private/OptiXLaserActor.cpp
@@ -60,6 +60,9 @@ void AOptiXLaserActor::BeginPlay()
 {
 	Super::BeginPlay();
 
+	FOptiXModule::Get().GetOptiXContextManager()->SetActiveLaserActor(this);
+
+
 	//FActorSpawnParameters SpawnInfo;
 	//SpawnInfo.Owner = this;
 	//MultiLineActorRef = GetWorld()->SpawnActor<AMultiLineActor>(GetActorLocation(), GetActorRotation(), SpawnInfo);
diff --git a/Source/OptiX/Private/OptiXLaserComponent.cpp b/Source/OptiX/Private/OptiXLaserComponent.cpp
index 2ca7f05627b7f7f056384b274fb8d02231c8d5ed..f4ef461ffd351d7cae8c92a23aa94edfaa1f6743 100644
--- a/Source/OptiX/Private/OptiXLaserComponent.cpp
+++ b/Source/OptiX/Private/OptiXLaserComponent.cpp
@@ -133,7 +133,6 @@ void UOptiXLaserComponent::BeginPlay()
 {
 	Super::BeginPlay();
 	Init();
-	FOptiXModule::Get().GetOptiXContextManager()->SetActiveLaserComponent(this);
 }
 
 void UOptiXLaserComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
diff --git a/Source/OptiX/Public/LineInstancedStaticMeshComponent.h b/Source/OptiX/Public/LineInstancedStaticMeshComponent.h
index 0cc83b3013d8ab7b8b242ffbe070e59c2c8ee08c..c899ee3638d42bfa8a8abb5d7476cebcea984760 100644
--- a/Source/OptiX/Public/LineInstancedStaticMeshComponent.h
+++ b/Source/OptiX/Public/LineInstancedStaticMeshComponent.h
@@ -34,6 +34,8 @@ public:
 
 	void UpdateLUT(TArray<FColor> ColorMap);
 
+	void SetLaserMaterial(UMaterialInstanceDynamic* Mat);
+
 public:
 
 	UPROPERTY(BlueprintReadWrite, Category = OptiX)
diff --git a/Source/OptiX/Public/OptiXContext.h b/Source/OptiX/Public/OptiXContext.h
index 70d9ac0fca270d34a45699d60bfc0f6c6252166e..47080534857124439c361bddbc215f68ed3d4ea3 100644
--- a/Source/OptiX/Public/OptiXContext.h
+++ b/Source/OptiX/Public/OptiXContext.h
@@ -334,6 +334,9 @@ public:
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
 	UOptiXBuffer* CreateOutputBufferDepth(int32 Width, int32 Height);
 
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateOutputBufferIntersections(int32 Width);
+
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
 	UOptiXBuffer* CreateInputBufferFloat(int32 Width);
 
diff --git a/Source/OptiX/Public/OptiXContextManager.h b/Source/OptiX/Public/OptiXContextManager.h
index 70271d647b0279a2fa6d4ba8d63cddf4e0fcf192..74e3d6d6c3b1c9a487ff239e48af4eb776708d22 100644
--- a/Source/OptiX/Public/OptiXContextManager.h
+++ b/Source/OptiX/Public/OptiXContextManager.h
@@ -14,6 +14,7 @@
 #include "OptiXContext.h"
 #include "OptiXObjectComponent.h"
 #include "OptiXLaserComponent.h"
+#include "OptiXLaserActor.h"
 #include "OptiXCameraActor.h"
 
 
@@ -135,9 +136,17 @@ public:
 		CubemapComponentsToUpdateQueue.Enqueue(Component);
 	}
 
-	void SetActiveLaserComponent(UOptiXLaserComponent* Component)
+	void SetActiveLaserActor(AOptiXLaserActor* Laser)
 	{
-		LaserComponent = Component;
+		LaserActor = Laser;
+		if (LaserMaterialDynamic.IsValid())
+		{
+			LaserActor->SetLaserMaterial(LaserMaterialDynamic.Get());
+		}
+		else
+		{
+			UE_LOG(LogTemp, Error, TEXT("LaserMaterialDynamic is invalid!"));
+		}
 	}
 
 	void SetActiveCameraActor(AOptiXPlayerCameraManager* Cam)
@@ -577,7 +586,8 @@ private:
 	TQueue<IOptiXComponentInterface*> ComponentsToUpdateQueue;
 	TQueue<UOptiXCubemapComponent*> CubemapComponentsToUpdateQueue;
 
-	TWeakObjectPtr<UOptiXLaserComponent> LaserComponent;
+	TWeakObjectPtr<AOptiXLaserActor> LaserActor;
+
 	TWeakObjectPtr<AOptiXPlayerCameraManager> CameraActor;
 
 	// OptiX Objects to be kept in the context manager, TODO triple check that the GC doesn't nab them.
@@ -614,7 +624,7 @@ private:
 
 	// Rendering Part
 
-	FUpdateTextureRegion2D TextureRegion;
+	//FUpdateTextureRegion2D TextureRegion;
 
 	//UTextureCube* TextureCube;
 
@@ -641,6 +651,13 @@ private:
 	// Laser stuff
 	// ---------------------------------------------------------------------------------------------------
 
+	FTexture2DRHIRef LaserIntersectionTextureRef;
+
+	TWeakObjectPtr<UTexture2D> LaserIntersectionTexture;
+	TWeakObjectPtr<UMaterial> LaserMaterial;
+	TWeakObjectPtr<UMaterialInstanceDynamic> LaserMaterialDynamic;
+
+
 public:
 
 	TQueue<TPair<uint32, TArray<FVector>>> LaserIntersectionQueue;
@@ -687,9 +704,12 @@ private:
 	cudaGraphicsResource* CudaResourceDepthRight;
 	cudaGraphicsResource* CudaResourceColorLeft;
 	cudaGraphicsResource* CudaResourceColorRight;
+	cudaGraphicsResource* CudaResourceIntersections;
 	void* CudaLinearMemoryDepth;
 	void* CudaLinearMemoryColor;
+	void* CudaLinearMemoryIntersections;
 	size_t Pitch; // fix me
+	size_t PitchLaser;
 
-	cudaGraphicsResource *Resources[4];
+	cudaGraphicsResource *Resources[5];
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXLaserActor.h b/Source/OptiX/Public/OptiXLaserActor.h
index 685d355b44a684aa87d835dcac2db50e5b597485..8315088ffb8ec14454e17948c247e3a9f339d9d7 100644
--- a/Source/OptiX/Public/OptiXLaserActor.h
+++ b/Source/OptiX/Public/OptiXLaserActor.h
@@ -43,6 +43,11 @@ public:
 	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXActor")
 	//void InitInstancedMeshData();
 
+	void SetLaserMaterial(UMaterialInstanceDynamic* DynamicLaserMaterial)
+	{
+		LineInstancedStaticMeshComponent->SetLaserMaterial(DynamicLaserMaterial);
+	}
+
 public:
 
 	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = OptiX)