2020-01-06 12:54:08 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "ClothingSimulation.h"
# include "Components/SkeletalMeshComponent.h"
# include "PhysicsEngine/PhysicsSettings.h"
//==============================================================================
// FClothingSimulationContextCommon
//==============================================================================
2020-10-29 13:38:15 -04:00
DEFINE_STAT ( STAT_ClothComputeNormals ) ;
DEFINE_STAT ( STAT_ClothInternalSolve ) ;
DEFINE_STAT ( STAT_ClothUpdateCollisions ) ;
DEFINE_STAT ( STAT_ClothSkinPhysMesh ) ;
DEFINE_STAT ( STAT_ClothFillContext ) ;
2020-01-06 12:54:08 -05:00
2020-01-10 15:54:40 -05:00
static TAutoConsoleVariable < float > GClothMaxDeltaTimeTeleportMultiplier (
TEXT ( " p.Cloth.MaxDeltaTimeTeleportMultiplier " ) ,
1.5f ,
TEXT ( " A multiplier of the MaxPhysicsDelta time at which we will automatically just teleport cloth to its new location \n " )
TEXT ( " default: 1.5 " ) ) ;
2020-01-06 12:54:08 -05:00
FClothingSimulationContextCommon : : FClothingSimulationContextCommon ( )
: ComponentToWorld ( FTransform : : Identity )
, WorldGravity ( FVector : : ZeroVector )
, WindVelocity ( FVector : : ZeroVector )
2020-10-29 13:38:15 -04:00
, WindAdaption ( 0.f )
2020-01-06 12:54:08 -05:00
, DeltaSeconds ( 0.f )
2020-01-10 15:54:40 -05:00
, TeleportMode ( EClothingTeleportMode : : None )
2020-03-11 14:37:58 -04:00
, MaxDistanceScale ( 1.f )
2020-08-14 06:18:22 -04:00
, PredictedLod ( INDEX_NONE )
2020-01-06 12:54:08 -05:00
{ }
FClothingSimulationContextCommon : : ~ FClothingSimulationContextCommon ( )
{ }
void FClothingSimulationContextCommon : : Fill ( const USkeletalMeshComponent * InComponent , float InDeltaSeconds , float InMaxPhysicsDelta )
2021-06-07 20:09:45 -04:00
{
// Deprecated version always fills RefToLocals with current animation results instead of using reference pose on initialization
const bool bIsInitialization = false ;
Fill ( InComponent , InDeltaSeconds , InMaxPhysicsDelta , bIsInitialization ) ;
}
void FClothingSimulationContextCommon : : Fill ( const USkeletalMeshComponent * InComponent , float InDeltaSeconds , float InMaxPhysicsDelta , bool bIsInitialization )
2020-01-06 12:54:08 -05:00
{
2020-10-29 13:38:15 -04:00
SCOPE_CYCLE_COUNTER ( STAT_ClothFillContext ) ;
LLM_SCOPE ( ELLMTag : : SkeletalMesh ) ;
2020-01-06 12:54:08 -05:00
check ( InComponent ) ;
FillBoneTransforms ( InComponent ) ;
2021-06-07 20:09:45 -04:00
FillRefToLocals ( InComponent , bIsInitialization ) ;
2020-01-06 12:54:08 -05:00
FillComponentToWorld ( InComponent ) ;
FillWorldGravity ( InComponent ) ;
FillWindVelocity ( InComponent ) ;
FillDeltaSeconds ( InDeltaSeconds , InMaxPhysicsDelta ) ;
2020-01-10 15:54:40 -05:00
FillTeleportMode ( InComponent , InDeltaSeconds , InMaxPhysicsDelta ) ;
2020-03-11 12:14:43 -04:00
FillMaxDistanceScale ( InComponent ) ;
2020-08-14 06:18:22 -04:00
2021-03-11 10:57:49 -04:00
PredictedLod = InComponent - > GetPredictedLODLevel ( ) ;
2020-01-06 12:54:08 -05:00
}
void FClothingSimulationContextCommon : : FillBoneTransforms ( const USkeletalMeshComponent * InComponent )
{
const USkeletalMesh * const SkeletalMesh = InComponent - > SkeletalMesh ;
if ( USkinnedMeshComponent * const MasterComponent = InComponent - > MasterPoseComponent . Get ( ) )
{
const TArray < int32 > & MasterBoneMap = InComponent - > GetMasterBoneMap ( ) ;
int32 NumBones = MasterBoneMap . Num ( ) ;
if ( NumBones = = 0 )
{
if ( SkeletalMesh )
{
// This case indicates an invalid master pose component (e.g. no skeletal mesh)
2020-11-25 11:17:08 -04:00
NumBones = SkeletalMesh - > GetRefSkeleton ( ) . GetNum ( ) ;
2020-01-06 12:54:08 -05:00
BoneTransforms . Empty ( NumBones ) ;
BoneTransforms . AddDefaulted ( NumBones ) ;
}
}
else
{
BoneTransforms . Reset ( NumBones ) ;
BoneTransforms . AddDefaulted ( NumBones ) ;
const TArray < FTransform > & MasterTransforms = MasterComponent - > GetComponentSpaceTransforms ( ) ;
for ( int32 BoneIndex = 0 ; BoneIndex < NumBones ; + + BoneIndex )
{
bool bFoundMaster = false ;
if ( MasterBoneMap . IsValidIndex ( BoneIndex ) )
{
const int32 MasterIndex = MasterBoneMap [ BoneIndex ] ;
if ( MasterIndex ! = INDEX_NONE & & MasterIndex < MasterTransforms . Num ( ) )
{
BoneTransforms [ BoneIndex ] = MasterTransforms [ MasterIndex ] ;
bFoundMaster = true ;
}
}
if ( ! bFoundMaster & & SkeletalMesh )
{
2020-11-25 11:17:08 -04:00
const int32 ParentIndex = SkeletalMesh - > GetRefSkeleton ( ) . GetParentIndex ( BoneIndex ) ;
2020-01-06 12:54:08 -05:00
BoneTransforms [ BoneIndex ] =
BoneTransforms . IsValidIndex ( ParentIndex ) & & ParentIndex < BoneIndex ?
2020-11-25 11:17:08 -04:00
BoneTransforms [ ParentIndex ] * SkeletalMesh - > GetRefSkeleton ( ) . GetRefBonePose ( ) [ BoneIndex ] :
SkeletalMesh - > GetRefSkeleton ( ) . GetRefBonePose ( ) [ BoneIndex ] ;
2020-01-06 12:54:08 -05:00
}
}
}
}
else
{
BoneTransforms = InComponent - > GetComponentSpaceTransforms ( ) ;
}
}
2021-06-07 20:09:45 -04:00
void FClothingSimulationContextCommon : : FillRefToLocals ( const USkeletalMeshComponent * InComponent , bool bIsInitialization )
2020-01-06 12:54:08 -05:00
{
RefToLocals . Reset ( ) ;
2021-06-07 20:09:45 -04:00
// Constraints are initialized using bone distances upon initialization, so fill out reference pose
if ( bIsInitialization )
{
const USkeletalMesh * const SkeletalMesh = InComponent - > SkeletalMesh ;
if ( SkeletalMesh )
{
const int32 NumBones = SkeletalMesh - > GetRefSkeleton ( ) . GetNum ( ) ;
RefToLocals . AddUninitialized ( NumBones ) ;
for ( int32 BoneIndex = 0 ; BoneIndex < NumBones ; + + BoneIndex )
{
2022-01-27 06:25:37 -05:00
RefToLocals [ BoneIndex ] = FMatrix44f : : Identity ;
2021-06-07 20:09:45 -04:00
}
}
return ;
}
2021-03-11 10:57:49 -04:00
InComponent - > GetCurrentRefToLocalMatrices ( RefToLocals , InComponent - > GetPredictedLODLevel ( ) ) ;
2020-01-06 12:54:08 -05:00
}
void FClothingSimulationContextCommon : : FillComponentToWorld ( const USkeletalMeshComponent * InComponent )
{
ComponentToWorld = InComponent - > GetComponentTransform ( ) ;
}
void FClothingSimulationContextCommon : : FillWorldGravity ( const USkeletalMeshComponent * InComponent )
{
const UWorld * const ComponentWorld = InComponent - > GetWorld ( ) ;
check ( ComponentWorld ) ;
WorldGravity = FVector ( 0.f , 0.f , ComponentWorld - > GetGravityZ ( ) ) ;
}
void FClothingSimulationContextCommon : : FillWindVelocity ( const USkeletalMeshComponent * InComponent )
{
2020-09-25 13:44:05 -04:00
InComponent - > GetWindForCloth_GameThread ( WindVelocity , WindAdaption ) ;
2020-01-06 12:54:08 -05:00
}
void FClothingSimulationContextCommon : : FillDeltaSeconds ( float InDeltaSeconds , float InMaxPhysicsDelta )
{
DeltaSeconds = FMath : : Min ( InDeltaSeconds , InMaxPhysicsDelta ) ;
}
2020-01-10 15:54:40 -05:00
void FClothingSimulationContextCommon : : FillTeleportMode ( const USkeletalMeshComponent * InComponent , float InDeltaSeconds , float InMaxPhysicsDelta )
{
TeleportMode = ( InDeltaSeconds > InMaxPhysicsDelta * GClothMaxDeltaTimeTeleportMultiplier . GetValueOnGameThread ( ) ) ?
EClothingTeleportMode : : Teleport :
InComponent - > ClothTeleportMode ;
}
2020-09-25 13:44:05 -04:00
void FClothingSimulationContextCommon : : FillMaxDistanceScale ( const USkeletalMeshComponent * InComponent )
2020-01-06 12:54:08 -05:00
{
2020-09-25 13:44:05 -04:00
MaxDistanceScale = InComponent - > GetClothMaxDistanceScale ( ) ;
2020-03-11 12:14:43 -04:00
}
2020-01-06 12:54:08 -05:00
//==============================================================================
// FClothingSimulationCommon
//==============================================================================
FClothingSimulationCommon : : FClothingSimulationCommon ( )
{
MaxPhysicsDelta = UPhysicsSettings : : Get ( ) - > MaxPhysicsDeltaTime ;
}
FClothingSimulationCommon : : ~ FClothingSimulationCommon ( )
{ }
void FClothingSimulationCommon : : FillContext ( USkeletalMeshComponent * InComponent , float InDeltaTime , IClothingSimulationContext * InOutContext )
2021-06-07 20:09:45 -04:00
{
// Deprecated version always fills RefToLocals with current animation results instead of using reference pose on initialization
const bool bIsInitialization = false ;
FillContext ( InComponent , InDeltaTime , InOutContext , bIsInitialization ) ;
}
void FClothingSimulationCommon : : FillContext ( USkeletalMeshComponent * InComponent , float InDeltaTime , IClothingSimulationContext * InOutContext , bool bIsInitialization )
2020-01-06 12:54:08 -05:00
{
check ( InOutContext ) ;
FClothingSimulationContextCommon * const Context = static_cast < FClothingSimulationContextCommon * > ( InOutContext ) ;
2021-06-07 20:09:45 -04:00
Context - > Fill ( InComponent , InDeltaTime , MaxPhysicsDelta , bIsInitialization ) ;
2020-01-06 12:54:08 -05:00
// Checking the component here to track rare issue leading to invalid contexts
2021-09-06 12:23:53 -04:00
if ( ! IsValid ( InComponent ) )
2020-01-06 12:54:08 -05:00
{
const AActor * const CompOwner = InComponent - > GetOwner ( ) ;
UE_LOG ( LogSkeletalMesh , Warning ,
TEXT ( " Attempting to fill a clothing simulation context for a PendingKill skeletal mesh component (Comp: %s, Actor: %s). "
" Pending kill skeletal mesh components should be unregistered before marked pending kill. " ) ,
* InComponent - > GetName ( ) , CompOwner ? * CompOwner - > GetName ( ) : TEXT ( " None " ) ) ;
// Make sure we clear this out to skip any attempted simulations
Context - > BoneTransforms . Reset ( ) ;
}
if ( Context - > BoneTransforms . Num ( ) = = 0 )
{
const AActor * const CompOwner = InComponent - > GetOwner ( ) ;
const USkinnedMeshComponent * const Master = InComponent - > MasterPoseComponent . Get ( ) ;
UE_LOG ( LogSkeletalMesh , Warning , TEXT ( " Attempting to fill a clothing simulation context for a skeletal mesh component that has zero bones (Comp: %s, Master: %s, Actor: %s). " ) , * InComponent - > GetName ( ) , Master ? * Master - > GetName ( ) : TEXT ( " None " ) , CompOwner ? * CompOwner - > GetName ( ) : TEXT ( " None " ) ) ;
// Make sure we clear this out to skip any attempted simulations
Context - > BoneTransforms . Reset ( ) ;
}
}