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
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 ;
int32 NumPoses = Poses . Num ( ) ;
Ar < < NumPoses ;
if ( Ar . IsLoading ( ) )
{
Poses . SetNum ( NumPoses ) ;
}
for ( FGeometryCollectionRepPose & Pose : Poses )
{
SerializePackedVector < 100 , 30 > ( Pose . Position , Ar ) ;
SerializePackedVector < 100 , 30 > ( Pose . LinearVelocity , Ar ) ;
SerializePackedVector < 100 , 30 > ( Pose . AngularVelocity , Ar ) ;
Pose . Rotation . NetSerialize ( Ar , Map , bOutSuccess ) ;
Ar < < Pose . ParticleIndex ;
}
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 )
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 )
, DamageThreshold ( { 250.0 } )
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 )
2021-03-18 20:04:04 -04:00
, bShowBoneColors ( false )
2020-09-01 14:07:48 -04:00
, bEnableReplication ( false )
, bEnableAbandonAfterLevel ( false )
, 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
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
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 ) ;
FDoRepLifetimeParams Params ;
Params . bIsPushBased = true ;
Params . RepNotifyCondition = REPNOTIFY_OnChanged ;
DOREPLIFETIME_WITH_PARAMS_FAST ( UGeometryCollectionComponent , RepData , Params ) ;
}
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-08-30 17:23:27 -04: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 ) ;
TManagedArray < FBox > & TransformBounds = HackGeometryCollectionPtr - > GetAttribute < 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
{
# 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 ) ;
# else
for ( int32 BoxIdx = 0 ; BoxIdx < NumBoxes ; + + BoxIdx )
{
const int32 TransformIndex = TransformIndices [ BoxIdx ] ;
if ( RestCollection - > GetGeometryCollection ( ) - > IsGeometry ( TransformIndex ) )
{
BoundingBox + = BoundingBoxes [ BoxIdx ] . TransformBy ( GlobalMatrices [ TransformIndex ] * LocalToWorldWithScale ) ;
}
}
# endif
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-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 ( ) ;
}
}
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 ;
FVector const VertexInWorldSpace = GeomToComponent [ SubsetIndex ] . TransformPosition ( Vertex [ SourceGeometryVertexIndex ] ) ;
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
UPhysicalMaterial * PhysMatToUse = PhysicalMaterialOverride ;
if ( ! PhysMatToUse )
{
// 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 ( ) ;
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-02-18 13:20:03 -04:00
const int32 ExemplarCount = EmbeddedGeometryComponents . Num ( ) ;
for ( int32 ExemplarIndex = 0 ; ExemplarIndex < ExemplarCount ; + + ExemplarIndex )
{
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 ] )
{
InstanceTransforms . Add ( FTransform ( GlobalMatrices [ Idx ] ) ) ;
}
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-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 ( SceneProxy - > IsNaniteMesh ( ) )
{
# 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
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 ( ) ;
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
if ( GetIsReplicated ( ) & & NetMode ! = NM_Standalone )
{
if ( LocalRole = = ENetRole : : ROLE_Authority )
{
// As we're the authority we need to track velocities in the dynamic collection so we
// can send them over to the other clients to correctly set their state. Attach this now.
// The physics proxy will pick them up and populate them as needed
2021-05-05 15:07:25 -04:00
DynamicCollection - > AddAttribute < FVector3f > ( " LinearVelocity " , FTransformCollection : : TransformGroup ) ;
DynamicCollection - > AddAttribute < FVector3f > ( " AngularVelocity " , FTransformCollection : : TransformGroup ) ;
2020-09-01 14:07:48 -04:00
// We also need to track our control of particles if that control can be shared between server and client
if ( bEnableAbandonAfterLevel )
{
TManagedArray < bool > & ControlFlags = DynamicCollection - > AddAttribute < bool > ( " AuthControl " , FTransformCollection : : TransformGroup ) ;
for ( bool & Flag : ControlFlags )
{
Flag = true ;
}
}
}
else
{
// We're a replicated component and we're not in control.
Chaos : : FPhysicsSolver * CurrSolver = GetSolver ( * this ) ;
if ( CurrSolver )
{
CurrSolver - > RegisterSimOneShotCallback ( [ Prox = PhysicsProxy ] ( )
{
// 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 ;
}
P - > SetStrain ( MaxStrain ) ;
}
} ) ;
}
}
}
}
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
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-08-18 23:04:26 -04:00
Chaos : : FPhysicsSolver * Solver = GetWorld ( ) - > GetPhysicsScene ( ) - > GetSolver ( ) ;
if ( Solver )
2019-06-08 17:15:34 -04:00
{
2021-08-18 23:04:26 -04: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 ) ;
} ) ;
}
if ( bNotifyBreaks )
{
EventDispatcher - > RegisterForBreakEvents ( this , & DispatchGeometryCollectionBreakEvent ) ;
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
}
}
}
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 ) ;
}
}
2021-05-05 15:07:25 -04:00
void ActivateClusters ( Chaos : : FPBDRigidsEvolution : : 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 : : OnRep_RepData ( const FGeometryCollectionRepData & OldData )
{
if ( ! DynamicCollection )
{
return ;
}
if ( AActor * Owner = GetOwner ( ) )
{
const int32 NumTransforms = DynamicCollection - > Transform . Num ( ) ;
const int32 NumNewPoses = RepData . Poses . Num ( ) ;
if ( NumTransforms < NumNewPoses )
{
return ;
}
Chaos : : FPhysicsSolver * Solver = GetSolver ( * this ) ;
for ( int32 Index = 0 ; Index < NumNewPoses ; + + Index )
{
const FGeometryCollectionRepPose & SourcePose = RepData . Poses [ Index ] ;
const int32 ParticleIndex = SourcePose . ParticleIndex ;
if ( ParticleIndex > = NumTransforms )
{
// Out of range
continue ;
}
Solver - > RegisterSimOneShotCallback ( [ SourcePose , Prox = PhysicsProxy ] ( )
{
2021-05-05 15:07:25 -04:00
Chaos : : TPBDRigidClusteredParticleHandle < Chaos : : FReal , 3 > * Particle = Prox - > GetParticles ( ) [ SourcePose . ParticleIndex ] ;
2020-09-01 14:07:48 -04:00
Chaos : : FPhysicsSolver * Solver = Prox - > GetSolver < Chaos : : FPhysicsSolver > ( ) ;
Chaos : : FPBDRigidsEvolution * Evo = Solver - > GetEvolution ( ) ;
check ( Evo ) ;
Chaos : : FPBDRigidsEvolution : : FRigidClustering & Clustering = Evo - > GetRigidClustering ( ) ;
// Set X/R/V/W for next sim step from the replicated state
Particle - > SetX ( SourcePose . Position ) ;
Particle - > SetR ( SourcePose . Rotation ) ;
Particle - > SetV ( SourcePose . LinearVelocity ) ;
Particle - > SetW ( SourcePose . AngularVelocity ) ;
if ( Particle - > ClusterIds ( ) . Id )
{
// This particle is clustered but the remote authority has it activated. Fracture the parent cluster
2021-04-07 23:42:46 -04:00
ActivateClusters ( Clustering , Particle - > Parent ( ) ) ;
2020-09-01 14:07:48 -04:00
}
else if ( Particle - > Disabled ( ) )
{
// We might have disabled the particle - need to reactivate if it's active on the remote.
Particle - > SetDisabled ( false ) ;
}
// Make sure to wake corrected particles
Particle - > SetSleeping ( false ) ;
} ) ;
}
}
}
void UGeometryCollectionComponent : : UpdateRepData ( )
{
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 ;
}
if ( Owner & & GetIsReplicated ( ) & & Owner - > GetLocalRole ( ) = = ROLE_Authority )
{
// We're inside a replicating actor and we're the authority - update the rep data
const int32 NumTransforms = DynamicCollection - > Transform . Num ( ) ;
RepData . Poses . Reset ( NumTransforms ) ;
2021-05-05 15:07:25 -04:00
TManagedArray < FVector3f > * LinearVelocity = DynamicCollection - > FindAttributeTyped < FVector3f > ( " LinearVelocity " , FTransformCollection : : TransformGroup ) ;
TManagedArray < FVector3f > * AngularVelocity = DynamicCollection - > FindAttributeTyped < FVector3f > ( " AngularVelocity " , FTransformCollection : : TransformGroup ) ;
2020-09-01 14:07:48 -04:00
for ( int32 Index = 0 ; Index < NumTransforms ; + + Index )
{
2021-02-03 14:57:28 -04:00
TManagedArray < TUniquePtr < Chaos : : FGeometryParticle > > & GTParticles = PhysicsProxy - > GetExternalParticles ( ) ;
Chaos : : FGeometryParticle * Particle = GTParticles [ Index ] . Get ( ) ;
2020-09-01 14:07:48 -04:00
if ( ! DynamicCollection - > Active [ Index ] | | DynamicCollection - > DynamicState [ Index ] ! = static_cast < uint8 > ( Chaos : : EObjectStateType : : Dynamic ) )
{
continue ;
}
const int32 ClusterLevel = GetClusterLevel ( RestCollection - > GetGeometryCollection ( ) . Get ( ) , Index ) ;
const bool bLevelValid = ! EnableClustering | | ! bEnableAbandonAfterLevel | | ClusterLevel < = ReplicationAbandonClusterLevel ;
if ( ! bLevelValid )
{
const int32 ParentTransformIndex = RestCollection - > GetGeometryCollection ( ) - > Parent [ Index ] ;
TManagedArray < bool > * ControlFlags = DynamicCollection - > FindAttributeTyped < bool > ( " AuthControl " , FTransformCollection : : TransformGroup ) ;
if ( ControlFlags & & ( * ControlFlags ) [ ParentTransformIndex ] )
{
( * ControlFlags ) [ ParentTransformIndex ] = false ;
NetAbandonCluster ( ParentTransformIndex ) ;
}
continue ;
}
RepData . Poses . AddDefaulted ( ) ;
FGeometryCollectionRepPose & Pose = RepData . Poses . Last ( ) ;
// No scale transfered - shouldn't be a simulated property
Pose . ParticleIndex = Index ;
Pose . Position = Particle - > X ( ) ;
Pose . Rotation = Particle - > R ( ) ;
if ( LinearVelocity )
{
check ( AngularVelocity ) ;
Pose . LinearVelocity = ( * LinearVelocity ) [ Index ] ;
Pose . AngularVelocity = ( * AngularVelocity ) [ Index ] ;
}
else
{
Pose . LinearVelocity = FVector : : ZeroVector ;
Pose . AngularVelocity = FVector : : ZeroVector ;
}
}
RepData . Version + + ;
MARK_PROPERTY_DIRTY_FROM_NAME ( UGeometryCollectionComponent , RepData , this ) ;
}
}
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 ) ;
}
}
void UGeometryCollectionComponent : : NetAbandonCluster_Implementation ( int32 TransformIndex )
{
// Called on clients when the server abandons a particle. TransformIndex is the index of the parent
// of that particle, should only get called once per cluster but survives multiple calls
if ( GetOwnerRole ( ) = = ENetRole : : ROLE_Authority )
{
// Owner called abandon - takes no action
return ;
}
if ( ! EnableClustering )
{
// No clustering information to update
return ;
}
if ( TransformIndex > = 0 & & TransformIndex < DynamicCollection - > NumElements ( FTransformCollection : : TransformGroup ) )
{
int32 ClusterLevel = GetClusterLevel ( RestCollection - > GetGeometryCollection ( ) . Get ( ) , TransformIndex ) ;
float Strain = DamageThreshold . IsValidIndex ( ClusterLevel ) ? DamageThreshold [ ClusterLevel ] : DamageThreshold . Num ( ) > 0 ? DamageThreshold [ 0 ] : 0.0f ;
if ( Strain > = 0 )
{
Chaos : : FPhysicsSolver * Solver = GetSolver ( * this ) ;
Solver - > RegisterSimOneShotCallback ( [ Prox = PhysicsProxy , Strain , TransformIndex , Solver ] ( )
{
2021-02-18 18:13:28 -04:00
Chaos : : TPBDRigidClustering < Chaos : : FPBDRigidsEvolution , Chaos : : FPBDCollisionConstraints > & Clustering = Solver - > GetEvolution ( ) - > GetRigidClustering ( ) ;
Chaos : : FPBDRigidClusteredParticleHandle * Parent = Prox - > GetParticles ( ) [ TransformIndex ] ;
2020-09-01 14:07:48 -04:00
if ( ! Parent - > Disabled ( ) )
{
SetHierarchyStrain ( Parent , Clustering . GetChildrenMap ( ) , Strain ) ;
// We know the server must have fractured this cluster, so repeat here
Clustering . DeactivateClusterParticle ( Parent ) ;
}
} ) ;
}
}
}
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-05-18 13:03:42 -04:00
const TManagedArray < TArray < FVector2D > > & UVs = Collection - > UVs ;
2021-04-20 09:50:07 -04:00
const TManagedArray < FLinearColor > & Color = Collection - > Color ;
const TManagedArray < FLinearColor > & BoneColors = Collection - > BoneColor ;
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-05-18 13:03:42 -04:00
ConstantData - > UVs = TArray < TArray < FVector2D > > ( 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 ;
VisibleOverride . Init ( true , Visible . Num ( ) ) ;
bool bUsingHideArray = false ;
if ( Collection - > HasAttribute ( " Hide " , FGeometryCollection : : TransformGroup ) )
{
bUsingHideArray = true ;
const TManagedArray < bool > & Hide = Collection - > GetAttribute < bool > ( " Hide " , FGeometryCollection : : TransformGroup ) ;
for ( int32 GeomIdx = 0 ; GeomIdx < NumGeom ; + + GeomIdx )
{
if ( Hide [ TransformIndex [ GeomIdx ] ] )
{
// (Temporarily) hide faces of this hidden geometry
for ( int32 FaceIdxOffset = 0 ; FaceIdxOffset < FaceCount [ GeomIdx ] ; + + FaceIdxOffset )
{
VisibleOverride [ FaceStart [ GeomIdx ] + FaceIdxOffset ] = false ;
}
}
}
}
# 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
NumIndices + = static_cast < int > ( VisibleOverride [ FaceIndex ] ) ;
# 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
if ( VisibleOverride [ MaterialIndex [ IndexIdx ] ] )
# 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
if ( ! VisibleOverride [ MaterialIndex [ TriangleIndex ] ] )
# 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
if ( ! VisibleOverride [ FaceIdx ] )
# 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-08-30 17:11:38 -04: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
if ( VisibleOverride [ FaceIndex ] & & ( MaterialID [ FaceIndex ] % 2 = = 0 | | bUsingHideArray ) )
# 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?
if ( bIsMoving )
{
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?
if ( ! bIsMoving )
{
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
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 ) )
{
TManagedArray < float > & UniformScale = DynamicCollection - > AddAttribute < float > ( " UniformScale " , FGeometryCollection : : TransformGroup ) ;
UniformScale . Fill ( 1.f ) ;
}
}
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
2019-06-08 17:15:34 -04:00
if ( ObjectType ! = EObjectStateTypeEnum : : Chaos_Object_UserDefined )
{
2020-12-09 18:44:07 -04:00
if ( RestCollection & & ( ObjectType = = 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 + + )
{
DynamicState [ i ] = ( InitialDynamicState [ i ] = = static_cast < int32 > ( Chaos : : EObjectStateType : : Uninitialized ) ) ? static_cast < int32 > ( ObjectType ) : InitialDynamicState [ i ] ;
}
}
else
{
for ( int i = 0 ; i < DynamicState . Num ( ) ; i + + )
{
DynamicState [ i ] = static_cast < int32 > ( ObjectType ) ;
}
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 ;
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 ( )
{
FSimulationParameters SimulationParameters ;
{
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
SimulationParameters . Name = GetPathName ( ) ;
# endif
EClusterConnectionTypeEnum ClusterCollectionType = ClusterConnectionType_DEPRECATED ;
if ( RestCollection )
{
RestCollection - > GetSharedSimulationParams ( SimulationParameters . Shared ) ;
SimulationParameters . RestCollection = RestCollection - > GetGeometryCollection ( ) . Get ( ) ;
ClusterCollectionType = RestCollection - > ClusterConnectionType ;
}
SimulationParameters . Simulating = BodyInstance . bSimulatePhysics ;
SimulationParameters . EnableClustering = EnableClustering ;
SimulationParameters . ClusterGroupIndex = EnableClustering ? ClusterGroupIndex : 0 ;
SimulationParameters . MaxClusterLevel = MaxClusterLevel ;
SimulationParameters . bUseSizeSpecificDamageThresholds = bUseSizeSpecificDamageThreshold ;
SimulationParameters . DamageThreshold = DamageThreshold ;
SimulationParameters . ClusterConnectionMethod = ( Chaos : : FClusterCreationParameters : : EConnectionMethod ) ClusterCollectionType ;
SimulationParameters . CollisionGroup = CollisionGroup ;
SimulationParameters . CollisionSampleFraction = CollisionSampleFraction ;
SimulationParameters . InitialVelocityType = InitialVelocityType ;
SimulationParameters . InitialLinearVelocity = InitialLinearVelocity ;
SimulationParameters . InitialAngularVelocity = InitialAngularVelocity ;
SimulationParameters . bClearCache = true ;
SimulationParameters . ObjectType = ObjectType ;
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 ;
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
}
PhysicsProxy = new FGeometryCollectionPhysicsProxy ( this , * DynamicCollection , SimulationParameters , InitialQueryFilter , InitialSimFilter ) ;
FPhysScene_Chaos * Scene = GetInnerChaosScene ( ) ;
Scene - > AddObject ( this , PhysicsProxy ) ;
RegisterForEvents ( ) ;
}
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 ( ) ;
}
2019-06-08 17:15:34 -04:00
//ResetDynamicCollection();
2018-12-12 11:25:29 -05:00
}
}
2019-06-20 12:19:58 -04:00
FGeometryCollectionEdit : : FGeometryCollectionEdit ( UGeometryCollectionComponent * InComponent , GeometryCollection : : EEditUpdate InEditUpdate )
2018-12-12 11:25:29 -05:00
: Component ( InComponent )
2019-06-20 12:19:58 -04:00
, EditUpdate ( InEditUpdate )
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 ( ) ;
}
}
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 ( ) ;
}
if ( EnumHasAnyFlags ( EditUpdate , GeometryCollection : : EEditUpdate : : Rest ) & & GetRestCollection ( ) )
2018-12-12 11:25:29 -05:00
{
GetRestCollection ( ) - > Modify ( ) ;
}
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 ;
}
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 ) ;
}
2021-06-15 00:47:27 -04:00
void FScopedColorEdit : : ToggleSelectedBones ( const TArray < int32 > & SelectedBonesIn , bool bAdd )
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
int32 ContextBoneIndex = ( GetViewLevel ( ) > - 1 ) ? FGeometryCollectionClusteringUtility : : GetParentOfBoneAtSpecifiedLevel ( GeometryCollectionPtr . Get ( ) , BoneIndex , GetViewLevel ( ) ) : BoneIndex ;
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 ( ) ;
}
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 ( ) ;
}
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 :
{
TArray < int32 > Roots ;
FGeometryCollectionClusteringUtility : : GetRootBones ( GeometryCollectionPtr . Get ( ) , Roots ) ;
ResetBoneSelection ( ) ;
for ( int32 RootElement : Roots )
{
TArray < int32 > LeafBones ;
2021-01-28 23:22:16 -04:00
FGeometryCollectionClusteringUtility : : GetLeafBones ( GeometryCollectionPtr . Get ( ) , RootElement , true , LeafBones ) ;
2018-12-12 11:25:29 -05:00
AppendSelectedBones ( LeafBones ) ;
}
}
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 ) ;
TArray < int32 > ChildBones ;
FGeometryCollectionClusteringUtility : : GetChildBonesFromLevel ( GeometryCollectionPtr . Get ( ) , ViewLevelBone , GetViewLevel ( ) , ChildBones ) ;
NewSelection . Append ( ChildBones ) ;
}
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 :
{
if ( ensureMsgf ( GeometryCollectionPtr - > HasAttribute ( " Proximity " , FGeometryCollection : : GeometryGroup ) ,
TEXT ( " Must build breaking group for neighbor based selection " ) ) )
{
2021-08-31 20:24:01 -04:00
FGeometryCollectionProximityUtility : : UpdateProximity ( GeometryCollectionPtr . Get ( ) ) ;
2019-06-08 17:15:34 -04: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 ) ;
const TArray < int32 > SelectedBones = GetSelectedBones ( ) ;
TArray < int32 > NewSelection ;
for ( int32 Bone : SelectedBones )
{
NewSelection . AddUnique ( Bone ) ;
2021-05-06 14:59:48 -04:00
int32 GeometryIdx = TransformToGeometryIndex [ Bone ] ;
if ( GeometryIdx ! = INDEX_NONE )
2019-06-08 17:15:34 -04:00
{
2021-05-06 14:59:48 -04:00
const TSet < int32 > & Neighbors = Proximity [ GeometryIdx ] ;
for ( int32 NeighborGeometryIndex : Neighbors )
{
NewSelection . AddUnique ( TransformIndex [ NeighborGeometryIndex ] ) ;
}
2019-06-08 17:15:34 -04:00
}
}
ResetBoneSelection ( ) ;
AppendSelectedBones ( NewSelection ) ;
}
}
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 ) )
2019-06-08 17:15:34 -04: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-08-30 17:18:37 -04:00
const TArray < int32 > SelectedBones = GetSelectedBones ( ) ;
TArray < int32 > NewSelection ;
for ( int32 Bone : SelectedBones )
2019-06-08 17:15:34 -04:00
{
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 )
{
NewSelection . AddUnique ( TransformIdx ) ;
}
}
2019-06-08 17:15:34 -04:00
}
2021-08-30 17:18:37 -04: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 ) ;
}
void FScopedColorEdit : : SetHighlightedBones ( const TArray < int32 > & HighlightedBonesIn )
{
2019-06-08 17:15:34 -04:00
if ( Component - > HighlightedBones ! = HighlightedBonesIn )
{
bUpdated = true ;
Component - > HighlightedBones = HighlightedBonesIn ;
}
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 ) ;
TManagedArray < int > * Levels = nullptr ;
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
{
if ( ChaosSolverActor )
{
return ChaosSolverActor ;
}
else
{
2020-03-09 13:22:54 -04:00
FPhysScene_Chaos const * const Scene = GetInnerChaosScene ( ) ;
2019-06-08 17:15:34 -04:00
return Scene ? Cast < AChaosSolverActor > ( Scene - > GetSolverActor ( ) ) : nullptr ;
}
return nullptr ;
}
void UGeometryCollectionComponent : : CalculateLocalBounds ( )
{
LocalBounds . Init ( ) ;
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-06-16 01:29:49 -04:00
{
// If hierarchy topology has changed, the RestTransforms is invalidated.
if ( RestTransforms . Num ( ) ! = GetTransformArray ( ) . Num ( ) )
{
RestTransforms . Empty ( ) ;
}
if ( ! DynamicCollection & & RestTransforms . Num ( ) > 0 )
{
GeometryCollectionAlgo : : GlobalMatrices ( RestTransforms , GetParentArray ( ) , GlobalMatrices ) ;
}
else
{
// Have to fully rebuild
2021-08-31 20:24:01 -04:00
if ( DynamicCollection & & RestCollection - > bRemoveOnMaxSleep & & DynamicCollection - > HasAttribute ( " SleepTimer " , FGeometryCollection : : TransformGroup ) & & DynamicCollection - > HasAttribute ( " UniformScale " , FGeometryCollection : : TransformGroup ) )
{
const TManagedArray < float > & SleepTimer = DynamicCollection - > GetAttribute < float > ( " SleepTimer " , FGeometryCollection : : TransformGroup ) ;
TManagedArray < float > & UniformScale = DynamicCollection - > GetAttribute < float > ( " UniformScale " , FGeometryCollection : : TransformGroup ) ;
for ( int32 Idx = 0 ; Idx < GetTransformArray ( ) . Num ( ) ; + + Idx )
{
if ( SleepTimer [ Idx ] > RestCollection - > MaximumSleepTime )
{
UniformScale [ Idx ] = 1.0 - FMath : : Min ( 1.0 , ( SleepTimer [ Idx ] - RestCollection - > MaximumSleepTime ) / RestCollection - > RemovalDuration ) ;
}
}
GeometryCollectionAlgo : : GlobalMatrices ( GetTransformArray ( ) , GetParentArray ( ) , UniformScale , DynamicCollection - > MassToLocal , GlobalMatrices ) ;
}
else
{
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 )
{
GlobalMatrices [ tt ] = GlobalMatrices [ tt ] . ConcatTranslation ( ExplodedVectors [ tt ] ) ;
}
}
}
# 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 ;
}
}
// #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-06-16 01:29:49 -04:00
if ( ( TargetComponent - > GetOuter ( ) = = this ) | | ( TargetComponent - > GetOuter ( ) - > IsPendingKill ( ) ) )
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 ( ) ;
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 ) ;
}
}
}
CalculateGlobalMatrices ( ) ;
RefreshEmbeddedGeometry ( ) ;
}
}
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.
if ( DynamicCollection & & PhysicsProxy & & DynamicCollection - > HasAttribute ( " SleepTimer " , FGeometryCollection : : TransformGroup ) )
{
TManagedArray < float > & SleepTimer = DynamicCollection - > GetAttribute < float > ( " SleepTimer " , FGeometryCollection : : TransformGroup ) ;
TArray < int32 > ToDisable ;
for ( int32 TransformIdx = 0 ; TransformIdx < SleepTimer . Num ( ) ; + + TransformIdx )
{
bool PreviouslyAwake = SleepTimer [ TransformIdx ] < RestCollection - > MaximumSleepTime ;
if ( SleepTimer [ TransformIdx ] < ( RestCollection - > MaximumSleepTime + RestCollection - > RemovalDuration ) )
{
SleepTimer [ TransformIdx ] = ( DynamicCollection - > DynamicState [ TransformIdx ] = = ( int ) EObjectStateTypeEnum : : Chaos_Object_Sleeping ) ? SleepTimer [ TransformIdx ] + DeltaTime : 0.0f ;
if ( SleepTimer [ TransformIdx ] > RestCollection - > MaximumSleepTime )
{
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 ) ;
}
}
}