Select Git revision
MainWindow.hpp
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);
}