2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2018-12-12 11:25:29 -05:00
# include "GeometryCollection/GeometryCollectionComponent.h"
2022-07-09 14:03:32 -04:00
# include "AI/NavigationSystemHelpers.h"
2018-12-12 11:25:29 -05:00
# include "Async/ParallelFor.h"
2022-07-09 14:03:32 -04:00
# include "Chaos/ChaosPhysicalMaterial.h"
2018-12-12 11:25:29 -05:00
# include "ChaosSolversModule.h"
# include "ChaosStats.h"
2022-07-09 14:03:32 -04:00
# include "ComponentRecreateRenderStateContext.h"
# include "Components/BoxComponent.h"
2022-10-26 12:57:32 -04:00
# include "Engine/Engine.h"
2022-07-09 14:03:32 -04:00
# include "Engine/InstancedStaticMesh.h"
2022-11-09 20:53:21 -05:00
# include "Field/FieldSystemComponent.h"
2022-10-29 03:00:57 -04:00
# include "GeometryCollection/Facades/CollectionHierarchyFacade.h"
2022-11-09 20:53:21 -05:00
# include "GeometryCollection/GeometryCollection.h"
2022-07-09 14:03:32 -04:00
# include "GeometryCollection/GeometryCollectionActor.h"
# include "GeometryCollection/GeometryCollectionAlgo.h"
# include "GeometryCollection/GeometryCollectionCache.h"
# include "GeometryCollection/GeometryCollectionClusteringUtility.h"
# include "GeometryCollection/GeometryCollectionComponentPluginPrivate.h"
# include "GeometryCollection/GeometryCollectionDebugDrawComponent.h"
# include "GeometryCollection/GeometryCollectionObject.h"
# include "GeometryCollection/GeometryCollectionProximityUtility.h"
# include "GeometryCollection/GeometryCollectionSQAccelerator.h"
# include "GeometryCollection/GeometryCollectionSceneProxy.h"
# include "GeometryCollection/GeometryCollectionUtility.h"
2022-10-21 19:51:57 -04:00
# include "GeometryCollection/GeometryCollectionISMPoolActor.h"
# include "GeometryCollection/GeometryCollectionISMPoolComponent.h"
2022-07-09 14:03:32 -04:00
# include "Math/Sphere.h"
# include "Modules/ModuleManager.h"
# include "Net/Core/PushModel/PushModel.h"
# include "Net/UnrealNetwork.h"
# include "PhysicalMaterials/PhysicalMaterial.h"
# include "Physics/Experimental/PhysScene_Chaos.h"
# include "Physics/PhysicsFiltering.h"
# include "PhysicsField/PhysicsFieldComponent.h"
2019-08-02 09:01:58 -04:00
# include "PhysicsProxy/GeometryCollectionPhysicsProxy.h"
# include "PhysicsSolver.h"
2018-12-12 11:25:29 -05:00
2022-06-14 12:44:09 -04:00
# include "Algo/RemoveIf.h"
2018-12-12 11:25:29 -05:00
# if WITH_EDITOR
# include "AssetToolsModule.h"
# include "Editor.h"
# endif
2019-06-08 17:15:34 -04:00
# include "PhysicsEngine/BodySetup.h"
# include "PhysicsEngine/BodyInstance.h"
# include "Chaos/ChaosGameplayEventDispatcher.h"
2018-12-12 11:25:29 -05:00
2020-07-15 03:39:13 -04:00
# include "Rendering/NaniteResources.h"
2020-07-15 19:46:08 -04:00
# include "PrimitiveSceneInfo.h"
2022-07-06 15:00:45 -04:00
# include "GeometryCollection/GeometryCollectionEngineRemoval.h"
2022-07-07 17:38:17 -04:00
# include "GeometryCollection/Facades/CollectionAnchoringFacade.h"
2022-11-21 18:58:53 -05:00
# include "GeometryCollection/Facades/CollectionRemoveOnBreakFacade.h"
2022-12-02 00:40:18 -05:00
# include "GeometryCollection/Facades/CollectionInstancedMeshFacade.h"
2020-07-15 03:39:13 -04:00
2022-09-24 13:57:58 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionComponent)
2019-06-08 17:15:34 -04:00
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
# include "Logging/MessageLog.h"
# include "Misc/UObjectToken.h"
# endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
# if INTEL_ISPC
2019-08-16 11:28:08 -04:00
# if USING_CODE_ANALYSIS
MSVC_PRAGMA ( warning ( push ) )
MSVC_PRAGMA ( warning ( disable : ALL_CODE_ANALYSIS_WARNINGS ) )
# endif // USING_CODE_ANALYSIS
2019-06-08 17:15:34 -04:00
# include "GeometryCollectionComponent.ispc.generated.h"
2019-08-16 11:28:08 -04:00
# if USING_CODE_ANALYSIS
MSVC_PRAGMA ( warning ( pop ) )
# endif // USING_CODE_ANALYSIS
2022-01-24 10:54:27 -05:00
static_assert ( sizeof ( ispc : : FMatrix ) = = sizeof ( FMatrix ) , " sizeof(ispc::FMatrix) != sizeof(FMatrix) " ) ;
static_assert ( sizeof ( ispc : : FBox ) = = sizeof ( FBox ) , " sizeof(ispc::FBox) != sizeof(FBox) " ) ;
# endif
2022-05-20 18:55:54 -04:00
# if !defined(CHAOS_BOX_CALC_BOUNDS_ISPC_ENABLED_DEFAULT)
# define CHAOS_BOX_CALC_BOUNDS_ISPC_ENABLED_DEFAULT 1
# endif
// Support run-time toggling on supported platforms in non-shipping configurations
# if !INTEL_ISPC || UE_BUILD_SHIPPING
static constexpr bool bChaos_BoxCalcBounds_ISPC_Enabled = INTEL_ISPC & & CHAOS_BOX_CALC_BOUNDS_ISPC_ENABLED_DEFAULT ;
# else
static bool bChaos_BoxCalcBounds_ISPC_Enabled = CHAOS_BOX_CALC_BOUNDS_ISPC_ENABLED_DEFAULT ;
static FAutoConsoleVariableRef CVarChaosBoxCalcBoundsISPCEnabled ( TEXT ( " p.Chaos.BoxCalcBounds.ISPC " ) , bChaos_BoxCalcBounds_ISPC_Enabled , TEXT ( " Whether to use ISPC optimizations in calculating box bounds in geometry collections " ) ) ;
2019-06-08 17:15:34 -04:00
# endif
2022-06-15 15:12:35 -04:00
bool bChaos_GC_CacheComponentSpaceBounds = true ;
FAutoConsoleVariableRef CVarChaosGCCacheComponentSpaceBounds ( TEXT ( " p.Chaos.GC.CacheComponentSpaceBounds " ) , bChaos_GC_CacheComponentSpaceBounds , TEXT ( " Cache component space bounds for performance " ) ) ;
2022-10-21 19:51:57 -04:00
bool bChaos_GC_UseISMPool = true ;
FAutoConsoleVariableRef CVarChaosGCUseISMPool ( TEXT ( " p.Chaos.GC.UseISMPool " ) , bChaos_GC_UseISMPool , TEXT ( " When enabled, use the ISM pool if specified " ) ) ;
bool bChaos_GC_UseISMPoolForNonFracturedParts = true ;
FAutoConsoleVariableRef CVarChaosGCUseISMPoolForNonFracturedParts ( TEXT ( " p.Chaos.GC.UseISMPoolForNonFracturedParts " ) , bChaos_GC_UseISMPoolForNonFracturedParts , TEXT ( " When enabled, non fractured part will use the ISM pool if specified " ) ) ;
2022-11-30 16:59:49 -05:00
bool bChaos_GC_InitConstantDataUseParallelFor = true ;
FAutoConsoleVariableRef CVarChaosGCInitConstantDataUseParallelFor ( TEXT ( " p.Chaos.GC.InitConstantDataUseParallelFor " ) , bChaos_GC_InitConstantDataUseParallelFor , TEXT ( " When enabled, InitConstant data will use parallelFor for copying some of the data " ) ) ;
int32 bChaos_GC_InitConstantDataParallelForBatchSize = 5000 ;
FAutoConsoleVariableRef CVarChaosGCInitConstantDataParallelForBatchSize ( TEXT ( " p.Chaos.GC.InitConstantDataParallelForBatchSize " ) , bChaos_GC_InitConstantDataParallelForBatchSize , TEXT ( " When parallelFor is used in InitConstantData, defined the minimium size of a batch of vertex " ) ) ;
2019-06-08 17:15:34 -04:00
DEFINE_LOG_CATEGORY_STATIC ( UGCC_LOG , Error , All ) ;
2021-04-20 10:45:04 -04:00
extern FGeometryCollectionDynamicDataPool GDynamicDataPool ;
2020-09-01 14:07:48 -04:00
FString NetModeToString ( ENetMode InMode )
{
switch ( InMode )
{
case ENetMode : : NM_Client :
return FString ( " Client " ) ;
case ENetMode : : NM_DedicatedServer :
return FString ( " DedicatedServer " ) ;
case ENetMode : : NM_ListenServer :
return FString ( " ListenServer " ) ;
case ENetMode : : NM_Standalone :
return FString ( " Standalone " ) ;
default :
break ;
}
return FString ( " INVALID NETMODE " ) ;
}
FString RoleToString ( ENetRole InRole )
{
switch ( InRole )
{
case ROLE_None :
return FString ( TEXT ( " None " ) ) ;
case ROLE_SimulatedProxy :
return FString ( TEXT ( " SimProxy " ) ) ;
case ROLE_AutonomousProxy :
return FString ( TEXT ( " AutoProxy " ) ) ;
case ROLE_Authority :
return FString ( TEXT ( " Auth " ) ) ;
default :
break ;
}
return FString ( TEXT ( " Invalid Role " ) ) ;
}
int32 GetClusterLevel ( const FTransformCollection * Collection , int32 TransformGroupIndex )
{
int32 Level = 0 ;
while ( Collection & & Collection - > Parent [ TransformGroupIndex ] ! = - 1 )
{
TransformGroupIndex = Collection - > Parent [ TransformGroupIndex ] ;
Level + + ;
}
return Level ;
}
bool FGeometryCollectionRepData : : Identical ( const FGeometryCollectionRepData * Other , uint32 PortFlags ) const
{
return Other & & ( Version = = Other - > Version ) ;
}
bool FGeometryCollectionRepData : : NetSerialize ( FArchive & Ar , class UPackageMap * Map , bool & bOutSuccess )
{
bOutSuccess = true ;
Ar < < Version ;
2022-04-25 13:09:18 -04:00
Ar < < OneOffActivated ;
2022-11-21 07:56:36 -05:00
Ar < < ServerFrame ;
2022-04-25 13:09:18 -04:00
int32 NumClusters = Clusters . Num ( ) ;
Ar < < NumClusters ;
2020-09-01 14:07:48 -04:00
if ( Ar . IsLoading ( ) )
{
2022-04-25 13:09:18 -04:00
Clusters . SetNum ( NumClusters ) ;
2020-09-01 14:07:48 -04:00
}
2022-04-25 13:09:18 -04:00
for ( FGeometryCollectionClusterRep & Cluster : Clusters )
2020-09-01 14:07:48 -04:00
{
2022-04-25 13:09:18 -04:00
Ar < < Cluster . Position ;
Ar < < Cluster . LinearVelocity ;
Ar < < Cluster . AngularVelocity ;
Ar < < Cluster . Rotation ;
Ar < < Cluster . ClusterIdx ;
2022-07-20 12:20:09 -04:00
Ar < < Cluster . ClusterState . Value ;
2020-09-01 14:07:48 -04:00
}
return true ;
}
2020-07-17 04:21:22 -04:00
int32 GGeometryCollectionNanite = 1 ;
2020-07-15 03:39:13 -04:00
FAutoConsoleVariableRef CVarGeometryCollectionNanite (
TEXT ( " r.GeometryCollection.Nanite " ) ,
GGeometryCollectionNanite ,
TEXT ( " Render geometry collections using Nanite. " ) ,
2021-05-17 22:54:18 -04:00
FConsoleVariableDelegate : : CreateLambda ( [ ] ( IConsoleVariable * InVariable )
{
FGlobalComponentRecreateRenderStateContext Context ;
} ) ,
2020-07-15 03:39:13 -04:00
ECVF_RenderThreadSafe
) ;
2020-04-30 07:34:59 -04:00
// Size in CM used as a threshold for whether a geometry in the collection is collected and exported for
// navigation purposes. Measured as the diagonal of the leaf node bounds.
float GGeometryCollectionNavigationSizeThreshold = 20.0f ;
FAutoConsoleVariableRef CVarGeometryCollectionNavigationSizeThreshold ( TEXT ( " p.GeometryCollectionNavigationSizeThreshold " ) , GGeometryCollectionNavigationSizeThreshold , TEXT ( " Size in CM used as a threshold for whether a geometry in the collection is collected and exported for navigation purposes. Measured as the diagonal of the leaf node bounds. " ) ) ;
2021-05-05 21:03:44 -04:00
// Single-Threaded Bounds
bool bGeometryCollectionSingleThreadedBoundsCalculation = false ;
FAutoConsoleVariableRef CVarGeometryCollectionSingleThreadedBoundsCalculation ( TEXT ( " p.GeometryCollectionSingleThreadedBoundsCalculation " ) , bGeometryCollectionSingleThreadedBoundsCalculation , TEXT ( " [Debug Only] Single threaded bounds calculation. [def:false] " ) ) ;
2021-02-18 13:20:03 -04:00
2018-12-12 11:25:29 -05:00
FGeomComponentCacheParameters : : FGeomComponentCacheParameters ( )
: CacheMode ( EGeometryCollectionCacheType : : None )
, TargetCache ( nullptr )
, ReverseCacheBeginTime ( 0.0f )
, SaveCollisionData ( false )
2019-06-08 17:15:34 -04:00
, DoGenerateCollisionData ( false )
, CollisionDataSizeMax ( 512 )
, DoCollisionDataSpatialHash ( false )
, CollisionDataSpatialHashRadius ( 50.f )
2018-12-12 11:25:29 -05:00
, MaxCollisionPerCell ( 1 )
2019-06-08 17:15:34 -04:00
, SaveBreakingData ( false )
, DoGenerateBreakingData ( false )
, BreakingDataSizeMax ( 512 )
, DoBreakingDataSpatialHash ( false )
, BreakingDataSpatialHashRadius ( 50.f )
, MaxBreakingPerCell ( 1 )
2018-12-12 11:25:29 -05:00
, SaveTrailingData ( false )
2019-06-08 17:15:34 -04:00
, DoGenerateTrailingData ( false )
, TrailingDataSizeMax ( 512 )
, TrailingMinSpeedThreshold ( 200.f )
2018-12-12 11:25:29 -05:00
, TrailingMinVolumeThreshold ( 10000.f )
{
}
2022-11-09 20:53:21 -05:00
# undef COPY_ON_WRITE_ATTRIBUTE
# define COPY_ON_WRITE_ATTRIBUTE(Type, Name, Group) \
const TManagedArray < Type > & UGeometryCollectionComponent : : Get # # Name # # Array ( ) const \
{ \
return Indirect # # Name # # Array ? \
* Indirect # # Name # # Array : RestCollection - > GetGeometryCollection ( ) - > Name ; \
} \
TManagedArray < Type > & UGeometryCollectionComponent : : Get # # Name # # ArrayCopyOnWrite ( ) \
{ \
if ( ! Indirect # # Name # # Array ) \
{ \
static FName StaticName ( # Name ) ; \
DynamicCollection - > AddAttribute < Type > ( StaticName , Group ) ; \
DynamicCollection - > CopyAttribute ( \
* RestCollection - > GetGeometryCollection ( ) , StaticName , Group ) ; \
Indirect # # Name # # Array = \
& DynamicCollection - > ModifyAttribute < Type > ( StaticName , Group ) ; \
CopyOnWriteAttributeList . Add ( \
reinterpret_cast < FManagedArrayBase * * > ( & Indirect # # Name # # Array ) ) ; \
} \
return * Indirect # # Name # # Array ; \
} \
void UGeometryCollectionComponent : : Reset # # Name # # ArrayDynamic ( ) \
{ \
Indirect # # Name # # Array = NULL ; \
} \
const TManagedArray < Type > & UGeometryCollectionComponent : : Get # # Name # # ArrayRest ( ) const \
{ \
return RestCollection - > GetGeometryCollection ( ) - > Name ; \
} \
// Define the methods
COPY_ON_WRITE_ATTRIBUTES
2018-12-12 11:25:29 -05:00
UGeometryCollectionComponent : : UGeometryCollectionComponent ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
, ChaosSolverActor ( nullptr )
2019-06-08 17:15:34 -04:00
, InitializationState ( ESimulationInitializationState : : Unintialized )
, ObjectType ( EObjectStateTypeEnum : : Chaos_Object_Dynamic )
2021-12-02 18:57:44 -05:00
, bForceMotionBlur ( )
2018-12-12 11:25:29 -05:00
, EnableClustering ( true )
2019-06-08 17:15:34 -04:00
, ClusterGroupIndex ( 0 )
2018-12-12 11:25:29 -05:00
, MaxClusterLevel ( 100 )
2022-02-02 07:39:24 -05:00
, DamageThreshold ( { 500000.f , 50000.f , 5000.f } )
2021-01-29 01:12:30 -04:00
, bUseSizeSpecificDamageThreshold ( false )
2022-06-21 22:08:04 -04:00
, bAllowRemovalOnSleep ( true )
, bAllowRemovalOnBreak ( true )
2021-03-19 15:28:38 -04:00
, ClusterConnectionType_DEPRECATED ( EClusterConnectionTypeEnum : : Chaos_MinimalSpanningSubsetDelaunayTriangulation )
2019-06-08 17:15:34 -04:00
, CollisionGroup ( 0 )
, CollisionSampleFraction ( 1.0 )
2018-12-12 11:25:29 -05:00
, InitialVelocityType ( EInitialVelocityTypeEnum : : Chaos_Initial_Velocity_User_Defined )
, InitialLinearVelocity ( 0.f , 0.f , 0.f )
, InitialAngularVelocity ( 0.f , 0.f , 0.f )
2019-06-08 17:15:34 -04:00
, BaseRigidBodyIndex ( INDEX_NONE )
, NumParticlesAdded ( 0 )
, CachePlayback ( false )
, bNotifyBreaks ( false )
, bNotifyCollisions ( false )
2021-08-31 20:24:01 -04:00
, bNotifyRemovals ( false )
2022-07-12 17:47:42 -04:00
, bNotifyCrumblings ( false )
2022-03-01 14:33:59 -05:00
, bStoreVelocities ( false )
2021-03-18 20:04:04 -04:00
, bShowBoneColors ( false )
2022-06-06 13:01:40 -04:00
# if WITH_EDITORONLY_DATA
, bEnableRunTimeDataCollection ( false )
, RunTimeDataCollectionGuid ( FGuid : : NewGuid ( ) )
# endif
2020-09-01 14:07:48 -04:00
, bEnableReplication ( false )
2022-04-25 13:09:18 -04:00
, bEnableAbandonAfterLevel ( true )
2022-09-14 13:58:55 -04:00
, ReplicationAbandonClusterLevel_DEPRECATED ( 0 )
, ReplicationAbandonAfterLevel ( 0 )
2018-12-12 11:25:29 -05:00
, bRenderStateDirty ( true )
2019-06-08 17:15:34 -04:00
, bEnableBoneSelection ( false )
2018-12-12 11:25:29 -05:00
, ViewLevel ( - 1 )
2019-06-08 17:15:34 -04:00
, NavmeshInvalidationTimeSliceIndex ( 0 )
, IsObjectDynamic ( false )
, IsObjectLoading ( true )
2019-08-02 09:01:58 -04:00
, PhysicsProxy ( nullptr )
2018-12-12 11:25:29 -05:00
# if WITH_EDITOR && WITH_EDITORONLY_DATA
, EditorActor ( nullptr )
# endif
2019-06-08 17:15:34 -04:00
# if GEOMETRYCOLLECTION_EDITOR_SELECTION
, bIsTransformSelectionModeEnabled ( false )
# endif // #if GEOMETRYCOLLECTION_EDITOR_SELECTION
2021-05-01 17:51:29 -04:00
, bIsMoving ( false )
2018-12-12 11:25:29 -05:00
{
PrimaryComponentTick . bCanEverTick = true ;
bTickInEditor = true ;
bAutoActivate = true ;
2019-06-08 17:15:34 -04:00
static uint32 GlobalNavMeshInvalidationCounter = 0 ;
//space these out over several frames (3 is arbitrary)
GlobalNavMeshInvalidationCounter + = 3 ;
NavmeshInvalidationTimeSliceIndex = GlobalNavMeshInvalidationCounter ;
// default current cache time
CurrentCacheTime = MAX_flt ;
SetGenerateOverlapEvents ( false ) ;
2020-04-02 11:57:01 -04:00
// By default use the destructible object channel unless the user specifies otherwise
BodyInstance . SetObjectType ( ECC_Destructible ) ;
2020-04-14 13:39:39 -04:00
2021-05-25 22:01:05 -04:00
// By default, we initialize immediately. If this is set false, we defer initialization.
BodyInstance . bSimulatePhysics = true ;
2020-04-14 13:39:39 -04:00
EventDispatcher = ObjectInitializer . CreateDefaultSubobject < UChaosGameplayEventDispatcher > ( this , TEXT ( " GameplayEventDispatcher " ) ) ;
2020-04-30 07:34:59 -04:00
2020-06-23 18:40:00 -04:00
DynamicCollection = nullptr ;
2020-04-30 07:34:59 -04:00
bHasCustomNavigableGeometry = EHasCustomNavigableGeometry : : Yes ;
2020-09-01 14:07:48 -04:00
bWantsInitializeComponent = true ;
2021-02-18 13:20:03 -04:00
2022-08-23 17:17:36 -04:00
// make sure older asset are using the default behaviour
DamagePropagationData . bEnabled = false ;
2018-12-12 11:25:29 -05:00
}
2022-11-21 07:56:36 -05:00
Chaos : : FPhysicsSolver * UGeometryCollectionComponent : : GetSolver ( const UGeometryCollectionComponent & GeometryCollectionComponent )
2018-12-12 11:25:29 -05:00
{
2020-09-01 14:07:48 -04:00
if ( GeometryCollectionComponent . ChaosSolverActor )
{
return GeometryCollectionComponent . ChaosSolverActor - > GetSolver ( ) ;
}
else if ( UWorld * CurrentWorld = GeometryCollectionComponent . GetWorld ( ) )
{
if ( FPhysScene * Scene = CurrentWorld - > GetPhysicsScene ( ) )
{
return Scene - > GetSolver ( ) ;
}
}
return nullptr ;
2019-10-02 17:27:26 -04:00
}
2018-12-12 11:25:29 -05:00
void UGeometryCollectionComponent : : BeginPlay ( )
{
Super : : BeginPlay ( ) ;
2021-11-22 21:18:29 -05:00
# if WITH_EDITOR
2021-11-23 16:50:50 -05:00
if ( RestCollection ! = nullptr )
2021-11-22 21:18:29 -05:00
{
2021-11-23 16:50:50 -05:00
if ( RestCollection - > GetGeometryCollection ( ) - > HasAttribute ( " ExplodedVector " , FGeometryCollection : : TransformGroup ) )
{
RestCollection - > GetGeometryCollection ( ) - > RemoveAttribute ( " ExplodedVector " , FGeometryCollection : : TransformGroup ) ;
}
2021-11-22 21:18:29 -05:00
}
# endif
2019-06-08 17:15:34 -04:00
// default current cache time
2021-12-02 18:57:44 -05:00
CurrentCacheTime = MAX_flt ;
2022-10-21 19:51:57 -04:00
// we only enable ISM if we are playing ( not in editing mode because of various side effect like selection )
RegisterToISMPool ( ) ;
2018-12-12 11:25:29 -05:00
}
2019-09-16 13:42:25 -04:00
void UGeometryCollectionComponent : : EndPlay ( const EEndPlayReason : : Type ReasonEnd )
2018-12-12 11:25:29 -05:00
{
# if WITH_EDITOR && WITH_EDITORONLY_DATA
// Track our editor component if needed for syncing simulations back from PIE on shutdown
EditorActor = EditorUtilities : : GetEditorWorldCounterpartActor ( GetTypedOuter < AActor > ( ) ) ;
# endif
2022-10-21 19:51:57 -04:00
UnregisterFromISMPool ( ) ;
2018-12-12 11:25:29 -05:00
Super : : EndPlay ( ReasonEnd ) ;
2019-06-08 17:15:34 -04:00
CurrentCacheTime = MAX_flt ;
2018-12-12 11:25:29 -05:00
}
2020-09-01 14:07:48 -04:00
void UGeometryCollectionComponent : : GetLifetimeReplicatedProps ( TArray < FLifetimeProperty > & OutLifetimeProps ) const
{
Super : : GetLifetimeReplicatedProps ( OutLifetimeProps ) ;
2022-05-04 12:47:38 -04:00
/*
2020-09-01 14:07:48 -04:00
FDoRepLifetimeParams Params ;
Params . bIsPushBased = true ;
Params . RepNotifyCondition = REPNOTIFY_OnChanged ;
2022-05-04 12:47:38 -04:00
DOREPLIFETIME_WITH_PARAMS_FAST ( UGeometryCollectionComponent , RepData , Params ) ; */
DOREPLIFETIME ( UGeometryCollectionComponent , RepData ) ;
2020-09-01 14:07:48 -04:00
}
2022-07-06 11:17:25 -04:00
namespace
{
void UpdateGlobalMatricesWithExplodedVectors ( TArray < FMatrix > & GlobalMatricesIn , FGeometryCollection & GeometryCollection )
{
int32 NumMatrices = GlobalMatricesIn . Num ( ) ;
if ( GlobalMatricesIn . Num ( ) > 0 )
{
if ( GeometryCollection . HasAttribute ( " ExplodedVector " , FGeometryCollection : : TransformGroup ) )
{
const TManagedArray < FVector3f > & ExplodedVectors = GeometryCollection . GetAttribute < FVector3f > ( " ExplodedVector " , FGeometryCollection : : TransformGroup ) ;
check ( NumMatrices = = ExplodedVectors . Num ( ) ) ;
for ( int32 tt = 0 , nt = NumMatrices ; tt < nt ; + + tt )
{
GlobalMatricesIn [ tt ] = GlobalMatricesIn [ tt ] . ConcatTranslation ( ( FVector ) ExplodedVectors [ tt ] ) ;
}
}
}
}
}
2022-06-15 15:12:35 -04:00
FBox UGeometryCollectionComponent : : ComputeBounds ( const FMatrix & LocalToWorldWithScale ) const
{
FBox BoundingBox ( ForceInit ) ;
if ( RestCollection )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
//Hold on to reference so it doesn't get GC'ed
auto HackGeometryCollectionPtr = RestCollection - > GetGeometryCollection ( ) ;
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
const TManagedArray < FBox > & BoundingBoxes = GetBoundingBoxArray ( ) ;
const TManagedArray < int32 > & TransformIndices = GetTransformIndexArray ( ) ;
const TManagedArray < int32 > & ParentIndices = GetParentArray ( ) ;
const TManagedArray < int32 > & TransformToGeometryIndex = GetTransformToGeometryIndexArray ( ) ;
2021-04-01 10:41:00 -04:00
const TManagedArray < FTransform > & Transforms = GetTransformArray ( ) ;
2018-12-12 11:25:29 -05:00
const int32 NumBoxes = BoundingBoxes . Num ( ) ;
2021-12-13 15:59:48 -05:00
2021-04-20 09:50:07 -04:00
int32 NumElements = HackGeometryCollectionPtr - > NumElements ( FGeometryCollection : : TransformGroup ) ;
if ( RestCollection - > EnableNanite & & HackGeometryCollectionPtr - > HasAttribute ( " BoundingBox " , FGeometryCollection : : TransformGroup ) & & NumElements )
2019-06-08 17:15:34 -04:00
{
2021-04-20 09:50:07 -04:00
TArray < FMatrix > TmpGlobalMatrices ;
GeometryCollectionAlgo : : GlobalMatrices ( Transforms , ParentIndices , TmpGlobalMatrices ) ;
2022-05-10 18:56:28 -04:00
TManagedArray < FBox > & TransformBounds = HackGeometryCollectionPtr - > ModifyAttribute < FBox > ( " BoundingBox " , " Transform " ) ;
2021-04-28 05:36:47 -04:00
for ( int32 TransformIndex = 0 ; TransformIndex < HackGeometryCollectionPtr - > NumElements ( FGeometryCollection : : TransformGroup ) ; TransformIndex + + )
2021-04-20 09:50:07 -04:00
{
BoundingBox + = TransformBounds [ TransformIndex ] . TransformBy ( TmpGlobalMatrices [ TransformIndex ] * LocalToWorldWithScale ) ;
}
}
else if ( NumElements = = 0 | | GlobalMatrices . Num ( ) ! = RestCollection - > NumElements ( FGeometryCollection : : TransformGroup ) )
{
// #todo(dmp): we could do the bbox transform in parallel with a bit of reformulating
// #todo(dmp): there are some cases where the calcbounds function is called before the component
// has set the global matrices cache while in the editor. This is a somewhat weak guard against this
// to default to just calculating tmp global matrices. This should be removed or modified somehow
// such that we always cache the global matrices and this method always does the correct behavior
2019-06-08 17:15:34 -04:00
TArray < FMatrix > TmpGlobalMatrices ;
2021-04-01 10:41:00 -04:00
GeometryCollectionAlgo : : GlobalMatrices ( Transforms , ParentIndices , TmpGlobalMatrices ) ;
2019-06-08 17:15:34 -04:00
if ( TmpGlobalMatrices . Num ( ) = = 0 )
2018-12-12 11:25:29 -05:00
{
2022-06-15 15:12:35 -04:00
BoundingBox = FBox ( ForceInitToZero ) ;
2018-12-12 11:25:29 -05:00
}
2022-06-15 15:12:35 -04:00
else
2019-06-08 17:15:34 -04:00
{
2022-07-06 11:17:25 -04:00
UpdateGlobalMatricesWithExplodedVectors ( TmpGlobalMatrices , * ( RestCollection - > GetGeometryCollection ( ) ) ) ;
2022-06-15 15:12:35 -04:00
for ( int32 BoxIdx = 0 ; BoxIdx < NumBoxes ; + + BoxIdx )
2019-06-08 17:15:34 -04:00
{
2022-06-15 15:12:35 -04:00
const int32 TransformIndex = TransformIndices [ BoxIdx ] ;
if ( RestCollection - > GetGeometryCollection ( ) - > IsGeometry ( TransformIndex ) )
{
BoundingBox + = BoundingBoxes [ BoxIdx ] . TransformBy ( TmpGlobalMatrices [ TransformIndex ] * LocalToWorldWithScale ) ;
}
2019-06-08 17:15:34 -04:00
}
2022-06-15 15:12:35 -04:00
2019-06-08 17:15:34 -04:00
}
}
2021-05-05 21:03:44 -04:00
else if ( bGeometryCollectionSingleThreadedBoundsCalculation )
{
CHAOS_ENSURE ( false ) ; // this is slower and only enabled through a pvar debugging, disable bGeometryCollectionSingleThreadedBoundsCalculation in a production environment.
for ( int32 BoxIdx = 0 ; BoxIdx < NumBoxes ; + + BoxIdx )
{
const int32 TransformIndex = TransformIndices [ BoxIdx ] ;
if ( RestCollection - > GetGeometryCollection ( ) - > IsGeometry ( TransformIndex ) )
{
BoundingBox + = BoundingBoxes [ BoxIdx ] . TransformBy ( GlobalMatrices [ TransformIndex ] * LocalToWorldWithScale ) ;
}
}
}
2019-06-08 17:15:34 -04:00
else
{
2022-01-24 10:54:27 -05:00
if ( bChaos_BoxCalcBounds_ISPC_Enabled )
2019-06-08 17:15:34 -04:00
{
2022-01-24 10:54:27 -05:00
# if INTEL_ISPC
ispc : : BoxCalcBounds (
( int32 * ) & TransformToGeometryIndex [ 0 ] ,
( int32 * ) & TransformIndices [ 0 ] ,
( ispc : : FMatrix * ) & GlobalMatrices [ 0 ] ,
( ispc : : FBox * ) & BoundingBoxes [ 0 ] ,
( ispc : : FMatrix & ) LocalToWorldWithScale ,
( ispc : : FBox & ) BoundingBox ,
NumBoxes ) ;
# endif
}
else
{
for ( int32 BoxIdx = 0 ; BoxIdx < NumBoxes ; + + BoxIdx )
2019-06-08 17:15:34 -04:00
{
2022-01-24 10:54:27 -05:00
const int32 TransformIndex = TransformIndices [ BoxIdx ] ;
if ( RestCollection - > GetGeometryCollection ( ) - > IsGeometry ( TransformIndex ) )
{
BoundingBox + = BoundingBoxes [ BoxIdx ] . TransformBy ( GlobalMatrices [ TransformIndex ] * LocalToWorldWithScale ) ;
}
2019-06-08 17:15:34 -04:00
}
}
2018-12-12 11:25:29 -05:00
}
}
2022-06-15 15:12:35 -04:00
return BoundingBox ;
}
FBoxSphereBounds UGeometryCollectionComponent : : CalcBounds ( const FTransform & LocalToWorldIn ) const
{
SCOPE_CYCLE_COUNTER ( STAT_GCCUpdateBounds ) ;
// #todo(dmp): hack to make bounds calculation work when we don't have valid physics proxy data. This will
// force bounds calculation.
const FGeometryCollectionResults * Results = PhysicsProxy ? PhysicsProxy - > GetConsumerResultsGT ( ) : nullptr ;
const int32 NumTransforms = Results ? Results - > GlobalTransforms . Num ( ) : 0 ;
if ( bChaos_GC_CacheComponentSpaceBounds )
{
bool NeedBoundsUpdate = false ;
NeedBoundsUpdate | = ( ComponentSpaceBounds . GetSphere ( ) . W < 1e-5 ) ;
NeedBoundsUpdate | = CachePlayback ;
NeedBoundsUpdate | = ( NumTransforms > 0 ) ;
NeedBoundsUpdate | = ( DynamicCollection & & DynamicCollection - > IsDirty ( ) ) ;
if ( NeedBoundsUpdate )
{
ComponentSpaceBounds = ComputeBounds ( FMatrix : : Identity ) ;
}
else
{
NeedBoundsUpdate = false ;
}
return ComponentSpaceBounds . TransformBy ( LocalToWorldIn ) ;
}
const FMatrix LocalToWorldWithScale = LocalToWorldIn . ToMatrixWithScale ( ) ;
return FBoxSphereBounds ( ComputeBounds ( LocalToWorldWithScale ) ) ;
2018-12-12 11:25:29 -05:00
}
2022-11-09 20:53:21 -05:00
int32 UGeometryCollectionComponent : : GetNumElements ( FName Group ) const
{
int32 Size = RestCollection - > NumElements ( Group ) ; //assume rest collection has the group and is connected to dynamic.
return Size > 0 ? Size : DynamicCollection - > NumElements ( Group ) ; //if not, maybe dynamic has the group
}
2022-07-06 11:17:25 -04:00
void UGeometryCollectionComponent : : UpdateCachedBounds ( )
{
ComponentSpaceBounds = ComputeBounds ( FMatrix : : Identity ) ;
CalculateLocalBounds ( ) ;
UpdateBounds ( ) ;
}
2020-02-06 13:13:41 -05:00
void UGeometryCollectionComponent : : CreateRenderState_Concurrent ( FRegisterComponentContext * Context )
2018-12-12 11:25:29 -05:00
{
2020-02-06 13:13:41 -05:00
Super : : CreateRenderState_Concurrent ( Context ) ;
2018-12-12 11:25:29 -05:00
}
FPrimitiveSceneProxy * UGeometryCollectionComponent : : CreateSceneProxy ( )
{
2021-05-17 22:54:18 -04:00
static const auto NaniteProxyRenderModeVar = IConsoleManager : : Get ( ) . FindConsoleVariable ( TEXT ( " r.Nanite.ProxyRenderMode " ) ) ;
const int32 NaniteProxyRenderMode = ( NaniteProxyRenderModeVar ! = nullptr ) ? ( NaniteProxyRenderModeVar - > GetInt ( ) ! = 0 ) : 0 ;
2021-03-25 18:53:29 -04:00
FPrimitiveSceneProxy * LocalSceneProxy = nullptr ;
2020-07-15 03:39:13 -04:00
2021-03-25 18:53:29 -04:00
if ( RestCollection )
2020-07-15 03:39:13 -04:00
{
2021-03-25 18:53:29 -04:00
if ( UseNanite ( GetScene ( ) - > GetShaderPlatform ( ) ) & &
RestCollection - > EnableNanite & &
RestCollection - > NaniteData ! = nullptr & &
GGeometryCollectionNanite ! = 0 )
{
LocalSceneProxy = new FNaniteGeometryCollectionSceneProxy ( this ) ;
2021-12-02 18:57:44 -05:00
// ForceMotionBlur means we maintain bIsMoving, regardless of actual state.
if ( bForceMotionBlur )
{
bIsMoving = true ;
if ( LocalSceneProxy )
{
FNaniteGeometryCollectionSceneProxy * NaniteProxy = static_cast < FNaniteGeometryCollectionSceneProxy * > ( LocalSceneProxy ) ;
ENQUEUE_RENDER_COMMAND ( NaniteProxyOnMotionEnd ) (
[ NaniteProxy ] ( FRHICommandListImmediate & RHICmdList )
{
NaniteProxy - > OnMotionBegin ( ) ;
}
) ;
}
}
2021-03-25 18:53:29 -04:00
}
2021-05-17 22:54:18 -04:00
// If we didn't get a proxy, but Nanite was enabled on the asset when it was built, evaluate proxy creation
else if ( RestCollection - > EnableNanite & & NaniteProxyRenderMode ! = 0 )
{
// Do not render Nanite proxy
return nullptr ;
}
2021-03-25 18:53:29 -04:00
else
{
LocalSceneProxy = new FGeometryCollectionSceneProxy ( this ) ;
}
if ( RestCollection - > HasVisibleGeometry ( ) )
{
FGeometryCollectionConstantData * const ConstantData = : : new FGeometryCollectionConstantData ;
InitConstantData ( ConstantData ) ;
2021-04-24 04:37:11 -04:00
FGeometryCollectionDynamicData * const DynamicData = InitDynamicData ( true /* initialization */ ) ;
2021-03-25 18:53:29 -04:00
if ( LocalSceneProxy - > IsNaniteMesh ( ) )
{
FNaniteGeometryCollectionSceneProxy * const GeometryCollectionSceneProxy = static_cast < FNaniteGeometryCollectionSceneProxy * > ( LocalSceneProxy ) ;
// ...
2021-04-28 05:36:47 -04:00
# if GEOMETRYCOLLECTION_EDITOR_SELECTION
2021-03-25 18:53:29 -04:00
if ( bIsTransformSelectionModeEnabled )
{
// ...
}
2021-04-28 05:36:47 -04:00
# endif
2021-03-25 18:53:29 -04:00
ENQUEUE_RENDER_COMMAND ( CreateRenderState ) (
[ GeometryCollectionSceneProxy , ConstantData , DynamicData ] ( FRHICommandListImmediate & RHICmdList )
{
2021-04-20 10:45:04 -04:00
GeometryCollectionSceneProxy - > SetConstantData_RenderThread ( ConstantData ) ;
2021-04-28 19:53:28 -04:00
2021-04-20 10:45:04 -04:00
if ( DynamicData )
2021-03-25 18:53:29 -04:00
{
GeometryCollectionSceneProxy - > SetDynamicData_RenderThread ( DynamicData ) ;
2021-04-20 10:45:04 -04:00
}
2021-04-28 05:36:47 -04:00
2021-05-11 01:18:05 -04:00
bool bValidUpdate = false ;
2021-04-28 05:36:47 -04:00
if ( FPrimitiveSceneInfo * PrimitiveSceneInfo = GeometryCollectionSceneProxy - > GetPrimitiveSceneInfo ( ) )
2021-04-20 10:45:04 -04:00
{
2021-05-11 01:18:05 -04:00
bValidUpdate = PrimitiveSceneInfo - > RequestGPUSceneUpdate ( ) ;
2021-03-25 18:53:29 -04:00
}
2021-05-11 01:18:05 -04:00
// Deferred the GPU Scene update if the primitive scene info is not yet initialized with a valid index.
GeometryCollectionSceneProxy - > SetRequiresGPUSceneUpdate_RenderThread ( ! bValidUpdate ) ;
2021-03-25 18:53:29 -04:00
}
) ;
}
else
{
FGeometryCollectionSceneProxy * const GeometryCollectionSceneProxy = static_cast < FGeometryCollectionSceneProxy * > ( LocalSceneProxy ) ;
2021-04-28 05:36:47 -04:00
# if GEOMETRYCOLLECTION_EDITOR_SELECTION
2021-03-25 18:53:29 -04:00
// Re-init subsections
if ( bIsTransformSelectionModeEnabled )
{
GeometryCollectionSceneProxy - > UseSubSections ( true , false ) ; // Do not force reinit now, it'll be done in SetConstantData_RenderThread
}
2021-04-28 05:36:47 -04:00
# endif
2021-03-25 18:53:29 -04:00
ENQUEUE_RENDER_COMMAND ( CreateRenderState ) (
[ GeometryCollectionSceneProxy , ConstantData , DynamicData ] ( FRHICommandListImmediate & RHICmdList )
{
2021-04-20 10:45:04 -04:00
GeometryCollectionSceneProxy - > SetConstantData_RenderThread ( ConstantData ) ;
if ( DynamicData )
2021-03-25 18:53:29 -04:00
{
GeometryCollectionSceneProxy - > SetDynamicData_RenderThread ( DynamicData ) ;
}
}
) ;
}
}
}
2020-07-15 03:39:13 -04:00
2021-04-28 05:36:47 -04:00
return LocalSceneProxy ;
2018-12-12 11:25:29 -05:00
}
bool UGeometryCollectionComponent : : ShouldCreatePhysicsState ( ) const
{
// Geometry collections always create physics state, not relying on the
// underlying implementation that requires the body instance to decide
return true ;
}
bool UGeometryCollectionComponent : : HasValidPhysicsState ( ) const
{
2019-08-02 09:01:58 -04:00
return PhysicsProxy ! = nullptr ;
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
void UGeometryCollectionComponent : : SetNotifyBreaks ( bool bNewNotifyBreaks )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
if ( bNotifyBreaks ! = bNewNotifyBreaks )
{
bNotifyBreaks = bNewNotifyBreaks ;
UpdateBreakEventRegistration ( ) ;
}
}
2021-08-31 20:24:01 -04:00
void UGeometryCollectionComponent : : SetNotifyRemovals ( bool bNewNotifyRemovals )
{
if ( bNotifyRemovals ! = bNewNotifyRemovals )
{
bNotifyRemovals = bNewNotifyRemovals ;
UpdateRemovalEventRegistration ( ) ;
}
}
2022-07-12 17:47:42 -04:00
void UGeometryCollectionComponent : : SetNotifyCrumblings ( bool bNewNotifyCrumblings )
{
if ( bNotifyCrumblings ! = bNewNotifyCrumblings )
{
bNotifyCrumblings = bNewNotifyCrumblings ;
UpdateBreakEventRegistration ( ) ;
}
}
2021-05-18 14:32:57 -04:00
FBodyInstance * UGeometryCollectionComponent : : GetBodyInstance ( FName BoneName /*= NAME_None*/ , bool bGetWelded /*= true*/ , int32 Index /*=INDEX_NONE*/ ) const
2019-06-08 17:15:34 -04:00
{
return nullptr ; // const_cast<FBodyInstance*>(&DummyBodyInstance);
}
void UGeometryCollectionComponent : : SetNotifyRigidBodyCollision ( bool bNewNotifyRigidBodyCollision )
{
Super : : SetNotifyRigidBodyCollision ( bNewNotifyRigidBodyCollision ) ;
UpdateRBCollisionEventRegistration ( ) ;
}
2021-05-25 22:01:05 -04:00
bool UGeometryCollectionComponent : : CanEditSimulatePhysics ( )
{
return true ;
}
void UGeometryCollectionComponent : : SetSimulatePhysics ( bool bEnabled )
{
2022-08-26 16:19:48 -04:00
// make sure owner component is set to null before calling Super::SetSimulatePhysics
// this will prevent unwanted log warning to trigger in BodyInstance::SetInstanceSimulatePhysics() because
// in geometry collection , body instance never holds a valid physics handle
const TWeakObjectPtr < UPrimitiveComponent > PreviousOwnerCOmponent = BodyInstance . OwnerComponent ;
{
BodyInstance . OwnerComponent = nullptr ;
Super : : SetSimulatePhysics ( bEnabled ) ;
BodyInstance . OwnerComponent = PreviousOwnerCOmponent ;
}
2021-05-25 22:01:05 -04:00
if ( bEnabled & & ! PhysicsProxy )
{
RegisterAndInitializePhysicsProxy ( ) ;
}
2022-04-12 19:07:33 -04:00
}
2021-05-25 22:01:05 -04:00
2022-04-12 19:07:33 -04:00
void UGeometryCollectionComponent : : AddForce ( FVector Force , FName BoneName , bool bAccelChange )
{
ensure ( bAccelChange = = false ) ; // not supported
const FVector Direction = Force . GetSafeNormal ( ) ;
const FVector : : FReal Magnitude = Force . Size ( ) ;
const FFieldSystemCommand Command = FFieldObjectCommands : : CreateFieldCommand ( EFieldPhysicsType : : Field_LinearForce , new FUniformVector ( Magnitude , Direction ) ) ;
DispatchFieldCommand ( Command ) ;
}
2022-10-04 19:02:56 -04:00
void UGeometryCollectionComponent : : AddForceAtLocation ( FVector Force , FVector WorldLocation , FName BoneName )
{
if ( PhysicsProxy )
{
PhysicsProxy - > ApplyForceAt_External ( Force , WorldLocation ) ;
}
}
2022-04-13 12:39:04 -04:00
void UGeometryCollectionComponent : : AddImpulse ( FVector Impulse , FName BoneName , bool bVelChange )
{
const FVector Direction = Impulse . GetSafeNormal ( ) ;
const FVector : : FReal Magnitude = Impulse . Size ( ) ;
const EFieldPhysicsType FieldType = bVelChange ? EFieldPhysicsType : : Field_LinearVelocity : EFieldPhysicsType : : Field_LinearImpulse ;
const FFieldSystemCommand Command = FFieldObjectCommands : : CreateFieldCommand ( FieldType , new FUniformVector ( Magnitude , Direction ) ) ;
DispatchFieldCommand ( Command ) ;
}
2022-10-04 19:02:56 -04:00
void UGeometryCollectionComponent : : AddImpulseAtLocation ( FVector Impulse , FVector WorldLocation , FName BoneName )
{
if ( PhysicsProxy )
{
PhysicsProxy - > ApplyImpulseAt_External ( Impulse , WorldLocation ) ;
}
}
2022-04-13 12:39:04 -04:00
TUniquePtr < FFieldNodeBase > MakeRadialField ( const FVector & Origin , float Radius , float Strength , ERadialImpulseFalloff Falloff )
{
TUniquePtr < FFieldNodeBase > Field ;
if ( Falloff = = ERadialImpulseFalloff : : RIF_Constant )
{
Field . Reset ( new FRadialVector ( Strength , Origin ) ) ;
}
else
{
FRadialFalloff * FalloffField = new FRadialFalloff ( Strength , 0.f , 1.f , 0.f , Radius , Origin , EFieldFalloffType : : Field_Falloff_Linear ) ;
FRadialVector * VectorField = new FRadialVector ( 1.f , Origin ) ;
Field . Reset ( new FSumVector ( 1.0 , FalloffField , VectorField , nullptr , Field_Multiply ) ) ;
}
return Field ;
}
2022-04-12 19:07:33 -04:00
void UGeometryCollectionComponent : : AddRadialForce ( FVector Origin , float Radius , float Strength , ERadialImpulseFalloff Falloff , bool bAccelChange )
{
ensure ( bAccelChange = = false ) ; // not supported
if ( bIgnoreRadialForce )
{
return ;
}
2022-04-13 12:39:04 -04:00
if ( TUniquePtr < FFieldNodeBase > Field = MakeRadialField ( Origin , Radius , Strength , Falloff ) )
2022-04-12 19:07:33 -04:00
{
2022-04-13 12:39:04 -04:00
const FFieldSystemCommand Command = FFieldObjectCommands : : CreateFieldCommand ( EFieldPhysicsType : : Field_LinearForce , Field . Release ( ) ) ;
DispatchFieldCommand ( Command ) ;
2022-04-12 19:07:33 -04:00
}
2022-04-13 12:39:04 -04:00
}
void UGeometryCollectionComponent : : AddRadialImpulse ( FVector Origin , float Radius , float Strength , enum ERadialImpulseFalloff Falloff , bool bVelChange )
{
if ( bIgnoreRadialImpulse )
2022-04-12 19:07:33 -04:00
{
2022-04-13 12:39:04 -04:00
return ;
2022-04-12 19:07:33 -04:00
}
2022-04-13 12:39:04 -04:00
if ( TUniquePtr < FFieldNodeBase > Field = MakeRadialField ( Origin , Radius , Strength , Falloff ) )
2022-04-12 19:07:33 -04:00
{
2022-04-13 12:39:04 -04:00
const EFieldPhysicsType FieldType = bVelChange ? EFieldPhysicsType : : Field_LinearVelocity : EFieldPhysicsType : : Field_LinearImpulse ;
const FFieldSystemCommand Command = FFieldObjectCommands : : CreateFieldCommand ( FieldType , Field . Release ( ) ) ;
2022-04-12 19:07:33 -04:00
DispatchFieldCommand ( Command ) ;
}
}
void UGeometryCollectionComponent : : AddTorqueInRadians ( FVector Torque , FName BoneName , bool bAccelChange )
{
ensure ( bAccelChange = = false ) ; // not supported
const FVector Direction = Torque . GetSafeNormal ( ) ;
const FVector : : FReal Magnitude = Torque . Size ( ) ;
const FFieldSystemCommand Command = FFieldObjectCommands : : CreateFieldCommand ( EFieldPhysicsType : : Field_AngularTorque , new FUniformVector ( Magnitude , Direction ) ) ;
DispatchFieldCommand ( Command ) ;
2021-05-25 22:01:05 -04:00
}
2019-06-08 17:15:34 -04:00
void UGeometryCollectionComponent : : DispatchBreakEvent ( const FChaosBreakEvent & Event )
{
// native
NotifyBreak ( Event ) ;
// bp
if ( OnChaosBreakEvent . IsBound ( ) )
{
OnChaosBreakEvent . Broadcast ( Event ) ;
}
}
2021-08-31 20:24:01 -04:00
void UGeometryCollectionComponent : : DispatchRemovalEvent ( const FChaosRemovalEvent & Event )
{
// native
NotifyRemoval ( Event ) ;
// bp
if ( OnChaosRemovalEvent . IsBound ( ) )
{
OnChaosRemovalEvent . Broadcast ( Event ) ;
}
}
2022-07-12 17:47:42 -04:00
void UGeometryCollectionComponent : : DispatchCrumblingEvent ( const FChaosCrumblingEvent & Event )
{
// bp
if ( OnChaosCrumblingEvent . IsBound ( ) )
{
OnChaosCrumblingEvent . Broadcast ( Event ) ;
}
}
2020-04-30 07:34:59 -04:00
bool UGeometryCollectionComponent : : DoCustomNavigableGeometryExport ( FNavigableGeometryExport & GeomExport ) const
{
2020-08-11 01:36:57 -04:00
if ( ! RestCollection )
{
// No geometry data so skip export - geometry collections don't have other geometry sources
// so return false here to skip non-custom export for this component as well.
return false ;
}
2020-04-30 07:34:59 -04:00
TArray < FVector > OutVertexBuffer ;
TArray < int32 > OutIndexBuffer ;
const FGeometryCollection * const Collection = RestCollection - > GetGeometryCollection ( ) . Get ( ) ;
check ( Collection ) ;
const float SizeThreshold = GGeometryCollectionNavigationSizeThreshold * GGeometryCollectionNavigationSizeThreshold ;
// for all geometry. inspect bounding box build int list of transform indices.
int32 VertexCount = 0 ;
int32 FaceCountEstimate = 0 ;
TArray < int32 > GeometryIndexBuffer ;
TArray < int32 > TransformIndexBuffer ;
int32 NumGeometry = Collection - > NumElements ( FGeometryCollection : : GeometryGroup ) ;
const TManagedArray < FBox > & BoundingBox = Collection - > BoundingBox ;
const TManagedArray < int32 > & TransformIndexArray = Collection - > TransformIndex ;
const TManagedArray < int32 > & VertexCountArray = Collection - > VertexCount ;
const TManagedArray < int32 > & FaceCountArray = Collection - > FaceCount ;
const TManagedArray < int32 > & VertexStartArray = Collection - > VertexStart ;
2021-05-05 15:07:25 -04:00
const TManagedArray < FVector3f > & Vertex = Collection - > Vertex ;
2020-04-30 07:34:59 -04:00
for ( int32 GeometryGroupIndex = 0 ; GeometryGroupIndex < NumGeometry ; GeometryGroupIndex + + )
{
if ( BoundingBox [ GeometryGroupIndex ] . GetSize ( ) . SizeSquared ( ) > SizeThreshold )
{
TransformIndexBuffer . Add ( TransformIndexArray [ GeometryGroupIndex ] ) ;
GeometryIndexBuffer . Add ( GeometryGroupIndex ) ;
VertexCount + = VertexCountArray [ GeometryGroupIndex ] ;
FaceCountEstimate + = FaceCountArray [ GeometryGroupIndex ] ;
}
}
// Get all the geometry transforms in component space (they are stored natively in parent-bone space)
TArray < FTransform > GeomToComponent ;
GeometryCollectionAlgo : : GlobalMatrices ( GetTransformArray ( ) , GetParentArray ( ) , TransformIndexBuffer , GeomToComponent ) ;
OutVertexBuffer . AddUninitialized ( VertexCount ) ;
int32 DestVertex = 0 ;
//for each "subset" we care about
for ( int32 SubsetIndex = 0 ; SubsetIndex < GeometryIndexBuffer . Num ( ) ; + + SubsetIndex )
{
//find indices into the collection data
int32 GeometryIndex = GeometryIndexBuffer [ SubsetIndex ] ;
int32 TransformIndex = TransformIndexBuffer [ SubsetIndex ] ;
int32 SourceGeometryVertexStart = VertexStartArray [ GeometryIndex ] ;
int32 SourceGeometryVertexCount = VertexCountArray [ GeometryIndex ] ;
ParallelFor ( SourceGeometryVertexCount , [ & ] ( int32 PointIdx )
{
//extract vertex from source
int32 SourceGeometryVertexIndex = SourceGeometryVertexStart + PointIdx ;
2022-02-02 07:59:31 -05:00
FVector const VertexInWorldSpace = GeomToComponent [ SubsetIndex ] . TransformPosition ( ( FVector ) Vertex [ SourceGeometryVertexIndex ] ) ;
2020-04-30 07:34:59 -04:00
int32 DestVertexIndex = DestVertex + PointIdx ;
OutVertexBuffer [ DestVertexIndex ] . X = VertexInWorldSpace . X ;
OutVertexBuffer [ DestVertexIndex ] . Y = VertexInWorldSpace . Y ;
OutVertexBuffer [ DestVertexIndex ] . Z = VertexInWorldSpace . Z ;
} ) ;
DestVertex + = SourceGeometryVertexCount ;
}
//gather data needed for indices
const TManagedArray < int32 > & FaceStartArray = Collection - > FaceStart ;
const TManagedArray < FIntVector > & Indices = Collection - > Indices ;
const TManagedArray < bool > & Visible = GetVisibleArray ( ) ;
const TManagedArray < int32 > & MaterialIndex = Collection - > MaterialIndex ;
//pre-allocate enough room (assuming all faces are visible)
OutIndexBuffer . AddUninitialized ( 3 * FaceCountEstimate ) ;
//reset vertex counter so that we base the indices off the new location rather than the global vertex list
DestVertex = 0 ;
int32 DestinationIndex = 0 ;
//leaving index traversal in a different loop to help cache coherency of source data
for ( int32 SubsetIndex = 0 ; SubsetIndex < GeometryIndexBuffer . Num ( ) ; + + SubsetIndex )
{
int32 GeometryIndex = GeometryIndexBuffer [ SubsetIndex ] ;
//for each index, subtract the starting vertex for that geometry to make it 0-based. Then add the new starting vertex index for this geometry
int32 SourceGeometryVertexStart = VertexStartArray [ GeometryIndex ] ;
int32 SourceGeometryVertexCount = VertexCountArray [ GeometryIndex ] ;
int32 IndexDelta = DestVertex - SourceGeometryVertexStart ;
int32 FaceStart = FaceStartArray [ GeometryIndex ] ;
int32 FaceCount = FaceCountArray [ GeometryIndex ] ;
//Copy the faces
for ( int FaceIdx = FaceStart ; FaceIdx < FaceStart + FaceCount ; FaceIdx + + )
{
if ( Visible [ FaceIdx ] )
{
OutIndexBuffer [ DestinationIndex + + ] = Indices [ FaceIdx ] . X + IndexDelta ;
OutIndexBuffer [ DestinationIndex + + ] = Indices [ FaceIdx ] . Y + IndexDelta ;
OutIndexBuffer [ DestinationIndex + + ] = Indices [ FaceIdx ] . Z + IndexDelta ;
}
}
DestVertex + = SourceGeometryVertexCount ;
}
// Invisible faces make the index buffer smaller
OutIndexBuffer . SetNum ( DestinationIndex ) ;
// Push as a custom mesh to navigation system
// #CHAOSTODO This is pretty inefficient as it copies the whole buffer transforming each vert by the component to world
// transform. Investigate a move aware custom mesh for pre-transformed verts to speed this up.
GeomExport . ExportCustomMesh ( OutVertexBuffer . GetData ( ) , OutVertexBuffer . Num ( ) , OutIndexBuffer . GetData ( ) , OutIndexBuffer . Num ( ) , GetComponentToWorld ( ) ) ;
return true ;
}
2020-09-24 00:43:27 -04:00
UPhysicalMaterial * UGeometryCollectionComponent : : GetPhysicalMaterial ( ) const
{
// Pull material from first mesh element to grab physical material. Prefer an override if one exists
2022-02-07 16:26:46 -05:00
UPhysicalMaterial * PhysMatToUse = BodyInstance . GetSimplePhysicalMaterial ( ) ;
2020-09-24 00:43:27 -04:00
2022-03-01 14:33:59 -05:00
if ( ! PhysMatToUse | | PhysMatToUse - > GetFName ( ) = = " DefaultPhysicalMaterial " )
2020-09-24 00:43:27 -04:00
{
// No override, try render materials
const int32 NumMaterials = GetNumMaterials ( ) ;
if ( NumMaterials > 0 )
{
UMaterialInterface * FirstMatInterface = GetMaterial ( 0 ) ;
if ( FirstMatInterface & & FirstMatInterface - > GetPhysicalMaterial ( ) )
{
PhysMatToUse = FirstMatInterface - > GetPhysicalMaterial ( ) ;
}
}
}
if ( ! PhysMatToUse )
{
// Still no material, fallback on default
PhysMatToUse = GEngine - > DefaultPhysMaterial ;
}
// Should definitely have a material at this point.
check ( PhysMatToUse ) ;
return PhysMatToUse ;
}
2021-02-18 13:20:03 -04:00
void UGeometryCollectionComponent : : RefreshEmbeddedGeometry ( )
{
2022-11-16 19:21:50 -05:00
const int32 ExemplarCount = EmbeddedGeometryComponents . Num ( ) ;
if ( ExemplarCount = = 0 )
{
return ;
}
2021-02-18 13:20:03 -04:00
const TManagedArray < int32 > & ExemplarIndexArray = GetExemplarIndexArray ( ) ;
const int32 TransformCount = GlobalMatrices . Num ( ) ;
2022-02-10 18:36:20 -05:00
if ( ! ensureMsgf ( TransformCount = = ExemplarIndexArray . Num ( ) , TEXT ( " GlobalMatrices (Num=%d) cached on GeometryCollectionComponent are not in sync with ExemplarIndexArray (Num=%d) on underlying GeometryCollection; likely missed a dynamic data update " ) , TransformCount , ExemplarIndexArray . Num ( ) ) )
{
return ;
}
2021-02-18 13:20:03 -04:00
2021-08-30 17:11:38 -04:00
const TManagedArray < bool > * HideArray = nullptr ;
if ( RestCollection - > GetGeometryCollection ( ) - > HasAttribute ( " Hide " , FGeometryCollection : : TransformGroup ) )
{
HideArray = & RestCollection - > GetGeometryCollection ( ) - > GetAttribute < bool > ( " Hide " , FGeometryCollection : : TransformGroup ) ;
}
2021-09-05 20:37:59 -04:00
# if WITH_EDITOR
EmbeddedInstanceIndex . Init ( INDEX_NONE , RestCollection - > GetGeometryCollection ( ) - > NumElements ( FGeometryCollection : : TransformGroup ) ) ;
# endif
2021-02-18 13:20:03 -04:00
for ( int32 ExemplarIndex = 0 ; ExemplarIndex < ExemplarCount ; + + ExemplarIndex )
{
2021-09-05 20:37:59 -04:00
# if WITH_EDITOR
EmbeddedBoneMaps [ ExemplarIndex ] . Empty ( TransformCount ) ;
EmbeddedBoneMaps [ ExemplarIndex ] . Reserve ( TransformCount ) ; // Allocate for worst case
# endif
2021-02-18 13:20:03 -04:00
TArray < FTransform > InstanceTransforms ;
InstanceTransforms . Reserve ( TransformCount ) ; // Allocate for worst case
// Construct instance transforms for this exemplar
for ( int32 Idx = 0 ; Idx < TransformCount ; + + Idx )
{
if ( ExemplarIndexArray [ Idx ] = = ExemplarIndex )
{
2021-08-30 17:11:38 -04:00
if ( ! HideArray | | ! ( * HideArray ) [ Idx ] )
{
2021-12-13 15:59:48 -05:00
InstanceTransforms . Add ( FTransform ( GlobalMatrices [ Idx ] ) ) ;
2021-09-05 20:37:59 -04:00
# if WITH_EDITOR
int32 InstanceIndex = EmbeddedBoneMaps [ ExemplarIndex ] . Add ( Idx ) ;
EmbeddedInstanceIndex [ Idx ] = InstanceIndex ;
# endif
2021-12-13 15:59:48 -05:00
}
2021-02-18 13:20:03 -04:00
}
}
if ( EmbeddedGeometryComponents [ ExemplarIndex ] )
{
const int32 InstanceCount = EmbeddedGeometryComponents [ ExemplarIndex ] - > GetInstanceCount ( ) ;
// If the number of instances has changed, we rebuild the structure.
if ( InstanceCount ! = InstanceTransforms . Num ( ) )
{
EmbeddedGeometryComponents [ ExemplarIndex ] - > ClearInstances ( ) ;
EmbeddedGeometryComponents [ ExemplarIndex ] - > PreAllocateInstancesMemory ( InstanceTransforms . Num ( ) ) ;
for ( const FTransform & InstanceTransform : InstanceTransforms )
{
EmbeddedGeometryComponents [ ExemplarIndex ] - > AddInstance ( InstanceTransform ) ;
}
EmbeddedGeometryComponents [ ExemplarIndex ] - > MarkRenderStateDirty ( ) ;
}
else
{
// #todo (bmiller) When ISMC has been changed to be able to update transforms in place, we need to switch this function call over.
EmbeddedGeometryComponents [ ExemplarIndex ] - > BatchUpdateInstancesTransforms ( 0 , InstanceTransforms , false , true , false ) ;
// EmbeddedGeometryComponents[ExemplarIndex]->UpdateKinematicTransforms(InstanceTransforms);
}
}
}
}
2021-09-05 20:37:59 -04:00
# if WITH_EDITOR
void UGeometryCollectionComponent : : SetEmbeddedGeometrySelectable ( bool bSelectableIn )
{
for ( TObjectPtr < UInstancedStaticMeshComponent > EmbeddedGeometryComponent : EmbeddedGeometryComponents )
{
2022-11-11 14:11:40 -05:00
if ( EmbeddedGeometryComponent )
{
EmbeddedGeometryComponent - > bSelectable = bSelectable ;
EmbeddedGeometryComponent - > bHasPerInstanceHitProxies = bSelectable ;
}
2021-09-05 20:37:59 -04:00
}
}
int32 UGeometryCollectionComponent : : EmbeddedIndexToTransformIndex ( const UInstancedStaticMeshComponent * ISMComponent , int32 InstanceIndex ) const
{
for ( int32 ISMIdx = 0 ; ISMIdx < EmbeddedGeometryComponents . Num ( ) ; + + ISMIdx )
{
if ( EmbeddedGeometryComponents [ ISMIdx ] . Get ( ) = = ISMComponent )
{
return ( EmbeddedBoneMaps [ ISMIdx ] [ InstanceIndex ] ) ;
}
}
return INDEX_NONE ;
}
# endif
2021-06-16 01:29:49 -04:00
void UGeometryCollectionComponent : : SetRestState ( TArray < FTransform > & & InRestTransforms )
2021-08-31 23:27:01 -04:00
{
2021-07-27 13:41:34 -04:00
RestTransforms = InRestTransforms ;
2021-06-16 01:29:49 -04:00
2021-07-27 13:41:34 -04:00
if ( DynamicCollection )
{
SetInitialTransforms ( RestTransforms ) ;
2021-06-16 01:29:49 -04:00
}
2021-07-27 13:41:34 -04:00
FGeometryCollectionDynamicData * DynamicData = GDynamicDataPool . Allocate ( ) ;
2021-08-31 23:27:01 -04:00
DynamicData - > SetPrevTransforms ( GlobalMatrices ) ;
CalculateGlobalMatrices ( ) ;
DynamicData - > SetTransforms ( GlobalMatrices ) ;
2021-07-27 13:41:34 -04:00
DynamicData - > IsDynamic = true ;
if ( SceneProxy )
{
# if WITH_EDITOR
// We need to do this in case we're controlled by Sequencer in editor, which doesn't invoke PostEditChangeProperty
2022-10-03 21:13:17 -04:00
UpdateCachedBounds ( ) ;
2021-07-27 13:41:34 -04:00
SendRenderTransform_Concurrent ( ) ;
# endif
2022-05-11 13:06:19 -04:00
if ( SceneProxy - > IsNaniteMesh ( ) )
{
2021-07-27 13:41:34 -04:00
FNaniteGeometryCollectionSceneProxy * GeometryCollectionSceneProxy = static_cast < FNaniteGeometryCollectionSceneProxy * > ( SceneProxy ) ;
ENQUEUE_RENDER_COMMAND ( SendRenderDynamicData ) (
[ GeometryCollectionSceneProxy , DynamicData ] ( FRHICommandListImmediate & RHICmdList )
{
GeometryCollectionSceneProxy - > SetDynamicData_RenderThread ( DynamicData ) ;
}
) ;
}
else
{
FGeometryCollectionSceneProxy * GeometryCollectionSceneProxy = static_cast < FGeometryCollectionSceneProxy * > ( SceneProxy ) ;
ENQUEUE_RENDER_COMMAND ( SendRenderDynamicData ) (
[ GeometryCollectionSceneProxy , DynamicData ] ( FRHICommandListImmediate & RHICmdList )
{
GeometryCollectionSceneProxy - > SetDynamicData_RenderThread ( DynamicData ) ;
}
) ;
}
}
RefreshEmbeddedGeometry ( ) ;
2021-06-16 01:29:49 -04:00
}
2020-09-01 14:07:48 -04:00
void UGeometryCollectionComponent : : InitializeComponent ( )
{
Super : : InitializeComponent ( ) ;
2022-05-04 22:12:17 -04:00
if ( DynamicCollection )
2022-03-01 14:33:59 -05:00
{
2022-05-04 22:12:17 -04:00
if ( bStoreVelocities | | bNotifyTrailing )
2022-03-01 14:33:59 -05:00
{
2022-05-04 22:12:17 -04:00
if ( ! DynamicCollection - > FindAttributeTyped < FVector3f > ( " LinearVelocity " , FTransformCollection : : TransformGroup ) )
{
DynamicCollection - > AddAttribute < FVector3f > ( " LinearVelocity " , FTransformCollection : : TransformGroup ) ;
}
2022-03-01 14:33:59 -05:00
2022-05-04 22:12:17 -04:00
if ( ! DynamicCollection - > FindAttributeTyped < FVector3f > ( " AngularVelocity " , FTransformCollection : : TransformGroup ) )
{
DynamicCollection - > AddAttribute < FVector3f > ( " AngularVelocity " , FTransformCollection : : TransformGroup ) ;
}
2022-03-01 14:33:59 -05:00
}
2022-05-28 00:20:07 -04:00
DynamicCollection - > AddAttribute < uint8 > ( " InternalClusterParentTypeArray " , FTransformCollection : : TransformGroup ) ;
2022-03-01 14:33:59 -05:00
}
2020-09-01 14:07:48 -04:00
}
2021-03-18 23:55:49 -04:00
# if WITH_EDITOR
2022-07-06 11:17:25 -04:00
FDelegateHandle UGeometryCollectionComponent : : RegisterOnGeometryCollectionPropertyChanged ( const FOnGeometryCollectionPropertyChanged & Delegate )
{
return OnGeometryCollectionPropertyChanged . Add ( Delegate ) ;
}
void UGeometryCollectionComponent : : UnregisterOnGeometryCollectionPropertyChanged ( FDelegateHandle Handle )
{
OnGeometryCollectionPropertyChanged . Remove ( Handle ) ;
}
2021-03-18 23:55:49 -04:00
void UGeometryCollectionComponent : : PostEditChangeChainProperty ( FPropertyChangedChainEvent & PropertyChangedEvent )
2021-03-18 20:04:04 -04:00
{
2021-03-18 23:55:49 -04:00
Super : : PostEditChangeChainProperty ( PropertyChangedEvent ) ;
2021-03-18 20:04:04 -04:00
if ( PropertyChangedEvent . Property & & PropertyChangedEvent . Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UGeometryCollectionComponent , bShowBoneColors ) )
{
2021-08-18 22:53:28 -04:00
FScopedColorEdit EditBoneColor ( this , true /*bForceUpdate*/ ) ; // the property has already changed; this will trigger the color update + render state updates
2022-07-06 11:17:25 -04:00
}
}
void UGeometryCollectionComponent : : PostEditChangeProperty ( FPropertyChangedEvent & PropertyChangedEvent )
{
Super : : PostEditChangeProperty ( PropertyChangedEvent ) ;
if ( OnGeometryCollectionPropertyChanged . IsBound ( ) )
{
OnGeometryCollectionPropertyChanged . Broadcast ( ) ;
}
2021-03-18 20:04:04 -04:00
}
2021-03-18 23:55:49 -04:00
# endif
2021-03-18 20:04:04 -04:00
2019-06-08 17:15:34 -04:00
static void DispatchGeometryCollectionBreakEvent ( const FChaosBreakEvent & Event )
{
if ( UGeometryCollectionComponent * const GC = Cast < UGeometryCollectionComponent > ( Event . Component ) )
{
GC - > DispatchBreakEvent ( Event ) ;
}
}
2021-08-31 20:24:01 -04:00
static void DispatchGeometryCollectionRemovalEvent ( const FChaosRemovalEvent & Event )
{
if ( UGeometryCollectionComponent * const GC = Cast < UGeometryCollectionComponent > ( Event . Component ) )
{
GC - > DispatchRemovalEvent ( Event ) ;
}
}
2022-07-12 17:47:42 -04:00
static void DispatchGeometryCollectionCrumblingEvent ( const FChaosCrumblingEvent & Event )
{
if ( UGeometryCollectionComponent * const GC = Cast < UGeometryCollectionComponent > ( Event . Component ) )
{
GC - > DispatchCrumblingEvent ( Event ) ;
}
}
2022-11-09 20:53:21 -05:00
const FGeometryDynamicCollection * UGeometryCollectionComponent : : GetDynamicCollection ( ) const
{
return DynamicCollection . Get ( ) ;
}
FGeometryDynamicCollection * UGeometryCollectionComponent : : GetDynamicCollection ( )
{
return DynamicCollection . Get ( ) ;
}
2019-06-08 17:15:34 -04:00
void UGeometryCollectionComponent : : DispatchChaosPhysicsCollisionBlueprintEvents ( const FChaosPhysicsCollisionInfo & CollisionInfo )
{
ReceivePhysicsCollision ( CollisionInfo ) ;
OnChaosPhysicsCollision . Broadcast ( CollisionInfo ) ;
}
// call when first registering
void UGeometryCollectionComponent : : RegisterForEvents ( )
{
2022-07-12 17:47:42 -04:00
if ( BodyInstance . bNotifyRigidBodyCollision | | bNotifyBreaks | | bNotifyCollisions | | bNotifyRemovals | | bNotifyCrumblings )
2019-06-08 17:15:34 -04:00
{
2021-08-18 23:04:26 -04:00
Chaos : : FPhysicsSolver * Solver = GetWorld ( ) - > GetPhysicsScene ( ) - > GetSolver ( ) ;
if ( Solver )
2019-06-08 17:15:34 -04:00
{
2021-12-13 15:59:48 -05:00
if ( bNotifyCollisions | | BodyInstance . bNotifyRigidBodyCollision )
{
EventDispatcher - > RegisterForCollisionEvents ( this , this ) ;
2019-06-08 17:15:34 -04:00
2021-08-18 23:04:26 -04:00
Solver - > EnqueueCommandImmediate ( [ Solver ] ( )
{
Solver - > SetGenerateCollisionData ( true ) ;
} ) ;
2021-12-13 15:59:48 -05:00
}
2021-08-18 23:04:26 -04:00
2021-12-13 15:59:48 -05:00
if ( bNotifyBreaks )
{
EventDispatcher - > RegisterForBreakEvents ( this , & DispatchGeometryCollectionBreakEvent ) ;
2021-08-18 23:04:26 -04:00
Solver - > EnqueueCommandImmediate ( [ Solver ] ( )
{
Solver - > SetGenerateBreakingData ( true ) ;
} ) ;
}
2021-08-31 20:24:01 -04:00
if ( bNotifyRemovals )
{
EventDispatcher - > RegisterForRemovalEvents ( this , & DispatchGeometryCollectionRemovalEvent ) ;
Solver - > EnqueueCommandImmediate ( [ Solver ] ( )
{
Solver - > SetGenerateRemovalData ( true ) ;
} ) ;
}
2022-07-12 17:47:42 -04:00
if ( bNotifyCrumblings )
{
EventDispatcher - > RegisterForCrumblingEvents ( this , & DispatchGeometryCollectionCrumblingEvent ) ;
Solver - > EnqueueCommandImmediate ( [ Solver ] ( )
{
Solver - > SetGenerateBreakingData ( true ) ;
} ) ;
}
2019-06-08 17:15:34 -04:00
}
2021-10-25 20:05:28 -04:00
}
2019-06-08 17:15:34 -04:00
}
void UGeometryCollectionComponent : : UpdateRBCollisionEventRegistration ( )
{
2020-04-14 13:39:39 -04:00
if ( bNotifyCollisions | | BodyInstance . bNotifyRigidBodyCollision )
2019-06-08 17:15:34 -04:00
{
2020-04-14 13:39:39 -04:00
EventDispatcher - > RegisterForCollisionEvents ( this , this ) ;
}
else
{
EventDispatcher - > UnRegisterForCollisionEvents ( this , this ) ;
2019-06-08 17:15:34 -04:00
}
}
void UGeometryCollectionComponent : : UpdateBreakEventRegistration ( )
{
2020-04-14 13:39:39 -04:00
if ( bNotifyBreaks )
2019-06-08 17:15:34 -04:00
{
2020-04-14 13:39:39 -04:00
EventDispatcher - > RegisterForBreakEvents ( this , & DispatchGeometryCollectionBreakEvent ) ;
}
else
{
EventDispatcher - > UnRegisterForBreakEvents ( this ) ;
2019-06-08 17:15:34 -04:00
}
}
2021-08-31 20:24:01 -04:00
void UGeometryCollectionComponent : : UpdateRemovalEventRegistration ( )
{
if ( bNotifyRemovals )
{
EventDispatcher - > RegisterForRemovalEvents ( this , & DispatchGeometryCollectionRemovalEvent ) ;
}
else
{
EventDispatcher - > UnRegisterForRemovalEvents ( this ) ;
}
}
2022-07-12 17:47:42 -04:00
void UGeometryCollectionComponent : : UpdateCrumblingEventRegistration ( )
{
if ( bNotifyCrumblings )
{
EventDispatcher - > RegisterForCrumblingEvents ( this , & DispatchGeometryCollectionCrumblingEvent ) ;
}
else
{
EventDispatcher - > UnRegisterForCrumblingEvents ( this ) ;
}
}
2022-01-03 16:19:33 -05:00
void ActivateClusters ( Chaos : : FRigidClustering & Clustering , Chaos : : TPBDRigidClusteredParticleHandle < Chaos : : FReal , 3 > * Cluster )
2020-09-01 14:07:48 -04:00
{
if ( ! Cluster )
{
return ;
}
if ( Cluster - > ClusterIds ( ) . Id )
{
2021-04-07 23:42:46 -04:00
ActivateClusters ( Clustering , Cluster - > Parent ( ) ) ;
2020-09-01 14:07:48 -04:00
}
Clustering . DeactivateClusterParticle ( Cluster ) ;
}
2022-10-22 15:35:03 -04:00
void UGeometryCollectionComponent : : ResetRepData ( )
{
ClustersToRep . Reset ( ) ;
RepData . Reset ( ) ;
OneOffActivatedProcessed = 0 ;
VersionProcessed = INDEX_NONE ;
LastHardsnapTimeInMs = 0 ;
}
2020-09-01 14:07:48 -04:00
void UGeometryCollectionComponent : : UpdateRepData ( )
{
2022-04-25 13:09:18 -04:00
using namespace Chaos ;
2020-09-01 14:07:48 -04:00
if ( ! bEnableReplication )
{
return ;
}
AActor * Owner = GetOwner ( ) ;
// If we have no owner or our netmode means we never require replication then early out
if ( ! Owner | | Owner - > GetNetMode ( ) = = ENetMode : : NM_Standalone )
{
return ;
}
2022-04-25 13:09:18 -04:00
if ( Owner & & GetIsReplicated ( ) & & Owner - > GetLocalRole ( ) = = ROLE_Authority )
2020-09-01 14:07:48 -04:00
{
2022-05-04 12:47:38 -04:00
bool bFirstUpdate = false ;
2022-04-25 13:09:18 -04:00
if ( ClustersToRep = = nullptr )
2020-09-01 14:07:48 -04:00
{
2022-04-25 13:09:18 -04:00
//we only allocate set if needed because it's pretty big to have per components that don't replicate
ClustersToRep = MakeUnique < TSet < Chaos : : FPBDRigidClusteredParticleHandle * > > ( ) ;
2022-05-04 12:47:38 -04:00
bFirstUpdate = true ;
2022-04-25 13:09:18 -04:00
}
2020-09-01 14:07:48 -04:00
2022-04-25 13:09:18 -04:00
//We need to build a snapshot of the GC
//We rely on the fact that clusters always fracture with one off pieces being removed.
//This means we only need to record the one offs that broke and we get the connected components for free
//The cluster properties are replicated with the first child of each connected component. These are always children that are known at author time and have a unique id per component
//If the first child is disabled it means the properties apply to the parent (i.e. the cluster)
//If the first child is enabled it means it's a one off and the cluster IS the first child
//TODO: for now we have to iterate over all particles to find the clusters, would be better if we had the clusters and children already available
//We are relying on the fact that we fracture one level per step. This means we will see all one offs here
2020-09-01 14:07:48 -04:00
2022-04-25 13:09:18 -04:00
bool bClustersChanged = false ;
const FPBDRigidsSolver * Solver = PhysicsProxy - > GetSolver < Chaos : : FPBDRigidsSolver > ( ) ;
const FRigidClustering & RigidClustering = Solver - > GetEvolution ( ) - > GetRigidClustering ( ) ;
2022-10-06 19:49:04 -04:00
const TManagedArray < int32 > * InitialLevels = PhysicsProxy - > GetPhysicsCollection ( ) . FindAttribute < int32 > ( " InitialLevel " , FGeometryCollection : : TransformGroup ) ;
2022-09-14 13:58:55 -04:00
const TManagedArray < TSet < int32 > > & InitialChildren = PhysicsProxy - > GetPhysicsCollection ( ) . Children ;
2022-07-07 14:41:38 -04:00
2022-04-25 13:09:18 -04:00
//see if we have any new clusters that are enabled
TSet < FPBDRigidClusteredParticleHandle * > Processed ;
for ( FPBDRigidClusteredParticleHandle * Particle : PhysicsProxy - > GetParticles ( ) )
{
2022-07-09 14:05:18 -04:00
// Particle can be null if we have embedded geometry
if ( Particle )
{
2022-07-20 12:20:09 -04:00
bool bProcess = true ;
Processed . Add ( Particle ) ;
FPBDRigidClusteredParticleHandle * Root = Particle ;
while ( Root - > Parent ( ) )
2020-09-01 14:07:48 -04:00
{
2022-07-20 12:20:09 -04:00
Root = Root - > Parent ( ) ;
//TODO: set avoids n^2, would be nice if clustered particle cached its root
if ( Processed . Contains ( Root ) )
2022-07-07 14:41:38 -04:00
{
2022-07-20 12:20:09 -04:00
bProcess = false ;
break ;
}
else
{
Processed . Add ( Root ) ;
}
}
if ( bProcess & & Root - > Disabled ( ) = = false & & ClustersToRep - > Find ( Root ) = = nullptr )
{
int32 TransformGroupIdx = INDEX_NONE ;
int32 Level = INDEX_NONE ;
if ( Root - > InternalCluster ( ) = = false )
{
TransformGroupIdx = PhysicsProxy - > GetTransformGroupIndexFromHandle ( Root ) ;
ensureMsgf ( TransformGroupIdx > = 0 , TEXT ( " Non-internal cluster should always have a group index " ) ) ;
ensureMsgf ( TransformGroupIdx < TNumericLimits < uint16 > : : Max ( ) , TEXT ( " Trying to replicate GC with more than 65k pieces. We assumed uint16 would suffice " ) ) ;
2022-10-06 21:44:57 -04:00
Level = InitialLevels & & InitialLevels - > Num ( ) > 0 ? ( * InitialLevels ) [ TransformGroupIdx ] : INDEX_NONE ;
2022-07-20 12:20:09 -04:00
}
else
{
// Use internal cluster child's index to compute level.
const TArray < FPBDRigidParticleHandle * > & Children = RigidClustering . GetChildrenMap ( ) [ Root ] ;
const int32 ChildTransformGroupIdx = PhysicsProxy - > GetTransformGroupIndexFromHandle ( Children [ 0 ] ) ;
2022-10-06 21:44:57 -04:00
Level = InitialLevels & & InitialLevels - > Num ( ) > 0 ? ( ( * InitialLevels ) [ ChildTransformGroupIdx ] - 1 ) : INDEX_NONE ;
2022-07-20 12:20:09 -04:00
}
2022-09-14 13:58:55 -04:00
if ( ! bEnableAbandonAfterLevel | | Level < = ReplicationAbandonAfterLevel )
2022-07-20 12:20:09 -04:00
{
// not already replicated and not abandoned level, start replicating cluster
ClustersToRep - > Add ( Root ) ;
2022-07-07 14:41:38 -04:00
bClustersChanged = true ;
2022-07-20 12:20:09 -04:00
}
2022-09-14 13:58:55 -04:00
2022-07-20 12:20:09 -04:00
if ( Root - > InternalCluster ( ) = = false & & bFirstUpdate = = false ) //if bFirstUpdate it must be that these are the initial roots of the GC. These did not break off so no need to replicate
{
//a one off so record it
ensureMsgf ( TransformGroupIdx > = 0 , TEXT ( " Non-internal cluster should always have a group index " ) ) ;
ensureMsgf ( TransformGroupIdx < TNumericLimits < uint16 > : : Max ( ) , TEXT ( " Trying to replicate GC with more than 65k pieces. We assumed uint16 would suffice " ) ) ;
// Because we cull ClustersToRep with abandoned level, we must make sure we don't add duplicates to one off activated.
// TODO: avoid search for entry for perf
2022-09-14 13:58:55 -04:00
// TODO: once we support deep fracture we should be able to remove one offs clusters that are now disabled, reducing the amount to be replicated
2022-07-20 12:20:09 -04:00
FGeometryCollectionActivatedCluster OneOffActivated ( TransformGroupIdx , Root - > V ( ) , Root - > W ( ) ) ;
if ( ! RepData . OneOffActivated . Contains ( OneOffActivated ) )
{
bClustersChanged = true ;
RepData . OneOffActivated . Add ( OneOffActivated ) ;
}
2022-07-07 14:41:38 -04:00
}
2022-09-14 13:58:55 -04:00
// if we just hit the abandon level , let's disable all children
if ( bEnableAbandonAfterLevel & & Level > = ( ReplicationAbandonAfterLevel + 1 ) )
{
if ( ! Root - > Disabled ( ) )
{
2022-10-19 22:03:57 -04:00
Solver - > GetEvolution ( ) - > DisableParticle ( Root ) ;
2022-09-14 13:58:55 -04:00
}
}
2022-04-25 13:09:18 -04:00
}
2020-09-01 14:07:48 -04:00
}
}
2022-07-07 14:41:38 -04:00
INC_DWORD_STAT_BY ( STAT_GCReplicatedFractures , RepData . OneOffActivated . Num ( ) ) ;
2022-09-14 13:58:55 -04:00
2022-04-25 13:09:18 -04:00
//build up clusters to replicate and compare with previous frame
TArray < FGeometryCollectionClusterRep > Clusters ;
//remove disabled clusters and update rep data if needed
for ( auto Itr = ClustersToRep - > CreateIterator ( ) ; Itr ; + + Itr )
{
FPBDRigidClusteredParticleHandle * Cluster = * Itr ;
if ( Cluster - > Disabled ( ) )
{
Itr . RemoveCurrent ( ) ;
}
else
{
Clusters . AddDefaulted ( ) ;
FGeometryCollectionClusterRep & ClusterRep = Clusters . Last ( ) ;
ClusterRep . Position = Cluster - > X ( ) ;
ClusterRep . Rotation = Cluster - > R ( ) ;
ClusterRep . LinearVelocity = Cluster - > V ( ) ;
ClusterRep . AngularVelocity = Cluster - > W ( ) ;
2022-07-20 12:20:09 -04:00
ClusterRep . ClusterState . SetObjectState ( Cluster - > ObjectState ( ) ) ;
ClusterRep . ClusterState . SetInternalCluster ( Cluster - > InternalCluster ( ) ) ;
2022-04-25 13:09:18 -04:00
int32 TransformGroupIdx ;
if ( Cluster - > InternalCluster ( ) )
{
const TArray < FPBDRigidParticleHandle * > & Children = RigidClustering . GetChildrenMap ( ) [ Cluster ] ;
ensureMsgf ( Children . Num ( ) , TEXT ( " Internal cluster yet we have no children? " ) ) ;
TransformGroupIdx = PhysicsProxy - > GetTransformGroupIndexFromHandle ( Children [ 0 ] ) ;
}
else
{
2022-07-20 12:20:09 -04:00
// not internal so we can just use the cluster's ID. On client we'll know based on the parent whether to use this index or the parent
2022-04-25 13:09:18 -04:00
TransformGroupIdx = PhysicsProxy - > GetTransformGroupIndexFromHandle ( Cluster ) ;
}
ensureMsgf ( TransformGroupIdx < TNumericLimits < uint16 > : : Max ( ) , TEXT ( " Trying to replicate GC with more than 65k pieces. We assumed uint16 would suffice " ) ) ;
ClusterRep . ClusterIdx = TransformGroupIdx ;
if ( ! bClustersChanged )
{
//compare to previous frame data
2022-09-14 13:58:55 -04:00
// this could be more efficient by having a way to find back the data from the idx
auto Predicate = [ TransformGroupIdx ] ( const FGeometryCollectionClusterRep & Entry )
2022-04-25 13:09:18 -04:00
{
2022-09-14 13:58:55 -04:00
return Entry . ClusterIdx = = TransformGroupIdx ;
} ;
if ( const FGeometryCollectionClusterRep * PrevClusterData = RepData . Clusters . FindByPredicate ( Predicate ) )
{
if ( ClusterRep . ClusterChanged ( * PrevClusterData ) )
2022-04-25 13:09:18 -04:00
{
bClustersChanged = true ;
}
}
}
}
}
if ( bClustersChanged )
{
RepData . Clusters = MoveTemp ( Clusters ) ;
2022-11-21 07:56:36 -05:00
if ( Owner - > GetWorld ( ) & & Owner - > GetWorld ( ) - > GetPhysicsScene ( ) )
{
RepData . ServerFrame = Owner - > GetWorld ( ) - > GetPhysicsScene ( ) - > ReplicationCache . ServerFrame ;
}
2022-04-25 13:09:18 -04:00
2022-07-07 14:41:38 -04:00
INC_DWORD_STAT_BY ( STAT_GCReplicatedClusters , RepData . Clusters . Num ( ) ) ;
2022-04-25 13:09:18 -04:00
MARK_PROPERTY_DIRTY_FROM_NAME ( UGeometryCollectionComponent , RepData , this ) ;
+ + RepData . Version ;
2022-05-04 12:47:38 -04:00
2022-06-15 20:50:03 -04:00
if ( Owner - > NetDormancy ! = DORM_Awake )
2022-05-04 12:47:38 -04:00
{
//If net dormancy is Initial it must be for perf reasons, but since a cluster changed we need to replicate down
//TODO: set back to dormant when sim goes to sleep
Owner - > SetNetDormancy ( DORM_Awake ) ;
}
2022-04-25 13:09:18 -04:00
}
2020-09-01 14:07:48 -04:00
}
}
2022-04-25 13:09:18 -04:00
int32 GeometryCollectionHardMissingUpdatesSnapThreshold = 20 ;
FAutoConsoleVariableRef CVarGeometryCollectionHardMissingUpdatesSnapThreshold ( TEXT ( " p.GeometryCollectionHardMissingUpdatesSnapThreshold " ) , GeometryCollectionHardMissingUpdatesSnapThreshold ,
TEXT ( " Determines how many missing updates before we trigger a hard snap " ) ) ;
2022-09-14 13:58:55 -04:00
int32 GeometryCollectionHardsnapThresholdMs = 100 ; // 10 Hz
FAutoConsoleVariableRef CVarGeometryCollectionHardsnapThresholdMs ( TEXT ( " p.GeometryCollectionHardsnapThresholdMs " ) , GeometryCollectionHardMissingUpdatesSnapThreshold ,
TEXT ( " Determines how many ms since the last hardsnap to trigger a new one " ) ) ;
2022-04-25 13:09:18 -04:00
void UGeometryCollectionComponent : : ProcessRepData ( )
{
using namespace Chaos ;
2022-12-14 15:50:10 -05:00
if ( ! PhysicsProxy | | ! PhysicsProxy - > IsInitializedOnPhysicsThread ( ) | | VersionProcessed = = RepData . Version | | PhysicsProxy - > GetReplicationMode ( ) ! = FGeometryCollectionPhysicsProxy : : EReplicationMode : : Client )
2022-04-25 13:09:18 -04:00
{
return ;
}
bool bHardSnap = false ;
2022-09-14 13:58:55 -04:00
const int64 CurrentTimeInMs = FPlatformTime : : ToMilliseconds64 ( FPlatformTime : : Cycles64 ( ) ) ;
2022-04-25 13:09:18 -04:00
if ( VersionProcessed < RepData . Version )
{
//TODO: this will not really work if a fracture happens and then immediately goes to sleep without updating client enough times
//A time method would work better here, but is limited to async mode. Maybe we can support both
2022-09-14 13:58:55 -04:00
bHardSnap | = ( RepData . Version - VersionProcessed ) > GeometryCollectionHardMissingUpdatesSnapThreshold ;
bHardSnap | = ( CurrentTimeInMs - LastHardsnapTimeInMs ) > GeometryCollectionHardsnapThresholdMs ;
2022-04-25 13:09:18 -04:00
}
else
{
//rollover so just treat as hard snap - this case is extremely rare and a one off
bHardSnap = true ;
}
2022-09-14 13:58:55 -04:00
if ( bHardSnap )
{
LastHardsnapTimeInMs = CurrentTimeInMs ;
}
2022-04-25 13:09:18 -04:00
FPBDRigidsSolver * Solver = PhysicsProxy - > GetSolver < Chaos : : FPBDRigidsSolver > ( ) ;
FRigidClustering & RigidClustering = Solver - > GetEvolution ( ) - > GetRigidClustering ( ) ;
//First make sure all one off activations have been applied. This ensures our connectivity graph is the same and we have the same clusters as the server
for ( ; OneOffActivatedProcessed < RepData . OneOffActivated . Num ( ) ; + + OneOffActivatedProcessed )
{
2022-06-15 20:50:03 -04:00
const FGeometryCollectionActivatedCluster & ActivatedCluster = RepData . OneOffActivated [ OneOffActivatedProcessed ] ;
FPBDRigidParticleHandle * OneOff = PhysicsProxy - > GetParticles ( ) [ ActivatedCluster . ActivatedIndex ] ;
2022-12-14 15:50:10 -05:00
check ( OneOff ) ;
2022-06-15 20:50:03 -04:00
// Set initial velocities if not hard snapping
if ( ! bHardSnap )
{
2022-07-20 12:20:09 -04:00
// TODO: we should get an update cluster position first so that when particles break off they get the right position
2022-06-15 20:50:03 -04:00
// TODO: should we invalidate?
OneOff - > SetV ( ActivatedCluster . InitialLinearVelocity ) ;
OneOff - > SetW ( ActivatedCluster . InitialAngularVelocity ) ;
}
2022-10-03 21:14:59 -04:00
RigidClustering . ReleaseClusterParticles ( TArray < FPBDRigidParticleHandle * > { OneOff } , /* bTriggerBreakEvents */ true ) ;
2022-04-25 13:09:18 -04:00
}
if ( bHardSnap )
{
for ( const FGeometryCollectionClusterRep & RepCluster : RepData . Clusters )
{
2022-07-20 12:20:09 -04:00
if ( FPBDRigidParticleHandle * Cluster = PhysicsProxy - > GetParticles ( ) [ RepCluster . ClusterIdx ] )
2022-04-25 13:09:18 -04:00
{
2022-07-20 12:20:09 -04:00
if ( RepCluster . ClusterState . IsInternalCluster ( ) )
{
// internal cluster do not have an index so we rep data send one of the children's
// let's find the parent
Cluster = Cluster - > CastToClustered ( ) - > Parent ( ) ;
}
if ( Cluster & & Cluster - > Disabled ( ) = = false )
{
Cluster - > SetX ( RepCluster . Position ) ;
Cluster - > SetR ( RepCluster . Rotation ) ;
Cluster - > SetV ( RepCluster . LinearVelocity ) ;
Cluster - > SetW ( RepCluster . AngularVelocity ) ;
// TODO: snap object state too once we fix interpolation
// Solver->GetEvolution()->SetParticleObjectState(Cluster, static_cast<Chaos::EObjectStateType>(RepCluster.ObjectState));
}
2022-04-25 13:09:18 -04:00
}
}
}
VersionProcessed = RepData . Version ;
}
2021-06-16 01:29:49 -04:00
void UGeometryCollectionComponent : : SetDynamicState ( const Chaos : : EObjectStateType & NewDynamicState )
{
if ( DynamicCollection )
{
TManagedArray < int32 > & DynamicState = DynamicCollection - > DynamicState ;
for ( int i = 0 ; i < DynamicState . Num ( ) ; i + + )
{
DynamicState [ i ] = static_cast < int32 > ( NewDynamicState ) ;
}
}
}
void UGeometryCollectionComponent : : SetInitialTransforms ( const TArray < FTransform > & InitialTransforms )
{
if ( DynamicCollection )
{
TManagedArray < FTransform > & Transform = DynamicCollection - > Transform ;
int32 MaxIdx = FMath : : Min ( Transform . Num ( ) , InitialTransforms . Num ( ) ) ;
for ( int32 Idx = 0 ; Idx < MaxIdx ; + + Idx )
{
Transform [ Idx ] = InitialTransforms [ Idx ] ;
}
}
}
void UGeometryCollectionComponent : : SetInitialClusterBreaks ( const TArray < int32 > & ReleaseIndices )
{
if ( DynamicCollection )
{
TManagedArray < int32 > & Parent = DynamicCollection - > Parent ;
TManagedArray < TSet < int32 > > & Children = DynamicCollection - > Children ;
const int32 NumTransforms = Parent . Num ( ) ;
for ( int32 ReleaseIndex : ReleaseIndices )
{
if ( ReleaseIndex < NumTransforms )
{
if ( Parent [ ReleaseIndex ] > INDEX_NONE )
{
Children [ Parent [ ReleaseIndex ] ] . Remove ( ReleaseIndex ) ;
Parent [ ReleaseIndex ] = INDEX_NONE ;
}
}
}
}
}
2021-02-23 19:43:30 -04:00
void SetHierarchyStrain ( Chaos : : TPBDRigidClusteredParticleHandle < Chaos : : FReal , 3 > * P , TMap < Chaos : : TPBDRigidClusteredParticleHandle < Chaos : : FReal , 3 > * , TArray < Chaos : : TPBDRigidParticleHandle < Chaos : : FReal , 3 > * > > & Map , float Strain )
2020-09-01 14:07:48 -04:00
{
TArray < Chaos : : TPBDRigidParticleHandle < Chaos : : FReal , 3 > * > * Children = Map . Find ( P ) ;
2021-02-23 19:43:30 -04:00
if ( Children )
2020-09-01 14:07:48 -04:00
{
for ( Chaos : : TPBDRigidParticleHandle < Chaos : : FReal , 3 > * ChildP : ( * Children ) )
{
SetHierarchyStrain ( ChildP - > CastToClustered ( ) , Map , Strain ) ;
}
}
if ( P )
{
P - > SetStrain ( Strain ) ;
}
}
2019-06-08 17:15:34 -04:00
void UGeometryCollectionComponent : : InitConstantData ( FGeometryCollectionConstantData * ConstantData ) const
{
// Constant data should all be moved to the DDC as time permits.
2022-12-05 18:38:18 -05:00
// todo : this should be computed once per asset not per component or at least the part that does not depend on the component properties
2019-06-08 17:15:34 -04:00
2018-12-12 11:25:29 -05:00
check ( ConstantData ) ;
2019-06-08 17:15:34 -04:00
check ( RestCollection ) ;
const FGeometryCollection * Collection = RestCollection - > GetGeometryCollection ( ) . Get ( ) ;
2018-12-12 11:25:29 -05:00
check ( Collection ) ;
2021-04-20 09:50:07 -04:00
if ( ! RestCollection - > EnableNanite )
2018-12-12 11:25:29 -05:00
{
2021-04-20 09:50:07 -04:00
const int32 NumPoints = Collection - > NumElements ( FGeometryCollection : : VerticesGroup ) ;
2021-05-05 15:07:25 -04:00
const TManagedArray < FVector3f > & Vertex = Collection - > Vertex ;
2021-04-20 09:50:07 -04:00
const TManagedArray < int32 > & BoneMap = Collection - > BoneMap ;
2021-05-05 15:07:25 -04:00
const TManagedArray < FVector3f > & TangentU = Collection - > TangentU ;
const TManagedArray < FVector3f > & TangentV = Collection - > TangentV ;
const TManagedArray < FVector3f > & Normal = Collection - > Normal ;
2021-11-18 14:37:34 -05:00
const TManagedArray < TArray < FVector2f > > & UVs = Collection - > UVs ;
2021-04-20 09:50:07 -04:00
const TManagedArray < FLinearColor > & Color = Collection - > Color ;
const TManagedArray < FLinearColor > & BoneColors = Collection - > BoneColor ;
2021-12-13 15:59:48 -05:00
2021-08-30 17:11:38 -04:00
const int32 NumGeom = Collection - > NumElements ( FGeometryCollection : : GeometryGroup ) ;
const TManagedArray < int32 > & TransformIndex = Collection - > TransformIndex ;
const TManagedArray < int32 > & FaceStart = Collection - > FaceStart ;
const TManagedArray < int32 > & FaceCount = Collection - > FaceCount ;
2018-12-12 11:25:29 -05:00
2021-05-05 15:07:25 -04:00
ConstantData - > Vertices = TArray < FVector3f > ( Vertex . GetData ( ) , Vertex . Num ( ) ) ;
2021-04-20 09:50:07 -04:00
ConstantData - > BoneMap = TArray < int32 > ( BoneMap . GetData ( ) , BoneMap . Num ( ) ) ;
2021-05-05 15:07:25 -04:00
ConstantData - > TangentU = TArray < FVector3f > ( TangentU . GetData ( ) , TangentU . Num ( ) ) ;
ConstantData - > TangentV = TArray < FVector3f > ( TangentV . GetData ( ) , TangentV . Num ( ) ) ;
ConstantData - > Normals = TArray < FVector3f > ( Normal . GetData ( ) , Normal . Num ( ) ) ;
2021-04-20 09:50:07 -04:00
ConstantData - > Colors = TArray < FLinearColor > ( Color . GetData ( ) , Color . Num ( ) ) ;
2019-06-08 17:15:34 -04:00
2022-12-05 18:38:18 -05:00
// find the maximum number of channels
int32 NumUVChannels = 0 ;
for ( const TArray < FVector2f > & VertexUVs : Collection - > UVs . GetConstArray ( ) )
{
NumUVChannels = FMath : : Max ( NumUVChannels , VertexUVs . Num ( ) ) ;
}
2022-11-30 16:59:49 -05:00
ConstantData - > UVChannels . SetNum ( NumUVChannels ) ;
for ( int32 UVChannelIndex = 0 ; UVChannelIndex < NumUVChannels ; UVChannelIndex + + )
{
ConstantData - > UVChannels [ UVChannelIndex ] . AddUninitialized ( NumPoints ) ;
}
2021-04-20 09:50:07 -04:00
ConstantData - > BoneColors . AddUninitialized ( NumPoints ) ;
2019-06-08 17:15:34 -04:00
2022-11-30 16:59:49 -05:00
if ( bChaos_GC_InitConstantDataUseParallelFor )
{
ParallelFor ( TEXT ( " GC:InitConstantData " ) , NumPoints , bChaos_GC_InitConstantDataParallelForBatchSize ,
[ & ] ( const int32 InPointIndex )
{
const int32 BoneIndex = ConstantData - > BoneMap [ InPointIndex ] ;
ConstantData - > BoneColors [ InPointIndex ] = BoneColors [ BoneIndex ] ;
2022-12-05 18:38:18 -05:00
const TArray < FVector2f > & VertexUVs = Collection - > UVs [ InPointIndex ] ;
for ( int32 UVChannelIndex = 0 ; UVChannelIndex < VertexUVs . Num ( ) ; UVChannelIndex + + )
2022-11-30 16:59:49 -05:00
{
ConstantData - > UVChannels [ UVChannelIndex ] [ InPointIndex ] = Collection - > UVs [ InPointIndex ] [ UVChannelIndex ] ;
}
2022-12-05 18:38:18 -05:00
for ( int32 UVChannelIndex = VertexUVs . Num ( ) ; UVChannelIndex < NumUVChannels ; UVChannelIndex + + )
{
ConstantData - > UVChannels [ UVChannelIndex ] [ InPointIndex ] = FVector2f : : ZeroVector ;
}
2022-11-30 16:59:49 -05:00
} ) ;
}
else
{
for ( int32 PointIndex = 0 ; PointIndex < NumPoints ; PointIndex + + )
2019-06-08 17:15:34 -04:00
{
2022-11-30 16:59:49 -05:00
const int32 BoneIndex = ConstantData - > BoneMap [ PointIndex ] ;
ConstantData - > BoneColors [ PointIndex ] = BoneColors [ BoneIndex ] ;
}
for ( int32 UVChannelIndex = 0 ; UVChannelIndex < NumUVChannels ; UVChannelIndex + + )
{
for ( int32 PointIndex = 0 ; PointIndex < NumPoints ; PointIndex + + )
{
ConstantData - > UVChannels [ UVChannelIndex ] [ PointIndex ] = Collection - > UVs [ PointIndex ] [ UVChannelIndex ] ;
}
}
}
2021-04-20 09:50:07 -04:00
int32 NumIndices = 0 ;
const TManagedArray < FIntVector > & Indices = Collection - > Indices ;
const TManagedArray < int32 > & MaterialID = Collection - > MaterialID ;
const TManagedArray < bool > & Visible = GetVisibleArray ( ) ; // Use copy on write attribute. The rest collection visible array can be overriden for the convenience of debug drawing the collision volumes
2021-08-30 17:11:38 -04:00
# if WITH_EDITOR
// We will override visibility with the Hide array (if available).
TArray < bool > VisibleOverride ;
2022-04-18 13:43:49 -04:00
VisibleOverride . SetNumUninitialized ( Visible . Num ( ) ) ;
for ( int32 FaceIdx = 0 ; FaceIdx < Visible . Num ( ) ; FaceIdx + + )
{
VisibleOverride [ FaceIdx ] = Visible [ FaceIdx ] ;
}
2021-08-30 17:11:38 -04:00
bool bUsingHideArray = false ;
if ( Collection - > HasAttribute ( " Hide " , FGeometryCollection : : TransformGroup ) )
{
bUsingHideArray = true ;
2021-09-02 22:24:58 -04:00
bool bAllHidden = true ;
2021-08-30 17:11:38 -04:00
const TManagedArray < bool > & Hide = Collection - > GetAttribute < bool > ( " Hide " , FGeometryCollection : : TransformGroup ) ;
for ( int32 GeomIdx = 0 ; GeomIdx < NumGeom ; + + GeomIdx )
{
2022-04-18 13:43:49 -04:00
int32 TransformIdx = TransformIndex [ GeomIdx ] ;
if ( Hide [ TransformIdx ] )
2021-08-30 17:11:38 -04:00
{
// (Temporarily) hide faces of this hidden geometry
for ( int32 FaceIdxOffset = 0 ; FaceIdxOffset < FaceCount [ GeomIdx ] ; + + FaceIdxOffset )
{
VisibleOverride [ FaceStart [ GeomIdx ] + FaceIdxOffset ] = false ;
}
}
2022-04-18 13:43:49 -04:00
else if ( bAllHidden & & Collection - > IsVisible ( TransformIdx ) )
2021-09-02 22:24:58 -04:00
{
bAllHidden = false ;
}
}
2022-04-18 13:43:49 -04:00
if ( ! ensure ( ! bAllHidden ) ) // if they're all hidden, rendering would crash -- reset to default visibility instead
2021-09-02 22:24:58 -04:00
{
for ( int32 FaceIdx = 0 ; FaceIdx < VisibleOverride . Num ( ) ; + + FaceIdx )
{
2022-04-18 13:43:49 -04:00
VisibleOverride [ FaceIdx ] = Visible [ FaceIdx ] ;
2021-09-02 22:24:58 -04:00
}
2021-08-30 17:11:38 -04:00
}
}
# endif
2021-04-20 09:50:07 -04:00
const TManagedArray < int32 > & MaterialIndex = Collection - > MaterialIndex ;
const int32 NumFaceGroupEntries = Collection - > NumElements ( FGeometryCollection : : FacesGroup ) ;
for ( int FaceIndex = 0 ; FaceIndex < NumFaceGroupEntries ; + + FaceIndex )
{
2021-08-30 17:11:38 -04:00
# if WITH_EDITOR
2021-11-25 13:38:07 -05:00
NumIndices + = bUsingHideArray ? static_cast < int > ( VisibleOverride [ FaceIndex ] ) : static_cast < int > ( Visible [ FaceIndex ] ) ;
2021-08-30 17:11:38 -04:00
# else
2021-04-20 09:50:07 -04:00
NumIndices + = static_cast < int > ( Visible [ FaceIndex ] ) ;
2021-08-30 17:11:38 -04:00
# endif
2021-04-20 09:50:07 -04:00
}
ConstantData - > Indices . AddUninitialized ( NumIndices ) ;
for ( int IndexIdx = 0 , cdx = 0 ; IndexIdx < NumFaceGroupEntries ; + + IndexIdx )
{
2021-08-30 17:11:38 -04:00
# if WITH_EDITOR
2021-11-25 13:38:07 -05:00
const bool bUseVisible = bUsingHideArray ? VisibleOverride [ MaterialIndex [ IndexIdx ] ] : Visible [ MaterialIndex [ IndexIdx ] ] ;
if ( bUseVisible )
2021-08-30 17:11:38 -04:00
# else
2021-04-20 09:50:07 -04:00
if ( Visible [ MaterialIndex [ IndexIdx ] ] )
2021-08-30 17:11:38 -04:00
# endif
2021-04-20 09:50:07 -04:00
{
ConstantData - > Indices [ cdx + + ] = Indices [ MaterialIndex [ IndexIdx ] ] ;
2019-06-08 17:15:34 -04:00
}
2018-12-12 11:25:29 -05:00
}
2021-04-20 09:50:07 -04:00
// We need to correct the section index start point & number of triangles since only the visible ones have been copied across in the code above
const int32 NumMaterialSections = Collection - > NumElements ( FGeometryCollection : : MaterialGroup ) ;
ConstantData - > Sections . AddUninitialized ( NumMaterialSections ) ;
const TManagedArray < FGeometryCollectionSection > & Sections = Collection - > Sections ;
for ( int SectionIndex = 0 ; SectionIndex < NumMaterialSections ; + + SectionIndex )
2018-12-12 11:25:29 -05:00
{
2021-04-20 09:50:07 -04:00
FGeometryCollectionSection Section = Sections [ SectionIndex ] ; // deliberate copy
for ( int32 TriangleIndex = 0 ; TriangleIndex < Sections [ SectionIndex ] . FirstIndex / 3 ; TriangleIndex + + )
2019-06-08 17:15:34 -04:00
{
2021-08-30 17:11:38 -04:00
# if WITH_EDITOR
2021-11-25 13:38:07 -05:00
const bool bUseVisible = bUsingHideArray ? VisibleOverride [ MaterialIndex [ TriangleIndex ] ] : Visible [ MaterialIndex [ TriangleIndex ] ] ;
if ( ! bUseVisible )
2021-08-30 17:11:38 -04:00
# else
2021-04-20 09:50:07 -04:00
if ( ! Visible [ MaterialIndex [ TriangleIndex ] ] )
2021-08-30 17:11:38 -04:00
# endif
2019-06-08 17:15:34 -04:00
{
2021-04-20 09:50:07 -04:00
Section . FirstIndex - = 3 ;
2019-06-08 17:15:34 -04:00
}
}
2021-04-20 09:50:07 -04:00
for ( int32 TriangleIndex = 0 ; TriangleIndex < Sections [ SectionIndex ] . NumTriangles ; TriangleIndex + + )
2019-06-08 17:15:34 -04:00
{
2021-08-30 17:11:38 -04:00
int32 FaceIdx = MaterialIndex [ Sections [ SectionIndex ] . FirstIndex / 3 + TriangleIndex ] ;
# if WITH_EDITOR
2021-11-25 13:38:07 -05:00
const bool bUseVisible = bUsingHideArray ? VisibleOverride [ FaceIdx ] : Visible [ FaceIdx ] ;
if ( ! bUseVisible )
2021-08-30 17:11:38 -04:00
# else
if ( ! Visible [ FaceIdx ] )
# endif
2021-04-20 09:50:07 -04:00
{
Section . NumTriangles - - ;
2019-06-08 17:15:34 -04:00
}
}
2021-04-20 09:50:07 -04:00
ConstantData - > Sections [ SectionIndex ] = MoveTemp ( Section ) ;
}
2021-06-16 01:29:49 -04:00
2021-04-20 09:50:07 -04:00
ConstantData - > NumTransforms = Collection - > NumElements ( FGeometryCollection : : TransformGroup ) ;
ConstantData - > LocalBounds = LocalBounds ;
// store the index buffer and render sections for the base unfractured mesh
const TManagedArray < int32 > & TransformToGeometryIndex = Collection - > TransformToGeometryIndex ;
2021-12-13 15:59:48 -05:00
2021-04-20 09:50:07 -04:00
const int32 NumFaces = Collection - > NumElements ( FGeometryCollection : : FacesGroup ) ;
TArray < FIntVector > BaseMeshIndices ;
TArray < int32 > BaseMeshOriginalFaceIndices ;
BaseMeshIndices . Reserve ( NumFaces ) ;
BaseMeshOriginalFaceIndices . Reserve ( NumFaces ) ;
// add all visible external faces to the original geometry index array
// #note: This is a stopgap because the original geometry array is broken
for ( int FaceIndex = 0 ; FaceIndex < NumFaces ; + + FaceIndex )
{
// only add visible external faces. MaterialID that is even is an external material
2021-08-30 17:11:38 -04:00
# if WITH_EDITOR
2021-11-25 13:38:07 -05:00
const bool bUseVisible = bUsingHideArray ? VisibleOverride [ FaceIndex ] : Visible [ FaceIndex ] ;
if ( bUseVisible & & ( MaterialID [ FaceIndex ] % 2 = = 0 | | bUsingHideArray ) )
2021-08-30 17:11:38 -04:00
# else
2021-04-20 09:50:07 -04:00
if ( Visible [ FaceIndex ] & & MaterialID [ FaceIndex ] % 2 = = 0 )
2021-08-30 17:11:38 -04:00
# endif
2021-04-20 09:50:07 -04:00
{
BaseMeshIndices . Add ( Indices [ FaceIndex ] ) ;
BaseMeshOriginalFaceIndices . Add ( FaceIndex ) ;
}
2019-06-08 17:15:34 -04:00
}
2021-04-20 09:50:07 -04:00
// We should always have external faces of a geometry collection
ensure ( BaseMeshIndices . Num ( ) > 0 ) ;
ConstantData - > OriginalMeshSections = Collection - > BuildMeshSections ( BaseMeshIndices , BaseMeshOriginalFaceIndices , ConstantData - > OriginalMeshIndices ) ;
2019-06-08 17:15:34 -04:00
}
2021-04-20 09:50:07 -04:00
2019-06-08 17:15:34 -04:00
TArray < FMatrix > RestMatrices ;
GeometryCollectionAlgo : : GlobalMatrices ( RestCollection - > GetGeometryCollection ( ) - > Transform , RestCollection - > GetGeometryCollection ( ) - > Parent , RestMatrices ) ;
2021-05-14 15:26:37 -04:00
ConstantData - > SetRestTransforms ( RestMatrices ) ;
2018-12-12 11:25:29 -05:00
}
2021-04-24 04:37:11 -04:00
FGeometryCollectionDynamicData * UGeometryCollectionComponent : : InitDynamicData ( bool bInitialization )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
SCOPE_CYCLE_COUNTER ( STAT_GCInitDynamicData ) ;
2021-04-20 10:45:04 -04:00
FGeometryCollectionDynamicData * DynamicData = nullptr ;
2018-12-12 11:25:29 -05:00
2021-04-20 10:45:04 -04:00
const bool bEditorMode = bShowBoneColors | | bEnableBoneSelection ;
2021-04-24 04:37:11 -04:00
const bool bIsDynamic = GetIsObjectDynamic ( ) | | bEditorMode | | bInitialization ;
2021-04-20 10:45:04 -04:00
2021-06-16 01:29:49 -04:00
if ( bIsDynamic )
2019-06-08 17:15:34 -04:00
{
2021-04-20 10:45:04 -04:00
DynamicData = GDynamicDataPool . Allocate ( ) ;
DynamicData - > IsDynamic = true ;
DynamicData - > IsLoading = GetIsObjectLoading ( ) ;
2019-06-08 17:15:34 -04:00
// If we have no transforms stored in the dynamic data, then assign both prev and current to the same global matrices
if ( GlobalMatrices . Num ( ) = = 0 )
{
// Copy global matrices over to DynamicData
2021-04-20 10:45:04 -04:00
CalculateGlobalMatrices ( ) ;
2019-07-16 19:12:32 -04:00
2021-05-14 15:26:37 -04:00
DynamicData - > SetAllTransforms ( GlobalMatrices ) ;
2019-06-08 17:15:34 -04:00
}
else
{
// Copy existing global matrices into prev transforms
2021-05-14 15:26:37 -04:00
DynamicData - > SetPrevTransforms ( GlobalMatrices ) ;
2019-06-08 17:15:34 -04:00
// Copy global matrices over to DynamicData
CalculateGlobalMatrices ( ) ;
2021-04-20 10:45:04 -04:00
bool bComputeChanges = true ;
2019-06-08 17:15:34 -04:00
// if the number of matrices has changed between frames, then sync previous to current
if ( GlobalMatrices . Num ( ) ! = DynamicData - > PrevTransforms . Num ( ) )
{
2021-05-14 15:26:37 -04:00
DynamicData - > SetPrevTransforms ( GlobalMatrices ) ;
2021-04-20 10:45:04 -04:00
DynamicData - > ChangedCount = GlobalMatrices . Num ( ) ;
bComputeChanges = false ; // Optimization to just force all transforms as changed and skip comparison
2019-06-08 17:15:34 -04:00
}
2021-05-14 15:26:37 -04:00
DynamicData - > SetTransforms ( GlobalMatrices ) ;
2019-06-08 17:15:34 -04:00
2021-04-20 10:45:04 -04:00
// The number of transforms for current and previous should match now
check ( DynamicData - > PrevTransforms . Num ( ) = = DynamicData - > Transforms . Num ( ) ) ;
if ( bComputeChanges )
{
DynamicData - > DetermineChanges ( ) ;
}
2019-07-16 19:12:32 -04:00
}
}
2021-04-20 10:45:04 -04:00
2021-05-01 17:51:29 -04:00
if ( ! bEditorMode & & ! bInitialization )
2021-04-20 10:45:04 -04:00
{
2021-05-01 17:51:29 -04:00
if ( DynamicData & & DynamicData - > ChangedCount = = 0 )
{
GDynamicDataPool . Release ( DynamicData ) ;
DynamicData = nullptr ;
// Change of state?
2021-12-02 18:57:44 -05:00
if ( bIsMoving & & ! bForceMotionBlur )
2021-05-01 17:51:29 -04:00
{
bIsMoving = false ;
if ( SceneProxy & & SceneProxy - > IsNaniteMesh ( ) )
{
FNaniteGeometryCollectionSceneProxy * NaniteProxy = static_cast < FNaniteGeometryCollectionSceneProxy * > ( SceneProxy ) ;
2021-05-01 21:33:36 -04:00
ENQUEUE_RENDER_COMMAND ( NaniteProxyOnMotionEnd ) (
[ NaniteProxy ] ( FRHICommandListImmediate & RHICmdList )
{
NaniteProxy - > OnMotionEnd ( ) ;
}
) ;
2021-05-01 17:51:29 -04:00
}
}
}
else
{
// Change of state?
2021-12-02 18:57:44 -05:00
if ( ! bIsMoving & & ! bForceMotionBlur )
2021-05-01 17:51:29 -04:00
{
bIsMoving = true ;
if ( SceneProxy & & SceneProxy - > IsNaniteMesh ( ) )
{
FNaniteGeometryCollectionSceneProxy * NaniteProxy = static_cast < FNaniteGeometryCollectionSceneProxy * > ( SceneProxy ) ;
2021-05-01 21:33:36 -04:00
ENQUEUE_RENDER_COMMAND ( NaniteProxyOnMotionBegin ) (
[ NaniteProxy ] ( FRHICommandListImmediate & RHICmdList )
{
NaniteProxy - > OnMotionBegin ( ) ;
}
) ;
2021-05-01 17:51:29 -04:00
}
}
}
2021-04-20 10:45:04 -04:00
}
return DynamicData ;
2019-06-08 17:15:34 -04:00
}
2018-12-12 11:25:29 -05:00
2021-03-25 17:47:32 -04:00
void UGeometryCollectionComponent : : OnUpdateTransform ( EUpdateTransformFlags UpdateTransformFlags , ETeleportType Teleport )
{
Super : : OnUpdateTransform ( UpdateTransformFlags , Teleport ) ;
if ( PhysicsProxy )
{
2022-06-24 11:19:02 -04:00
PhysicsProxy - > SetWorldTransform_External ( GetComponentTransform ( ) ) ;
2021-03-25 17:47:32 -04:00
}
}
2022-07-21 22:26:08 -04:00
bool UGeometryCollectionComponent : : HasAnySockets ( ) const
{
if ( RestCollection & & RestCollection - > GetGeometryCollection ( ) )
{
return ( RestCollection - > GetGeometryCollection ( ) - > BoneName . Num ( ) > 0 ) ;
}
return false ;
}
bool UGeometryCollectionComponent : : DoesSocketExist ( FName InSocketName ) const
{
if ( RestCollection & & RestCollection - > GetGeometryCollection ( ) )
{
return RestCollection - > GetGeometryCollection ( ) - > BoneName . Contains ( InSocketName . ToString ( ) ) ;
}
return false ;
}
FTransform UGeometryCollectionComponent : : GetSocketTransform ( FName InSocketName , ERelativeTransformSpace TransformSpace ) const
{
if ( RestCollection & & RestCollection - > GetGeometryCollection ( ) )
{
const TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > Collection = RestCollection - > GetGeometryCollection ( ) ;
const int32 TransformIndex = Collection - > BoneName . Find ( InSocketName . ToString ( ) ) ;
if ( TransformIndex ! = INDEX_NONE )
{
if ( GlobalMatrices . IsValidIndex ( TransformIndex ) )
{
const FTransform BoneComponentSpaceTransform = FTransform ( GlobalMatrices [ TransformIndex ] ) ;
switch ( TransformSpace )
{
case RTS_World :
return BoneComponentSpaceTransform * GetComponentTransform ( ) ;
case RTS_Actor :
{
if ( const AActor * Actor = GetOwner ( ) )
{
const FTransform SocketWorldSpaceTransform = BoneComponentSpaceTransform * GetComponentTransform ( ) ;
return SocketWorldSpaceTransform . GetRelativeTransform ( Actor - > GetTransform ( ) ) ;
}
break ;
}
case RTS_Component :
return BoneComponentSpaceTransform ;
case RTS_ParentBoneSpace :
{
const int32 ParentTransformIndex = Collection - > Parent [ TransformIndex ] ;
FTransform ParentComponentSpaceTransform { FTransform : : Identity } ;
if ( GlobalMatrices . IsValidIndex ( ParentTransformIndex ) )
{
ParentComponentSpaceTransform = FTransform ( GlobalMatrices [ ParentTransformIndex ] ) ;
}
return BoneComponentSpaceTransform . GetRelativeTransform ( ParentComponentSpaceTransform ) ;
}
default :
check ( false ) ;
}
}
}
}
return Super : : GetSocketTransform ( InSocketName , TransformSpace ) ;
}
void UGeometryCollectionComponent : : QuerySupportedSockets ( TArray < FComponentSocketDescription > & OutSockets ) const
{
if ( RestCollection & & RestCollection - > GetGeometryCollection ( ) )
{
for ( const FString & BoneName : RestCollection - > GetGeometryCollection ( ) - > BoneName )
{
FComponentSocketDescription & Desc = OutSockets . AddZeroed_GetRef ( ) ;
Desc . Name = * BoneName ;
Desc . Type = EComponentSocketType : : Type : : Bone ;
}
}
}
void UGeometryCollectionComponent : : UpdateAttachedChildrenTransform ( ) const
{
// todo(chaos) : find a way to only update that of transform have changed
// right now this does not work properly because the dirty flags may not be updated at the right time
//if (PhysicsProxy && PhysicsProxy->IsGTCollectionDirty())
{
for ( const TObjectPtr < USceneComponent > & AttachedChild : this - > GetAttachChildren ( ) )
{
2022-10-21 19:51:57 -04:00
if ( AttachedChild )
{
AttachedChild - > UpdateComponentToWorld ( ) ;
}
2022-07-21 22:26:08 -04:00
}
}
}
2018-12-12 11:25:29 -05:00
void UGeometryCollectionComponent : : TickComponent ( float DeltaTime , enum ELevelTick TickType , FActorComponentTickFunction * ThisTickFunction )
{
//UE_LOG(UGCC_LOG, Log, TEXT("GeometryCollectionComponent[%p]::TickComponent()"), this);
Super : : TickComponent ( DeltaTime , TickType , ThisTickFunction ) ;
2020-06-23 18:40:00 -04:00
2020-07-21 15:17:07 -04:00
# if WITH_EDITOR
if ( IsRegistered ( ) & & SceneProxy & & RestCollection )
{
const bool bWantNanite = RestCollection - > EnableNanite & & GGeometryCollectionNanite ! = 0 ;
const bool bHaveNanite = SceneProxy - > IsNaniteMesh ( ) ;
bool bRecreateProxy = bWantNanite ! = bHaveNanite ;
if ( bRecreateProxy )
{
// Wait until resources are released
FlushRenderingCommands ( ) ;
FComponentReregisterContext ReregisterContext ( this ) ;
UpdateAllPrimitiveSceneInfosForSingleComponent ( this ) ;
}
}
# endif
2019-06-08 17:15:34 -04:00
//if (bRenderStateDirty && DynamicCollection) //todo: always send for now
2020-07-21 15:17:07 -04:00
if ( RestCollection )
2018-12-12 11:25:29 -05:00
{
2021-05-27 13:40:37 -04:00
// In editor mode we have no DynamicCollection so this test is necessary
if ( DynamicCollection ) //, TEXT("No dynamic collection available for component %s during tick."), *GetName()))
2018-12-12 11:25:29 -05:00
{
2022-11-16 19:21:50 -05:00
if ( IsRootBroken ( ) )
{
IncrementSleepTimer ( DeltaTime ) ;
IncrementBreakTimer ( DeltaTime ) ;
}
2021-08-31 20:24:01 -04:00
2022-07-21 22:26:08 -04:00
// todo(chaos) : find a way to only update that of transform have changed
// right now this does not work properly because the dirty flags may not be updated at the right time
//if (PhysicsProxy && PhysicsProxy->IsGTCollectionDirty())
// {
// for (const TObjectPtr<USceneComponent>& AttachedChild: this->GetAttachChildren())
// {
// AttachedChild->UpdateComponentToWorld();
// }
// }
2021-05-11 01:18:05 -04:00
if ( RestCollection - > HasVisibleGeometry ( ) | | DynamicCollection - > IsDirty ( ) )
2020-04-30 07:34:59 -04:00
{
2021-02-18 13:20:03 -04:00
// #todo review: When we've made changes to ISMC, we need to move this function call to SetRenderDynamicData_Concurrent
RefreshEmbeddedGeometry ( ) ;
2022-10-21 19:51:57 -04:00
// we may want to call this when the geometry collection updates ( notified by the proxy buffer updates )
// otherwise we are getting a frame delay
RefreshISMPoolInstances ( ) ;
2021-05-11 01:18:05 -04:00
if ( SceneProxy & & SceneProxy - > IsNaniteMesh ( ) )
{
FNaniteGeometryCollectionSceneProxy * NaniteProxy = static_cast < FNaniteGeometryCollectionSceneProxy * > ( SceneProxy ) ;
NaniteProxy - > FlushGPUSceneUpdate_GameThread ( ) ;
}
2021-02-18 13:20:03 -04:00
2020-06-23 18:40:00 -04:00
MarkRenderTransformDirty ( ) ;
MarkRenderDynamicDataDirty ( ) ;
bRenderStateDirty = false ;
2022-07-21 22:26:08 -04:00
2020-06-23 18:40:00 -04:00
const UWorld * MyWorld = GetWorld ( ) ;
if ( MyWorld & & MyWorld - > IsGameWorld ( ) )
2020-04-30 07:34:59 -04:00
{
2020-06-23 18:40:00 -04:00
//cycle every 0xff frames
//@todo - Need way of seeing if the collection is actually changing
if ( bNavigationRelevant & & bRegistered & & ( ( ( GFrameCounter + NavmeshInvalidationTimeSliceIndex ) & 0xff ) = = 0 ) )
{
UpdateNavigationData ( ) ;
}
2020-04-30 07:34:59 -04:00
}
}
2018-12-12 11:25:29 -05:00
}
}
2022-04-25 13:09:18 -04:00
}
2020-06-23 18:40:00 -04:00
2022-04-25 13:09:18 -04:00
void UGeometryCollectionComponent : : AsyncPhysicsTickComponent ( float DeltaTime , float SimTime )
{
Super : : AsyncPhysicsTickComponent ( DeltaTime , SimTime ) ;
2022-10-28 00:33:43 -04:00
// using net mode for now as using local role seemed to cause other issues at initialization time
// we may nee dto to also use local role in the future if the authority is likely to change at runtime
if ( GetNetMode ( ) ! = ENetMode : : NM_Client )
2022-05-04 12:47:38 -04:00
{
UpdateRepData ( ) ;
}
else
{
ProcessRepData ( ) ;
}
2018-12-12 11:25:29 -05:00
}
void UGeometryCollectionComponent : : OnRegister ( )
{
//UE_LOG(UGCC_LOG, Log, TEXT("GeometryCollectionComponent[%p]::OnRegister()[%p]"), this,RestCollection );
ResetDynamicCollection ( ) ;
2022-06-03 22:08:40 -04:00
bool bIsReplicated = false ;
const bool bHasClusterGroup = ( ClusterGroupIndex ! = 0 ) ;
if ( bEnableReplication )
2022-06-03 15:40:23 -04:00
{
2022-06-03 22:08:40 -04:00
if ( ensureMsgf ( ! bHasClusterGroup , TEXT ( " Replication with cluster groups is not supported - disabling replication " ) ) )
{
bIsReplicated = true ;
}
2022-06-03 15:40:23 -04:00
}
2022-06-03 22:08:40 -04:00
SetIsReplicated ( bIsReplicated ) ;
2020-09-01 14:07:48 -04:00
2021-02-18 13:20:03 -04:00
InitializeEmbeddedGeometry ( ) ;
2019-06-08 17:15:34 -04:00
Super : : OnRegister ( ) ;
2018-12-12 11:25:29 -05:00
}
void UGeometryCollectionComponent : : ResetDynamicCollection ( )
{
2019-06-08 17:15:34 -04:00
bool bCreateDynamicCollection = true ;
# if WITH_EDITOR
bCreateDynamicCollection = false ;
if ( UWorld * World = GetWorld ( ) )
{
2022-12-16 17:59:26 -05:00
if ( World - > IsGameWorld ( ) | | World - > IsPreviewWorld ( ) )
2019-06-08 17:15:34 -04:00
{
bCreateDynamicCollection = true ;
}
}
# endif
2022-11-21 18:58:53 -05:00
if ( bCreateDynamicCollection & & RestCollection & & RestCollection - > GetGeometryCollection ( ) )
2019-06-08 17:15:34 -04:00
{
DynamicCollection = MakeUnique < FGeometryDynamicCollection > ( ) ;
for ( const auto DynamicArray : CopyOnWriteAttributeList )
{
* DynamicArray = nullptr ;
}
GetTransformArrayCopyOnWrite ( ) ;
GetParentArrayCopyOnWrite ( ) ;
GetChildrenArrayCopyOnWrite ( ) ;
GetSimulationTypeArrayCopyOnWrite ( ) ;
GetStatusFlagsArrayCopyOnWrite ( ) ;
2021-08-31 20:24:01 -04:00
2022-07-06 15:00:45 -04:00
FGeometryCollectionDecayDynamicFacade DecayDynamicFacade ( * DynamicCollection ) ;
2022-06-21 22:08:04 -04:00
// we are not testing for bAllowRemovalOnSleep, so that we can enable it at runtime if necessary
2021-08-31 20:24:01 -04:00
if ( RestCollection - > bRemoveOnMaxSleep )
{
2022-07-06 15:00:45 -04:00
DecayDynamicFacade . AddAttributes ( ) ;
2021-08-31 20:24:01 -04:00
2022-07-06 15:00:45 -04:00
FGeometryCollectionRemoveOnSleepDynamicFacade RemoveOnSleepDynamicFacade ( * DynamicCollection ) ;
2022-11-21 18:58:53 -05:00
RemoveOnSleepDynamicFacade . DefineSchema ( ) ;
RemoveOnSleepDynamicFacade . SetAttributeValues ( RestCollection - > MaximumSleepTime , RestCollection - > RemovalDuration ) ;
2022-06-09 15:31:24 -04:00
}
// Remove on break feature related dynamic attribute arrays
2022-11-21 18:58:53 -05:00
// we are not testing for bAllowRemovalOnBreak, so that we can enable it at runtime if necessary
GeometryCollection : : Facades : : FCollectionRemoveOnBreakFacade RemoveOnBreakFacade ( * RestCollection - > GetGeometryCollection ( ) ) ;
if ( RemoveOnBreakFacade . IsValid ( ) )
2022-06-09 15:31:24 -04:00
{
2022-07-06 15:00:45 -04:00
DecayDynamicFacade . AddAttributes ( ) ;
2022-06-09 15:31:24 -04:00
2022-07-06 15:00:45 -04:00
FGeometryCollectionRemoveOnBreakDynamicFacade RemoveOnBreakDynamicFacade ( * DynamicCollection ) ;
2022-11-21 18:58:53 -05:00
RemoveOnBreakDynamicFacade . DefineSchema ( ) ;
RemoveOnBreakDynamicFacade . SetAttributeValues ( RemoveOnBreakFacade ) ;
2021-08-31 20:24:01 -04:00
}
2019-06-08 17:15:34 -04:00
SetRenderStateDirty ( ) ;
}
2021-06-16 01:29:49 -04:00
if ( RestTransforms . Num ( ) > 0 )
{
SetInitialTransforms ( RestTransforms ) ;
}
2018-12-12 11:25:29 -05:00
if ( RestCollection )
{
2019-06-08 17:15:34 -04:00
CalculateGlobalMatrices ( ) ;
CalculateLocalBounds ( ) ;
2018-12-12 11:25:29 -05:00
}
}
void UGeometryCollectionComponent : : OnCreatePhysicsState ( )
{
// Skip the chain - don't care about body instance setup
UActorComponent : : OnCreatePhysicsState ( ) ;
2021-05-25 22:01:05 -04:00
if ( ! BodyInstance . bSimulatePhysics ) IsObjectLoading = false ; // just mark as loaded if we are simulating.
2018-12-12 11:25:29 -05:00
2020-02-21 17:40:37 -05:00
// Static mesh uses an init framework that goes through FBodyInstance. We
// do the same thing, but through the geometry collection proxy and lambdas
// defined below. FBodyInstance doesn't work for geometry collections
// because FBodyInstance manages a single particle, where we have many.
2019-08-02 09:01:58 -04:00
if ( ! PhysicsProxy )
2019-06-08 17:15:34 -04:00
{
2018-12-12 11:25:29 -05:00
# if WITH_EDITOR && WITH_EDITORONLY_DATA
2019-06-08 17:15:34 -04:00
EditorActor = nullptr ;
if ( RestCollection )
{
//hack: find a better place for this
2020-10-21 17:56:05 -04:00
UGeometryCollection * RestCollectionMutable = const_cast < UGeometryCollection * > ( ToRawPtr ( RestCollection ) ) ;
2022-12-13 18:16:59 -05:00
RestCollectionMutable - > CreateSimulationDataIfNeeded ( ) ;
2019-06-08 17:15:34 -04:00
}
2018-12-12 11:25:29 -05:00
# endif
2022-12-16 17:59:26 -05:00
const bool bValidWorld = GetWorld ( ) & & ( GetWorld ( ) - > IsGameWorld ( ) | | GetWorld ( ) - > IsPreviewWorld ( ) ) ;
2019-06-08 17:15:34 -04:00
const bool bValidCollection = DynamicCollection & & DynamicCollection - > Transform . Num ( ) > 0 ;
if ( bValidWorld & & bValidCollection )
2018-12-12 11:25:29 -05:00
{
2020-03-09 13:22:54 -04:00
FPhysxUserData : : Set < UPrimitiveComponent > ( & PhysicsUserData , this ) ;
2020-12-09 18:44:07 -04:00
// If the Component is set to Dynamic, we look to the RestCollection for initial dynamic state override per transform.
2019-06-08 17:15:34 -04:00
TManagedArray < int32 > & DynamicState = DynamicCollection - > DynamicState ;
2020-12-09 18:44:07 -04:00
2022-05-13 12:55:08 -04:00
// if this code is changed you may need to account for bStartAwake
2022-02-25 15:15:52 -05:00
EObjectStateTypeEnum LocalObjectType = ( ObjectType ! = EObjectStateTypeEnum : : Chaos_Object_Sleeping ) ? ObjectType : EObjectStateTypeEnum : : Chaos_Object_Dynamic ;
if ( LocalObjectType ! = EObjectStateTypeEnum : : Chaos_Object_UserDefined )
2019-06-08 17:15:34 -04:00
{
2022-02-25 15:15:52 -05:00
if ( RestCollection & & ( LocalObjectType = = EObjectStateTypeEnum : : Chaos_Object_Dynamic ) )
2019-06-08 17:15:34 -04:00
{
2020-12-09 18:44:07 -04:00
TManagedArray < int32 > & InitialDynamicState = RestCollection - > GetGeometryCollection ( ) - > InitialDynamicState ;
for ( int i = 0 ; i < DynamicState . Num ( ) ; i + + )
{
2022-02-25 15:15:52 -05:00
DynamicState [ i ] = ( InitialDynamicState [ i ] = = static_cast < int32 > ( Chaos : : EObjectStateType : : Uninitialized ) ) ? static_cast < int32 > ( LocalObjectType ) : InitialDynamicState [ i ] ;
2020-12-09 18:44:07 -04:00
}
}
else
{
for ( int i = 0 ; i < DynamicState . Num ( ) ; i + + )
{
2022-02-25 15:15:52 -05:00
DynamicState [ i ] = static_cast < int32 > ( LocalObjectType ) ;
2020-12-09 18:44:07 -04:00
}
2019-06-08 17:15:34 -04:00
}
}
2020-12-09 18:44:07 -04:00
2021-06-16 01:29:49 -04:00
TManagedArray < bool > & Active = DynamicCollection - > Active ;
if ( RestCollection - > GetGeometryCollection ( ) - > HasAttribute ( FGeometryCollection : : SimulatableParticlesAttribute , FTransformCollection : : TransformGroup ) )
2019-06-08 17:15:34 -04:00
{
2021-06-16 01:29:49 -04:00
TManagedArray < bool > * SimulatableParticles = RestCollection - > GetGeometryCollection ( ) - > FindAttribute < bool > ( FGeometryCollection : : SimulatableParticlesAttribute , FTransformCollection : : TransformGroup ) ;
2019-06-08 17:15:34 -04:00
for ( int i = 0 ; i < Active . Num ( ) ; i + + )
{
2021-06-16 01:29:49 -04:00
Active [ i ] = ( * SimulatableParticles ) [ i ] ;
2019-06-08 17:15:34 -04:00
}
}
2021-06-16 01:29:49 -04:00
else
{
// If no simulation data is available then default to the simulation of just the rigid geometry.
for ( int i = 0 ; i < Active . Num ( ) ; i + + )
{
Active [ i ] = RestCollection - > GetGeometryCollection ( ) - > IsRigid ( i ) ;
}
}
2019-06-08 17:15:34 -04:00
TManagedArray < int32 > & CollisionGroupArray = DynamicCollection - > CollisionGroup ;
{
for ( int i = 0 ; i < CollisionGroupArray . Num ( ) ; i + + )
{
CollisionGroupArray [ i ] = CollisionGroup ;
}
}
2022-07-07 17:38:17 -04:00
2022-07-19 14:11:45 -04:00
// there's a code path where Level is not serialized and InitializeSharedCollisionStructures is not being called,
// resulting in the attribute missing and causing a crash in CopyAttribute calls later in FGeometryCollectionPhysicsProxy::Initialize
// @todo(chaos) we should better handle computation of dependent attribute like level
// @todo(chaos) We should implement a facade for levels, (parent and child included ? )
if ( ! RestCollection - > GetGeometryCollection ( ) - > HasAttribute ( " Level " , FTransformCollection : : TransformGroup ) )
{
TManagedArray < int32 > & Levels = RestCollection - > GetGeometryCollection ( ) - > AddAttribute < int32 > ( " Level " , FTransformCollection : : TransformGroup ) ;
for ( int32 TransformIndex = 0 ; TransformIndex < Levels . Num ( ) ; + + TransformIndex )
{
FGeometryCollectionPhysicsProxy : : CalculateAndSetLevel ( TransformIndex , RestCollection - > GetGeometryCollection ( ) - > Parent , Levels ) ;
}
}
2022-07-07 17:38:17 -04:00
// let's copy anchored information if available
const Chaos : : Facades : : FCollectionAnchoringFacade RestCollectionAnchoringFacade ( * RestCollection - > GetGeometryCollection ( ) ) ;
Chaos : : Facades : : FCollectionAnchoringFacade DynamicCollectionAnchoringFacade ( * DynamicCollection ) ;
DynamicCollectionAnchoringFacade . CopyAnchoredAttribute ( RestCollectionAnchoringFacade ) ;
2020-12-09 18:44:07 -04:00
2020-03-09 13:22:54 -04:00
// Set up initial filter data for our particles
2020-04-02 11:57:01 -04:00
// #BGTODO We need a dummy body setup for now to allow the body instance to generate filter information. Change body instance to operate independently.
DummyBodySetup = NewObject < UBodySetup > ( this , UBodySetup : : StaticClass ( ) ) ;
BodyInstance . BodySetup = DummyBodySetup ;
2022-05-11 15:55:55 -04:00
BodyInstance . OwnerComponent = this ; // Required to make filter data include component/actor ID for ignored actors/components
2020-04-02 11:57:01 -04:00
2022-05-26 20:17:19 -04:00
BuildInitialFilterData ( ) ;
2020-03-09 13:22:54 -04:00
2021-05-25 22:01:05 -04:00
if ( BodyInstance . bSimulatePhysics )
{
RegisterAndInitializePhysicsProxy ( ) ;
}
2019-06-08 17:15:34 -04:00
}
2018-12-12 11:25:29 -05:00
}
}
2022-10-20 16:47:18 -04:00
static FORCEINLINE_DEBUGGABLE int32 ComputeParticleLevel ( Chaos : : FPBDRigidClusteredParticleHandle * Particle )
{
int32 Level = 0 ;
if ( Particle )
{
Chaos : : FPBDRigidClusteredParticleHandle * Current = Particle ;
while ( Current - > Parent ( ) )
{
Current = Current - > Parent ( ) ;
+ + Level ;
}
}
return Level ;
} ;
2021-05-25 22:01:05 -04:00
void UGeometryCollectionComponent : : RegisterAndInitializePhysicsProxy ( )
{
FSimulationParameters SimulationParameters ;
{
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
SimulationParameters . Name = GetPathName ( ) ;
# endif
EClusterConnectionTypeEnum ClusterCollectionType = ClusterConnectionType_DEPRECATED ;
2022-05-20 15:20:13 -04:00
float ConnectionGraphBoundsFilteringMargin = 0 ;
2021-05-25 22:01:05 -04:00
if ( RestCollection )
{
RestCollection - > GetSharedSimulationParams ( SimulationParameters . Shared ) ;
SimulationParameters . RestCollection = RestCollection - > GetGeometryCollection ( ) . Get ( ) ;
ClusterCollectionType = RestCollection - > ClusterConnectionType ;
2022-05-20 15:20:13 -04:00
ConnectionGraphBoundsFilteringMargin = RestCollection - > ConnectionGraphBoundsFilteringMargin ;
2021-05-25 22:01:05 -04:00
}
SimulationParameters . Simulating = BodyInstance . bSimulatePhysics ;
SimulationParameters . EnableClustering = EnableClustering ;
SimulationParameters . ClusterGroupIndex = EnableClustering ? ClusterGroupIndex : 0 ;
SimulationParameters . MaxClusterLevel = MaxClusterLevel ;
SimulationParameters . bUseSizeSpecificDamageThresholds = bUseSizeSpecificDamageThreshold ;
SimulationParameters . DamageThreshold = DamageThreshold ;
2022-04-28 20:20:32 -04:00
SimulationParameters . bUsePerClusterOnlyDamageThreshold = RestCollection ? RestCollection - > PerClusterOnlyDamageThreshold : false ;
2021-05-25 22:01:05 -04:00
SimulationParameters . ClusterConnectionMethod = ( Chaos : : FClusterCreationParameters : : EConnectionMethod ) ClusterCollectionType ;
2022-05-20 15:20:13 -04:00
SimulationParameters . ConnectionGraphBoundsFilteringMargin = ConnectionGraphBoundsFilteringMargin ;
2021-05-25 22:01:05 -04:00
SimulationParameters . CollisionGroup = CollisionGroup ;
SimulationParameters . CollisionSampleFraction = CollisionSampleFraction ;
SimulationParameters . InitialVelocityType = InitialVelocityType ;
SimulationParameters . InitialLinearVelocity = InitialLinearVelocity ;
SimulationParameters . InitialAngularVelocity = InitialAngularVelocity ;
SimulationParameters . bClearCache = true ;
SimulationParameters . ObjectType = ObjectType ;
2022-05-13 12:55:08 -04:00
SimulationParameters . StartAwake = BodyInstance . bStartAwake ;
2021-05-25 22:01:05 -04:00
SimulationParameters . CacheType = CacheParameters . CacheMode ;
SimulationParameters . ReverseCacheBeginTime = CacheParameters . ReverseCacheBeginTime ;
2021-06-17 15:46:36 -04:00
SimulationParameters . bGenerateBreakingData = bNotifyBreaks ;
SimulationParameters . bGenerateCollisionData = bNotifyCollisions ;
SimulationParameters . bGenerateTrailingData = bNotifyTrailing ;
2021-08-31 20:24:01 -04:00
SimulationParameters . bGenerateRemovalsData = bNotifyRemovals ;
2022-07-12 17:47:42 -04:00
SimulationParameters . bGenerateCrumblingData = bNotifyCrumblings ;
SimulationParameters . bGenerateCrumblingChildrenData = bCrumblingEventIncludesChildren ;
2022-05-10 19:47:19 -04:00
SimulationParameters . EnableGravity = BodyInstance . bEnableGravity ;
2022-06-01 04:25:06 -04:00
SimulationParameters . UseInertiaConditioning = BodyInstance . IsInertiaConditioningEnabled ( ) ;
2022-06-17 11:29:46 -04:00
SimulationParameters . UseCCD = BodyInstance . bUseCCD ;
SimulationParameters . LinearDamping = BodyInstance . LinearDamping ;
SimulationParameters . AngularDamping = BodyInstance . AngularDamping ;
2022-08-23 17:17:36 -04:00
SimulationParameters . bUseDamagePropagation = DamagePropagationData . bEnabled ;
SimulationParameters . BreakDamagePropagationFactor = DamagePropagationData . BreakDamagePropagationFactor ;
SimulationParameters . ShockDamagePropagationFactor = DamagePropagationData . ShockDamagePropagationFactor ;
2021-05-25 22:01:05 -04:00
SimulationParameters . WorldTransform = GetComponentToWorld ( ) ;
SimulationParameters . UserData = static_cast < void * > ( & PhysicsUserData ) ;
UPhysicalMaterial * EnginePhysicalMaterial = GetPhysicalMaterial ( ) ;
if ( ensure ( EnginePhysicalMaterial ) )
{
SimulationParameters . PhysicalMaterialHandle = EnginePhysicalMaterial - > GetPhysicsMaterial ( ) ;
}
2021-05-27 16:31:32 -04:00
GetInitializationCommands ( SimulationParameters . InitializationCommands ) ;
2021-05-25 22:01:05 -04:00
}
2022-06-06 13:01:40 -04:00
FGuid CollectorGuid = FGuid : : NewGuid ( ) ;
# if WITH_EDITORONLY_DATA
CollectorGuid = RunTimeDataCollectionGuid ;
if ( bEnableRunTimeDataCollection & & RestCollection )
{
2022-06-07 01:41:53 -04:00
FRuntimeDataCollector : : GetInstance ( ) . AddCollector ( CollectorGuid , RestCollection - > NumElements ( FGeometryCollection : : TransformGroup ) ) ;
2022-06-06 13:01:40 -04:00
}
else
{
2022-06-07 01:41:53 -04:00
FRuntimeDataCollector : : GetInstance ( ) . RemoveCollector ( CollectorGuid ) ;
2022-06-06 13:01:40 -04:00
}
# endif
PhysicsProxy = new FGeometryCollectionPhysicsProxy ( this , * DynamicCollection , SimulationParameters , InitialSimFilter , InitialQueryFilter , CollectorGuid ) ;
2022-07-21 22:26:08 -04:00
PhysicsProxy - > SetPostPhysicsSyncCallback ( [ this ] ( ) { UpdateAttachedChildrenTransform ( ) ; } ) ;
2022-10-20 16:47:18 -04:00
if ( GetIsReplicated ( ) )
{
2022-10-28 00:33:43 -04:00
// using net mode and not local role because at this time in the initialization client and server both have an authority local role
const ENetMode NetMode = GetNetMode ( ) ;
if ( NetMode ! = NM_Standalone )
{
const FGeometryCollectionPhysicsProxy : : EReplicationMode ReplicationMode =
( NetMode = = ENetMode : : NM_Client )
? FGeometryCollectionPhysicsProxy : : EReplicationMode : : Client
: FGeometryCollectionPhysicsProxy : : EReplicationMode : : Server ;
PhysicsProxy - > SetReplicationMode ( ReplicationMode ) ;
}
2022-10-20 16:47:18 -04:00
}
2021-05-25 22:01:05 -04:00
FPhysScene_Chaos * Scene = GetInnerChaosScene ( ) ;
Scene - > AddObject ( this , PhysicsProxy ) ;
2022-10-20 16:47:18 -04:00
// If we're replicating we need some extra setup - check netmode as we don't need this for standalone runtimes where we aren't going to network the component
// IMPORTANT this need to happen after the object is registered so this will garantee that the particles are properly created by the time the callback below gets called
if ( GetIsReplicated ( ) )
{
// Client side : geometry collection children of parents below the rep level need to be infintely strong so that client cannot break it
if ( Chaos : : FPhysicsSolver * CurrSolver = GetSolver ( * this ) )
{
CurrSolver - > EnqueueCommandImmediate ( [ Proxy = PhysicsProxy , AbandonAfterLevel = ReplicationAbandonAfterLevel , EnableAbandonAfterLevel = bEnableAbandonAfterLevel ] ( )
{
if ( Proxy - > GetReplicationMode ( ) = = FGeometryCollectionPhysicsProxy : : EReplicationMode : : Client )
{
// As we're not in control we make it so our simulated proxy cannot break clusters
// We have to set the strain to a high value but be below the max for the data type
// so releasing on authority demand works
constexpr Chaos : : FReal MaxStrain = TNumericLimits < Chaos : : FReal > : : Max ( ) - TNumericLimits < Chaos : : FReal > : : Min ( ) ;
for ( Chaos : : FPBDRigidClusteredParticleHandle * ParticleHandle : Proxy - > GetParticles ( ) )
{
if ( ParticleHandle )
{
const int32 Level = EnableAbandonAfterLevel ? ComputeParticleLevel ( ParticleHandle ) : - 1 ;
if ( Level < = AbandonAfterLevel + 1 ) //we only replicate up until level X, but it means we should replicate the breaking event of level X+1 (but not X+1's positions)
{
ParticleHandle - > SetStrain ( MaxStrain ) ;
}
}
}
}
} ) ;
}
}
2021-05-25 22:01:05 -04:00
RegisterForEvents ( ) ;
2022-04-26 14:28:07 -04:00
SetAsyncPhysicsTickEnabled ( GetIsReplicated ( ) ) ;
2021-05-25 22:01:05 -04:00
}
2022-06-06 13:01:40 -04:00
# if WITH_EDITORONLY_DATA
2022-06-07 01:41:53 -04:00
const FDamageCollector * UGeometryCollectionComponent : : GetRunTimeDataCollector ( ) const
2022-06-06 13:01:40 -04:00
{
2022-06-07 01:41:53 -04:00
return FRuntimeDataCollector : : GetInstance ( ) . Find ( RunTimeDataCollectionGuid ) ;
2022-06-06 13:01:40 -04:00
}
# endif
2018-12-12 11:25:29 -05:00
void UGeometryCollectionComponent : : OnDestroyPhysicsState ( )
{
UActorComponent : : OnDestroyPhysicsState ( ) ;
2019-06-08 17:15:34 -04:00
if ( DummyBodyInstance . IsValidBodyInstance ( ) )
{
DummyBodyInstance . TermBody ( ) ;
}
2019-08-02 09:01:58 -04:00
if ( PhysicsProxy )
2019-06-08 17:15:34 -04:00
{
2020-03-09 13:22:54 -04:00
FPhysScene_Chaos * Scene = GetInnerChaosScene ( ) ;
2019-08-02 09:01:58 -04:00
Scene - > RemoveObject ( PhysicsProxy ) ;
2019-06-08 17:15:34 -04:00
InitializationState = ESimulationInitializationState : : Unintialized ;
2022-10-22 15:35:03 -04:00
// clear the clusters to rep as the information hold by it is now invalid
// we can still call this on the game thread because replication runs with the game thread frozen and will not run while the physics state is being torned down
ResetRepData ( ) ;
2019-06-08 17:15:34 -04:00
// Discard the pointer (cleanup happens through the scene or dedicated thread)
2019-08-02 09:01:58 -04:00
PhysicsProxy = nullptr ;
2018-12-12 11:25:29 -05:00
}
}
void UGeometryCollectionComponent : : SendRenderDynamicData_Concurrent ( )
{
//UE_LOG(UGCC_LOG, Log, TEXT("GeometryCollectionComponent[%p]::SendRenderDynamicData_Concurrent()"), this);
Super : : SendRenderDynamicData_Concurrent ( ) ;
2019-06-08 17:15:34 -04:00
// Only update the dynamic data if the dynamic collection is dirty
2022-10-21 19:51:57 -04:00
if ( SceneProxy & & ( ( DynamicCollection & & DynamicCollection - > IsDirty ( ) ) | | CachePlayback ) )
2019-06-08 17:15:34 -04:00
{
2021-04-24 04:37:11 -04:00
FGeometryCollectionDynamicData * DynamicData = InitDynamicData ( false /* initialization */ ) ;
2019-06-08 17:15:34 -04:00
2021-04-28 19:53:28 -04:00
if ( DynamicData | | SceneProxy - > IsNaniteMesh ( ) )
2019-06-08 17:15:34 -04:00
{
2021-04-28 19:53:28 -04:00
INC_DWORD_STAT_BY ( STAT_GCTotalTransforms , DynamicData ? DynamicData - > Transforms . Num ( ) : 0 ) ;
INC_DWORD_STAT_BY ( STAT_GCChangedTransforms , DynamicData ? DynamicData - > ChangedCount : 0 ) ;
2019-06-08 17:15:34 -04:00
2021-02-18 13:20:03 -04:00
// #todo (bmiller) Once ISMC changes have been complete, this is the best place to call this method
2021-04-20 10:45:04 -04:00
// but we can't currently because it's an inappropriate place to call MarkRenderStateDirty on the ISMC.
2021-02-18 13:20:03 -04:00
// RefreshEmbeddedGeometry();
2018-12-12 11:25:29 -05:00
// Enqueue command to send to render thread
2020-07-15 19:46:08 -04:00
if ( SceneProxy - > IsNaniteMesh ( ) )
{
FNaniteGeometryCollectionSceneProxy * GeometryCollectionSceneProxy = static_cast < FNaniteGeometryCollectionSceneProxy * > ( SceneProxy ) ;
ENQUEUE_RENDER_COMMAND ( SendRenderDynamicData ) (
[ GeometryCollectionSceneProxy , DynamicData ] ( FRHICommandListImmediate & RHICmdList )
2019-06-08 17:15:34 -04:00
{
2021-04-28 19:53:28 -04:00
if ( DynamicData )
{
GeometryCollectionSceneProxy - > SetDynamicData_RenderThread ( DynamicData ) ;
}
else
{
// No longer dynamic, make sure previous transforms are reset
GeometryCollectionSceneProxy - > ResetPreviousTransforms_RenderThread ( ) ;
}
2019-06-08 17:15:34 -04:00
}
2020-07-15 19:46:08 -04:00
) ;
}
else
{
FGeometryCollectionSceneProxy * GeometryCollectionSceneProxy = static_cast < FGeometryCollectionSceneProxy * > ( SceneProxy ) ;
ENQUEUE_RENDER_COMMAND ( SendRenderDynamicData ) (
[ GeometryCollectionSceneProxy , DynamicData ] ( FRHICommandListImmediate & RHICmdList )
{
if ( GeometryCollectionSceneProxy )
{
GeometryCollectionSceneProxy - > SetDynamicData_RenderThread ( DynamicData ) ;
}
}
) ;
}
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
// mark collection clean now that we have rendered
if ( DynamicCollection )
{
DynamicCollection - > MakeClean ( ) ;
}
2018-12-12 11:25:29 -05:00
}
}
2022-05-26 20:17:19 -04:00
void UGeometryCollectionComponent : : OnActorEnableCollisionChanged ( )
{
// Update filters on BI
BodyInstance . UpdatePhysicsFilterData ( ) ;
// Update InitialSimFilter and InitialQueryFilter
BuildInitialFilterData ( ) ;
// Update filters stored on proxy
if ( PhysicsProxy )
{
PhysicsProxy - > UpdateFilterData_External ( InitialSimFilter , InitialQueryFilter ) ;
}
}
void UGeometryCollectionComponent : : BuildInitialFilterData ( )
{
FBodyCollisionFilterData FilterData ;
FMaskFilter FilterMask = BodyInstance . GetMaskFilter ( ) ;
BodyInstance . BuildBodyFilterData ( FilterData ) ;
InitialSimFilter = FilterData . SimFilter ;
InitialQueryFilter = FilterData . QuerySimpleFilter ;
// Enable for complex and simple (no dual representation currently like other meshes)
InitialQueryFilter . Word3 | = ( EPDF_SimpleCollision | EPDF_ComplexCollision ) ;
InitialSimFilter . Word3 | = ( EPDF_SimpleCollision | EPDF_ComplexCollision ) ;
if ( bNotifyCollisions )
{
InitialQueryFilter . Word3 | = EPDF_ContactNotify ;
InitialSimFilter . Word3 | = EPDF_ContactNotify ;
}
}
2019-06-08 17:15:34 -04:00
void UGeometryCollectionComponent : : SetRestCollection ( const UGeometryCollection * RestCollectionIn )
2018-12-12 11:25:29 -05:00
{
//UE_LOG(UGCC_LOG, Log, TEXT("GeometryCollectionComponent[%p]::SetRestCollection()"), this);
if ( RestCollectionIn )
{
RestCollection = RestCollectionIn ;
2021-06-16 01:29:49 -04:00
const int32 NumTransforms = RestCollection - > GetGeometryCollection ( ) - > NumElements ( FGeometryCollection : : TransformGroup ) ;
RestTransforms . SetNum ( NumTransforms ) ;
for ( int32 Idx = 0 ; Idx < NumTransforms ; + + Idx )
{
RestTransforms [ Idx ] = RestCollection - > GetGeometryCollection ( ) - > Transform [ Idx ] ;
}
2019-06-08 17:15:34 -04:00
CalculateGlobalMatrices ( ) ;
CalculateLocalBounds ( ) ;
2021-02-18 13:20:03 -04:00
if ( ! IsEmbeddedGeometryValid ( ) )
{
InitializeEmbeddedGeometry ( ) ;
}
2022-05-24 12:10:43 -04:00
// initialize the component per level damage threshold from the asset defaults
2022-09-16 11:31:36 -04:00
DamageThreshold = RestCollection - > DamageThreshold ;
2022-09-16 21:25:31 -04:00
bUseSizeSpecificDamageThreshold = RestCollection - > bUseSizeSpecificDamageThreshold ;
2022-08-23 17:17:36 -04:00
// initialize the component damage progataion data from the asset defaults
DamagePropagationData = RestCollection - > DamagePropagationData ;
2021-02-18 13:20:03 -04:00
2019-06-08 17:15:34 -04:00
//ResetDynamicCollection();
2018-12-12 11:25:29 -05:00
}
}
2022-11-03 13:56:42 -04:00
FString UGeometryCollectionComponent : : GetDebugInfo ( )
{
// print the game thread side of things
FString DebugInfo ;
DebugInfo + = FString ( " RestCollection - " ) + ( RestCollection ? RestCollection - > GetName ( ) : FString ( " None " ) ) ;
DebugInfo + = " \n " ;
if ( RestCollection & & RestCollection - > GetGeometryCollection ( ) )
{
DebugInfo + = RestCollection - > GetGeometryCollection ( ) - > ToString ( ) ;
}
DebugInfo + = FString ( " DynamicCollection - " ) + FString ( DynamicCollection ? " Yes " : " No " ) ;
DebugInfo + = " \n " ;
if ( DynamicCollection )
{
DebugInfo + = DynamicCollection - > ToString ( ) ;
}
return DebugInfo ;
}
2022-02-02 01:45:10 -05:00
FGeometryCollectionEdit : : FGeometryCollectionEdit ( UGeometryCollectionComponent * InComponent , GeometryCollection : : EEditUpdate InEditUpdate , bool bShapeIsUnchanged )
2018-12-12 11:25:29 -05:00
: Component ( InComponent )
2019-06-20 12:19:58 -04:00
, EditUpdate ( InEditUpdate )
2022-02-02 01:45:10 -05:00
, bShapeIsUnchanged ( bShapeIsUnchanged )
2018-12-12 11:25:29 -05:00
{
bHadPhysicsState = Component - > HasValidPhysicsState ( ) ;
2019-06-20 12:19:58 -04:00
if ( EnumHasAnyFlags ( EditUpdate , GeometryCollection : : EEditUpdate : : Physics ) & & bHadPhysicsState )
2018-12-12 11:25:29 -05:00
{
Component - > DestroyPhysicsState ( ) ;
}
2022-01-28 13:40:49 -05:00
if ( EnumHasAnyFlags ( EditUpdate , GeometryCollection : : EEditUpdate : : Rest ) & & GetRestCollection ( ) )
{
2022-01-31 12:57:29 -05:00
Component - > Modify ( ) ;
2022-01-31 14:58:13 -05:00
GetRestCollection ( ) - > Modify ( ) ;
2022-01-28 13:40:49 -05:00
}
2018-12-12 11:25:29 -05:00
}
FGeometryCollectionEdit : : ~ FGeometryCollectionEdit ( )
{
2019-06-08 17:15:34 -04:00
# if WITH_EDITOR
2019-06-20 12:19:58 -04:00
if ( ! ! EditUpdate )
2018-12-12 11:25:29 -05:00
{
2019-06-20 12:19:58 -04:00
if ( EnumHasAnyFlags ( EditUpdate , GeometryCollection : : EEditUpdate : : Dynamic ) )
{
Component - > ResetDynamicCollection ( ) ;
}
2022-01-31 12:57:29 -05:00
if ( EnumHasAnyFlags ( EditUpdate , GeometryCollection : : EEditUpdate : : Rest ) & & GetRestCollection ( ) )
{
2022-02-02 01:45:10 -05:00
if ( ! bShapeIsUnchanged )
{
2022-10-24 16:24:39 -04:00
GetRestCollection ( ) - > UpdateGeometryDependentProperties ( ) ;
2022-02-02 01:45:10 -05:00
}
2022-01-31 12:57:29 -05:00
GetRestCollection ( ) - > InvalidateCollection ( ) ;
}
2019-06-20 12:19:58 -04:00
if ( EnumHasAnyFlags ( EditUpdate , GeometryCollection : : EEditUpdate : : Physics ) & & bHadPhysicsState )
2018-12-12 11:25:29 -05:00
{
Component - > RecreatePhysicsState ( ) ;
}
}
2019-06-08 17:15:34 -04:00
# endif
2018-12-12 11:25:29 -05:00
}
UGeometryCollection * FGeometryCollectionEdit : : GetRestCollection ( )
{
if ( Component )
{
2020-10-21 17:56:05 -04:00
return const_cast < UGeometryCollection * > ( ToRawPtr ( Component - > RestCollection ) ) ; //const cast is ok here since we are explicitly in edit mode. Should all this editor code be in an editor module?
2018-12-12 11:25:29 -05:00
}
return nullptr ;
}
2019-06-08 17:15:34 -04:00
# if WITH_EDITOR
2018-12-12 11:25:29 -05:00
TArray < FLinearColor > FScopedColorEdit : : RandomColors ;
2019-06-08 17:15:34 -04:00
FScopedColorEdit : : FScopedColorEdit ( UGeometryCollectionComponent * InComponent , bool bForceUpdate ) : bUpdated ( bForceUpdate ) , Component ( InComponent )
2018-12-12 11:25:29 -05:00
{
if ( RandomColors . Num ( ) = = 0 )
{
2019-06-08 17:15:34 -04:00
FMath : : RandInit ( 2019 ) ;
2018-12-12 11:25:29 -05:00
for ( int i = 0 ; i < 100 ; i + + )
{
const FColor Color ( FMath : : Rand ( ) % 100 + 5 , FMath : : Rand ( ) % 100 + 5 , FMath : : Rand ( ) % 100 + 5 , 255 ) ;
RandomColors . Push ( FLinearColor ( Color ) ) ;
}
}
}
FScopedColorEdit : : ~ FScopedColorEdit ( )
{
2019-06-08 17:15:34 -04:00
if ( bUpdated )
{
UpdateBoneColors ( ) ;
}
2018-12-12 11:25:29 -05:00
}
void FScopedColorEdit : : SetShowBoneColors ( bool ShowBoneColorsIn )
{
2019-06-08 17:15:34 -04:00
if ( Component - > bShowBoneColors ! = ShowBoneColorsIn )
{
bUpdated = true ;
Component - > bShowBoneColors = ShowBoneColorsIn ;
}
2018-12-12 11:25:29 -05:00
}
bool FScopedColorEdit : : GetShowBoneColors ( ) const
{
2019-06-08 17:15:34 -04:00
return Component - > bShowBoneColors ;
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
void FScopedColorEdit : : SetEnableBoneSelection ( bool ShowSelectedBonesIn )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
if ( Component - > bEnableBoneSelection ! = ShowSelectedBonesIn )
{
bUpdated = true ;
Component - > bEnableBoneSelection = ShowSelectedBonesIn ;
}
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
bool FScopedColorEdit : : GetEnableBoneSelection ( ) const
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
return Component - > bEnableBoneSelection ;
2018-12-12 11:25:29 -05:00
}
bool FScopedColorEdit : : IsBoneSelected ( int BoneIndex ) const
{
return Component - > SelectedBones . Contains ( BoneIndex ) ;
}
2022-09-09 14:15:27 -04:00
void FScopedColorEdit : : Sanitize ( )
{
const UGeometryCollection * GeometryCollection = Component - > GetRestCollection ( ) ;
if ( GeometryCollection )
{
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > GeometryCollectionPtr = GeometryCollection - > GetGeometryCollection ( ) ;
if ( GeometryCollectionPtr )
{
const int32 NumTransforms = GeometryCollectionPtr - > NumElements ( FGeometryCollection : : TransformGroup ) ;
const int32 NumSelectionRemoved = Component - > SelectedBones . RemoveAll ( [ this , NumTransforms ] ( int32 Index ) {
return Index < 0 | | Index > = NumTransforms ;
} ) ;
const int32 NumHighlightRemoved = Component - > HighlightedBones . RemoveAll ( [ this , NumTransforms ] ( int32 Index ) {
return Index < 0 | | Index > = NumTransforms ;
} ) ;
2022-09-29 23:42:41 -04:00
bUpdated = bUpdated | | NumSelectionRemoved | | NumHighlightRemoved ;
2022-09-09 14:15:27 -04:00
}
}
}
2018-12-12 11:25:29 -05:00
void FScopedColorEdit : : SetSelectedBones ( const TArray < int32 > & SelectedBonesIn )
{
2019-06-08 17:15:34 -04:00
bUpdated = true ;
2018-12-12 11:25:29 -05:00
Component - > SelectedBones = SelectedBonesIn ;
2021-09-05 20:37:59 -04:00
Component - > SelectEmbeddedGeometry ( ) ;
2018-12-12 11:25:29 -05:00
}
void FScopedColorEdit : : AppendSelectedBones ( const TArray < int32 > & SelectedBonesIn )
{
2019-06-08 17:15:34 -04:00
bUpdated = true ;
2018-12-12 11:25:29 -05:00
Component - > SelectedBones . Append ( SelectedBonesIn ) ;
}
2022-02-10 18:36:20 -05:00
void FScopedColorEdit : : ToggleSelectedBones ( const TArray < int32 > & SelectedBonesIn , bool bAdd , bool bSnapToLevel )
2019-06-08 17:15:34 -04:00
{
bUpdated = true ;
2021-06-15 00:47:27 -04:00
const UGeometryCollection * GeometryCollection = Component - > GetRestCollection ( ) ;
if ( GeometryCollection )
{
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > GeometryCollectionPtr = GeometryCollection - > GetGeometryCollection ( ) ;
for ( int32 BoneIndex : SelectedBonesIn )
2019-06-08 17:15:34 -04:00
{
2021-06-15 00:47:27 -04:00
2022-02-10 18:36:20 -05:00
int32 ContextBoneIndex = ( bSnapToLevel & & GetViewLevel ( ) > - 1 ) ?
FGeometryCollectionClusteringUtility : : GetParentOfBoneAtSpecifiedLevel ( GeometryCollectionPtr . Get ( ) , BoneIndex , GetViewLevel ( ) , true /*bSkipFiltered*/ )
: BoneIndex ;
if ( ContextBoneIndex = = FGeometryCollection : : Invalid )
{
continue ;
}
2021-06-15 00:47:27 -04:00
if ( bAdd ) // shift select
{
2022-06-28 14:18:01 -04:00
Component - > SelectedBones . Add ( ContextBoneIndex ) ;
2021-06-15 00:47:27 -04:00
}
else // ctrl select (toggle)
{
if ( Component - > SelectedBones . Contains ( ContextBoneIndex ) )
{
Component - > SelectedBones . Remove ( ContextBoneIndex ) ;
}
else
{
Component - > SelectedBones . Add ( ContextBoneIndex ) ;
}
}
2019-06-08 17:15:34 -04:00
}
}
}
2018-12-12 11:25:29 -05:00
void FScopedColorEdit : : AddSelectedBone ( int32 BoneIndex )
{
2019-06-08 17:15:34 -04:00
if ( ! Component - > SelectedBones . Contains ( BoneIndex ) )
{
bUpdated = true ;
Component - > SelectedBones . Push ( BoneIndex ) ;
}
2018-12-12 11:25:29 -05:00
}
void FScopedColorEdit : : ClearSelectedBone ( int32 BoneIndex )
{
2019-06-08 17:15:34 -04:00
if ( Component - > SelectedBones . Contains ( BoneIndex ) )
{
bUpdated = true ;
Component - > SelectedBones . Remove ( BoneIndex ) ;
}
2018-12-12 11:25:29 -05:00
}
const TArray < int32 > & FScopedColorEdit : : GetSelectedBones ( ) const
{
return Component - > GetSelectedBones ( ) ;
}
2022-02-10 18:36:20 -05:00
int32 FScopedColorEdit : : GetMaxSelectedLevel ( bool bOnlyRigid ) const
{
int32 MaxSelectedLevel = - 1 ;
const UGeometryCollection * GeometryCollection = Component - > GetRestCollection ( ) ;
2022-07-20 20:17:14 -04:00
if ( GeometryCollection & & GeometryCollection - > GetGeometryCollection ( ) - > HasAttribute ( " Level " , FGeometryCollection : : TransformGroup ) )
2022-02-10 18:36:20 -05:00
{
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > GeometryCollectionPtr = GeometryCollection - > GetGeometryCollection ( ) ;
const TManagedArray < int32 > & Levels = GeometryCollectionPtr - > GetAttribute < int32 > ( " Level " , FGeometryCollection : : TransformGroup ) ;
const TManagedArray < int32 > & SimTypes = GeometryCollectionPtr - > SimulationType ;
for ( int32 BoneIndex : Component - > SelectedBones )
{
if ( ! bOnlyRigid | | SimTypes [ BoneIndex ] = = FGeometryCollection : : ESimulationTypes : : FST_Rigid )
{
MaxSelectedLevel = FMath : : Max ( MaxSelectedLevel , Levels [ BoneIndex ] ) ;
}
}
}
return MaxSelectedLevel ;
}
bool FScopedColorEdit : : IsSelectionValidAtLevel ( int32 TargetLevel ) const
{
if ( TargetLevel = = - 1 )
{
return true ;
}
const UGeometryCollection * GeometryCollection = Component - > GetRestCollection ( ) ;
2022-07-20 20:17:14 -04:00
if ( GeometryCollection & & GeometryCollection - > GetGeometryCollection ( ) - > HasAttribute ( " Level " , FGeometryCollection : : TransformGroup ) )
2022-02-10 18:36:20 -05:00
{
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > GeometryCollectionPtr = GeometryCollection - > GetGeometryCollection ( ) ;
const TManagedArray < int32 > & Levels = GeometryCollectionPtr - > GetAttribute < int32 > ( " Level " , FGeometryCollection : : TransformGroup ) ;
const TManagedArray < int32 > & SimTypes = GeometryCollectionPtr - > SimulationType ;
for ( int32 BoneIndex : Component - > SelectedBones )
{
if ( SimTypes [ BoneIndex ] ! = FGeometryCollection : : ESimulationTypes : : FST_Clustered & & // clusters are always shown in outliner
Levels [ BoneIndex ] ! = TargetLevel & & // nodes at the target level are shown in outliner
// non-cluster parents are shown if they have children that are exact matches (i.e., a rigid parent w/ embedded at the target level)
( GeometryCollectionPtr - > Children [ BoneIndex ] . Num ( ) = = 0 | | Levels [ BoneIndex ] + 1 ! = TargetLevel ) )
{
return false ;
}
}
}
return true ;
}
2018-12-12 11:25:29 -05:00
void FScopedColorEdit : : ResetBoneSelection ( )
{
2019-06-08 17:15:34 -04:00
if ( Component - > SelectedBones . Num ( ) > 0 )
{
bUpdated = true ;
}
2018-12-12 11:25:29 -05:00
Component - > SelectedBones . Empty ( ) ;
}
2022-02-10 18:36:20 -05:00
void FScopedColorEdit : : FilterSelectionToLevel ( bool bPreferLowestOnly )
{
const UGeometryCollection * GeometryCollection = Component - > GetRestCollection ( ) ;
int32 ViewLevel = GetViewLevel ( ) ;
bool bNeedsFiltering = ViewLevel > = 0 | | bPreferLowestOnly ;
2022-07-20 20:17:14 -04:00
if ( GeometryCollection & & Component - > SelectedBones . Num ( ) > 0 & & bNeedsFiltering & & GeometryCollection - > GetGeometryCollection ( ) - > HasAttribute ( " Level " , FGeometryCollection : : TransformGroup ) )
2022-02-10 18:36:20 -05:00
{
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > GeometryCollectionPtr = GeometryCollection - > GetGeometryCollection ( ) ;
const TManagedArray < int32 > & Levels = GeometryCollectionPtr - > GetAttribute < int32 > ( " Level " , FGeometryCollection : : TransformGroup ) ;
const TManagedArray < int32 > & SimTypes = GeometryCollectionPtr - > SimulationType ;
TArray < int32 > NewSelection ;
NewSelection . Reserve ( Component - > SelectedBones . Num ( ) ) ;
if ( ViewLevel > = 0 )
{
for ( int32 BoneIdx : Component - > SelectedBones )
{
bool bIsCluster = SimTypes [ BoneIdx ] = = FGeometryCollection : : ESimulationTypes : : FST_Clustered ;
if ( bPreferLowestOnly & & bIsCluster & & Levels [ BoneIdx ] < ViewLevel )
{
continue ;
}
if ( Levels [ BoneIdx ] = = ViewLevel | | ( bIsCluster & & Levels [ BoneIdx ] < = ViewLevel ) )
{
NewSelection . Add ( BoneIdx ) ;
}
}
}
else // bPreferLowestOnly && ViewLevel == -1
{
// If view level is "all" and we prefer lowest selection, just select any non-cluster nodes
for ( int32 BoneIdx : Component - > SelectedBones )
{
bool bIsCluster = SimTypes [ BoneIdx ] = = FGeometryCollection : : ESimulationTypes : : FST_Clustered ;
if ( ! bIsCluster )
{
NewSelection . Add ( BoneIdx ) ;
}
}
}
if ( NewSelection . Num ( ) ! = Component - > SelectedBones . Num ( ) )
{
SetSelectedBones ( NewSelection ) ;
SetHighlightedBones ( NewSelection , true ) ;
}
}
}
2018-12-12 11:25:29 -05:00
void FScopedColorEdit : : SelectBones ( GeometryCollection : : ESelectionMode SelectionMode )
{
check ( Component ) ;
2019-06-08 17:15:34 -04:00
2018-12-12 11:25:29 -05:00
const UGeometryCollection * GeometryCollection = Component - > GetRestCollection ( ) ;
if ( GeometryCollection )
{
2019-06-08 17:15:34 -04:00
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > GeometryCollectionPtr = GeometryCollection - > GetGeometryCollection ( ) ;
2018-12-12 11:25:29 -05:00
switch ( SelectionMode )
{
case GeometryCollection : : ESelectionMode : : None :
ResetBoneSelection ( ) ;
break ;
case GeometryCollection : : ESelectionMode : : AllGeometry :
{
ResetBoneSelection ( ) ;
2022-02-10 18:36:20 -05:00
TArray < int32 > BonesToSelect ;
FGeometryCollectionClusteringUtility : : GetBonesToLevel ( GeometryCollectionPtr . Get ( ) , GetViewLevel ( ) , BonesToSelect , true , true ) ;
AppendSelectedBones ( BonesToSelect ) ;
2018-12-12 11:25:29 -05:00
}
break ;
2022-06-14 12:44:09 -04:00
case GeometryCollection : : ESelectionMode : : Leaves :
{
ResetBoneSelection ( ) ;
2022-06-16 13:56:41 -04:00
int32 ViewLevel = GetViewLevel ( ) ;
2022-06-14 12:44:09 -04:00
TArray < int32 > BonesToSelect ;
FGeometryCollectionClusteringUtility : : GetBonesToLevel ( GeometryCollectionPtr . Get ( ) , GetViewLevel ( ) , BonesToSelect , true , true ) ;
const TManagedArray < int32 > & SimType = GeometryCollectionPtr - > SimulationType ;
2022-07-20 20:17:14 -04:00
const TManagedArray < int32 > * Levels = GeometryCollectionPtr - > FindAttributeTyped < int32 > ( " Level " , FGeometryCollection : : TransformGroup ) ;
2022-06-14 12:44:09 -04:00
BonesToSelect . SetNum ( Algo : : RemoveIf ( BonesToSelect , [ & ] ( int32 BoneIdx )
{
2022-06-16 13:56:41 -04:00
return SimType [ BoneIdx ] ! = FGeometryCollection : : ESimulationTypes : : FST_Rigid
2022-07-20 20:17:14 -04:00
| | ( ViewLevel ! = - 1 & & Levels & & ( * Levels ) [ BoneIdx ] ! = ViewLevel ) ;
2022-06-14 12:44:09 -04:00
} ) ) ;
AppendSelectedBones ( BonesToSelect ) ;
}
break ;
case GeometryCollection : : ESelectionMode : : Clusters :
{
ResetBoneSelection ( ) ;
2022-06-16 13:56:41 -04:00
int32 ViewLevel = GetViewLevel ( ) ;
2022-06-14 12:44:09 -04:00
TArray < int32 > BonesToSelect ;
2022-06-16 13:56:41 -04:00
FGeometryCollectionClusteringUtility : : GetBonesToLevel ( GeometryCollectionPtr . Get ( ) , ViewLevel , BonesToSelect , true , true ) ;
2022-06-14 12:44:09 -04:00
const TManagedArray < int32 > & SimType = GeometryCollectionPtr - > SimulationType ;
2022-07-20 20:17:14 -04:00
const TManagedArray < int32 > * Levels = GeometryCollectionPtr - > FindAttributeTyped < int32 > ( " Level " , FGeometryCollection : : TransformGroup ) ;
2022-06-14 12:44:09 -04:00
BonesToSelect . SetNum ( Algo : : RemoveIf ( BonesToSelect , [ & ] ( int32 BoneIdx )
{
2022-06-16 13:56:41 -04:00
return SimType [ BoneIdx ] ! = FGeometryCollection : : ESimulationTypes : : FST_Clustered
2022-07-20 20:17:14 -04:00
| | ( ViewLevel ! = - 1 & & Levels & & ( * Levels ) [ BoneIdx ] ! = ViewLevel ) ;
2022-06-14 12:44:09 -04:00
} ) ) ;
AppendSelectedBones ( BonesToSelect ) ;
}
break ;
2018-12-12 11:25:29 -05:00
case GeometryCollection : : ESelectionMode : : InverseGeometry :
{
TArray < int32 > Roots ;
FGeometryCollectionClusteringUtility : : GetRootBones ( GeometryCollectionPtr . Get ( ) , Roots ) ;
TArray < int32 > NewSelection ;
2021-06-15 00:47:27 -04:00
2018-12-12 11:25:29 -05:00
for ( int32 RootElement : Roots )
{
2021-06-15 00:47:27 -04:00
if ( GetViewLevel ( ) = = - 1 )
2018-12-12 11:25:29 -05:00
{
2021-06-15 00:47:27 -04:00
TArray < int32 > LeafBones ;
FGeometryCollectionClusteringUtility : : GetLeafBones ( GeometryCollectionPtr . Get ( ) , RootElement , true , LeafBones ) ;
for ( int32 Element : LeafBones )
2018-12-12 11:25:29 -05:00
{
2021-06-15 00:47:27 -04:00
if ( ! IsBoneSelected ( Element ) )
{
NewSelection . Push ( Element ) ;
}
}
}
else
{
TArray < int32 > ViewLevelBones ;
FGeometryCollectionClusteringUtility : : GetChildBonesAtLevel ( GeometryCollectionPtr . Get ( ) , RootElement , GetViewLevel ( ) , ViewLevelBones ) ;
for ( int32 ViewLevelBone : ViewLevelBones )
{
if ( ! IsBoneSelected ( ViewLevelBone ) )
{
NewSelection . Push ( ViewLevelBone ) ;
}
2018-12-12 11:25:29 -05:00
}
}
}
2021-06-15 00:47:27 -04:00
2018-12-12 11:25:29 -05:00
ResetBoneSelection ( ) ;
AppendSelectedBones ( NewSelection ) ;
}
break ;
2019-06-08 17:15:34 -04:00
case GeometryCollection : : ESelectionMode : : Neighbors :
{
2021-09-01 01:43:26 -04:00
FGeometryCollectionProximityUtility ProximityUtility ( GeometryCollectionPtr . Get ( ) ) ;
2022-10-24 16:24:39 -04:00
ProximityUtility . RequireProximity ( ) ;
2021-09-01 01:43:26 -04:00
2021-12-13 15:59:48 -05:00
const TManagedArray < int32 > & TransformIndex = GeometryCollectionPtr - > TransformIndex ;
const TManagedArray < int32 > & TransformToGeometryIndex = GeometryCollectionPtr - > TransformToGeometryIndex ;
const TManagedArray < TSet < int32 > > & Proximity = GeometryCollectionPtr - > GetAttribute < TSet < int32 > > ( " Proximity " , FGeometryCollection : : GeometryGroup ) ;
2021-09-01 01:43:26 -04:00
2021-12-13 15:59:48 -05:00
const TArray < int32 > SelectedBones = GetSelectedBones ( ) ;
2021-09-01 01:43:26 -04:00
2022-06-14 12:44:09 -04:00
TSet < int32 > NewSelection ;
2021-12-13 15:59:48 -05:00
for ( int32 Bone : SelectedBones )
{
2022-06-14 12:44:09 -04:00
NewSelection . Add ( Bone ) ;
2021-12-13 15:59:48 -05:00
int32 GeometryIdx = TransformToGeometryIndex [ Bone ] ;
if ( GeometryIdx ! = INDEX_NONE )
2019-06-08 17:15:34 -04:00
{
2021-12-13 15:59:48 -05:00
const TSet < int32 > & Neighbors = Proximity [ GeometryIdx ] ;
for ( int32 NeighborGeometryIndex : Neighbors )
2019-06-08 17:15:34 -04:00
{
2022-06-14 12:44:09 -04:00
NewSelection . Add ( TransformIndex [ NeighborGeometryIndex ] ) ;
2019-06-08 17:15:34 -04:00
}
}
2021-09-06 12:23:53 -04:00
}
2021-12-13 15:59:48 -05:00
ResetBoneSelection ( ) ;
2022-06-14 12:44:09 -04:00
AppendSelectedBones ( NewSelection . Array ( ) ) ;
2021-12-13 15:59:48 -05:00
}
2019-06-08 17:15:34 -04:00
break ;
2021-08-30 17:18:37 -04:00
case GeometryCollection : : ESelectionMode : : Parent :
{
const TManagedArray < int32 > & Parents = GeometryCollectionPtr - > Parent ;
const TArray < int32 > SelectedBones = GetSelectedBones ( ) ;
2022-06-14 12:44:09 -04:00
TSet < int32 > NewSelection ;
2021-08-30 17:18:37 -04:00
for ( int32 Bone : SelectedBones )
{
int32 ParentBone = Parents [ Bone ] ;
if ( ParentBone ! = FGeometryCollection : : Invalid )
{
2022-06-14 12:44:09 -04:00
NewSelection . Add ( ParentBone ) ;
2021-08-30 17:18:37 -04:00
}
}
ResetBoneSelection ( ) ;
2022-06-14 12:44:09 -04:00
AppendSelectedBones ( NewSelection . Array ( ) ) ;
2021-08-30 17:18:37 -04:00
}
break ;
case GeometryCollection : : ESelectionMode : : Children :
{
const TManagedArray < TSet < int32 > > & Children = GeometryCollectionPtr - > Children ;
const TArray < int32 > SelectedBones = GetSelectedBones ( ) ;
2022-06-14 12:44:09 -04:00
TSet < int32 > NewSelection ;
2021-08-30 17:18:37 -04:00
for ( int32 Bone : SelectedBones )
{
2022-06-14 12:44:09 -04:00
if ( Children [ Bone ] . IsEmpty ( ) )
{
NewSelection . Add ( Bone ) ;
continue ;
}
2021-08-30 17:18:37 -04:00
for ( int32 Child : Children [ Bone ] )
{
2022-06-14 12:44:09 -04:00
NewSelection . Add ( Child ) ;
2021-08-30 17:18:37 -04:00
}
}
ResetBoneSelection ( ) ;
2022-06-14 12:44:09 -04:00
AppendSelectedBones ( NewSelection . Array ( ) ) ;
2021-08-30 17:18:37 -04:00
}
break ;
2019-06-08 17:15:34 -04:00
case GeometryCollection : : ESelectionMode : : Siblings :
{
const TManagedArray < int32 > & Parents = GeometryCollectionPtr - > Parent ;
const TManagedArray < TSet < int32 > > & Children = GeometryCollectionPtr - > Children ;
const TArray < int32 > SelectedBones = GetSelectedBones ( ) ;
2022-06-14 12:44:09 -04:00
TSet < int32 > NewSelection ;
2019-06-08 17:15:34 -04:00
for ( int32 Bone : SelectedBones )
{
int32 ParentBone = Parents [ Bone ] ;
if ( ParentBone ! = FGeometryCollection : : Invalid )
{
for ( int32 Child : Children [ ParentBone ] )
{
2022-06-14 12:44:09 -04:00
NewSelection . Add ( Child ) ;
2019-06-08 17:15:34 -04:00
}
}
}
ResetBoneSelection ( ) ;
2022-06-14 12:44:09 -04:00
AppendSelectedBones ( NewSelection . Array ( ) ) ;
2019-06-08 17:15:34 -04:00
}
break ;
2021-08-30 17:18:37 -04:00
case GeometryCollection : : ESelectionMode : : Level :
2019-06-08 17:15:34 -04:00
{
2021-08-30 17:18:37 -04:00
if ( GeometryCollectionPtr - > HasAttribute ( " Level " , FTransformCollection : : TransformGroup ) )
2021-12-13 15:59:48 -05:00
{
2021-08-30 17:18:37 -04:00
const TManagedArray < int32 > & Levels = GeometryCollectionPtr - > GetAttribute < int32 > ( " Level " , FTransformCollection : : TransformGroup ) ;
2019-06-08 17:15:34 -04:00
2021-12-13 15:59:48 -05:00
const TArray < int32 > SelectedBones = GetSelectedBones ( ) ;
2021-08-30 17:18:37 -04:00
2022-06-14 12:44:09 -04:00
TSet < int32 > NewSelection ;
2021-12-13 15:59:48 -05:00
for ( int32 Bone : SelectedBones )
{
2021-08-30 17:18:37 -04:00
int32 Level = Levels [ Bone ] ;
for ( int32 TransformIdx = 0 ; TransformIdx < GeometryCollectionPtr - > NumElements ( FTransformCollection : : TransformGroup ) ; + + TransformIdx )
{
if ( Levels [ TransformIdx ] = = Level )
2021-12-13 15:59:48 -05:00
{
2022-06-14 12:44:09 -04:00
NewSelection . Add ( TransformIdx ) ;
2021-08-30 17:18:37 -04:00
}
2021-12-13 15:59:48 -05:00
}
2019-06-08 17:15:34 -04:00
}
2021-12-13 15:59:48 -05:00
ResetBoneSelection ( ) ;
2022-06-14 12:44:09 -04:00
AppendSelectedBones ( NewSelection . Array ( ) ) ;
2021-12-13 15:59:48 -05:00
}
2019-06-08 17:15:34 -04:00
}
break ;
2018-12-12 11:25:29 -05:00
default :
check ( false ) ; // unexpected selection mode
break ;
}
2019-06-08 17:15:34 -04:00
const TArray < int32 > & SelectedBones = GetSelectedBones ( ) ;
2021-08-30 17:23:27 -04:00
TArray < int32 > HighlightBones ;
for ( int32 SelectedBone : SelectedBones )
{
FGeometryCollectionClusteringUtility : : RecursiveAddAllChildren ( GeometryCollectionPtr - > Children , SelectedBone , HighlightBones ) ;
}
SetHighlightedBones ( HighlightBones ) ;
2018-12-12 11:25:29 -05:00
}
}
bool FScopedColorEdit : : IsBoneHighlighted ( int BoneIndex ) const
{
return Component - > HighlightedBones . Contains ( BoneIndex ) ;
}
2022-02-10 18:36:20 -05:00
void FScopedColorEdit : : SetHighlightedBones ( const TArray < int32 > & HighlightedBonesIn , bool bHighlightChildren )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
if ( Component - > HighlightedBones ! = HighlightedBonesIn )
{
2022-02-10 18:36:20 -05:00
const UGeometryCollection * GeometryCollection = Component - > GetRestCollection ( ) ;
if ( bHighlightChildren & & GeometryCollection )
{
Component - > HighlightedBones . Reset ( ) ;
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > GeometryCollectionPtr = GeometryCollection - > GetGeometryCollection ( ) ;
for ( int32 SelectedBone : HighlightedBonesIn )
{
FGeometryCollectionClusteringUtility : : RecursiveAddAllChildren ( GeometryCollectionPtr - > Children , SelectedBone , Component - > HighlightedBones ) ;
}
}
else
{
Component - > HighlightedBones = HighlightedBonesIn ;
}
2019-06-08 17:15:34 -04:00
bUpdated = true ;
}
2018-12-12 11:25:29 -05:00
}
void FScopedColorEdit : : AddHighlightedBone ( int32 BoneIndex )
{
Component - > HighlightedBones . Push ( BoneIndex ) ;
}
const TArray < int32 > & FScopedColorEdit : : GetHighlightedBones ( ) const
{
return Component - > GetHighlightedBones ( ) ;
}
void FScopedColorEdit : : ResetHighlightedBones ( )
{
2019-06-08 17:15:34 -04:00
if ( Component - > HighlightedBones . Num ( ) > 0 )
{
bUpdated = true ;
Component - > HighlightedBones . Empty ( ) ;
}
2018-12-12 11:25:29 -05:00
}
void FScopedColorEdit : : SetLevelViewMode ( int ViewLevelIn )
{
2019-06-08 17:15:34 -04:00
if ( Component - > ViewLevel ! = ViewLevelIn )
{
bUpdated = true ;
Component - > ViewLevel = ViewLevelIn ;
}
2018-12-12 11:25:29 -05:00
}
int FScopedColorEdit : : GetViewLevel ( )
{
return Component - > ViewLevel ;
}
void FScopedColorEdit : : UpdateBoneColors ( )
{
2019-06-08 17:15:34 -04:00
// @todo FractureTools - For large fractures updating colors this way is extremely slow because the render state (and thus all buffers) must be recreated.
// It would be better to push the update to the proxy via a render command and update the existing buffer directly
2019-07-22 14:27:12 -04:00
FGeometryCollectionEdit GeometryCollectionEdit = Component - > EditRestCollection ( GeometryCollection : : EEditUpdate : : None ) ;
2018-12-12 11:25:29 -05:00
UGeometryCollection * GeometryCollection = GeometryCollectionEdit . GetRestCollection ( ) ;
2019-06-08 17:15:34 -04:00
if ( GeometryCollection )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
FGeometryCollection * Collection = GeometryCollection - > GetGeometryCollection ( ) . Get ( ) ;
FLinearColor BlankColor ( FColor ( 80 , 80 , 80 , 50 ) ) ;
const TManagedArray < int > & Parents = Collection - > Parent ;
bool HasLevelAttribute = Collection - > HasAttribute ( " Level " , FTransformCollection : : TransformGroup ) ;
2022-05-10 18:56:28 -04:00
const TManagedArray < int > * Levels = nullptr ;
2019-06-08 17:15:34 -04:00
if ( HasLevelAttribute )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
Levels = & Collection - > GetAttribute < int32 > ( " Level " , FTransformCollection : : TransformGroup ) ;
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
TManagedArray < FLinearColor > & BoneColors = Collection - > BoneColor ;
2019-07-23 16:27:55 -04:00
for ( int32 BoneIndex = 0 , NumBones = Parents . Num ( ) ; BoneIndex < NumBones ; + + BoneIndex )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
FLinearColor BoneColor = FLinearColor ( FColor : : Black ) ;
2022-09-20 18:48:26 -04:00
if ( Component - > bShowBoneColors )
2018-12-12 11:25:29 -05:00
{
2022-09-20 18:48:26 -04:00
if ( Component - > ViewLevel = = - 1 )
2018-12-12 11:25:29 -05:00
{
2022-09-20 18:48:26 -04:00
BoneColor = RandomColors [ BoneIndex % RandomColors . Num ( ) ] ;
2018-12-12 11:25:29 -05:00
}
else
{
2022-09-20 18:48:26 -04:00
if ( HasLevelAttribute & & ( * Levels ) [ BoneIndex ] > = Component - > ViewLevel )
{
// go up until we find parent at the required ViewLevel
int32 Bone = BoneIndex ;
while ( Bone ! = - 1 & & ( * Levels ) [ Bone ] > Component - > ViewLevel )
{
Bone = Parents [ Bone ] ;
}
int32 ColorIndex = Bone + 1 ; // parent can be -1 for root, range [-1..n]
BoneColor = RandomColors [ ColorIndex % RandomColors . Num ( ) ] ;
BoneColor . LinearRGBToHSV ( ) ;
BoneColor . B * = .5 ;
BoneColor . HSVToLinearRGB ( ) ;
}
else
{
BoneColor = BlankColor ;
}
2018-12-12 11:25:29 -05:00
}
}
2022-09-20 18:48:26 -04:00
else
{
BoneColor = FLinearColor ( FColor : : White ) ;
if ( Component - > ViewLevel ! = INDEX_NONE & & HasLevelAttribute & & ( * Levels ) [ BoneIndex ] < Component - > ViewLevel )
{
BoneColor = FLinearColor ( FColor ( 128U , 128U , 128U , 255U ) ) ;
}
}
2019-06-08 17:15:34 -04:00
// store the bone selected toggle in alpha so we can use it in the shader
BoneColor . A = IsBoneHighlighted ( BoneIndex ) ? 1 : 0 ;
BoneColors [ BoneIndex ] = BoneColor ;
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
Component - > MarkRenderStateDirty ( ) ;
Component - > MarkRenderDynamicDataDirty ( ) ;
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
}
# endif
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
void UGeometryCollectionComponent : : ApplyKinematicField ( float Radius , FVector Position )
{
2021-05-19 13:46:19 -04:00
FFieldSystemCommand Command = FFieldObjectCommands : : CreateFieldCommand ( EFieldPhysicsType : : Field_DynamicState , new FRadialIntMask ( Radius , Position , ( int32 ) Chaos : : EObjectStateType : : Dynamic ,
( int32 ) Chaos : : EObjectStateType : : Kinematic , ESetMaskConditionType : : Field_Set_IFF_NOT_Interior ) ) ;
DispatchFieldCommand ( Command ) ;
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
void UGeometryCollectionComponent : : ApplyPhysicsField ( bool Enabled , EGeometryCollectionPhysicsTypeEnum Target , UFieldSystemMetaData * MetaData , UFieldNodeBase * Field )
{
if ( Enabled & & Field )
2018-12-12 11:25:29 -05:00
{
2021-05-19 13:46:19 -04:00
FFieldSystemCommand Command = FFieldObjectCommands : : CreateFieldCommand ( GetGeometryCollectionPhysicsType ( Target ) , Field , MetaData ) ;
2021-02-03 14:57:28 -04:00
DispatchFieldCommand ( Command ) ;
2018-12-12 11:25:29 -05:00
}
}
2021-05-25 22:01:05 -04:00
bool UGeometryCollectionComponent : : GetIsObjectDynamic ( ) const
{
return PhysicsProxy ? PhysicsProxy - > GetIsObjectDynamic ( ) : IsObjectDynamic ;
}
2021-05-19 13:46:19 -04:00
2021-02-03 14:57:28 -04:00
void UGeometryCollectionComponent : : DispatchFieldCommand ( const FFieldSystemCommand & InCommand )
2019-06-08 17:15:34 -04:00
{
2021-08-02 07:51:15 -04:00
if ( PhysicsProxy & & InCommand . RootNode )
2019-06-08 17:15:34 -04:00
{
2020-09-24 00:43:27 -04:00
FChaosSolversModule * ChaosModule = FChaosSolversModule : : GetModule ( ) ;
2019-06-08 17:15:34 -04:00
checkSlow ( ChaosModule ) ;
2020-09-24 00:43:27 -04:00
auto Solver = PhysicsProxy - > GetSolver < Chaos : : FPBDRigidsSolver > ( ) ;
2021-05-12 18:10:03 -04:00
const FName Name = GetOwner ( ) ? * GetOwner ( ) - > GetName ( ) : TEXT ( " " ) ;
FFieldSystemCommand LocalCommand = InCommand ;
LocalCommand . InitFieldNodes ( Solver - > GetSolverTime ( ) , Name ) ;
Solver - > EnqueueCommandImmediate ( [ Solver , PhysicsProxy = this - > PhysicsProxy , NewCommand = LocalCommand ] ( )
2019-06-08 17:15:34 -04:00
{
// Pass through nullptr here as geom component commands can never affect other solvers
2020-09-24 00:43:27 -04:00
PhysicsProxy - > BufferCommand ( Solver , NewCommand ) ;
2019-06-08 17:15:34 -04:00
} ) ;
}
}
void UGeometryCollectionComponent : : GetInitializationCommands ( TArray < FFieldSystemCommand > & CombinedCommmands )
{
CombinedCommmands . Reset ( ) ;
2021-02-03 14:57:28 -04:00
for ( const AFieldSystemActor * FieldSystemActor : InitializationFields )
2019-06-08 17:15:34 -04:00
{
if ( FieldSystemActor ! = nullptr )
{
2021-02-03 14:57:28 -04:00
if ( FieldSystemActor - > GetFieldSystemComponent ( ) )
2019-06-08 17:15:34 -04:00
{
2021-03-10 06:11:34 -04:00
const int32 NumCommands = FieldSystemActor - > GetFieldSystemComponent ( ) - > ConstructionCommands . GetNumCommands ( ) ;
if ( NumCommands > 0 )
2019-06-08 17:15:34 -04:00
{
2021-03-10 06:11:34 -04:00
for ( int32 CommandIndex = 0 ; CommandIndex < NumCommands ; + + CommandIndex )
{
2021-08-02 07:51:15 -04:00
const FFieldSystemCommand NewCommand = FieldSystemActor - > GetFieldSystemComponent ( ) - > ConstructionCommands . BuildFieldCommand ( CommandIndex ) ;
if ( NewCommand . RootNode )
{
CombinedCommmands . Emplace ( NewCommand ) ;
}
2021-03-10 06:11:34 -04:00
}
}
// Legacy path : only there for old levels. New ones will have the commands directly stored onto the component
else if ( FieldSystemActor - > GetFieldSystemComponent ( ) - > GetFieldSystem ( ) )
{
2021-05-12 18:10:03 -04:00
const FName Name = GetOwner ( ) ? * GetOwner ( ) - > GetName ( ) : TEXT ( " " ) ;
2021-03-10 06:11:34 -04:00
for ( const FFieldSystemCommand & Command : FieldSystemActor - > GetFieldSystemComponent ( ) - > GetFieldSystem ( ) - > Commands )
{
2021-08-02 07:51:15 -04:00
if ( Command . RootNode )
2021-03-10 06:11:34 -04:00
{
2021-08-02 07:51:15 -04:00
FFieldSystemCommand NewCommand = { Command . TargetAttribute , Command . RootNode - > NewCopy ( ) } ;
NewCommand . InitFieldNodes ( 0.0 , Name ) ;
for ( const TPair < FFieldSystemMetaData : : EMetaType , TUniquePtr < FFieldSystemMetaData > > & Elem : Command . MetaData )
{
NewCommand . MetaData . Add ( Elem . Key , TUniquePtr < FFieldSystemMetaData > ( Elem . Value - > NewCopy ( ) ) ) ;
}
CombinedCommmands . Emplace ( NewCommand ) ;
2021-03-10 06:11:34 -04:00
}
}
2019-06-08 17:15:34 -04:00
}
}
}
}
}
2022-11-09 20:53:21 -05:00
bool UGeometryCollectionComponent : : GetSuppressSelectionMaterial ( ) const
{
return RestCollection - > GetGeometryCollection ( ) - > HasAttribute ( " Hide " , FGeometryCollection : : TransformGroup ) ;
}
const int UGeometryCollectionComponent : : GetBoneSelectedMaterialID ( ) const
{
return RestCollection - > GetBoneSelectedMaterialIndex ( ) ;
}
2020-03-09 13:22:54 -04:00
FPhysScene_Chaos * UGeometryCollectionComponent : : GetInnerChaosScene ( ) const
2018-12-12 11:25:29 -05:00
{
if ( ChaosSolverActor )
{
2019-11-22 05:24:36 -05:00
return ChaosSolverActor - > GetPhysicsScene ( ) . Get ( ) ;
2018-12-12 11:25:29 -05:00
}
else
{
2019-06-08 17:15:34 -04:00
if ( ensure ( GetOwner ( ) ) & & ensure ( GetOwner ( ) - > GetWorld ( ) ) )
{
2020-08-11 01:36:57 -04:00
return GetOwner ( ) - > GetWorld ( ) - > GetPhysicsScene ( ) ;
2019-06-08 17:15:34 -04:00
}
2022-06-01 06:59:18 -04:00
2019-06-08 17:15:34 -04:00
check ( GWorld ) ;
2020-08-11 01:36:57 -04:00
return GWorld - > GetPhysicsScene ( ) ;
2018-12-12 11:25:29 -05:00
}
}
2019-06-08 17:15:34 -04:00
AChaosSolverActor * UGeometryCollectionComponent : : GetPhysicsSolverActor ( ) const
{
if ( ChaosSolverActor )
{
return ChaosSolverActor ;
}
else
{
2020-03-09 13:22:54 -04:00
FPhysScene_Chaos const * const Scene = GetInnerChaosScene ( ) ;
2019-06-08 17:15:34 -04:00
return Scene ? Cast < AChaosSolverActor > ( Scene - > GetSolverActor ( ) ) : nullptr ;
}
return nullptr ;
}
void UGeometryCollectionComponent : : CalculateLocalBounds ( )
{
LocalBounds . Init ( ) ;
2022-07-06 11:17:25 -04:00
LocalBounds = ComputeBounds ( FMatrix : : Identity ) ;
2019-06-08 17:15:34 -04:00
}
void UGeometryCollectionComponent : : CalculateGlobalMatrices ( )
{
SCOPE_CYCLE_COUNTER ( STAT_GCCUGlobalMatrices ) ;
2020-08-11 01:36:57 -04:00
2019-11-20 13:24:55 -05:00
const FGeometryCollectionResults * Results = PhysicsProxy ? PhysicsProxy - > GetConsumerResultsGT ( ) : nullptr ;
2019-06-08 17:15:34 -04:00
const int32 NumTransforms = Results ? Results - > GlobalTransforms . Num ( ) : 0 ;
if ( NumTransforms > 0 )
{
// Just calc from results
2021-04-20 10:45:04 -04:00
GlobalMatrices . Reset ( ) ;
2021-02-18 13:20:03 -04:00
GlobalMatrices . Append ( Results - > GlobalTransforms ) ;
2019-06-08 17:15:34 -04:00
}
else
2021-12-02 18:57:44 -05:00
{
2021-06-16 01:29:49 -04:00
// If hierarchy topology has changed, the RestTransforms is invalidated.
if ( RestTransforms . Num ( ) ! = GetTransformArray ( ) . Num ( ) )
{
RestTransforms . Empty ( ) ;
}
2021-12-02 18:57:44 -05:00
2021-06-16 01:29:49 -04:00
if ( ! DynamicCollection & & RestTransforms . Num ( ) > 0 )
{
GeometryCollectionAlgo : : GlobalMatrices ( RestTransforms , GetParentArray ( ) , GlobalMatrices ) ;
}
else
{
// Have to fully rebuild
2021-09-15 17:18:16 -04:00
if ( DynamicCollection
& & DynamicCollection - > HasAttribute ( " UniformScale " , FGeometryCollection : : TransformGroup )
2022-05-28 00:20:07 -04:00
& & DynamicCollection - > HasAttribute ( " Decay " , FGeometryCollection : : TransformGroup ) )
2021-08-31 20:24:01 -04:00
{
2022-05-28 00:20:07 -04:00
const TManagedArray < float > & Decay = DynamicCollection - > GetAttribute < float > ( " Decay " , FGeometryCollection : : TransformGroup ) ;
2022-05-10 18:56:28 -04:00
TManagedArray < FTransform > & UniformScale = DynamicCollection - > ModifyAttribute < FTransform > ( " UniformScale " , FGeometryCollection : : TransformGroup ) ;
2021-09-15 17:18:16 -04:00
2022-05-28 00:20:07 -04:00
const FTransform InverseComponentTransform = GetComponentTransform ( ) . Inverse ( ) ;
const FTransform ZeroScaleTransform ( FQuat : : Identity , FVector : : Zero ( ) , FVector ( 0 , 0 , 0 ) ) ;
2021-08-31 20:24:01 -04:00
for ( int32 Idx = 0 ; Idx < GetTransformArray ( ) . Num ( ) ; + + Idx )
{
2022-05-28 00:20:07 -04:00
// only update values if the decay has changed
if ( Decay [ Idx ] > 0.f & & Decay [ Idx ] < = 1.f )
2021-08-31 20:24:01 -04:00
{
2022-05-28 00:20:07 -04:00
const float Scale = 1.0 - Decay [ Idx ] ;
if ( Scale < UE_SMALL_NUMBER )
{
UniformScale [ Idx ] = ZeroScaleTransform ;
}
else
2021-09-15 17:18:16 -04:00
{
float ShrinkRadius = 0.0f ;
2022-07-09 14:03:32 -04:00
UE : : Math : : TSphere < double > AccumulatedSphere ;
2022-05-28 00:20:07 -04:00
// todo(chaos) : find a faster way to do that ( precompute the data ? )
2021-09-15 17:18:16 -04:00
if ( CalculateInnerSphere ( Idx , AccumulatedSphere ) )
{
ShrinkRadius = - AccumulatedSphere . W ;
}
2022-05-28 00:20:07 -04:00
const FQuat LocalRotation = ( InverseComponentTransform * FTransform ( GlobalMatrices [ Idx ] ) . Inverse ( ) ) . GetRotation ( ) ;
const FVector LocalDown = LocalRotation . RotateVector ( FVector ( 0.f , 0.f , ShrinkRadius ) ) ;
const FVector CenterOfMass = DynamicCollection - > MassToLocal [ Idx ] . GetTranslation ( ) ;
const FVector ScaleCenter = LocalDown + CenterOfMass ;
UniformScale [ Idx ] = FTransform ( FQuat : : Identity , ScaleCenter * ( FVector : : FReal ) ( 1.f - Scale ) , FVector ( Scale ) ) ;
2021-09-15 17:18:16 -04:00
}
2021-08-31 20:24:01 -04:00
}
}
2021-09-15 17:18:16 -04:00
GeometryCollectionAlgo : : GlobalMatrices ( GetTransformArray ( ) , GetParentArray ( ) , UniformScale , GlobalMatrices ) ;
2021-08-31 20:24:01 -04:00
}
else
{
2021-12-13 15:59:48 -05:00
GeometryCollectionAlgo : : GlobalMatrices ( GetTransformArray ( ) , GetParentArray ( ) , GlobalMatrices ) ;
}
2021-06-16 01:29:49 -04:00
}
2019-06-08 17:15:34 -04:00
}
2021-06-16 01:29:49 -04:00
2019-06-08 17:15:34 -04:00
# if WITH_EDITOR
2022-07-06 11:17:25 -04:00
UpdateGlobalMatricesWithExplodedVectors ( GlobalMatrices , * ( RestCollection - > GetGeometryCollection ( ) ) ) ;
2019-06-08 17:15:34 -04:00
# endif
}
// #todo(dmp): for backwards compatibility with existing maps, we need to have a default of 3 materials. Otherwise
// some existing test scenes will crash
int32 UGeometryCollectionComponent : : GetNumMaterials ( ) const
{
return ! RestCollection | | RestCollection - > Materials . Num ( ) = = 0 ? 3 : RestCollection - > Materials . Num ( ) ;
}
UMaterialInterface * UGeometryCollectionComponent : : GetMaterial ( int32 MaterialIndex ) const
{
// If we have a base materials array, use that
if ( OverrideMaterials . IsValidIndex ( MaterialIndex ) & & OverrideMaterials [ MaterialIndex ] )
{
return OverrideMaterials [ MaterialIndex ] ;
}
// Otherwise get from geom collection
else
{
return RestCollection & & RestCollection - > Materials . IsValidIndex ( MaterialIndex ) ? RestCollection - > Materials [ MaterialIndex ] : nullptr ;
}
}
2021-09-05 20:37:59 -04:00
# if WITH_EDITOR
void UGeometryCollectionComponent : : SelectEmbeddedGeometry ( )
{
// First reset the selections
for ( TObjectPtr < UInstancedStaticMeshComponent > EmbeddedGeometryComponent : EmbeddedGeometryComponents )
{
EmbeddedGeometryComponent - > ClearInstanceSelection ( ) ;
}
const TManagedArray < int32 > & ExemplarIndex = GetExemplarIndexArray ( ) ;
for ( int32 SelectedBone : SelectedBones )
{
2021-11-07 23:43:01 -05:00
if ( EmbeddedGeometryComponents . IsValidIndex ( ExemplarIndex [ SelectedBone ] ) )
2021-09-05 20:37:59 -04:00
{
EmbeddedGeometryComponents [ ExemplarIndex [ SelectedBone ] ] - > SelectInstance ( true , EmbeddedInstanceIndex [ SelectedBone ] , 1 ) ;
}
}
}
# endif
2019-06-08 17:15:34 -04:00
// #temp HACK for demo, When fracture happens (physics state changes to dynamic) then switch the visible render meshes in a blueprint/actor from static meshes to geometry collections
void UGeometryCollectionComponent : : SwitchRenderModels ( const AActor * Actor )
{
2019-06-17 19:58:42 -04:00
// Don't touch visibility if the component is not visible
if ( ! IsVisible ( ) )
{
return ;
}
2019-09-05 15:45:24 -04:00
TInlineComponentArray < UPrimitiveComponent * > PrimitiveComponents ;
Actor - > GetComponents ( PrimitiveComponents ) ;
for ( UPrimitiveComponent * PrimitiveComponent : PrimitiveComponents )
2019-06-08 17:15:34 -04:00
{
bool ValidComponent = false ;
if ( UStaticMeshComponent * StaticMeshComp = Cast < UStaticMeshComponent > ( PrimitiveComponent ) )
{
2021-02-18 13:20:03 -04:00
// unhacked.
//StaticMeshComp->SetVisibility(false);
2019-06-08 17:15:34 -04:00
}
else if ( UGeometryCollectionComponent * GeometryCollectionComponent = Cast < UGeometryCollectionComponent > ( PrimitiveComponent ) )
{
2019-07-16 19:12:32 -04:00
if ( ! GeometryCollectionComponent - > IsVisible ( ) )
{
continue ;
}
2019-06-08 17:15:34 -04:00
GeometryCollectionComponent - > SetVisibility ( true ) ;
}
}
2019-09-05 15:45:24 -04:00
TInlineComponentArray < UChildActorComponent * > ChildActorComponents ;
Actor - > GetComponents ( ChildActorComponents ) ;
2019-06-08 17:15:34 -04:00
for ( UChildActorComponent * ChildComponent : ChildActorComponents )
{
AActor * ChildActor = ChildComponent - > GetChildActor ( ) ;
if ( ChildActor )
{
SwitchRenderModels ( ChildActor ) ;
}
}
}
# if GEOMETRYCOLLECTION_EDITOR_SELECTION
void UGeometryCollectionComponent : : EnableTransformSelectionMode ( bool bEnable )
{
2020-07-15 19:46:08 -04:00
// TODO: Support for Nanite?
if ( SceneProxy & & ! SceneProxy - > IsNaniteMesh ( ) & & RestCollection & & RestCollection - > HasVisibleGeometry ( ) )
2019-06-08 17:15:34 -04:00
{
static_cast < FGeometryCollectionSceneProxy * > ( SceneProxy ) - > UseSubSections ( bEnable , true ) ;
}
bIsTransformSelectionModeEnabled = bEnable ;
}
# endif // #if GEOMETRYCOLLECTION_EDITOR_SELECTION
2021-02-18 13:20:03 -04:00
bool UGeometryCollectionComponent : : IsEmbeddedGeometryValid ( ) const
{
// Check that the array of ISMCs that implement embedded geometry matches RestCollection Exemplar array.
if ( ! RestCollection )
{
return false ;
}
if ( RestCollection - > EmbeddedGeometryExemplar . Num ( ) ! = EmbeddedGeometryComponents . Num ( ) )
{
return false ;
}
for ( int32 Idx = 0 ; Idx < EmbeddedGeometryComponents . Num ( ) ; + + Idx )
{
UStaticMesh * ExemplarStaticMesh = Cast < UStaticMesh > ( RestCollection - > EmbeddedGeometryExemplar [ Idx ] . StaticMeshExemplar . TryLoad ( ) ) ;
if ( ! ExemplarStaticMesh )
{
return false ;
}
if ( ExemplarStaticMesh ! = EmbeddedGeometryComponents [ Idx ] - > GetStaticMesh ( ) )
{
return false ;
}
}
return true ;
}
void UGeometryCollectionComponent : : ClearEmbeddedGeometry ( )
{
2021-02-21 16:04:54 -04:00
AActor * OwningActor = GetOwner ( ) ;
2021-02-21 17:15:16 -04:00
TArray < UActorComponent * > TargetComponents ;
OwningActor - > GetComponents ( TargetComponents , false ) ;
2021-03-30 20:35:50 -04:00
for ( UActorComponent * TargetComponent : TargetComponents )
2021-02-18 13:20:03 -04:00
{
2021-09-06 12:23:53 -04:00
if ( ( TargetComponent - > GetOuter ( ) = = this ) | | ! IsValidChecked ( TargetComponent - > GetOuter ( ) ) )
2021-02-21 16:04:54 -04:00
{
2021-03-30 20:35:50 -04:00
if ( UInstancedStaticMeshComponent * ISMComponent = Cast < UInstancedStaticMeshComponent > ( TargetComponent ) )
{
ISMComponent - > ClearInstances ( ) ;
ISMComponent - > DestroyComponent ( ) ;
}
2021-02-21 16:04:54 -04:00
}
2021-02-18 13:20:03 -04:00
}
EmbeddedGeometryComponents . Empty ( ) ;
}
void UGeometryCollectionComponent : : InitializeEmbeddedGeometry ( )
{
if ( RestCollection )
{
ClearEmbeddedGeometry ( ) ;
2021-12-02 18:57:44 -05:00
2021-02-18 13:20:03 -04:00
AActor * ActorOwner = GetOwner ( ) ;
check ( ActorOwner ) ;
// Construct an InstancedStaticMeshComponent for each exemplar
for ( const FGeometryCollectionEmbeddedExemplar & Exemplar : RestCollection - > EmbeddedGeometryExemplar )
{
if ( UStaticMesh * ExemplarStaticMesh = Cast < UStaticMesh > ( Exemplar . StaticMeshExemplar . TryLoad ( ) ) )
{
2021-03-30 20:35:50 -04:00
if ( UInstancedStaticMeshComponent * ISMC = NewObject < UInstancedStaticMeshComponent > ( this ) )
2021-02-18 13:20:03 -04:00
{
ISMC - > SetStaticMesh ( ExemplarStaticMesh ) ;
ISMC - > SetCullDistances ( Exemplar . StartCullDistance , Exemplar . EndCullDistance ) ;
ISMC - > SetCanEverAffectNavigation ( false ) ;
ISMC - > SetCollisionProfileName ( UCollisionProfile : : NoCollision_ProfileName ) ;
ISMC - > SetCastShadow ( false ) ;
ISMC - > SetMobility ( EComponentMobility : : Stationary ) ;
2021-03-24 21:38:10 -04:00
ISMC - > SetupAttachment ( this ) ;
2021-06-16 01:29:49 -04:00
ActorOwner - > AddInstanceComponent ( ISMC ) ;
2021-02-18 13:20:03 -04:00
ISMC - > RegisterComponent ( ) ;
EmbeddedGeometryComponents . Add ( ISMC ) ;
}
}
}
2021-09-05 20:37:59 -04:00
# if WITH_EDITOR
EmbeddedBoneMaps . SetNum ( RestCollection - > EmbeddedGeometryExemplar . Num ( ) ) ;
EmbeddedInstanceIndex . Init ( INDEX_NONE , RestCollection - > GetGeometryCollection ( ) - > NumElements ( FGeometryCollection : : TransformGroup ) ) ;
# endif
2021-02-18 13:20:03 -04:00
}
}
2021-04-12 15:19:31 -04:00
2022-10-21 19:51:57 -04:00
bool UGeometryCollectionComponent : : CanUseISMPool ( ) const
{
return bChaos_GC_UseISMPool & & ISMPool ;
}
void UGeometryCollectionComponent : : RegisterToISMPool ( )
{
UnregisterFromISMPool ( ) ;
if ( CanUseISMPool ( ) )
{
if ( UGeometryCollectionISMPoolComponent * ISMPoolComp = ISMPool - > GetISMPoolComp ( ) )
{
bool bCanRenderComponent = true ;
if ( RestCollection )
{
2022-10-29 03:00:57 -04:00
ISMPoolMeshGroupIndex = ISMPoolComp - > CreateMeshGroup ( ) ;
2022-10-21 19:51:57 -04:00
if ( bChaos_GC_UseISMPoolForNonFracturedParts )
{
if ( RestCollection - > GetGeometryCollection ( ) )
{
// if we use ISM pool for the hierarchy we must hide the component for rendering
bCanRenderComponent = false ;
// fisrt count the instance per mesh
TArray < int32 > InstanceCounts ;
InstanceCounts . AddZeroed ( RestCollection - > AutoInstanceMeshes . Num ( ) ) ;
2022-12-02 00:40:18 -05:00
2022-10-21 19:51:57 -04:00
const TManagedArray < TSet < int32 > > & Children = RestCollection - > GetGeometryCollection ( ) - > Children ;
2022-12-02 00:40:18 -05:00
const GeometryCollection : : Facades : : FCollectionInstancedMeshFacade InstancedMeshFacade ( * RestCollection - > GetGeometryCollection ( ) ) ;
if ( InstancedMeshFacade . IsValid ( ) )
2022-10-21 19:51:57 -04:00
{
2022-12-02 00:40:18 -05:00
for ( int32 TransformIndex = 0 ; TransformIndex < InstancedMeshFacade . GetNumIndices ( ) ; TransformIndex + + )
2022-10-21 19:51:57 -04:00
{
2022-12-02 00:40:18 -05:00
const int32 AutoInstanceMeshIndex = InstancedMeshFacade . GetIndex ( TransformIndex ) ;
2022-10-21 19:51:57 -04:00
if ( Children [ TransformIndex ] . Num ( ) = = 0 )
{
InstanceCounts [ AutoInstanceMeshIndex ] + + ;
}
}
}
// now register each mesh
for ( int32 MeshIndex = 0 ; MeshIndex < RestCollection - > AutoInstanceMeshes . Num ( ) ; MeshIndex + + )
{
const FGeometryCollectionAutoInstanceMesh & AutoInstanceMesh = RestCollection - > AutoInstanceMeshes [ MeshIndex ] ;
if ( UStaticMesh * StaticMesh = Cast < UStaticMesh > ( AutoInstanceMesh . StaticMesh . TryLoad ( ) ) )
{
bool bMaterialOverride = false ;
for ( int32 MatIndex = 0 ; MatIndex < AutoInstanceMesh . Materials . Num ( ) ; MatIndex + + )
{
const UMaterialInterface * OriginalMaterial = StaticMesh - > GetMaterial ( MatIndex ) ;
if ( OriginalMaterial ! = AutoInstanceMesh . Materials [ MatIndex ] )
{
bMaterialOverride = true ;
break ;
}
}
FGeometryCollectionStaticMeshInstance StaticMeshInstance ;
StaticMeshInstance . StaticMesh = StaticMesh ;
if ( bMaterialOverride )
{
StaticMeshInstance . MaterialsOverrides = AutoInstanceMesh . Materials ;
}
ISMPoolComp - > AddMeshToGroup ( ISMPoolMeshGroupIndex , StaticMeshInstance , InstanceCounts [ MeshIndex ] ) ;
}
}
}
}
// root proxy if available
// TODO : if ISM pool is not available : uses a standard static mesh component
if ( UObject * RootMeshProxyObject = RestCollection - > RootProxy . ResolveObject ( ) )
{
if ( UStaticMesh * RootMeshProxy = Cast < UStaticMesh > ( RootMeshProxyObject ) )
{
// if we use a mesh proxy hide the component for rendering
bCanRenderComponent = false ;
FGeometryCollectionStaticMeshInstance StaticMeshInstance ;
StaticMeshInstance . StaticMesh = RootMeshProxy ;
2022-10-29 03:00:57 -04:00
ISMPoolRootProxyMeshId = ISMPoolComp - > AddMeshToGroup ( ISMPoolMeshGroupIndex , StaticMeshInstance , 1 ) ;
2022-10-21 19:51:57 -04:00
}
}
}
SetVisibility ( bCanRenderComponent ) ;
RefreshISMPoolInstances ( ) ;
}
}
}
void UGeometryCollectionComponent : : UnregisterFromISMPool ( )
{
if ( ISMPool )
{
if ( UGeometryCollectionISMPoolComponent * ISMPoolComp = ISMPool - > GetISMPoolComp ( ) )
{
ISMPoolComp - > DestroyMeshGroup ( ISMPoolMeshGroupIndex ) ;
ISMPoolMeshGroupIndex = INDEX_NONE ;
2022-10-29 03:00:57 -04:00
ISMPoolRootProxyMeshId = INDEX_NONE ;
2022-10-21 19:51:57 -04:00
}
}
SetVisibility ( true ) ;
}
void UGeometryCollectionComponent : : RefreshISMPoolInstances ( )
{
if ( CanUseISMPool ( ) )
{
if ( UGeometryCollectionISMPoolComponent * ISMPoolComp = ISMPool - > GetISMPoolComp ( ) )
{
if ( RestCollection )
{
// default to true for editor purposes?
//const bool bCollectionIsDirty = DynamicCollection ? DynamicCollection->IsDirty() : true;
if ( bChaos_GC_UseISMPoolForNonFracturedParts /*&& bCollectionIsDirty*/ )
{
if ( RestCollection - > GetGeometryCollection ( ) )
{
const TManagedArray < TSet < int32 > > & Children = RestCollection - > GetGeometryCollection ( ) - > Children ;
2022-12-02 00:40:18 -05:00
const GeometryCollection : : Facades : : FCollectionInstancedMeshFacade InstancedMeshFacade ( * RestCollection - > GetGeometryCollection ( ) ) ;
if ( InstancedMeshFacade . IsValid ( ) )
2022-10-21 19:51:57 -04:00
{
const int32 NumTransforms = RestCollection - > NumElements ( FGeometryCollection : : TransformAttribute ) ;
CalculateGlobalMatrices ( ) ;
const FTransform & ComponentTransform = GetComponentTransform ( ) ;
2022-10-29 03:00:57 -04:00
constexpr bool bWorlSpace = true ;
constexpr bool bMarkRenderStateDirty = true ;
constexpr bool bTeleport = true ;
const int32 RootIndex = GetRootIndex ( ) ;
//const bool bIsBroken = DynamicCollection ? (DynamicCollection->Children[RootIndex].Num() != Children[RootIndex].Num()) : false;
const bool bIsBroken = DynamicCollection ? ! DynamicCollection - > Active [ RootIndex ] : false ;
const bool bHasRootProxyMesh = ( ISMPoolRootProxyMeshId ! = INDEX_NONE ) ;
if ( bHasRootProxyMesh & & ! bIsBroken )
2022-10-21 19:51:57 -04:00
{
2022-10-29 03:00:57 -04:00
if ( GlobalMatrices . IsValidIndex ( RootIndex ) )
2022-10-21 19:51:57 -04:00
{
2022-10-29 03:00:57 -04:00
FTransform RootTransform = FTransform ( GlobalMatrices [ RootIndex ] ) * ComponentTransform ;
ISMPoolComp - > BatchUpdateInstancesTransforms ( ISMPoolMeshGroupIndex , ISMPoolRootProxyMeshId , 0 , { RootTransform } , bWorlSpace , bMarkRenderStateDirty , bTeleport ) ;
}
}
else if ( bChaos_GC_UseISMPoolForNonFracturedParts )
{
// make sure this mesh is invisible
// todo : should be event based instead of doing it every frame
if ( bHasRootProxyMesh & & GlobalMatrices . IsValidIndex ( RootIndex ) )
{
FTransform RootTransformZeroScale ;
RootTransformZeroScale . SetIdentityZeroScale ( ) ;
ISMPoolComp - > BatchUpdateInstancesTransforms ( ISMPoolMeshGroupIndex , ISMPoolRootProxyMeshId , 0 , { RootTransformZeroScale } , bWorlSpace , bMarkRenderStateDirty , bTeleport ) ;
}
TArray < FTransform > InstanceTransforms ;
for ( int32 MeshIndex = 0 ; MeshIndex < RestCollection - > AutoInstanceMeshes . Num ( ) ; MeshIndex + + )
{
InstanceTransforms . Reset ( NumTransforms ) ; // Allocate for worst case
for ( int32 TransformIndex = 0 ; TransformIndex < NumTransforms ; TransformIndex + + )
{
2022-12-02 00:40:18 -05:00
const int32 AutoInstanceMeshIndex = InstancedMeshFacade . GetIndex ( TransformIndex ) ;
2022-10-29 03:00:57 -04:00
if ( AutoInstanceMeshIndex = = MeshIndex & & Children [ TransformIndex ] . Num ( ) = = 0 )
{
InstanceTransforms . Add ( FTransform ( GlobalMatrices [ TransformIndex ] ) * ComponentTransform ) ;
}
}
ISMPoolComp - > BatchUpdateInstancesTransforms ( ISMPoolMeshGroupIndex , MeshIndex , 0 , InstanceTransforms , bWorlSpace , bMarkRenderStateDirty , bTeleport ) ;
2022-10-21 19:51:57 -04:00
}
}
}
}
}
}
}
}
}
2022-11-16 19:21:50 -05:00
bool UGeometryCollectionComponent : : IsRootBroken ( ) const
{
if ( DynamicCollection & & DynamicCollection - > Active . Num ( ) > 0 )
{
const int32 RootIndex = GetRootIndex ( ) ;
if ( RootIndex ! = INDEX_NONE )
{
return ! DynamicCollection - > Active [ RootIndex ] ;
}
}
return false ;
}
2022-10-21 19:51:57 -04:00
2022-07-06 15:00:45 -04:00
struct FGeometryCollectionDecayContext
{
FGeometryCollectionDecayContext ( FGeometryCollectionPhysicsProxy & PhysicsProxyIn , FGeometryCollectionDecayDynamicFacade & DecayFacadeIn )
: PhysicsProxy ( PhysicsProxyIn )
, DecayFacade ( DecayFacadeIn )
, DirtyDynamicCollection ( false )
{ }
FGeometryCollectionPhysicsProxy & PhysicsProxy ;
FGeometryCollectionDecayDynamicFacade & DecayFacade ;
bool DirtyDynamicCollection ;
TArray < int32 > ToDisable ;
TArray < FGeometryCollectionItemIndex > ToCrumble ;
void Process ( FGeometryDynamicCollection & DynamicCollection )
{
if ( DirtyDynamicCollection )
{
DynamicCollection . MakeDirty ( ) ;
}
if ( ToCrumble . Num ( ) )
{
PhysicsProxy . BreakClusters_External ( MoveTemp ( ToCrumble ) ) ;
}
if ( ToDisable . Num ( ) )
{
PhysicsProxy . DisableParticles_External ( MoveTemp ( ToDisable ) ) ;
}
}
} ;
void UGeometryCollectionComponent : : UpdateDecay ( int32 TransformIdx , float UpdatedDecay , bool bUseClusterCrumbling , bool bHasDynamicInternalClusterParent , FGeometryCollectionDecayContext & ContextInOut )
{
TManagedArray < float > & Decay = ContextInOut . DecayFacade . DecayAttribute . Modify ( ) ;
if ( UpdatedDecay > Decay [ TransformIdx ] )
{
ContextInOut . DirtyDynamicCollection = true ;
Decay [ TransformIdx ] = UpdatedDecay ;
if ( bUseClusterCrumbling )
{
if ( bHasDynamicInternalClusterParent )
{
FGeometryCollectionItemIndex InternalClusterItemindex = ContextInOut . PhysicsProxy . GetInternalClusterParentItemIndex_External ( TransformIdx ) ;
if ( InternalClusterItemindex . IsValid ( ) )
{
ContextInOut . ToCrumble . AddUnique ( InternalClusterItemindex ) ;
Decay [ TransformIdx ] = 0.0f ;
}
}
else
{
ContextInOut . ToCrumble . AddUnique ( FGeometryCollectionItemIndex : : CreateTransformItemIndex ( TransformIdx ) ) ;
Decay [ TransformIdx ] = 0.0f ;
}
}
else if ( Decay [ TransformIdx ] > = 1.0f )
{
// Disable the particle if it has decayed the requisite time
Decay [ TransformIdx ] = 1.0f ;
ContextInOut . ToDisable . Add ( TransformIdx ) ;
}
}
}
2021-08-31 20:24:01 -04:00
void UGeometryCollectionComponent : : IncrementSleepTimer ( float DeltaTime )
{
2022-06-21 22:08:04 -04:00
if ( DeltaTime < = 0 | | ! RestCollection - > bRemoveOnMaxSleep | | ! bAllowRemovalOnSleep )
2022-05-28 00:20:07 -04:00
{
return ;
}
2021-08-31 20:24:01 -04:00
// If a particle is sleeping, increment its sleep timer, otherwise reset it.
2022-07-06 15:00:45 -04:00
if ( DynamicCollection & & PhysicsProxy )
2021-08-31 20:24:01 -04:00
{
2022-07-06 15:00:45 -04:00
FGeometryCollectionRemoveOnSleepDynamicFacade RemoveOnSleepFacade ( * DynamicCollection ) ;
FGeometryCollectionDecayDynamicFacade DecayFacade ( * DynamicCollection ) ;
FGeometryCollectionDynamicStateFacade DynamicStateFacade ( * DynamicCollection ) ;
if ( RemoveOnSleepFacade . IsValid ( )
& & DecayFacade . IsValid ( )
& & DynamicStateFacade . IsValid ( ) )
2021-08-31 20:24:01 -04:00
{
2022-07-06 15:00:45 -04:00
FGeometryCollectionDecayContext DecayContext ( * PhysicsProxy , DecayFacade ) ;
2022-09-06 21:29:52 -04:00
const TManagedArray < int32 > & OriginalParents = RestCollection - > GetGeometryCollection ( ) - > Parent ;
2022-07-06 15:00:45 -04:00
TManagedArray < float > & Decay = DecayFacade . DecayAttribute . Modify ( ) ;
for ( int32 TransformIdx = 0 ; TransformIdx < Decay . Num ( ) ; + + TransformIdx )
{
2022-09-06 21:29:52 -04:00
const bool HasInternalClusterParent = DynamicStateFacade . HasInternalClusterParent ( TransformIdx ) ;
if ( HasInternalClusterParent )
2022-05-28 00:20:07 -04:00
{
2022-09-06 21:29:52 -04:00
// this children has an dynamic internal cluster parent so it can't be removed but we need tyo process the internal cluster by looking at the original parent properties
const int32 OriginalParentIdx = OriginalParents [ TransformIdx ] ;
const bool HasDynamicInternalClusterParent = DynamicStateFacade . HasDynamicInternalClusterParent ( TransformIdx ) ;
if ( OriginalParentIdx > INDEX_NONE & & HasDynamicInternalClusterParent & & RemoveOnSleepFacade . IsRemovalActive ( OriginalParentIdx ) )
2022-05-28 00:20:07 -04:00
{
2022-09-06 21:29:52 -04:00
const bool UseClusterCrumbling = true ; // with sleep removal : internal clusters always crumble - this will change when we merge the removal feature together
const float UpdatedBreakDecay = UE_SMALL_NUMBER ; // since we crumble we can only pass a timy number since this will be ignore ( but need to be >0 to ake sure Update Decay works properly )
UpdateDecay ( TransformIdx , UpdatedBreakDecay , UseClusterCrumbling , HasDynamicInternalClusterParent , DecayContext ) ;
2022-05-28 00:20:07 -04:00
}
2022-09-06 21:29:52 -04:00
}
else if ( RemoveOnSleepFacade . IsRemovalActive ( TransformIdx ) & & DynamicStateFacade . HasBrokenOff ( TransformIdx ) )
{
// root bone should not be affected by remove on sleep
if ( OriginalParents [ TransformIdx ] > INDEX_NONE )
2021-08-31 20:24:01 -04:00
{
2022-09-06 21:29:52 -04:00
// if decay has started we do not need to check slow moving or sleeping state anymore
bool ShouldUpdateTimer = ( Decay [ TransformIdx ] > 0 ) ;
if ( ! ShouldUpdateTimer & & RestCollection - > bSlowMovingAsSleeping )
{
const FVector CurrentPosition = DynamicCollection - > Transform [ TransformIdx ] . GetTranslation ( ) ;
ShouldUpdateTimer | = RemoveOnSleepFacade . ComputeSlowMovingState ( TransformIdx , CurrentPosition , DeltaTime , RestCollection - > SlowMovingVelocityThreshold ) ;
}
if ( ShouldUpdateTimer | | DynamicStateFacade . IsSleeping ( TransformIdx ) )
{
RemoveOnSleepFacade . UpdateSleepTimer ( TransformIdx , DeltaTime ) ;
}
// update the decay and disable the particle when decay has completed
const float UpdatedDecay = RemoveOnSleepFacade . ComputeDecay ( TransformIdx ) ;
UpdateDecay ( TransformIdx , UpdatedDecay , DynamicStateFacade . HasChildren ( TransformIdx ) , false , DecayContext ) ;
2021-08-31 20:24:01 -04:00
}
}
}
2022-07-06 15:00:45 -04:00
DecayContext . Process ( * DynamicCollection ) ;
2021-08-31 20:24:01 -04:00
}
}
}
2022-06-09 15:31:24 -04:00
void UGeometryCollectionComponent : : IncrementBreakTimer ( float DeltaTime )
{
2022-06-21 22:08:04 -04:00
if ( DeltaTime < = 0 | | ! bAllowRemovalOnBreak )
2022-06-09 15:31:24 -04:00
{
return ;
}
2022-08-30 21:32:37 -04:00
if ( RestCollection & & DynamicCollection & & PhysicsProxy )
2022-06-09 15:31:24 -04:00
{
2022-07-06 15:00:45 -04:00
FGeometryCollectionRemoveOnBreakDynamicFacade RemoveOnBreakFacade ( * DynamicCollection ) ;
FGeometryCollectionDecayDynamicFacade DecayFacade ( * DynamicCollection ) ;
FGeometryCollectionDynamicStateFacade DynamicStateFacade ( * DynamicCollection ) ;
2022-06-09 15:31:24 -04:00
2022-09-14 13:58:55 -04:00
// if replication is on, client may not need to process this at all or only partially ( depending on the abandon cluster level )
const bool bIsReplicatedClient = GetIsReplicated ( ) & & PhysicsProxy - > GetReplicationMode ( ) = = FGeometryCollectionPhysicsProxy : : EReplicationMode : : Client ;
2022-07-06 15:00:45 -04:00
if ( RemoveOnBreakFacade . IsValid ( )
& & DecayFacade . IsValid ( )
& & DynamicStateFacade . IsValid ( ) )
{
FGeometryCollectionDecayContext DecayContext ( * PhysicsProxy , DecayFacade ) ;
2022-08-30 21:32:37 -04:00
const TManagedArray < int32 > & OriginalParents = RestCollection - > GetGeometryCollection ( ) - > Parent ;
2022-09-14 13:58:55 -04:00
const TManagedArray < int32 > * InitialLevels = PhysicsProxy - > GetPhysicsCollection ( ) . FindAttribute < int32 > ( " InitialLevel " , FGeometryCollection : : TransformGroup ) ;
2022-07-06 15:00:45 -04:00
TManagedArray < float > & Decay = DecayFacade . DecayAttribute . Modify ( ) ;
for ( int32 TransformIdx = 0 ; TransformIdx < Decay . Num ( ) ; + + TransformIdx )
{
2022-09-06 21:29:52 -04:00
const bool HasInternalClusterParent = DynamicStateFacade . HasInternalClusterParent ( TransformIdx ) ;
if ( HasInternalClusterParent )
2022-07-06 15:00:45 -04:00
{
2022-09-06 21:29:52 -04:00
// this children has an internal cluster parent so it can't be removed but we need tyo process the internal cluster by looking at the original parent properties
const int32 OriginalParentIdx = OriginalParents [ TransformIdx ] ;
const bool HasDynamicInternalClusterParent = DynamicStateFacade . HasDynamicInternalClusterParent ( TransformIdx ) ;
if ( OriginalParentIdx > INDEX_NONE & & HasDynamicInternalClusterParent & & RemoveOnBreakFacade . IsRemovalActive ( OriginalParentIdx ) )
2022-06-09 15:31:24 -04:00
{
2022-09-14 13:58:55 -04:00
bool bIsAllowedClusterCrumbling = true ;
2022-10-07 19:45:55 -04:00
if ( bIsReplicatedClient & & InitialLevels & & ( InitialLevels - > Num ( ) > 0 ) )
2022-09-14 13:58:55 -04:00
{
if ( ! bEnableAbandonAfterLevel | | ( * InitialLevels ) [ OriginalParentIdx ] < = ReplicationAbandonAfterLevel )
{
bIsAllowedClusterCrumbling = false ;
}
}
2022-09-06 21:29:52 -04:00
const bool UseClusterCrumbling = RemoveOnBreakFacade . UseClusterCrumbling ( OriginalParentIdx ) ;
2022-09-14 13:58:55 -04:00
if ( ! UseClusterCrumbling | | bIsAllowedClusterCrumbling )
{
const float UpdatedBreakDecay = RemoveOnBreakFacade . UpdateBreakTimerAndComputeDecay ( TransformIdx , DeltaTime ) ;
UpdateDecay ( TransformIdx , UpdatedBreakDecay , UseClusterCrumbling , HasDynamicInternalClusterParent , DecayContext ) ;
}
2022-06-09 15:31:24 -04:00
}
2022-09-06 21:29:52 -04:00
}
else if ( RemoveOnBreakFacade . IsRemovalActive ( TransformIdx ) & & DynamicStateFacade . HasBrokenOff ( TransformIdx ) )
{
2022-09-14 13:58:55 -04:00
bool bIsAllowedClusterCrumbling = true ;
2022-10-07 19:45:55 -04:00
if ( bIsReplicatedClient & & InitialLevels & & ( InitialLevels - > Num ( ) > 0 ) )
2022-09-14 13:58:55 -04:00
{
if ( ! bEnableAbandonAfterLevel | | ( * InitialLevels ) [ TransformIdx ] < = ReplicationAbandonAfterLevel )
{
bIsAllowedClusterCrumbling = false ;
}
}
2022-09-06 21:29:52 -04:00
const bool UseClusterCrumbling = RemoveOnBreakFacade . UseClusterCrumbling ( TransformIdx ) ;
2022-09-14 13:58:55 -04:00
if ( ! UseClusterCrumbling | | bIsAllowedClusterCrumbling )
{
const float UpdatedBreakDecay = RemoveOnBreakFacade . UpdateBreakTimerAndComputeDecay ( TransformIdx , DeltaTime ) ;
UpdateDecay ( TransformIdx , UpdatedBreakDecay , UseClusterCrumbling , false , DecayContext ) ;
}
2022-06-09 15:31:24 -04:00
}
}
2022-07-06 15:00:45 -04:00
DecayContext . Process ( * DynamicCollection ) ;
2022-06-09 15:31:24 -04:00
}
}
}
2022-07-06 21:50:26 -04:00
void UGeometryCollectionComponent : : ApplyExternalStrain ( int32 ItemIndex , const FVector & Location , float Radius , int32 PropagationDepth , float PropagationFactor , float Strain )
2022-06-21 20:12:20 -04:00
{
2022-07-01 13:54:00 -04:00
if ( PhysicsProxy )
2022-06-21 20:12:20 -04:00
{
2022-07-06 21:50:26 -04:00
PhysicsProxy - > ApplyExternalStrain_External ( FGeometryCollectionItemIndex : : CreateFromExistingItemIndex ( ItemIndex ) , Location , Radius , PropagationDepth , PropagationFactor , Strain ) ;
}
}
void UGeometryCollectionComponent : : ApplyInternalStrain ( int32 ItemIndex , const FVector & Location , float Radius , int32 PropagationDepth , float PropagationFactor , float Strain )
{
if ( PhysicsProxy )
{
PhysicsProxy - > ApplyInternalStrain_External ( FGeometryCollectionItemIndex : : CreateFromExistingItemIndex ( ItemIndex ) , Location , Radius , PropagationDepth , PropagationFactor , Strain ) ;
2022-06-21 20:12:20 -04:00
}
}
2022-07-01 13:54:00 -04:00
void UGeometryCollectionComponent : : CrumbleCluster ( int32 ItemIndex )
2022-06-21 20:12:20 -04:00
{
2022-07-01 13:54:00 -04:00
if ( PhysicsProxy )
2022-06-21 20:12:20 -04:00
{
2022-07-01 13:54:00 -04:00
PhysicsProxy - > BreakClusters_External ( { FGeometryCollectionItemIndex : : CreateFromExistingItemIndex ( ItemIndex ) } ) ;
2022-06-21 20:12:20 -04:00
}
}
2022-06-09 15:31:24 -04:00
2022-09-24 13:28:05 -04:00
void UGeometryCollectionComponent : : CrumbleActiveClusters ( )
{
if ( PhysicsProxy )
{
PhysicsProxy - > BreakActiveClusters_External ( ) ;
}
}
2022-11-03 13:56:42 -04:00
void UGeometryCollectionComponent : : SetAnchoredByIndex ( int32 Index , bool bAnchored )
2022-11-02 11:47:15 -04:00
{
if ( PhysicsProxy )
{
2022-11-03 13:56:42 -04:00
PhysicsProxy - > SetAnchoredByIndex_External ( Index , bAnchored ) ;
2022-11-02 11:47:15 -04:00
}
}
2022-11-03 13:56:42 -04:00
void UGeometryCollectionComponent : : SetAnchoredByBox ( FBox WorldSpaceBox , bool bAnchored )
2022-11-02 11:47:15 -04:00
{
2022-11-11 14:11:40 -05:00
SetAnchoredByTransformedBox ( WorldSpaceBox , FTransform : : Identity , bAnchored ) ;
2022-11-02 11:47:15 -04:00
}
2022-11-11 14:11:40 -05:00
void UGeometryCollectionComponent : : SetAnchoredByTransformedBox ( FBox Box , FTransform Transform , bool bAnchored )
{
if ( PhysicsProxy )
{
PhysicsProxy - > SetAnchoredByTransformedBox_External ( Box , Transform , bAnchored ) ;
}
}
2022-09-24 13:28:05 -04:00
void UGeometryCollectionComponent : : RemoveAllAnchors ( )
{
if ( PhysicsProxy )
{
PhysicsProxy - > RemoveAllAnchors_External ( ) ;
}
}
2022-07-04 16:46:24 -04:00
void UGeometryCollectionComponent : : ApplyBreakingLinearVelocity ( int32 ItemIndex , const FVector & LinearVelocity )
{
if ( PhysicsProxy )
{
PhysicsProxy - > ApplyBreakingLinearVelocity_External ( FGeometryCollectionItemIndex : : CreateFromExistingItemIndex ( ItemIndex ) , LinearVelocity ) ;
}
}
void UGeometryCollectionComponent : : ApplyBreakingAngularVelocity ( int32 ItemIndex , const FVector & AngularVelocity )
{
if ( PhysicsProxy )
{
PhysicsProxy - > ApplyBreakingLinearVelocity_External ( FGeometryCollectionItemIndex : : CreateFromExistingItemIndex ( ItemIndex ) , AngularVelocity ) ;
}
}
void UGeometryCollectionComponent : : ApplyLinearVelocity ( int32 ItemIndex , const FVector & LinearVelocity )
{
if ( PhysicsProxy )
{
PhysicsProxy - > ApplyLinearVelocity_External ( FGeometryCollectionItemIndex : : CreateFromExistingItemIndex ( ItemIndex ) , LinearVelocity ) ;
}
}
void UGeometryCollectionComponent : : ApplyAngularVelocity ( int32 ItemIndex , const FVector & AngularVelocity )
{
if ( PhysicsProxy )
{
PhysicsProxy - > ApplyAngularVelocity_External ( FGeometryCollectionItemIndex : : CreateFromExistingItemIndex ( ItemIndex ) , AngularVelocity ) ;
}
}
int32 UGeometryCollectionComponent : : GetInitialLevel ( int32 ItemIndex )
{
using FGeometryCollectionPtr = const TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > ;
int32 Level = INDEX_NONE ;
if ( RestCollection & & RestCollection - > GetGeometryCollection ( ) )
{
const TManagedArray < int32 > & Parent = RestCollection - > GetGeometryCollection ( ) - > Parent ;
int32 TransformIndex = INDEX_NONE ;
FGeometryCollectionItemIndex GCItemIndex = FGeometryCollectionItemIndex : : CreateFromExistingItemIndex ( ItemIndex ) ;
if ( GCItemIndex . IsInternalCluster ( ) )
{
if ( const TArray < int32 > * Children = PhysicsProxy - > FindInternalClusterChildrenTransformIndices_External ( GCItemIndex ) )
{
if ( ! Children - > IsEmpty ( ) )
{
// find the original cluster index from first children
TransformIndex = Parent [ ( * Children ) [ 0 ] ] ;
}
}
}
else
{
TransformIndex = GCItemIndex . GetTransformIndex ( ) ;
}
// @todo(chaos) : use "Level" attribute when it will be properly serialized
// for now climb back the hierarchy
if ( TransformIndex > INDEX_NONE )
{
Level = 0 ;
int32 ParentTransformIndex = Parent [ TransformIndex ] ;
while ( ParentTransformIndex ! = INDEX_NONE )
{
+ + Level ;
ParentTransformIndex = Parent [ ParentTransformIndex ] ;
}
}
}
return Level ;
}
2022-11-16 19:21:50 -05:00
int32 UGeometryCollectionComponent : : GetRootIndex ( ) const
2022-10-29 03:00:57 -04:00
{
if ( RestCollection & & RestCollection - > GetGeometryCollection ( ) )
{
Chaos : : Facades : : FCollectionHierarchyFacade HierarchyFacade ( * RestCollection - > GetGeometryCollection ( ) ) ;
return HierarchyFacade . GetRootIndex ( ) ;
}
return INDEX_NONE ;
}
2022-10-04 19:02:56 -04:00
void UGeometryCollectionComponent : : GetMassAndExtents ( int32 ItemIndex , float & OutMass , FBox & OutExtents )
{
using FGeometryCollectionPtr = const TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > ;
OutMass = 0.0f ;
OutExtents = FBox ( EForceInit : : ForceInitToZero ) ;
int32 Level = INDEX_NONE ;
if ( RestCollection & & RestCollection - > GetGeometryCollection ( ) )
{
const FGeometryCollection & Collection = * RestCollection - > GetGeometryCollection ( ) ;
if ( const TManagedArray < float > * CollectionMass = Collection . FindAttribute < float > ( TEXT ( " Mass " ) , FTransformCollection : : TransformGroup ) )
{
const TManagedArray < FBox > * TransformBoundingBoxes = Collection . FindAttribute < FBox > ( TEXT ( " BoundingBox " ) , FTransformCollection : : TransformGroup ) ;
const TManagedArray < FBox > * GeoBoundingBoxes = Collection . FindAttribute < FBox > ( TEXT ( " BoundingBox " ) , FGeometryCollection : : GeometryGroup ) ;
int32 TransformIndex = INDEX_NONE ;
FGeometryCollectionItemIndex GCItemIndex = FGeometryCollectionItemIndex : : CreateFromExistingItemIndex ( ItemIndex ) ;
if ( GCItemIndex . IsInternalCluster ( ) )
{
const TArray < int32 > * Children = PhysicsProxy - > FindInternalClusterChildrenTransformIndices_External ( GCItemIndex ) ;
if ( Children )
{
for ( const int32 ChildTramsformIndex : * Children )
{
OutMass + = ( * CollectionMass ) [ ChildTramsformIndex ] ;
if ( TransformBoundingBoxes )
{
OutExtents + = ( * TransformBoundingBoxes ) [ ChildTramsformIndex ] ;
}
else if ( GeoBoundingBoxes )
{
OutExtents + = ( * GeoBoundingBoxes ) [ Collection . TransformToGeometryIndex [ ChildTramsformIndex ] ] ;
}
}
}
}
else
{
TransformIndex = GCItemIndex . GetTransformIndex ( ) ;
OutMass = ( * CollectionMass ) [ TransformIndex ] ;
if ( TransformBoundingBoxes )
{
OutExtents = ( * TransformBoundingBoxes ) [ TransformIndex ] ;
}
else
{
OutExtents = ( * GeoBoundingBoxes ) [ Collection . TransformToGeometryIndex [ TransformIndex ] ] ;
}
}
}
}
}
2022-07-09 14:03:32 -04:00
bool UGeometryCollectionComponent : : CalculateInnerSphere ( int32 TransformIndex , UE : : Math : : TSphere < double > & SphereOut ) const
2021-09-15 17:18:16 -04:00
{
// Approximates the inscribed sphere. Returns false if no such sphere exists, if for instance the index is to an embedded geometry.
const TManagedArray < int32 > & TransformToGeometryIndex = RestCollection - > GetGeometryCollection ( ) - > TransformToGeometryIndex ;
const TManagedArray < Chaos : : FRealSingle > & InnerRadius = RestCollection - > GetGeometryCollection ( ) - > InnerRadius ;
const TManagedArray < TSet < int32 > > & Children = RestCollection - > GetGeometryCollection ( ) - > Children ;
const TManagedArray < FTransform > & MassToLocal = RestCollection - > GetGeometryCollection ( ) - > GetAttribute < FTransform > ( " MassToLocal " , FGeometryCollection : : TransformGroup ) ;
if ( RestCollection - > GetGeometryCollection ( ) - > IsRigid ( TransformIndex ) )
{
// Sphere in component space, centered on body's COM.
FVector COM = MassToLocal [ TransformIndex ] . GetLocation ( ) ;
2022-07-09 14:03:32 -04:00
SphereOut = UE : : Math : : TSphere < double > ( COM , InnerRadius [ TransformToGeometryIndex [ TransformIndex ] ] ) ;
2021-09-15 17:18:16 -04:00
return true ;
}
else if ( RestCollection - > GetGeometryCollection ( ) - > IsClustered ( TransformIndex ) )
{
// Recursively accumulate the cluster's child spheres.
bool bSphereFound = false ;
for ( int32 ChildIndex : Children [ TransformIndex ] )
{
2022-07-09 14:03:32 -04:00
UE : : Math : : TSphere < double > LocalSphere ;
2021-09-15 17:18:16 -04:00
if ( CalculateInnerSphere ( ChildIndex , LocalSphere ) )
{
if ( ! bSphereFound )
{
bSphereFound = true ;
SphereOut = LocalSphere ;
}
else
{
SphereOut + = LocalSphere ;
}
}
}
return bSphereFound ;
}
else
{
// Likely an embedded geometry, which doesn't count towards volume.
return false ;
}
2022-02-07 16:26:46 -05:00
}
void UGeometryCollectionComponent : : PostLoad ( )
{
Super : : PostLoad ( ) ;
//
// The UGeometryCollectionComponent::PhysicalMaterial_DEPRECATED needs
// to be transferred to the BodyInstance simple material. Going forward
// the deprecated value will not be saved.
//
if ( PhysicalMaterialOverride_DEPRECATED )
{
BodyInstance . SetPhysMaterialOverride ( PhysicalMaterialOverride_DEPRECATED . Get ( ) ) ;
PhysicalMaterialOverride_DEPRECATED = nullptr ;
}
2022-07-12 17:47:42 -04:00
}
2022-09-24 13:57:58 -04:00
2022-12-07 15:41:26 -05:00
Chaos : : FPhysicsObject * UGeometryCollectionComponent : : GetPhysicsObjectById ( int32 Id ) const
{
if ( ! PhysicsProxy )
{
return nullptr ;
}
return PhysicsProxy - > GetPhysicsObjectByIndex ( Id ) ;
}
Chaos : : FPhysicsObject * UGeometryCollectionComponent : : GetPhysicsObjectByName ( const FName & Name ) const
{
if ( ! RestCollection )
{
return nullptr ;
}
2022-12-14 15:51:16 -05:00
if ( Name = = NAME_None )
{
// Special case where it's more convenient for us to return the root bone instead.
TArray < int32 > Roots ;
FGeometryCollectionClusteringUtility : : GetRootBones ( RestCollection - > GetGeometryCollection ( ) . Get ( ) , Roots ) ;
if ( Roots . IsEmpty ( ) )
{
return nullptr ;
}
// More convenient just to assume there's one root for this special case here.
return GetPhysicsObjectById ( Roots [ 0 ] ) ;
}
2022-12-07 15:41:26 -05:00
const int32 Index = RestCollection - > GetGeometryCollection ( ) - > BoneName . Find ( Name . ToString ( ) ) ;
return GetPhysicsObjectById ( Index ) ;
}
TArray < Chaos : : FPhysicsObject * > UGeometryCollectionComponent : : GetAllPhysicsObjects ( ) const
{
if ( ! PhysicsProxy )
{
return { } ;
}
TArray < Chaos : : FPhysicsObject * > Objects ;
Objects . Reserve ( PhysicsProxy - > GetNumParticles ( ) ) ;
for ( int32 Index = 0 ; Index < PhysicsProxy - > GetNumParticles ( ) ; + + Index )
{
Objects . Add ( GetPhysicsObjectById ( Index ) ) ;
}
return Objects ;
}