Search code examples
c++geometryunreal-engine5unreal

How to tell real particles from clusters in C++


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:

Geometry Collection

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());
        }
    }
}

How do I tell the real particles from the clusters?

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


Solution

  • 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
            }
        }
    }