diff --git a/Source/InstancedMeshLineRendering/InstancedMeshLineRendering.Build.cs b/Source/InstancedMeshLineRendering/InstancedMeshLineRendering.Build.cs index 3b05bab63b8f0731f987ad4fabd2e4a924bc8b9d..e5c8687e7f777d27cb18191b0dc9e6393a83c51a 100644 --- a/Source/InstancedMeshLineRendering/InstancedMeshLineRendering.Build.cs +++ b/Source/InstancedMeshLineRendering/InstancedMeshLineRendering.Build.cs @@ -37,8 +37,7 @@ public class InstancedMeshLineRendering : ModuleRules { "CoreUObject", "Engine", - "Slate", - "SlateCore", + "RenderCore" // ... add private dependencies that you statically link with here ... } ); diff --git a/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp b/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp index 247356b1ccdfed6d77209320c36640967a3bb6ec..3be69d7e47b585606e686ba7d5da8d1c301e4532 100644 --- a/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp +++ b/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp @@ -9,6 +9,19 @@ UGPUInstancedLineComponent::UGPUInstancedLineComponent(const FObjectInitializer& ObjectInitializer) { + NumCustomDataFloats = 5; + + CurrentTextureMarker = FIntPoint(0, 0); + CurrentTextureIndex = 0, + NextFreeId = 0; + + TextureWidth = 1024; + TextureHeight = 1024; + + //PrimaryComponentTick.bCanEverTick = true; + //bTickInEditor = true; + //bAutoActivate = true; + SetWorldTransform(FTransform::Identity); SetUsingAbsoluteLocation(true); @@ -26,27 +39,10 @@ UGPUInstancedLineComponent::UGPUInstancedLineComponent(const FObjectInitializer& SetMaterial(0, LineMaterial); - UMaterialInterface* LineMaterialInterface = LoadObject<UMaterialInterface>(NULL, TEXT("/InstancedMeshLineRendering/DynamicLineMaterial.DynamicLineMaterial"), NULL, LOAD_None, NULL); - DynamicLineMaterial = UMaterialInstanceDynamic::Create(LineMaterialInterface, GetTransientPackage()); - check(DynamicLineMaterial); - - - // three color values + width + 1 texture index value - // r | g | b | w | i_T - NumCustomDataFloats = 5; - - CurrentTextureMarker = FIntPoint(0, 0); - CurrentTextureIndex = 0, - NextFreeId = 0; - - TextureWidth = 2048; - TextureHeight = 2048; - + LineMaterialInterface = LoadObject<UMaterialInterface>(NULL, TEXT("/InstancedMeshLineRendering/DynamicLineMaterial.DynamicLineMaterial"), NULL, LOAD_None, NULL); + //DynamicLineMaterial = UMaterialInstanceDynamic::Create(LineMaterialInterface, GetTransientPackage()); + SetMaterial(0, DynamicLineMaterial); SetMobility(EComponentMobility::Static); - - - //DynamicLineMaterial = nullptr; - //PositionTexture = nullptr; } UGPUInstancedLineComponent::~UGPUInstancedLineComponent() @@ -89,68 +85,35 @@ void UGPUInstancedLineComponent::UpdateWholeTexture() } void UGPUInstancedLineComponent::Init() -{ - if(PositionTexture != nullptr) +{ + if (PositionTexture == nullptr) { - UE_LOG(LogLineRendering, Error, TEXT("UGPUInstancedLineComponent::Init PositionTexture already exists!")); + UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Creating Texture")); + PositionTexture = UTexture2D::CreateTransient(TextureWidth, TextureHeight, PF_A32B32G32R32F); + //// Allocate the texture RHI + PositionTexture->UpdateResource(); + UpdateWholeTexture(); } - UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Creating Texture")); - PositionTexture = UTexture2D::CreateTransient(TextureWidth, TextureHeight, PF_A32B32G32R32F); - // Allocate the texture RHI - PositionTexture->UpdateResource(); - if (DynamicLineMaterial == nullptr) // FOR WHATEVER REASON I HAVE NO IDEA { - UE_LOG(LogLineRendering, Fatal, TEXT("UGPUInstancedLineComponent::Init MID was nullptr!")); - } - else - { - UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Setting MID")); - + //UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init MID was nullptr!")); + DynamicLineMaterial = UMaterialInstanceDynamic::Create(LineMaterialInterface, GetTransientPackage()); SetMaterial(0, DynamicLineMaterial); - DynamicLineMaterial->SetTextureParameterValue("PositionTexture", PositionTexture); - DynamicLineMaterial->SetScalarParameterValue("TextureWidth", TextureWidth); - } + //check(DynamicLineMaterial); - //UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init Resetting Data")); - //LineMap.Empty(); - //LinearLineData.Empty(); - //NextFreeId = 0; - //CurrentTextureIndex = 0; - //CurrentTextureMarker = FIntPoint(0, 0); - //ClearInstances(); + //DynamicLineMaterial = CreateAndSetMaterialInstanceDynamic(0); + //DynamicLineMaterial->SetTextureParameterValue("PositionTexture", PositionTexture); + //DynamicLineMaterial->SetScalarParameterValue("TextureWidth", TextureWidth); + } - //RegisterSerializedEditorLines(); + DynamicLineMaterial->SetTextureParameterValue("PositionTexture", PositionTexture); + DynamicLineMaterial->SetScalarParameterValue("TextureWidth", TextureWidth); + //UpdateWholeTexture(); bIsInitialized = true; - - //// Add serialized lines to be rendered immediately - pretty sure this could and should be done differently. - //for (FEditorLineData& EditorLine : EditorLines) - //{ - // AddLineFromEditorData(EditorLine); - //} - - // Update the texture - - // Theoretically we could serialize the texture as well, but that seems like too much work - UpdateWholeTexture(); } -//void UGPUInstancedLineComponent::RegisterSerializedEditorLines() -//{ -// -// // Here's to hoping the respective id field doesn't get serialized... -// -// for (FEditorLineData& EditorLine : EditorLines) -// { -// if(EditorLine.RespectiveLineId == -1 || !LineMap.Contains(EditorLine.RespectiveLineId)) -// { -// AddLineFromEditorData(EditorLine); -// } -// } -//} - void UGPUInstancedLineComponent::UpdateAllEditorLines() { for (const FEditorLineData& EditorLine : EditorLines) @@ -235,14 +198,11 @@ FUpdateTextureRegion2D* UGPUInstancedLineComponent::CalculateTextureRegions(cons void UGPUInstancedLineComponent::BeginPlay() { Super::BeginPlay(); - - // todo don't think this is needed here - //RegisterSerializedEditorLines(); - //Init(); - if(!bIsInitialized) + if(!PositionTexture) { - UE_LOG(LogLineRendering, Fatal, TEXT("UGPUInstancedLineComponent::BeginPlay: FATAL ERROR - Component is not initialized on BeginPlay!")); + UE_LOG(LogLineRendering, Warning, TEXT("UGPUInstancedLineComponent::BeginPlay: Component is not initialized on BeginPlay, Initializing...")); + Init(); } } @@ -250,15 +210,16 @@ void UGPUInstancedLineComponent::BeginPlay() void UGPUInstancedLineComponent::PostInitProperties() { Super::PostInitProperties(); - if (FApp::CanEverRender() && !HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) - UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::PostInitProperties IF")); - + //if (FApp::CanEverRender() && !HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) + //UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::PostInitProperties IF")); } #if WITH_EDITOR void UGPUInstancedLineComponent::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) { - if (PropertyChangedEvent.Property != NULL && bIsInitialized) + Init(); + + if (PropertyChangedEvent.Property != NULL) { if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UGPUInstancedLineComponent, EditorLines)) { @@ -419,6 +380,7 @@ void UGPUInstancedLineComponent::PostEditChangeChainProperty(FPropertyChangedCha void UGPUInstancedLineComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { + Init(); const FName PropertyName = PropertyChangedEvent.GetPropertyName(); if (PropertyChangedEvent.Property != NULL) @@ -444,34 +406,65 @@ void UGPUInstancedLineComponent::OnUpdateTransform(EUpdateTransformFlags UpdateT { SetWorldTransform(FTransform::Identity); } + +TStructOnScope<FActorComponentInstanceData> UGPUInstancedLineComponent::GetComponentInstanceData() const +{ + TStructOnScope<FActorComponentInstanceData> InstanceData; +#if WITH_EDITOR + InstanceData.InitializeAs<FUGPUInstancedLineComponentInstanceData>(this); + FUGPUInstancedLineComponentInstanceData* LineInstanceData = InstanceData.Cast<FUGPUInstancedLineComponentInstanceData>(); + + //LineInstanceData->PositionTexture = PositionTexture; + //LineInstanceData->DynamicMaterial = DynamicLineMaterial; + //LineInstanceData->LineMap = LineMap; + +#endif + return InstanceData; +} #endif +void UGPUInstancedLineComponent::ApplyComponentInstanceData(FUGPUInstancedLineComponentInstanceData* ComponentInstanceData) +{ +#if WITH_EDITOR + //check(ComponentInstanceData); + //if(ComponentInstanceData->PositionTexture != nullptr) + // PositionTexture = ComponentInstanceData->PositionTexture; + //if (ComponentInstanceData->DynamicMaterial != nullptr) + //{ + // DynamicLineMaterial = ComponentInstanceData->DynamicMaterial; + // DynamicLineMaterial->SetTextureParameterValue("PositionTexture", PositionTexture); + // DynamicLineMaterial->SetScalarParameterValue("TextureWidth", TextureWidth); + // SetMaterial(0, DynamicLineMaterial); + //} + //if (ComponentInstanceData->LineMap.Num() > 0) + // LineMap = ComponentInstanceData->LineMap; + + +#endif +} + // Doesn't do anything yet, just as a testing function to see execution order on Unreal startup. void UGPUInstancedLineComponent::PostLoad() { Super::PostLoad(); - UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::PostLoad")); - if (FApp::CanEverRender() && !HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) - { - UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::PostLoad IF")); - - if (!bIsInitialized) - Init(); - } + //UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::PostLoad")); + //if (FApp::CanEverRender() && !IsTemplate()) + //{ + //DynamicLineMaterial = UMaterialInstanceDynamic::Create(LineMaterialInterface, this); + //SetMaterial(0, DynamicLineMaterial); + //} } // Doesn't do anything yet, just as a testing function to see execution order on Unreal startup. void UGPUInstancedLineComponent::OnComponentCreated() { Super::OnComponentCreated(); - UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::OnComponentCreated")); - if (FApp::CanEverRender() && !HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) - { - UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::OnComponentCreated IF")); - - if (!bIsInitialized) - Init(); - } + //UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::OnComponentCreated")); + //if (FApp::CanEverRender() && !IsTemplate()) + //{ + // DynamicLineMaterial = UMaterialInstanceDynamic::Create(LineMaterialInterface, this); + // SetMaterial(0, DynamicLineMaterial); + //} } void UGPUInstancedLineComponent::BeginDestroy() @@ -483,9 +476,6 @@ void UGPUInstancedLineComponent::BeginDestroy() void UGPUInstancedLineComponent::Serialize(FArchive& Ar) { Super::Serialize(Ar); - - - } void UGPUInstancedLineComponent::ReserveMemory(int32 NumberOfSegments, int32 NumberOfLines) @@ -493,10 +483,7 @@ void UGPUInstancedLineComponent::ReserveMemory(int32 NumberOfSegments, int32 Num const int32 Total = NumberOfSegments * NumberOfLines; PreAllocateInstancesMemory(Total); LineMap.Reserve(Total); - LinearLineData.Reserve(NumberOfLines * (NumberOfSegments + 1)); - - // TODO: Texture size - + LinearLineData.Reserve(NumberOfLines * (NumberOfSegments + 1)); } bool UGPUInstancedLineComponent::ResizeTexture(int32 Width, int32 Height) diff --git a/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h b/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h index c9e7e5a4ba6a417fabd1a1281c99891b09a9e989..c026ebfdfb7af0bd04ff7a55362c2a6f40ebc0d4 100644 --- a/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h +++ b/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h @@ -6,27 +6,6 @@ #include "Components/InstancedStaticMeshComponent.h" #include "GPUInstancedLineComponent.generated.h" -/** - * - */ - -//typedef TPair<FVector, TTuple<int32, int32, int32>> GPULineSegment; - -// Pair of InstanceId and LinearData index. -// - - - -// LineArray that contains indices into the instance list and the linear data. - -typedef TPair<int32, int32> GPULineIndices; - -typedef TArray<GPULineIndices> GPULineArray; - -// Maps a LineId to a LineArray. -typedef TMap<int32, GPULineArray> GPULinesMap; - - USTRUCT(BlueprintType) struct FEditorPoint @@ -62,7 +41,7 @@ struct FEditorLineData UPROPERTY(EditAnywhere) FColor Color; - UPROPERTY() + UPROPERTY(VisibleAnywhere) int32 RespectiveLineId = -1; FEditorLineData() @@ -116,7 +95,7 @@ class INSTANCEDMESHLINERENDERING_API UGPUInstancedLineComponent : public UInstan public: UGPUInstancedLineComponent(const FObjectInitializer& ObjectInitializer); - ~UGPUInstancedLineComponent(); + virtual ~UGPUInstancedLineComponent(); virtual void BeginPlay() override; @@ -125,10 +104,14 @@ public: virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) override; virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; // need this for the widget as for some godforsaken reason the Chain event doesn't fire... // This is ABSURDLY hacky - virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override; - + virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override; #endif + virtual TStructOnScope<FActorComponentInstanceData> GetComponentInstanceData() const override; + + /** Applies the cached component instance data to a newly blueprint constructed component. */ + virtual void ApplyComponentInstanceData(struct FUGPUInstancedLineComponentInstanceData* ComponentInstanceData); + virtual void PostLoad() override; virtual void OnComponentCreated() override; virtual void BeginDestroy() override; @@ -148,7 +131,6 @@ private: } } - void UpdateWholeTexture(); void Init(); @@ -162,6 +144,9 @@ public: // todo void ReleaseData(); + void UpdateWholeTexture(); + + /** * Reserves internal memory for a given amount of Lines and Segments per Line. */ @@ -458,17 +443,20 @@ public: UPROPERTY(BlueprintReadOnly, EditAnywhere) int32 TextureHeight; - UPROPERTY(transient) + UPROPERTY(Transient) UMaterialInstanceDynamic* DynamicLineMaterial; UPROPERTY(EditAnywhere, DisplayName = "Lines", meta = (MakeEditWidget = true, EditFixedOrder)) TArray<FEditorLineData> EditorLines; -private: - + UPROPERTY() + UMaterialInterface* LineMaterialInterface; + UPROPERTY() TMap<int32, FGPULineArray> LineMap; +//private: + UPROPERTY() TArray<FVector4> LinearLineData; @@ -487,5 +475,51 @@ private: UPROPERTY() FIntPoint CurrentTextureMarker; + UPROPERTY(Transient) bool bIsInitialized = false; +}; + + +/** Helper class used to preserve texture pointer across blueprint reinstancing */ +USTRUCT() +struct FUGPUInstancedLineComponentInstanceData : public FSceneComponentInstanceData +{ + GENERATED_BODY() +public: + FUGPUInstancedLineComponentInstanceData() = default; + FUGPUInstancedLineComponentInstanceData(const UGPUInstancedLineComponent* InComponent) + : FSceneComponentInstanceData(InComponent) + , PositionTexture(InComponent->PositionTexture), LineMap(InComponent->LineMap) + {} + virtual ~FUGPUInstancedLineComponentInstanceData() = default; + + virtual bool ContainsData() const override + { + return true; + } + + virtual void ApplyToComponent(UActorComponent* Component, const ECacheApplyPhase CacheApplyPhase) override + { + Super::ApplyToComponent(Component, CacheApplyPhase); + CastChecked<UGPUInstancedLineComponent>(Component)->ApplyComponentInstanceData(this); + } + + virtual void AddReferencedObjects(FReferenceCollector& Collector) override + { + Super::AddReferencedObjects(Collector); + Collector.AddReferencedObject(PositionTexture); + } + +public: + + + + //UPROPERTY() + UTexture2D* PositionTexture; + + //UPROPERTY() + UMaterialInstanceDynamic* DynamicMaterial; + + //UPROPERTY() + TMap<int32, FGPULineArray> LineMap; }; \ No newline at end of file