Files
2025-05-18 13:04:45 +08:00

709 lines
26 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "RigPhysicsExecution.h"
#include "RigPhysicsSimulation.h"
#include "RigPhysicsBodyComponent.h"
#include "RigPhysicsJointComponent.h"
#include "RigPhysicsSolverComponent.h"
#include "RigPhysicsControlComponent.h"
#include "Rigs/RigHierarchyController.h"
#include "Units/RigUnitContext.h"
#include "Units/Execution/RigUnit_PrepareForExecution.h"
#include "ControlRigPhysicsModule.h"
#include "PhysicsEngine/PhysicsAsset.h"
#include "PhysicsEngine/SkeletalBodySetup.h"
#include "PhysicsEngine/PhysicsConstraintTemplate.h"
#include "PhysicalMaterials/PhysicalMaterial.h"
#include "ControlRig.h"
#if WITH_EDITOR
#include "RigVMModel/RigVMController.h"
#include "ControlRigBlueprint.h"
#endif
#include UE_INLINE_GENERATED_CPP_BY_NAME(RigPhysicsExecution)
TAutoConsoleVariable<int> CVarControlRigPhysicsVisualizationOverride(
TEXT("ControlRig.Physics.VisualizationOveride"), -1,
TEXT("-1 uses the Step Physics Solver setting, 0 forces visualization to be disabled, 1 forces it to be enabled."));
//======================================================================================================================
FRigUnit_AddPhysicsSolver_Execute()
{
if (!ExecuteContext.Hierarchy)
{
return;
}
if (ExecuteContext.GetEventName() != FRigUnit_PrepareForExecution::EventName)
{
UE_CONTROLRIG_RIGUNIT_REPORT_ERROR(TEXT("AddPhysicsSolver can only be used during Setup"));
}
if (URigHierarchyController* Controller = ExecuteContext.Hierarchy->GetController())
{
FRigHierarchyControllerInstructionBracket InstructionBracket(
Controller, ExecuteContext.GetInstructionIndex());
PhysicsSolverComponentKey = Controller->AddComponent(
FRigPhysicsSolverComponent::StaticStruct(), TEXT("PhysicsSolver"), Owner);
if (PhysicsSolverComponentKey.IsValid())
{
if (FRigPhysicsSolverComponent* Component = Cast<FRigPhysicsSolverComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsSolverComponentKey)))
{
Component->SolverSettings = SolverSettings;
Component->SimulationSpaceSettings = SimulationSpaceSettings;
}
}
}
}
//======================================================================================================================
FRigUnit_TrackInputPose_Execute()
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT();
if (!ExecuteContext.Hierarchy)
{
return;
}
if (UControlRig* ControlRig = Cast<UControlRig>(ExecuteContext.Hierarchy->GetOuter()))
{
if (FRigPhysicsSolverComponent* SolverComponent = Cast<FRigPhysicsSolverComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsSolverComponentKey)))
{
if (bForceNumberOfFrames)
{
SolverComponent->TrackInputCounter = NumberOfFrames;
}
else
{
SolverComponent->TrackInputCounter = FMath::Max(SolverComponent->TrackInputCounter, NumberOfFrames);
}
}
}
}
//======================================================================================================================
FRigUnit_StepPhysicsSolver_Execute()
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT();
if (!ExecuteContext.Hierarchy)
{
return;
}
if (UControlRig* ControlRig = Cast<UControlRig>(ExecuteContext.Hierarchy->GetOuter()))
{
if (FRigPhysicsSolverComponent* SolverComponent = Cast<FRigPhysicsSolverComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsSolverComponentKey)))
{
FRigPhysicsSimulation* PhysicsSimulation = Cast<FRigPhysicsSimulation>(
ControlRig->GetPhysicsSimulation(PhysicsSolverComponentKey));
// Make the solver and instantiate if necessary
if (!PhysicsSimulation)
{
TSharedPtr<FRigPhysicsSimulation> NewPhysicsSimulation = MakeShared<FRigPhysicsSimulation>(ControlRig);
if (ControlRig->RegisterPhysicsSimulation(NewPhysicsSimulation, PhysicsSolverComponentKey))
{
NewPhysicsSimulation->Instantiate(ExecuteContext, SolverComponent);
}
PhysicsSimulation = NewPhysicsSimulation.Get();
}
if (PhysicsSimulation)
{
PhysicsSimulation->StepSimulation(
ExecuteContext, SolverComponent, DeltaTimeOverride, SimulationSpaceDeltaTimeOverride, Alpha);
int32 VisualizationOverride = CVarControlRigPhysicsVisualizationOverride.GetValueOnAnyThread();
if (VisualizationOverride == 1 || (VisualizationOverride < 0 && VisualizationSettings.bEnableVisualization))
{
PhysicsSimulation->Draw(
ExecuteContext.GetDrawInterface(), SolverComponent->SolverSettings,
VisualizationSettings, ExecuteContext.GetWorld());
}
}
}
}
}
//======================================================================================================================
FRigUnit_SetPhysicsSolverSimulationSpaceSettings_Execute()
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT();
if (!ExecuteContext.Hierarchy)
{
return;
}
if (UControlRig* ControlRig = Cast<UControlRig>(ExecuteContext.Hierarchy->GetOuter()))
{
if (FRigPhysicsSolverComponent* SolverComponent = Cast<FRigPhysicsSolverComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsSolverComponentKey)))
{
SolverComponent->SimulationSpaceSettings = SimulationSpaceSettings;
}
}
}
//======================================================================================================================
FRigUnit_SetPhysicsSolverExternalVelocity_Execute()
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT();
if (!ExecuteContext.Hierarchy)
{
return;
}
if (UControlRig* ControlRig = Cast<UControlRig>(ExecuteContext.Hierarchy->GetOuter()))
{
if (FRigPhysicsSolverComponent* SolverComponent = Cast<FRigPhysicsSolverComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsSolverComponentKey)))
{
SolverComponent->SimulationSpaceSettings.ExternalLinearVelocity = ExternalLinearVelocity;
SolverComponent->SimulationSpaceSettings.ExternalAngularVelocity = ExternalAngularVelocity;
SolverComponent->SimulationSpaceSettings.ExternalTurbulenceVelocity = ExternalTurbulenceVelocity;
}
}
}
//======================================================================================================================
FRigUnit_InstantiatePhysics_Execute()
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT();
if (!ExecuteContext.Hierarchy)
{
return;
}
if (UControlRig* ControlRig = Cast<UControlRig>(ExecuteContext.Hierarchy->GetOuter()))
{
if (FRigPhysicsSolverComponent* SolverComponent = Cast<FRigPhysicsSolverComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsSolverComponentKey)))
{
TSharedPtr<FRigPhysicsSimulation> PhysicsSimulation = MakeShared<FRigPhysicsSimulation>(ControlRig);
if (ControlRig->RegisterPhysicsSimulation(PhysicsSimulation, PhysicsSolverComponentKey))
{
PhysicsSimulation->Instantiate(ExecuteContext, SolverComponent);
}
}
}
}
//======================================================================================================================
FRigUnit_AddPhysicsComponents_Execute()
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT();
if (!ExecuteContext.Hierarchy)
{
return;
}
if (ExecuteContext.GetEventName() != FRigUnit_PrepareForExecution::EventName)
{
UE_CONTROLRIG_RIGUNIT_REPORT_ERROR(TEXT("AddPhysicsComponents can only be used during Setup"));
}
if (URigHierarchyController* Controller = ExecuteContext.Hierarchy->GetController())
{
FRigHierarchyControllerInstructionBracket InstructionBracket(
Controller, ExecuteContext.GetInstructionIndex());
// Add the body
PhysicsBodyComponentKey = Controller->AddComponent(
FRigPhysicsBodyComponent::StaticStruct(), FRigPhysicsBodyComponent::GetDefaultName(), Owner);
if (PhysicsBodyComponentKey.IsValid())
{
if (FRigPhysicsBodyComponent* Component = Cast<FRigPhysicsBodyComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsBodyComponentKey)))
{
Component->BodySolverSettings = Solver;
Component->Dynamics = Dynamics;
Component->BodyData = BodyData;
Component->Collision = Collision;
if (Collision.IsEmpty())
{
Component->AutoCalculateCollision(ExecuteContext.Hierarchy);
}
}
if (bAddJoint)
{
PhysicsJointComponentKey = Controller->AddComponent(
FRigPhysicsJointComponent::StaticStruct(), FRigPhysicsJointComponent::GetDefaultName(), Owner);
if (PhysicsJointComponentKey.IsValid())
{
if (FRigPhysicsJointComponent* Component = Cast<FRigPhysicsJointComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsJointComponentKey)))
{
// Leave parent as blank to automatically find it
Component->ChildBodyComponentKey = PhysicsBodyComponentKey;
Component->JointData = JointData;
Component->DriveData = DriveData;
}
}
}
if (bAddSimSpaceControl)
{
SimSpaceControlComponentKey = Controller->AddComponent(FRigPhysicsControlComponent::StaticStruct(),
TEXT("SimSpaceControl"), Owner);
if (SimSpaceControlComponentKey.IsValid())
{
if (FRigPhysicsControlComponent* Component = Cast<FRigPhysicsControlComponent>(
ExecuteContext.Hierarchy->FindComponent(SimSpaceControlComponentKey)))
{
Component->bUseParentBodyAsDefault = false;
Component->ChildBodyComponentKey = PhysicsBodyComponentKey;
Component->ControlData = SimSpaceControlData;
}
}
}
if (bAddParentSpaceControl)
{
ParentSpaceControlComponentKey = Controller->AddComponent(FRigPhysicsControlComponent::StaticStruct(),
TEXT("ParentSpaceControl"), Owner);
if (ParentSpaceControlComponentKey.IsValid())
{
if (FRigPhysicsControlComponent* Component = Cast<FRigPhysicsControlComponent>(
ExecuteContext.Hierarchy->FindComponent(ParentSpaceControlComponentKey)))
{
Component->bUseParentBodyAsDefault = true;
Component->ChildBodyComponentKey = PhysicsBodyComponentKey;
Component->ControlData = ParentSpaceControlData;
}
}
}
}
}
}
//======================================================================================================================
static void SetCommonProperties(FRigPhysicsCollisionShape& Shape, const FKShapeElem& ShapeElem)
{
Shape.RestOffset = ShapeElem.RestOffset;
Shape.Name = ShapeElem.GetName();
Shape.bContributeToMass = ShapeElem.GetContributeToMass();
}
//======================================================================================================================
static void SetUpJointData(
FRigPhysicsJointData& JointData,
const FConstraintInstance& ConstraintInstance,
const FConstraintProfileProperties& ConstraintProfileProperties)
{
JointData.bAutoCalculateChildOffset = false;
JointData.bAutoCalculateParentOffset = false;
JointData.ExtraChildOffset = ConstraintInstance.GetRefFrame(EConstraintFrame::Frame1);
JointData.ExtraParentOffset = ConstraintInstance.GetRefFrame(EConstraintFrame::Frame2);
JointData.ExtraParentOffset.SetRotation(JointData.ExtraParentOffset.GetRotation() *
ConstraintInstance.AngularRotationOffset.Quaternion());
JointData.LinearConstraint = ConstraintProfileProperties.LinearLimit;
JointData.ConeConstraint = ConstraintProfileProperties.ConeLimit;
JointData.TwistConstraint = ConstraintProfileProperties.TwistLimit;
}
//======================================================================================================================
FRigUnit_HierarchyInstantiateFromPhysicsAsset_Execute()
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT();
if (!ExecuteContext.Hierarchy)
{
return;
}
if (ExecuteContext.GetEventName() != FRigUnit_PrepareForExecution::EventName)
{
UE_CONTROLRIG_RIGUNIT_REPORT_ERROR(TEXT("InstantiateFromPhysicsAsset can only be used during Setup"));
return;
}
if (!PhysicsAsset)
{
UE_CONTROLRIG_RIGUNIT_REPORT_ERROR(TEXT("InstantiateFromPhysicsAsset needs a valid physics asset"));
return;
}
URigHierarchyController * Controller = ExecuteContext.Hierarchy->GetController();
if (!Controller)
{
return;
}
FRigHierarchyControllerInstructionBracket InstructionBracket(Controller, ExecuteContext.GetInstructionIndex());
// When we create physics joints we need to be able to refer back to the bodies that have been created
TMap<FName, FRigComponentKey> BoneToBodyComponentKeyMap;
for (TObjectPtr<USkeletalBodySetup> SkeletalBodySetup : PhysicsAsset->SkeletalBodySetups)
{
if (!SkeletalBodySetup)
{
continue;
}
// Check we can use this based on the bone name
FName BoneName = SkeletalBodySetup->BoneName;
FRigElementKey OwnerElementKey(BoneName, ERigElementType::Bone);
if (!ExecuteContext.Hierarchy->Find(OwnerElementKey))
{
continue;
}
if (!BonesToUse.IsEmpty() && BonesToUse.Find(OwnerElementKey) == INDEX_NONE)
{
continue;
}
// Collision
FRigPhysicsCollision Collision;
const FKAggregateGeom& AggGeom = SkeletalBodySetup->AggGeom;
for (const FKBoxElem& BoxElem : AggGeom.BoxElems)
{
FTransform TM(BoxElem.Rotation, BoxElem.Center);
FRigPhysicsCollisionBox Box(TM, FVector(BoxElem.X, BoxElem.Y, BoxElem.Z));
SetCommonProperties(Box, BoxElem);
Collision.Boxes.Add(Box);
}
for (const FKSphereElem& SphereElem : AggGeom.SphereElems)
{
FTransform TM(SphereElem.Center);
FRigPhysicsCollisionSphere Sphere(TM, SphereElem.Radius);
SetCommonProperties(Sphere, SphereElem);
Collision.Spheres.Add(Sphere);
}
for (const FKSphylElem& SphylElem : AggGeom.SphylElems)
{
FTransform TM(SphylElem.Rotation, SphylElem.Center);
FRigPhysicsCollisionCapsule Capsule(TM, SphylElem.Radius, SphylElem.Length);
SetCommonProperties(Capsule, SphylElem);
Collision.Capsules.Add(Capsule);
}
const UPhysicalMaterial* Material = SkeletalBodySetup->GetPhysMaterial();
Material = Material ? Material : GetDefault<UPhysicalMaterial>();
if (Material)
{
Collision.Material.Friction = FMath::Max(Material->Friction, Material->StaticFriction);
Collision.Material.Restitution = Material->Restitution;
Collision.Material.FrictionCombineMode = (ERigPhysicsCombineMode)
Material->FrictionCombineMode.GetValue();
Collision.Material.RestitutionCombineMode = (ERigPhysicsCombineMode)
Material->RestitutionCombineMode.GetValue();
}
// Dynamics
FRigPhysicsDynamics Dynamics;
Dynamics.MassOverride = SkeletalBodySetup->CalculateMass();
Dynamics.LinearDamping = SkeletalBodySetup->DefaultInstance.LinearDamping;
Dynamics.AngularDamping = SkeletalBodySetup->DefaultInstance.AngularDamping;
// Body Data
FPhysicsControlModifierData BodyData;
BodyData.MovementType =
SkeletalBodySetup->PhysicsType == EPhysicsType::PhysType_Simulated ?
EPhysicsMovementType::Simulated : EPhysicsMovementType::Kinematic;
BodyData.CollisionType =
SkeletalBodySetup->CollisionReponse == EBodyCollisionResponse::BodyCollision_Enabled ?
ECollisionEnabled::PhysicsOnly : ECollisionEnabled::NoCollision;
// Add the component
FRigComponentKey PhysicsBodyComponentKey = Controller->AddComponent(
FRigPhysicsBodyComponent::StaticStruct(), TEXT("PhysicsBody"), OwnerElementKey);
if (FRigPhysicsBodyComponent* Component = Cast<FRigPhysicsBodyComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsBodyComponentKey)))
{
Component->BodySolverSettings.PhysicsSolverComponentKey = PhysicsBodyComponentKey;
Component->BodySolverSettings.bUseAutomaticSolver = bUseAutomaticSolver;
Component->Dynamics = Dynamics;
Component->BodyData = BodyData;
Component->Collision = Collision;
BoneToBodyComponentKeyMap.Add(BoneName, PhysicsBodyComponentKey);
PhysicsBodyComponentKeys.Add(PhysicsBodyComponentKey);
}
if (bAddSimSpaceControl)
{
FRigComponentKey SimSpaceControlComponentKey = Controller->AddComponent(
FRigPhysicsControlComponent::StaticStruct(),
TEXT("SimSpaceControl"), PhysicsBodyComponentKey.ElementKey);
if (FRigPhysicsControlComponent* Component = Cast<FRigPhysicsControlComponent>(
ExecuteContext.Hierarchy->FindComponent(SimSpaceControlComponentKey)))
{
Component->bUseParentBodyAsDefault = false;
Component->ChildBodyComponentKey = PhysicsBodyComponentKey;
Component->ControlData = SimSpaceControlData;
SimSpaceControlComponentKeys.Add(SimSpaceControlComponentKey);
}
}
if (bAddParentSpaceControl)
{
FRigComponentKey ParentSpaceControlComponentKey = Controller->AddComponent(
FRigPhysicsControlComponent::StaticStruct(),
TEXT("ParentSpaceControl"), PhysicsBodyComponentKey.ElementKey);
if (FRigPhysicsControlComponent* Component = Cast<FRigPhysicsControlComponent>(
ExecuteContext.Hierarchy->FindComponent(ParentSpaceControlComponentKey)))
{
Component->bUseParentBodyAsDefault = true;
Component->ChildBodyComponentKey = PhysicsBodyComponentKey;
Component->ControlData = ParentSpaceControlData;
ParentSpaceControlComponentKeys.Add(ParentSpaceControlComponentKey);
}
}
} // Loop over SkeletalBodySetup
// Now bodies are created we can handle no-collision
const TMap<FRigidBodyIndexPair, bool>& CollisionDisableTable = PhysicsAsset->CollisionDisableTable;
for (const TPair<FRigidBodyIndexPair, bool>& PairPair : CollisionDisableTable)
{
if (!PairPair.Value)
{
const FRigidBodyIndexPair& Pair = PairPair.Key;
int32 I1 = Pair.Indices[0];
int32 I2 = Pair.Indices[1];
if (I1 >= 0 && I1 < PhysicsAsset->SkeletalBodySetups.Num() &&
I2 >= 0 && I2 < PhysicsAsset->SkeletalBodySetups.Num())
{
if (PhysicsAsset->SkeletalBodySetups[I1] && PhysicsAsset->SkeletalBodySetups[I2])
{
const FName BoneName1 = PhysicsAsset->SkeletalBodySetups[I1]->BoneName;
const FName BoneName2 = PhysicsAsset->SkeletalBodySetups[I2]->BoneName;
if (FRigComponentKey* BodyComponentKey1 = BoneToBodyComponentKeyMap.Find(BoneName1))
{
if (FRigPhysicsBodyComponent* Component = Cast<FRigPhysicsBodyComponent>(
ExecuteContext.Hierarchy->FindComponent(*BodyComponentKey1)))
if (FRigComponentKey* BodyComponentKey2 = BoneToBodyComponentKeyMap.Find(BoneName2))
{
if (ExecuteContext.Hierarchy->FindComponent(*BodyComponentKey2))
{
Component->NoCollisionBodies.Add(*BodyComponentKey2);
}
}
}
}
}
}
}
// Physics Joints
if (bEnableJoints)
{
for (TObjectPtr<UPhysicsConstraintTemplate>& ConstraintTemplate : PhysicsAsset->ConstraintSetup)
{
if (!ConstraintTemplate)
{
continue;
}
// Note that physics assets are normally set up as child/parent for 1/2
// However, users can create their own constraints, and some assets will be the other way round.
FConstraintInstance& ConstraintInstance = ConstraintTemplate->DefaultInstance;
const FName ChildBoneName = ConstraintInstance.ConstraintBone1;
const FName ParentBoneName = ConstraintInstance.ConstraintBone2;
const FRigComponentKey* ChildBodyComponentKey = BoneToBodyComponentKeyMap.Find(ChildBoneName);
const FRigComponentKey* ParentBodyComponentKey = BoneToBodyComponentKeyMap.Find(ParentBoneName);
if (!ChildBodyComponentKey || !ParentBodyComponentKey)
{
if (BonesToUse.IsEmpty())
{
// If BonesToUse is not empty, it is hard to say whether this is an
// error/warning condition. However, if the physics asset is OK and BonesToUse
// is empty, then we shouldn't get here.
UE_CONTROLRIG_RIGUNIT_REPORT_WARNING(
TEXT("InstantiateFromPhysicsAsset - unable to make physics joint between %s and %s"),
*ChildBoneName.ToString(), *ParentBoneName.ToString());
}
continue;
}
const FConstraintProfileProperties& ConstraintProfileProperties =
ConstraintTemplate->GetConstraintProfilePropertiesOrDefault(ConstraintProfileName);
FRigPhysicsJointData JointData;
SetUpJointData(JointData, ConstraintInstance, ConstraintProfileProperties);
FRigPhysicsDriveData DriveData;
if (bEnableDrives)
{
DriveData.LinearDriveConstraint = ConstraintProfileProperties.LinearDrive;
DriveData.AngularDriveConstraint = ConstraintProfileProperties.AngularDrive;
// RBAN doesn't use skeletal animation, and by default we want to replicate that.
DriveData.bUseSkeletalAnimation = false;
}
// Add the component
FRigComponentKey PhysicsJointComponentKey = Controller->AddComponent(
FRigPhysicsJointComponent::StaticStruct(), TEXT("PhysicsJoint"), ChildBodyComponentKey->ElementKey);
if (PhysicsJointComponentKey.IsValid())
{
if (FRigPhysicsJointComponent* Component = Cast<FRigPhysicsJointComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsJointComponentKey)))
{
Component->JointData = JointData;
Component->DriveData = DriveData;
Component->ParentBodyComponentKey = *ParentBodyComponentKey;
Component->ChildBodyComponentKey = *ChildBodyComponentKey;
PhysicsJointComponentKeys.Add(PhysicsJointComponentKey);
}
}
} // Loop over constraint templates
}
}
//======================================================================================================================
FRigUnit_HierarchyImportCollisionFromPhysicsAsset_Execute()
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT();
if (!ExecuteContext.Hierarchy)
{
return;
}
if (ExecuteContext.GetEventName() != FRigUnit_PrepareForExecution::EventName)
{
UE_CONTROLRIG_RIGUNIT_REPORT_ERROR(TEXT("InstantiateFromPhysicsAsset can only be used during Setup"));
return;
}
if (!PhysicsAsset)
{
UE_CONTROLRIG_RIGUNIT_REPORT_ERROR(TEXT("InstantiateFromPhysicsAsset needs a valid physics asset"));
return;
}
URigHierarchyController* Controller = ExecuteContext.Hierarchy->GetController();
if (!Controller)
{
return;
}
FRigHierarchyControllerInstructionBracket InstructionBracket(Controller, ExecuteContext.GetInstructionIndex());
for (TObjectPtr<USkeletalBodySetup> SkeletalBodySetup : PhysicsAsset->SkeletalBodySetups)
{
if (!SkeletalBodySetup)
{
continue;
}
// Check we can use this based on the bone name
FName PhysicsBoneName = SkeletalBodySetup->BoneName;
if (!BonesToUse.IsEmpty() && BonesToUse.Find(PhysicsBoneName) == INDEX_NONE)
{
continue;
}
FName BoneName(NameSpace.ToString() + PhysicsBoneName.ToString());
FRigElementKey BoneKey = Controller->AddBone(BoneName, Owner, FTransform(), true, ERigBoneType::Imported);
if (BoneKey.IsValid())
{
// Collision
FRigPhysicsCollision Collision;
const FKAggregateGeom& AggGeom = SkeletalBodySetup->AggGeom;
for (const FKBoxElem& BoxElem : AggGeom.BoxElems)
{
FTransform TM(BoxElem.Rotation, BoxElem.Center);
FRigPhysicsCollisionBox Box(TM, FVector(BoxElem.X, BoxElem.Y, BoxElem.Z));
SetCommonProperties(Box, BoxElem);
Collision.Boxes.Add(Box);
}
for (const FKSphereElem& SphereElem : AggGeom.SphereElems)
{
FTransform TM(SphereElem.Center);
FRigPhysicsCollisionSphere Sphere(TM, SphereElem.Radius);
SetCommonProperties(Sphere, SphereElem);
Collision.Spheres.Add(Sphere);
}
for (const FKSphylElem& SphylElem : AggGeom.SphylElems)
{
FTransform TM(SphylElem.Rotation, SphylElem.Center);
FRigPhysicsCollisionCapsule Capsule(TM, SphylElem.Radius, SphylElem.Length);
SetCommonProperties(Capsule, SphylElem);
Collision.Capsules.Add(Capsule);
}
const UPhysicalMaterial* Material = SkeletalBodySetup->GetPhysMaterial();
Material = Material ? Material : GetDefault<UPhysicalMaterial>();
if (Material)
{
Collision.Material.Friction = FMath::Max(Material->Friction, Material->StaticFriction);
Collision.Material.Restitution = Material->Restitution;
Collision.Material.FrictionCombineMode = (ERigPhysicsCombineMode)
Material->FrictionCombineMode.GetValue();
Collision.Material.RestitutionCombineMode = (ERigPhysicsCombineMode)
Material->RestitutionCombineMode.GetValue();
}
// Dynamics
FRigPhysicsDynamics Dynamics;
Dynamics.MassOverride = SkeletalBodySetup->CalculateMass();
Dynamics.LinearDamping = SkeletalBodySetup->DefaultInstance.LinearDamping;
Dynamics.AngularDamping = SkeletalBodySetup->DefaultInstance.AngularDamping;
// Body Data
FPhysicsControlModifierData BodyData;
BodyData.MovementType = EPhysicsMovementType::Kinematic; // Always kinematic
BodyData.CollisionType =
SkeletalBodySetup->CollisionReponse == EBodyCollisionResponse::BodyCollision_Enabled ?
ECollisionEnabled::PhysicsOnly : ECollisionEnabled::NoCollision;
// Add the component
FRigComponentKey PhysicsBodyComponentKey = Controller->AddComponent(
FRigPhysicsBodyComponent::StaticStruct(), TEXT("PhysicsBody"), BoneKey);
if (FRigPhysicsBodyComponent* Component = Cast<FRigPhysicsBodyComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsBodyComponentKey)))
{
Component->BodySolverSettings.PhysicsSolverComponentKey = PhysicsBodyComponentKey;
Component->BodySolverSettings.bUseAutomaticSolver = bUseAutomaticSolver;
Component->Dynamics = Dynamics;
Component->BodyData = BodyData;
Component->Collision = Collision;
PhysicsBodyComponentKeys.Add(PhysicsBodyComponentKey);
BoneKeys.Add(BoneKey);
}
else
{
Controller->RemoveElement(BoneKey);
}
}
}
}
//======================================================================================================================
FRigUnit_GetPhysicsSolverSpaceData_Execute()
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_RIGUNIT();
if (!ExecuteContext.Hierarchy)
{
return;
}
if (UControlRig* ControlRig = Cast<UControlRig>(ExecuteContext.Hierarchy->GetOuter()))
{
if (FRigPhysicsSolverComponent* SolverComponent = Cast<FRigPhysicsSolverComponent>(
ExecuteContext.Hierarchy->FindComponent(PhysicsSolverComponentKey)))
{
if (FRigPhysicsSimulation* PhysicsSimulation = Cast<FRigPhysicsSimulation>(
ControlRig->GetPhysicsSimulation(PhysicsSolverComponentKey)))
{
const FRigPhysicsSimulation::FSimulationSpaceData& SimulationSpaceData =
PhysicsSimulation->GetSimulationSpaceData();
LinearVelocity = SimulationSpaceData.LinearVelocity;
AngularVelocity = SimulationSpaceData.AngularVelocity;
LinearAcceleration = SimulationSpaceData.LinearAcceleration;
AngularAcceleration = SimulationSpaceData.AngularAcceleration;
Gravity = SimulationSpaceData.Gravity;
}
}
}
}