Hello!
I happened to notice that the SSequencerObjectTrack performs really bad once tracks get reasonably complex.
This seems to be due to the CollectAllKeyTimes method of it which has 4 for loops wrapped into each other and is executed every frame.
The frame time in some of these instances is over 100ms which is not acceptable. I have to speed this up by a factor of 4 with quick and dirty changes.
void SSequencerObjectTrack::CollectAllKeyTimes(TArray<float>& OutKeyTimes) const
{
TArray<TSharedRef<FSequencerSectionKeyAreaNode>> OutNodes;
RootNode->GetChildKeyAreaNodesRecursively(OutNodes);
for (int32 i = 0; i < OutNodes.Num(); ++i)
{
TArray< TSharedRef<IKeyArea> > KeyAreas = OutNodes[i]->GetAllKeyAreas();
for (int32 j = 0; j < KeyAreas.Num(); ++j)
{
TArray<FKeyHandle> KeyHandles = KeyAreas[j]->GetUnsortedKeyHandles();
for (int32 k = 0; k < KeyHandles.Num(); ++k)
{
AddKeyTime(KeyAreas[j]->GetKeyTime(KeyHandles[k]), OutKeyTimes);
}
}
}
}
void SSequencerObjectTrack::AddKeyTime(const float& NewTime, TArray<float>& OutKeyTimes) const
{
// @todo Sequencer It might be more efficient to add each key and do the pruning at the end
for (float& KeyTime : OutKeyTimes)
{
if (FMath::IsNearlyEqual(KeyTime, NewTime))
{
return;
}
}
OutKeyTimes.Add(NewTime);
}
Improved version:
int32 SSequencerObjectTrack::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
if (RootNode->GetSequencer().GetSettings()->GetShowCombinedKeyframes())
{
FTimeToPixel TimeToPixelConverter(AllottedGeometry, ViewRange.Get());
TArray<float> OutKeyTimes;
CollectAllKeyTimes(OutKeyTimes, FVector2D(ViewRange.Get().GetLowerBoundValue(), ViewRange.Get().GetUpperBoundValue()));
OutKeyTimes.Sort();
for (int32 i = 0; i < OutKeyTimes.Num(); ++i)
{
if (i > 0&& FMath::IsNearlyEqual(OutKeyTimes[i], OutKeyTimes[i - 1]))
{
continue;
}
float KeyPosition = TimeToPixelConverter.TimeToPixel(OutKeyTimes[i]);
static const FVector2D KeyMarkSize = FVector2D(3.f, 21.f);
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId+1,
AllottedGeometry.ToPaintGeometry(FVector2D(KeyPosition - FMath::CeilToFloat(KeyMarkSize.X/2.f), FMath::CeilToFloat(AllottedGeometry.Size.Y/2.f - KeyMarkSize.Y/2.f)), KeyMarkSize),
FEditorStyle::GetBrush("Sequencer.KeyMark"),
MyClippingRect,
ESlateDrawEffect::None,
FLinearColor(1.f, 1.f, 1.f, 1.f)
);
}
return LayerId+1;
}
return LayerId;
}
void SSequencerObjectTrack::CollectAllKeyTimes(TArray<float>& OutKeyTimes, FVector2D Range) const
{
TArray<TSharedRef<FSequencerSectionKeyAreaNode>> OutNodes;
RootNode->GetChildKeyAreaNodesRecursively(OutNodes);
uint32 Num = 0;
for (int32 i = 0; i < OutNodes.Num(); ++i)
{
auto& KeyAreas = OutNodes[i]->GetAllKeyAreas();
for (int32 j = 0; j < KeyAreas.Num(); ++j)
{
Num += KeyAreas[j]->GetNumberOfKeyHandles();
}
}
OutKeyTimes.SetNumUninitialized(Num);
Num = 0;
for (int32 i = 0; i < OutNodes.Num(); ++i)
{
auto& KeyAreas = OutNodes[i]->GetAllKeyAreas();
for (int32 j = 0; j < KeyAreas.Num(); ++j)
{
TArray<FKeyHandle> KeyHandles = KeyAreas[j]->GetUnsortedKeyHandles();
for (int32 k = 0; k < KeyHandles.Num(); ++k)
{
float Time = KeyAreas[j]->GetKeyTime(KeyHandles[k]);
if (Time >= Range.X && Time < Range.Y)
{
OutKeyTimes[Num++] = Time;
}
}
}
}
OutKeyTimes.SetNum(Num,false);
}
This also applies to the red keyframe dots as well by the way
Thank you