Skip to content
Snippets Groups Projects
Select Git revision
  • d70232d3bd9abb4a5b930e70fdc7a70d05ecae75
  • master default protected
  • feature/refactor
  • 4.24
  • develop
  • Rendering
  • temp-optix-6
7 results

OptiXLensComponent.cpp

Blame
  • OptiXLensComponent.cpp 14.10 KiB
    // Fill out your copyright notice in the Description page of Project Settings.
    
    #include "OptiXLensComponent.h"
    
    #include "Runtime/Engine/Classes/Engine/TextureRenderTargetCube.h"
    
    
    #include "OptiXModule.h"
    
    UOptiXLensComponent::UOptiXLensComponent(const FObjectInitializer& ObjectInitializer)
    	: Super(ObjectInitializer)
    {
    	Radius1 = 0.8 * 100; // todo default values
    	Radius2 = 1.0 * 100;
    	LensRadius = 0.1 * 100;
    
    	LensType1 = ELensSideType::CONVEX;
    	LensType2 = ELensSideType::CONVEX;
    	LensThickness = 0.025 * 100;
    	CurrentWavelength = 450.0f;
    
    	// A little hacky but w/e
    	for (const TPair<FString, FGlassDefinition>& Pair : FOptiXModule::Get().GetGlassDefinitions())
    	{
    		GlassType = Pair.Key;
    		break;
    	}
    	
    }
    
    
    void UOptiXLensComponent::BeginPlay()
    {
    	Super::BeginPlay();
    
    
    	// do this on the game thread
    	// hook into WL update:
    	//UE_LOG(LogTemp, Display, TEXT("Begin Play on LensComponent, GameThread"));
    
    	FOptiXModule::Get().GetOptiXContextManager()->WavelengthChangedEvent.AddUFunction(this, "OnWavelengthChangedEvent");
    }
    
    
    void UOptiXLensComponent::UpdateOptiXComponentVariables()
    {
    	check(IsInRenderingThread());
    
    
    	OptiXGeometryInstance->SetFloat("radius", Radius1);
    	//UE_LOG(LogTemp, Display, TEXT("radius1 : %f"), Radius1);
    
    	OptiXGeometryInstance->SetFloat("radius2", Radius2);
    	//UE_LOG(LogTemp, Display, TEXT("radius2 : %f"), Radius2);
    
    	OptiXGeometryInstance->SetFloat("lensRadius", LensRadius);
    	//UE_LOG(LogTemp, Display, TEXT("lensradius : %f"), LensRadius);
    
    	OptiXGeometryInstance->SetFloat("halfCylinderLength", GetCylinderLength(LensThickness) / 2.0f);
    	//UE_LOG(LogTemp, Display, TEXT("halfCylinderLength : %f"), GetCylinderLength(LensThickness) / 2.0f);
    
    	OptiXGeometryInstance->SetInt("side1Type", static_cast<int32>(LensType1));
    	//UE_LOG(LogTemp, Display, TEXT("type1 : %i"), static_cast<int32>(LensType1));
    
    	OptiXGeometryInstance->SetInt("side2Type", static_cast<int32>(LensType2));
    	//UE_LOG(LogTemp, Display, TEXT("type2 : %i"), static_cast<int32>(LensType2));
    
    
    	double WL2 = FMath::Pow(CurrentWavelength / 1000.0, 2.0f);
    	FGlassDefinition Def = FOptiXModule::Get().GetGlassDefinitions()[GlassType];
    	//UE_LOG(LogTemp, Display, TEXT("Glass Def: %f, %f, %F"), Def.B.X, Def.B.Y, Def.B.Z);
    
    	float Index = FMath::Sqrt(1 +
    		Def.B.X * WL2 / (WL2 - Def.C.X) +
    		Def.B.Y * WL2 / (WL2 - Def.C.Y) +
    		Def.B.Z * WL2 / (WL2 - Def.C.Z));
    
    	OptiXMaterial->SetFloat("refraction_index", Index);
    
    	MarkDirty();
    }
    
    
    void UOptiXLensComponent::UpdateOptiXComponent()
    {
    	if (OptiXGeometry != nullptr && OptiXTransform != nullptr && OptiXAcceleration != nullptr)
    	{
    		FMatrix T = GetComponentToWorld().ToMatrixNoScale();
    		OptiXTransform->SetMatrix(T);
    		//OptiXAcceleration->MarkDirty();
    		OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
    		FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
    	}
    }
    
    void UOptiXLensComponent::InitOptiXGeometry()
    {
    	OptiXGeometry = OptiXContext->CreateGeometry();
    	OptiXGeometry->SetPrimitiveCount(1u);
    	UOptiXProgram* BB = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/lens_parametric.ptx", "bounds");
    	UOptiXProgram* IP = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/lens_parametric.ptx", "intersect");
    
    	OptiXGeometry->SetBoundingBoxProgram(BB);
    	OptiXGeometry->SetIntersectionProgram(IP);
    }
    
    void UOptiXLensComponent::InitOptiXMaterial()
    {
    	UOptiXProgram* CHPerspective = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/glass_perspective_camera.ptx", "closest_hit_radiance");
    	UOptiXProgram* CHIterative = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/glass_iterative_camera.ptx", "closest_hit_radiance");
    
    	OptiXMaterial = OptiXContext->CreateMaterial();
    	OptiXMaterial->SetClosestHitProgram(0, CHPerspective);
    	OptiXMaterial->SetClosestHitProgram(1, CHIterative);
    
    	OptiXMaterial->SetFloat("importance_cutoff", 1e-2f);
    	OptiXMaterial->SetFloat3D("cutoff_color", 0.035f, 0.102f, 0.169f);
    	OptiXMaterial->SetFloat("fresnel_exponent", 3.0f);
    	OptiXMaterial->SetFloat("fresnel_minimum", 0.1f);
    	OptiXMaterial->SetFloat("fresnel_maximum", 1.0f);
    	OptiXMaterial->SetFloat("refraction_index", 1.4f);
    
    	OptiXMaterial->SetFloat3D("refraction_color", 1.0f, 1.0f, 1.0f);
    	OptiXMaterial->SetFloat3D("reflection_color", 1.0f, 1.0f, 1.0f);
    
    	OptiXMaterial->SetInt("refraction_maxdepth", 10);
    	OptiXMaterial->SetInt("reflection_maxdepth", 5);
    
    	OptiXMaterial->SetFloat3D("extinction_constant", FMath::Loge(0.83f), FMath::Loge(0.83f), FMath::Loge(0.83f));
    
    	OptiXMaterial->SetInt("lens_id", OptiXCubemapId);
    
    }
    
    void UOptiXLensComponent::InitOptiXGroups()
    {
    	OptiXGeometryInstance = OptiXContext->CreateGeometryInstance(OptiXGeometry, OptiXMaterial);
    
    	OptiXGeometryInstance->SetFloat3D("center", 0.0f, 0.0f, 0.0f);
    
    	OptiXGeometryInstance->SetFloat3DVector("orientation", {0, 0, -1}); // TODO Why this vector?!?!
    
    
    	SetRadius1(Radius1);
    	SetRadius2(Radius2);
    	SetLensRadius(LensRadius);
    	SetThickness(LensThickness);
    	SetLensType1(LensType1);
    	SetLensType2(LensType2);
    	SetWavelength(CurrentWavelength); // min value
    
    	OptiXTransform = OptiXContext->CreateTransform();
    
    	FMatrix WorldTransform = GetComponentToWorld().ToMatrixNoScale();
    	OptiXTransform->SetMatrix(WorldTransform);
    
    	OptiXGeometryGroup = OptiXContext->CreateGeometryGroup();
    	OptiXGeometryGroup->AddChild(OptiXGeometryInstance);
    
    	OptiXAcceleration = OptiXContext->CreateAcceleration("NoAccel"); // Seems to be faster for now
    	//OptiXAcceleration->SetProperty("refit", "1");
    
    	OptiXGeometryGroup->SetAcceleration(OptiXAcceleration);
    
    	OptiXTransform->SetChild(OptiXGeometryGroup);
    
    
    	OptiXContext->GetGroup("top_object")->AddChild(OptiXTransform);
    	MarkDirty();
    }
    
    void UOptiXLensComponent::InitCubemap(FRHICommandListImmediate & RHICmdList)
    {
    	UE_LOG(LogTemp, Display, TEXT("Init Cubemap"));
    
    	//OptiXContext->SetBuffer("skyboxBuffer", CubemapBuffer);
    
    	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);
    	CubemapSampler->SetFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
    	
    
    	UpdateCubemap(RHICmdList);
    
    
    	// Writes the variable into the input buffer
    	FOptiXModule::Get().GetOptiXContextManager()->AddCubemapToBuffer(OptiXCubemapId, CubemapSampler->GetId());
    	UE_LOG(LogTemp, Display, TEXT("Finished Init Cubemap"));
    
    }
    
    void UOptiXLensComponent::UpdateCubemap(FRHICommandListImmediate & RHICmdList)
    {
    
    	UE_LOG(LogTemp, Display, TEXT("Updating Cubemap"));
    
    
    	int32 X = 1024; // todo hardcoded
    	int32 Y = X;
    
    	TArray<TArray<FColor>> SurfaceDataCube;
    	SurfaceDataCube.SetNumZeroed(6);
    
    	//TArray<FLinearColor> SD;
    
    	optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->MapNative());
    
    	FTextureRenderTargetCubeResource* RenderTargetCube = static_cast<FTextureRenderTargetCubeResource*>(CubeRenderTarget->GetRenderTargetResource());
    
    	FIntRect InRectCube = FIntRect(0, 0, RenderTargetCube->GetSizeXY().X, RenderTargetCube->GetSizeXY().Y);
    	FReadSurfaceDataFlags FlagsCube0(RCM_UNorm, CubeFace_PosX);
    	FReadSurfaceDataFlags FlagsCube1(RCM_UNorm, CubeFace_NegX);
    	FReadSurfaceDataFlags FlagsCube2(RCM_UNorm, CubeFace_PosY);
    	FReadSurfaceDataFlags FlagsCube3(RCM_UNorm, CubeFace_NegY);
    	FReadSurfaceDataFlags FlagsCube4(RCM_UNorm, CubeFace_PosZ);
    	FReadSurfaceDataFlags FlagsCube5(RCM_UNorm, CubeFace_NegZ);
    
    	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[0], FlagsCube0);
    	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[1], FlagsCube1);
    	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[2], FlagsCube2);
    	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[3], FlagsCube3);
    	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[4], FlagsCube4);
    	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[5], FlagsCube5);
    
    	uint32 MemSize = (X * Y * sizeof(FColor));
    	FMemory::Memcpy(BufferData, SurfaceDataCube[0].GetData(), MemSize); // front
    	FMemory::Memcpy(BufferData + X * Y * 1, SurfaceDataCube[1].GetData(), MemSize); // back
    	FMemory::Memcpy(BufferData + X * Y * 2, SurfaceDataCube[2].GetData(), MemSize); // 
    	FMemory::Memcpy(BufferData + X * Y * 3, SurfaceDataCube[3].GetData(), MemSize); // 
    	FMemory::Memcpy(BufferData + X * Y * 4, SurfaceDataCube[4].GetData(), MemSize); // 
    	FMemory::Memcpy(BufferData + X * Y * 5, SurfaceDataCube[5].GetData(), MemSize); //
    
    	CubemapBuffer->Unmap();
    
    	UE_LOG(LogTemp, Display, TEXT("Finished Updating Cubemap"));
    
    
    }
    
    
    void UOptiXLensComponent::CleanOptiXComponent()
    {
    	if(OptiXContext != NULL && OptiXContext->GetGroup("top_object") != NULL)
    		OptiXContext->GetGroup("top_object")->RemoveChild(OptiXTransform);
    	OptiXTransform = nullptr;
    
    	Super::CleanOptiXComponent();
    	OptiXGeometryGroup = nullptr;
    
    }
    
    void UOptiXLensComponent::InitFromData(const FLensData& Data)
    {
    	SetLensRadius(Data.LensRadius * 10);
    	SetRadius1(Data.Radius1 * 10);
    	SetRadius2(Data.Radius2 * 10);
    	SetThickness(Data.Thickness);
    	SetLensType1(Data.LensTypeSide1);
    	SetLensType2(Data.LensTypeSide2);
    	SetGlassType(Data.GlassType);
    }
    
    void UOptiXLensComponent::SetThickness(float Thickness)
    {
    	UE_LOG(LogTemp, Display, TEXT("Setting Thickness: %f"), Thickness);
    	LensThickness = Thickness;
    	QueueOptiXContextUpdate();
    	if(IsInGameThread())
    		OnLensThicknessChanged.Broadcast(LensThickness);
    }
    
    float UOptiXLensComponent::GetThickness() const
    {
    	// No silly conversions...
    	return LensThickness;
    }
    
    void UOptiXLensComponent::SetRadius1(float Radius)
    {
    	UE_LOG(LogTemp, Display, TEXT("Setting Radius 1: %f"), Radius);
    	Radius1 = Radius;
    	QueueOptiXContextUpdate();
    }
    
    float UOptiXLensComponent::GetRadius1() const
    {
    	return Radius1;
    }
    
    void UOptiXLensComponent::SetRadius2(float Radius)
    {
    
    	UE_LOG(LogTemp, Display, TEXT("Setting Radius 2: %f"), Radius);
    	Radius2 = Radius;
    	QueueOptiXContextUpdate();
    }
    
    float UOptiXLensComponent::GetRadius2() const
    {
    	return Radius2;
    }
    
    void UOptiXLensComponent::SetLensRadius(float Radius)
    {
    	UE_LOG(LogTemp, Display, TEXT("Setting Lens Radius: %f"), Radius);
    	LensRadius = Radius;
    	QueueOptiXContextUpdate();
    	if (IsInGameThread())
    		OnLensRadiusChanged.Broadcast(Radius);
    }
    
    float UOptiXLensComponent::GetLensRadius() const
    {
    	return LensRadius;
    }
    
    void UOptiXLensComponent::SetLensType1(ELensSideType Type)
    {
    	UE_LOG(LogTemp, Display, TEXT("Setting Lens Side 1 Type: %i"), static_cast<int>(Type));
    
    	LensType1 = Type;
    	// Recalculate Thickness and set new half cylinder length
    	//SetThickness(LensThickness);
    	QueueOptiXContextUpdate();
    }
    
    ELensSideType UOptiXLensComponent::GetLensType1() const
    {
    	return LensType1;
    }
    
    void UOptiXLensComponent::SetLensType2(ELensSideType Type)
    {
    	UE_LOG(LogTemp, Display, TEXT("Setting Lens Side 2 Type: %i"), static_cast<int>(Type));
    
    	LensType2 = Type;
    	// Recalculate Thickness and set new half cylinder length
    	//SetThickness(LensThickness);
    	QueueOptiXContextUpdate();
    }
    
    ELensSideType UOptiXLensComponent::GetLensType2() const
    {
    	return LensType2;
    }
    
    void UOptiXLensComponent::SetGlassType(FString Type)
    {
    	UE_LOG(LogTemp, Display, TEXT("Setting Glass Type: %s"), *Type);
    
    	GlassType = Type;
    	SetWavelength(CurrentWavelength); // ???
    	QueueOptiXContextUpdate();
    }
    
    FString UOptiXLensComponent::GetGlassType() const
    {
    	return GlassType;
    }
    
    void UOptiXLensComponent::SetWavelength(float WL)
    {
    	UE_LOG(LogTemp, Display, TEXT("Setting new WL in lens: %s"), *GetName());
    	CurrentWavelength = WL;
    	QueueOptiXContextUpdate();
    }
    
    float UOptiXLensComponent::GetWavelength() const
    {
    	return CurrentWavelength;
    }
    
    void UOptiXLensComponent::MarkDirty()
    {
    
    	UE_LOG(LogTemp, Display, TEXT("Marking Dirty"));
    
    
    	if (OptiXGeometry != nullptr)
    	{
    		OptiXGeometry->MarkDirty();
    	}
    	if (OptiXAcceleration != nullptr)
    	{
    		OptiXAcceleration->MarkDirty();
    	}
    
    	//manager_->TopAccelerationMarkDirty();
    	UOptiXAcceleration* TopAccel = OptiXContext->GetGroup("top_object")->GetAcceleration();
    	if (TopAccel != nullptr)
    	{
    		TopAccel->MarkDirty(); // This should never be null, but check anyway
    	}
    
    	//RecalculateBoundingBox(); // TODO
    
    }
    
    
    float UOptiXLensComponent::GetCylinderLength(float Thickness) const
    {
    	// Halfsphere thickness
    	float HalfThickness1;
    	float HalfThickness2;
    
    	// Side 1
    	if (LensType1 == ELensSideType::PLANE)
    	{
    		HalfThickness1 = 0;
    	}
    	else
    	{
    		HalfThickness1 = Radius1 - FMath::Sqrt(-LensRadius * LensRadius + Radius1 * Radius1);
    		if (LensType1 == ELensSideType::CONCAVE)
    		{
    			HalfThickness1 *= -1;
    		}
    	}
    
    	// Side 2
    	if (LensType2 == ELensSideType::PLANE)
    	{
    		HalfThickness2 = 0;
    	}
    	else
    	{
    		HalfThickness2 = Radius2 - FMath::Sqrt(-LensRadius * LensRadius + Radius2 * Radius2);
    		if (LensType2 == ELensSideType::CONCAVE)
    		{
    			HalfThickness2 *= -1;
    		}
    	}
    	return Thickness - HalfThickness1 - HalfThickness2;
    }
    
    
    void UOptiXLensComponent::RecalculateBoundingBox()
    {
    
    	// Do we even need this? Seems like it was just used for phoenix stuff TODO
    	return;
    
    	// TODO Shouldn't have to call the getter here - this should just be the actor rotation transform?
    	/*FVector Orientation = OptiXGeometry->GetFloat3D("orientation");
    	float HalfThickness1;	
    	LensType1 == ELensSideType::CONVEX ? HalfThickness1 = Radius1 - FMath::Sqrt(-LensRadius * LensRadius + Radius1 * Radius1) : HalfThickness1 = 0;
    
    	float HalfThickness2;
    	LensType2 == ELensSideType::CONVEX ? HalfThickness2 = Radius2 - FMath::Sqrt(-LensRadius * LensRadius + Radius2 * Radius2) : HalfThickness2 = 0;
    */
    	// TODO
    
    }
    
    TArray<FString> UOptiXLensComponent::GetGlassDefinitionNames()
    {
    	TArray<FString> Names;
    
    	for (const TPair<FString, FGlassDefinition>& Pair : FOptiXModule::Get().GetGlassDefinitions())
    	{
    		Names.Add(Pair.Key);
    	}
    
    	return Names;
    }
    
    void UOptiXLensComponent::OnWavelengthChangedEvent(float WL)
    {
    	SetWavelength(WL);
    }