I've created a custom geometry collection component in C++ and a blueprint based on it. Here's what my test geometry collection looks like in the editor:
There are 9 "real particles" inside 4 clusters, counting the root. And my custom geometry component logs 13 total particles:
void ACustomGCActor::BeginPlay()
{
Super::BeginPlay();
const FGeometryCollectionPhysicsProxy* PhysicsProxy = GeometryCollectionComponent->GetPhysicsProxy();
for (int32 i = 0; i < GeometryCollectionComponent->GetDynamicCollection()->GetNumTransforms(); ++i)
{
if (const Chaos::TPBDRigidParticle<Chaos::FReal, 3>* Particle = PhysicsProxy->GetParticleByIndex_External(i))
{
UE_LOG(LogTemp, Warning, TEXT("%s[%d] M: %f"), *GetName(), i, Particle->M());
}
}
}
I logged the mass of each particle:
GeometryCollectionActor_1[0] M: 100000.000000
GeometryCollectionActor_1[1] M: 53194.617188
GeometryCollectionActor_1[2] M: 30795.964844
GeometryCollectionActor_1[3] M: 16009.417969
GeometryCollectionActor_1[4] M: 17966.726562
GeometryCollectionActor_1[5] M: 33580.132812
GeometryCollectionActor_1[6] M: 1647.759644
GeometryCollectionActor_1[7] M: 9634.439453
GeometryCollectionActor_1[8] M: 7064.375000
GeometryCollectionActor_1[9] M: 14097.150391
GeometryCollectionActor_1[10] M: 1927.681030
GeometryCollectionActor_1[11] M: 14055.364258
GeometryCollectionActor_1[12] M: 26.372398
The mass of the first particle at index 0
stands out immediately because it's the total mass of the whole object. So, I assume that is the root node named SM_ChamferCube
in the screenshot above.
The following three particles at index 1
, 2
, and 3
have masses that add up to the mass of the first particle (53194.617188 + 30795.964844 + 16009.417969 = 100000.000000) so I assume those are SM_ChamferCube_0
, SM_ChamferCube_1
, and SM_ChamferCube_2
The method GeometryCollectionComponent->GetParentArrayRest()
gets any particle index's parent index. There are also 13 values in this array, and they look like this:
-1
0
0
0
1
1
1
2
2
2
3
3
3
The index 0
parent is -1
because it's the root. The parent of indexes 1
, 2
, and 3
is index 0
. The rest of the particles are real, having parent 1
, 2
, or 3
. Any particle that's the parent of another particle isn't real; it's a "cluster union particle."
So, we can determine how many cluster union particle groups are in the geometry collection by iterating over the parent array, finding the highest index + 1, and storing that value as FirstRealParticleIndex
to use as the beginning of any loop that's supposed to iterate over only the real particles.
void ACustomGCActor::BeginPlay()
{
Super::BeginPlay();
for (const int32 i : GeometryCollectionComponent->GetParentArrayRest())
{
FirstRealParticleIndex = FMath::Max(FirstRealParticleIndex, i + 1);
}
const FGeometryCollectionPhysicsProxy* PhysicsProxy = GeometryCollectionComponent->GetPhysicsProxy();
for (int32 i = FirstRealParticleIndex; i < GeometryCollectionComponent->GetDynamicCollection()->GetNumTransforms();
++i)
{
if (const Chaos::TPBDRigidParticle<Chaos::FReal, 3>* Particle = PhysicsProxy->GetParticleByIndex_External(i))
{
// ...do something with the particle
}
}
}