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

LineInstancedStaticMeshComponent.cpp

Blame
  • LineInstancedStaticMeshComponent.cpp 7.40 KiB
    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "LineInstancedStaticMeshComponent.h"
    
    #include "Components/InstancedStaticMeshComponent.h"
    #include "Runtime/Engine/Private/InstancedStaticMesh.h"
    #include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
    #include "UObject/ConstructorHelpers.h"
    
    #include "Runtime/Engine/Classes/Engine/Texture2D.h"
    
    
    #include "OptiXModule.h"
    #include "OptiXContextManager.h"
    
    
    ULineInstancedStaticMeshComponent::ULineInstancedStaticMeshComponent(const FObjectInitializer& ObjectInitializer)
    	: Super(ObjectInitializer)
    {
    
    	UE_LOG(LogTemp, Display, TEXT("ULineInstancedStaticMeshComponent Constructor"));
    
    
    	SetGenerateOverlapEvents(false);
    
    	static ConstructorHelpers::FObjectFinder<UStaticMesh>LineMeshAsset(TEXT("StaticMesh'/OptiX/Laser/cylinder.cylinder'"));
    	UStaticMesh* LineAsset = LineMeshAsset.Object;
    	SetStaticMesh(LineAsset);
    
    	SetRenderCustomDepth(true);
    	SetCastShadow(false);
    	SetCollisionEnabled(ECollisionEnabled::NoCollision);
    	SetCullDistance(10000);
    	SetBoundsScale(1000); // Prevent culling due to usage of worldpositionoffset
    
    	SegmentsPerLine = 20;
    	LineNumber = 16;
    
    }
    
    void ULineInstancedStaticMeshComponent::BeginPlay()
    {
    	Super::BeginPlay();
    }
    
    FPrimitiveSceneProxy* ULineInstancedStaticMeshComponent::CreateSceneProxy()
    {
    
    	FPrimitiveSceneProxy* Proxy = Super::CreateSceneProxy();
    
    	if (!PerInstanceRenderData.IsValid() || PerInstanceSMData.Num() < 1 )
    	{
    		return Proxy;
    	}
    
    	//check(IsInGameThread());
    
    	//bool bSupportsVertexHalfFloat = GVertexElementTypeSupport.IsSupported(VET_Half2);
    	//int32 NumInstances = PerInstanceSMData.Num();
    	int32 NumInstancesRenderData = PerInstanceRenderData->InstanceBuffer_GameThread->GetNumInstances();
    	
    
    	for (int32 Index = 0; Index < NumInstancesRenderData; ++Index)
    	{
    		int32 RenderIndex = InstanceReorderTable.IsValidIndex(Index) ? InstanceReorderTable[Index] : Index;
    		if (RenderIndex == INDEX_NONE)
    		{
    			// could be skipped by density settings
    			continue;
    		}
    
    		FMatrix Transform;
    		PerInstanceRenderData->InstanceBuffer_GameThread->GetInstanceTransform(RenderIndex, Transform);
    		PerInstanceRenderData->InstanceBuffer_GameThread->SetInstance(RenderIndex, Transform, static_cast<float>(RenderIndex));
    	}
    
    	return Proxy;
    }
    
    // todo currently copies the array, save a reference/ptr instead
    void ULineInstancedStaticMeshComponent::InitLineSegments(TArray<int32> Indices, int32 NumberOfSegmentsPerLine, float LineW)
    {
    
    	ClearInstances();
    	
    	LaserIndices = Indices;
    
    	LineNumber = LaserIndices.Num();
    	SegmentsPerLine = NumberOfSegmentsPerLine;
    	LineWidth = LineW;
    
    	for (int32 Line = 0; Line < LineNumber; Line++)
    	{
    		for (int32 Segment = 0; Segment < SegmentsPerLine; Segment++)
    		{
    			FTransform LineTransform;
    
    			LineTransform.SetScale3D({ 1, 1, 1 });
    			LineTransform.SetLocation(GetComponentLocation());
    
    			// Rotation - align z to point towards End:
    
    			LineTransform.SetRotation(FQuat::Identity);
    
    			if (LineTransform.ContainsNaN())
    			{
    				UE_LOG(LogTemp, Fatal, TEXT("Line Transform contains NaNs!"));
    			}
    
    			int32 Index = AddInstanceWorldSpace(LineTransform);
    			UE_LOG(LogTemp, Display, TEXT("Line Instance Index: %i"), Index);
    		}
    	}
    
    	UE_LOG(LogTemp, Display, TEXT("Created #%i Lines with #%i Segments."), LineNumber, SegmentsPerLine);
    
    
    	if (DynamicLaserMaterial != NULL)
    	{
    		DynamicLaserMaterial->SetScalarParameterValue("Segments", SegmentsPerLine);
    		DynamicLaserMaterial->SetScalarParameterValue("Lines", LineNumber);
    
    
    		TextureRegion->Height = LineNumber;
    		TextureRegion->Width = 1;
    
    		LaserIndicesFloat.Empty();
    		LaserIndicesFloat.SetNumZeroed(LineNumber);
    
    		for (int32 i = 0; i < LineNumber; i++)
    		{
    			LaserIndicesFloat[i] = static_cast<float>(LaserIndices[i]);
    		}
    
    		IndexMap = UTexture2D::CreateTransient(1, LineNumber, EPixelFormat::PF_R32_FLOAT);
    		IndexMap->UpdateResource();
    		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);
    
    	}
    }
    
    void  ULineInstancedStaticMeshComponent::UpdateLUT(TArray<FColor> ColorMap)
    {
    	if (DynamicLaserMaterial != NULL)
    	{
    
    		ColorArray = ColorMap;
    
    		// Store the actual laser index in the alpha component of the LUT - bit hacky but should do the trick for now.
    			
    
    		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, EPixelFormat::PF_R32_FLOAT);
    	ColorLUT->UpdateResource();
    
    	IndexMap = UTexture2D::CreateTransient(1, LineNumber, EPixelFormat::PF_R32_FLOAT);
    	IndexMap->UpdateResource();
    
    	DynamicLaserMaterial = Mat;
    	SetMaterial(0, DynamicLaserMaterial);
    
    	DynamicLaserMaterial->SetTextureParameterValue("LUT", ColorLUT);
    	DynamicLaserMaterial->SetTextureParameterValue("IndexMap", IndexMap);
    	/*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)
    {
    	LineWidth = NewLineWidth;
    
    	for (int32 i = 0; i < 50 * 50; ++i) // until queue is empty
    	{
    		if (FOptiXModule::Get().GetOptiXContextManager()->LaserIntersectionQueue.IsEmpty()) break;
    
    		TPair<uint32, TArray<FVector>> QueueItem;
    		FOptiXModule::Get().GetOptiXContextManager()->LaserIntersectionQueue.Dequeue(QueueItem);
    		int32 Index = QueueItem.Key;
    
    		FVector PrevIntersection(0, 0, 0);
    
    		bool bIsDirty = true;
    
    		for (int32 Intersection = 0; Intersection < SegmentsPerLine * 2; Intersection += 2)
    		{
    			int32 TransformIndex = Index * SegmentsPerLine + Intersection / 2; // should be safe
    			bIsDirty = true;
    			FTransform LineTransform;
    			FVector Start = QueueItem.Value[Intersection];
    			FVector End = QueueItem.Value[Intersection + 1];
    
    			float D = FVector::Distance(Start, End);
    			float DScaled = D / 100.0;
    			float Width = LineWidth;
    			if (D == 0)
    			{
    				Width = 0; // Set scale to 0 if it shouldn't be drawn
    			}
    
    			LineTransform.SetScale3D({ Width, Width, DScaled });
    			LineTransform.SetLocation(Start);
    
    			// Rotation - align z to point towards End:
    			FQuat Rot = FRotationMatrix::MakeFromZ(End - Start).ToQuat();
    
    			if (D == 0)
    			{
    				Rot = FRotationMatrix::Identity.ToQuat();
    			}
    
    			LineTransform.SetRotation(Rot);
    
    			FTransform OldTransform;
    			GetInstanceTransform(TransformIndex, OldTransform, true);
    
    			if (OldTransform.Equals(LineTransform))
    			{
    				bIsDirty = false;
    			}
    
    			if (LineTransform.ContainsNaN())
    			{
    				UE_LOG(LogTemp, Fatal, TEXT("Line Transform contains NaNs!"));
    			}
    
    			UpdateInstanceTransform(TransformIndex, LineTransform, true, bIsDirty, true);
    			TransformIndex++;
    		}
    	}
    }