2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-06-08 17:15:34 -04:00
# include "SQCapture.h"
2019-08-02 09:01:58 -04:00
2019-06-08 17:15:34 -04:00
# include "Chaos/ImplicitObject.h"
2019-10-02 17:27:26 -04:00
# include "Chaos/PBDRigidsEvolutionGBF.h"
2020-03-04 17:25:08 -05:00
# include "PhysicsInterfaceTypesCore.h"
2019-08-02 09:01:58 -04:00
2019-06-08 17:15:34 -04:00
# include "PhysXSupportCore.h"
# include "PhysicsPublicCore.h"
# include "PhysTestSerializer.h"
2020-03-03 17:06:00 -05:00
# if PHYSICS_INTERFACE_PHYSX
2019-06-08 17:15:34 -04:00
# include "PhysXToChaosUtil.h"
# endif
2019-10-02 17:27:26 -04:00
class FSQCaptureFilterCallback : public ICollisionQueryFilterCallbackBase
{
public :
FSQCaptureFilterCallback ( const FSQCapture & InCapture ) : Capture ( InCapture ) { }
virtual ~ FSQCaptureFilterCallback ( ) { }
virtual ECollisionQueryHitType PostFilter ( const FCollisionFilterData & FilterData , const ChaosInterface : : FQueryHit & Hit ) override { /*check(false);*/ return ECollisionQueryHitType : : Touch ; }
2021-02-03 14:57:28 -04:00
virtual ECollisionQueryHitType PreFilter ( const FCollisionFilterData & FilterData , const Chaos : : FPerShapeData & Shape , const Chaos : : FGeometryParticle & Actor ) override { return Capture . GetFilterResult ( & Shape , & Actor ) ; }
2019-10-02 17:27:26 -04:00
2022-02-04 12:58:24 -05:00
virtual ECollisionQueryHitType PostFilter ( const FCollisionFilterData & FilterData , const ChaosInterface : : FPTQueryHit & Hit ) override { ensure ( false ) ; return ECollisionQueryHitType : : Touch ; }
virtual ECollisionQueryHitType PreFilter ( const FCollisionFilterData & FilterData , const Chaos : : FPerShapeData & Shape , const Chaos : : FGeometryParticleHandle & Actor ) override { ensure ( false ) ; return ECollisionQueryHitType : : Touch ; }
2020-03-03 17:06:00 -05:00
# if PHYSICS_INTERFACE_PHYSX
2019-10-02 17:27:26 -04:00
virtual ECollisionQueryHitType PostFilter ( const FCollisionFilterData & FilterData , const physx : : PxQueryHit & Hit ) override { return ECollisionQueryHitType : : Touch ; }
virtual ECollisionQueryHitType PreFilter ( const FCollisionFilterData & FilterData , const physx : : PxShape & Shape , physx : : PxRigidActor & Actor ) override { return Capture . GetFilterResult ( & Shape , & Actor ) ; }
virtual PxQueryHitType : : Enum preFilter ( const PxFilterData & filterData , const PxShape * shape , const PxRigidActor * actor , PxHitFlags & queryFlags ) override { return U2PCollisionQueryHitType ( Capture . GetFilterResult ( shape , actor ) ) ; }
virtual PxQueryHitType : : Enum postFilter ( const PxFilterData & filterData , const PxQueryHit & hit ) override { return PxQueryHitType : : eTOUCH ; }
# endif
private :
const FSQCapture & Capture ;
} ;
2019-06-08 17:15:34 -04:00
FSQCapture : : FSQCapture ( FPhysTestSerializer & InPhysSerializer )
: OutputFlags ( EHitFlags : : None )
, ChaosGeometry ( nullptr )
, PhysSerializer ( InPhysSerializer )
, bDiskDataIsChaos ( false )
, bChaosDataReady ( false )
, bPhysXDataReady ( false )
{
}
FSQCapture : : ~ FSQCapture ( )
{
}
2020-03-03 17:06:00 -05:00
# if PHYSICS_INTERFACE_PHYSX
2019-06-08 17:15:34 -04:00
PxActor * FSQCapture : : GetTransientActor ( PxActor * Actor ) const
{
PxActor * TransientActor = NonTransientToTransientActors . FindRef ( Actor ) ;
return TransientActor ? TransientActor : Actor ;
}
PxShape * FSQCapture : : GetTransientShape ( PxShape * Shape ) const
{
PxShape * TransientShape = NonTransientToTransientShapes . FindRef ( Shape ) ;
return TransientShape ? TransientShape : Shape ;
}
void FSQCapture : : SerializePhysXHitType ( FArchive & Ar , PxOverlapHit & Hit )
{
uint64 Actor = ( PxSerialObjectId ) GetTransientActor ( Hit . actor ) ;
uint64 Shape = ( PxSerialObjectId ) GetTransientShape ( Hit . shape ) ;
Ar < < Actor < < Shape < < Hit . faceIndex ;
Hit . actor = ( PxRigidActor * ) Actor ; //todo: 32bit, should be ok as long as you never load a 64bit capture on a 32bit machine. If compiler error just add some checks and do conversion manually
Hit . shape = ( PxShape * ) Shape ;
}
template < typename T >
void FSQCapture : : SerializePhysXHitType ( FArchive & Ar , T & Hit )
{
uint64 Actor = ( PxSerialObjectId ) GetTransientActor ( Hit . actor ) ;
uint64 Shape = ( PxSerialObjectId ) GetTransientShape ( Hit . shape ) ;
FVector Position = P2UVector ( Hit . position ) ;
FVector Normal = P2UVector ( Hit . normal ) ;
uint16 HitFlags = Hit . flags ;
Ar < < Actor < < Shape < < Hit . faceIndex < < HitFlags < < Position < < Normal < < Hit . distance ;
Hit . actor = ( PxRigidActor * ) Actor ; //todo: 32bit, should be ok as long as you never load a 64bit capture on a 32bit machine. If compiler error just add some checks and do conversion manually
Hit . shape = ( PxShape * ) Shape ;
Hit . position = U2PVector ( Position ) ;
Hit . normal = U2PVector ( Normal ) ;
Hit . flags = ( PxHitFlags ) HitFlags ;
}
template < typename THit >
2019-08-02 09:01:58 -04:00
void FSQCapture : : SerializePhysXBuffers ( FArchive & Ar , int32 Version , PhysXInterface : : FDynamicHitBuffer < THit > & PhysXBuffer )
2019-06-08 17:15:34 -04:00
{
Ar < < PhysXBuffer . hasBlock ;
if ( PhysXBuffer . hasBlock )
{
SerializePhysXHitType ( Ar , PhysXBuffer . block ) ;
}
TArray < THit > TmpHits ;
THit * Hits ;
int32 NumHits ;
if ( Version < 1 )
{
Ar < < PhysXBuffer . maxNbTouches < < PhysXBuffer . nbTouches ;
TmpHits . AddDefaulted ( PhysXBuffer . nbTouches ) ;
Hits = TmpHits . GetData ( ) ;
NumHits = TmpHits . Num ( ) ;
}
else
{
NumHits = PhysXBuffer . GetNumHits ( ) ;
Ar < < NumHits ;
if ( Ar . IsLoading ( ) )
{
TmpHits . AddDefaulted ( NumHits ) ;
PhysXBuffer . processTouches ( TmpHits . GetData ( ) , NumHits ) ;
}
Hits = PhysXBuffer . GetHits ( ) ;
}
for ( int32 Idx = 0 ; Idx < NumHits ; + + Idx )
{
SerializePhysXHitType ( Ar , Hits [ Idx ] ) ;
}
}
void FSQCapture : : SerializeActorToShapeHitsArray ( FArchive & Ar )
{
2019-08-02 09:01:58 -04:00
int32 NumActors = PxActorToShapeHitsArray . Num ( ) ;
2019-06-08 17:15:34 -04:00
Ar < < NumActors ;
if ( Ar . IsLoading ( ) )
{
for ( int32 ActorIdx = 0 ; ActorIdx < NumActors ; + + ActorIdx )
{
uint64 Actor ;
Ar < < Actor ;
int32 NumShapes ;
Ar < < NumShapes ;
TArray < TPair < PxShape * , ECollisionQueryHitType > > Pairs ;
for ( int32 ShapeIdx = 0 ; ShapeIdx < NumShapes ; + + ShapeIdx )
{
uint64 Shape ;
Ar < < Shape ;
ECollisionQueryHitType HitType ;
Ar < < HitType ;
PxShape * ShapePtr = static_cast < PxShape * > ( PhysSerializer . FindObject ( Shape ) ) ;
check ( ShapePtr ) ;
Pairs . Emplace ( ShapePtr , HitType ) ;
}
PxActor * ActorPtr = static_cast < PxActor * > ( PhysSerializer . FindObject ( Actor ) ) ;
check ( ActorPtr ) ;
2019-08-02 09:01:58 -04:00
PxActorToShapeHitsArray . Add ( ActorPtr , Pairs ) ;
2019-06-08 17:15:34 -04:00
}
}
else if ( Ar . IsSaving ( ) )
{
2019-08-02 09:01:58 -04:00
for ( auto & Itr : PxActorToShapeHitsArray )
2019-06-08 17:15:34 -04:00
{
uint64 Actor = ( PxSerialObjectId ) NonTransientToTransientActors . FindChecked ( Itr . Key ) ;
Ar < < Actor ;
int32 NumShapes = Itr . Value . Num ( ) ;
Ar < < NumShapes ;
for ( auto & Pair : Itr . Value )
{
uint64 Shape = ( PxSerialObjectId ) NonTransientToTransientShapes . FindChecked ( Pair . Key ) ;
Ar < < Shape ;
Ar < < Pair . Value ;
}
}
}
}
2020-03-03 09:46:37 -05:00
# endif
2019-06-08 17:15:34 -04:00
void SerializeQueryFilterData ( FArchive & Ar , FQueryFilterData & QueryFilterData )
{
Ar < < QueryFilterData . data . word0 ;
Ar < < QueryFilterData . data . word1 ;
Ar < < QueryFilterData . data . word2 ;
Ar < < QueryFilterData . data . word3 ;
uint16 Flags = QueryFilterData . flags ;
Ar < < Flags ;
2020-03-04 17:25:08 -05:00
# if PHYSICS_INTERFACE_PHYSX
2019-06-08 17:15:34 -04:00
QueryFilterData . flags = ( PxQueryFlags ) Flags ;
2020-03-04 17:25:08 -05:00
# else
QueryFilterData . flags = ( FChaosQueryFlags ) Flags ;
# endif
2019-06-08 17:15:34 -04:00
Ar < < QueryFilterData . clientId ;
}
2019-10-02 17:27:26 -04:00
void FSQCapture : : SerializeChaosActorToShapeHitsArray ( Chaos : : FChaosArchive & Ar )
2019-06-08 17:15:34 -04:00
{
2019-10-02 17:27:26 -04:00
int32 NumActors = ChaosActorToShapeHitsArray . Num ( ) ;
Ar < < NumActors ;
if ( Ar . IsLoading ( ) )
{
for ( int32 ActorIdx = 0 ; ActorIdx < NumActors ; + + ActorIdx )
{
2021-02-03 14:57:28 -04:00
Chaos : : TSerializablePtr < Chaos : : FGeometryParticle > Actor ;
2019-10-02 17:27:26 -04:00
Ar < < Actor ;
int32 NumShapes ;
Ar < < NumShapes ;
2020-03-10 17:25:27 -04:00
TArray < TPair < Chaos : : FPerShapeData * , ECollisionQueryHitType > > Pairs ;
2019-10-02 17:27:26 -04:00
for ( int32 ShapeIdx = 0 ; ShapeIdx < NumShapes ; + + ShapeIdx )
{
2020-03-10 17:25:27 -04:00
Chaos : : TSerializablePtr < Chaos : : FPerShapeData > Shape ;
2019-10-02 17:27:26 -04:00
Ar < < Shape ;
ECollisionQueryHitType HitType ;
Ar < < HitType ;
2020-03-10 17:25:27 -04:00
Pairs . Emplace ( const_cast < Chaos : : FPerShapeData * > ( Shape . Get ( ) ) , HitType ) ;
2019-10-02 17:27:26 -04:00
}
2021-02-03 14:57:28 -04:00
ChaosActorToShapeHitsArray . Add ( const_cast < Chaos : : FGeometryParticle * > ( Actor . Get ( ) ) , Pairs ) ;
2019-10-02 17:27:26 -04:00
}
}
else if ( Ar . IsSaving ( ) )
{
for ( auto & Itr : ChaosActorToShapeHitsArray )
{
Ar < < AsAlwaysSerializable ( Itr . Key ) ;
int32 NumShapes = Itr . Value . Num ( ) ;
Ar < < NumShapes ;
for ( auto & Pair : Itr . Value )
{
Ar < < AsAlwaysSerializable ( Pair . Key ) ;
Ar < < Pair . Value ;
}
}
}
}
template < typename THit >
void FSQCapture : : SerializeChaosBuffers ( Chaos : : FChaosArchive & Ar , int32 Version , ChaosInterface : : FSQHitBuffer < THit > & ChaosBuffer )
{
bool bHasBlock = ChaosBuffer . HasBlockingHit ( ) ;
Ar < < bHasBlock ;
if ( bHasBlock )
{
if ( Ar . IsLoading ( ) )
{
THit Hit ;
Ar < < Hit ;
ChaosBuffer . SetBlockingHit ( Hit ) ;
}
else
{
THit Hit = * ChaosBuffer . GetBlock ( ) ;
Ar < < Hit ;
}
}
int32 NumHits ;
NumHits = ChaosBuffer . GetNumHits ( ) ;
Ar < < NumHits ;
for ( int32 Idx = 0 ; Idx < NumHits ; + + Idx )
{
if ( Ar . IsLoading ( ) )
{
THit Touch ;
Ar < < Touch ;
ChaosBuffer . AddTouchingHit ( Touch ) ;
}
else
{
THit * Hits = ChaosBuffer . GetHits ( ) ;
Ar < < Hits [ Idx ] ;
}
}
}
void FSQCapture : : Serialize ( Chaos : : FChaosArchive & Ar )
{
static const FName SQCaptureName = TEXT ( " SQCapture " ) ;
Chaos : : FChaosArchiveScopedMemory ScopedMemory ( Ar , SQCaptureName , false ) ;
int32 Version = 2 ;
2019-06-08 17:15:34 -04:00
Ar < < Version ;
Ar < < SQType ;
Ar < < bDiskDataIsChaos ;
Ar < < Dir < < StartTM < < DeltaMag < < OutputFlags ;
Ar < < GeomData ;
Ar < < HitData ;
if ( Version > = 1 )
{
Ar < < StartPoint ;
}
# if WITH_PHYSX
if ( bDiskDataIsChaos = = false )
{
2020-03-03 17:06:00 -05:00
# if PHYSICS_INTERFACE_PHYSX
2019-06-08 17:15:34 -04:00
SerializePhysXBuffers ( Ar , Version , PhysXSweepBuffer ) ;
if ( Version > = 1 )
{
SerializePhysXBuffers ( Ar , Version , PhysXRaycastBuffer ) ;
SerializePhysXBuffers ( Ar , Version , PhysXOverlapBuffer ) ;
SerializeActorToShapeHitsArray ( Ar ) ;
}
if ( Ar . IsLoading ( ) )
{
CreatePhysXData ( ) ;
}
2020-03-03 17:06:00 -05:00
# endif
if ( Version > = 1 )
{
SerializeQueryFilterData ( Ar , QueryFilterData ) ;
}
2019-06-08 17:15:34 -04:00
}
# endif
2020-03-03 17:06:00 -05:00
# if WITH_CHAOS
2019-06-08 17:15:34 -04:00
if ( bDiskDataIsChaos )
{
2020-03-03 14:10:10 -05:00
# if WITH_CHAOS
2019-10-02 17:27:26 -04:00
SerializeChaosBuffers ( Ar , Version , ChaosSweepBuffer ) ;
SerializeChaosBuffers ( Ar , Version , ChaosRaycastBuffer ) ;
SerializeChaosBuffers ( Ar , Version , ChaosOverlapBuffer ) ;
2020-03-03 14:10:10 -05:00
# endif // WITH_CHAOS
2019-10-02 17:27:26 -04:00
SerializeChaosActorToShapeHitsArray ( Ar ) ;
SerializeQueryFilterData ( Ar , QueryFilterData ) ;
if ( Version > = 2 )
{
Ar < < SerializableChaosGeometry ;
ChaosGeometry = SerializableChaosGeometry . Get ( ) ;
}
2019-06-08 17:15:34 -04:00
}
2020-03-03 17:06:00 -05:00
# endif
2019-10-02 17:27:26 -04:00
2019-06-08 17:15:34 -04:00
if ( Ar . IsLoading ( ) )
{
2020-03-03 17:06:00 -05:00
#if 0
2019-10-02 17:27:26 -04:00
CreateChaosDataFromPhysX ( ) ;
2020-03-03 09:46:37 -05:00
# endif // WITH_PHYSX
2019-10-02 17:27:26 -04:00
if ( bDiskDataIsChaos )
{
FilterCallback = MakeUnique < FSQCaptureFilterCallback > ( * this ) ;
}
}
}
2020-04-20 09:47:13 -04:00
void FSQCapture : : StartCaptureChaosSweep ( const Chaos : : FPBDRigidsEvolution & Evolution , const Chaos : : FImplicitObject & InQueryGeom , const FTransform & InStartTM , const FVector & InDir , float InDeltaMag , FHitFlags InOutputFlags , const FQueryFilterData & QueryFilter , const FCollisionFilterData & FilterData , ICollisionQueryFilterCallbackBase & Callback )
2019-10-02 17:27:26 -04:00
{
if ( IsInGameThread ( ) )
{
bDiskDataIsChaos = true ;
CaptureChaosFilterResults ( Evolution , FilterData , Callback ) ;
//copy data
SerializableChaosGeometry = InQueryGeom . Copy ( ) ;
ChaosGeometry = SerializableChaosGeometry . Get ( ) ;
StartTM = InStartTM ;
Dir = InDir ;
DeltaMag = InDeltaMag ;
OutputFlags = InOutputFlags ;
QueryFilterData = QueryFilter ;
SQType = ESQType : : Sweep ;
}
}
void FSQCapture : : EndCaptureChaosSweep ( const ChaosInterface : : FSQHitBuffer < ChaosInterface : : FSweepHit > & Results )
{
2020-03-03 17:06:00 -05:00
# if WITH_CHAOS
2019-10-02 17:27:26 -04:00
if ( IsInGameThread ( ) )
{
check ( SQType = = ESQType : : Sweep ) ;
2020-03-03 14:10:10 -05:00
# if WITH_CHAOS
2019-10-02 17:27:26 -04:00
ChaosSweepBuffer = Results ;
2020-03-03 14:10:10 -05:00
# endif // WITH_CHAOS
2019-10-02 17:27:26 -04:00
}
2020-03-03 17:06:00 -05:00
# endif
2019-10-02 17:27:26 -04:00
}
2020-04-20 09:47:13 -04:00
void FSQCapture : : StartCaptureChaosRaycast ( const Chaos : : FPBDRigidsEvolution & Evolution , const FVector & InStartPoint , const FVector & InDir , float InDeltaMag , FHitFlags InOutputFlags , const FQueryFilterData & QueryFilter , const FCollisionFilterData & FilterData , ICollisionQueryFilterCallbackBase & Callback )
2019-10-02 17:27:26 -04:00
{
if ( IsInGameThread ( ) )
{
bDiskDataIsChaos = true ;
CaptureChaosFilterResults ( Evolution , FilterData , Callback ) ;
//copy data
StartPoint = InStartPoint ;
Dir = InDir ;
DeltaMag = InDeltaMag ;
OutputFlags = InOutputFlags ;
QueryFilterData = QueryFilter ;
SQType = ESQType : : Raycast ;
}
}
void FSQCapture : : EndCaptureChaosRaycast ( const ChaosInterface : : FSQHitBuffer < ChaosInterface : : FRaycastHit > & Results )
{
2020-03-03 17:06:00 -05:00
# if WITH_CHAOS
2019-10-02 17:27:26 -04:00
if ( IsInGameThread ( ) )
{
check ( SQType = = ESQType : : Raycast ) ;
2020-03-03 14:10:10 -05:00
# if WITH_CHAOS
2019-10-02 17:27:26 -04:00
ChaosRaycastBuffer = Results ;
2020-03-03 14:10:10 -05:00
# endif // WITH_CHAOS
2019-10-02 17:27:26 -04:00
}
2020-03-03 17:06:00 -05:00
# endif
2019-10-02 17:27:26 -04:00
}
2020-04-20 09:47:13 -04:00
void FSQCapture : : StartCaptureChaosOverlap ( const Chaos : : FPBDRigidsEvolution & Evolution , const Chaos : : FImplicitObject & InQueryGeom , const FTransform & InStartTM , const FQueryFilterData & QueryFilter , const FCollisionFilterData & FilterData , ICollisionQueryFilterCallbackBase & Callback )
2019-10-02 17:27:26 -04:00
{
if ( IsInGameThread ( ) )
{
bDiskDataIsChaos = true ;
CaptureChaosFilterResults ( Evolution , FilterData , Callback ) ;
//copy data
SerializableChaosGeometry = InQueryGeom . Copy ( ) ;
ChaosGeometry = SerializableChaosGeometry . Get ( ) ;
StartTM = InStartTM ;
QueryFilterData = QueryFilter ;
SQType = ESQType : : Overlap ;
}
}
void FSQCapture : : EndCaptureChaosOverlap ( const ChaosInterface : : FSQHitBuffer < ChaosInterface : : FOverlapHit > & Results )
{
2020-03-03 17:06:00 -05:00
# if WITH_CHAOS
2019-10-02 17:27:26 -04:00
if ( IsInGameThread ( ) )
{
check ( SQType = = ESQType : : Overlap ) ;
2020-03-03 14:10:10 -05:00
# if WITH_CHAOS
2019-10-02 17:27:26 -04:00
ChaosOverlapBuffer = Results ;
2020-03-03 14:10:10 -05:00
# endif // WITH_CHAOS
2019-06-08 17:15:34 -04:00
}
2020-03-03 17:06:00 -05:00
# endif
2019-06-08 17:15:34 -04:00
}
2020-04-20 09:47:13 -04:00
void FSQCapture : : CaptureChaosFilterResults ( const Chaos : : FPBDRigidsEvolution & TransientEvolution , const FCollisionFilterData & FilterData , ICollisionQueryFilterCallbackBase & Callback )
2020-03-03 09:46:37 -05:00
{
using namespace Chaos ;
2021-03-05 19:27:14 -04:00
const FPBDRigidsSOAs & Particles = TransientEvolution . GetParticles ( ) ;
2020-03-03 09:46:37 -05:00
const int32 NumTransientActors = Particles . GetParticleHandles ( ) . Size ( ) ;
for ( int32 Idx = 0 ; Idx < NumTransientActors ; + + Idx )
{
2021-02-03 14:57:28 -04:00
FGeometryParticle * TransientActor = Particles . GetParticleHandles ( ) . Handle ( Idx ) - > GTGeometryParticle ( ) ;
2020-03-10 17:25:27 -04:00
const FShapesArray & TransientShapes = TransientActor - > ShapesArray ( ) ;
2020-03-03 09:46:37 -05:00
const int32 NumTransientShapes = TransientShapes . Num ( ) ;
2020-03-10 17:25:27 -04:00
TArray < TPair < FPerShapeData * , ECollisionQueryHitType > > ShapeHitsArray ; ShapeHitsArray . Reserve ( NumTransientShapes ) ;
2020-03-03 09:46:37 -05:00
for ( const auto & TransientShape : TransientShapes )
{
const ECollisionQueryHitType Result = Callback . PreFilter ( FilterData , * TransientShape , * TransientActor ) ;
ShapeHitsArray . Emplace ( TransientShape . Get ( ) , Result ) ;
}
ChaosActorToShapeHitsArray . Add ( TransientActor , ShapeHitsArray ) ;
}
}
2020-03-03 17:06:00 -05:00
template < typename TShape , typename TActor >
ECollisionQueryHitType GetFilterResultHelper ( const TShape * Shape , const TActor * Actor , const TMap < TActor * , TArray < TPair < TShape * , ECollisionQueryHitType > > > & ActorToShapeHitsArray )
{
if ( const TArray < TPair < TShape * , ECollisionQueryHitType > > * ActorToPairs = ActorToShapeHitsArray . Find ( Actor ) )
{
for ( const TPair < TShape * , ECollisionQueryHitType > & Pair : * ActorToPairs )
{
if ( Pair . Key = = Shape )
{
return Pair . Value ;
}
}
}
//todo: figure out why this hits - suspect it's related to threading and how we capture an evolution on GT
ensure ( false ) ; //should not get here, means we didn't properly capture all filter results
return ECollisionQueryHitType : : None ;
}
2021-02-03 14:57:28 -04:00
ECollisionQueryHitType FSQCapture : : GetFilterResult ( const Chaos : : FPerShapeData * Shape , const Chaos : : FGeometryParticle * Actor ) const
2020-03-03 17:06:00 -05:00
{
return GetFilterResultHelper ( Shape , Actor , ChaosActorToShapeHitsArray ) ;
}
# if PHYSICS_INTERFACE_PHYSX
2019-06-08 17:15:34 -04:00
void FSQCapture : : StartCapturePhysXSweep ( const PxScene & Scene , const PxGeometry & InQueryGeom , const FTransform & InStartTM , const FVector & InDir , float InDeltaMag , FHitFlags InOutputFlags , const FQueryFilterData & QueryFilter , const FCollisionFilterData & FilterData , ICollisionQueryFilterCallbackBase & Callback )
{
if ( IsInGameThread ( ) )
{
2019-10-02 17:27:26 -04:00
bDiskDataIsChaos = false ;
2019-06-08 17:15:34 -04:00
CapturePhysXFilterResults ( Scene , FilterData , Callback ) ;
//copy data
PhysXGeometry . storeAny ( InQueryGeom ) ;
StartTM = InStartTM ;
Dir = InDir ;
DeltaMag = InDeltaMag ;
OutputFlags = InOutputFlags ;
QueryFilterData = QueryFilter ;
SQType = ESQType : : Sweep ;
SetPhysXGeometryData ( InQueryGeom ) ;
}
}
void FSQCapture : : StartCapturePhysXRaycast ( const PxScene & Scene , const FVector & InStartPoint , const FVector & InDir , float InDeltaMag , FHitFlags InOutputFlags , const FQueryFilterData & QueryFilter , const FCollisionFilterData & FilterData , ICollisionQueryFilterCallbackBase & Callback )
{
if ( IsInGameThread ( ) )
{
2019-10-02 17:27:26 -04:00
bDiskDataIsChaos = false ;
2019-06-08 17:15:34 -04:00
CapturePhysXFilterResults ( Scene , FilterData , Callback ) ;
//copy data
StartPoint = InStartPoint ;
Dir = InDir ;
DeltaMag = InDeltaMag ;
OutputFlags = InOutputFlags ;
QueryFilterData = QueryFilter ;
SQType = ESQType : : Raycast ;
}
}
void FSQCapture : : StartCapturePhysXOverlap ( const PxScene & Scene , const PxGeometry & InQueryGeom , const FTransform & WorldTM , const FQueryFilterData & QueryFilter , const FCollisionFilterData & FilterData , ICollisionQueryFilterCallbackBase & Callback )
{
if ( IsInGameThread ( ) )
{
2019-10-02 17:27:26 -04:00
bDiskDataIsChaos = false ;
2019-06-08 17:15:34 -04:00
CapturePhysXFilterResults ( Scene , FilterData , Callback ) ;
//copy data
StartTM = WorldTM ;
QueryFilterData = QueryFilter ;
SQType = ESQType : : Overlap ;
SetPhysXGeometryData ( InQueryGeom ) ;
}
}
void FSQCapture : : CapturePhysXFilterResults ( const PxScene & TransientScene , const FCollisionFilterData & FilterData , ICollisionQueryFilterCallbackBase & Callback )
{
const uint32 NumTransientActors = TransientScene . getNbActors ( PxActorTypeFlag : : eRIGID_STATIC | PxActorTypeFlag : : eRIGID_DYNAMIC ) ;
TArray < PxActor * > TransientActors ; TransientActors . AddUninitialized ( NumTransientActors ) ;
if ( NumTransientActors )
{
TransientScene . getActors ( PxActorTypeFlag : : eRIGID_STATIC | PxActorTypeFlag : : eRIGID_DYNAMIC , TransientActors . GetData ( ) , NumTransientActors ) ;
}
PxHitFlags QueryFlags ; //we know our callback throws this away so no need to store it or use real data
for ( PxActor * TransientAct : TransientActors )
{
PxRigidActor * TransientActor = static_cast < PxRigidActor * > ( TransientAct ) ;
const uint32 NumTransientShapes = TransientActor - > getNbShapes ( ) ;
TArray < PxShape * > TransientShapes ; TransientShapes . AddUninitialized ( NumTransientShapes ) ;
TransientActor - > getShapes ( TransientShapes . GetData ( ) , NumTransientShapes ) ;
TArray < TPair < PxShape * , ECollisionQueryHitType > > ShapeHitsArray ; ShapeHitsArray . Reserve ( NumTransientShapes ) ;
for ( PxShape * TransientShape : TransientShapes )
{
const PxQueryHitType : : Enum Result = Callback . preFilter ( U2PFilterData ( FilterData ) , TransientShape , TransientActor , QueryFlags ) ;
//We must use the non transient shape/actor so that we can replay scene queries at runtime without serializing.
PxShape * NonTransientShape = static_cast < PxShape * > ( PhysSerializer . FindObject ( ( PxSerialObjectId ) TransientShape ) ) ;
ShapeHitsArray . Emplace ( NonTransientShape , P2UCollisionQueryHitType ( Result ) ) ;
NonTransientToTransientShapes . Add ( NonTransientShape , TransientShape ) ; //however, for serialization we must use the original shape/actor because conversion is done during load already
}
PxActor * NonTransientActor = static_cast < PxActor * > ( PhysSerializer . FindObject ( ( PxSerialObjectId ) TransientActor ) ) ;
2019-08-02 09:01:58 -04:00
PxActorToShapeHitsArray . Add ( NonTransientActor , ShapeHitsArray ) ;
2019-06-08 17:15:34 -04:00
NonTransientToTransientActors . Add ( NonTransientActor , TransientActor ) ;
}
}
2019-10-02 17:27:26 -04:00
2019-06-08 17:15:34 -04:00
template < typename THit >
2019-08-02 09:01:58 -04:00
void EndCaptureHelper ( PhysXInterface : : FDynamicHitBuffer < THit > & Dest , const PxHitCallback < THit > & Results )
2019-06-08 17:15:34 -04:00
{
Dest . block = Results . block ;
Dest . hasBlock = Results . hasBlock ;
if ( Results . maxNbTouches = = 0 )
{
//we know this came from a single hit buffer because that's how UE uses the physx api.
//since we're putting it into a dynamic hit buffer we need to push the block into the hits array
if ( Dest . hasBlock )
{
Dest . processTouches ( & Dest . block , 1 ) ;
}
}
else
{
//we know this came from a dynamic hit buffer because that's how UE uses the physx api. Since it's dynamic block is already in the hits buffer
2019-08-02 09:01:58 -04:00
const PhysXInterface : : FDynamicHitBuffer < THit > & DynamicResults = static_cast < const PhysXInterface : : FDynamicHitBuffer < THit > & > ( Results ) ;
2019-06-08 17:15:34 -04:00
Dest . processTouches ( DynamicResults . GetHits ( ) , DynamicResults . GetNumHits ( ) ) ;
}
}
void FSQCapture : : EndCapturePhysXSweep ( const PxHitCallback < PxSweepHit > & Results )
{
if ( IsInGameThread ( ) )
{
check ( SQType = = ESQType : : Sweep ) ;
EndCaptureHelper ( PhysXSweepBuffer , Results ) ;
}
}
void FSQCapture : : EndCapturePhysXRaycast ( const PxHitCallback < PxRaycastHit > & Results )
{
if ( IsInGameThread ( ) )
{
check ( SQType = = ESQType : : Raycast ) ;
EndCaptureHelper ( PhysXRaycastBuffer , Results ) ;
}
}
void FSQCapture : : EndCapturePhysXOverlap ( const PxHitCallback < PxOverlapHit > & Results )
{
if ( IsInGameThread ( ) )
{
check ( SQType = = ESQType : : Overlap ) ;
EndCaptureHelper ( PhysXOverlapBuffer , Results ) ;
}
}
template < typename THit >
2019-08-02 09:01:58 -04:00
void FixupBufferPointers ( FPhysTestSerializer & PhysSerializer , PhysXInterface : : FDynamicHitBuffer < THit > & PhysXBuffer )
2019-06-08 17:15:34 -04:00
{
auto FixupPointersLambda = [ & PhysSerializer ] ( PxActorShape & Hit )
{
Hit . actor = static_cast < PxRigidActor * > ( PhysSerializer . FindObject ( ( PxSerialObjectId ) Hit . actor ) ) ;
Hit . shape = static_cast < PxShape * > ( PhysSerializer . FindObject ( ( PxSerialObjectId ) Hit . shape ) ) ;
} ;
if ( PhysXBuffer . hasBlock )
{
FixupPointersLambda ( PhysXBuffer . block ) ;
}
const int32 NumHits = PhysXBuffer . GetNumHits ( ) ;
for ( int32 Idx = 0 ; Idx < NumHits ; + + Idx )
{
THit & Hit = PhysXBuffer . GetHits ( ) [ Idx ] ;
FixupPointersLambda ( Hit ) ;
}
}
2019-08-02 09:01:58 -04:00
ECollisionQueryHitType FSQCapture : : GetFilterResult ( const PxShape * Shape , const PxActor * Actor ) const
{
return GetFilterResultHelper ( Shape , Actor , PxActorToShapeHitsArray ) ;
}
2019-06-08 17:15:34 -04:00
void FSQCapture : : CreatePhysXData ( )
{
2019-10-02 17:27:26 -04:00
if ( bDiskDataIsChaos | | bPhysXDataReady )
2019-06-08 17:15:34 -04:00
{
return ;
}
if ( SQType ! = ESQType : : Raycast )
{
AlignedDataHelper = MakeUnique < FPhysXSerializerData > ( GeomData . Num ( ) ) ;
FMemory : : Memcpy ( AlignedDataHelper - > Data , GeomData . GetData ( ) , GeomData . Num ( ) ) ;
AlignedDataHelper - > Registry = PxSerialization : : createSerializationRegistry ( * GPhysXSDK ) ;
AlignedDataHelper - > Collection = PxSerialization : : createCollectionFromBinary ( AlignedDataHelper - > Data , * AlignedDataHelper - > Registry ) ;
if ( PxBase * ColShape = AlignedDataHelper - > Collection - > find ( ShapeCollectionID ) )
{
AlignedDataHelper - > Shape = static_cast < PxShape * > ( ColShape ) ;
PhysXGeometry = AlignedDataHelper - > Shape - > getGeometry ( ) ;
}
else
{
AlignedDataHelper . Reset ( ) ;
}
}
FixupBufferPointers ( PhysSerializer , PhysXRaycastBuffer ) ;
FixupBufferPointers ( PhysSerializer , PhysXSweepBuffer ) ;
FixupBufferPointers ( PhysSerializer , PhysXOverlapBuffer ) ;
FilterCallback = MakeUnique < FSQCaptureFilterCallback > ( * this ) ;
bPhysXDataReady = true ;
}
void FSQCapture : : SetPhysXGeometryData ( const PxGeometry & Geometry )
{
check ( AlignedDataHelper = = nullptr ) ;
check ( SQType ! = ESQType : : Raycast ) ;
PxSerializationRegistry * Registry = PxSerialization : : createSerializationRegistry ( * GPhysXSDK ) ;
PxCollection * Collection = PxCreateCollection ( ) ;
//create a shape so we can serialize geometry
PxMaterial * Material = GPhysXSDK - > createMaterial ( 1 , 1 , 1 ) ;
PxShape * Shape = GPhysXSDK - > createShape ( Geometry , * Material ) ;
Collection - > add ( * Shape , ShapeCollectionID ) ;
PxSerialization : : complete ( * Collection , * Registry ) ;
GeomData . Empty ( ) ;
FPhysXOutputStream Stream ( & GeomData ) ;
PxSerialization : : serializeCollectionToBinary ( Stream , * Collection , * Registry ) ;
Material - > release ( ) ;
Shape - > release ( ) ;
Collection - > release ( ) ;
Registry - > release ( ) ;
}
FSQCapture : : FPhysXSerializerData : : FPhysXSerializerData ( int32 NumBytes )
: Data ( FMemory : : Malloc ( NumBytes , 128 ) )
, Shape ( nullptr )
, Collection ( nullptr )
, Registry ( nullptr )
{
}
FSQCapture : : FPhysXSerializerData : : ~ FPhysXSerializerData ( )
{
if ( Collection )
{
//release all resources the collection created (calling release on the collection is not enough)
const uint32 NumObjects = Collection - > getNbObjects ( ) ;
TArray < PxBase * > Objects ;
Objects . AddUninitialized ( NumObjects ) ;
Collection - > getObjects ( Objects . GetData ( ) , NumObjects ) ;
for ( PxBase * Obj : Objects )
{
Obj - > release ( ) ;
}
Collection - > release ( ) ;
Registry - > release ( ) ;
}
FMemory : : Free ( Data ) ;
}
# endif
2020-03-03 17:06:00 -05:00
#if 0
2019-08-02 09:01:58 -04:00
void PhysXQueryHitToChaosQueryHit ( ChaosInterface : : FQueryHit & ChaosHit , const PxQueryHit & PxHit , const FPhysTestSerializer & Serializer )
2019-06-08 17:15:34 -04:00
{
2019-08-02 09:01:58 -04:00
ChaosHit . Actor = Serializer . PhysXActorToChaosHandle ( PxHit . actor ) ;
2019-06-08 17:15:34 -04:00
ChaosHit . Shape = Serializer . PhysXShapeToChaosImplicit ( PxHit . shape ) ;
}
2019-08-02 09:01:58 -04:00
void PhysXLocationHitToChaosLocationHit ( ChaosInterface : : FLocationHit & ChaosHit , const PxLocationHit & PxHit , const FPhysTestSerializer & Serializer )
2019-06-08 17:15:34 -04:00
{
PhysXQueryHitToChaosQueryHit ( ChaosHit , PxHit , Serializer ) ;
ChaosHit . WorldPosition = P2UVector ( PxHit . position ) ;
ChaosHit . WorldNormal = P2UVector ( PxHit . normal ) ;
ChaosHit . Flags = P2UHitFlags ( PxHit . flags ) ;
2019-08-02 09:01:58 -04:00
ChaosHit . Distance = PxHit . distance ;
2019-06-08 17:15:34 -04:00
}
2019-08-02 09:01:58 -04:00
void PhysXHitToChaosHit ( ChaosInterface : : FSweepHit & ChaosHit , const PxSweepHit & PxHit , const FPhysTestSerializer & Serializer )
2019-06-08 17:15:34 -04:00
{
PhysXLocationHitToChaosLocationHit ( ChaosHit , PxHit , Serializer ) ;
}
2019-08-02 09:01:58 -04:00
void PhysXHitToChaosHit ( ChaosInterface : : FOverlapHit & ChaosHit , const PxOverlapHit & PxHit , const FPhysTestSerializer & Serializer )
2019-06-08 17:15:34 -04:00
{
PhysXQueryHitToChaosQueryHit ( ChaosHit , PxHit , Serializer ) ;
}
2019-08-02 09:01:58 -04:00
void PhysXHitToChaosHit ( ChaosInterface : : FRaycastHit & ChaosHit , const PxRaycastHit & PxHit , const FPhysTestSerializer & Serializer )
2019-06-08 17:15:34 -04:00
{
PhysXLocationHitToChaosLocationHit ( ChaosHit , PxHit , Serializer ) ;
ChaosHit . U = PxHit . u ;
ChaosHit . V = PxHit . v ;
}
template < typename TChaosHit , typename TPhysXHit >
2019-08-02 09:01:58 -04:00
void PhysXToChaosBufferData ( ChaosInterface : : FSQHitBuffer < TChaosHit > & ChaosBuffer , const PhysXInterface : : FDynamicHitBuffer < TPhysXHit > & PhysXBuffer , const FPhysTestSerializer & PhysSerializer )
2019-06-08 17:15:34 -04:00
{
2019-08-02 09:01:58 -04:00
if ( PhysXBuffer . hasBlock )
2019-06-08 17:15:34 -04:00
{
2019-08-02 09:01:58 -04:00
TChaosHit Hit ;
PhysXHitToChaosHit ( Hit , PhysXBuffer . block , PhysSerializer ) ;
ChaosBuffer . SetBlockingHit ( Hit ) ;
2019-06-08 17:15:34 -04:00
}
const int32 NumHits = PhysXBuffer . GetNumHits ( ) ;
for ( int32 Idx = 0 ; Idx < NumHits ; + + Idx )
{
2019-08-02 09:01:58 -04:00
TChaosHit Hit ;
PhysXHitToChaosHit ( Hit , PhysXBuffer . GetHits ( ) [ Idx ] , PhysSerializer ) ;
ChaosBuffer . AddTouchingHit ( Hit ) ;
2019-06-08 17:15:34 -04:00
}
}
void FSQCapture : : CreateChaosFilterResults ( )
{
# if WITH_PHYSX
2019-08-02 09:01:58 -04:00
for ( auto Itr : PxActorToShapeHitsArray )
2019-06-08 17:15:34 -04:00
{
2021-02-03 14:57:28 -04:00
Chaos : : FGeometryParticle * Actor = PhysSerializer . PhysXActorToChaosHandle ( Itr . Key ) ;
2019-08-02 09:01:58 -04:00
const auto & ShapesArray = Actor - > ShapesArray ( ) ;
2020-03-10 17:25:27 -04:00
TArray < TPair < Chaos : : FPerShapeData * , ECollisionQueryHitType > > FilterResults ;
2019-06-08 17:15:34 -04:00
const auto & Pairs = Itr . Value ;
2019-08-02 09:01:58 -04:00
int32 Idx = 0 ;
2019-06-08 17:15:34 -04:00
for ( const auto & Pair : Pairs )
{
2020-03-10 17:25:27 -04:00
FilterResults . Add ( TPair < Chaos : : FPerShapeData * , ECollisionQueryHitType > ( ShapesArray [ Idx + + ] . Get ( ) , Pair . Value ) ) ;
2019-06-08 17:15:34 -04:00
}
2019-08-02 09:01:58 -04:00
ChaosActorToShapeHitsArray . Add ( Actor , FilterResults ) ;
2019-06-08 17:15:34 -04:00
}
# endif
}
2019-10-02 17:27:26 -04:00
void FSQCapture : : CreateChaosDataFromPhysX ( )
2019-06-08 17:15:34 -04:00
{
using namespace Chaos ;
2019-10-02 17:27:26 -04:00
if ( bDiskDataIsChaos | | bChaosDataReady )
2019-06-08 17:15:34 -04:00
{
return ;
}
if ( AlignedDataHelper & & AlignedDataHelper - > Shape )
{
TUniquePtr < TImplicitObjectTransformed < float , 3 > > TransformedObj = PxShapeToChaosGeom ( AlignedDataHelper - > Shape ) ;
//we know the dummy px shape has no transform so we want to use the inner object
ChaosGeometry = TransformedObj - > GetTransformedObject ( ) ;
ChaosOwnerObject = MoveTemp ( TransformedObj ) ;
}
2020-03-03 14:10:10 -05:00
# if WITH_CHAOS
2019-06-08 17:15:34 -04:00
PhysXToChaosBufferData ( ChaosRaycastBuffer , PhysXRaycastBuffer , PhysSerializer ) ;
PhysXToChaosBufferData ( ChaosSweepBuffer , PhysXSweepBuffer , PhysSerializer ) ;
PhysXToChaosBufferData ( ChaosOverlapBuffer , PhysXOverlapBuffer , PhysSerializer ) ;
2020-03-03 14:10:10 -05:00
# endif // WITH_CHAOS
2019-06-08 17:15:34 -04:00
CreateChaosFilterResults ( ) ;
bChaosDataReady = true ;
}
# endif