I’m trying to use some custom C++ with the mass plugin to add custom data to the Instanced Static Mesh. I’m trying to use exclusively ISM using Anim to Texture plugin to drive animations, but I need to update the Current Frame (ISM Custom Data Index 0). Some of this process is mentioned here: https://dev.epicgames.com/community/learning/talks-and-demos/37Oz/large-numbers-of-entities-with-mass-in-unreal-engine-5
I made a custom state tree task that is supposed to change the custom data but I can’t seem to get it to work without erroring (or doing nothing). Here’s some code with my current erroring:
#include "AnimationOffsetTask.h"
#include "MassCrowdRepresentationSubsystem.h"
#include "MassCrowdSpawnerSubsystem.h"
#include "MassRepresentationSubsystem.h"
#include "MassStateTreeExecutionContext.h"
#include "MassVisualizationComponent.h"
#include "MassRepresentationTypes.h"
#include "Components/InstancedStaticMeshComponent.h"
#include "Misc/LowLevelTestAdapter.h"
using FMassISMCSharedDataMap = TMap<uint32, FMassISMCSharedData>;
bool FAnimationOffsetTask::Link(FStateTreeLinker& Linker)
{
Linker.LinkExternalData(DataHandle);
Linker.LinkExternalData(AnimationHandle);
Linker.LinkExternalData(LODHandle);
Linker.LinkExternalData(RepresentationHandle);
return true;
}
EStateTreeRunStatus FAnimationOffsetTask::Tick(FStateTreeExecutionContext& Context, const float DeltaTime) const
{
const FMassStateTreeExecutionContext& MassContext = static_cast<FMassStateTreeExecutionContext&>(Context);
FMassEntityHandle EntityHandle = MassContext.GetEntity();
FCustomFloatsFragment* DataFragment = MassContext.GetExternalDataPtr(DataHandle);
DataFragment->Data[1] = DataFragment->Data[0];
DataFragment->Data[0] = DataFragment->Data[1] + (DeltaTime*60.0f);
UMassCrowdRepresentationSubsystem* RepresentationSubsystem = UWorld::GetSubsystem<UMassCrowdRepresentationSubsystem>(Context.GetWorld());
FMassRepresentationFragment RepresentationFragment = MassContext.GetExternalData(RepresentationHandle);
FMassRepresentationLODFragment RepresentationLODFragment = MassContext.GetExternalData(LODHandle);
FMassInstancedStaticMeshInfoArrayView ISMInfo = RepresentationSubsystem->GetMutableInstancedStaticMeshInfos();
if (RepresentationFragment.CurrentRepresentation == EMassRepresentationType::StaticMeshInstance)
{
ISMInfo[RepresentationFragment.StaticMeshDescIndex].WriteCustomDataFloatsAtStartIndex(0,TArray{DataFragment->Data[0],DataFragment->Data[1]},RepresentationLODFragment.LODSignificance,2,0,RepresentationFragment.PrevLODSignificance);
//Similar result. //ISMInfo[RepresentationFragment.StaticMeshDescIndex].AddBatchedCustomData(TArray{DataFragment->Data[0],DataFragment->Data[1]},RepresentationLODFragment.LODSignificance,RepresentationFragment.PrevLODSignificance);
}
return EStateTreeRunStatus::Succeeded;
}
This results in the following ensure getting fired off:
void FMassLODSignificanceRange::WriteCustomDataFloatsAtStartIndex(int32 StaticMeshIndex, const TArrayView<float>& CustomFloats, const int32 FloatsPerInstance, const int32 StartFloatIndex, const TArray<uint32>& ExcludeStaticMeshRefs)
{
check(ISMCSharedDataPtr);
if (StaticMeshRefs.IsValidIndex(StaticMeshIndex))
{
if (ExcludeStaticMeshRefs.Contains(StaticMeshRefs[StaticMeshIndex]))
{
return;
}
FMassISMCSharedData& SharedData = (*ISMCSharedDataPtr)[StaticMeshRefs[StaticMeshIndex]];
int32 StartIndex = FloatsPerInstance * SharedData.WriteIterator + StartFloatIndex;
//This is the offending ensure
ensure(SharedData.StaticMeshInstanceCustomFloats.Num() >= StartIndex + CustomFloats.Num());
for (int CustomFloatIdx = 0; CustomFloatIdx < CustomFloats.Num(); CustomFloatIdx++)
{
SharedData.StaticMeshInstanceCustomFloats[StartIndex + CustomFloatIdx] = CustomFloats[CustomFloatIdx];
}
SharedData.WriteIterator++;
}
}
I tried to get a hold of the guy who made the post above but could not find a way to contact him (privated social media). Ideally I’d like to ask Mario Palmero how he did this, but as a second best, if someone else can answer, how can I do this? I’d be happy to provide more information.