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"
# include "Async/ParallelFor.h"
# include "Components/BoxComponent.h"
2020-07-15 03:39:13 -04:00
# include "ComponentRecreateRenderStateContext.h"
2018-12-12 11:25:29 -05:00
# include "GeometryCollection/GeometryCollectionObject.h"
# include "GeometryCollection/GeometryCollectionAlgo.h"
# include "GeometryCollection/GeometryCollectionComponentPluginPrivate.h"
# include "GeometryCollection/GeometryCollectionSceneProxy.h"
# include "GeometryCollection/GeometryCollectionSQAccelerator.h"
# include "GeometryCollection/GeometryCollectionUtility.h"
# include "GeometryCollection/GeometryCollectionClusteringUtility.h"
2021-08-31 20:24:01 -04:00
# include "GeometryCollection/GeometryCollectionProximityUtility.h"
2018-12-12 11:25:29 -05:00
# include "GeometryCollection/GeometryCollectionCache.h"
2019-06-08 17:15:34 -04:00
# include "GeometryCollection/GeometryCollectionActor.h"
# include "GeometryCollection/GeometryCollectionDebugDrawComponent.h"
2018-12-12 11:25:29 -05:00
# include "Physics/Experimental/PhysScene_Chaos.h"
# include "Modules/ModuleManager.h"
# include "ChaosSolversModule.h"
# include "ChaosStats.h"
2019-08-02 09:01:58 -04:00
# include "PhysicsProxy/GeometryCollectionPhysicsProxy.h"
# include "PhysicsSolver.h"
2020-03-09 13:22:54 -04:00
# include "Physics/PhysicsFiltering.h"
2020-08-11 01:36:57 -04:00
# include "Chaos/ChaosPhysicalMaterial.h"
2020-04-30 07:34:59 -04:00
# include "AI/NavigationSystemHelpers.h"
2020-09-01 14:07:48 -04:00
# include "Net/UnrealNetwork.h"
# include "Net/Core/PushModel/PushModel.h"
2020-09-24 00:43:27 -04:00
# include "PhysicalMaterials/PhysicalMaterial.h"
2021-05-12 18:10:03 -04:00
# include "PhysicsField/PhysicsFieldComponent.h"
2021-02-18 13:20:03 -04:00
# include "Engine/InstancedStaticMesh.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"
2020-07-15 03:39:13 -04:00
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
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 ;
}
2019-10-02 17:27:26 -04:00
# if WITH_PHYSX && !WITH_CHAOS_NEEDS_TO_BE_FIXED
2018-12-12 11:25:29 -05:00
FGeometryCollectionSQAccelerator GlobalGeomCollectionAccelerator ; //todo(ocohen): proper lifetime management needed
void HackRegisterGeomAccelerator ( UGeometryCollectionComponent & Component )
{
2019-08-02 09:01:58 -04:00
# if TODO_REIMPLEMENT_SCENEQUERY_CROSSENGINE
2018-12-12 11:25:29 -05:00
if ( UWorld * World = Component . GetWorld ( ) )
{
if ( FPhysScene * PhysScene = World - > GetPhysicsScene ( ) )
{
2019-06-08 17:15:34 -04:00
if ( FSQAcceleratorUnion * SQAccelerationUnion = PhysScene - > GetSQAcceleratorUnion ( ) )
{
SQAccelerationUnion - > AddSQAccelerator ( & GlobalGeomCollectionAccelerator ) ;
}
2018-12-12 11:25:29 -05:00
}
}
2019-08-02 09:01:58 -04:00
# endif
2018-12-12 11:25:29 -05:00
}
# endif
2020-09-01 14:07:48 -04:00
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 ;
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 ;
Ar < < Cluster . ObjectState ;
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 )
{
}
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 )
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-03-01 14:33:59 -05:00
, bStoreVelocities ( false )
2021-03-18 20:04:04 -04:00
, bShowBoneColors ( false )
2020-09-01 14:07:48 -04:00
, bEnableReplication ( false )
2022-04-25 13:09:18 -04:00
, bEnableAbandonAfterLevel ( true )
2020-09-01 14:07:48 -04:00
, ReplicationAbandonClusterLevel ( 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 ;
WorldBounds = FBoxSphereBounds ( FBox ( ForceInit ) ) ;
// 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
2018-12-12 11:25:29 -05:00
}
2019-08-02 09:01:58 -04:00
Chaos : : FPhysicsSolver * GetSolver ( const UGeometryCollectionComponent & GeometryCollectionComponent )
2018-12-12 11:25:29 -05:00
{
2019-10-02 17:27:26 -04:00
# if INCLUDE_CHAOS
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 ( ) ;
}
}
2018-12-12 11:25:29 -05:00
# endif
2020-09-01 14:07:48 -04:00
return nullptr ;
2019-10-02 17:27:26 -04:00
}
2018-12-12 11:25:29 -05:00
void UGeometryCollectionComponent : : BeginPlay ( )
{
Super : : BeginPlay ( ) ;
2019-06-08 17:15:34 -04:00
# if WITH_PHYSX && !WITH_CHAOS_NEEDS_TO_BE_FIXED
2018-12-12 11:25:29 -05:00
HackRegisterGeomAccelerator ( * this ) ;
# endif
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
//////////////////////////////////////////////////////////////////////////
// Commenting out these callbacks for now due to the threading model. The callbacks here
// expect the rest collection to be mutable which is not the case when running in multiple
// threads. Ideally we have some separate animation collection or track that we cache to
// without affecting the data we've dispatched to the physics thread
//////////////////////////////////////////////////////////////////////////
// ---------- SolverCallbacks->SetResetAnimationCacheFunction([&]()
// ---------- {
// ---------- FGeometryCollectionEdit Edit = EditRestCollection();
// ---------- Edit.GetRestCollection()->RecordedData.SetNum(0);
// ---------- });
// ---------- SolverCallbacks->SetUpdateTransformsFunction([&](const TArrayView<FTransform>&)
// ---------- {
// ---------- // todo : Move the update to the array passed here...
// ---------- });
// ----------
// ---------- SolverCallbacks->SetUpdateRestStateFunction([&](const int32 & CurrentFrame, const TManagedArray<int32> & RigidBodyID, const TManagedArray<FGeometryCollectionBoneNode>& Hierarchy, const FSolverCallbacks::FParticlesType& Particles)
// ---------- {
// ---------- FGeometryCollectionEdit Edit = EditRestCollection();
// ---------- UGeometryCollection * RestCollection = Edit.GetRestCollection();
// ---------- check(RestCollection);
// ----------
// ---------- if (CurrentFrame >= RestCollection->RecordedData.Num())
// ---------- {
// ---------- RestCollection->RecordedData.SetNum(CurrentFrame + 1);
// ---------- RestCollection->RecordedData[CurrentFrame].SetNum(RigidBodyID.Num());
// ---------- ParallelFor(RigidBodyID.Num(), [&](int32 i)
// ---------- {
// ---------- if (!Hierarchy[i].Children.Num())
// ---------- {
// ---------- RestCollection->RecordedData[CurrentFrame][i].SetTranslation(Particles.X(RigidBodyID[i]));
// ---------- RestCollection->RecordedData[CurrentFrame][i].SetRotation(Particles.R(RigidBodyID[i]));
// ---------- }
// ---------- else
// ---------- {
// ---------- RestCollection->RecordedData[CurrentFrame][i].SetTranslation(FVector::ZeroVector);
// ---------- RestCollection->RecordedData[CurrentFrame][i].SetRotation(FQuat::Identity);
// ---------- }
// ---------- });
// ---------- }
// ---------- });
//////////////////////////////////////////////////////////////////////////
// default current cache time
2021-12-02 18:57:44 -05:00
CurrentCacheTime = MAX_flt ;
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
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
}
2018-12-12 11:25:29 -05:00
FBoxSphereBounds UGeometryCollectionComponent : : CalcBounds ( const FTransform & LocalToWorldIn ) const
2019-06-08 17:15:34 -04:00
{
SCOPE_CYCLE_COUNTER ( STAT_GCCUpdateBounds ) ;
2020-02-19 17:10:11 -05:00
// #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 ( ! CachePlayback & & WorldBounds . GetSphere ( ) . W > 1e-5 & & NumTransforms > 0 )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
return WorldBounds ;
}
2021-04-01 10:41:00 -04:00
else if ( RestCollection )
2019-06-08 17:15:34 -04:00
{
const FMatrix LocalToWorldWithScale = LocalToWorldIn . ToMatrixWithScale ( ) ;
2018-12-12 11:25:29 -05:00
FBox BoundingBox ( ForceInit ) ;
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
{
2019-06-08 17:15:34 -04:00
return FBoxSphereBounds ( ForceInitToZero ) ;
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
for ( int32 BoxIdx = 0 ; BoxIdx < NumBoxes ; + + BoxIdx )
{
const int32 TransformIndex = TransformIndices [ BoxIdx ] ;
if ( RestCollection - > GetGeometryCollection ( ) - > IsGeometry ( TransformIndex ) )
{
BoundingBox + = BoundingBoxes [ BoxIdx ] . TransformBy ( TmpGlobalMatrices [ TransformIndex ] * LocalToWorldWithScale ) ;
}
}
}
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
}
return FBoxSphereBounds ( BoundingBox ) ;
}
return FBoxSphereBounds ( ForceInitToZero ) ;
}
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 ( ) ;
}
}
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 )
{
Super : : SetSimulatePhysics ( bEnabled ) ;
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-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 ) ;
}
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 ) ;
}
}
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 ( )
{
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
const int32 ExemplarCount = EmbeddedGeometryComponents . Num ( ) ;
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 )
{
EmbeddedGeometryComponent - > bSelectable = bSelectable ;
EmbeddedGeometryComponent - > bHasPerInstanceHitProxies = bSelectable ;
}
}
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
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
}
}
2020-09-01 14:07:48 -04:00
AActor * Owner = GetOwner ( ) ;
if ( ! Owner )
{
return ;
}
const ENetRole LocalRole = Owner - > GetLocalRole ( ) ;
const ENetMode NetMode = Owner - > GetNetMode ( ) ;
// 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
2022-04-25 13:09:18 -04:00
if ( GetIsReplicated ( ) )
2020-09-01 14:07:48 -04:00
{
2022-04-25 13:09:18 -04:00
if ( LocalRole ! = ENetRole : : ROLE_Authority )
2020-09-01 14:07:48 -04:00
{
2022-03-01 14:33:59 -05:00
2020-09-01 14:07:48 -04:00
// We're a replicated component and we're not in control.
Chaos : : FPhysicsSolver * CurrSolver = GetSolver ( * this ) ;
if ( CurrSolver )
{
2022-05-04 12:47:38 -04:00
CurrSolver - > RegisterSimOneShotCallback ( [ Prox = PhysicsProxy , ReplicationLevel = ReplicationAbandonClusterLevel , AbandonAfterLevel = bEnableAbandonAfterLevel , this ] ( )
2020-09-01 14:07:48 -04:00
{
// 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
const Chaos : : FReal MaxStrain = TNumericLimits < Chaos : : FReal > : : Max ( ) - TNumericLimits < Chaos : : FReal > : : Min ( ) ;
TArray < Chaos : : TPBDRigidClusteredParticleHandle < Chaos : : FReal , 3 > * > Particles = Prox - > GetParticles ( ) ;
for ( Chaos : : TPBDRigidClusteredParticleHandle < Chaos : : FReal , 3 > * P : Particles )
{
if ( ! P )
{
continue ;
}
2022-04-25 13:09:18 -04:00
int32 Level = AbandonAfterLevel ? 0 : - 1 ;
if ( AbandonAfterLevel )
{
Chaos : : TPBDRigidClusteredParticleHandle < Chaos : : FReal , 3 > * Current = P ;
while ( Current - > Parent ( ) )
{
Current = Current - > Parent ( ) ;
+ + Level ;
}
}
if ( Level < = ReplicationLevel + 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)
{
P - > SetStrain ( MaxStrain ) ;
}
2020-09-01 14:07:48 -04:00
}
2022-05-04 12:47:38 -04:00
Prox - > SetInitializedForReplication ( ) ;
2020-09-01 14:07:48 -04:00
} ) ;
}
}
}
}
2021-03-18 23:55:49 -04:00
# if WITH_EDITOR
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-02-07 16:26:46 -05:00
}
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 ) ;
}
}
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 ( )
{
2021-08-31 20:24:01 -04:00
if ( BodyInstance . bNotifyRigidBodyCollision | | bNotifyBreaks | | bNotifyCollisions | | bNotifyRemovals )
2019-06-08 17:15:34 -04:00
{
2021-09-06 12:23:53 -04:00
# if INCLUDE_CHAOS
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 ) ;
} ) ;
}
2019-06-08 17:15:34 -04:00
}
2021-09-06 12:23:53 -04:00
# endif
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-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 ) ;
}
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
//Large refactor happening to this stuff so for now we just iterate
//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 ( ) ;
//see if we have any new clusters that are enabled
TSet < FPBDRigidClusteredParticleHandle * > Processed ;
for ( FPBDRigidClusteredParticleHandle * Particle : PhysicsProxy - > GetParticles ( ) )
{
bool bProcess = true ;
Processed . Add ( Particle ) ;
FPBDRigidClusteredParticleHandle * Root = Particle ;
while ( Root - > Parent ( ) )
{
Root = Root - > Parent ( ) ;
//TODO: set avoids n^2, would be nice if clustered particle cached its root
if ( Processed . Contains ( Root ) )
2020-09-01 14:07:48 -04:00
{
2022-04-25 13:09:18 -04:00
bProcess = false ;
break ;
}
else
{
Processed . Add ( Root ) ;
2020-09-01 14:07:48 -04:00
}
}
2022-04-25 13:09:18 -04:00
if ( bProcess & & Root - > Disabled ( ) = = false & & ClustersToRep - > Find ( Root ) = = nullptr )
2020-09-01 14:07:48 -04:00
{
2022-04-25 13:09:18 -04:00
//first time in here so needs a new count
//TODO: check root needs to replicate if abandon by level is enabled
ClustersToRep - > Add ( Root ) ;
2022-05-04 12:47:38 -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
2022-04-25 13:09:18 -04:00
{
//a one off so record it
const int32 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 " ) ) ;
RepData . OneOffActivated . Add ( TransformGroupIdx ) ;
bClustersChanged = true ;
}
2020-09-01 14:07:48 -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 ( ) ;
ClusterRep . ObjectState = static_cast < int8 > ( Cluster - > ObjectState ( ) ) ;
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
{
//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
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
if ( RepData . Clusters . Num ( ) > = Clusters . Num ( ) )
{
const FGeometryCollectionClusterRep & PrevCluster = RepData . Clusters [ Clusters . Num ( ) - 1 ] ;
if ( ClusterRep . ClusterChanged ( PrevCluster ) )
{
bClustersChanged = true ;
}
}
else
{
//must be some new clusters so definitely changed
bClustersChanged = true ;
}
}
}
}
if ( bClustersChanged )
{
RepData . Clusters = MoveTemp ( Clusters ) ;
MARK_PROPERTY_DIRTY_FROM_NAME ( UGeometryCollectionComponent , RepData , this ) ;
+ + RepData . Version ;
2022-05-04 12:47:38 -04:00
if ( Owner - > NetDormancy = = DORM_Initial )
{
//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 " ) ) ;
void UGeometryCollectionComponent : : ProcessRepData ( )
{
using namespace Chaos ;
2022-05-04 12:47:38 -04:00
if ( VersionProcessed = = RepData . Version | | PhysicsProxy - > GetInitializedForReplication ( ) = = false )
2022-04-25 13:09:18 -04:00
{
return ;
}
bool bHardSnap = false ;
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
bHardSnap = ( RepData . Version - VersionProcessed ) > GeometryCollectionHardMissingUpdatesSnapThreshold ;
}
else
{
//rollover so just treat as hard snap - this case is extremely rare and a one off
bHardSnap = true ;
}
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 )
{
FPBDRigidParticleHandle * OneOff = PhysicsProxy - > GetParticles ( ) [ RepData . OneOffActivated [ OneOffActivatedProcessed ] ] ;
RigidClustering . ReleaseClusterParticles ( TArray < FPBDRigidParticleHandle * > { OneOff } ) ;
}
if ( bHardSnap )
{
for ( const FGeometryCollectionClusterRep & RepCluster : RepData . Clusters )
{
FPBDRigidParticleHandle * Cluster = PhysicsProxy - > GetParticles ( ) [ RepCluster . ClusterIdx ] ;
if ( 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));
}
}
}
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.
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-11-18 14:37:34 -05:00
ConstantData - > UVs = TArray < TArray < FVector2f > > ( UVs . GetData ( ) , UVs . 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
2021-04-20 09:50:07 -04:00
ConstantData - > BoneColors . AddUninitialized ( NumPoints ) ;
2019-06-08 17:15:34 -04:00
2021-04-20 09:50:07 -04:00
ParallelFor ( NumPoints , [ & ] ( const int32 InPointIndex )
2019-06-08 17:15:34 -04:00
{
2021-04-20 09:50:07 -04:00
const int32 BoneIndex = ConstantData - > BoneMap [ InPointIndex ] ;
ConstantData - > BoneColors [ InPointIndex ] = BoneColors [ BoneIndex ] ;
} ) ;
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 WITH_CHAOS
if ( PhysicsProxy )
{
PhysicsProxy - > SetWorldTransform ( GetComponentTransform ( ) ) ;
}
# endif
}
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
2020-06-23 18:40:00 -04:00
# if WITH_CHAOS
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
{
2021-08-31 20:24:01 -04:00
if ( RestCollection - > bRemoveOnMaxSleep )
{
IncrementSleepTimer ( DeltaTime ) ;
}
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 ( ) ;
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 ;
2021-02-18 13:20:03 -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
}
}
2020-06-23 18:40:00 -04:00
# endif
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-05-04 12:47:38 -04:00
const ENetRole LocalRole = GetOwnerRole ( ) ;
if ( LocalRole = = ROLE_Authority )
{
UpdateRepData ( ) ;
}
else
{
ProcessRepData ( ) ;
}
2018-12-12 11:25:29 -05:00
}
void UGeometryCollectionComponent : : OnRegister ( )
{
2020-06-23 18:40:00 -04:00
# if WITH_CHAOS
2018-12-12 11:25:29 -05:00
//UE_LOG(UGCC_LOG, Log, TEXT("GeometryCollectionComponent[%p]::OnRegister()[%p]"), this,RestCollection );
ResetDynamicCollection ( ) ;
2019-07-23 16:27:55 -04:00
2020-06-23 18:40:00 -04:00
# endif // WITH_CHAOS
2020-09-01 14:07:48 -04:00
SetIsReplicated ( bEnableReplication ) ;
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 ( ) )
{
if ( World - > IsGameWorld ( ) )
{
bCreateDynamicCollection = true ;
}
}
# endif
2018-12-12 11:25:29 -05:00
//UE_LOG(UGCC_LOG, Log, TEXT("GeometryCollectionComponent[%p]::ResetDynamicCollection()"), static_cast<const void*>(this));
2019-06-08 17:15:34 -04:00
if ( bCreateDynamicCollection & & RestCollection )
{
DynamicCollection = MakeUnique < FGeometryDynamicCollection > ( ) ;
for ( const auto DynamicArray : CopyOnWriteAttributeList )
{
* DynamicArray = nullptr ;
}
GetTransformArrayCopyOnWrite ( ) ;
GetParentArrayCopyOnWrite ( ) ;
GetChildrenArrayCopyOnWrite ( ) ;
GetSimulationTypeArrayCopyOnWrite ( ) ;
GetStatusFlagsArrayCopyOnWrite ( ) ;
2021-08-31 20:24:01 -04:00
if ( RestCollection - > bRemoveOnMaxSleep )
{
if ( ! DynamicCollection - > HasAttribute ( " SleepTimer " , FGeometryCollection : : TransformGroup ) )
{
TManagedArray < float > & SleepTimer = DynamicCollection - > AddAttribute < float > ( " SleepTimer " , FGeometryCollection : : TransformGroup ) ;
SleepTimer . Fill ( 0.f ) ;
}
if ( ! DynamicCollection - > HasAttribute ( " UniformScale " , FGeometryCollection : : TransformGroup ) )
{
2021-09-15 17:18:16 -04:00
TManagedArray < FTransform > & UniformScale = DynamicCollection - > AddAttribute < FTransform > ( " UniformScale " , FGeometryCollection : : TransformGroup ) ;
UniformScale . Fill ( FTransform : : Identity ) ;
}
if ( ! DynamicCollection - > HasAttribute ( " MaxSleepTime " , FGeometryCollection : : TransformGroup ) )
{
float MinTime = FMath : : Max ( 0.0f , RestCollection - > MaximumSleepTime . X ) ;
float MaxTime = FMath : : Max ( MinTime , RestCollection - > MaximumSleepTime . Y ) ;
TManagedArray < float > & MaxSleepTime = DynamicCollection - > AddAttribute < float > ( " MaxSleepTime " , FGeometryCollection : : TransformGroup ) ;
for ( int32 Idx = 0 ; Idx < MaxSleepTime . Num ( ) ; + + Idx )
{
MaxSleepTime [ Idx ] = FMath : : RandRange ( MinTime , MaxTime ) ;
}
}
if ( ! DynamicCollection - > HasAttribute ( " RemovalDuration " , FGeometryCollection : : TransformGroup ) )
{
float MinTime = FMath : : Max ( 0.0f , RestCollection - > RemovalDuration . X ) ;
float MaxTime = FMath : : Max ( MinTime , RestCollection - > RemovalDuration . Y ) ;
TManagedArray < float > & RemovalDuration = DynamicCollection - > AddAttribute < float > ( " RemovalDuration " , FGeometryCollection : : TransformGroup ) ;
for ( int32 Idx = 0 ; Idx < RemovalDuration . Num ( ) ; + + Idx )
{
RemovalDuration [ Idx ] = FMath : : RandRange ( MinTime , MaxTime ) ;
}
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 ( )
{
2020-02-21 17:40:37 -05:00
/*#if WITH_PHYSX
2019-06-08 17:15:34 -04:00
DummyBodySetup = NewObject < UBodySetup > ( this , UBodySetup : : StaticClass ( ) ) ;
DummyBodySetup - > AggGeom . BoxElems . Add ( FKBoxElem ( 1.0f ) ) ;
DummyBodyInstance . InitBody ( DummyBodySetup , GetComponentToWorld ( ) , this , nullptr ) ;
DummyBodyInstance . bNotifyRigidBodyCollision = BodyInstance . bNotifyRigidBodyCollision ;
# endif
2020-02-21 17:40:37 -05:00
*/
2018-12-12 11:25:29 -05:00
// 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
/*#if WITH_PHYSX
2019-06-08 17:15:34 -04:00
DummyBodyInstance . SetCollisionEnabled ( ECollisionEnabled : : QueryOnly ) ;
DummyBodyInstance . SetResponseToAllChannels ( ECR_Block ) ;
# endif
2020-02-21 17:40:37 -05:00
*/
2020-06-23 18:40:00 -04:00
# if WITH_CHAOS
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 ) ) ;
2021-08-31 23:01:20 -04:00
RestCollectionMutable - > CreateSimulationData ( ) ;
2019-06-08 17:15:34 -04:00
}
2018-12-12 11:25:29 -05:00
# endif
2019-06-08 17:15:34 -04:00
const bool bValidWorld = GetWorld ( ) & & GetWorld ( ) - > IsGameWorld ( ) ;
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 ;
}
}
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
FBodyCollisionFilterData FilterData ;
FMaskFilter FilterMask = BodyInstance . GetMaskFilter ( ) ;
BodyInstance . BuildBodyFilterData ( FilterData ) ;
InitialSimFilter = FilterData . SimFilter ;
InitialQueryFilter = FilterData . QuerySimpleFilter ;
2020-03-09 13:22:54 -04:00
// Enable for complex and simple (no dual representation currently like other meshes)
InitialQueryFilter . Word3 | = ( EPDF_SimpleCollision | EPDF_ComplexCollision ) ;
InitialSimFilter . Word3 | = ( EPDF_SimpleCollision | EPDF_ComplexCollision ) ;
2021-03-03 21:40:44 -04:00
if ( bNotifyCollisions )
{
InitialQueryFilter . Word3 | = EPDF_ContactNotify ;
InitialSimFilter . Word3 | = EPDF_ContactNotify ;
}
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
}
2019-06-08 17:15:34 -04:00
# if WITH_PHYSX && !WITH_CHAOS_NEEDS_TO_BE_FIXED
2019-08-02 09:01:58 -04:00
if ( PhysicsProxy )
2019-06-08 17:15:34 -04:00
{
GlobalGeomCollectionAccelerator . AddComponent ( this ) ;
}
# endif
2020-06-23 18:40:00 -04:00
# endif // WITH_CHAOS
2018-12-12 11:25:29 -05:00
}
2021-05-25 22:01:05 -04:00
void UGeometryCollectionComponent : : RegisterAndInitializePhysicsProxy ( )
{
2021-10-25 20:05:28 -04:00
# if WITH_CHAOS
2021-05-25 22:01:05 -04:00
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 ;
2021-05-25 22:01:05 -04:00
SimulationParameters . RemoveOnFractureEnabled = SimulationParameters . Shared . RemoveOnFractureIndices . Num ( ) > 0 ;
2022-05-10 19:47:19 -04:00
SimulationParameters . EnableGravity = BodyInstance . bEnableGravity ;
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
}
2021-11-07 23:43:01 -05:00
PhysicsProxy = new FGeometryCollectionPhysicsProxy ( this , * DynamicCollection , SimulationParameters , InitialSimFilter , InitialQueryFilter ) ;
2021-05-25 22:01:05 -04:00
FPhysScene_Chaos * Scene = GetInnerChaosScene ( ) ;
Scene - > AddObject ( this , PhysicsProxy ) ;
RegisterForEvents ( ) ;
2022-04-26 14:28:07 -04:00
SetAsyncPhysicsTickEnabled ( GetIsReplicated ( ) ) ;
2021-10-25 20:05:28 -04:00
# endif
2021-05-25 22:01:05 -04:00
}
2018-12-12 11:25:29 -05:00
void UGeometryCollectionComponent : : OnDestroyPhysicsState ( )
{
UActorComponent : : OnDestroyPhysicsState ( ) ;
2020-06-23 18:40:00 -04:00
# if WITH_CHAOS
2019-06-08 17:15:34 -04:00
# if WITH_PHYSX && !WITH_CHAOS_NEEDS_TO_BE_FIXED
GlobalGeomCollectionAccelerator . RemoveComponent ( this ) ;
# endif
# if WITH_PHYSX
if ( DummyBodyInstance . IsValidBodyInstance ( ) )
{
DummyBodyInstance . TermBody ( ) ;
}
# endif
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 ;
// 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
}
2020-06-23 18:40:00 -04:00
# endif
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
if ( SceneProxy & & ( ( DynamicCollection & & DynamicCollection - > IsDirty ( ) ) | | CachePlayback ) )
{
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
}
}
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
DamageThreshold = RestCollection - > DamageThreshold ;
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-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 )
{
GetRestCollection ( ) - > UpdateConvexGeometry ( ) ;
}
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 ) ;
}
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
{
Component - > SelectedBones . Add ( BoneIndex ) ;
}
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 ( ) ;
if ( GeometryCollection )
{
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 ( ) ;
if ( GeometryCollection )
{
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 ;
if ( GeometryCollection & & Component - > SelectedBones . Num ( ) > 0 & & bNeedsFiltering )
{
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 ;
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 ( ) ) ;
ProximityUtility . UpdateProximity ( ) ;
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
2021-12-13 15:59:48 -05:00
TArray < int32 > NewSelection ;
for ( int32 Bone : SelectedBones )
{
NewSelection . AddUnique ( Bone ) ;
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
{
2021-12-13 15:59:48 -05:00
NewSelection . AddUnique ( 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 ( ) ;
AppendSelectedBones ( NewSelection ) ;
}
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 ( ) ;
TArray < int32 > NewSelection ;
for ( int32 Bone : SelectedBones )
{
int32 ParentBone = Parents [ Bone ] ;
if ( ParentBone ! = FGeometryCollection : : Invalid )
{
NewSelection . AddUnique ( ParentBone ) ;
}
}
ResetBoneSelection ( ) ;
AppendSelectedBones ( NewSelection ) ;
}
break ;
case GeometryCollection : : ESelectionMode : : Children :
{
const TManagedArray < TSet < int32 > > & Children = GeometryCollectionPtr - > Children ;
const TArray < int32 > SelectedBones = GetSelectedBones ( ) ;
TArray < int32 > NewSelection ;
for ( int32 Bone : SelectedBones )
{
for ( int32 Child : Children [ Bone ] )
{
NewSelection . AddUnique ( Child ) ;
}
}
ResetBoneSelection ( ) ;
AppendSelectedBones ( NewSelection ) ;
}
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 ( ) ;
TArray < int32 > NewSelection ;
for ( int32 Bone : SelectedBones )
{
int32 ParentBone = Parents [ Bone ] ;
if ( ParentBone ! = FGeometryCollection : : Invalid )
{
for ( int32 Child : Children [ ParentBone ] )
{
NewSelection . AddUnique ( Child ) ;
}
}
}
ResetBoneSelection ( ) ;
AppendSelectedBones ( NewSelection ) ;
}
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
2021-12-13 15:59:48 -05:00
TArray < int32 > NewSelection ;
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
{
2021-08-30 17:18:37 -04:00
NewSelection . AddUnique ( TransformIdx ) ;
}
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 ( ) ;
AppendSelectedBones ( NewSelection ) ;
}
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 ) ;
2018-12-12 11:25:29 -05:00
if ( Component - > ViewLevel = = - 1 )
{
BoneColor = RandomColors [ BoneIndex % RandomColors . Num ( ) ] ;
}
else
{
2019-06-08 17:15:34 -04:00
if ( HasLevelAttribute & & ( * Levels ) [ BoneIndex ] > = Component - > ViewLevel )
2018-12-12 11:25:29 -05:00
{
// go up until we find parent at the required ViewLevel
int32 Bone = BoneIndex ;
2019-06-08 17:15:34 -04:00
while ( Bone ! = - 1 & & ( * Levels ) [ Bone ] > Component - > ViewLevel )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
Bone = Parents [ Bone ] ;
2018-12-12 11:25:29 -05:00
}
int32 ColorIndex = Bone + 1 ; // parent can be -1 for root, range [-1..n]
BoneColor = RandomColors [ ColorIndex % RandomColors . Num ( ) ] ;
2019-06-08 17:15:34 -04:00
BoneColor . LinearRGBToHSV ( ) ;
BoneColor . B * = .5 ;
BoneColor . HSVToLinearRGB ( ) ;
2018-12-12 11:25:29 -05:00
}
else
{
BoneColor = BlankColor ;
}
}
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
}
}
}
}
}
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-10-02 17:27:26 -04:00
# if INCLUDE_CHAOS
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
}
check ( GWorld ) ;
2020-08-11 01:36:57 -04:00
return GWorld - > GetPhysicsScene ( ) ;
2019-10-02 17:27:26 -04:00
# else
return nullptr ;
# endif
2018-12-12 11:25:29 -05:00
}
}
2019-06-08 17:15:34 -04:00
AChaosSolverActor * UGeometryCollectionComponent : : GetPhysicsSolverActor ( ) const
{
2021-10-25 20:05:28 -04:00
# if WITH_CHAOS
2019-06-08 17:15:34 -04:00
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 ;
}
2021-10-25 20:05:28 -04:00
# endif
2019-06-08 17:15:34 -04:00
return nullptr ;
}
void UGeometryCollectionComponent : : CalculateLocalBounds ( )
{
LocalBounds . Init ( ) ;
const TManagedArray < FBox > & BoundingBoxes = GetBoundingBoxArray ( ) ;
const TManagedArray < int32 > & TransformIndices = GetTransformIndexArray ( ) ;
const int32 NumBoxes = BoundingBoxes . Num ( ) ;
for ( int32 BoxIdx = 0 ; BoxIdx < NumBoxes ; + + BoxIdx )
{
const int32 TransformIndex = TransformIndices [ BoxIdx ] ;
if ( GetRestCollection ( ) - > GetGeometryCollection ( ) - > IsGeometry ( TransformIndex ) )
{
LocalBounds + = BoundingBoxes [ BoxIdx ] ;
}
}
}
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
& & RestCollection - > bRemoveOnMaxSleep
& & DynamicCollection - > HasAttribute ( " SleepTimer " , FGeometryCollection : : TransformGroup )
& & DynamicCollection - > HasAttribute ( " UniformScale " , FGeometryCollection : : TransformGroup )
& & DynamicCollection - > HasAttribute ( " MaxSleepTime " , FGeometryCollection : : TransformGroup )
& & DynamicCollection - > HasAttribute ( " RemovalDuration " , FGeometryCollection : : TransformGroup ) )
2021-08-31 20:24:01 -04:00
{
const TManagedArray < float > & SleepTimer = DynamicCollection - > GetAttribute < float > ( " SleepTimer " , FGeometryCollection : : TransformGroup ) ;
2021-09-15 17:18:16 -04:00
const TManagedArray < float > & MaxSleepTime = DynamicCollection - > GetAttribute < float > ( " MaxSleepTime " , FGeometryCollection : : TransformGroup ) ;
const TManagedArray < float > & RemovalDuration = DynamicCollection - > GetAttribute < float > ( " RemovalDuration " , 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
2021-08-31 20:24:01 -04:00
for ( int32 Idx = 0 ; Idx < GetTransformArray ( ) . Num ( ) ; + + Idx )
{
2021-09-15 17:18:16 -04:00
if ( SleepTimer [ Idx ] > MaxSleepTime [ Idx ] )
2021-08-31 20:24:01 -04:00
{
2021-09-15 17:18:16 -04:00
float Scale = 1.0 - FMath : : Min ( 1.0 , ( SleepTimer [ Idx ] - MaxSleepTime [ Idx ] ) / RemovalDuration [ Idx ] ) ;
if ( ( Scale < 1.0 ) & & ( Scale > 0.0 ) )
{
float ShrinkRadius = 0.0f ;
FSphere AccumulatedSphere ;
if ( CalculateInnerSphere ( Idx , AccumulatedSphere ) )
{
ShrinkRadius = - AccumulatedSphere . W ;
}
FQuat LocalRotation = ( GetComponentTransform ( ) . Inverse ( ) * FTransform ( GlobalMatrices [ Idx ] ) . Inverse ( ) ) . GetRotation ( ) ;
FTransform LocalDown ( LocalRotation . RotateVector ( FVector ( 0.f , 0.f , ShrinkRadius ) ) ) ;
FTransform ToCOM ( DynamicCollection - > MassToLocal [ Idx ] . GetTranslation ( ) ) ;
UniformScale [ Idx ] = ToCOM . Inverse ( ) * LocalDown . Inverse ( ) * FTransform ( FQuat : : Identity , FVector ( 0.f , 0.f , 0.f ) , FVector ( Scale ) ) * LocalDown * ToCOM ;
}
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
if ( GlobalMatrices . Num ( ) > 0 )
{
if ( RestCollection - > GetGeometryCollection ( ) - > HasAttribute ( " ExplodedVector " , FGeometryCollection : : TransformGroup ) )
{
2021-05-05 15:07:25 -04:00
const TManagedArray < FVector3f > & ExplodedVectors = RestCollection - > GetGeometryCollection ( ) - > GetAttribute < FVector3f > ( " ExplodedVector " , FGeometryCollection : : TransformGroup ) ;
2019-06-08 17:15:34 -04:00
check ( GlobalMatrices . Num ( ) = = ExplodedVectors . Num ( ) ) ;
for ( int32 tt = 0 , nt = GlobalMatrices . Num ( ) ; tt < nt ; + + tt )
{
2022-02-02 07:59:31 -05:00
GlobalMatrices [ tt ] = GlobalMatrices [ tt ] . ConcatTranslation ( ( FVector ) ExplodedVectors [ tt ] ) ;
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
CalculateGlobalMatrices ( ) ;
RefreshEmbeddedGeometry ( ) ;
2021-12-02 18:57:44 -05:00
2021-02-18 13:20:03 -04:00
}
}
2021-04-12 15:19:31 -04:00
2021-08-31 20:24:01 -04:00
void UGeometryCollectionComponent : : IncrementSleepTimer ( float DeltaTime )
{
// If a particle is sleeping, increment its sleep timer, otherwise reset it.
2021-09-15 17:18:16 -04:00
if ( DynamicCollection & & PhysicsProxy
& & DynamicCollection - > HasAttribute ( " SleepTimer " , FGeometryCollection : : TransformGroup )
& & DynamicCollection - > HasAttribute ( " MaxSleepTime " , FGeometryCollection : : TransformGroup )
& & DynamicCollection - > HasAttribute ( " RemovalDuration " , FGeometryCollection : : TransformGroup ) )
2021-08-31 20:24:01 -04:00
{
2022-05-10 18:56:28 -04:00
TManagedArray < float > & SleepTimer = DynamicCollection - > ModifyAttribute < float > ( " SleepTimer " , FGeometryCollection : : TransformGroup ) ;
2021-09-15 17:18:16 -04:00
const TManagedArray < float > & RemovalDuration = DynamicCollection - > GetAttribute < float > ( " RemovalDuration " , FGeometryCollection : : TransformGroup ) ;
const TManagedArray < float > & MaxSleepTime = DynamicCollection - > GetAttribute < float > ( " MaxSleepTime " , FGeometryCollection : : TransformGroup ) ;
2021-08-31 20:24:01 -04:00
TArray < int32 > ToDisable ;
for ( int32 TransformIdx = 0 ; TransformIdx < SleepTimer . Num ( ) ; + + TransformIdx )
{
2021-09-15 17:18:16 -04:00
bool PreviouslyAwake = SleepTimer [ TransformIdx ] < MaxSleepTime [ TransformIdx ] ;
if ( SleepTimer [ TransformIdx ] < ( MaxSleepTime [ TransformIdx ] + RemovalDuration [ TransformIdx ] ) )
2021-08-31 20:24:01 -04:00
{
SleepTimer [ TransformIdx ] = ( DynamicCollection - > DynamicState [ TransformIdx ] = = ( int ) EObjectStateTypeEnum : : Chaos_Object_Sleeping ) ? SleepTimer [ TransformIdx ] + DeltaTime : 0.0f ;
2021-09-15 17:18:16 -04:00
if ( SleepTimer [ TransformIdx ] > MaxSleepTime [ TransformIdx ] )
2021-08-31 20:24:01 -04:00
{
DynamicCollection - > MakeDirty ( ) ;
if ( PreviouslyAwake )
{
// Disable the particle if it has been asleep for the requisite time
ToDisable . Add ( TransformIdx ) ;
}
}
}
}
if ( ToDisable . Num ( ) )
{
PhysicsProxy - > DisableParticles ( ToDisable ) ;
}
}
}
2021-09-15 17:18:16 -04:00
bool UGeometryCollectionComponent : : CalculateInnerSphere ( int32 TransformIndex , FSphere & SphereOut ) const
{
// 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 ( ) ;
SphereOut = FSphere ( COM , InnerRadius [ TransformToGeometryIndex [ TransformIndex ] ] ) ;
return true ;
}
else if ( RestCollection - > GetGeometryCollection ( ) - > IsClustered ( TransformIndex ) )
{
// Recursively accumulate the cluster's child spheres.
bool bSphereFound = false ;
for ( int32 ChildIndex : Children [ TransformIndex ] )
{
FSphere LocalSphere ;
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 ;
}
2021-09-15 17:18:16 -04:00
}