If you want to see examples on how a FBody Instance can be manually created for a Primitive Component check out InstancedStaticMeshComponent
FBodyInstance* NewBodyInstance = new FBodyInstance();EnemyInstance.Pin()->BodyInstance = NewBodyInstance;// Get transform of the instanceFTransform InstanceTransform = GetActorTransform();// TODO: set a tracked id so later on tracing we can get back what enemy instance it isNewBodyInstance->InstanceBodyIndex = -2;NewBodyInstance->CopyBodyInstancePropertiesFrom(CollisionPrimitiveComponent->GetBodyInstance());NewBodyInstance->bAutoWeld = false;NewBodyInstance->bSimulatePhysics = true;UBodySetup* NewBodySetup = NewObject<UBodySetup>(CollisionPrimitiveComponent.Get());NewBodySetup->DefaultInstance.SetCollisionProfileName(UCollisionProfile::BlockAll_ProfileName);FKAggregateGeom Geom;FKSphereElem TestSphere;TestSphere.Center = FVector(0, 0, 0);TestSphere.Radius = 20;Geom.AddElement(TestSphere);NewBodySetup->AddCollisionFrom(Geom);NewBodyInstance->InitBody(NewBodySetup, InstanceTransform, CollisionPrimitiveComponent.Get(), GetWorld()->GetPhysicsScene());
A important parent class of the BI is FBodyInstanceCore
The body instance seems to be mostly used from UPrimitiveComponent.
It also seems that a lot of physic functions are running from FBodyInstance.
BIs are initialized using a UBodySetup.
Physics Core
See Physics types for more detailed info on some types
Most of the functions will register a physic command using ApplyAsyncPhysicsCommand, that has a function call-back that’s using FPhysicsInterface (a typedef of FPhysInterface_Chaos which inherits FChaosEngineInterface and FGenericPhysicsInterface).
A BI holds a FPhysicsActorHandle ActorHandle which is the “Internal physics representation of our body instance”.
In some functions such as AddImpulse the params will be redirected to FChaosEngineInterface where either FRigidBodyHandle_Internal or FRigidBodyHandle_External handle is used (this is taken from the FPhysicsActorHandle BI handle).
By “internal” we mean that we are running the code on the physics thread, external would be if we are on the game thread.
Both of these handle are based on TThreadedSingleParticlePhysicsProxyBase which holds the interface to update physics properties on the particle such as (in this example) the linear velocity.
Miscs
Sleeping and wake
WakeInstance and PutInstanceToSleep will at some point call SetObjectState in TPBDRigidParticle.
Inside SetObjectState it is written than when we put an object to sleep, its velocity is zeroed and buffered (“in case the velocity is queried during sleep, or in case the object is woken up again”).
After that its said that “If another force is added after the object is put to sleep, the old forces will remain and the new ones will accumulate and re-dirty the dynamic properties which will wake the body.”
Gravity
Warning
If you enable gravity the BI will wake up
Changing collision
For some reasonSetCollisionEnabled(NewState) doesn’t work as expected, you can use SetShapeCollisionEnabled(0, NewState) instead.
For more detailed collision setting, there are many functions like SetResponseToChannel and SetResponseToAllChannels.
Warning
SetShapeCollisionEnabled calls UpdatePhysicsFilterData, which will wake up the BI
When you select a PrimitiveComponent, you can set Constraints These constraint settings are ONLY applied on the first body instance of this component
For a regular static mesh, this would be expected, but for a skeletal mesh component, this means only the root bone is constrained.
To apply constraint to other body instances, one way is to iterate the Bodies (available in SKMC) and apply set the constraint you want
Example:
// iterate all the bodies of this Static Skeletal Mesh Componentfor (int i = 0; i < Bodies.Num(); ++i) { FBodyInstance* BI = Bodies[i]; // Those settings are almost the same that you can see in the details panel BI->DOFMode = EDOFMode::Type::Default; // Here we are locking all axis for translation BI->bLockXTranslation = true; BI->bLockYTranslation = true; BI->bLockZTranslation = true; // Must be called so the BI create a constraint in the physic engine (it will read the variables we just set) BI->CreateDOFLock();}
Set body transform
If called on a dynamic (not kinematic) body, it will eventually call SetGlobalPose_AssumesLocked. And it seems that the new scale is not used there.
As mentioned in this blog post section (see FPushPhysicsData) FBodyInstance::SetBodyTransform will eventually call FSingleParticlePhysicsProxy::SetXBase.
Sleeping
SetXBase will wake up the particle if its sleeping.