2018-12-14 13:41:00 -05:00
// Copyright 1998-2019 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"
# 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"
# 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 "Chaos/DebugDrawQueue.h"
# include "DrawDebugHelpers.h"
# include "Modules/ModuleManager.h"
# include "ChaosSolversModule.h"
# include "ChaosStats.h"
2019-06-08 17:15:34 -04:00
# include "SolverObjects/GeometryCollectionPhysicsObject.h"
# include "PBDRigidsSolver.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
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
# include "GeometryCollectionComponent.ispc.generated.h"
# endif
DEFINE_LOG_CATEGORY_STATIC ( UGCC_LOG , Error , All ) ;
# if INCLUDE_CHAOS && 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 )
{
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
}
}
}
# endif
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 )
, Simulating ( true )
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 } )
2019-06-08 17:15:34 -04:00
, ClusterConnectionType ( EClusterConnectionTypeEnum : : Chaos_PointImplicit )
, 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 )
2018-12-12 11:25:29 -05:00
, bRenderStateDirty ( true )
2019-06-08 17:15:34 -04:00
, bShowBoneColors ( false )
, 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 )
, PhysicsObject ( 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
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 ;
ChaosMaterial = MakeUnique < Chaos : : TChaosPhysicsMaterial < float > > ( ) ;
WorldBounds = FBoxSphereBounds ( FBox ( ForceInit ) ) ;
// default current cache time
CurrentCacheTime = MAX_flt ;
// Buffer for rolling cache of past N=3 transforms being equal.
TransformsAreEqual . AddDefaulted ( 3 ) ;
TransformsAreEqualIndex = 0 ;
SetGenerateOverlapEvents ( false ) ;
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
2018-12-12 11:25:29 -05:00
# if INCLUDE_CHAOS
2019-06-08 17:15:34 -04:00
Chaos : : FPBDRigidsSolver * GetSolver ( const UGeometryCollectionComponent & GeometryCollectionComponent )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
return GeometryCollectionComponent . ChaosSolverActor ! = nullptr ? GeometryCollectionComponent . ChaosSolverActor - > GetSolver ( ) : GeometryCollectionComponent . GetOwner ( ) - > GetWorld ( ) - > PhysicsScene_Chaos - > GetSolver ( ) ;
2018-12-12 11:25:29 -05:00
}
# endif
void UGeometryCollectionComponent : : BeginPlay ( )
{
Super : : BeginPlay ( ) ;
# if INCLUDE_CHAOS
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);
// ---------- }
// ---------- });
// ---------- }
// ---------- });
//////////////////////////////////////////////////////////////////////////
FChaosSolversModule * ChaosModule = FModuleManager : : Get ( ) . GetModulePtr < FChaosSolversModule > ( " ChaosSolvers " ) ;
if ( ChaosModule ! = nullptr )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
Chaos : : FPBDRigidsSolver * Solver = GetSolver ( * this ) ;
if ( Solver ! = nullptr )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
if ( PhysicsObject ! = nullptr )
{
ChaosModule - > GetDispatcher ( ) - > EnqueueCommand ( Solver , [ & InPhysicsObject = PhysicsObject ] ( Chaos : : FPBDRigidsSolver * InSolver )
{
if ( InPhysicsObject )
{
InPhysicsObject - > ActivateBodies ( ) ;
}
} ) ;
}
}
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
InitializationState = ESimulationInitializationState : : Activated ;
2018-12-12 11:25:29 -05:00
# endif
2019-06-08 17:15:34 -04:00
// default current cache time
CurrentCacheTime = MAX_flt ;
2018-12-12 11:25:29 -05:00
}
void UGeometryCollectionComponent : : EndPlay ( EEndPlayReason : : Type ReasonEnd )
{
# 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
}
FBoxSphereBounds UGeometryCollectionComponent : : CalcBounds ( const FTransform & LocalToWorldIn ) const
2019-06-08 17:15:34 -04:00
{
SCOPE_CYCLE_COUNTER ( STAT_GCCUpdateBounds ) ;
// Don't use bounds calculated in the physics object if we are doing sequencer cache playback
// because we are overriding the transforms in the GC
if ( ! CachePlayback & & WorldBounds . GetSphere ( ) . W > 1e-5 )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
return WorldBounds ;
}
else if ( RestCollection & & RestCollection - > HasVisibleGeometry ( ) )
{
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 ( ) ;
2018-12-12 11:25:29 -05:00
const int32 NumBoxes = BoundingBoxes . Num ( ) ;
2019-06-08 17:15:34 -04:00
// #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
if ( GlobalMatrices . Num ( ) ! = RestCollection - > NumElements ( FGeometryCollection : : TransformGroup ) )
{
TArray < FMatrix > TmpGlobalMatrices ;
GeometryCollectionAlgo : : GlobalMatrices ( GetTransformArray ( ) , ParentIndices , TmpGlobalMatrices ) ;
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 ) ;
}
}
}
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 ) ;
}
void UGeometryCollectionComponent : : CreateRenderState_Concurrent ( )
{
Super : : CreateRenderState_Concurrent ( ) ;
2019-06-08 17:15:34 -04:00
if ( SceneProxy & & RestCollection & & RestCollection - > HasVisibleGeometry ( ) )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
FGeometryCollectionSceneProxy * const GeometryCollectionSceneProxy = static_cast < FGeometryCollectionSceneProxy * > ( SceneProxy ) ;
# if GEOMETRYCOLLECTION_EDITOR_SELECTION
// Re-init subsections
if ( bIsTransformSelectionModeEnabled )
{
GeometryCollectionSceneProxy - > UseSubSections ( true , false ) ; // Do not force reinit now, it'll be done in SetConstantData_RenderThread
}
# endif // #if GEOMETRYCOLLECTION_EDITOR_SELECTION
FGeometryCollectionConstantData * const ConstantData = : : new FGeometryCollectionConstantData ;
2018-12-12 11:25:29 -05:00
InitConstantData ( ConstantData ) ;
2019-06-08 17:15:34 -04:00
FGeometryCollectionDynamicData * const DynamicData = : : new FGeometryCollectionDynamicData ;
2018-12-12 11:25:29 -05:00
InitDynamicData ( DynamicData ) ;
2019-06-08 17:15:34 -04:00
ENQUEUE_RENDER_COMMAND ( CreateRenderState ) (
2019-02-07 10:35:08 -05:00
[ GeometryCollectionSceneProxy , ConstantData , DynamicData ] ( FRHICommandListImmediate & RHICmdList )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
if ( GeometryCollectionSceneProxy )
{
GeometryCollectionSceneProxy - > SetConstantData_RenderThread ( ConstantData ) ;
GeometryCollectionSceneProxy - > SetDynamicData_RenderThread ( DynamicData ) ;
}
}
) ;
2018-12-12 11:25:29 -05:00
}
}
FPrimitiveSceneProxy * UGeometryCollectionComponent : : CreateSceneProxy ( )
{
2019-06-08 17:15:34 -04:00
if ( RestCollection )
2018-12-12 11:25:29 -05:00
{
return new FGeometryCollectionSceneProxy ( this ) ;
}
return nullptr ;
}
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-06-08 17:15:34 -04:00
return PhysicsObject ! = 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 ( ) ;
}
}
FBodyInstance * UGeometryCollectionComponent : : GetBodyInstance ( FName BoneName /*= NAME_None*/ , bool bGetWelded /*= true*/ ) const
{
return nullptr ; // const_cast<FBodyInstance*>(&DummyBodyInstance);
}
void UGeometryCollectionComponent : : SetNotifyRigidBodyCollision ( bool bNewNotifyRigidBodyCollision )
{
Super : : SetNotifyRigidBodyCollision ( bNewNotifyRigidBodyCollision ) ;
UpdateRBCollisionEventRegistration ( ) ;
}
void UGeometryCollectionComponent : : DispatchBreakEvent ( const FChaosBreakEvent & Event )
{
// native
NotifyBreak ( Event ) ;
// bp
if ( OnChaosBreakEvent . IsBound ( ) )
{
OnChaosBreakEvent . Broadcast ( Event ) ;
}
}
static void DispatchGeometryCollectionBreakEvent ( const FChaosBreakEvent & Event )
{
if ( UGeometryCollectionComponent * const GC = Cast < UGeometryCollectionComponent > ( Event . Component ) )
{
GC - > DispatchBreakEvent ( Event ) ;
}
}
void UGeometryCollectionComponent : : DispatchChaosPhysicsCollisionBlueprintEvents ( const FChaosPhysicsCollisionInfo & CollisionInfo )
{
ReceivePhysicsCollision ( CollisionInfo ) ;
OnChaosPhysicsCollision . Broadcast ( CollisionInfo ) ;
}
// call when first registering
void UGeometryCollectionComponent : : RegisterForEvents ( )
{
# if INCLUDE_CHAOS
if ( BodyInstance . bNotifyRigidBodyCollision | | bNotifyBreaks | | bNotifyCollisions )
{
if ( AChaosSolverActor * const SolverActor = GetPhysicsSolverActor ( ) )
{
if ( UChaosGameplayEventDispatcher * const EventDispatcher = SolverActor - > GetGameplayEventDispatcher ( ) )
{
if ( bNotifyCollisions | | BodyInstance . bNotifyRigidBodyCollision )
{
EventDispatcher - > RegisterForCollisionEvents ( this , this ) ;
}
if ( bNotifyBreaks )
{
EventDispatcher - > RegisterForBreakEvents ( this , & DispatchGeometryCollectionBreakEvent ) ;
}
}
}
}
# endif
}
void UGeometryCollectionComponent : : UpdateRBCollisionEventRegistration ( )
{
# if INCLUDE_CHAOS
if ( AChaosSolverActor * const SolverActor = GetPhysicsSolverActor ( ) )
{
if ( UChaosGameplayEventDispatcher * const EventDispatcher = SolverActor - > GetGameplayEventDispatcher ( ) )
{
if ( bNotifyCollisions | | BodyInstance . bNotifyRigidBodyCollision )
{
EventDispatcher - > RegisterForCollisionEvents ( this , this ) ;
}
else
{
EventDispatcher - > UnRegisterForCollisionEvents ( this , this ) ;
}
}
}
# endif
}
void UGeometryCollectionComponent : : UpdateBreakEventRegistration ( )
{
# if INCLUDE_CHAOS
if ( AChaosSolverActor * const SolverActor = GetPhysicsSolverActor ( ) )
{
if ( UChaosGameplayEventDispatcher * const EventDispatcher = SolverActor - > GetGameplayEventDispatcher ( ) )
{
if ( bNotifyBreaks )
{
EventDispatcher - > RegisterForBreakEvents ( this , & DispatchGeometryCollectionBreakEvent ) ;
}
else
{
EventDispatcher - > UnRegisterForBreakEvents ( this ) ;
}
}
}
# endif
}
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 ) ;
2019-06-08 17:15:34 -04:00
const int32 NumPoints = Collection - > NumElements ( FGeometryCollection : : VerticesGroup ) ;
const TManagedArray < FVector > & Vertex = Collection - > Vertex ;
const TManagedArray < int32 > & BoneMap = Collection - > BoneMap ;
const TManagedArray < FVector > & TangentU = Collection - > TangentU ;
const TManagedArray < FVector > & TangentV = Collection - > TangentV ;
const TManagedArray < FVector > & Normal = Collection - > Normal ;
const TManagedArray < FVector2D > & UV = Collection - > UV ;
const TManagedArray < FLinearColor > & Color = Collection - > Color ;
const TManagedArray < FLinearColor > & BoneColors = Collection - > BoneColor ;
ConstantData - > Vertices = TArray < FVector > ( Vertex . GetData ( ) , Vertex . Num ( ) ) ;
ConstantData - > BoneMap = TArray < int32 > ( BoneMap . GetData ( ) , BoneMap . Num ( ) ) ;
ConstantData - > TangentU = TArray < FVector > ( TangentU . GetData ( ) , TangentU . Num ( ) ) ;
ConstantData - > TangentV = TArray < FVector > ( TangentV . GetData ( ) , TangentV . Num ( ) ) ;
ConstantData - > Normals = TArray < FVector > ( Normal . GetData ( ) , Normal . Num ( ) ) ;
ConstantData - > UVs = TArray < FVector2D > ( UV . GetData ( ) , UV . Num ( ) ) ;
ConstantData - > Colors = TArray < FLinearColor > ( Color . GetData ( ) , Color . Num ( ) ) ;
2018-12-12 11:25:29 -05:00
ConstantData - > BoneColors . AddUninitialized ( NumPoints ) ;
2019-06-08 17:15:34 -04:00
ParallelFor ( NumPoints , [ & ] ( const int32 InPointIndex )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
const int32 BoneIndex = ConstantData - > BoneMap [ InPointIndex ] ;
ConstantData - > BoneColors [ InPointIndex ] = BoneColors [ BoneIndex ] ;
2018-12-12 11:25:29 -05:00
} ) ;
int32 NumIndices = 0 ;
2019-06-08 17:15:34 -04:00
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
const TManagedArray < int32 > & MaterialIndex = Collection - > MaterialIndex ;
const int32 NumFaceGroupEntries = Collection - > NumElements ( FGeometryCollection : : FacesGroup ) ;
for ( int FaceIndex = 0 ; FaceIndex < NumFaceGroupEntries ; + + FaceIndex )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
NumIndices + = static_cast < int > ( Visible [ FaceIndex ] ) ;
2018-12-12 11:25:29 -05:00
}
ConstantData - > Indices . AddUninitialized ( NumIndices ) ;
2019-06-08 17:15:34 -04:00
for ( int IndexIdx = 0 , cdx = 0 ; IndexIdx < NumFaceGroupEntries ; + + IndexIdx )
2018-12-12 11:25:29 -05:00
{
if ( Visible [ MaterialIndex [ IndexIdx ] ] )
{
ConstantData - > Indices [ cdx + + ] = Indices [ MaterialIndex [ IndexIdx ] ] ;
}
}
// 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
2019-06-08 17:15:34 -04:00
const int32 NumMaterialSections = Collection - > NumElements ( FGeometryCollection : : MaterialGroup ) ;
2018-12-12 11:25:29 -05:00
ConstantData - > Sections . AddUninitialized ( NumMaterialSections ) ;
2019-06-08 17:15:34 -04:00
const TManagedArray < FGeometryCollectionSection > & Sections = Collection - > Sections ;
for ( int SectionIndex = 0 ; SectionIndex < NumMaterialSections ; + + SectionIndex )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
FGeometryCollectionSection Section = Sections [ SectionIndex ] ; // deliberate copy
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
for ( int32 TriangleIndex = 0 ; TriangleIndex < Sections [ SectionIndex ] . FirstIndex / 3 ; TriangleIndex + + )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
if ( ! Visible [ MaterialIndex [ TriangleIndex ] ] )
{
Section . FirstIndex - = 3 ;
}
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
for ( int32 TriangleIndex = 0 ; TriangleIndex < Sections [ SectionIndex ] . NumTriangles ; TriangleIndex + + )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
if ( ! Visible [ MaterialIndex [ Sections [ SectionIndex ] . FirstIndex / 3 + TriangleIndex ] ] )
{
2018-12-12 11:25:29 -05:00
Section . NumTriangles - - ;
2019-06-08 17:15:34 -04:00
}
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
ConstantData - > Sections [ SectionIndex ] = MoveTemp ( Section ) ;
}
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 ;
const TManagedArray < int32 > & FaceStart = Collection - > FaceStart ;
const TManagedArray < int32 > & FaceCount = Collection - > FaceCount ;
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
if ( Visible [ FaceIndex ] & & MaterialID [ FaceIndex ] % 2 = = 0 )
{
BaseMeshIndices . Add ( Indices [ FaceIndex ] ) ;
BaseMeshOriginalFaceIndices . Add ( FaceIndex ) ;
}
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
// We should always have external faces of a geometry collection
ensure ( BaseMeshIndices . Num ( ) > 0 ) ;
// #todo(dmp): we should eventually get this working where we use geometry nodes
// that signify original unfractured geometry. For now, this system is broken.
/*
for ( int i = 0 ; i < Collection - > NumElements ( FGeometryCollection : : TransformGroup ) ; + + i )
{
const FGeometryCollectionBoneNode & CurrBone = BoneHierarchy [ i ] ;
// root node could be parent geo
if ( CurrBone . Parent = = INDEX_NONE )
{
int32 GeometryIndex = TransformToGeometryIndex [ i ] ;
// found geometry associated with base mesh root node
if ( GeometryIndex ! = INDEX_NONE )
{
int32 CurrFaceStart = FaceStart [ GeometryIndex ] ;
int32 CurrFaceCount = FaceCount [ GeometryIndex ] ;
// add all the faces to the original geometry face array
for ( int face = CurrFaceStart ; face < CurrFaceStart + CurrFaceCount ; + + face )
{
BaseMeshIndices . Add ( Indices [ face ] ) ;
BaseMeshOriginalFaceIndices . Add ( face ) ;
}
// build an array of mesh sections
ConstantData - > HasOriginalMesh = true ;
}
else
{
// all the direct decedents of the root node with no geometry are original geometry
for ( int32 CurrChild : CurrBone . Children )
{
int32 GeometryIndex = TransformToGeometryIndex [ CurrChild ] ;
if ( GeometryIndex ! = INDEX_NONE )
{
// original geo static mesh
int32 CurrFaceStart = FaceStart [ GeometryIndex ] ;
int32 CurrFaceCount = FaceCount [ GeometryIndex ] ;
// add all the faces to the original geometry face array
for ( int face = CurrFaceStart ; face < CurrFaceStart + CurrFaceCount ; + + face )
{
BaseMeshIndices . Add ( Indices [ face ] ) ;
BaseMeshOriginalFaceIndices . Add ( face ) ;
}
ConstantData - > HasOriginalMesh = true ;
}
}
}
}
}
*/
ConstantData - > OriginalMeshSections = Collection - > BuildMeshSections ( BaseMeshIndices , BaseMeshOriginalFaceIndices , ConstantData - > OriginalMeshIndices ) ;
TArray < FMatrix > RestMatrices ;
GeometryCollectionAlgo : : GlobalMatrices ( RestCollection - > GetGeometryCollection ( ) - > Transform , RestCollection - > GetGeometryCollection ( ) - > Parent , RestMatrices ) ;
ConstantData - > RestTransforms = MoveTemp ( RestMatrices ) ;
2018-12-12 11:25:29 -05:00
}
void UGeometryCollectionComponent : : InitDynamicData ( FGeometryCollectionDynamicData * DynamicData )
{
2019-06-08 17:15:34 -04:00
SCOPE_CYCLE_COUNTER ( STAT_GCInitDynamicData ) ;
2018-12-12 11:25:29 -05:00
check ( DynamicData ) ;
2019-06-08 17:15:34 -04:00
DynamicData - > IsDynamic = this - > GetIsObjectDynamic ( ) | | bShowBoneColors | | bEnableBoneSelection ;
DynamicData - > IsLoading = this - > GetIsObjectLoading ( ) ;
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
if ( CachePlayback & & CacheParameters . TargetCache & & CacheParameters . TargetCache - > GetData ( ) )
{
const TManagedArray < int32 > & Parents = GetParentArray ( ) ;
const TManagedArray < TSet < int32 > > & Children = GetChildrenArray ( ) ;
const TManagedArray < FTransform > & Transform = RestCollection - > GetGeometryCollection ( ) - > Transform ;
const TManagedArray < FTransform > & MassToLocal = RestCollection - > GetGeometryCollection ( ) - > GetAttribute < FTransform > ( " MassToLocal " , FGeometryCollection : : TransformGroup ) ;
2018-12-12 11:25:29 -05:00
2019-07-16 19:12:23 -04:00
// #todo(dmp): find a better place to calculate and store this
float CacheDt = CacheParameters . TargetCache - > GetData ( ) - > GetDt ( ) ;
// if we want the state before the first cached frame, then the collection doesn't need to be dynamic since it'll render the pre-fractured geometry
DynamicData - > IsDynamic = DesiredCacheTime > CacheDt ;
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
// if we are already on the current cached frame, return
if ( FMath : : IsNearlyEqual ( CurrentCacheTime , DesiredCacheTime ) & & GlobalMatrices . Num ( ) ! = 0 )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
DynamicData - > PrevTransforms = GlobalMatrices ;
DynamicData - > Transforms = GlobalMatrices ;
2019-07-16 19:12:23 -04:00
// maintaining the cache time means we should consider the transforms equal for dynamic data sending purposes
TransformsAreEqual [ ( TransformsAreEqualIndex + + ) % TransformsAreEqual . Num ( ) ] = true ;
2019-06-08 17:15:34 -04:00
return ;
}
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
// if the input simulation time to playback is the first frame, reset simulation time
if ( DesiredCacheTime < = CacheDt | | FMath : : IsNearlyEqual ( CurrentCacheTime , FLT_MAX ) )
{
CurrentCacheTime = DesiredCacheTime ;
GeometryCollectionAlgo : : GlobalMatrices ( GetTransformArray ( ) , GetParentArray ( ) , GlobalMatrices ) ;
DynamicData - > PrevTransforms = GlobalMatrices ;
DynamicData - > Transforms = GlobalMatrices ;
EventsPlayed . Empty ( ) ;
EventsPlayed . AddDefaulted ( CacheParameters . TargetCache - > GetData ( ) - > Records . Num ( ) ) ;
2019-07-16 19:12:23 -04:00
// reset should send new transforms to the RT
TransformsAreEqual [ ( TransformsAreEqualIndex + + ) % TransformsAreEqual . Num ( ) ] = false ;
2019-06-08 17:15:34 -04:00
}
else if ( GlobalMatrices . Num ( ) = = 0 )
{
// bad case here. Sequencer starts at non zero position We cannot correctly reconstruct the current frame, so give a warning
GeometryCollectionAlgo : : GlobalMatrices ( GetTransformArray ( ) , GetParentArray ( ) , GlobalMatrices ) ;
DynamicData - > PrevTransforms = GlobalMatrices ;
DynamicData - > Transforms = GlobalMatrices ;
EventsPlayed . Empty ( ) ;
EventsPlayed . AddDefaulted ( CacheParameters . TargetCache - > GetData ( ) - > Records . Num ( ) ) ;
2019-07-16 19:12:23 -04:00
// degenerate case causes and reset should send new transforms to the RT
TransformsAreEqual [ ( TransformsAreEqualIndex + + ) % TransformsAreEqual . Num ( ) ] = false ;
2019-06-08 17:15:34 -04:00
UE_LOG ( UGCC_LOG , Warning , TEXT ( " Cache out of sync - must rewind sequencer to start frame " ) ) ;
}
else if ( DesiredCacheTime > = CurrentCacheTime )
{
int NumSteps = floor ( ( DesiredCacheTime - CurrentCacheTime ) / CacheDt ) ;
float LastDt = FMath : : Fmod ( DesiredCacheTime - CurrentCacheTime , CacheDt ) ;
NumSteps + = LastDt > SMALL_NUMBER ? 1 : 0 ;
FTransform ActorToWorld = GetComponentTransform ( ) ;
2019-07-16 19:12:23 -04:00
bool HasAnyActiveTransforms = false ;
2019-06-08 17:15:34 -04:00
// Jump ahead in increments of CacheDt evaluating the cache until we reach our desired time
for ( int st = 0 ; st < NumSteps ; + + st )
{
float TimeIncrement = st = = NumSteps - 1 ? LastDt : CacheDt ;
CurrentCacheTime + = TimeIncrement ;
DynamicData - > PrevTransforms = GlobalMatrices ;
const FRecordedFrame * FirstFrame = nullptr ;
const FRecordedFrame * SecondFrame = nullptr ;
2019-07-16 19:12:23 -04:00
CacheParameters . TargetCache - > GetData ( ) - > GetFramesForTime ( CurrentCacheTime , FirstFrame , SecondFrame ) ;
2019-06-08 17:15:34 -04:00
if ( FirstFrame & & ! SecondFrame )
{
const TArray < FTransform > & xforms = FirstFrame - > Transforms ;
const TArray < int32 > & TransformIndices = FirstFrame - > TransformIndices ;
const int32 NumActives = FirstFrame - > TransformIndices . Num ( ) ;
2019-07-16 19:12:23 -04:00
if ( NumActives > 0 )
{
HasAnyActiveTransforms = true ;
}
2019-06-08 17:15:34 -04:00
for ( int i = 0 ; i < NumActives ; + + i )
{
const int32 InternalIndexTmp = TransformIndices [ i ] ;
if ( InternalIndexTmp > = GlobalMatrices . Num ( ) )
{
UE_LOG ( UGCC_LOG , Error ,
TEXT ( " %s: TargetCache (%s) is out of sync with GeometryCollection. Regenerate the cache. " ) ,
* RestCollection - > GetName ( ) , * CacheParameters . TargetCache - > GetName ( ) ) ;
DynamicData - > PrevTransforms = GlobalMatrices ;
DynamicData - > Transforms = GlobalMatrices ;
return ;
}
// calculate global matrix for current
FTransform ParticleToWorld = xforms [ i ] ;
FTransform CurrGlobalTransform = MassToLocal [ InternalIndexTmp ] . GetRelativeTransformReverse ( ParticleToWorld ) . GetRelativeTransform ( ActorToWorld ) ;
CurrGlobalTransform . NormalizeRotation ( ) ;
GlobalMatrices [ InternalIndexTmp ] = CurrGlobalTransform . ToMatrixWithScale ( ) ;
// Traverse from active parent node down to all children and set global transforms
GeometryCollectionAlgo : : GlobalMatricesFromRoot ( InternalIndexTmp , Transform , Children , GlobalMatrices ) ;
}
}
2019-07-16 19:12:23 -04:00
else if ( FirstFrame & & SecondFrame & & CurrentCacheTime > FirstFrame - > Timestamp )
2019-06-08 17:15:34 -04:00
{
2019-07-16 19:12:23 -04:00
const float Alpha = ( CurrentCacheTime - FirstFrame - > Timestamp ) / ( SecondFrame - > Timestamp - FirstFrame - > Timestamp ) ;
2019-06-08 17:15:34 -04:00
check ( 0 < = Alpha & & Alpha < = 1.0f ) ;
const int32 NumActives = SecondFrame - > TransformIndices . Num ( ) ;
2019-07-16 19:12:23 -04:00
if ( NumActives > 0 )
{
HasAnyActiveTransforms = true ;
}
2019-06-08 17:15:34 -04:00
for ( int Index = 0 ; Index < NumActives ; + + Index )
{
const int32 InternalIndexTmp = SecondFrame - > TransformIndices [ Index ] ;
// check if transform index is valid
if ( InternalIndexTmp > = GlobalMatrices . Num ( ) )
{
UE_LOG ( UGCC_LOG , Error ,
TEXT ( " %s: TargetCache (%s) is out of sync with GeometryCollection. Regenerate the cache. " ) ,
* RestCollection - > GetName ( ) , * CacheParameters . TargetCache - > GetName ( ) ) ;
DynamicData - > PrevTransforms = GlobalMatrices ;
DynamicData - > Transforms = GlobalMatrices ;
return ;
}
const int32 PreviousIndexSlot = Index < SecondFrame - > PreviousTransformIndices . Num ( ) ? SecondFrame - > PreviousTransformIndices [ Index ] : INDEX_NONE ;
if ( PreviousIndexSlot ! = INDEX_NONE )
{
FTransform ParticleToWorld ;
ParticleToWorld . Blend ( FirstFrame - > Transforms [ PreviousIndexSlot ] , SecondFrame - > Transforms [ Index ] , Alpha ) ;
FTransform CurrGlobalTransform = MassToLocal [ InternalIndexTmp ] . GetRelativeTransformReverse ( ParticleToWorld ) . GetRelativeTransform ( ActorToWorld ) ;
CurrGlobalTransform . NormalizeRotation ( ) ;
GlobalMatrices [ InternalIndexTmp ] = CurrGlobalTransform . ToMatrixWithScale ( ) ;
// Traverse from active parent node down to all children and set global transforms
GeometryCollectionAlgo : : GlobalMatricesFromRoot ( InternalIndexTmp , Transform , Children , GlobalMatrices ) ;
}
else
{
FTransform ParticleToWorld = SecondFrame - > Transforms [ Index ] ;
FTransform CurrGlobalTransform = MassToLocal [ InternalIndexTmp ] . GetRelativeTransformReverse ( ParticleToWorld ) . GetRelativeTransform ( ActorToWorld ) ;
CurrGlobalTransform . NormalizeRotation ( ) ;
GlobalMatrices [ InternalIndexTmp ] = CurrGlobalTransform . ToMatrixWithScale ( ) ;
// Traverse from active parent node down to all children and set global transforms
GeometryCollectionAlgo : : GlobalMatricesFromRoot ( InternalIndexTmp , Transform , Children , GlobalMatrices ) ;
}
}
}
DynamicData - > Transforms = GlobalMatrices ;
/**********************************************************************************************************************************************************************************/
// Capture all events for the given time
if ( false )
{
# if INCLUDE_CHAOS
// clear events on the solver
Chaos : : FPBDRigidsSolver * Solver = GetSolver ( * this ) ;
if ( Solver )
{
Chaos : : FSolverWriteLock ScopedWriteLock ( Solver ) ;
//////////////////////////////////////////////////////////////////////////
// Temporary workaround for writing on multiple threads.
// The following is called wide from the render thread to populate
// Niagara data from a cache without invoking a solver directly
//
// The above write lock guarantees we can safely write to these buffers
//
// TO BE REFACTORED
// #TODO BG
//////////////////////////////////////////////////////////////////////////
Chaos : : FPBDRigidsSolver : : FAllCollisionData * CollisionDataToWriteTo = const_cast < Chaos : : FPBDRigidsSolver : : FAllCollisionData * > ( Solver - > GetAllCollisions_FromSequencerCache_NEEDSLOCK ( ) ) ;
Chaos : : FPBDRigidsSolver : : FAllBreakingData * BreakingDataToWriteTo = const_cast < Chaos : : FPBDRigidsSolver : : FAllBreakingData * > ( Solver - > GetAllBreakings_FromSequencerCache_NEEDSLOCK ( ) ) ;
Chaos : : FPBDRigidsSolver : : FAllTrailingData * TrailingDataToWriteTo = const_cast < Chaos : : FPBDRigidsSolver : : FAllTrailingData * > ( Solver - > GetAllTrailings_FromSequencerCache_NEEDSLOCK ( ) ) ;
if ( ! FMath : : IsNearlyEqual ( CollisionDataToWriteTo - > TimeCreated , DesiredCacheTime ) )
{
CollisionDataToWriteTo - > AllCollisionsArray . Empty ( ) ;
CollisionDataToWriteTo - > TimeCreated = DesiredCacheTime ;
}
int32 Index = CacheParameters . TargetCache - > GetData ( ) - > FindLastKeyBefore ( CurrentCacheTime ) ;
const FRecordedFrame * RecordedFrame = & CacheParameters . TargetCache - > GetData ( ) - > Records [ Index ] ;
if ( RecordedFrame & & PhysicsObject & & ! EventsPlayed [ Index ] )
{
EventsPlayed [ Index ] = true ;
// Collisions
if ( RecordedFrame - > Collisions . Num ( ) > 0 )
{
for ( int32 Idx = 0 ; Idx < RecordedFrame - > Collisions . Num ( ) ; + + Idx )
{
// Check if the particle is still kinematic
int32 NewIdx = CollisionDataToWriteTo - > AllCollisionsArray . Add ( Chaos : : TCollisionData < float , 3 > ( ) ) ;
Chaos : : TCollisionData < float , 3 > & AllCollisionsDataArrayItem = CollisionDataToWriteTo - > AllCollisionsArray [ NewIdx ] ;
AllCollisionsDataArrayItem . Location = RecordedFrame - > Collisions [ Idx ] . Location ;
AllCollisionsDataArrayItem . AccumulatedImpulse = RecordedFrame - > Collisions [ Idx ] . AccumulatedImpulse ;
AllCollisionsDataArrayItem . Normal = RecordedFrame - > Collisions [ Idx ] . Normal ;
AllCollisionsDataArrayItem . Velocity1 = RecordedFrame - > Collisions [ Idx ] . Velocity1 ;
AllCollisionsDataArrayItem . Velocity2 = RecordedFrame - > Collisions [ Idx ] . Velocity2 ;
AllCollisionsDataArrayItem . AngularVelocity1 = RecordedFrame - > Collisions [ Idx ] . AngularVelocity1 ;
AllCollisionsDataArrayItem . AngularVelocity2 = RecordedFrame - > Collisions [ Idx ] . AngularVelocity2 ;
AllCollisionsDataArrayItem . Mass1 = RecordedFrame - > Collisions [ Idx ] . Mass1 ;
AllCollisionsDataArrayItem . Mass2 = RecordedFrame - > Collisions [ Idx ] . Mass2 ;
AllCollisionsDataArrayItem . ParticleIndex = RecordedFrame - > Collisions [ Idx ] . ParticleIndex ;
AllCollisionsDataArrayItem . LevelsetIndex = RecordedFrame - > Collisions [ Idx ] . LevelsetIndex ;
AllCollisionsDataArrayItem . ParticleIndexMesh = RecordedFrame - > Collisions [ Idx ] . ParticleIndexMesh ;
AllCollisionsDataArrayItem . LevelsetIndexMesh = RecordedFrame - > Collisions [ Idx ] . LevelsetIndexMesh ;
}
}
// Breaking
if ( RecordedFrame - > Breakings . Num ( ) > 0 )
{
for ( int32 Idx = 0 ; Idx < RecordedFrame - > Breakings . Num ( ) ; + + Idx )
{
// Check if the particle is still kinematic
int32 NewIdx = BreakingDataToWriteTo - > AllBreakingsArray . Add ( Chaos : : TBreakingData < float , 3 > ( ) ) ;
Chaos : : TBreakingData < float , 3 > & AllBreakingsDataArrayItem = BreakingDataToWriteTo - > AllBreakingsArray [ NewIdx ] ;
AllBreakingsDataArrayItem . Location = RecordedFrame - > Breakings [ Idx ] . Location ;
AllBreakingsDataArrayItem . Velocity = RecordedFrame - > Breakings [ Idx ] . Velocity ;
AllBreakingsDataArrayItem . AngularVelocity = RecordedFrame - > Breakings [ Idx ] . AngularVelocity ;
AllBreakingsDataArrayItem . Mass = RecordedFrame - > Breakings [ Idx ] . Mass ;
AllBreakingsDataArrayItem . ParticleIndex = RecordedFrame - > Breakings [ Idx ] . ParticleIndex ;
AllBreakingsDataArrayItem . ParticleIndexMesh = RecordedFrame - > Breakings [ Idx ] . ParticleIndexMesh ;
}
}
// Trailing
if ( RecordedFrame - > Trailings . Num ( ) > 0 )
{
for ( FSolverTrailingData Trailing : RecordedFrame - > Trailings )
{
// Check if the particle is still kinematic
int32 NewIdx = TrailingDataToWriteTo - > AllTrailingsArray . Add ( Chaos : : TTrailingData < float , 3 > ( ) ) ;
Chaos : : TTrailingData < float , 3 > & AllTrailingsDataArrayItem = TrailingDataToWriteTo - > AllTrailingsArray [ NewIdx ] ;
AllTrailingsDataArrayItem . Location = Trailing . Location ;
AllTrailingsDataArrayItem . Velocity = Trailing . Velocity ;
AllTrailingsDataArrayItem . AngularVelocity = Trailing . AngularVelocity ;
AllTrailingsDataArrayItem . Mass = Trailing . Mass ;
AllTrailingsDataArrayItem . ParticleIndex = Trailing . ParticleIndex ;
AllTrailingsDataArrayItem . ParticleIndexMesh = Trailing . ParticleIndexMesh ;
}
}
}
}
# endif
}
}
2019-07-16 19:12:23 -04:00
// check if transforms at start of this tick are the same as what is calculated from the cache
TransformsAreEqual [ ( TransformsAreEqualIndex + + ) % TransformsAreEqual . Num ( ) ] = ! HasAnyActiveTransforms ;
2019-06-08 17:15:34 -04:00
}
else
{
// time is before current cache time so maintain the matrices we have since we can't rewind
DynamicData - > PrevTransforms = GlobalMatrices ;
DynamicData - > Transforms = GlobalMatrices ;
2019-07-16 19:12:23 -04:00
// reset event means we don't want to consider transforms as being equal between prev and current frame
TransformsAreEqual [ ( TransformsAreEqualIndex + + ) % TransformsAreEqual . Num ( ) ] = true ;
2019-06-08 17:15:34 -04:00
}
}
else if ( DynamicData - > IsDynamic )
{
// 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
CalculateGlobalMatrices ( ) ;
DynamicData - > PrevTransforms = GlobalMatrices ;
DynamicData - > Transforms = GlobalMatrices ;
2019-07-16 19:12:23 -04:00
// reset event means we don't want to consider transforms as being equal between prev and current frame
TransformsAreEqual [ ( TransformsAreEqualIndex + + ) % TransformsAreEqual . Num ( ) ] = false ;
2019-06-08 17:15:34 -04:00
}
else
{
// Copy existing global matrices into prev transforms
DynamicData - > PrevTransforms = GlobalMatrices ;
// Copy global matrices over to DynamicData
CalculateGlobalMatrices ( ) ;
// if the number of matrices has changed between frames, then sync previous to current
if ( GlobalMatrices . Num ( ) ! = DynamicData - > PrevTransforms . Num ( ) )
{
DynamicData - > PrevTransforms = GlobalMatrices ;
}
DynamicData - > Transforms = GlobalMatrices ;
2019-07-16 19:12:23 -04:00
// check if previous transforms are the same as current
TransformsAreEqual [ ( TransformsAreEqualIndex + + ) % TransformsAreEqual . Num ( ) ] = IsEqual ( DynamicData - > PrevTransforms , DynamicData - > Transforms ) ;
}
}
2019-06-08 17:15:34 -04:00
}
2018-12-12 11:25:29 -05:00
# if CHAOS_DEBUG_DRAW
void DebugDrawChaos ( UWorld * World )
{
if ( ! World - > IsGameWorld ( ) )
{
return ;
}
using namespace Chaos ;
TArray < FLatentDrawCommand > LatenetDrawCommands ;
FDebugDrawQueue : : GetInstance ( ) . ExtractAllElements ( LatenetDrawCommands ) ;
for ( const FLatentDrawCommand & Command : LatenetDrawCommands )
{
switch ( Command . Type )
{
case FLatentDrawCommand : : EDrawType : : Point :
{
DrawDebugPoint ( World , Command . LineStart , Command . Thickness , Command . Color , Command . bPersistentLines , Command . LifeTime , Command . DepthPriority ) ;
break ;
}
case FLatentDrawCommand : : EDrawType : : Line :
{
DrawDebugLine ( World , Command . LineStart , Command . LineEnd , Command . Color , Command . bPersistentLines , Command . LifeTime , Command . DepthPriority , Command . Thickness ) ;
break ;
}
case FLatentDrawCommand : : EDrawType : : DirectionalArrow :
{
DrawDebugDirectionalArrow ( World , Command . LineStart , Command . LineEnd , Command . ArrowSize , Command . Color , Command . bPersistentLines , Command . LifeTime , Command . DepthPriority , Command . Thickness ) ;
break ;
}
case FLatentDrawCommand : : EDrawType : : Sphere :
{
DrawDebugSphere ( World , Command . LineStart , Command . Radius , Command . Segments , Command . Color , Command . bPersistentLines , Command . LifeTime , Command . DepthPriority , Command . Thickness ) ;
break ;
}
case FLatentDrawCommand : : EDrawType : : Box :
{
DrawDebugBox ( World , Command . Center , Command . Extent , Command . Rotation , Command . Color , Command . bPersistentLines , Command . LifeTime , Command . DepthPriority , Command . Thickness ) ;
break ;
}
default :
break ;
}
}
}
# endif
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 ) ;
2019-06-08 17:15:34 -04:00
//if (bRenderStateDirty && DynamicCollection) //todo: always send for now
if ( RestCollection )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
//if (RestCollection->HasVisibleGeometry() || DynamicCollection->IsDirty())
if ( RestCollection - > HasVisibleGeometry ( ) )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
MarkRenderTransformDirty ( ) ;
2018-12-12 11:25:29 -05:00
MarkRenderDynamicDataDirty ( ) ;
bRenderStateDirty = false ;
2019-06-08 17:15:34 -04:00
//DynamicCollection->MakeClean(); clean?
// const UWorld* MyWorld = GetWorld();
// if (MyWorld && MyWorld->IsGameWorld())
// {
// //cycle every 0xff frames
// //@todo - Need way of seeing if the collection is actually changing
// if (bNavigationRelevant && bRegistered && (((GFrameCounter + NavmeshInvalidationTimeSliceIndex) & 0xff) == 0))
// {
// UpdateNavigationData();
// }
// }
2018-12-12 11:25:29 -05:00
}
}
# if CHAOS_DEBUG_DRAW
using namespace Chaos ;
// General debug drawing
if ( FDebugDrawQueue : : EnableDebugDrawing )
{
if ( UWorld * World = GetWorld ( ) )
{
DebugDrawChaos ( World ) ;
}
}
# endif
}
void UGeometryCollectionComponent : : OnRegister ( )
{
//UE_LOG(UGCC_LOG, Log, TEXT("GeometryCollectionComponent[%p]::OnRegister()[%p]"), this,RestCollection );
ResetDynamicCollection ( ) ;
2019-07-23 16:27:28 -04:00
2019-07-24 13:03:22 -04:00
# if WITH_EDITOR
FScopedColorEdit ColorEdit ( this ) ;
2019-07-23 16:27:28 -04:00
ColorEdit . ResetBoneSelection ( ) ;
ColorEdit . ResetHighlightedBones ( ) ;
2019-07-24 13:03:22 -04:00
# endif
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 ( ) ;
SetRenderStateDirty ( ) ;
}
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 ( )
{
2019-06-08 17:15:34 -04:00
# if WITH_PHYSX
DummyBodySetup = NewObject < UBodySetup > ( this , UBodySetup : : StaticClass ( ) ) ;
DummyBodySetup - > AggGeom . BoxElems . Add ( FKBoxElem ( 1.0f ) ) ;
DummyBodyInstance . InitBody ( DummyBodySetup , GetComponentToWorld ( ) , this , nullptr ) ;
DummyBodyInstance . bNotifyRigidBodyCollision = BodyInstance . bNotifyRigidBodyCollision ;
# endif
2018-12-12 11:25:29 -05:00
// Skip the chain - don't care about body instance setup
UActorComponent : : OnCreatePhysicsState ( ) ;
2019-06-08 17:15:34 -04:00
if ( ! Simulating ) IsObjectLoading = false ; // just mark as loaded if we are simulating.
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
# if WITH_PHYSX
DummyBodyInstance . SetCollisionEnabled ( ECollisionEnabled : : QueryOnly ) ;
DummyBodyInstance . SetResponseToAllChannels ( ECR_Block ) ;
# endif
if ( ! PhysicsObject )
{
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
UGeometryCollection * RestCollectionMutable = const_cast < UGeometryCollection * > ( RestCollection ) ;
RestCollectionMutable - > EnsureDataIsCooked ( ) ;
}
2018-12-12 11:25:29 -05:00
# endif
# if INCLUDE_CHAOS
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
{
2019-06-08 17:15:34 -04:00
if ( PhysicalMaterial )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
ChaosMaterial - > Friction = PhysicalMaterial - > Friction ;
ChaosMaterial - > Restitution = PhysicalMaterial - > Restitution ;
ChaosMaterial - > SleepingLinearThreshold = PhysicalMaterial - > SleepingLinearVelocityThreshold ;
ChaosMaterial - > SleepingAngularThreshold = PhysicalMaterial - > SleepingAngularVelocityThreshold ;
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
auto InitFunc = [ this ] ( FSimulationParameters & InParams )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
InParams . Name = GetPathName ( ) ;
# endif
InParams . RestCollection = RestCollection - > GetGeometryCollection ( ) . Get ( ) ;
GetInitializationCommands ( InParams . InitializationCommands ) ;
InParams . InitializationState = InitializationState ;
InParams . Simulating = Simulating ;
InParams . WorldTransform = GetComponentToWorld ( ) ;
RestCollection - > GetSharedSimulationParams ( InParams . Shared ) ;
InParams . EnableClustering = EnableClustering ;
InParams . ClusterGroupIndex = EnableClustering ? ClusterGroupIndex : 0 ;
InParams . MaxClusterLevel = MaxClusterLevel ;
InParams . DamageThreshold = DamageThreshold ;
InParams . ClusterConnectionMethod = ( Chaos : : FClusterCreationParameters < float > : : EConnectionMethod ) ClusterConnectionType ;
InParams . CollisionGroup = CollisionGroup ;
InParams . CollisionSampleFraction = CollisionSampleFraction ;
InParams . InitialVelocityType = InitialVelocityType ;
InParams . InitialLinearVelocity = InitialLinearVelocity ;
InParams . InitialAngularVelocity = InitialAngularVelocity ;
InParams . bClearCache = true ;
InParams . PhysicalMaterial = MakeSerializable ( ChaosMaterial ) ;
InParams . CacheType = CacheParameters . CacheMode ;
InParams . ReverseCacheBeginTime = CacheParameters . ReverseCacheBeginTime ;
InParams . CollisionData . SaveCollisionData = CacheParameters . SaveCollisionData ;
InParams . CollisionData . DoGenerateCollisionData = CacheParameters . DoGenerateCollisionData ;
InParams . CollisionData . CollisionDataSizeMax = CacheParameters . CollisionDataSizeMax ;
InParams . CollisionData . DoCollisionDataSpatialHash = CacheParameters . DoCollisionDataSpatialHash ;
InParams . CollisionData . CollisionDataSpatialHashRadius = CacheParameters . CollisionDataSpatialHashRadius ;
InParams . CollisionData . MaxCollisionPerCell = CacheParameters . MaxCollisionPerCell ;
InParams . BreakingData . SaveBreakingData = CacheParameters . SaveBreakingData ;
InParams . BreakingData . DoGenerateBreakingData = CacheParameters . DoGenerateBreakingData ;
InParams . BreakingData . BreakingDataSizeMax = CacheParameters . BreakingDataSizeMax ;
InParams . BreakingData . DoBreakingDataSpatialHash = CacheParameters . DoBreakingDataSpatialHash ;
InParams . BreakingData . BreakingDataSpatialHashRadius = CacheParameters . BreakingDataSpatialHashRadius ;
InParams . BreakingData . MaxBreakingPerCell = CacheParameters . MaxBreakingPerCell ;
InParams . TrailingData . SaveTrailingData = CacheParameters . SaveTrailingData ;
InParams . TrailingData . DoGenerateTrailingData = CacheParameters . DoGenerateTrailingData ;
InParams . TrailingData . TrailingDataSizeMax = CacheParameters . TrailingDataSizeMax ;
InParams . TrailingData . TrailingMinSpeedThreshold = CacheParameters . TrailingMinSpeedThreshold ;
InParams . TrailingData . TrailingMinVolumeThreshold = CacheParameters . TrailingMinVolumeThreshold ;
InParams . RemoveOnFractureEnabled = InParams . Shared . RemoveOnFractureIndices . Num ( ) > 0 ;
UGeometryCollectionCache * Cache = CacheParameters . TargetCache ;
if ( Cache & & CacheParameters . CacheMode ! = EGeometryCollectionCacheType : : None )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
bool bCacheValid = false ;
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
switch ( CacheParameters . CacheMode )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
case EGeometryCollectionCacheType : : Record :
case EGeometryCollectionCacheType : : RecordAndPlay :
bCacheValid = Cache - > CompatibleWithForRecord ( RestCollection ) ;
break ;
case EGeometryCollectionCacheType : : Play :
bCacheValid = Cache - > CompatibleWithForPlayback ( RestCollection ) ;
break ;
default :
check ( false ) ;
break ;
}
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
if ( bCacheValid )
{
InParams . RecordedTrack = ( InParams . IsCachePlaying ( ) & & CacheParameters . TargetCache ) ? CacheParameters . TargetCache - > GetData ( ) : nullptr ;
}
else
{
// We attempted to utilize a cache that was not compatible with this component. Report and do not use
UE_LOG ( LogChaos , Error , TEXT ( " Geometry collection '%s' attempted to use cache '%s' but it is not compatible. " ) , * GetName ( ) , * ( CacheParameters . TargetCache - > GetName ( ) ) ) ;
InParams . RecordedTrack = nullptr ;
InParams . CacheType = EGeometryCollectionCacheType : : None ;
CacheParameters . CacheMode = EGeometryCollectionCacheType : : None ;
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
FMessageLog ( " PIE " ) . Error ( )
- > AddToken ( FTextToken : : Create ( NSLOCTEXT ( " GeomCollectionComponent " , " BadCache_01 " , " Geometry collection " ) ) )
- > AddToken ( FUObjectToken : : Create ( this ) )
- > AddToken ( FTextToken : : Create ( NSLOCTEXT ( " GeomCollectionComponent " , " BadCache_02 " , " attempted to use cache " ) ) )
- > AddToken ( FUObjectToken : : Create ( CacheParameters . TargetCache ) )
- > AddToken ( FTextToken : : Create ( NSLOCTEXT ( " GeomCollectionComponent " , " BadCache_03 " , " but it is not compatible " ) ) ) ;
# endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
2018-12-12 11:25:29 -05:00
}
}
2019-06-08 17:15:34 -04:00
} ;
auto CacheSyncFunc = [ this ] ( const FGeometryCollectionResults & Results )
{
# if GEOMETRYCOLLECTION_DEBUG_DRAW
const bool bHasNumParticlesChanged = ( NumParticlesAdded ! = Results . NumParticlesAdded ) ; // Needs to be evaluated before NumParticlesAdded gets updated
# endif // #if GEOMETRYCOLLECTION_DEBUG_DRAW
RigidBodyIds . Init ( Results . RigidBodyIds ) ;
BaseRigidBodyIndex = Results . BaseIndex ;
NumParticlesAdded = Results . NumParticlesAdded ;
DisabledFlags = Results . DisabledStates ;
if ( ! IsObjectDynamic & & Results . IsObjectDynamic )
{
IsObjectDynamic = Results . IsObjectDynamic ;
NotifyGeometryCollectionPhysicsStateChange . Broadcast ( this ) ;
SwitchRenderModels ( GetOwner ( ) ) ;
}
if ( IsObjectLoading & & ! Results . IsObjectLoading )
{
IsObjectLoading = Results . IsObjectLoading ;
NotifyGeometryCollectionPhysicsLoadingStateChange . Broadcast ( this ) ;
}
WorldBounds = Results . WorldBounds ;
# if GEOMETRYCOLLECTION_DEBUG_DRAW
// Notify debug draw componentUGeometryCollectionDebugDrawComponent of particle changes
if ( bHasNumParticlesChanged )
{
if ( const AGeometryCollectionActor * const Owner = Cast < AGeometryCollectionActor > ( GetOwner ( ) ) )
{
if ( UGeometryCollectionDebugDrawComponent * const GeometryCollectionDebugDrawComponent = Owner - > GetGeometryCollectionDebugDrawComponent ( ) )
{
GeometryCollectionDebugDrawComponent - > OnClusterChanged ( ) ;
}
}
}
# endif // #if GEOMETRYCOLLECTION_DEBUG_DRAW
} ;
auto FinalSyncFunc = [ this ] ( const FRecordedTransformTrack & InTrack )
{
# if WITH_EDITOR && WITH_EDITORONLY_DATA
if ( CacheParameters . CacheMode = = EGeometryCollectionCacheType : : Record & & InTrack . Records . Num ( ) > 0 )
{
Modify ( ) ;
if ( ! CacheParameters . TargetCache )
{
CacheParameters . TargetCache = UGeometryCollectionCache : : CreateCacheForCollection ( RestCollection ) ;
}
if ( CacheParameters . TargetCache )
{
// Queue this up to be dirtied after PIE ends
TSharedPtr < FPhysScene_Chaos > Scene = GetPhysicsScene ( ) ;
CacheParameters . TargetCache - > PreEditChange ( nullptr ) ;
CacheParameters . TargetCache - > Modify ( ) ;
CacheParameters . TargetCache - > SetFromRawTrack ( InTrack ) ;
CacheParameters . TargetCache - > PostEditChange ( ) ;
Scene - > AddPieModifiedObject ( CacheParameters . TargetCache ) ;
if ( EditorActor )
{
UGeometryCollectionComponent * EditorComponent = Cast < UGeometryCollectionComponent > ( EditorUtilities : : FindMatchingComponentInstance ( this , EditorActor ) ) ;
if ( EditorComponent )
{
EditorComponent - > PreEditChange ( FindField < UProperty > ( EditorComponent - > GetClass ( ) , GET_MEMBER_NAME_CHECKED ( UGeometryCollectionComponent , CacheParameters ) ) ) ;
EditorComponent - > Modify ( ) ;
EditorComponent - > CacheParameters . TargetCache = CacheParameters . TargetCache ;
EditorComponent - > PostEditChange ( ) ;
Scene - > AddPieModifiedObject ( EditorComponent ) ;
Scene - > AddPieModifiedObject ( EditorActor ) ;
}
EditorActor = nullptr ;
}
}
}
2018-12-12 11:25:29 -05:00
# endif
2019-06-08 17:15:34 -04:00
} ;
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
// @todo(temporary) : This is Temporary code for the collection to match the ObjectType
// attribute on initialization. Once proper per-object manipulation is
// in place this code will need to be removed.
//
TManagedArray < int32 > & DynamicState = DynamicCollection - > DynamicState ;
if ( ObjectType ! = EObjectStateTypeEnum : : Chaos_Object_UserDefined )
{
for ( int i = 0 ; i < DynamicState . Num ( ) ; i + + )
{
DynamicState [ i ] = ( int32 ) ObjectType ;
}
}
TManagedArray < bool > & Active = DynamicCollection - > Active ;
{
for ( int i = 0 ; i < Active . Num ( ) ; i + + )
{
Active [ i ] = Simulating ;
}
}
TManagedArray < int32 > & CollisionGroupArray = DynamicCollection - > CollisionGroup ;
{
for ( int i = 0 ; i < CollisionGroupArray . Num ( ) ; i + + )
{
CollisionGroupArray [ i ] = CollisionGroup ;
}
}
// end temporary
2018-12-12 11:25:29 -05:00
2019-06-08 17:15:34 -04:00
PhysicsObject = new FGeometryCollectionPhysicsObject ( this , DynamicCollection . Get ( ) , InitFunc , CacheSyncFunc , FinalSyncFunc ) ;
TSharedPtr < FPhysScene_Chaos > Scene = GetPhysicsScene ( ) ;
Scene - > AddObject ( this , PhysicsObject ) ;
RegisterForEvents ( ) ;
}
# endif
2018-12-12 11:25:29 -05:00
}
2019-06-08 17:15:34 -04:00
# if INCLUDE_CHAOS
# if WITH_PHYSX && !WITH_CHAOS_NEEDS_TO_BE_FIXED
if ( PhysicsObject )
{
GlobalGeomCollectionAccelerator . AddComponent ( this ) ;
}
# endif
2018-12-12 11:25:29 -05:00
# endif
}
void UGeometryCollectionComponent : : OnDestroyPhysicsState ( )
{
UActorComponent : : OnDestroyPhysicsState ( ) ;
2019-06-08 17:15:34 -04:00
# if INCLUDE_CHAOS
# if WITH_PHYSX && !WITH_CHAOS_NEEDS_TO_BE_FIXED
GlobalGeomCollectionAccelerator . RemoveComponent ( this ) ;
# endif
# endif
# if WITH_PHYSX
if ( DummyBodyInstance . IsValidBodyInstance ( ) )
{
DummyBodyInstance . TermBody ( ) ;
}
# endif
# if INCLUDE_CHAOS
if ( PhysicsObject )
{
TSharedPtr < FPhysScene_Chaos > Scene = GetPhysicsScene ( ) ;
Scene - > RemoveObject ( PhysicsObject ) ;
InitializationState = ESimulationInitializationState : : Unintialized ;
// Discard the pointer (cleanup happens through the scene or dedicated thread)
PhysicsObject = nullptr ;
2018-12-12 11:25:29 -05:00
}
# endif
}
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 ) )
{
FGeometryCollectionDynamicData * DynamicData = : : new FGeometryCollectionDynamicData ;
InitDynamicData ( DynamicData ) ;
//
// Only send dynamic data if the transform arrys on the past N frames are different
//
bool PastFramesTransformsAreEqual = true ;
for ( int i = 0 ; i < TransformsAreEqual . Num ( ) ; + + i )
{
PastFramesTransformsAreEqual = PastFramesTransformsAreEqual & & TransformsAreEqual [ i ] ;
}
if ( PastFramesTransformsAreEqual )
{
delete DynamicData ;
}
else
{
2018-12-12 11:25:29 -05:00
// Enqueue command to send to render thread
2019-06-08 17:15:34 -04:00
FGeometryCollectionSceneProxy * GeometryCollectionSceneProxy = static_cast < FGeometryCollectionSceneProxy * > ( SceneProxy ) ;
ENQUEUE_RENDER_COMMAND ( SendRenderDynamicData ) (
2019-02-18 18:35:01 -05:00
[ GeometryCollectionSceneProxy , DynamicData ] ( FRHICommandListImmediate & RHICmdList )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
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 ;
2019-06-08 17:15:34 -04:00
CalculateGlobalMatrices ( ) ;
CalculateLocalBounds ( ) ;
//ResetDynamicCollection();
2018-12-12 11:25:29 -05:00
}
}
2019-06-20 12:19:51 -04:00
FGeometryCollectionEdit : : FGeometryCollectionEdit ( UGeometryCollectionComponent * InComponent , GeometryCollection : : EEditUpdate InEditUpdate )
2018-12-12 11:25:29 -05:00
: Component ( InComponent )
2019-06-20 12:19:51 -04:00
, EditUpdate ( InEditUpdate )
2018-12-12 11:25:29 -05:00
{
bHadPhysicsState = Component - > HasValidPhysicsState ( ) ;
2019-06-20 12:19:51 -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:51 -04:00
if ( ! ! EditUpdate )
2018-12-12 11:25:29 -05:00
{
2019-06-20 12:19:51 -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:51 -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 )
{
2019-06-08 17:15:34 -04:00
return const_cast < UGeometryCollection * > ( 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 ) ;
}
2019-06-08 17:15:34 -04:00
void FScopedColorEdit : : ToggleSelectedBones ( const TArray < int32 > & SelectedBonesIn )
{
bUpdated = true ;
for ( int32 BoneIndex : SelectedBonesIn )
{
if ( Component - > SelectedBones . Contains ( BoneIndex ) )
{
Component - > SelectedBones . Remove ( BoneIndex ) ;
}
else
{
Component - > SelectedBones . Add ( BoneIndex ) ;
}
}
}
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 ;
FGeometryCollectionClusteringUtility : : GetLeafBones ( GeometryCollectionPtr . Get ( ) , RootElement , LeafBones ) ;
AppendSelectedBones ( LeafBones ) ;
}
}
break ;
case GeometryCollection : : ESelectionMode : : InverseGeometry :
{
TArray < int32 > Roots ;
FGeometryCollectionClusteringUtility : : GetRootBones ( GeometryCollectionPtr . Get ( ) , Roots ) ;
TArray < int32 > NewSelection ;
for ( int32 RootElement : Roots )
{
TArray < int32 > LeafBones ;
FGeometryCollectionClusteringUtility : : GetLeafBones ( GeometryCollectionPtr . Get ( ) , RootElement , LeafBones ) ;
for ( int32 Element : LeafBones )
{
if ( ! IsBoneSelected ( Element ) )
{
NewSelection . Push ( Element ) ;
}
}
}
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 " ) ) )
{
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 ) ;
const TSet < int32 > & Neighbors = Proximity [ TransformToGeometryIndex [ Bone ] ] ;
for ( int32 NeighborGeometryIndex : Neighbors )
{
NewSelection . AddUnique ( TransformIndex [ NeighborGeometryIndex ] ) ;
}
}
ResetBoneSelection ( ) ;
AppendSelectedBones ( NewSelection ) ;
}
}
break ;
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 ;
case GeometryCollection : : ESelectionMode : : AllInCluster :
{
const TManagedArray < int32 > & Parents = GeometryCollectionPtr - > Parent ;
const TArray < int32 > SelectedBones = GetSelectedBones ( ) ;
TArray < int32 > NewSelection ;
for ( int32 Bone : SelectedBones )
{
int32 ParentBone = Parents [ Bone ] ;
TArray < int32 > LeafBones ;
FGeometryCollectionClusteringUtility : : GetLeafBones ( GeometryCollectionPtr . Get ( ) , ParentBone , LeafBones ) ;
for ( int32 Element : LeafBones )
{
NewSelection . AddUnique ( Element ) ;
}
}
ResetBoneSelection ( ) ;
AppendSelectedBones ( NewSelection ) ;
}
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 ( ) ;
2018-12-12 11:25:29 -05:00
SetHighlightedBones ( SelectedBones ) ;
}
}
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:26:42 -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:28 -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 )
{
FName TargetName = GetGeometryCollectionPhysicsTypeName ( EGeometryCollectionPhysicsTypeEnum : : Chaos_DynamicState ) ;
DispatchCommand ( { TargetName , new FRadialIntMask ( Radius , Position , ( int32 ) EObjectStateTypeEnum : : Chaos_Object_Dynamic ,
( int32 ) EObjectStateTypeEnum : : Chaos_Object_Kinematic , ESetMaskConditionType : : Field_Set_IFF_NOT_Interior ) } ) ;
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
{
2019-06-08 17:15:34 -04:00
TArray < const UFieldNodeBase * > Nodes ;
FFieldSystemCommand Command = { GetGeometryCollectionPhysicsTypeName ( Target ) , Field - > NewEvaluationGraph ( Nodes ) } ;
if ( ensureMsgf ( Command . RootNode ,
TEXT ( " Failed to generate physics field command for target attribute. " ) ) )
{
if ( MetaData )
{
switch ( MetaData - > Type ( ) )
{
case FFieldSystemMetaData : : EMetaType : : ECommandData_ProcessingResolution :
UFieldSystemMetaDataProcessingResolution * ResolutionMeta = static_cast < UFieldSystemMetaDataProcessingResolution * > ( MetaData ) ;
Command . MetaData . Add ( FFieldSystemMetaData : : EMetaType : : ECommandData_ProcessingResolution ) . Reset ( new FFieldSystemMetaDataProcessingResolution ( ResolutionMeta - > ResolutionType ) ) ;
break ;
}
}
ensure ( ! Command . TargetAttribute . IsEqual ( " None " ) ) ;
DispatchCommand ( Command ) ;
}
2018-12-12 11:25:29 -05:00
}
}
2019-06-08 17:15:34 -04:00
void UGeometryCollectionComponent : : DispatchCommand ( const FFieldSystemCommand & InCommand )
{
# if INCLUDE_CHAOS
if ( PhysicsObject )
{
FChaosSolversModule * ChaosModule = FModuleManager : : Get ( ) . GetModulePtr < FChaosSolversModule > ( " ChaosSolvers " ) ;
checkSlow ( ChaosModule ) ;
Chaos : : IDispatcher * PhysicsDispatcher = ChaosModule - > GetDispatcher ( ) ;
checkSlow ( PhysicsDispatcher ) ; // Should always have one of these
PhysicsDispatcher - > EnqueueCommand ( [ PhysicsObject = this - > PhysicsObject , NewCommand = InCommand ] ( )
{
// Pass through nullptr here as geom component commands can never affect other solvers
PhysicsObject - > BufferCommand ( nullptr , NewCommand ) ;
} ) ;
}
# endif
}
void UGeometryCollectionComponent : : GetInitializationCommands ( TArray < FFieldSystemCommand > & CombinedCommmands )
{
# if INCLUDE_CHAOS
CombinedCommmands . Reset ( ) ;
for ( const AFieldSystemActor * FieldSystemActor : InitializationFields )
{
if ( FieldSystemActor ! = nullptr )
{
if ( FieldSystemActor - > GetFieldSystemComponent ( ) & & FieldSystemActor - > GetFieldSystemComponent ( ) - > GetFieldSystem ( ) )
{
for ( const FFieldSystemCommand & Command : FieldSystemActor - > GetFieldSystemComponent ( ) - > GetFieldSystem ( ) - > Commands )
{
FFieldSystemCommand NewCommand = { Command . TargetAttribute , Command . RootNode - > NewCopy ( ) } ;
for ( auto & Elem : Command . MetaData )
{
NewCommand . MetaData . Add ( Elem . Key , TUniquePtr < FFieldSystemMetaData > ( Elem . Value - > NewCopy ( ) ) ) ;
}
CombinedCommmands . Add ( NewCommand ) ;
}
}
}
}
# endif
}
2018-12-12 11:25:29 -05:00
# if INCLUDE_CHAOS
const TSharedPtr < FPhysScene_Chaos > UGeometryCollectionComponent : : GetPhysicsScene ( ) const
{
if ( ChaosSolverActor )
{
return ChaosSolverActor - > GetPhysicsScene ( ) ;
}
else
{
2019-06-08 17:15:34 -04:00
if ( ensure ( GetOwner ( ) ) & & ensure ( GetOwner ( ) - > GetWorld ( ) ) )
{
return GetOwner ( ) - > GetWorld ( ) - > PhysicsScene_Chaos ;
}
check ( GWorld ) ;
return GWorld - > PhysicsScene_Chaos ;
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
{
FPhysScene_Chaos const * const Scene = GetPhysicsScene ( ) . Get ( ) ;
return Scene ? Cast < AChaosSolverActor > ( Scene - > GetSolverActor ( ) ) : nullptr ;
}
return nullptr ;
}
2018-12-12 11:25:29 -05:00
# endif
2019-06-08 17:15:34 -04:00
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 ) ;
# if INCLUDE_CHAOS
FChaosSolversModule * Module = FChaosSolversModule : : GetModule ( ) ;
Module - > LockResultsRead ( ) ;
const FGeometryCollectionResults * Results = PhysicsObject ? & PhysicsObject - > GetPhysicsResults ( ) . GetGameDataForRead ( ) : nullptr ;
const int32 NumTransforms = Results ? Results - > GlobalTransforms . Num ( ) : 0 ;
if ( NumTransforms > 0 )
{
// Just calc from results
GlobalMatrices . Empty ( ) ;
GlobalMatrices . Append ( Results - > GlobalTransforms ) ;
}
else
{
// Have to fully rebuild
GeometryCollectionAlgo : : GlobalMatrices ( GetTransformArray ( ) , GetParentArray ( ) , GlobalMatrices ) ;
}
# if WITH_EDITOR
if ( GlobalMatrices . Num ( ) > 0 )
{
if ( RestCollection - > GetGeometryCollection ( ) - > HasAttribute ( " ExplodedVector " , FGeometryCollection : : TransformGroup ) )
{
const TManagedArray < FVector > & ExplodedVectors = RestCollection - > GetGeometryCollection ( ) - > GetAttribute < FVector > ( " ExplodedVector " , FGeometryCollection : : TransformGroup ) ;
check ( GlobalMatrices . Num ( ) = = ExplodedVectors . Num ( ) ) ;
for ( int32 tt = 0 , nt = GlobalMatrices . Num ( ) ; tt < nt ; + + tt )
{
GlobalMatrices [ tt ] = GlobalMatrices [ tt ] . ConcatTranslation ( ExplodedVectors [ tt ] ) ;
}
}
}
# endif
Module - > UnlockResultsRead ( ) ;
# 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:19 -04:00
// Don't touch visibility if the component is not visible
if ( ! IsVisible ( ) )
{
return ;
}
2019-06-08 17:15:34 -04:00
TArray < UActorComponent * > PrimitiveComponents = Actor - > GetComponentsByClass ( UPrimitiveComponent : : StaticClass ( ) ) ;
for ( UActorComponent * PrimitiveComponent : PrimitiveComponents )
{
bool ValidComponent = false ;
if ( UStaticMeshComponent * StaticMeshComp = Cast < UStaticMeshComponent > ( PrimitiveComponent ) )
{
StaticMeshComp - > SetVisibility ( false ) ;
}
else if ( UGeometryCollectionComponent * GeometryCollectionComponent = Cast < UGeometryCollectionComponent > ( PrimitiveComponent ) )
{
2019-07-16 19:12:23 -04:00
if ( ! GeometryCollectionComponent - > IsVisible ( ) )
{
continue ;
}
2019-06-08 17:15:34 -04:00
GeometryCollectionComponent - > SetVisibility ( true ) ;
}
}
TArray < UChildActorComponent * > ChildActorComponents ;
Actor - > GetComponents < UChildActorComponent > ( ChildActorComponents ) ;
for ( UChildActorComponent * ChildComponent : ChildActorComponents )
{
AActor * ChildActor = ChildComponent - > GetChildActor ( ) ;
if ( ChildActor )
{
SwitchRenderModels ( ChildActor ) ;
}
}
}
bool UGeometryCollectionComponent : : IsEqual ( const TArray < FMatrix > & A , const TArray < FMatrix > & B , const float Tolerance )
{
if ( A . Num ( ) ! = B . Num ( ) )
{
return false ;
}
for ( int Index = 0 ; Index < A . Num ( ) ; + + Index )
{
if ( ! A [ Index ] . Equals ( B [ Index ] , Tolerance ) )
{
return false ;
}
}
return true ;
}
# if GEOMETRYCOLLECTION_EDITOR_SELECTION
void UGeometryCollectionComponent : : EnableTransformSelectionMode ( bool bEnable )
{
if ( SceneProxy & & RestCollection & & RestCollection - > HasVisibleGeometry ( ) )
{
static_cast < FGeometryCollectionSceneProxy * > ( SceneProxy ) - > UseSubSections ( bEnable , true ) ;
}
bIsTransformSelectionModeEnabled = bEnable ;
}
# endif // #if GEOMETRYCOLLECTION_EDITOR_SELECTION