diff --git a/Content/DynamicLineMaterial.uasset b/Content/DynamicLineMaterial.uasset index edbb6625eeb1a6e53b2cc00d07ffb9c7a1ca2aa3..26f025290ed78a74a384cd2da2d1cabe3817a43b 100644 Binary files a/Content/DynamicLineMaterial.uasset and b/Content/DynamicLineMaterial.uasset differ diff --git a/Content/line_subdivided.uasset b/Content/line_subdivided.uasset new file mode 100644 index 0000000000000000000000000000000000000000..9176a669bab265b7ae855bd320b742438e2563d5 Binary files /dev/null and b/Content/line_subdivided.uasset differ diff --git a/Content/line_subdivided2.uasset b/Content/line_subdivided2.uasset new file mode 100644 index 0000000000000000000000000000000000000000..f13825e8639ccaf1ffa02ac8a8a0aed1d28acac0 Binary files /dev/null and b/Content/line_subdivided2.uasset differ diff --git a/Content/line_subdivided3.uasset b/Content/line_subdivided3.uasset new file mode 100644 index 0000000000000000000000000000000000000000..86d57bbf6c0d259ba0cf08e557cc86e8667c115d Binary files /dev/null and b/Content/line_subdivided3.uasset differ diff --git a/Content/line_subdivided5.uasset b/Content/line_subdivided5.uasset new file mode 100644 index 0000000000000000000000000000000000000000..6739970c818bfdb7bc0ac6f3a237dd496ee07f6d Binary files /dev/null and b/Content/line_subdivided5.uasset differ diff --git a/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp b/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp index 291a0c2c28c4fa57a0c0dae04cef349ec6b2010a..c9bb355e58c833783fb1e6fddea5edb786d21d31 100644 --- a/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp +++ b/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp @@ -61,11 +61,6 @@ UGPUInstancedLineComponent::~UGPUInstancedLineComponent() // Not implemented yet because the data structure isn't clear yet. void UGPUInstancedLineComponent::ReleaseData() { - //LineMap.Empty(); - //LinearLineData.Empty(); - //NextFreeId = 0; - //CurrentTextureMarker.X = 0; - //CurrentTextureMarker.Y = 0; } void UGPUInstancedLineComponent::UpdateWholeTexture() const @@ -92,10 +87,18 @@ void UGPUInstancedLineComponent::UpdateWholeTexture() const }); } +FLinearColor UGPUInstancedLineComponent::GetLineColor(int32 LineId) +{ + const float R = PerInstanceSMCustomData[LineMap[LineId].IndexArray[0].InstanceIndex * NumCustomDataFloats]; + const float G = PerInstanceSMCustomData[LineMap[LineId].IndexArray[0].InstanceIndex * NumCustomDataFloats + 1]; + const float B = PerInstanceSMCustomData[LineMap[LineId].IndexArray[0].InstanceIndex * NumCustomDataFloats + 2]; + return { R, G, B }; +} + int32 UGPUInstancedLineComponent::AddNewSegmentInstance(const FLinearColor& Color, float Width, int32 Index) { // Add with a dummy transform - int32 InstanceId = AddInstance(FTransform::Identity); + const int32 InstanceId = AddInstance(FTransform::Identity); SetCustomDataValue(InstanceId, 0, Color.R, false); SetCustomDataValue(InstanceId, 1, Color.G, false); SetCustomDataValue(InstanceId, 2, Color.B, false); @@ -104,6 +107,25 @@ int32 UGPUInstancedLineComponent::AddNewSegmentInstance(const FLinearColor& Colo return InstanceId; } +void UGPUInstancedLineComponent::UpdateTexture(const FIntPoint& StartIndex, int32 NumberOfPoints, uint8* SrcData, bool bMarkRenderStateDirty) +{ + int32 NumRegions = 0; + FUpdateTextureRegion2D* Regions = CalculateTextureRegions(StartIndex, NumberOfPoints, NumRegions); + + const uint32 Pitch = TextureWidth; + PositionTexture->UpdateTextureRegions(0, NumRegions, Regions, Pitch * sizeof(FVector4), sizeof(FVector4), SrcData, + [](auto InTextureData, auto InRegions) + { + // Clean up the copied data + delete InTextureData; + delete InRegions; + }); + + // Probably not a good place to call this + if(bMarkRenderStateDirty) + MarkRenderStateDirty(); +} + void UGPUInstancedLineComponent::Init() { if (PositionTexture == nullptr) @@ -119,11 +141,6 @@ void UGPUInstancedLineComponent::Init() //UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::Init MID was nullptr!")); DynamicLineMaterial = UMaterialInstanceDynamic::Create(LineMaterialInterface, GetTransientPackage()); SetMaterial(0, DynamicLineMaterial); - //check(DynamicLineMaterial); - - //DynamicLineMaterial = CreateAndSetMaterialInstanceDynamic(0); - //DynamicLineMaterial->SetTextureParameterValue("PositionTexture", PositionTexture); - //DynamicLineMaterial->SetScalarParameterValue("TextureWidth", TextureWidth); } DynamicLineMaterial->SetTextureParameterValue("PositionTexture", PositionTexture); @@ -154,6 +171,7 @@ FUpdateTextureRegion2D* UGPUInstancedLineComponent::CalculateTextureRegions(cons { // Calculate the first consecutive region: int32 RemainingPoints = NumberOfPoints; + const uint32 TextureWidthU = static_cast<uint32>(TextureWidth); TArray<FUpdateTextureRegion2D>* Regions = new TArray<FUpdateTextureRegion2D>(); Regions->AddZeroed(1); @@ -165,7 +183,7 @@ FUpdateTextureRegion2D* UGPUInstancedLineComponent::CalculateTextureRegions(cons (*Regions)[0].Width = FMath::Min(NumberOfPoints, TextureWidth - static_cast<int32>((*Regions)[0].DestX)); (*Regions)[0].Height = StartIndex.X == 0 ? (NumberOfPoints / TextureWidth) : 1; - checkf((*Regions)[0].DestX + (*Regions)[0].Width <= (uint32)TextureWidth, TEXT("Region[0] out of bounds on X. Texture: %i, %i, %i"), (*Regions)[0].DestX, (*Regions)[0].Width, PositionTexture->GetSizeX()); + checkf((*Regions)[0].DestX + (*Regions)[0].Width <= TextureWidthU, TEXT("Region[0] out of bounds on X. Texture: %i, %i, %i"), (*Regions)[0].DestX, (*Regions)[0].Width, PositionTexture->GetSizeX()); RemainingPoints -= (*Regions)[0].Height == 1 ? (*Regions)[0].Width : (*Regions)[0].Width * (*Regions)[0].Height; if(RemainingPoints == 0) @@ -184,7 +202,7 @@ FUpdateTextureRegion2D* UGPUInstancedLineComponent::CalculateTextureRegions(cons (*Regions)[1].Height = RemainingPoints == 0 ? 1 : (RemainingPoints / TextureWidth); RemainingPoints -= (*Regions)[1].Width * ((*Regions)[1].Height - 1); - checkf((*Regions)[1].DestX + (*Regions)[1].Width <= (uint32)TextureWidth, TEXT("Region[1] out of bounds on X. Texture: %i, %i, %i"), (*Regions)[1].DestX, (*Regions)[1].Width, PositionTexture->GetSizeX()); + checkf((*Regions)[1].DestX + (*Regions)[1].Width <= TextureWidthU, TEXT("Region[1] out of bounds on X. Texture: %i, %i, %i"), (*Regions)[1].DestX, (*Regions)[1].Width, PositionTexture->GetSizeX()); if (RemainingPoints == 0) { @@ -205,7 +223,7 @@ FUpdateTextureRegion2D* UGPUInstancedLineComponent::CalculateTextureRegions(cons (*Regions)[2].Height = RemainingPoints == 0 ? 1 : (RemainingPoints / TextureWidth); RemainingPoints -= (*Regions)[2].Width * ((*Regions)[1].Height - 1); - checkf((*Regions)[2].DestX + (*Regions)[2].Width <= (uint32)TextureWidth, TEXT("Region[2] out of bounds on X. Texture: %i, %i, %i"), (*Regions)[2].DestX, (*Regions)[2].Width, PositionTexture->GetSizeX()); + checkf((*Regions)[2].DestX + (*Regions)[2].Width <= TextureWidthU, TEXT("Region[2] out of bounds on X. Texture: %i, %i, %i"), (*Regions)[2].DestX, (*Regions)[2].Width, PositionTexture->GetSizeX()); if (RemainingPoints > 0) @@ -226,20 +244,13 @@ void UGPUInstancedLineComponent::BeginPlay() } } -// Doesn't do anything yet, just as a testing function to see execution order on Unreal startup. -void UGPUInstancedLineComponent::PostInitProperties() -{ - Super::PostInitProperties(); - //if (FApp::CanEverRender() && !HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) - //UE_LOG(LogLineRendering, Display, TEXT("UGPUInstancedLineComponent::PostInitProperties IF")); -} #if WITH_EDITOR void UGPUInstancedLineComponent::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) { Init(); - if (PropertyChangedEvent.Property != NULL) + if (PropertyChangedEvent.Property != nullptr) { if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UGPUInstancedLineComponent, EditorLines)) { @@ -403,7 +414,7 @@ void UGPUInstancedLineComponent::PostEditChangeProperty(FPropertyChangedEvent& P Init(); const FName PropertyName = PropertyChangedEvent.GetPropertyName(); - if (PropertyChangedEvent.Property != NULL) + if (PropertyChangedEvent.Property != nullptr) { if (PropertyName == GET_MEMBER_NAME_CHECKED(FEditorPoint, Point)) { @@ -447,29 +458,12 @@ void UGPUInstancedLineComponent::TickComponent(float DeltaTime, ELevelTick TickT #endif - -// Doesn't do anything yet, just as a testing function to see execution order on Unreal startup. -void UGPUInstancedLineComponent::PostLoad() -{ - Super::PostLoad(); -} - -// Doesn't do anything yet, just as a testing function to see execution order on Unreal startup. -void UGPUInstancedLineComponent::OnComponentCreated() -{ - Super::OnComponentCreated(); -} - void UGPUInstancedLineComponent::BeginDestroy() { Super::BeginDestroy(); ReleaseData(); } -void UGPUInstancedLineComponent::Serialize(FArchive& Ar) -{ - Super::Serialize(Ar); -} void UGPUInstancedLineComponent::ReserveMemory(int32 NumberOfSegments, int32 NumberOfLines) { @@ -563,7 +557,7 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3 { const FLinearColor Color = UniformColor ? Colors[0] : Colors[LineIndex]; const float Width = UniformWidth ? Widths[0] : Widths[LineIndex]; - int32 Idx = LineMap.Add(FGPULineArray()); + const int32 Idx = LineMap.Add(FGPULineArray()); FGPULineArray& NewLineArray = LineMap[Idx]; NewLineArray.IndexArray.Reserve(NumberOfSegmentsPerLine + 1); @@ -585,6 +579,82 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3 UpdateWholeTexture(); } +void UGPUInstancedLineComponent::InitializeLinesInBulkTesselate(int32 NumberOfLines, int32 NumberOfSegmentsPerLine, + TArray<FVector4>& Points, const TArray<FLinearColor>& Colors, const TArray<float>& Widths) +{ + // Just as a test + const int32 NumOriginalSegments = NumberOfSegmentsPerLine; + NumberOfSegmentsPerLine += 9; + LinearLineData.Reserve(NumberOfLines * (NumberOfSegmentsPerLine + 1)); + + + if (LinearLineData.Num() != 0 || LineMap.Num() != 0 || GetInstanceCount() != 0) + { + LinearLineData.Empty(); // Reset + LineMap.Empty(); + + //NextFreeId = 0; + CurrentTextureIndex = 0; + CurrentTextureMarker = FIntPoint(0, 0); + ClearInstances(); + } + + LinearLineData = MoveTemp(Points); + + // Add tesselated points from back to front + for (int LineIdx = NumberOfLines - 1; LineIdx >= 0; --LineIdx) + { + // Get start and end of line + const FVector4 Start = LinearLineData[LineIdx * (NumOriginalSegments + 1)]; + const FVector4 End = LinearLineData[LineIdx * (NumOriginalSegments + 1) + 1]; + const FVector4 Dist = End - Start; + // Tesselate + const FVector4 First = Start + 0.1 * Dist; + const FVector4 Second = Start + 0.2 * Dist; + const FVector4 Third = Start + 0.3 * Dist; + const FVector4 Fourth = Start + 0.4 * Dist; + const FVector4 Fith = Start + 0.5 * Dist; + const FVector4 Sixth = Start + 0.6 * Dist; + const FVector4 Seventh = Start + 0.7 * Dist; + const FVector4 Eigth = Start + 0.8 * Dist; + const FVector4 Nineth = Start + 0.9 * Dist; + + LinearLineData.Insert({ First, Second, Third, Fourth, Fith, Sixth, Seventh, Eigth, Nineth }, LineIdx * (NumOriginalSegments + 1) + 1); + + } + + // Add the number of instances - sadly this requires the for loop + + const bool UniformColor = Colors.Num() == 1; + const bool UniformWidth = Widths.Num() == 1; + + for (int32 LineIndex = 0; LineIndex < NumberOfLines; ++LineIndex) + { + const FLinearColor Color = UniformColor ? Colors[0] : Colors[LineIndex]; + const float Width = UniformWidth ? Widths[0] : Widths[LineIndex]; + const int32 Idx = LineMap.Add(FGPULineArray()); + FGPULineArray& NewLineArray = LineMap[Idx]; + NewLineArray.IndexArray.Reserve(NumberOfSegmentsPerLine + 1); + + for (int32 PointIndex = 0; PointIndex < NumberOfSegmentsPerLine; ++PointIndex) + { + const int32 InstanceId = AddNewSegmentInstance(Color, Width, CurrentTextureIndex); + NewLineArray.IndexArray.Add({ InstanceId, LineIndex * (NumberOfSegmentsPerLine + 1) + PointIndex }); + CurrentTextureIndex++; + + MoveTextureMarker(); + } + NewLineArray.IndexArray.Add({ -1, LineIndex * (NumberOfSegmentsPerLine + 1) + NumberOfSegmentsPerLine }); + MoveTextureMarker(); + CurrentTextureIndex++; + //NextFreeId++; + } + + MarkRenderStateDirty(); + UpdateWholeTexture(); + +} + int32 UGPUInstancedLineComponent::AddLine(const TArray<FVector>& Line, FLinearColor Color, float Width) { @@ -630,25 +700,12 @@ int32 UGPUInstancedLineComponent::AddLine(const TArray<FVector>& Line, FLinearCo // Store the points in a linear array here LinearLineData.Append(*TextureData); - int32 NumRegions = 0; - FUpdateTextureRegion2D* Regions = CalculateTextureRegions(InitialTextureMarker, Line.Num(), NumRegions); - - const uint32 Pitch = TextureWidth; - PositionTexture->UpdateTextureRegions(0, NumRegions, Regions, Pitch * sizeof(FVector4), sizeof(FVector4), (uint8*)TextureData->GetData(), - [](auto InTextureData, auto InRegions) - { - // Clean up the copied data - delete InTextureData; - delete InRegions; - }); - - //UE_LOG(LogLineRendering, Display, TEXT("Added Line #%d"), LineId); // Actually we can! - + UpdateTexture(InitialTextureMarker, Line.Num(), (uint8*)TextureData->GetData()); return LineId; } -int32 UGPUInstancedLineComponent::AddLine(TArray<FVector4>& Line, FLinearColor Color, float Width) +int32 UGPUInstancedLineComponent::AddLine(TArray<FVector4>& Line, FLinearColor Color, float Width, bool bMarkRenderStateDirty) { if (Line.Num() < 2) { @@ -687,21 +744,7 @@ int32 UGPUInstancedLineComponent::AddLine(TArray<FVector4>& Line, FLinearColor C // Store the points in a linear array here LinearLineData.Append(*TextureData); - int32 NumRegions = 0; - FUpdateTextureRegion2D* Regions = CalculateTextureRegions(InitialTextureMarker, TextureData->Num(), NumRegions); - - const uint32 Pitch = TextureWidth; - PositionTexture->UpdateTextureRegions(0, NumRegions, Regions, Pitch * sizeof(FVector4), sizeof(FVector4), (uint8*)TextureData->GetData(), - [](auto InTextureData, auto InRegions) - { - // Clean up the copied data - delete InTextureData; - delete InRegions; - }); - - //UE_LOG(LogLineRendering, Display, TEXT("Added Line #%d"), LineId); // Actually we can! - - + UpdateTexture(InitialTextureMarker, TextureData->Num(), (uint8*)TextureData->GetData(), bMarkRenderStateDirty); return LineId; @@ -729,17 +772,13 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point) // Get color and width of the line FGPULineArray& Line = LineMap[LineId]; - - const float R = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats]; - const float G = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 1]; - const float B = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 2]; const float Width = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 3]; const FIntPoint InitialTextureMarker = CurrentTextureMarker; // Check if it's the last line: FGPULineIndices& Indices = Line.IndexArray.Last(); - const int32 InstanceId = AddNewSegmentInstance({R, G, B}, Width, Indices.TextureIndex); + const int32 InstanceId = AddNewSegmentInstance(GetLineColor(LineId), Width, Indices.TextureIndex); Line.IndexArray.Last().InstanceIndex = InstanceId; @@ -899,12 +938,7 @@ bool UGPUInstancedLineComponent::InsertPoint(int32 LineId, int32 SegmentId, cons bool UGPUInstancedLineComponent::InsertPointWithSameColor(int32 LineId, int32 SegmentId, const FVector& Point) { - FGPULineArray& Line = LineMap[LineId]; - const float R = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats]; - const float G = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 1]; - const float B = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 2]; - - return InsertPoint(LineId, SegmentId, Point, { R, G, B }); + return InsertPoint(LineId, SegmentId, Point, GetLineColor(LineId)); } bool UGPUInstancedLineComponent::InsertPointWithColor(int32 LineId, int32 SegmentId, const FVector& Point, @@ -921,9 +955,9 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& // Get color and width of the line FGPULineArray& Line = LineMap[LineId]; - const float R = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats]; - const float G = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 1]; - const float B = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 2]; + + const FLinearColor Color = GetLineColor(LineId); + const float Width = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 3]; const FIntPoint InitialTextureMarker = CurrentTextureMarker; @@ -938,7 +972,7 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& { for (int32 PointIndex = 0; PointIndex < Points.Num(); ++PointIndex) { - const int32 InstanceId = AddNewSegmentInstance({ R, G, B }, Width, PointTextureIndex + PointIndex); + const int32 InstanceId = AddNewSegmentInstance(Color, Width, PointTextureIndex + PointIndex); // Update the latest dummy entry to point to the actual segment. if (PointIndex == 0) @@ -960,21 +994,10 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& // Recreate the data on the heap to allow asynchronous texture update. TArray<FVector4>* TextureData = new TArray<FVector4>(Points); - int32 NumberOfRegions = 0; - FUpdateTextureRegion2D* Regions = CalculateTextureRegions(InitialTextureMarker, Points.Num(), NumberOfRegions); - - // Update the actual texture on the gpu - const uint32 Pitch = TextureWidth; - PositionTexture->UpdateTextureRegions(0, NumberOfRegions, Regions, Pitch * sizeof(FVector4), sizeof(FVector4), (uint8*)TextureData->GetData(), - [](auto InTextureData, auto InRegions) - { - // Clean up the copied data - delete InTextureData; - delete InRegions; - }); - + + UpdateTexture(InitialTextureMarker, Points.Num(), (uint8*)TextureData->GetData()); - MarkRenderStateDirty(); + //MarkRenderStateDirty(); called in UpdateTexture already return true; } @@ -1000,7 +1023,7 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>& for (int32 PointIndex = 0; PointIndex < Points.Num(); ++PointIndex) { - const int32 InstanceId = AddNewSegmentInstance({ R, G, B }, Width, NewPointTextureIndex - 1 + PointIndex); + const int32 InstanceId = AddNewSegmentInstance(Color, Width, NewPointTextureIndex - 1 + PointIndex); // Update the latest dummy entry to point to the actual segment. if (PointIndex == 0) @@ -1043,9 +1066,7 @@ bool UGPUInstancedLineComponent::InsertPoints(int32 LineId, int32 SegmentId, con { return AddPoints(LineId, Points); } - const float R = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats]; - const float G = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 1]; - const float B = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 2]; + const float Width = PerInstanceSMCustomData[Line.IndexArray[0].InstanceIndex * NumCustomDataFloats + 3]; const int32 LinearDataIndex = Line.IndexArray[SegmentId].TextureIndex; @@ -1060,7 +1081,7 @@ bool UGPUInstancedLineComponent::InsertPoints(int32 LineId, int32 SegmentId, con for (int32 PointIndex = 0; PointIndex < Points.Num(); ++PointIndex) { - const int32 InstanceId = AddNewSegmentInstance({ R, G, B }, Width, LinearDataIndex + PointIndex); + const int32 InstanceId = AddNewSegmentInstance(GetLineColor(LineId), Width, LinearDataIndex + PointIndex); Line.IndexArray.Insert({ InstanceId, LinearDataIndex + PointIndex }, SegmentId + PointIndex); CurrentTextureIndex++; @@ -1117,15 +1138,7 @@ bool UGPUInstancedLineComponent::UpdateLine(int32 LineId, TArray<FVector>& Point FMemory::Memcpy(LinearLineData.GetData() + TextureIndex, TextureData->GetData(), TextureData->Num() * sizeof(FVector4)); - int32 NumberOfRegions = 0; - const FUpdateTextureRegion2D* Regions = CalculateTextureRegions(StartIndex, TextureData->Num(), NumberOfRegions); - - PositionTexture->UpdateTextureRegions(0, NumberOfRegions, Regions, TextureWidth * sizeof(FVector4), sizeof(FVector4), (uint8*)TextureData->GetData(), - [](auto InTextureData, auto InRegions) - { - delete InTextureData; - delete InRegions; - }); + UpdateTexture(StartIndex, TextureData->Num(), (uint8*)TextureData->GetData()); return true; } @@ -1149,19 +1162,8 @@ bool UGPUInstancedLineComponent::UpdateLinesDataDirectly(int32 LineIdStart, TArr TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::UpdateLines - MoveTemp Texture Data")) TextureData = new TArray<FVector4>(MoveTemp(Points)); } - int32 NumberOfRegions = 0; - FUpdateTextureRegion2D* Regions; - { - TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::UpdateLines - Calculate Texture Regions")) - Regions = CalculateTextureRegions(FIntPoint(X, Y), TextureData->Num(), NumberOfRegions); - } - PositionTexture->UpdateTextureRegions(0, NumberOfRegions, Regions, TextureWidth * sizeof(FVector4), sizeof(FVector4), (uint8*)TextureData->GetData(), - [](auto InTextureData, auto InRegions) - { - delete InTextureData; - delete InRegions; - }); - + + UpdateTexture(FIntPoint(X, Y), TextureData->Num(), (uint8*)TextureData->GetData()); return true; } @@ -1184,14 +1186,8 @@ bool UGPUInstancedLineComponent::DrawLinesDirectly(int32 LineIdStart, TArray<FVe TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UGPUInstancedLineComponent::DrawLinesDirectly - MoveTemp Texture Data")) TextureData = new TArray<FVector4>(MoveTemp(Points)); } - int32 NumberOfRegions = 0; - FUpdateTextureRegion2D* Regions = CalculateTextureRegions(FIntPoint(X, Y), TextureData->Num(), NumberOfRegions); - PositionTexture->UpdateTextureRegions(0, NumberOfRegions, Regions, TextureWidth * sizeof(FVector4), sizeof(FVector4), (uint8*)TextureData->GetData(), - [](auto InTextureData, auto InRegions) - { - delete InTextureData; - delete InRegions; - }); + UpdateTexture(FIntPoint(X, Y), TextureData->Num(), (uint8*)TextureData->GetData()); + return true; } @@ -1211,14 +1207,7 @@ bool UGPUInstancedLineComponent::DrawLinesDirectly(int32 LineIdStart, TArray<FVe const int32 X = LineIdStart % TextureWidth; const int32 Y = LineIdStart / TextureWidth; - int32 NumberOfRegions = 0; - FUpdateTextureRegion2D* Regions = CalculateTextureRegions(FIntPoint(X, Y), Points->Num(), NumberOfRegions); - PositionTexture->UpdateTextureRegions(0, NumberOfRegions, Regions, TextureWidth * sizeof(FVector4), sizeof(FVector4), (uint8*)Points->GetData(), - [](auto InTextureData, auto InRegions) - { - delete InTextureData; - delete InRegions; - }); + UpdateTexture(FIntPoint(X, Y), Points->Num(), (uint8*)Points->GetData()); return true; } @@ -1230,14 +1219,7 @@ bool UGPUInstancedLineComponent::DrawLinesDirectly(int32 LineIdStart, uint8* Src const int32 X = LineIdStart % TextureWidth; const int32 Y = LineIdStart / TextureWidth; - int32 NumberOfRegions = 0; - FUpdateTextureRegion2D* Regions = CalculateTextureRegions(FIntPoint(X, Y), Num, NumberOfRegions); - PositionTexture->UpdateTextureRegions(0, NumberOfRegions, Regions, TextureWidth * sizeof(FVector4), sizeof(FVector4), SrcData, - [](auto InTextureData, auto InRegions) - { - delete InTextureData; - delete InRegions; - }); + UpdateTexture(FIntPoint(X, Y), Num, SrcData); return true; } @@ -1253,10 +1235,7 @@ bool UGPUInstancedLineComponent::UpdatePoint(int32 LineId, int32 PointId, const LinearLineData[PointIndices.TextureIndex].Y = Point.Y; LinearLineData[PointIndices.TextureIndex].Z = Point.Z; - const int32 InstanceId = (PointIndices.InstanceIndex != -1) ? PointIndices.InstanceIndex : LineMap[LineId].IndexArray[PointId - 1].InstanceIndex; - const int32 TextureIndex = PointIndices.TextureIndex; - //const int32 Y = PerInstanceSMCustomData[InstanceId * NumCustomDataFloats + 5]; const int32 X = TextureIndex % TextureWidth; const int32 Y = TextureIndex / TextureWidth; @@ -1269,8 +1248,6 @@ bool UGPUInstancedLineComponent::UpdatePoint(int32 LineId, int32 PointId, const 0, 0, 1, 1); - - // Copy for now - no need to do that TArray<FVector4>* TextureData = new TArray<FVector4>{ LinearLineData[PointIndices.TextureIndex] }; @@ -1302,15 +1279,12 @@ bool UGPUInstancedLineComponent::UpdatePoints(int32 LineId, int32 StartingPointI return UpdateLine(LineId, Points); } - // Should check for validity - const FGPULineIndices& FirstPointIndices = LineMap[LineId].IndexArray[StartingPointId]; - TArray<FVector4>* TextureData = new TArray<FVector4>(MoveTemp(Points)); if(StartingPointId == 0) { (*TextureData)[0].W = 0; } - if (StartingPointId + Points.Num() == Line.IndexArray.Num()) + if (StartingPointId + TextureData->Num() == Line.IndexArray.Num()) { TextureData->Last().W = -1; } @@ -1319,17 +1293,9 @@ bool UGPUInstancedLineComponent::UpdatePoints(int32 LineId, int32 StartingPointI const FIntPoint StartIndex(StartTextureIndex % TextureWidth, StartTextureIndex / TextureWidth); FMemory::Memcpy(LinearLineData.GetData() + StartTextureIndex, TextureData->GetData(), TextureData->Num() * sizeof(FVector4)); - - int32 NumberOfRegions = 0; - const FUpdateTextureRegion2D* Regions = CalculateTextureRegions(StartIndex, TextureData->Num(), NumberOfRegions); - - PositionTexture->UpdateTextureRegions(0, NumberOfRegions, Regions, TextureWidth * sizeof(FVector4), sizeof(FVector4), (uint8*)TextureData->GetData(), - [](auto InTextureData, auto InRegions) - { - delete InTextureData; - delete InRegions; - }); - + + UpdateTexture(StartIndex, TextureData->Num(), (uint8*)TextureData->GetData()); + return true; } @@ -1459,7 +1425,7 @@ bool UGPUInstancedLineComponent::RemovePoint(int32 LineId, int32 PointId) Line.IndexArray[i].TextureIndex -= 1; SetCustomDataValue(Line.IndexArray[i].InstanceIndex, 4, Line.IndexArray[i].TextureIndex, false); } - MarkRenderStateDirty(); + //MarkRenderStateDirty(); RemoveInstance(RemovedInstanceId); } diff --git a/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h b/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h index 87a7b78957ff8acdebb60b6a4ccc86f0e1268872..ee7e845a51d82dae9d0c46e8409781b241838fd3 100644 --- a/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h +++ b/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h @@ -99,7 +99,6 @@ public: virtual void BeginPlay() override; - virtual void PostInitProperties() override; #if WITH_EDITOR 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... @@ -107,16 +106,7 @@ public: virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) 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; - - virtual void Serialize(FArchive& Ar) override; private: @@ -134,19 +124,21 @@ private: void Init(); - //void RegisterSerializedEditorLines(); - void UpdateAllEditorLines(); FUpdateTextureRegion2D* CalculateTextureRegions(const FIntPoint& StartIndex, int32 NumberOfPoints, int32& NumberOfRegionsOut); -public: - // todo - void ReleaseData(); + void ReleaseData(); // todo + + int32 AddNewSegmentInstance(const FLinearColor& Color, float Width, int32 Index); + + void UpdateTexture(const FIntPoint& StartIndex, int32 NumberOfPoints, uint8* SrcData, bool bMarkRenderStateDirty = true); + +public: void UpdateWholeTexture() const; - int32 AddNewSegmentInstance(const FLinearColor& Color, float Width, int32 Index); + FLinearColor GetLineColor(int32 LineId); /** * Reserves internal memory for a given amount of Lines and Segments per Line. @@ -188,6 +180,9 @@ public: */ UFUNCTION(BlueprintCallable, Category = "Components|InstancedLineComponent") void InitializeLinesInBulk(int32 NumberOfLines, int32 NumberOfSegmentsPerLine, TArray<FVector4>& Points, const TArray<FLinearColor>& Colors, const TArray<float>& Widths); + + void InitializeLinesInBulkTesselate(int32 NumberOfLines, int32 NumberOfSegmentsPerLine, TArray<FVector4>& Points, const TArray<FLinearColor>& Colors, const TArray<float>& Widths); + /** * Adds a line and returns the respective ID of the line, which can be used to identify it for updating, modifying and removing. @@ -202,7 +197,7 @@ public: int32 AddLine(const TArray<FVector>& Line, FLinearColor Color, float Width = 1.0); - int32 AddLine(TArray<FVector4>& Line, FLinearColor Color, float Width = 1.0); + int32 AddLine(TArray<FVector4>& Line, FLinearColor Color, float Width = 1.0, bool bMarkRenderStateDirty = true); /** * Adds a line and returns the respective ID of the line, which can be used to identify it for updating, modifying and removing.