2020-05-05 11:41:40 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "GeometryCollection/GeometryCollectionTestFramework.h"
# include "GeometryCollection/GeometryCollectionTestUtility.h"
# include "GeometryCollection/GeometryCollectionUtility.h"
# include "GeometryCollection/GeometryCollectionAlgo.h"
# include "Generators/SphereGenerator.h"
# include "Generators/GridBoxMeshGenerator.h"
2020-10-22 19:19:16 -04:00
# include "HeadlessChaosTestUtility.h"
2020-05-05 11:41:40 -04:00
# include "ChaosSolversModule.h"
# include "Chaos/ErrorReporter.h"
# include "../Resource/SphereGeometry.h"
namespace GeometryCollectionTest
{
TSharedPtr < FGeometryCollection > MakeSphereElement (
FTransform RootTranform , FTransform GeomTransform ,
const int NumberOfMaterials = 2 )
{
2021-09-03 13:21:35 -04:00
UE : : Geometry : : FSphereGenerator SphereGen ;
2020-05-05 11:41:40 -04:00
SphereGen . Radius = 1.f ;
SphereGen . NumPhi = 16 ; // Vertical divisions
SphereGen . NumTheta = 16 ; // Horizontal divisions
SphereGen . Generate ( ) ;
// FSphereGenerator's points drift off the surface just a bit, so we correct for that.
2021-02-03 14:57:28 -04:00
Chaos : : TSphere < Chaos : : FReal , 3 > Sphere ( Chaos : : FVec3 ( 0 ) , SphereGen . Radius ) ;
Chaos : : FVec3 Normal ;
2020-05-05 11:41:40 -04:00
for ( int32 Idx = 0 ; Idx < SphereGen . Vertices . Num ( ) ; Idx + + )
{
auto & SrcPt = SphereGen . Vertices [ Idx ] ; // double precision
2021-02-03 14:57:28 -04:00
Chaos : : FVec3 Pt ( SrcPt [ 0 ] , SrcPt [ 1 ] , SrcPt [ 2 ] ) ; // single precision
const Chaos : : FReal Phi = Sphere . PhiWithNormal ( Pt , Normal ) ;
2020-05-05 11:41:40 -04:00
SrcPt [ 0 ] - = Phi * Normal [ 0 ] ;
SrcPt [ 1 ] - = Phi * Normal [ 1 ] ;
SrcPt [ 2 ] - = Phi * Normal [ 2 ] ;
// Ensure all the normals are pointing the right direction
check ( FVector : : DotProduct ( FVector ( SphereGen . Normals [ Idx ] [ 0 ] , SphereGen . Normals [ Idx ] [ 1 ] , SphereGen . Normals [ Idx ] [ 2 ] ) , Normal ) > 0.0f ) ;
}
// Ensure each edge has 2 associated faces (no holes)
TMap < TPair < int32 , int32 > , uint8 > EdgeCount ;
for ( auto & Tri : SphereGen . Triangles )
{
// Reverse triangle orientations
{
int32 Tmp = Tri [ 0 ] ;
Tri [ 0 ] = Tri [ 1 ] ;
Tri [ 1 ] = Tmp ;
}
for ( int32 i = 0 ; i < 3 ; i + + )
{
int32 A = Tri [ i ] ;
2021-02-03 14:57:28 -04:00
int32 B = Tri [ ( i + 1 ) % 3 ] ;
2020-05-05 11:41:40 -04:00
TPair < int32 , int32 > Edge (
A < B ? A : B ,
A > B ? A : B ) ;
if ( uint8 * Count = EdgeCount . Find ( Edge ) )
{
( * Count ) + + ;
}
else
{
EdgeCount . Emplace ( Edge ) = 1 ;
}
}
}
for ( auto & KV : EdgeCount )
{
check ( KV . Value = = 2 ) ;
}
return GeometryCollection : : MakeMeshElement (
2021-02-03 14:57:28 -04:00
SphereGen . Vertices ,
SphereGen . Normals ,
SphereGen . Triangles ,
SphereGen . UVs ,
2020-05-05 11:41:40 -04:00
RootTranform , GeomTransform , NumberOfMaterials ) ;
}
TSharedPtr < FGeometryCollection > MakeCubeElement ( FTransform RootTranform , FTransform GeomTransform )
{
2021-09-03 13:21:35 -04:00
using FVector3i = UE : : Geometry : : FVector3i ;
2021-05-05 15:07:25 -04:00
const TArray < FVector3f > PointsIn = { FVector3f ( - 1 , 1 , - 1 ) , FVector3f ( 1 , 1 , - 1 ) , FVector3f ( 1 , - 1 , - 1 ) , FVector3f ( - 1 , - 1 , - 1 ) , FVector3f ( - 1 , 1 , 1 ) , FVector3f ( 1 , 1 , 1 ) , FVector3f ( 1 , - 1 , 1 ) , FVector3f ( - 1 , - 1 , 1 ) } ;
const TArray < FVector3f > NormalsIn = { FVector3f ( - 1 , 1 , - 1 ) . GetSafeNormal ( ) , FVector3f ( 1 , 1 , - 1 ) . GetSafeNormal ( ) , FVector3f ( 1 , - 1 , - 1 ) . GetSafeNormal ( ) , FVector3f ( - 1 , - 1 , - 1 ) . GetSafeNormal ( ) , FVector3f ( - 1 , 1 , 1 ) . GetSafeNormal ( ) , FVector3f ( 1 , 1 , 1 ) . GetSafeNormal ( ) , FVector3f ( 1 , - 1 , 1 ) . GetSafeNormal ( ) , FVector3f ( - 1 , - 1 , 1 ) . GetSafeNormal ( ) } ;
2021-02-03 14:57:28 -04:00
const TArray < FVector3i > TrianglesIn = { FVector3i ( 0 , 1 , 2 ) , FVector3i ( 0 , 2 , 3 ) , FVector3i ( 2 , 1 , 6 ) , FVector3i ( 1 , 5 , 6 ) , FVector3i ( 2 , 6 , 7 ) , FVector3i ( 3 , 2 , 7 ) , FVector3i ( 4 , 7 , 3 ) , FVector3i ( 4 , 0 , 3 ) , FVector3i ( 4 , 1 , 0 ) , FVector3i ( 4 , 5 , 1 ) , FVector3i ( 5 , 4 , 7 ) , FVector3i ( 5 , 7 , 6 ) } ;
2020-05-05 11:41:40 -04:00
const TArray < FVector2f > UVsIn = { FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) } ;
return GeometryCollection : : MakeMeshElement ( PointsIn , NormalsIn , TrianglesIn , UVsIn , RootTranform , GeomTransform ) ;
}
TSharedPtr < FGeometryCollection > MakeTetrahedronElement ( FTransform RootTranform , FTransform GeomTransform )
{
2021-09-03 13:21:35 -04:00
using FVector3i = UE : : Geometry : : FVector3i ;
2021-05-05 15:07:25 -04:00
const TArray < FVector3f > PointsIn = { FVector3f ( - 1 , 1 , - 1 ) , FVector3f ( - 1 , - 1 , 1 ) , FVector3f ( 1 , - 1 , - 1 ) , FVector3f ( 1 , 1 , 1 ) } ;
const TArray < FVector3f > NormalsIn = { FVector3f ( - 1 , 1 , - 1 ) . GetSafeNormal ( ) , FVector3f ( - 1 , - 1 , 1 ) . GetSafeNormal ( ) , FVector3f ( 1 , - 1 , - 1 ) . GetSafeNormal ( ) , FVector3f ( 1 , 1 , 1 ) . GetSafeNormal ( ) } ;
2020-05-05 11:41:40 -04:00
const TArray < FVector3i > TrianglesIn = { FVector3i ( 1 , 0 , 2 ) , FVector3i ( 2 , 1 , 3 ) , FVector3i ( 3 , 2 , 0 ) , FVector3i ( 3 , 0 , 1 ) } ;
const TArray < FVector2f > UVsIn = { FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) , FVector2f ( 0.f , 0.f ) } ;
return GeometryCollection : : MakeMeshElement ( PointsIn , NormalsIn , TrianglesIn , UVsIn , RootTranform , GeomTransform ) ;
}
TSharedPtr < FGeometryCollection > MakeImportedSphereElement ( FTransform RootTranform , FTransform GeomTransform )
{
FGeometryCollection * Collection = FGeometryCollection : : NewGeometryCollection ( SphereGeometry : : RawVertexArray , SphereGeometry : : RawIndicesArray ) ;
2021-05-05 15:07:25 -04:00
TManagedArray < FVector3f > & Vertices = Collection - > Vertex ;
2022-03-04 13:04:45 -05:00
for ( int i = 0 ; i < Vertices . Num ( ) ; i + + ) Vertices [ i ] = FVector3f ( GeomTransform . TransformPosition ( FVector ( Vertices [ i ] ) ) ) ;
2020-05-05 11:41:40 -04:00
return TSharedPtr < FGeometryCollection > ( Collection ) ;
}
TSharedPtr < FGeometryCollection > MakeGriddedBoxElement (
FTransform RootTranform , FTransform GeomTransform ,
const FVector & Extents = FVector ( 1 , 1 , 1 ) ,
2021-09-03 13:21:35 -04:00
const UE : : Geometry : : FIndex3i & EdgeVertices = UE : : Geometry : : FIndex3i ( 4 , 4 , 4 ) ,
2020-05-05 11:41:40 -04:00
const int NumberOfMaterials = 2 )
{
2021-09-23 19:37:40 -04:00
using GeomVector = UE : : Math : : TVector < double > ;
2021-09-03 13:21:35 -04:00
UE : : Geometry : : FGridBoxMeshGenerator BoxGen ;
BoxGen . Box = UE : : Geometry : : FOrientedBox3d ( GeomVector : : Zero ( ) , GeomVector ( Extents ) ) ; // box center, box dimensions
2020-05-05 11:41:40 -04:00
BoxGen . EdgeVertices = EdgeVertices ;
BoxGen . Generate ( ) ;
return GeometryCollection : : MakeMeshElement (
BoxGen . Vertices ,
BoxGen . Normals ,
BoxGen . Triangles ,
BoxGen . UVs ,
FTransform : : Identity , GeomTransform , NumberOfMaterials ) ;
}
WrapperBase * CommonInit ( const TSharedPtr < FGeometryCollection > & RestCollection , const CreationParameters & Params )
{
FTransformCollection SingleTransform = FTransformCollection : : SingleTransform ( ) ;
for ( int i = 0 ; i < Params . NestedTransforms . Num ( ) ; i + + )
{
int ChildIndex = RestCollection - > NumElements ( FTransformCollection : : TransformGroup ) - 1 ;
int32 ParentIndex = RestCollection - > AppendTransform ( SingleTransform , Params . NestedTransforms [ 0 ] ) ;
RestCollection - > ParentTransforms ( ParentIndex , ChildIndex ) ;
}
2020-09-24 00:43:27 -04:00
Chaos : : FMaterialHandle NewHandle = Chaos : : FPhysicalMaterialManager : : Get ( ) . Create ( ) ;
InitMaterialToZero ( NewHandle . Get ( ) ) ;
Chaos : : FPhysicalMaterialManager : : Get ( ) . UpdateMaterial ( NewHandle ) ;
2020-05-05 11:41:40 -04:00
TSharedPtr < FGeometryDynamicCollection > DynamicCollection = GeometryCollectionToGeometryDynamicCollection ( RestCollection . Get ( ) , Params . DynamicState ) ;
FSimulationParameters SimulationParams ;
{
SimulationParams . RestCollection = RestCollection . Get ( ) ;
2020-09-24 00:43:27 -04:00
SimulationParams . PhysicalMaterialHandle = NewHandle ;
2020-05-05 11:41:40 -04:00
SimulationParams . Shared . Mass = Params . Mass ;
SimulationParams . Shared . bMassAsDensity = Params . bMassAsDensity ;
2021-05-22 12:07:31 -04:00
SimulationParams . Shared . SizeSpecificData [ 0 ] . CollisionShapesData [ 0 ] . CollisionType = Params . CollisionType ;
SimulationParams . Shared . SizeSpecificData [ 0 ] . CollisionShapesData [ 0 ] . ImplicitType = Params . ImplicitType ;
2021-08-25 18:04:59 -04:00
SimulationParams . Shared . SizeSpecificData [ 0 ] . CollisionShapesData [ 0 ] . LevelSetData . MinLevelSetResolution = Params . MinLevelSetResolution ;
SimulationParams . Shared . SizeSpecificData [ 0 ] . CollisionShapesData [ 0 ] . LevelSetData . MaxLevelSetResolution = Params . MaxLevelSetResolution ;
SimulationParams . Shared . SizeSpecificData [ 0 ] . CollisionShapesData [ 0 ] . ImplicitType = Params . ImplicitType ;
SimulationParams . Shared . SizeSpecificData [ 0 ] . CollisionShapesData [ 0 ] . CollisionParticleData . CollisionParticlesFraction = Params . CollisionParticleFraction ;
SimulationParams . CollisionSampleFraction = Params . CollisionParticleFraction ; // this should not be here, must remove/replace SimulationParams.CollisionSampleFraction in other files.
2020-05-05 11:41:40 -04:00
SimulationParams . Simulating = Params . Simulating ;
SimulationParams . EnableClustering = Params . EnableClustering ;
SimulationParams . InitialLinearVelocity = Params . InitialLinearVelocity ;
SimulationParams . InitialVelocityType = Params . InitialVelocityType ;
SimulationParams . DamageThreshold = Params . DamageThreshold ;
2021-02-03 14:57:28 -04:00
SimulationParams . MaxClusterLevel = Params . MaxClusterLevel ;
2020-05-05 11:41:40 -04:00
SimulationParams . ClusterConnectionMethod = Params . ClusterConnectionMethod ;
SimulationParams . RemoveOnFractureEnabled = Params . RemoveOnFractureEnabled ;
SimulationParams . CollisionGroup = Params . CollisionGroup ;
SimulationParams . ClusterGroupIndex = Params . ClusterGroupIndex ;
Chaos : : FErrorReporter ErrorReporter ;
BuildSimulationData ( ErrorReporter , * RestCollection . Get ( ) , SimulationParams . Shared ) ;
FGeometryCollectionPhysicsProxy : : InitializeDynamicCollection ( * DynamicCollection , * RestCollection , SimulationParams ) ;
}
FCollisionFilterData SimFilterData ;
FCollisionFilterData QueryFilterData ;
// Enable all collisions
SimFilterData . Word1 = 0xFFFF ; // this body channel
SimFilterData . Word3 = 0xFFFF ; // collision candidate channels
2020-09-24 00:43:27 -04:00
FGeometryCollectionPhysicsProxy * PhysObject =
new FGeometryCollectionPhysicsProxy (
2020-05-05 11:41:40 -04:00
nullptr , // UObject owner
* DynamicCollection , // Game thread collection
SimulationParams ,
SimFilterData ,
2021-05-25 22:01:05 -04:00
QueryFilterData ) ;
2021-03-18 15:20:03 -04:00
return new FGeometryCollectionWrapper ( RestCollection , DynamicCollection , PhysObject ) ;
2020-05-05 11:41:40 -04:00
}
template < >
WrapperBase * TNewSimulationObject < GeometryType : : GeometryCollectionWithSingleRigid > : : Init ( const CreationParameters Params )
{
TSharedPtr < FGeometryCollection > RestCollection ;
switch ( Params . SimplicialType )
{
case ESimplicialType : : Chaos_Simplicial_Box :
2021-02-03 14:57:28 -04:00
RestCollection = MakeCubeElement ( Params . RootTransform , Params . GeomTransform ) ;
2020-05-05 11:41:40 -04:00
break ;
case ESimplicialType : : Chaos_Simplicial_Sphere :
RestCollection = MakeSphereElement ( Params . RootTransform , Params . GeomTransform ) ;
break ;
case ESimplicialType : : Chaos_Simplicial_GriddleBox :
RestCollection = MakeGriddedBoxElement ( Params . RootTransform , Params . GeomTransform ) ;
break ;
case ESimplicialType : : Chaos_Simplicial_Tetrahedron :
RestCollection = MakeTetrahedronElement ( Params . RootTransform , Params . GeomTransform ) ;
break ;
case ESimplicialType : : Chaos_Simplicial_Imported_Sphere :
RestCollection = MakeImportedSphereElement ( Params . RootTransform , Params . GeomTransform ) ;
break ;
case ESimplicialType : : Chaos_Simplicial_None :
RestCollection = TSharedPtr < FGeometryCollection > ( new FGeometryCollection ( ) ) ;
RestCollection - > AddElements ( 1 , FGeometryCollection : : GeometryGroup ) ;
RestCollection - > TransformIndex [ 0 ] = 0 ;
RestCollection - > InnerRadius [ 0 ] = 1.f ; // Assume sphere w/radius 1
RestCollection - > OuterRadius [ 0 ] = 1.f ; // Assume sphere w/radius 1
RestCollection - > AddElements ( 1 , FGeometryCollection : : TransformGroup ) ;
RestCollection - > Transform [ 0 ] = Params . RootTransform ;
RestCollection - > Transform [ 0 ] . NormalizeRotation ( ) ;
break ;
default :
check ( false ) ; // unimplemented!
break ;
}
2021-03-18 15:20:03 -04:00
return CommonInit ( RestCollection , Params ) ;
2020-05-05 11:41:40 -04:00
}
template < >
WrapperBase * TNewSimulationObject < GeometryType : : RigidFloor > : : Init ( const CreationParameters Params )
{
TSharedPtr < Chaos : : FChaosPhysicsMaterial > PhysicalMaterial = MakeShared < Chaos : : FChaosPhysicsMaterial > ( ) ; InitMaterialToZero ( PhysicalMaterial . Get ( ) ) ;
2021-02-03 14:57:28 -04:00
auto Proxy = FSingleParticlePhysicsProxy : : Create ( Chaos : : FGeometryParticle : : CreateParticle ( ) ) ;
auto & Particle = Proxy - > GetGameThreadAPI ( ) ;
2021-09-02 11:55:11 -04:00
Particle . SetGeometry ( TUniquePtr < Chaos : : TPlane < FReal , 3 > > ( new Chaos : : TPlane < FReal , 3 > ( FVector ( 0 ) , FVector ( 0 , 0 , 1 ) ) ) ) ;
2020-05-05 11:41:40 -04:00
FCollisionFilterData FilterData ;
FilterData . Word1 = 0xFFFF ;
FilterData . Word3 = 0xFFFF ;
2021-02-03 14:57:28 -04:00
Particle . SetShapeSimData ( 0 , FilterData ) ;
2020-05-05 11:41:40 -04:00
2021-02-03 14:57:28 -04:00
return new RigidBodyWrapper ( PhysicalMaterial , Proxy ) ;
2020-05-05 11:41:40 -04:00
}
template < >
WrapperBase * TNewSimulationObject < GeometryType : : GeometryCollectionWithSuppliedRestCollection > : : Init ( const CreationParameters Params )
{
check ( Params . RestCollection . IsValid ( ) ) ;
2021-03-18 15:20:03 -04:00
return CommonInit ( Params . RestCollection , Params ) ;
2020-05-05 11:41:40 -04:00
}
2021-03-18 15:20:03 -04:00
FFramework : : FFramework ( FrameworkParameters Parameters )
2020-06-23 18:40:00 -04:00
: Dt ( Parameters . Dt )
, Module ( FChaosSolversModule : : GetModule ( ) )
, Solver ( nullptr )
2020-05-05 11:41:40 -04:00
{
2021-06-14 15:00:35 -04:00
Solver = Module - > CreateSolver ( nullptr , /*AsyncDt=*/ - 1 , Parameters . ThreadingMode ) ; //until refactor is done, solver must be created after thread change
2020-10-22 19:19:16 -04:00
ChaosTest : : InitSolverSettings ( Solver ) ;
2020-05-05 11:41:40 -04:00
}
2021-03-18 15:20:03 -04:00
FFramework : : ~ FFramework ( )
2020-05-05 11:41:40 -04:00
{
for ( WrapperBase * Object : PhysicsObjects )
{
2021-03-18 15:20:03 -04:00
if ( FGeometryCollectionWrapper * GCW = Object - > As < FGeometryCollectionWrapper > ( ) )
2020-05-05 11:41:40 -04:00
{
2020-09-01 14:07:48 -04:00
Solver - > UnregisterObject ( GCW - > PhysObject ) ;
2020-05-05 11:41:40 -04:00
}
else if ( RigidBodyWrapper * BCW = Object - > As < RigidBodyWrapper > ( ) )
{
2020-09-01 14:07:48 -04:00
Solver - > UnregisterObject ( BCW - > Particle ) ;
2020-05-05 11:41:40 -04:00
}
}
2021-02-03 14:57:28 -04:00
2020-05-05 11:41:40 -04:00
FChaosSolversModule : : GetModule ( ) - > DestroySolver ( Solver ) ;
2020-09-24 00:43:27 -04:00
//don't delete wrapper objects until solver is gone.
//can have callbacks that rely on wrapper objects
for ( WrapperBase * Object : PhysicsObjects )
{
delete Object ;
}
2020-05-05 11:41:40 -04:00
}
2021-03-18 15:20:03 -04:00
void FFramework : : AddSimulationObject ( WrapperBase * Object )
2020-05-05 11:41:40 -04:00
{
PhysicsObjects . Add ( Object ) ;
}
2021-02-03 14:57:28 -04:00
2021-03-18 15:20:03 -04:00
void FFramework : : Initialize ( )
2020-05-05 11:41:40 -04:00
{
for ( WrapperBase * Object : PhysicsObjects )
{
2021-03-18 15:20:03 -04:00
if ( FGeometryCollectionWrapper * GCW = Object - > As < FGeometryCollectionWrapper > ( ) )
2020-05-05 11:41:40 -04:00
{
Solver - > RegisterObject ( GCW - > PhysObject ) ;
Solver - > AddDirtyProxy ( GCW - > PhysObject ) ;
}
else if ( RigidBodyWrapper * RBW = Object - > As < RigidBodyWrapper > ( ) )
{
Solver - > RegisterObject ( RBW - > Particle ) ;
}
}
}
2021-03-18 15:20:03 -04:00
void FFramework : : Advance ( )
2020-05-05 11:41:40 -04:00
{
Solver - > SyncEvents_GameThread ( ) ;
2020-08-11 01:36:57 -04:00
Solver - > AdvanceAndDispatch_External ( Dt ) ;
2020-05-05 11:41:40 -04:00
Solver - > UpdateGameThreadStructures ( ) ;
}
2021-02-03 14:57:28 -04:00
2020-05-05 11:41:40 -04:00
} // end namespace GeometryCollectionTest