I’ve encountered some problems with using MetaDataFilters in Chaos Fields.
This happens on the UE5.1 release build from the launcher.
What I’m trying to do: applying a field only on certain Types.
I’ve read this thread Field System not working for Chaos destruction and downloaded the sample project files.
The meta data filtering works as expected for the Sleeping/Disable/Kill field:
However, When I try to implement the same logic to apply external strain, applying a MetaDataFilter (even with State Type
and Object Type
set to All
) results in nothing happening.
Setup: A GeometryCollectionActor
with a simple Box Geometry collection:
This Geometry actor is placed above ground.
Then, I created a Blueprint inheriting from FieldSystemActor
. Event graph tick function looks like this: A simple box falloff applying external strain.
In the map, I place this field overlapping with the GeomActor:
Now two scenario’s:
- With Meta Data Filter: box does not break
- With Meta Data Filter node disconnected: box does break.
I took a look at the code to see what’s happening differently.
The filter gets checked in FieldSystemProxyHelper.h
:
//if (LocalProxy && ( (PrevResolutionType != ResolutionType) || (PrevFilterType != FilterType) || (PrevObjectType != ObjectType) || (PrevPositionType != PositionType) || FilteredHandles.Num() == 0))
{
if (FilterType != EFieldFilterType::Field_Filter_Max)
{
LocalProxy->GetFilteredParticleHandles(FilteredHandles, RigidSolver, FilterType, ObjectType);
}
else
{
LocalProxy->GetRelevantParticleHandles(FilteredHandles, RigidSolver, ResolutionType);
}
...
Depending on the presence of the MetaDataFilter, one of the two paths gets executed.
These two functions reside in PerSolverFieldSystem.cpp
.
The big difference between the two I observed when debugging, is that when no filter is applied (and thus GetRelevantParticleHandles
is called), there is an additional lookup of clusters within each Handle:
for (Chaos::TParticleIterator<Chaos::FGeometryParticles> It = ParticleView.Begin(), ItEnd = ParticleView.End();
It != ItEnd; ++It)
{
const Chaos::TTransientGeometryParticleHandle<Chaos::FReal,3>* Handle = &(*It);
Handles.Add(GetHandleHelper(const_cast<Chaos::TTransientGeometryParticleHandle<Chaos::FReal,3>*>(Handle)));
const auto* Clustered = Handle->CastToClustered();
if (Clustered && Clustered->ClusterIds().NumChildren)
{
Chaos::TPBDRigidClusteredParticleHandle<Chaos::FReal, 3>* ClusterHandle = (*It).Handle()->CastToClustered();
if (ClusterMap.Contains(ClusterHandle))
{
for (Chaos::TPBDRigidParticleHandle<Chaos::FReal, 3> * Child : ClusterMap[ClusterHandle])
{
Handles.Add(Child);
}
}
}
}
(This only happens when the Resolution Type is set to EFieldResolutionType::Field_Resolution_Minimal
. (Which is the default value, afaik.)
In the other function (GetFilteredParticleHandles
), only handles within the view get added, and not their possible cluster children:
else if (FilterType == EFieldFilterType::Field_Filter_All)
{
const Chaos::TParticleView<Chaos::FGeometryParticles>& ParticleView =
SolverParticles.GetNonDisabledView();
Handles.Reserve(ParticleView.Num());
for (Chaos::TParticleIterator<Chaos::FGeometryParticles> It = ParticleView.Begin(), ItEnd = ParticleView.End();
It != ItEnd; ++It)
{
if (ValidateParticle(ObjectType, It))
{
const Chaos::TTransientGeometryParticleHandle<Chaos::FReal, 3>* Handle = &(*It);
Handles.Add(GetHandleHelper(const_cast<Chaos::TTransientGeometryParticleHandle<Chaos::FReal, 3>*>(Handle)));
}
}
}
Any help much appreciated.