diff --git a/Content/DynamicLineMaterial-Unoptimized.uasset b/Content/DynamicLineMaterial-Unoptimized.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..00cd4efcf8507ee0abbf45cf2ad43e44494c54b2
Binary files /dev/null and b/Content/DynamicLineMaterial-Unoptimized.uasset differ
diff --git a/Content/DynamicLineMaterial.uasset b/Content/DynamicLineMaterial.uasset
index e4529ef79a4492ebb3bb941980aab51f06487134..caea7d8737eb5a2668617a54dfc47b98154aecdf 100644
Binary files a/Content/DynamicLineMaterial.uasset and b/Content/DynamicLineMaterial.uasset differ
diff --git a/Content/DynamicLineMaterialNewBackup.uasset b/Content/DynamicLineMaterialNewBackup.uasset
index 8941aaff1f87b80799abf485b6497bb4d5b034be..cd0056d098d43cf45c8aafbcf08c79609961a3f3 100644
Binary files a/Content/DynamicLineMaterialNewBackup.uasset and b/Content/DynamicLineMaterialNewBackup.uasset differ
diff --git a/Content/DynamicLineMaterialOldBackup.uasset b/Content/DynamicLineMaterialOldBackup.uasset
index 91d3640c2277496afadde2c9499505066c57455e..2187dc645856e8d11f7368184d65fe2f9fc3932c 100644
Binary files a/Content/DynamicLineMaterialOldBackup.uasset and b/Content/DynamicLineMaterialOldBackup.uasset differ
diff --git a/Content/DynamicLineMaterialTesting.uasset b/Content/DynamicLineMaterialTesting.uasset
index 9b4c6fd06cc86ca8e0d37fe60f303c7ef5892f7d..79d7b52111d4169ebbaba1e1eef3c472ce6f4c40 100644
Binary files a/Content/DynamicLineMaterialTesting.uasset and b/Content/DynamicLineMaterialTesting.uasset differ
diff --git a/Content/line.uasset b/Content/line.uasset
index e53730b60727f78b76728d091c3f56474d3dc599..5eef0bfd3997b72daff8b796b43dfe1f06c9375d 100644
Binary files a/Content/line.uasset and b/Content/line.uasset differ
diff --git a/Content/optimized_line.uasset b/Content/optimized_line.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..d03b0c31a0886d08d020f9d0b27d847d777b0140
Binary files /dev/null and b/Content/optimized_line.uasset differ
diff --git a/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp b/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp
index 687d43f5644036086f2697aab03c51a2cc180176..17a5b81849fd5ec8ad14418ae59962b3027835de 100644
--- a/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp
+++ b/Source/InstancedMeshLineRendering/Private/GPUInstancedLineComponent.cpp
@@ -13,7 +13,7 @@ UGPUInstancedLineComponent::UGPUInstancedLineComponent(const FObjectInitializer&
CurrentTextureMarker = FIntPoint(0, 0);
CurrentTextureIndex = 0,
- NextFreeId = 0;
+ //NextFreeId = 0;
TextureWidth = 2048;
TextureHeight = 2048;
@@ -27,7 +27,7 @@ UGPUInstancedLineComponent::UGPUInstancedLineComponent(const FObjectInitializer&
SetCanEverAffectNavigation(false);
- static ConstructorHelpers::FObjectFinder<UStaticMesh>LineMeshAsset(TEXT("StaticMesh'/InstancedMeshLineRendering/line.line'"));
+ static ConstructorHelpers::FObjectFinder<UStaticMesh>LineMeshAsset(TEXT("StaticMesh'/InstancedMeshLineRendering/optimized_line.optimized_line'"));
static ConstructorHelpers::FObjectFinder<UMaterial>LineMaterialAsset(TEXT("Material'/InstancedMeshLineRendering/DynamicLineMaterial.DynamicLineMaterial'"));
UStaticMesh* LineAsset = LineMeshAsset.Object;
UMaterial* LineMaterial = LineMaterialAsset.Object;
@@ -513,6 +513,13 @@ void UGPUInstancedLineComponent::ReserveMemory(int32 NumberOfSegments, int32 Num
LinearLineData.Reserve(NumberOfLines * (NumberOfSegments + 1));
}
+void UGPUInstancedLineComponent::ReserveMemoryWithoutSegments(int32 NumberOfLines, int32 NumberOfTotalPoints)
+{
+ PreAllocateInstancesMemory(NumberOfTotalPoints - NumberOfLines); // Allocates a bit too much
+ LineMap.Reserve(NumberOfTotalPoints - NumberOfLines);
+ LinearLineData.Reserve(NumberOfTotalPoints);
+}
+
bool UGPUInstancedLineComponent::ResizeTexture(int32 Width, int32 Height)
{
if (LinearLineData.Num() > Width * Height)
@@ -531,9 +538,9 @@ bool UGPUInstancedLineComponent::ResizeTexture(int32 Width, int32 Height)
// This might be a bit awkward as the line map is a *map*, and not just an array.
// Some lines might be re-ordered in the texture, but that should be fine.
- for(TPair<int32, FGPULineArray>& Line : LineMap)
+ for(int32 LineId = 0; LineId < LineMap.Num(); ++LineId)// TPair<int32, FGPULineArray>& Line : LineMap)
{
- for (FGPULineIndices& LineIndices : Line.Value.IndexArray)
+ for (FGPULineIndices& LineIndices : LineMap[LineId].IndexArray)
{
// Key is instance id, value is texture index.
if(LineIndices.InstanceIndex >= 0)
@@ -567,7 +574,7 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3
LinearLineData.Empty(); // Reset
LineMap.Empty();
- NextFreeId = 0;
+ //NextFreeId = 0;
CurrentTextureIndex = 0;
CurrentTextureMarker = FIntPoint(0, 0);
ClearInstances();
@@ -590,8 +597,8 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3
{
const FLinearColor Color = UniformColor ? Colors[0] : Colors[LineIndex];
const float Width = UniformWidth ? Widths[0] : Widths[LineIndex];
-
- FGPULineArray& NewLineArray = LineMap.Add(NextFreeId, FGPULineArray());
+ int32 Idx = LineMap.Add(FGPULineArray());
+ FGPULineArray& NewLineArray = LineMap[Idx];
NewLineArray.IndexArray.Reserve(NumberOfSegmentsPerLine + 1);
for (int32 PointIndex = 0; PointIndex < NumberOfSegmentsPerLine; ++PointIndex)
@@ -601,7 +608,7 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3
SetCustomDataValue(InstanceId, 0, Color.R, false);
SetCustomDataValue(InstanceId, 1, Color.G, false);
SetCustomDataValue(InstanceId, 2, Color.B, false);
- SetCustomDataValue(InstanceId, 3, Width, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
SetCustomDataValue(InstanceId, 4, static_cast<float>(CurrentTextureIndex), false); // Segment Start
NewLineArray.IndexArray.Add({InstanceId, LineIndex * (NumberOfSegmentsPerLine + 1) + PointIndex});
CurrentTextureIndex++;
@@ -611,7 +618,7 @@ void UGPUInstancedLineComponent::InitializeLinesInBulk(int32 NumberOfLines, int3
NewLineArray.IndexArray.Add({-1, LineIndex * (NumberOfSegmentsPerLine + 1) + NumberOfSegmentsPerLine});
MoveTextureMarker();
CurrentTextureIndex++;
- NextFreeId++;
+ //NextFreeId++;
}
MarkRenderStateDirty();
@@ -627,11 +634,12 @@ int32 UGPUInstancedLineComponent::AddLine(const TArray<FVector>& Line, FLinearCo
return -1;
}
// 1.
- FGPULineArray& NewLineArray = LineMap.Add(NextFreeId, FGPULineArray());
+ const int32 LineId = LineMap.Add(FGPULineArray());
+ FGPULineArray& NewLineArray = LineMap[LineId];
NewLineArray.IndexArray.Reserve(Line.Num());
- const int32 LineId = NextFreeId;
- NextFreeId++; // TODO Fix Id system as this can possibly overflow.
+ //const int32 LineId = NextFreeId;
+ //NextFreeId++; // TODO Fix Id system as this can possibly overflow.
@@ -646,7 +654,7 @@ int32 UGPUInstancedLineComponent::AddLine(const TArray<FVector>& Line, FLinearCo
SetCustomDataValue(InstanceId, 0, Color.R, false);
SetCustomDataValue(InstanceId, 1, Color.G, false);
SetCustomDataValue(InstanceId, 2, Color.B, false);
- SetCustomDataValue(InstanceId, 3, Width, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
SetCustomDataValue(InstanceId, 4, static_cast<float>(CurrentTextureIndex), false); // Segment Start
NewLineArray.IndexArray.Add({InstanceId, LinearLineData.Num() + PointIndex});
CurrentTextureIndex++;
@@ -685,6 +693,70 @@ int32 UGPUInstancedLineComponent::AddLine(const TArray<FVector>& Line, FLinearCo
return LineId;
}
+int32 UGPUInstancedLineComponent::AddLine(TArray<FVector4>& Line, FLinearColor Color, float Width)
+{
+ if (Line.Num() < 2)
+ {
+ UE_LOG(LogLineRendering, Error, TEXT("UGPUInstancedLineComponent::AddLine : Can't add line with less than 2 points.")); // Actually we can!
+ return -1;
+ }
+ // 1.
+ const int32 LineId = LineMap.Add(FGPULineArray());
+ FGPULineArray& NewLineArray = LineMap[LineId];
+ NewLineArray.IndexArray.Reserve(Line.Num());
+
+
+
+ const int32 NumberSegments = Line.Num() - 1;
+
+ const FIntPoint InitialTextureMarker = CurrentTextureMarker;
+
+ for (int32 PointIndex = 0; PointIndex < NumberSegments; ++PointIndex)
+ {
+ // Add with a dummy transform
+ int32 InstanceId = AddInstance(FTransform::Identity);
+ SetCustomDataValue(InstanceId, 0, Color.R, false);
+ SetCustomDataValue(InstanceId, 1, Color.G, false);
+ SetCustomDataValue(InstanceId, 2, Color.B, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
+ SetCustomDataValue(InstanceId, 4, static_cast<float>(CurrentTextureIndex), false); // Segment Start
+ NewLineArray.IndexArray.Add({ InstanceId, LinearLineData.Num() + PointIndex });
+ CurrentTextureIndex++;
+
+ MoveTextureMarker();
+ }
+ // Add the last point which does not correspond to a transform/instance, but needs to be added to the texture still such that the second last instance can read it:
+ NewLineArray.IndexArray.Add({ -1, LinearLineData.Num() + NumberSegments });
+ MoveTextureMarker();
+ CurrentTextureIndex++;
+
+ // Recreate the data on the heap to allow asynchronous texture update.
+ TArray<FVector4>* TextureData = new TArray<FVector4>(MoveTemp(Line));
+
+
+ // 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!
+
+
+ return LineId;
+
+
+}
+
int32 UGPUInstancedLineComponent::AddLineFromEditorData(FEditorLineData& LineData)
{
const TArray<FEditorPoint>* EditorLineDataPtr = &LineData.Points;
@@ -721,7 +793,7 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point)
SetCustomDataValue(InstanceId, 0, R, false);
SetCustomDataValue(InstanceId, 1, G, false);
SetCustomDataValue(InstanceId, 2, B, false);
- SetCustomDataValue(InstanceId, 3, Width, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
// Update the latest dummy entry to point to the actual segment.
Line.IndexArray.Last().InstanceIndex = InstanceId;
@@ -731,7 +803,7 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point)
FVector4& PreviousLastPoint = LinearLineData[Indices.TextureIndex];
PreviousLastPoint.W = 1.0; // This isn't the line end anymore.
- if(LineId == NextFreeId - 1)
+ if(LineId == LineMap.Num() - 1)
{
LinearLineData.Add(FVector4(Point, -1)); // This is the last point now.
@@ -793,10 +865,10 @@ bool UGPUInstancedLineComponent::AddPoint(int32 LineId, const FVector& Point)
const int32 NewPointTextureIndex = Indices.TextureIndex + 1;
- // Update all LineMap Indices that have a texture index larger than the newly inserted point. Todo: Make more efficient, maybe remove map and swap to array:
- for (TPair<int32, FGPULineArray>& Pair : LineMap)
+ // Update all LineMap Indices that have a texture index larger than the newly inserted point.
+ //Todo: Make more efficient
+ for (FGPULineArray& LineArray : LineMap)
{
- FGPULineArray& LineArray = Pair.Value;
if (LineArray.IndexArray[0].TextureIndex >= NewPointTextureIndex)
{
// Need to increase all indices by 1 and adjust the custom data
@@ -842,7 +914,7 @@ bool UGPUInstancedLineComponent::InsertPoint(int32 LineId, int32 SegmentId, cons
SetCustomDataValue(InstanceId, 0, Color.R, false);
SetCustomDataValue(InstanceId, 1, Color.G, false);
SetCustomDataValue(InstanceId, 2, Color.B, false);
- SetCustomDataValue(InstanceId, 3, Width, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
LinearLineData.Insert(FVector4(Point), LinearDataIndex);
@@ -865,9 +937,8 @@ bool UGPUInstancedLineComponent::InsertPoint(int32 LineId, int32 SegmentId, cons
}
// Update all following lines
- for (TPair<int32, FGPULineArray>& Pair : LineMap)
+ for (FGPULineArray& LineArray : LineMap)
{
- FGPULineArray& LineArray = Pair.Value;
if (LineArray.IndexArray[0].TextureIndex > LinearDataIndex)
{
// Need to increase all indices by 1 and adjust the custom data
@@ -927,7 +998,7 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
FVector4& PreviousLastPoint = LinearLineData[Indices.TextureIndex];
PreviousLastPoint.W = 1.0; // This isn't the line end anymore.
- if (LineId == NextFreeId - 1)
+ if (LineId == LineMap.Num() - 1)
{
for (int32 PointIndex = 0; PointIndex < Points.Num(); ++PointIndex)
{
@@ -936,7 +1007,7 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
SetCustomDataValue(InstanceId, 0, R, false);
SetCustomDataValue(InstanceId, 1, G, false);
SetCustomDataValue(InstanceId, 2, B, false);
- SetCustomDataValue(InstanceId, 3, Width, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
SetCustomDataValue(InstanceId, 4, static_cast<float>(PointTextureIndex + PointIndex), false);
// Update the latest dummy entry to point to the actual segment.
@@ -987,9 +1058,8 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
const int32 NewPointTextureIndex = Indices.TextureIndex + 1;
// Update all LineMap Indices that have a texture index larger than the newly inserted point. Todo: Make more efficient, maybe remove map and swap to array:
- for (TPair<int32, FGPULineArray>& Pair : LineMap)
+ for (FGPULineArray& LineArray : LineMap)
{
- FGPULineArray& LineArray = Pair.Value;
if (LineArray.IndexArray[0].TextureIndex >= NewPointTextureIndex)
{
// Need to increase all indices by 1 and adjust the custom data
@@ -1008,7 +1078,7 @@ bool UGPUInstancedLineComponent::AddPoints(int32 LineId, const TArray<FVector>&
SetCustomDataValue(InstanceId, 0, R, false);
SetCustomDataValue(InstanceId, 1, G, false);
SetCustomDataValue(InstanceId, 2, B, false);
- SetCustomDataValue(InstanceId, 3, Width, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
SetCustomDataValue(InstanceId, 4, static_cast<float>(NewPointTextureIndex - 1 + PointIndex), false);
// Update the latest dummy entry to point to the actual segment.
@@ -1073,7 +1143,7 @@ bool UGPUInstancedLineComponent::InsertPoints(int32 LineId, int32 SegmentId, con
SetCustomDataValue(InstanceId, 0, R, false);
SetCustomDataValue(InstanceId, 1, G, false);
SetCustomDataValue(InstanceId, 2, B, false);
- SetCustomDataValue(InstanceId, 3, Width, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
Line.IndexArray.Insert({ InstanceId, LinearDataIndex + PointIndex }, SegmentId + PointIndex);
SetCustomDataValue(InstanceId, 4, LinearDataIndex + PointIndex, false);
@@ -1089,9 +1159,9 @@ bool UGPUInstancedLineComponent::InsertPoints(int32 LineId, int32 SegmentId, con
}
// Update all following lines
- for (TPair<int32, FGPULineArray>& Pair : LineMap)
+ for (FGPULineArray& LineArray : LineMap)
{
- FGPULineArray& LineArray = Pair.Value;
+ //FGPULineArray& LineArray = Pair.Value;
if (LineArray.IndexArray[0].TextureIndex > LinearDataIndex)
{
// Need to increase all indices by 1 and adjust the custom data
@@ -1376,12 +1446,12 @@ bool UGPUInstancedLineComponent::RemoveLine(int32 LineId)
// Remove linear data:
LinearLineData.RemoveAt(LineTextureIndex, LineLength);
// Remove line from map, this invalidates above Line reference.
- LineMap.Remove(LineId);
+ LineMap.RemoveAt(LineId);
// Update all following lines
- for (TPair<int32, FGPULineArray>& Pair : LineMap)
+ for (FGPULineArray& LineArray : LineMap)
{
- FGPULineArray& LineArray = Pair.Value;
+ //FGPULineArray& LineArray = Pair.Value;
for (int32 i = 0; i < LineArray.IndexArray.Num(); ++i)
{
if (LineArray.IndexArray[i].InstanceIndex >= InstancesToRemove[0])
@@ -1480,9 +1550,8 @@ bool UGPUInstancedLineComponent::RemovePoint(int32 LineId, int32 PointId)
Line.IndexArray.RemoveAt(PointId);
// Update all following lines
- for (TPair<int32, FGPULineArray>& Pair : LineMap)
+ for (FGPULineArray& LineArray : LineMap)
{
- FGPULineArray& LineArray = Pair.Value;
for (int32 i = 0; i < LineArray.IndexArray.Num(); ++i)
{
if (LineArray.IndexArray[i].InstanceIndex >= RemovedInstanceId)
@@ -1558,7 +1627,7 @@ bool UGPUInstancedLineComponent::SetLineWidth(int32 LineId, float Width)
const int32 InstanceId = LineIndices.InstanceIndex;
if (InstanceId >= 0)
{
- SetCustomDataValue(InstanceId, 3, Width, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
}
}
MarkRenderStateDirty();
@@ -1569,7 +1638,7 @@ bool UGPUInstancedLineComponent::SetSegmentWidth(int32 LineId, int32 SegmentId,
{
const int32 InstanceId = LineMap[LineId].IndexArray[SegmentId].InstanceIndex;
- SetCustomDataValue(InstanceId, 3, Width, false);
+ SetCustomDataValue(InstanceId, 3, Width / 2.0f, false);
return true;
}
//#pragma optimize("", on)
diff --git a/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h b/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h
index 2dbfe14ec283739aa35f2573988c2d2cc931052d..a949141c4c7a7e15b5fe14dff31c0c2e31038f81 100644
--- a/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h
+++ b/Source/InstancedMeshLineRendering/Public/GPUInstancedLineComponent.h
@@ -155,6 +155,10 @@ public:
UFUNCTION(BlueprintCallable, Category = "Components|InstancedLineComponent")
void ReserveMemory(int32 NumberOfSegments, int32 NumberOfLines);
+
+ void ReserveMemoryWithoutSegments(int32 NumberOfLines, int32 NumberOfTotalPoints);
+
+
/**
* Manually resized the texture to the specified width and height. Returns false if the texture couldn't be resized, e.g. if more lines are
* being rendered than can be displayed in the texture.
@@ -198,6 +202,9 @@ public:
UFUNCTION(BlueprintCallable, Category = "Components|InstancedLineComponent")
int32 AddLine(const TArray<FVector>& Line, FLinearColor Color, float Width = 1.0);
+
+ int32 AddLine(TArray<FVector4>& Line, FLinearColor Color, float Width = 1.0);
+
/**
* Adds a line and returns the respective ID of the line, which can be used to identify it for updating, modifying and removing.
*
@@ -462,7 +469,7 @@ public:
UMaterialInterface* LineMaterialInterface;
UPROPERTY()
- TMap<int32, FGPULineArray> LineMap;
+ TArray<FGPULineArray> LineMap;
//private:
@@ -475,8 +482,8 @@ public:
UPROPERTY()
TArray<int32> EditorLineIds;
- UPROPERTY()
- int32 NextFreeId;
+ //UPROPERTY()
+ //int32 NextFreeId;
UPROPERTY()
int32 CurrentTextureIndex;