Array Out Of Index error and editor crash using USkeletalMeshComponent::ComputeSkinnedPositions

When I try to call USkeletalMeshComponent::ComputeSkinnedPositions() from code (called from BlueprintFunctionLibrary in C++) my editor crashes and I get the following dump:

LoginId:b6bf1b2146c1836d4202ecb3617f81d0
EpicAccountId:992eed892efd4710896314cfeaa64bba

Assertion failed: (Index >= 0) & (Index < ArrayNum) [File:D:\Build\++UE4\Sync\Engine\Source\Runtime\Core\Public\Containers/Array.h] [Line: 611] Array index out of bounds: 3 from an array of size 0

UE4Editor_Core!FDebug::AssertFailed() [d:\build\++ue4\sync\engine\source\runtime\core\private\misc\assertionmacros.cpp:425]
UE4Editor_Engine!GetTypedSkinnedVertexPosition<1,1>() [d:\build\++ue4\sync\engine\source\runtime\engine\private\components\skinnedmeshcomponent.cpp:3313]
UE4Editor_Engine!USkeletalMeshComponent::ComputeSkinnedPositions() [d:\build\++ue4\sync\engine\source\runtime\engine\private\skeletalmeshcomponentphysics.cpp:2029]
UE4Editor_test_9343!UCustomFunctionLibrary::AnimatedVertex__GetAnimatedVertexLocations() [c:\users\defaultuser\documents\unreal projects\test\source\test\custombase\customfunctionlibrary.cpp:504]
UE4Editor_test_9343!UCustomFunctionLibrary::execAnimatedVertex__GetAnimatedVertexLocations() [c:\users\defaultuser\documents\unreal projects\test\source\test\custombase\customfunctionlibrary.h:39]
UE4Editor_CoreUObject!UFunction::Invoke() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\class.cpp:4728]
UE4Editor_CoreUObject!UObject::CallFunction() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:772]
UE4Editor_CoreUObject!UObject::ProcessContextOpcode() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:2197]
UE4Editor_CoreUObject!UObject::execLetBool() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:2099]
UE4Editor_CoreUObject!UObject::ProcessInternal() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:984]
UE4Editor_CoreUObject!UObject::CallFunction() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:896]
UE4Editor_CoreUObject!UObject::ProcessInternal() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:984]
UE4Editor_CoreUObject!UObject::CallFunction() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:896]
UE4Editor_CoreUObject!UObject::ProcessContextOpcode() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:2197]
UE4Editor_CoreUObject!UObject::ProcessInternal() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:984]
UE4Editor_CoreUObject!UObject::CallFunction() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:896]
UE4Editor_CoreUObject!UObject::ProcessInternal() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:984]
UE4Editor_CoreUObject!UFunction::Invoke() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\class.cpp:4728]
UE4Editor_CoreUObject!UObject::ProcessEvent() [d:\build\++ue4\sync\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:1344]
UE4Editor_Engine!AActor::ProcessEvent() [d:\build\++ue4\sync\engine\source\runtime\engine\private\actor.cpp:724]
UE4Editor_Engine!AActor::ReceiveTick()
UE4Editor_Engine!AActor::Tick() [d:\build\++ue4\sync\engine\source\runtime\engine\private\actor.cpp:943]
UE4Editor_Engine!AActor::TickActor() [d:\build\++ue4\sync\engine\source\runtime\engine\private\actor.cpp:925]
UE4Editor_Engine!FActorTickFunction::ExecuteTick() [d:\build\++ue4\sync\engine\source\runtime\engine\private\actor.cpp:137]
UE4Editor_Engine!TGraphTask<FTickFunctionTask>::ExecuteTask() [d:\build\++ue4\sync\engine\source\runtime\core\public\async\taskgraphinterfaces.h:829]
UE4Editor_Core!FNamedTaskThread::ProcessTasksNamedThread() [d:\build\++ue4\sync\engine\source\runtime\core\private\async\taskgraph.cpp:665]
UE4Editor_Core!FNamedTaskThread::ProcessTasksUntilQuit() [d:\build\++ue4\sync\engine\source\runtime\core\private\async\taskgraph.cpp:574]
UE4Editor_Core!FTaskGraphImplementation::WaitUntilTasksComplete() [d:\build\++ue4\sync\engine\source\runtime\core\private\async\taskgraph.cpp:1358]
UE4Editor_Engine!FTickTaskSequencer::ReleaseTickGroup() [d:\build\++ue4\sync\engine\source\runtime\engine\private\ticktaskmanager.cpp:541]
UE4Editor_Engine!FTickTaskManager::RunTickGroup() [d:\build\++ue4\sync\engine\source\runtime\engine\private\ticktaskmanager.cpp:1455]
UE4Editor_Engine!UWorld::RunTickGroup() [d:\build\++ue4\sync\engine\source\runtime\engine\private\leveltick.cpp:780]
UE4Editor_Engine!UWorld::Tick() [d:\build\++ue4\sync\engine\source\runtime\engine\private\leveltick.cpp:1454]
UE4Editor_UnrealEd!UEditorEngine::Tick() [d:\build\++ue4\sync\engine\source\editor\unrealed\private\editorengine.cpp:1691]
UE4Editor_UnrealEd!UUnrealEdEngine::Tick() [d:\build\++ue4\sync\engine\source\editor\unrealed\private\unrealedengine.cpp:403]
UE4Editor!FEngineLoop::Tick() [d:\build\++ue4\sync\engine\source\runtime\launch\private\launchengineloop.cpp:3495]
UE4Editor!GuardedMain() [d:\build\++ue4\sync\engine\source\runtime\launch\private\launch.cpp:166]
UE4Editor!GuardedMainWrapper() [d:\build\++ue4\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:144]
UE4Editor!WinMain() [d:\build\++ue4\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:223]
UE4Editor!__scrt_common_main_seh() [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:283]
kernel32
ntdll		

I don’t believe this is caused by my own code, but I’ll put it here in case I’m doing something wrong. I took Rama’s original code for computing skinned vertex positions and modified it to compile on 4.20. Disclaimer that I have next to no idea what I’m doing so maybe it is my fault but I really have no way of knowing. Here’s my code:

bool UCustomFunctionLibrary::AnimatedVertex__GetAnimatedVertexLocations(USkeletalMeshComponent* Mesh, TArray<FVector>& Locations, TArray<FMatrix>& CacheToLocals, bool PerformPawnVelocityCorrection)
{
	if (!Mesh) { return false; }

	//~~~~~~~~~~~~~ Locations.Empty(); //~~~~~~~~~~~~~
	FSkeletalMeshLODRenderData& LOD = Mesh->GetSkeletalMeshRenderData()->LODRenderData[0];
	FSkinWeightVertexBuffer& Buffer = LOD.SkinWeightVertexBuffer;

	Mesh->ComputeSkinnedPositions(Mesh, Locations, CacheToLocals, LOD, Buffer);

	FTransform ToWorld = Mesh->GetComponentTransform(); FVector WorldLocation = ToWorld.GetLocation();

	//Pawn Velocity Correction UPawnMovementComponent* MovementComp = nullptr; if(PerformPawnVelocityCorrection) { APawn* Pawn = Cast<APawn>(Mesh->GetOwner()); MovementComp = (Pawn) ? Pawn->GetMovementComponent() : NULL; } bool DoVelocityCorrection = PerformPawnVelocityCorrection && MovementComp; //Pawn Velocity Correction

	for (FVector& EachVertex : Locations) 
	{ 
		EachVertex = WorldLocation + ToWorld.TransformVector(EachVertex); 
		//if (PerformPawnVelocityCorrection) 
		//{ 
		//	EachVertex += MovementComp->Velocity * FApp::GetDeltaTime(); 
		//} 
	}

	return true;
}

After a few days of tinkering, I found out why it was crashing. It was user error. I was passing in a blank FMatrix when I should have gotten a reference to the model’s locals. I don’t entirely know what this all means, but at least it works now. Working 4.20 code below:

bool UCustomFunctionLibrary::AnimatedVertex__GetAnimatedVertexLocations(USkeletalMeshComponent* Mesh, TArray<FVector>& Locations, TArray<FMatrix>& CacheToLocals, int32 LOD_Index, bool PerformPawnVelocityCorrection)
{
	if (!Mesh) { return false; }

	//~~~~~~~~~~~~~ Locations.Empty(); //~~~~~~~~~~~~~
	FSkeletalMeshLODRenderData& LOD = Mesh->GetSkeletalMeshRenderData()->LODRenderData[LOD_Index];
	FSkinWeightVertexBuffer& Buffer = LOD.SkinWeightVertexBuffer;

	//Output current locals to variable
	Mesh->GetCurrentRefToLocalMatrices(CacheToLocals, LOD_Index);

	Mesh->ComputeSkinnedPositions(Mesh, Locations, CacheToLocals, LOD, Buffer);

	FTransform ToWorld = Mesh->GetComponentTransform(); FVector WorldLocation = ToWorld.GetLocation();

	//Pawn Velocity Correction UPawnMovementComponent* MovementComp = nullptr; if(PerformPawnVelocityCorrection) { APawn* Pawn = Cast<APawn>(Mesh->GetOwner()); MovementComp = (Pawn) ? Pawn->GetMovementComponent() : NULL; } bool DoVelocityCorrection = PerformPawnVelocityCorrection && MovementComp; //Pawn Velocity Correction

	for (FVector& EachVertex : Locations) 
	{ 
		EachVertex = WorldLocation + ToWorld.TransformVector(EachVertex); 
		//if (PerformPawnVelocityCorrection) 
		//{ 
		//	EachVertex += MovementComp->Velocity * FApp::GetDeltaTime(); 
		//} 
	}

	return true;
}