2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2018-12-12 11:25:29 -05:00
/*=============================================================================
GeometryCollection . cpp : UGeometryCollection methods .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "GeometryCollection/GeometryCollectionObject.h"
# include "GeometryCollection/GeometryCollection.h"
# include "GeometryCollection/GeometryCollectionCache.h"
# include "UObject/DestructionObjectVersion.h"
2020-07-15 01:49:28 -04:00
# include "UObject/UE5MainStreamObjectVersion.h"
2018-12-12 11:25:29 -05:00
# include "Serialization/ArchiveCountMem.h"
# include "HAL/IConsoleManager.h"
2020-09-24 00:43:27 -04:00
# include "Interfaces/ITargetPlatform.h"
2018-12-12 11:25:29 -05:00
# include "UObject/Package.h"
# include "Materials/MaterialInstance.h"
2020-03-27 17:52:09 -04:00
# include "ProfilingDebugging/CookStats.h"
2020-12-01 11:18:19 -04:00
# include "EngineUtils.h"
2021-02-21 16:04:49 -04:00
# include "Engine/StaticMesh.h"
2021-07-03 18:25:03 -04:00
# include "PhysicsEngine/PhysicsSettings.h"
2020-09-24 00:43:27 -04:00
2019-06-08 17:15:34 -04:00
# if WITH_EDITOR
# include "GeometryCollection/DerivedDataGeometryCollectionCooker.h"
2022-01-31 12:57:29 -05:00
# include "GeometryCollection/GeometryCollectionConvexUtility.h"
2022-02-10 17:08:59 -05:00
# include "GeometryCollection/GeometryCollectionEngineSizeSpecificUtility.h"
2020-07-21 15:17:07 -04:00
# include "GeometryCollection/GeometryCollectionComponent.h"
2019-06-08 17:15:34 -04:00
# include "DerivedDataCacheInterface.h"
# include "Serialization/MemoryReader.h"
2020-07-15 01:49:28 -04:00
# include "NaniteBuilder.h"
# include "Rendering/NaniteResources.h"
2020-07-15 03:39:13 -04:00
// TODO: Temp until new asset-agnostic builder API
# include "StaticMeshResources.h"
2019-06-08 17:15:34 -04:00
# endif
# include "GeometryCollection/GeometryCollectionSimulationCoreTypes.h"
# include "Chaos/ChaosArchive.h"
2020-03-11 17:01:25 -04:00
# include "GeometryCollectionProxyData.h"
2019-06-08 17:15:34 -04:00
2020-10-22 19:19:16 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogGeometryCollectionInternal , Log , All ) ;
2018-12-12 11:25:29 -05:00
2021-04-20 09:50:07 -04:00
bool GeometryCollectionAssetForceStripOnCook = false ;
FAutoConsoleVariableRef CVarGeometryCollectionBypassPhysicsAttributes (
TEXT ( " p.GeometryCollectionAssetForceStripOnCook " ) ,
GeometryCollectionAssetForceStripOnCook ,
TEXT ( " Bypass the construction of simulation properties when all bodies are simply cached. for playback. " ) ) ;
2022-02-09 13:27:35 -05:00
bool bGeometryCollectionEnableForcedConvexGenerationInSerialize = true ;
FAutoConsoleVariableRef CVarGeometryCollectionEnableForcedConvexGenerationInSerialize (
TEXT ( " p.GeometryCollectionEnableForcedConvexGenerationInSerialize " ) ,
bGeometryCollectionEnableForcedConvexGenerationInSerialize ,
TEXT ( " Enable generation of convex geometry on older destruction files.[def:true] " ) ) ;
2021-04-20 09:50:07 -04:00
2020-03-27 17:52:09 -04:00
# if ENABLE_COOK_STATS
namespace GeometryCollectionCookStats
{
static FCookStats : : FDDCResourceUsageStats UsageStats ;
static FCookStatsManager : : FAutoRegisterCallback RegisterCookStats ( [ ] ( FCookStatsManager : : AddStatFuncRef AddStat )
{
UsageStats . LogStats ( AddStat , TEXT ( " GeometryCollection.Usage " ) , TEXT ( " " ) ) ;
} ) ;
}
# endif
2022-03-29 02:16:42 -04:00
static constexpr float DefaultMaxSizeValue = 99999.9 ;
2018-12-12 11:25:29 -05:00
UGeometryCollection : : UGeometryCollection ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2020-11-20 01:16:51 -04:00
# if WITH_EDITOR
, bManualDataCreate ( false )
# endif
2021-01-25 00:53:27 -04:00
, EnableClustering ( true )
, ClusterGroupIndex ( 0 )
, MaxClusterLevel ( 100 )
2022-02-09 19:28:14 -05:00
, DamageThreshold ( { 500000.f , 50000.f , 5000.f } )
2022-04-28 20:20:32 -04:00
, PerClusterOnlyDamageThreshold ( false )
2022-01-19 13:48:58 -05:00
, ClusterConnectionType ( EClusterConnectionTypeEnum : : Chaos_MinimalSpanningSubsetDelaunayTriangulation )
2022-05-20 15:20:13 -04:00
, ConnectionGraphBoundsFilteringMargin ( 0 )
2021-06-01 14:20:47 -04:00
, bUseFullPrecisionUVs ( false )
2021-04-20 09:50:07 -04:00
, bStripOnCook ( false )
2020-07-15 01:49:28 -04:00
, EnableNanite ( false )
2021-05-22 12:07:31 -04:00
# if WITH_EDITORONLY_DATA
, CollisionType_DEPRECATED ( ECollisionTypeEnum : : Chaos_Volumetric )
2022-01-31 12:57:29 -05:00
, ImplicitType_DEPRECATED ( EImplicitTypeEnum : : Chaos_Implicit_Convex )
2021-05-22 12:07:31 -04:00
, MinLevelSetResolution_DEPRECATED ( 10 )
, MaxLevelSetResolution_DEPRECATED ( 10 )
, MinClusterLevelSetResolution_DEPRECATED ( 50 )
, MaxClusterLevelSetResolution_DEPRECATED ( 50 )
, CollisionObjectReductionPercentage_DEPRECATED ( 0.0f )
# endif
2022-02-02 07:39:24 -05:00
, bMassAsDensity ( true )
, Mass ( 2500.0f )
2019-06-08 17:15:34 -04:00
, MinimumMassClamp ( 0.1f )
2022-05-26 12:02:54 -04:00
, bImportCollisionFromSource ( false )
2021-08-31 20:24:01 -04:00
, bRemoveOnMaxSleep ( false )
2022-02-02 07:39:24 -05:00
, MaximumSleepTime ( 5.0 , 10.0 )
, RemovalDuration ( 2.5 , 5.0 )
2019-06-08 17:15:34 -04:00
, EnableRemovePiecesOnFracture ( false )
2018-12-12 11:25:29 -05:00
, GeometryCollection ( new FGeometryCollection ( ) )
{
PersistentGuid = FGuid : : NewGuid ( ) ;
InvalidateCollection ( ) ;
2020-11-19 22:01:51 -04:00
# if WITH_EDITOR
SimulationDataGuid = StateGuid ;
2021-04-20 09:50:07 -04:00
bStripOnCook = GeometryCollectionAssetForceStripOnCook ;
2020-11-19 22:01:51 -04:00
# endif
2018-12-12 11:25:29 -05:00
}
2021-05-22 12:07:31 -04:00
FGeometryCollectionLevelSetData : : FGeometryCollectionLevelSetData ( )
: MinLevelSetResolution ( 5 )
2019-06-08 17:15:34 -04:00
, MaxLevelSetResolution ( 10 )
, MinClusterLevelSetResolution ( 25 )
, MaxClusterLevelSetResolution ( 50 )
2021-05-22 12:07:31 -04:00
{
}
FGeometryCollectionCollisionParticleData : : FGeometryCollectionCollisionParticleData ( )
: CollisionParticlesFraction ( 1.0f )
2019-08-15 21:16:13 -04:00
, MaximumCollisionParticles ( 60 )
2021-05-22 12:07:31 -04:00
{
}
FGeometryCollectionCollisionTypeData : : FGeometryCollectionCollisionTypeData ( )
: CollisionType ( ECollisionTypeEnum : : Chaos_Volumetric )
2022-01-31 12:57:29 -05:00
, ImplicitType ( EImplicitTypeEnum : : Chaos_Implicit_Convex )
2021-05-22 12:07:31 -04:00
, LevelSet ( )
, CollisionParticles ( )
, CollisionObjectReductionPercentage ( 0.0f )
2022-02-08 11:57:43 -05:00
, CollisionMarginFraction ( 0.f )
2021-05-22 12:07:31 -04:00
{
}
FGeometryCollectionSizeSpecificData : : FGeometryCollectionSizeSpecificData ( )
2022-03-29 02:16:42 -04:00
: MaxSize ( DefaultMaxSizeValue )
2021-05-22 12:07:31 -04:00
, CollisionShapes ( { FGeometryCollectionCollisionTypeData ( ) } )
# if WITH_EDITORONLY_DATA
, CollisionType_DEPRECATED ( ECollisionTypeEnum : : Chaos_Volumetric )
2022-01-31 12:57:29 -05:00
, ImplicitType_DEPRECATED ( EImplicitTypeEnum : : Chaos_Implicit_Convex )
2021-05-22 12:07:31 -04:00
, MinLevelSetResolution_DEPRECATED ( 5 )
, MaxLevelSetResolution_DEPRECATED ( 10 )
, MinClusterLevelSetResolution_DEPRECATED ( 25 )
, MaxClusterLevelSetResolution_DEPRECATED ( 50 )
, CollisionObjectReductionPercentage_DEPRECATED ( 0 )
, CollisionParticlesFraction_DEPRECATED ( 1.f )
, MaximumCollisionParticles_DEPRECATED ( 60 )
# endif
2022-02-02 07:39:24 -05:00
, DamageThreshold ( 5000.0 )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
}
2021-05-22 12:07:31 -04:00
bool FGeometryCollectionSizeSpecificData : : Serialize ( FArchive & Ar )
{
Ar . UsingCustomVersion ( FUE5MainStreamObjectVersion : : GUID ) ;
2022-01-05 21:51:22 -05:00
Ar . UsingCustomVersion ( FPhysicsObjectVersion : : GUID ) ;
2021-05-22 12:07:31 -04:00
return false ; //We only have this function to mark custom GUID. Still want serialize tagged properties
}
# if WITH_EDITORONLY_DATA
void FGeometryCollectionSizeSpecificData : : PostSerialize ( const FArchive & Ar )
{
2022-01-05 21:51:22 -05:00
const int32 PhysicsObjectVersion = Ar . CustomVer ( FPhysicsObjectVersion : : GUID ) ;
const int32 StreamObjectVersion = Ar . CustomVer ( FUE5MainStreamObjectVersion : : GUID ) ;
2021-05-22 12:07:31 -04:00
// make sure to load back the deprecated values in the new structure if necessary
2022-01-05 21:51:22 -05:00
// IMPORTANT : this was merge backed in UE4 and PhysicsObjectVersion had to be used,
// that's why we need to test both version to make sure backward asset compatibility is maintained
if ( Ar . IsLoading ( ) & & (
StreamObjectVersion < FUE5MainStreamObjectVersion : : GeometryCollectionUserDefinedCollisionShapes & &
PhysicsObjectVersion < FPhysicsObjectVersion : : GeometryCollectionUserDefinedCollisionShapes
) )
2021-05-22 12:07:31 -04:00
{
2021-06-03 21:03:44 -04:00
if ( CollisionShapes . Num ( ) )
2021-05-22 12:07:31 -04:00
{
2021-06-03 21:03:44 -04:00
// @todo(chaos destruction collisions) : Add support for many
2021-05-22 12:07:31 -04:00
CollisionShapes [ 0 ] . CollisionType = CollisionType_DEPRECATED ;
CollisionShapes [ 0 ] . ImplicitType = ImplicitType_DEPRECATED ;
CollisionShapes [ 0 ] . CollisionObjectReductionPercentage = CollisionObjectReductionPercentage_DEPRECATED ;
2021-07-03 18:25:03 -04:00
CollisionShapes [ 0 ] . CollisionMarginFraction = UPhysicsSettings : : Get ( ) - > SolverOptions . CollisionMarginFraction ;
2021-05-22 12:07:31 -04:00
CollisionShapes [ 0 ] . CollisionParticles . CollisionParticlesFraction = CollisionParticlesFraction_DEPRECATED ;
CollisionShapes [ 0 ] . CollisionParticles . MaximumCollisionParticles = MaximumCollisionParticles_DEPRECATED ;
CollisionShapes [ 0 ] . LevelSet . MinLevelSetResolution = MinLevelSetResolution_DEPRECATED ;
CollisionShapes [ 0 ] . LevelSet . MaxLevelSetResolution = MaxLevelSetResolution_DEPRECATED ;
CollisionShapes [ 0 ] . LevelSet . MinClusterLevelSetResolution = MinClusterLevelSetResolution_DEPRECATED ;
CollisionShapes [ 0 ] . LevelSet . MaxClusterLevelSetResolution = MaxClusterLevelSetResolution_DEPRECATED ;
}
}
}
# endif
2019-06-08 17:15:34 -04:00
void FillSharedSimulationSizeSpecificData ( FSharedSimulationSizeSpecificData & ToData , const FGeometryCollectionSizeSpecificData & FromData )
{
ToData . MaxSize = FromData . MaxSize ;
2021-05-22 12:07:31 -04:00
ToData . CollisionShapesData . SetNumUninitialized ( FromData . CollisionShapes . Num ( ) ) ;
2021-06-03 21:03:44 -04:00
if ( FromData . CollisionShapes . Num ( ) )
2021-05-22 12:07:31 -04:00
{
2021-06-03 21:03:44 -04:00
for ( int i = 0 ; i < FromData . CollisionShapes . Num ( ) ; i + + )
{
ToData . CollisionShapesData [ i ] . CollisionType = FromData . CollisionShapes [ i ] . CollisionType ;
ToData . CollisionShapesData [ i ] . ImplicitType = FromData . CollisionShapes [ i ] . ImplicitType ;
ToData . CollisionShapesData [ i ] . LevelSetData . MinLevelSetResolution = FromData . CollisionShapes [ i ] . LevelSet . MinLevelSetResolution ;
ToData . CollisionShapesData [ i ] . LevelSetData . MaxLevelSetResolution = FromData . CollisionShapes [ i ] . LevelSet . MaxLevelSetResolution ;
ToData . CollisionShapesData [ i ] . LevelSetData . MinClusterLevelSetResolution = FromData . CollisionShapes [ i ] . LevelSet . MinClusterLevelSetResolution ;
ToData . CollisionShapesData [ i ] . LevelSetData . MaxClusterLevelSetResolution = FromData . CollisionShapes [ i ] . LevelSet . MaxClusterLevelSetResolution ;
ToData . CollisionShapesData [ i ] . CollisionObjectReductionPercentage = FromData . CollisionShapes [ i ] . CollisionObjectReductionPercentage ;
2021-07-03 18:25:03 -04:00
ToData . CollisionShapesData [ i ] . CollisionMarginFraction = FromData . CollisionShapes [ i ] . CollisionMarginFraction ;
2021-06-03 21:03:44 -04:00
ToData . CollisionShapesData [ i ] . CollisionParticleData . CollisionParticlesFraction = FromData . CollisionShapes [ i ] . CollisionParticles . CollisionParticlesFraction ;
ToData . CollisionShapesData [ i ] . CollisionParticleData . MaximumCollisionParticles = FromData . CollisionShapes [ i ] . CollisionParticles . MaximumCollisionParticles ;
}
2021-05-22 12:07:31 -04:00
}
2021-01-29 00:35:21 -04:00
ToData . DamageThreshold = FromData . DamageThreshold ;
2018-12-12 11:25:29 -05:00
}
2021-05-25 17:13:53 -04:00
FGeometryCollectionSizeSpecificData UGeometryCollection : : GeometryCollectionSizeSpecificDataDefaults ( )
2021-05-22 12:07:31 -04:00
{
FGeometryCollectionSizeSpecificData Data ;
2022-03-29 02:16:42 -04:00
Data . MaxSize = DefaultMaxSizeValue ;
2021-06-03 21:03:44 -04:00
if ( Data . CollisionShapes . Num ( ) )
{
Data . CollisionShapes [ 0 ] . CollisionType = ECollisionTypeEnum : : Chaos_Volumetric ;
2022-01-31 12:57:29 -05:00
Data . CollisionShapes [ 0 ] . ImplicitType = EImplicitTypeEnum : : Chaos_Implicit_Capsule ;
2021-06-03 21:03:44 -04:00
Data . CollisionShapes [ 0 ] . LevelSet . MinLevelSetResolution = 5 ;
Data . CollisionShapes [ 0 ] . LevelSet . MaxLevelSetResolution = 10 ;
Data . CollisionShapes [ 0 ] . LevelSet . MinClusterLevelSetResolution = 25 ;
Data . CollisionShapes [ 0 ] . LevelSet . MaxClusterLevelSetResolution = 50 ;
Data . CollisionShapes [ 0 ] . CollisionObjectReductionPercentage = 1.0 ;
2021-07-03 18:25:03 -04:00
Data . CollisionShapes [ 0 ] . CollisionMarginFraction = UPhysicsSettings : : Get ( ) - > SolverOptions . CollisionMarginFraction ;
2021-06-03 21:03:44 -04:00
Data . CollisionShapes [ 0 ] . CollisionParticles . CollisionParticlesFraction = 1.0 ;
Data . CollisionShapes [ 0 ] . CollisionParticles . MaximumCollisionParticles = 60 ;
}
2022-02-02 07:39:24 -05:00
Data . DamageThreshold = 5000.0f ;
2021-05-22 12:07:31 -04:00
return Data ;
}
2021-05-25 17:13:53 -04:00
2021-05-26 17:46:30 -04:00
void UGeometryCollection : : ValidateSizeSpecificDataDefaults ( )
2021-05-25 17:13:53 -04:00
{
auto HasDefault = [ ] ( const TArray < FGeometryCollectionSizeSpecificData > & DatasIn )
{
for ( const FGeometryCollectionSizeSpecificData & Data : DatasIn )
{
2022-03-29 02:16:42 -04:00
if ( Data . MaxSize > = DefaultMaxSizeValue )
2021-05-25 17:13:53 -04:00
{
return true ;
}
}
return false ;
} ;
if ( ! SizeSpecificData . Num ( ) | | ! HasDefault ( SizeSpecificData ) )
{
FGeometryCollectionSizeSpecificData Data = GeometryCollectionSizeSpecificDataDefaults ( ) ;
2021-06-03 21:03:44 -04:00
if ( Data . CollisionShapes . Num ( ) )
2021-05-25 17:13:53 -04:00
{
2021-06-03 21:03:44 -04:00
# if WITH_EDITORONLY_DATA
Data . CollisionShapes [ 0 ] . CollisionType = CollisionType_DEPRECATED ;
Data . CollisionShapes [ 0 ] . ImplicitType = ImplicitType_DEPRECATED ;
Data . CollisionShapes [ 0 ] . LevelSet . MinLevelSetResolution = MinLevelSetResolution_DEPRECATED ;
Data . CollisionShapes [ 0 ] . LevelSet . MaxLevelSetResolution = MaxLevelSetResolution_DEPRECATED ;
Data . CollisionShapes [ 0 ] . LevelSet . MinClusterLevelSetResolution = MinClusterLevelSetResolution_DEPRECATED ;
Data . CollisionShapes [ 0 ] . LevelSet . MaxClusterLevelSetResolution = MaxClusterLevelSetResolution_DEPRECATED ;
Data . CollisionShapes [ 0 ] . CollisionObjectReductionPercentage = CollisionObjectReductionPercentage_DEPRECATED ;
2021-07-03 18:25:03 -04:00
Data . CollisionShapes [ 0 ] . CollisionMarginFraction = UPhysicsSettings : : Get ( ) - > SolverOptions . CollisionMarginFraction ;
2021-06-03 21:03:44 -04:00
# endif
if ( Data . CollisionShapes [ 0 ] . ImplicitType = = EImplicitTypeEnum : : Chaos_Implicit_LevelSet )
{
Data . CollisionShapes [ 0 ] . CollisionType = ECollisionTypeEnum : : Chaos_Surface_Volumetric ;
}
2021-05-25 17:13:53 -04:00
}
SizeSpecificData . Add ( Data ) ;
}
2021-06-03 21:03:44 -04:00
check ( SizeSpecificData . Num ( ) ) ;
2021-05-25 17:13:53 -04:00
}
2022-01-31 12:57:29 -05:00
void UGeometryCollection : : UpdateConvexGeometry ( )
{
# if WITH_EDITOR
if ( GeometryCollection )
{
FGeometryCollectionConvexPropertiesInterface : : FConvexCreationProperties ConvexProperties = GeometryCollection - > GetConvexProperties ( ) ;
2022-06-13 11:05:31 -04:00
FGeometryCollectionConvexUtility : : CreateNonOverlappingConvexHullData ( GeometryCollection . Get ( ) , ConvexProperties . FractionRemove ,
ConvexProperties . SimplificationThreshold , ConvexProperties . CanExceedFraction , ConvexProperties . bRemoveOverlaps ) ;
2022-01-31 12:57:29 -05:00
InvalidateCollection ( ) ;
}
# endif
}
2021-05-25 17:13:53 -04:00
2019-06-08 17:15:34 -04:00
float KgCm3ToKgM3 ( float Density )
{
return Density * 1000000 ;
}
float KgM3ToKgCm3 ( float Density )
{
return Density / 1000000 ;
}
void UGeometryCollection : : GetSharedSimulationParams ( FSharedSimulationParameters & OutParams ) const
{
2021-05-22 12:07:31 -04:00
const FGeometryCollectionSizeSpecificData & SizeSpecificDefault = GetDefaultSizeSpecificData ( ) ;
2019-06-08 17:15:34 -04:00
OutParams . bMassAsDensity = bMassAsDensity ;
OutParams . Mass = bMassAsDensity ? KgM3ToKgCm3 ( Mass ) : Mass ; //todo(ocohen): we still have the solver working in old units. This is mainly to fix ui issues. Long term need to normalize units for best precision
OutParams . MinimumMassClamp = MinimumMassClamp ;
2020-10-22 19:19:16 -04:00
2019-06-08 17:15:34 -04:00
FGeometryCollectionSizeSpecificData InfSize ;
2021-06-03 21:03:44 -04:00
if ( SizeSpecificDefault . CollisionShapes . Num ( ) )
{
InfSize . CollisionShapes . SetNum ( 1 ) ; // @todo(chaos destruction collisions) : Add support for multiple shapes.
OutParams . MaximumCollisionParticleCount = SizeSpecificDefault . CollisionShapes [ 0 ] . CollisionParticles . MaximumCollisionParticles ;
2019-06-08 17:15:34 -04:00
2021-06-03 21:03:44 -04:00
ECollisionTypeEnum SelectedCollisionType = SizeSpecificDefault . CollisionShapes [ 0 ] . CollisionType ;
if ( SelectedCollisionType = = ECollisionTypeEnum : : Chaos_Volumetric & & SizeSpecificDefault . CollisionShapes [ 0 ] . ImplicitType = = EImplicitTypeEnum : : Chaos_Implicit_LevelSet )
{
UE_LOG ( LogGeometryCollectionInternal , Verbose , TEXT ( " LevelSet geometry selected but non-particle collisions selected. Forcing particle-implicit collisions for %s " ) , * GetPathName ( ) ) ;
SelectedCollisionType = ECollisionTypeEnum : : Chaos_Surface_Volumetric ;
}
InfSize . CollisionShapes [ 0 ] . CollisionType = SelectedCollisionType ;
InfSize . CollisionShapes [ 0 ] . ImplicitType = SizeSpecificDefault . CollisionShapes [ 0 ] . ImplicitType ;
InfSize . CollisionShapes [ 0 ] . LevelSet . MinLevelSetResolution = SizeSpecificDefault . CollisionShapes [ 0 ] . LevelSet . MinLevelSetResolution ;
InfSize . CollisionShapes [ 0 ] . LevelSet . MaxLevelSetResolution = SizeSpecificDefault . CollisionShapes [ 0 ] . LevelSet . MaxLevelSetResolution ;
InfSize . CollisionShapes [ 0 ] . LevelSet . MinClusterLevelSetResolution = SizeSpecificDefault . CollisionShapes [ 0 ] . LevelSet . MinClusterLevelSetResolution ;
InfSize . CollisionShapes [ 0 ] . LevelSet . MaxClusterLevelSetResolution = SizeSpecificDefault . CollisionShapes [ 0 ] . LevelSet . MaxClusterLevelSetResolution ;
InfSize . CollisionShapes [ 0 ] . CollisionObjectReductionPercentage = SizeSpecificDefault . CollisionShapes [ 0 ] . CollisionObjectReductionPercentage ;
2021-07-03 18:25:03 -04:00
InfSize . CollisionShapes [ 0 ] . CollisionMarginFraction = SizeSpecificDefault . CollisionShapes [ 0 ] . CollisionMarginFraction ;
2021-06-03 21:03:44 -04:00
InfSize . CollisionShapes [ 0 ] . CollisionParticles . CollisionParticlesFraction = SizeSpecificDefault . CollisionShapes [ 0 ] . CollisionParticles . CollisionParticlesFraction ;
InfSize . CollisionShapes [ 0 ] . CollisionParticles . MaximumCollisionParticles = SizeSpecificDefault . CollisionShapes [ 0 ] . CollisionParticles . MaximumCollisionParticles ;
}
2022-04-21 18:50:41 -04:00
InfSize . MaxSize = TNumericLimits < float > : : Max ( ) ;
2019-06-08 17:15:34 -04:00
OutParams . SizeSpecificData . SetNum ( SizeSpecificData . Num ( ) + 1 ) ;
FillSharedSimulationSizeSpecificData ( OutParams . SizeSpecificData [ 0 ] , InfSize ) ;
for ( int32 Idx = 0 ; Idx < SizeSpecificData . Num ( ) ; + + Idx )
{
FillSharedSimulationSizeSpecificData ( OutParams . SizeSpecificData [ Idx + 1 ] , SizeSpecificData [ Idx ] ) ;
}
if ( EnableRemovePiecesOnFracture )
{
FixupRemoveOnFractureMaterials ( OutParams ) ;
}
2022-05-26 12:02:54 -04:00
OutParams . bUseImportedCollisionImplicits = bImportCollisionFromSource ;
2019-06-08 17:15:34 -04:00
OutParams . SizeSpecificData . Sort ( ) ; //can we do this at editor time on post edit change?
}
void UGeometryCollection : : FixupRemoveOnFractureMaterials ( FSharedSimulationParameters & SharedParms ) const
{
// Match RemoveOnFracture materials with materials in model and record the material indices
int32 NumMaterials = Materials . Num ( ) ;
for ( int32 MaterialIndex = 0 ; MaterialIndex < NumMaterials ; MaterialIndex + + )
{
UMaterialInterface * MaterialInfo = Materials [ MaterialIndex ] ;
for ( int32 ROFMaterialIndex = 0 ; ROFMaterialIndex < RemoveOnFractureMaterials . Num ( ) ; ROFMaterialIndex + + )
{
if ( MaterialInfo = = RemoveOnFractureMaterials [ ROFMaterialIndex ] )
{
SharedParms . RemoveOnFractureIndices . Add ( MaterialIndex ) ;
break ;
}
}
}
}
2020-10-22 19:19:16 -04:00
void UGeometryCollection : : Reset ( )
{
if ( GeometryCollection . IsValid ( ) )
{
Modify ( ) ;
GeometryCollection - > Empty ( ) ;
Materials . Empty ( ) ;
2021-02-21 16:04:54 -04:00
EmbeddedGeometryExemplar . Empty ( ) ;
2020-10-22 19:19:16 -04:00
InvalidateCollection ( ) ;
}
}
2018-12-12 11:25:29 -05:00
/** AppendGeometry */
2019-06-08 17:15:34 -04:00
int32 UGeometryCollection : : AppendGeometry ( const UGeometryCollection & Element , bool ReindexAllMaterials , const FTransform & TransformRoot )
2018-12-12 11:25:29 -05:00
{
Modify ( ) ;
InvalidateCollection ( ) ;
2019-06-08 17:15:34 -04:00
// add all materials
// if there are none, we assume all material assignments in Element are shared by this GeometryCollection
// otherwise, we assume all assignments come from the contained materials
int32 MaterialIDOffset = 0 ;
if ( Element . Materials . Num ( ) > 0 )
{
MaterialIDOffset = Materials . Num ( ) ;
Materials . Append ( Element . Materials ) ;
}
return GeometryCollection - > AppendGeometry ( * Element . GetGeometryCollection ( ) , MaterialIDOffset , ReindexAllMaterials , TransformRoot ) ;
2018-12-12 11:25:29 -05:00
}
/** NumElements */
2019-06-08 17:15:34 -04:00
int32 UGeometryCollection : : NumElements ( const FName & Group ) const
2018-12-12 11:25:29 -05:00
{
return GeometryCollection - > NumElements ( Group ) ;
}
/** RemoveElements */
void UGeometryCollection : : RemoveElements ( const FName & Group , const TArray < int32 > & SortedDeletionList )
{
Modify ( ) ;
GeometryCollection - > RemoveElements ( Group , SortedDeletionList ) ;
InvalidateCollection ( ) ;
}
2021-05-22 12:07:31 -04:00
int UGeometryCollection : : GetDefaultSizeSpecificDataIndex ( ) const
{
int LargestIndex = INDEX_NONE ;
float MaxSize = TNumericLimits < float > : : Lowest ( ) ;
for ( int i = 0 ; i < SizeSpecificData . Num ( ) ; i + + )
{
const float SizeSpecificDataMaxSize = SizeSpecificData [ i ] . MaxSize ;
if ( MaxSize < SizeSpecificDataMaxSize )
{
MaxSize = SizeSpecificDataMaxSize ;
LargestIndex = i ;
}
}
check ( LargestIndex ! = INDEX_NONE & & LargestIndex < SizeSpecificData . Num ( ) ) ;
return LargestIndex ;
}
/** Size Specific Data Access */
FGeometryCollectionSizeSpecificData & UGeometryCollection : : GetDefaultSizeSpecificData ( )
{
if ( ! SizeSpecificData . Num ( ) )
{
SizeSpecificData . Add ( GeometryCollectionSizeSpecificDataDefaults ( ) ) ;
}
const int DefaultSizeIndex = GetDefaultSizeSpecificDataIndex ( ) ;
return SizeSpecificData [ DefaultSizeIndex ] ;
}
const FGeometryCollectionSizeSpecificData & UGeometryCollection : : GetDefaultSizeSpecificData ( ) const
{
ensure ( SizeSpecificData . Num ( ) ) ;
const int DefaultSizeIndex = GetDefaultSizeSpecificDataIndex ( ) ;
return SizeSpecificData [ DefaultSizeIndex ] ;
}
2018-12-12 11:25:29 -05:00
/** ReindexMaterialSections */
void UGeometryCollection : : ReindexMaterialSections ( )
{
Modify ( ) ;
GeometryCollection - > ReindexMaterials ( ) ;
InvalidateCollection ( ) ;
}
2019-06-08 17:15:34 -04:00
void UGeometryCollection : : InitializeMaterials ( )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
Modify ( ) ;
2021-02-09 20:08:13 -04:00
// Last Material is the selection one
UMaterialInterface * BoneSelectedMaterial = LoadObject < UMaterialInterface > ( nullptr , GetSelectedMaterialPath ( ) , nullptr , LOAD_None , nullptr ) ;
2019-06-08 17:15:34 -04:00
2021-05-19 21:03:35 -04:00
TManagedArray < int32 > & MaterialID = GeometryCollection - > MaterialID ;
// normally we filter out instances of the selection material ID, but if it's actually used on any face we have to keep it
bool bBoneSelectedMaterialIsUsed = false ;
for ( int32 FaceIdx = 0 ; FaceIdx < MaterialID . Num ( ) ; + + FaceIdx )
{
int32 FaceMaterialID = MaterialID [ FaceIdx ] ;
if ( FaceMaterialID < Materials . Num ( ) & & Materials [ FaceMaterialID ] = = BoneSelectedMaterial )
{
bBoneSelectedMaterialIsUsed = true ;
break ;
}
}
2021-02-09 20:08:13 -04:00
// We're assuming that all materials are arranged in pairs, so first we collect these.
using FMaterialPair = TPair < UMaterialInterface * , UMaterialInterface * > ;
TSet < FMaterialPair > MaterialSet ;
for ( int32 MaterialIndex = 0 ; MaterialIndex < Materials . Num ( ) ; + + MaterialIndex )
2019-06-08 17:15:34 -04:00
{
2021-02-09 20:08:13 -04:00
UMaterialInterface * ExteriorMaterial = Materials [ MaterialIndex ] ;
2021-05-19 21:03:35 -04:00
if ( ExteriorMaterial = = BoneSelectedMaterial & & ! bBoneSelectedMaterialIsUsed ) // skip unused bone selected material
{
continue ;
}
2021-02-09 20:08:13 -04:00
// If we have an odd number of materials, the last material duplicates itself.
UMaterialInterface * InteriorMaterial = Materials [ MaterialIndex ] ;
2021-05-19 21:03:35 -04:00
while ( + + MaterialIndex < Materials . Num ( ) )
2021-02-09 20:08:13 -04:00
{
2021-05-19 21:03:35 -04:00
if ( Materials [ MaterialIndex ] = = BoneSelectedMaterial & & ! bBoneSelectedMaterialIsUsed ) // skip bone selected material
{
continue ;
}
2021-02-09 20:08:13 -04:00
InteriorMaterial = Materials [ MaterialIndex ] ;
2021-05-19 21:03:35 -04:00
break ;
2021-02-09 20:08:13 -04:00
}
2019-06-08 17:15:34 -04:00
2021-02-09 20:08:13 -04:00
MaterialSet . Add ( FMaterialPair ( ExteriorMaterial , InteriorMaterial ) ) ;
}
2019-06-08 17:15:34 -04:00
// create the final material array only containing unique materials
2021-02-09 20:08:13 -04:00
// alternating exterior and interior materials
TMap < UMaterialInterface * , int32 > ExteriorMaterialPtrToArrayIndex ;
TMap < UMaterialInterface * , int32 > InteriorMaterialPtrToArrayIndex ;
2019-06-08 17:15:34 -04:00
TArray < UMaterialInterface * > FinalMaterials ;
2021-02-09 20:08:13 -04:00
for ( const FMaterialPair & Curr : MaterialSet )
2019-06-08 17:15:34 -04:00
{
// Add base material
2021-02-09 20:08:13 -04:00
TTuple < UMaterialInterface * , int32 > BaseTuple ( Curr . Key , FinalMaterials . Add ( Curr . Key ) ) ;
ExteriorMaterialPtrToArrayIndex . Add ( BaseTuple ) ;
2019-06-08 17:15:34 -04:00
// Add interior material
2021-02-09 20:08:13 -04:00
TTuple < UMaterialInterface * , int32 > InteriorTuple ( Curr . Value , FinalMaterials . Add ( Curr . Value ) ) ;
InteriorMaterialPtrToArrayIndex . Add ( InteriorTuple ) ;
2019-06-08 17:15:34 -04:00
}
2020-07-22 13:12:31 -04:00
// Reassign material ID for each face given the new consolidated array of materials
for ( int32 Material = 0 ; Material < MaterialID . Num ( ) ; + + Material )
2019-06-08 17:15:34 -04:00
{
2020-07-22 13:12:31 -04:00
if ( MaterialID [ Material ] < Materials . Num ( ) )
2019-06-08 17:15:34 -04:00
{
2020-07-22 13:12:31 -04:00
UMaterialInterface * OldMaterialPtr = Materials [ MaterialID [ Material ] ] ;
2021-02-09 20:08:13 -04:00
if ( MaterialID [ Material ] % 2 = = 0 )
{
MaterialID [ Material ] = * ExteriorMaterialPtrToArrayIndex . Find ( OldMaterialPtr ) ;
}
else
{
MaterialID [ Material ] = * InteriorMaterialPtrToArrayIndex . Find ( OldMaterialPtr ) ;
}
2019-06-08 17:15:34 -04:00
}
}
// Set new material array on the collection
Materials = FinalMaterials ;
2018-12-12 11:25:29 -05:00
// Last Material is the selection one
2019-06-08 17:15:34 -04:00
BoneSelectedMaterialIndex = Materials . Add ( BoneSelectedMaterial ) ;
2021-02-09 20:08:13 -04:00
2019-06-08 17:15:34 -04:00
GeometryCollection - > ReindexMaterials ( ) ;
InvalidateCollection ( ) ;
2018-12-12 11:25:29 -05:00
}
2021-02-09 20:08:13 -04:00
2018-12-12 11:25:29 -05:00
/** Returns true if there is anything to render */
2019-06-08 17:15:34 -04:00
bool UGeometryCollection : : HasVisibleGeometry ( ) const
2018-12-12 11:25:29 -05:00
{
2020-06-23 18:40:00 -04:00
if ( ensureMsgf ( GeometryCollection . IsValid ( ) , TEXT ( " Geometry Collection %s has an invalid internal collection " ) ) )
{
2021-04-20 09:50:07 -04:00
return ( ( EnableNanite & & NaniteData ) | | GeometryCollection - > HasVisibleGeometry ( ) ) ;
2020-06-23 18:40:00 -04:00
}
return false ;
2018-12-12 11:25:29 -05:00
}
2020-12-01 11:18:19 -04:00
struct FPackedHierarchyNode_Old
{
FSphere LODBounds [ 64 ] ;
FSphere Bounds [ 64 ] ;
struct
{
uint32 MinLODError_MaxParentLODError ;
uint32 ChildStartReference ;
uint32 ResourcePageIndex_NumPages_GroupPartSize ;
} Misc [ 64 ] ;
} ;
FArchive & operator < < ( FArchive & Ar , FPackedHierarchyNode_Old & Node )
{
for ( uint32 i = 0 ; i < 64 ; i + + )
{
Ar < < Node . LODBounds [ i ] ;
Ar < < Node . Bounds [ i ] ;
Ar < < Node . Misc [ i ] . MinLODError_MaxParentLODError ;
Ar < < Node . Misc [ i ] . ChildStartReference ;
Ar < < Node . Misc [ i ] . ResourcePageIndex_NumPages_GroupPartSize ;
}
return Ar ;
}
struct FPageStreamingState_Old
{
uint32 BulkOffset ;
uint32 BulkSize ;
uint32 PageUncompressedSize ;
uint32 DependenciesStart ;
uint32 DependenciesNum ;
} ;
FArchive & operator < < ( FArchive & Ar , FPageStreamingState_Old & PageStreamingState )
{
Ar < < PageStreamingState . BulkOffset ;
Ar < < PageStreamingState . BulkSize ;
Ar < < PageStreamingState . PageUncompressedSize ;
Ar < < PageStreamingState . DependenciesStart ;
Ar < < PageStreamingState . DependenciesNum ;
return Ar ;
}
// Parse old Nanite data and throw it away. We need this to not crash when parsing old files.
static void SerializeOldNaniteData ( FArchive & Ar , UGeometryCollection * Owner )
{
check ( Ar . IsLoading ( ) ) ;
int32 NumNaniteResources = 0 ;
Ar < < NumNaniteResources ;
for ( int32 i = 0 ; i < NumNaniteResources ; + + i )
{
FStripDataFlags StripFlags ( Ar , 0 ) ;
if ( ! StripFlags . IsDataStrippedForServer ( ) )
{
bool bLZCompressed ;
TArray < uint8 > RootClusterPage ;
FByteBulkData StreamableClusterPages ;
TArray < uint16 > ImposterAtlas ;
TArray < FPackedHierarchyNode_Old > HierarchyNodes ;
TArray < FPageStreamingState_Old > PageStreamingStates ;
TArray < uint32 > PageDependencies ;
Ar < < bLZCompressed ;
Ar < < RootClusterPage ;
StreamableClusterPages . Serialize ( Ar , Owner , 0 ) ;
Ar < < PageStreamingStates ;
Ar < < HierarchyNodes ;
Ar < < PageDependencies ;
Ar < < ImposterAtlas ;
}
}
}
2018-12-12 11:25:29 -05:00
/** Serialize */
void UGeometryCollection : : Serialize ( FArchive & Ar )
{
2021-05-22 12:07:31 -04:00
bool bCreateSimulationData = false ;
2018-12-12 11:25:29 -05:00
Ar . UsingCustomVersion ( FDestructionObjectVersion : : GUID ) ;
2020-07-15 01:49:28 -04:00
Ar . UsingCustomVersion ( FUE5MainStreamObjectVersion : : GUID ) ;
2022-02-03 17:40:00 -05:00
Ar . UsingCustomVersion ( FUE5ReleaseStreamObjectVersion : : GUID ) ;
2022-02-07 09:08:07 -05:00
Ar . UsingCustomVersion ( FPhysicsObjectVersion : : GUID ) ;
2022-02-03 17:40:00 -05:00
2019-06-08 17:15:34 -04:00
Chaos : : FChaosArchive ChaosAr ( Ar ) ;
2018-12-12 11:25:29 -05:00
2021-04-20 09:50:07 -04:00
// The Geometry Collection we will be archiving. This may be replaced with a transient, stripped back Geometry Collection if we are cooking.
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > ArchiveGeometryCollection = GeometryCollection ;
bool bIsCookedOrCooking = Ar . IsCooking ( ) ;
if ( bIsCookedOrCooking & & Ar . IsSaving ( ) )
{
# if WITH_EDITOR
if ( bStripOnCook & & EnableNanite & & NaniteData )
{
// If this is a cooked archive, we strip unnecessary data from the Geometry Collection to keep the memory footprint as small as possible.
ArchiveGeometryCollection = GenerateMinimalGeometryCollection ( ) ;
}
# endif
}
2019-06-08 17:15:34 -04:00
# if WITH_EDITOR
//Early versions did not have tagged properties serialize first
if ( Ar . CustomVer ( FDestructionObjectVersion : : GUID ) < FDestructionObjectVersion : : GeometryCollectionInDDC )
2018-12-12 11:25:29 -05:00
{
2021-04-20 09:50:07 -04:00
if ( Ar . IsLoading ( ) )
{
GeometryCollection - > Serialize ( ChaosAr ) ;
}
else
{
ArchiveGeometryCollection - > Serialize ( ChaosAr ) ;
}
2019-06-08 17:15:34 -04:00
}
if ( Ar . CustomVer ( FDestructionObjectVersion : : GUID ) < FDestructionObjectVersion : : AddedTimestampedGeometryComponentCache )
{
if ( Ar . IsLoading ( ) )
2018-12-12 11:25:29 -05:00
{
// Strip old recorded cache data
int32 DummyNumFrames ;
TArray < TArray < FTransform > > DummyTransforms ;
Ar < < DummyNumFrames ;
DummyTransforms . SetNum ( DummyNumFrames ) ;
2019-06-08 17:15:34 -04:00
for ( int32 Index = 0 ; Index < DummyNumFrames ; + + Index )
2018-12-12 11:25:29 -05:00
{
Ar < < DummyTransforms [ Index ] ;
}
}
}
else
2019-06-08 17:15:34 -04:00
# endif
2018-12-12 11:25:29 -05:00
{
// Push up the chain to hit tagged properties too
// This should have always been in here but because we have saved assets
// from before this line was here it has to be gated
Super : : Serialize ( Ar ) ;
}
2019-06-08 17:15:34 -04:00
2021-05-25 11:59:44 -04:00
if ( ! SizeSpecificData . Num ( ) )
{
2021-05-26 17:46:30 -04:00
ValidateSizeSpecificDataDefaults ( ) ;
2021-05-25 11:59:44 -04:00
}
2019-06-08 17:15:34 -04:00
if ( Ar . CustomVer ( FDestructionObjectVersion : : GUID ) < FDestructionObjectVersion : : DensityUnitsChanged )
{
if ( bMassAsDensity )
{
Mass = KgCm3ToKgM3 ( Mass ) ;
}
}
if ( Ar . CustomVer ( FDestructionObjectVersion : : GUID ) > = FDestructionObjectVersion : : GeometryCollectionInDDC )
{
Ar < < bIsCookedOrCooking ;
}
//new versions serialize geometry collection after tagged properties
if ( Ar . CustomVer ( FDestructionObjectVersion : : GUID ) > = FDestructionObjectVersion : : GeometryCollectionInDDCAndAsset )
{
# if WITH_EDITOR
if ( Ar . IsSaving ( ) & & ! Ar . IsTransacting ( ) )
{
CreateSimulationDataImp ( /*bCopyFromDDC=*/ false ) ; //make sure content is built before saving
}
# endif
2021-04-20 09:50:07 -04:00
if ( Ar . IsLoading ( ) )
{
GeometryCollection - > Serialize ( ChaosAr ) ;
}
else
{
ArchiveGeometryCollection - > Serialize ( ChaosAr ) ;
}
2020-03-11 17:01:25 -04:00
// Fix up the type change for implicits here, previously they were unique ptrs, now they're shared
2021-04-20 09:50:07 -04:00
TManagedArray < TUniquePtr < Chaos : : FImplicitObject > > * OldAttr = ArchiveGeometryCollection - > FindAttributeTyped < TUniquePtr < Chaos : : FImplicitObject > > ( FGeometryDynamicCollection : : ImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
TManagedArray < TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > > * NewAttr = ArchiveGeometryCollection - > FindAttributeTyped < TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > > ( FGeometryDynamicCollection : : SharedImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
if ( OldAttr )
2020-03-11 17:01:25 -04:00
{
2021-04-20 09:50:07 -04:00
if ( ! NewAttr )
2020-03-11 17:01:25 -04:00
{
2021-04-20 09:50:07 -04:00
NewAttr = & ArchiveGeometryCollection - > AddAttribute < TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > > ( FGeometryDynamicCollection : : SharedImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
2020-03-11 17:01:25 -04:00
const int32 NumElems = GeometryCollection - > NumElements ( FTransformCollection : : TransformGroup ) ;
2021-04-20 09:50:07 -04:00
for ( int32 Index = 0 ; Index < NumElems ; + + Index )
2020-03-11 17:01:25 -04:00
{
( * NewAttr ) [ Index ] = TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > ( ( * OldAttr ) [ Index ] . Release ( ) ) ;
}
}
2021-04-20 09:50:07 -04:00
ArchiveGeometryCollection - > RemoveAttribute ( FGeometryDynamicCollection : : ImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
2020-03-11 17:01:25 -04:00
}
2019-06-08 17:15:34 -04:00
}
if ( Ar . CustomVer ( FDestructionObjectVersion : : GUID ) < FDestructionObjectVersion : : GroupAndAttributeNameRemapping )
{
2021-04-20 09:50:07 -04:00
ArchiveGeometryCollection - > UpdateOldAttributeNames ( ) ;
2019-06-08 17:15:34 -04:00
InvalidateCollection ( ) ;
2021-05-22 12:07:31 -04:00
bCreateSimulationData = true ;
2019-06-08 17:15:34 -04:00
}
2020-12-01 11:18:19 -04:00
if ( Ar . CustomVer ( FUE5MainStreamObjectVersion : : GUID ) = = FUE5MainStreamObjectVersion : : GeometryCollectionNaniteData | |
( Ar . CustomVer ( FUE5MainStreamObjectVersion : : GUID ) > = FUE5MainStreamObjectVersion : : GeometryCollectionNaniteCooked & &
Ar . CustomVer ( FUE5MainStreamObjectVersion : : GUID ) < FUE5MainStreamObjectVersion : : GeometryCollectionNaniteTransient ) )
2020-07-15 01:49:28 -04:00
{
2020-09-01 12:46:08 -04:00
// This legacy version serialized structure information into archive, but the data is transient.
// Just load it and throw away here, it will be rebuilt later and resaved past this point.
2020-12-01 11:18:19 -04:00
SerializeOldNaniteData ( ChaosAr , this ) ;
2020-07-15 01:49:28 -04:00
}
2020-12-01 11:18:19 -04:00
if ( Ar . CustomVer ( FUE5MainStreamObjectVersion : : GUID ) > = FUE5MainStreamObjectVersion : : GeometryCollectionNaniteTransient )
2020-11-02 21:12:24 -04:00
{
2020-12-01 11:18:19 -04:00
bool bCooked = Ar . IsCooking ( ) ;
Ar < < bCooked ;
if ( bCooked )
2020-11-02 21:12:24 -04:00
{
2020-12-01 11:18:19 -04:00
if ( NaniteData = = nullptr )
{
NaniteData = MakeUnique < FGeometryCollectionNaniteData > ( ) ;
}
2020-11-02 21:12:24 -04:00
2020-12-01 11:18:19 -04:00
NaniteData - > Serialize ( ChaosAr , this ) ;
}
2020-11-02 21:12:24 -04:00
}
2022-02-03 17:40:00 -05:00
// will generate convex bodies when they dont exist.
2022-02-07 09:08:07 -05:00
if ( Ar . CustomVer ( FUE5ReleaseStreamObjectVersion : : GUID ) < FUE5ReleaseStreamObjectVersion : : GeometryCollectionConvexDefaults
& & Ar . CustomVer ( FPhysicsObjectVersion : : GUID ) < FPhysicsObjectVersion : : GeometryCollectionConvexDefaults )
2022-02-03 17:40:00 -05:00
{
# if WITH_EDITOR
2022-02-09 13:27:35 -05:00
if ( bGeometryCollectionEnableForcedConvexGenerationInSerialize )
2022-02-03 17:40:00 -05:00
{
2022-02-10 17:08:59 -05:00
if ( ! FGeometryCollectionConvexUtility : : HasConvexHullData ( GeometryCollection . Get ( ) ) & &
GeometryCollection : : SizeSpecific : : UsesImplicitCollisionType ( SizeSpecificData , EImplicitTypeEnum : : Chaos_Implicit_Convex ) )
2022-02-09 13:27:35 -05:00
{
2022-02-10 17:08:59 -05:00
GeometryCollection : : SizeSpecific : : SetImplicitCollisionType ( SizeSpecificData , EImplicitTypeEnum : : Chaos_Implicit_Box , EImplicitTypeEnum : : Chaos_Implicit_Convex ) ;
2022-02-09 13:27:35 -05:00
bCreateSimulationData = true ;
InvalidateCollection ( ) ;
}
2022-02-03 17:40:00 -05:00
}
# endif
}
2022-04-28 20:20:32 -04:00
if ( Ar . CustomVer ( FUE5MainStreamObjectVersion : : GUID ) < FUE5MainStreamObjectVersion : : GeometryCollectionPerChildDamageThreshold )
{
// prior this version, damage threshold were computed per cluster and propagated to children
PerClusterOnlyDamageThreshold = true ;
}
2021-05-22 12:07:31 -04:00
# if WITH_EDITORONLY_DATA
if ( bCreateSimulationData )
{
CreateSimulationData ( ) ;
}
2021-04-20 09:50:07 -04:00
2019-06-08 17:15:34 -04:00
//for all versions loaded, make sure sim data is up to date
2021-05-22 12:07:31 -04:00
if ( Ar . IsLoading ( ) )
2019-06-08 17:15:34 -04:00
{
2020-08-28 16:47:53 -04:00
EnsureDataIsCooked ( ) ; //make sure loaded content is built
2019-06-08 17:15:34 -04:00
}
# endif
2018-12-12 11:25:29 -05:00
}
2021-02-09 20:08:13 -04:00
const TCHAR * UGeometryCollection : : GetSelectedMaterialPath ( )
2020-07-22 13:12:31 -04:00
{
return TEXT ( " /Engine/EditorMaterials/GeometryCollection/SelectedGeometryMaterial.SelectedGeometryMaterial " ) ;
}
2019-06-08 17:15:34 -04:00
# if WITH_EDITOR
2020-09-01 12:46:08 -04:00
void UGeometryCollection : : CreateSimulationDataImp ( bool bCopyFromDDC )
2019-06-08 17:15:34 -04:00
{
2020-03-27 17:52:09 -04:00
COOK_STAT ( auto Timer = GeometryCollectionCookStats : : UsageStats . TimeSyncWork ( ) ) ;
2020-03-11 17:01:25 -04:00
// Skips the DDC fetch entirely for testing the builder without adding to the DDC
const static bool bSkipDDC = false ;
2019-06-08 17:15:34 -04:00
//Use the DDC to build simulation data. If we are loading in the editor we then serialize this data into the geometry collection
TArray < uint8 > DDCData ;
FDerivedDataGeometryCollectionCooker * GeometryCollectionCooker = new FDerivedDataGeometryCollectionCooker ( * this ) ;
if ( GeometryCollectionCooker - > CanBuild ( ) )
{
2020-03-27 17:52:09 -04:00
if ( bSkipDDC )
2020-03-11 17:01:25 -04:00
{
GeometryCollectionCooker - > Build ( DDCData ) ;
2020-03-27 17:52:09 -04:00
COOK_STAT ( Timer . AddMiss ( DDCData . Num ( ) ) ) ;
2020-03-11 17:01:25 -04:00
}
else
{
2020-03-27 17:52:09 -04:00
bool bBuilt = false ;
const bool bSuccess = GetDerivedDataCacheRef ( ) . GetSynchronous ( GeometryCollectionCooker , DDCData , & bBuilt ) ;
COOK_STAT ( Timer . AddHitOrMiss ( ! bSuccess | | bBuilt ? FCookStats : : CallStats : : EHitOrMiss : : Miss : FCookStats : : CallStats : : EHitOrMiss : : Hit , DDCData . Num ( ) ) ) ;
2020-03-11 17:01:25 -04:00
}
2020-03-27 17:52:09 -04:00
if ( bCopyFromDDC )
2019-06-08 17:15:34 -04:00
{
2020-08-28 16:47:53 -04:00
FMemoryReader Ar ( DDCData , true ) ; // Must be persistent for BulkData to serialize
2019-06-08 17:15:34 -04:00
Chaos : : FChaosArchive ChaosAr ( Ar ) ;
GeometryCollection - > Serialize ( ChaosAr ) ;
2020-09-01 12:46:08 -04:00
NaniteData = MakeUnique < FGeometryCollectionNaniteData > ( ) ;
NaniteData - > Serialize ( ChaosAr , this ) ;
2019-06-08 17:15:34 -04:00
}
}
}
void UGeometryCollection : : CreateSimulationData ( )
{
CreateSimulationDataImp ( /*bCopyFromDDC=*/ false ) ;
2020-11-19 22:01:51 -04:00
SimulationDataGuid = StateGuid ;
2019-06-08 17:15:34 -04:00
}
2020-07-15 01:49:28 -04:00
2020-09-01 12:46:08 -04:00
TUniquePtr < FGeometryCollectionNaniteData > UGeometryCollection : : CreateNaniteData ( FGeometryCollection * Collection )
2020-07-15 01:49:28 -04:00
{
2020-09-01 12:46:08 -04:00
TUniquePtr < FGeometryCollectionNaniteData > NaniteData ;
2020-07-15 01:49:28 -04:00
2021-01-19 06:29:15 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( UGeometryCollection : : CreateNaniteData ) ;
2020-07-15 01:49:28 -04:00
Nanite : : IBuilderModule & NaniteBuilderModule = Nanite : : IBuilderModule : : Get ( ) ;
2020-09-01 12:46:08 -04:00
NaniteData = MakeUnique < FGeometryCollectionNaniteData > ( ) ;
2020-07-15 01:49:28 -04:00
// Transform Group
const TManagedArray < int32 > & TransformToGeometryIndexArray = Collection - > TransformToGeometryIndex ;
const TManagedArray < int32 > & SimulationTypeArray = Collection - > SimulationType ;
const TManagedArray < int32 > & StatusFlagsArray = Collection - > StatusFlags ;
// Vertices Group
2021-05-05 15:07:25 -04:00
const TManagedArray < FVector3f > & VertexArray = Collection - > Vertex ;
2021-11-18 14:37:34 -05:00
const TManagedArray < TArray < FVector2f > > & UVsArray = Collection - > UVs ;
2020-07-15 01:49:28 -04:00
const TManagedArray < FLinearColor > & ColorArray = Collection - > Color ;
2021-05-05 15:07:25 -04:00
const TManagedArray < FVector3f > & TangentUArray = Collection - > TangentU ;
const TManagedArray < FVector3f > & TangentVArray = Collection - > TangentV ;
const TManagedArray < FVector3f > & NormalArray = Collection - > Normal ;
2020-07-15 01:49:28 -04:00
const TManagedArray < int32 > & BoneMapArray = Collection - > BoneMap ;
// Faces Group
const TManagedArray < FIntVector > & IndicesArray = Collection - > Indices ;
const TManagedArray < bool > & VisibleArray = Collection - > Visible ;
const TManagedArray < int32 > & MaterialIndexArray = Collection - > MaterialIndex ;
const TManagedArray < int32 > & MaterialIDArray = Collection - > MaterialID ;
// Geometry Group
const TManagedArray < int32 > & TransformIndexArray = Collection - > TransformIndex ;
const TManagedArray < FBox > & BoundingBoxArray = Collection - > BoundingBox ;
const TManagedArray < float > & InnerRadiusArray = Collection - > InnerRadius ;
const TManagedArray < float > & OuterRadiusArray = Collection - > OuterRadius ;
const TManagedArray < int32 > & VertexStartArray = Collection - > VertexStart ;
const TManagedArray < int32 > & VertexCountArray = Collection - > VertexCount ;
const TManagedArray < int32 > & FaceStartArray = Collection - > FaceStart ;
const TManagedArray < int32 > & FaceCountArray = Collection - > FaceCount ;
// Material Group
2020-12-01 11:18:19 -04:00
const int32 NumGeometry = Collection - > NumElements ( FGeometryCollection : : GeometryGroup ) ;
2020-07-15 01:49:28 -04:00
2021-05-18 13:03:42 -04:00
const uint32 NumTexCoords = Collection - > NumUVLayers ( ) ;
2020-12-01 11:18:19 -04:00
const bool bHasColors = ColorArray . Num ( ) > 0 ;
TArray < FStaticMeshBuildVertex > BuildVertices ;
TArray < uint32 > BuildIndices ;
TArray < int32 > MaterialIndices ;
TArray < uint32 > MeshTriangleCounts ;
MeshTriangleCounts . SetNum ( NumGeometry ) ;
2020-07-15 01:49:28 -04:00
for ( int32 GeometryGroupIndex = 0 ; GeometryGroupIndex < NumGeometry ; GeometryGroupIndex + + )
{
const int32 VertexStart = VertexStartArray [ GeometryGroupIndex ] ;
const int32 VertexCount = VertexCountArray [ GeometryGroupIndex ] ;
2020-12-01 11:18:19 -04:00
uint32 DestVertexStart = BuildVertices . Num ( ) ;
BuildVertices . Reserve ( DestVertexStart + VertexCount ) ;
2020-07-15 01:49:28 -04:00
for ( int32 VertexIndex = 0 ; VertexIndex < VertexCount ; + + VertexIndex )
{
FStaticMeshBuildVertex & Vertex = BuildVertices . Emplace_GetRef ( ) ;
Vertex . Position = VertexArray [ VertexStart + VertexIndex ] ;
2020-07-15 05:35:35 -04:00
Vertex . Color = bHasColors ? ColorArray [ VertexStart + VertexIndex ] . ToFColor ( false /* sRGB */ ) : FColor : : White ;
2021-05-05 15:07:25 -04:00
Vertex . TangentX = FVector3f : : ZeroVector ;
Vertex . TangentY = FVector3f : : ZeroVector ;
2020-07-15 05:35:35 -04:00
Vertex . TangentZ = NormalArray [ VertexStart + VertexIndex ] ;
2021-05-18 13:03:42 -04:00
for ( int32 UVIdx = 0 ; UVIdx < UVsArray [ VertexStart + VertexIndex ] . Num ( ) ; + + UVIdx )
2020-07-15 05:35:35 -04:00
{
2021-05-18 13:03:42 -04:00
Vertex . UVs [ UVIdx ] = UVsArray [ VertexStart + VertexIndex ] [ UVIdx ] ;
if ( Vertex . UVs [ UVIdx ] . ContainsNaN ( ) )
{
2022-02-02 01:47:07 -05:00
Vertex . UVs [ UVIdx ] = FVector2f : : ZeroVector ;
2021-05-18 13:03:42 -04:00
}
2020-07-15 05:35:35 -04:00
}
2020-07-15 01:49:28 -04:00
}
const int32 FaceStart = FaceStartArray [ GeometryGroupIndex ] ;
const int32 FaceCount = FaceCountArray [ GeometryGroupIndex ] ;
// TODO: Respect multiple materials like in FGeometryCollectionConversion::AppendStaticMesh
2020-07-21 17:01:45 -04:00
2021-03-17 17:58:16 -04:00
int32 DestFaceStart = MaterialIndices . Num ( ) ;
2020-12-01 11:18:19 -04:00
MaterialIndices . Reserve ( DestFaceStart + FaceCount ) ;
BuildIndices . Reserve ( ( DestFaceStart + FaceCount ) * 3 ) ;
2020-07-15 01:49:28 -04:00
for ( int32 FaceIndex = 0 ; FaceIndex < FaceCount ; + + FaceIndex )
{
2020-07-21 15:17:07 -04:00
if ( ! VisibleArray [ FaceStart + FaceIndex ] ) // TODO: Always in range?
{
continue ;
}
2021-03-17 17:58:16 -04:00
FIntVector FaceIndices = IndicesArray [ FaceStart + FaceIndex ] ;
FaceIndices = FaceIndices + FIntVector ( DestVertexStart - VertexStart ) ;
// Remove degenerates
if ( BuildVertices [ FaceIndices [ 0 ] ] . Position = = BuildVertices [ FaceIndices [ 1 ] ] . Position | |
BuildVertices [ FaceIndices [ 1 ] ] . Position = = BuildVertices [ FaceIndices [ 2 ] ] . Position | |
BuildVertices [ FaceIndices [ 2 ] ] . Position = = BuildVertices [ FaceIndices [ 0 ] ] . Position )
{
continue ;
}
BuildIndices . Add ( FaceIndices . X ) ;
BuildIndices . Add ( FaceIndices . Y ) ;
BuildIndices . Add ( FaceIndices . Z ) ;
2020-07-15 01:49:28 -04:00
2020-07-21 17:01:45 -04:00
const int32 MaterialIndex = MaterialIDArray [ FaceStart + FaceIndex ] ;
MaterialIndices . Add ( MaterialIndex ) ;
2020-07-15 01:49:28 -04:00
}
2020-12-01 11:18:19 -04:00
MeshTriangleCounts [ GeometryGroupIndex ] = MaterialIndices . Num ( ) - DestFaceStart ;
}
2020-07-21 15:17:07 -04:00
2020-12-01 11:18:19 -04:00
FMeshNaniteSettings NaniteSettings = { } ;
NaniteSettings . bEnabled = true ;
2021-12-03 10:01:28 -05:00
NaniteSettings . TargetMinimumResidencyInKB = 0 ; // Default to smallest possible, which is a single page
2022-02-02 21:14:51 -05:00
NaniteSettings . KeepPercentTriangles = 1.0f ;
NaniteSettings . TrimRelativeError = 0.0f ;
2022-02-02 08:19:56 -05:00
NaniteSettings . FallbackPercentTriangles = 1.0f ; // 100% - no reduction
NaniteSettings . FallbackRelativeError = 0.0f ;
2020-07-15 01:49:28 -04:00
2020-12-01 11:18:19 -04:00
NaniteData - > NaniteResource = { } ;
if ( ! NaniteBuilderModule . Build ( NaniteData - > NaniteResource , BuildVertices , BuildIndices , MaterialIndices , MeshTriangleCounts , NumTexCoords , NaniteSettings ) )
{
UE_LOG ( LogStaticMesh , Error , TEXT ( " Failed to build Nanite for geometry collection. See previous line(s) for details. " ) ) ;
2020-07-15 01:49:28 -04:00
}
2020-09-01 12:46:08 -04:00
return NaniteData ;
2020-07-15 01:49:28 -04:00
}
2021-04-20 09:50:07 -04:00
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > UGeometryCollection : : GenerateMinimalGeometryCollection ( ) const
{
TMap < FName , TSet < FName > > SkipList ;
static TSet < FName > GeometryGroups { FGeometryCollection : : GeometryGroup , FGeometryCollection : : VerticesGroup , FGeometryCollection : : FacesGroup } ;
if ( bStripOnCook )
{
// Remove all geometry
//static TSet<FName> GeometryGroups{ FGeometryCollection::GeometryGroup, FGeometryCollection::VerticesGroup, FGeometryCollection::FacesGroup, FGeometryCollection::MaterialGroup };
for ( const FName & GeometryGroup : GeometryGroups )
{
TSet < FName > & SkipAttributes = SkipList . Add ( GeometryGroup ) ;
SkipAttributes . Append ( GeometryCollection - > AttributeNames ( GeometryGroup ) ) ;
}
}
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > DuplicateGeometryCollection ( new FGeometryCollection ( ) ) ;
DuplicateGeometryCollection - > AddAttribute < bool > ( FGeometryCollection : : SimulatableParticlesAttribute , FTransformCollection : : TransformGroup ) ;
2021-05-05 15:07:25 -04:00
DuplicateGeometryCollection - > AddAttribute < FVector3f > ( " InertiaTensor " , FGeometryCollection : : TransformGroup ) ;
2021-04-20 09:50:07 -04:00
DuplicateGeometryCollection - > AddAttribute < float > ( " Mass " , FGeometryCollection : : TransformGroup ) ;
DuplicateGeometryCollection - > AddAttribute < FTransform > ( " MassToLocal " , FGeometryCollection : : TransformGroup ) ;
DuplicateGeometryCollection - > AddAttribute < FGeometryDynamicCollection : : FSharedImplicit > (
FGeometryDynamicCollection : : ImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
DuplicateGeometryCollection - > CopyMatchingAttributesFrom ( * GeometryCollection , & SkipList ) ;
// If we've removed all geometry, we need to make sure any references to that geometry are removed.
// We also need to resize geometry groups to ensure that they are empty.
if ( bStripOnCook )
{
2022-05-10 18:56:28 -04:00
const TManagedArray < int32 > & TransformToGeometryIndex = DuplicateGeometryCollection - > GetAttribute < int32 > ( " TransformToGeometryIndex " , FTransformCollection : : TransformGroup ) ;
2021-04-20 09:50:07 -04:00
//
// Copy the bounds to the TransformGroup.
// @todo(nanite.bounds) : Rely on Nanite bounds in the component instead and dont copy here
//
if ( ! DuplicateGeometryCollection - > HasAttribute ( " BoundingBox " , " Transform " ) )
{
DuplicateGeometryCollection - > AddAttribute < FBox > ( " BoundingBox " , " Transform " ) ;
}
if ( ! DuplicateGeometryCollection - > HasAttribute ( " NaniteIndex " , " Transform " ) )
{
DuplicateGeometryCollection - > AddAttribute < FBox > ( " NaniteIndex " , " Transform " ) ;
}
2022-05-10 18:56:28 -04:00
const int32 NumTransforms = GeometryCollection - > NumElements ( FGeometryCollection : : TransformGroup ) ;
TManagedArray < int32 > & NaniteIndex = DuplicateGeometryCollection - > ModifyAttribute < int32 > ( " NaniteIndex " , " Transform " ) ;
TManagedArray < FBox > & TransformBounds = DuplicateGeometryCollection - > ModifyAttribute < FBox > ( " BoundingBox " , " Transform " ) ;
const TManagedArray < FBox > & GeometryBounds = GeometryCollection - > GetAttribute < FBox > ( " BoundingBox " , " Geometry " ) ;
2021-04-20 09:50:07 -04:00
NaniteIndex . Fill ( INDEX_NONE ) ;
for ( int TransformIndex = 0 ; TransformIndex < NumTransforms ; TransformIndex + + )
{
NaniteIndex [ TransformIndex ] = TransformToGeometryIndex [ TransformIndex ] ;
2022-05-10 18:56:28 -04:00
const int32 GeometryIndex = TransformToGeometryIndex [ TransformIndex ] ;
2021-04-20 09:50:07 -04:00
if ( GeometryIndex ! = INDEX_NONE )
{
TransformBounds [ TransformIndex ] = GeometryBounds [ GeometryIndex ] ;
}
else
{
TransformBounds [ TransformIndex ] . Init ( ) ;
}
}
//
// Clear the geometry and the transforms connection to it.
//
//TransformToGeometryIndex.Fill(INDEX_NONE);
for ( const FName & GeometryGroup : GeometryGroups )
{
DuplicateGeometryCollection - > EmptyGroup ( GeometryGroup ) ;
}
}
return DuplicateGeometryCollection ;
}
2019-06-08 17:15:34 -04:00
# endif
2020-07-15 01:49:28 -04:00
void UGeometryCollection : : InitResources ( )
{
2020-09-01 12:46:08 -04:00
if ( NaniteData )
2020-07-15 01:49:28 -04:00
{
2020-09-01 12:46:08 -04:00
NaniteData - > InitResources ( this ) ;
2020-07-15 01:49:28 -04:00
}
}
void UGeometryCollection : : ReleaseResources ( )
{
2020-09-01 12:46:08 -04:00
if ( NaniteData )
2020-07-15 01:49:28 -04:00
{
2020-09-01 12:46:08 -04:00
NaniteData - > ReleaseResources ( ) ;
2020-07-15 01:49:28 -04:00
}
}
2018-12-12 11:25:29 -05:00
void UGeometryCollection : : InvalidateCollection ( )
{
StateGuid = FGuid : : NewGuid ( ) ;
}
2020-11-19 22:01:51 -04:00
# if WITH_EDITOR
bool UGeometryCollection : : IsSimulationDataDirty ( ) const
{
return StateGuid ! = SimulationDataGuid ;
}
# endif
2021-02-18 13:20:03 -04:00
int32 UGeometryCollection : : AttachEmbeddedGeometryExemplar ( const UStaticMesh * Exemplar )
{
FSoftObjectPath NewExemplarPath ( Exemplar ) ;
// Check first if the exemplar is already attached
for ( int32 ExemplarIndex = 0 ; ExemplarIndex < EmbeddedGeometryExemplar . Num ( ) ; + + ExemplarIndex )
{
if ( NewExemplarPath = = EmbeddedGeometryExemplar [ ExemplarIndex ] . StaticMeshExemplar )
{
return ExemplarIndex ;
}
}
return EmbeddedGeometryExemplar . Emplace ( NewExemplarPath ) ;
}
void UGeometryCollection : : RemoveExemplars ( const TArray < int32 > & SortedRemovalIndices )
{
if ( SortedRemovalIndices . Num ( ) > 0 )
{
for ( int32 Index = SortedRemovalIndices . Num ( ) - 1 ; Index > = 0 ; - - Index )
{
EmbeddedGeometryExemplar . RemoveAt ( Index ) ;
}
}
}
2018-12-12 11:25:29 -05:00
FGuid UGeometryCollection : : GetIdGuid ( ) const
{
return PersistentGuid ;
}
FGuid UGeometryCollection : : GetStateGuid ( ) const
{
return StateGuid ;
}
# if WITH_EDITOR
2020-09-01 12:46:08 -04:00
2018-12-12 11:25:29 -05:00
void UGeometryCollection : : PostEditChangeProperty ( struct FPropertyChangedEvent & PropertyChangedEvent )
{
2020-07-21 15:17:07 -04:00
if ( PropertyChangedEvent . Property )
2019-06-08 17:15:34 -04:00
{
2022-02-02 07:39:24 -05:00
FName PropertyName = PropertyChangedEvent . Property - > GetFName ( ) ;
bool bDoInvalidateCollection = false ;
bool bDoEnsureDataIsCooked = false ;
bool bValidateSizeSpecificDataDefaults = false ;
bool bDoUpdateConvexGeometry = false ;
2021-05-26 17:46:30 -04:00
bool bRebuildSimulationData = false ;
2020-07-21 15:17:07 -04:00
if ( PropertyChangedEvent . Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UGeometryCollection , EnableNanite ) )
{
2022-02-02 07:39:24 -05:00
bDoInvalidateCollection = true ;
bDoEnsureDataIsCooked = true ;
2020-07-21 15:17:07 -04:00
}
2021-06-01 14:20:47 -04:00
else if ( PropertyChangedEvent . Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UGeometryCollection , bUseFullPrecisionUVs ) )
{
2022-02-02 07:39:24 -05:00
bDoInvalidateCollection = true ;
2021-06-01 14:20:47 -04:00
}
2021-05-26 17:46:30 -04:00
else if ( PropertyChangedEvent . Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UGeometryCollection , SizeSpecificData ) )
{
2022-02-02 07:39:24 -05:00
bDoInvalidateCollection = true ;
bDoUpdateConvexGeometry = true ;
bValidateSizeSpecificDataDefaults = true ;
2021-05-26 17:46:30 -04:00
bRebuildSimulationData = true ;
2022-02-02 07:39:24 -05:00
}
else if ( PropertyName . ToString ( ) . Contains ( FString ( " ImplicitType " ) ) )
//SizeSpecificData.Num() && SizeSpecificData[0].CollisionShapes.Num() &&
// PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UGeometryCollection, SizeSpecificData[0].CollisionShapes[0].ImplicitType))
{
bDoInvalidateCollection = true ;
bDoUpdateConvexGeometry = true ;
bRebuildSimulationData = true ;
2021-05-26 17:46:30 -04:00
}
2020-09-01 12:46:08 -04:00
else if ( PropertyChangedEvent . Property - > GetFName ( ) ! = GET_MEMBER_NAME_CHECKED ( UGeometryCollection , Materials ) )
{
2022-02-02 07:39:24 -05:00
bDoInvalidateCollection = true ;
2021-05-26 17:46:30 -04:00
bRebuildSimulationData = true ;
}
2021-06-03 21:03:44 -04:00
2022-02-02 07:39:24 -05:00
if ( bDoInvalidateCollection )
{
InvalidateCollection ( ) ;
}
if ( bValidateSizeSpecificDataDefaults )
{
ValidateSizeSpecificDataDefaults ( ) ;
}
if ( bDoUpdateConvexGeometry )
{
UpdateConvexGeometry ( ) ;
}
if ( bDoEnsureDataIsCooked )
{
EnsureDataIsCooked ( ) ;
}
2021-05-26 17:46:30 -04:00
if ( bRebuildSimulationData )
{
2020-11-19 22:01:51 -04:00
if ( ! bManualDataCreate )
{
CreateSimulationData ( ) ;
}
2020-09-01 12:46:08 -04:00
}
2019-06-08 17:15:34 -04:00
}
2018-12-12 11:25:29 -05:00
}
bool UGeometryCollection : : Modify ( bool bAlwaysMarkDirty /*= true*/ )
{
bool bSuperResult = Super : : Modify ( bAlwaysMarkDirty ) ;
UPackage * Package = GetOutermost ( ) ;
2020-09-01 12:46:08 -04:00
if ( Package - > IsDirty ( ) )
2018-12-12 11:25:29 -05:00
{
InvalidateCollection ( ) ;
}
return bSuperResult ;
}
2021-01-08 20:00:52 -04:00
void UGeometryCollection : : EnsureDataIsCooked ( bool bInitResources )
2019-06-08 17:15:34 -04:00
{
if ( StateGuid ! = LastBuiltGuid )
{
CreateSimulationDataImp ( /*bCopyFromDDC=*/ true ) ;
2021-04-20 09:50:07 -04:00
2021-01-08 20:00:52 -04:00
if ( FApp : : CanEverRender ( ) & & bInitResources )
2020-10-15 05:19:18 -04:00
{
2021-04-20 09:50:07 -04:00
// If there is no geometry in the collection, we leave Nanite data alone.
if ( GeometryCollection - > NumElements ( FGeometryCollection : : GeometryGroup ) > 0 )
{
NaniteData - > InitResources ( this ) ;
}
2020-10-15 05:19:18 -04:00
}
2019-06-08 17:15:34 -04:00
LastBuiltGuid = StateGuid ;
}
}
# endif
2020-07-15 01:49:28 -04:00
void UGeometryCollection : : PostLoad ( )
{
Super : : PostLoad ( ) ;
2020-07-21 15:17:07 -04:00
// Initialize rendering resources.
2020-07-15 01:49:28 -04:00
if ( FApp : : CanEverRender ( ) )
{
InitResources ( ) ;
}
}
void UGeometryCollection : : BeginDestroy ( )
{
Super : : BeginDestroy ( ) ;
ReleaseResources ( ) ;
}
2020-09-01 12:46:08 -04:00
FGeometryCollectionNaniteData : : FGeometryCollectionNaniteData ( )
{
}
FGeometryCollectionNaniteData : : ~ FGeometryCollectionNaniteData ( )
{
2021-03-23 22:42:38 -04:00
ReleaseResources ( ) ;
2020-09-01 12:46:08 -04:00
}
void FGeometryCollectionNaniteData : : Serialize ( FArchive & Ar , UGeometryCollection * Owner )
{
if ( Ar . IsSaving ( ) )
{
if ( Owner - > EnableNanite )
{
// Nanite data is currently 1:1 with each geometry group in the collection.
const int32 NumGeometryGroups = Owner - > NumElements ( FGeometryCollection : : GeometryGroup ) ;
2020-12-01 11:18:19 -04:00
if ( NumGeometryGroups ! = NaniteResource . HierarchyRootOffsets . Num ( ) )
2020-09-01 12:46:08 -04:00
{
Ar . SetError ( ) ;
}
}
2022-01-20 15:23:39 -05:00
NaniteResource . Serialize ( Ar , Owner , true ) ;
2020-09-01 12:46:08 -04:00
}
else if ( Ar . IsLoading ( ) )
{
2022-01-20 15:23:39 -05:00
NaniteResource . Serialize ( Ar , Owner , true ) ;
2020-12-01 11:18:19 -04:00
2020-09-01 12:46:08 -04:00
if ( ! Owner - > EnableNanite )
{
2020-12-01 11:18:19 -04:00
NaniteResource = { } ;
2020-09-01 12:46:08 -04:00
}
}
}
void FGeometryCollectionNaniteData : : InitResources ( UGeometryCollection * Owner )
{
if ( bIsInitialized )
{
ReleaseResources ( ) ;
}
2021-12-03 02:41:20 -05:00
NaniteResource . InitResources ( Owner ) ;
2020-09-01 12:46:08 -04:00
bIsInitialized = true ;
}
void FGeometryCollectionNaniteData : : ReleaseResources ( )
{
if ( ! bIsInitialized )
{
return ;
}
2021-03-23 22:42:38 -04:00
if ( NaniteResource . ReleaseResources ( ) )
{
// HACK: Make sure the renderer is done processing the command, and done using NaniteResource, before we continue.
// This code could really use a refactor.
FRenderCommandFence Fence ;
Fence . BeginFence ( ) ;
Fence . Wait ( ) ;
}
2020-09-01 12:46:08 -04:00
bIsInitialized = false ;
2021-03-23 22:42:38 -04:00
}