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"
2023-02-16 12:40:53 -05:00
# include "GeometryCollection/GeometryCollectionRenderData.h"
2022-10-26 19:29:11 -04:00
# include "Materials/Material.h"
2018-12-12 11:25:29 -05:00
# include "UObject/DestructionObjectVersion.h"
2020-07-15 01:49:28 -04:00
# include "UObject/UE5MainStreamObjectVersion.h"
2023-06-12 15:24:20 -04:00
# include "UObject/FortniteMainBranchObjectVersion.h"
2024-05-29 13:10:12 -04:00
# include "UObject/ObjectSaveContext.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"
2023-04-27 17:31:13 -04:00
# include "Engine/Engine.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"
2022-11-08 04:24:06 -05:00
# include "EditorFramework/AssetImportData.h"
2023-02-16 12:40:53 -05:00
# include "Rendering/NaniteResources.h"
2023-03-01 15:44:13 -05:00
# include "Engine/AssetUserData.h"
2023-04-27 17:31:13 -04:00
# include "PhysicalMaterials/PhysicalMaterial.h"
2024-05-14 22:36:52 -04:00
# include "PhysicsProxy/GeometryCollectionPhysicsProxy.h"
# include "Chaos/ErrorReporter.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"
2023-04-27 15:40:42 -04:00
# include "Chaos/MassProperties.h"
2020-03-11 17:01:25 -04:00
# include "GeometryCollectionProxyData.h"
2024-06-19 08:11:11 -04:00
# include "Dataflow/DataflowObject.h"
2023-03-03 18:14:55 -05:00
# include "GeometryCollection/Facades/CollectionHierarchyFacade.h"
2023-03-27 18:52:40 -04:00
# include "GeometryCollection/Facades/CollectionInstancedMeshFacade.h"
2019-06-08 17:15:34 -04:00
2022-09-24 13:57:58 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionObject)
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 ,
2023-02-22 17:30:06 -05:00
TEXT ( " Bypass the construction of simulation properties when all bodies are simply cached for playback. " ) ) ;
2021-04-20 09:50:07 -04:00
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] " ) ) ;
2022-12-13 18:16:59 -05:00
bool bGeometryCollectionAlwaysRecreateSimulationData = false ;
FAutoConsoleVariableRef CVarGeometryCollectionAlwaysRecreateSimulationData (
TEXT ( " p.GeometryCollectionAlwaysRecreateSimulationData " ) ,
bGeometryCollectionAlwaysRecreateSimulationData ,
TEXT ( " always recreate the simulation data even if the simulation data is not marked as dirty - this has runtime cost in editor - only use as a last resort if default has issues [def:false] " ) ) ;
2024-03-22 15:20:59 -04:00
namespace Chaos
{
namespace CVars
{
extern CHAOS_API bool bChaosConvexSimplifyUnion ;
}
}
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 )
2023-05-06 02:23:36 -04:00
, DamageModel ( EDamageModelTypeEnum : : Chaos_Damage_Model_UserDefined_Damage_Threshold )
2022-02-09 19:28:14 -05:00
, DamageThreshold ( { 500000.f , 50000.f , 5000.f } )
2022-09-16 21:25:31 -04:00
, bUseSizeSpecificDamageThreshold ( false )
2023-08-08 11:31:47 -04:00
, bUseMaterialDamageModifiers ( false )
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 )
2023-02-22 17:30:06 -05:00
, bStripRenderDataOnCook ( false )
2020-07-15 01:49:28 -04:00
, EnableNanite ( false )
2024-09-19 13:08:02 -04:00
, bEnableNaniteFallback ( 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
2023-04-27 15:40:42 -04:00
, bDensityFromPhysicsMaterial ( false )
2023-07-28 13:39:56 -04:00
, CachedDensityFromPhysicsMaterialInGCm3 ( 0 ) // <=0 value means not cached yet
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 )
2024-03-22 15:20:59 -04:00
, bOptimizeConvexes ( Chaos : : CVars : : bChaosConvexSimplifyUnion )
2023-03-10 20:05:11 -05:00
, bScaleOnRemoval ( true )
2023-03-10 20:05:22 -05:00
, bRemoveOnMaxSleep ( false )
2022-02-02 07:39:24 -05:00
, MaximumSleepTime ( 5.0 , 10.0 )
, RemovalDuration ( 2.5 , 5.0 )
2022-06-14 11:45:26 -04:00
, bSlowMovingAsSleeping ( true )
, SlowMovingVelocityThreshold ( 1 )
2022-09-15 15:14:33 -04:00
, EnableRemovePiecesOnFracture_DEPRECATED ( 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 ;
2023-02-16 12:40:53 -05:00
RenderDataGuid = StateGuid ;
2021-04-20 09:50:07 -04:00
bStripOnCook = GeometryCollectionAssetForceStripOnCook ;
2020-11-19 22:01:51 -04:00
# endif
2023-04-27 15:40:42 -04:00
PhysicsMaterial = GEngine ? GEngine - > DefaultPhysMaterial : nullptr ;
2024-05-21 19:52:06 -04:00
// make sure we have at least one size specific entry
SizeSpecificData . AddDefaulted ( ) ;
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
}
2023-03-03 18:14:55 -05:00
// update cachedroot index using the current hierarchy setup
void UGeometryCollection : : UpdateRootIndex ( )
{
RootIndex = INDEX_NONE ;
if ( GeometryCollection )
{
Chaos : : Facades : : FCollectionHierarchyFacade HierarchyFacade ( * GeometryCollection ) ;
RootIndex = HierarchyFacade . GetRootIndex ( ) ;
}
}
2023-09-06 17:00:17 -04:00
void UGeometryCollection : : CacheBreadthFirstTransformIndices ( )
{
BreadthFirstTransformIndices . Reset ( ) ;
if ( GeometryCollection )
{
Chaos : : Facades : : FCollectionHierarchyFacade HierarchyFacade ( * GeometryCollection ) ;
BreadthFirstTransformIndices = HierarchyFacade . ComputeTransformIndicesInBreadthFirstOrder ( ) ;
}
}
2023-10-11 23:17:16 -04:00
void UGeometryCollection : : CacheAutoInstanceTransformRemapIndices ( )
{
AutoInstanceTransformRemapIndices . Reset ( ) ;
if ( GeometryCollection = = nullptr )
{
return ;
}
const GeometryCollection : : Facades : : FCollectionInstancedMeshFacade InstancedMeshFacade ( * GeometryCollection ) ;
if ( ! InstancedMeshFacade . IsValid ( ) )
{
return ;
}
const int32 NumMeshes = AutoInstanceMeshes . Num ( ) ;
2023-12-15 17:46:59 -05:00
if ( NumMeshes ! = 0 )
2023-10-11 23:17:16 -04:00
{
2023-12-15 17:46:59 -05:00
TArray < int32 > TransformGroups ;
TransformGroups . AddZeroed ( NumMeshes ) ;
TArray < int32 > TransformStarts ;
TransformStarts . AddUninitialized ( NumMeshes ) ;
TArray < int32 > InstanceCounts ;
InstanceCounts . AddUninitialized ( NumMeshes ) ;
TArray < int32 > WrittenTransformCounts ;
WrittenTransformCounts . AddZeroed ( NumMeshes ) ;
2023-10-11 23:17:16 -04:00
2023-12-15 17:46:59 -05:00
for ( int32 MeshIndex = 0 ; MeshIndex < NumMeshes ; MeshIndex + + )
2023-10-11 23:17:16 -04:00
{
2023-12-15 17:46:59 -05:00
const int32 NumInstances = AutoInstanceMeshes [ MeshIndex ] . NumInstances ;
TransformStarts [ MeshIndex ] = MeshIndex = = 0 ? 0 : TransformStarts [ MeshIndex - 1 ] + InstanceCounts [ MeshIndex - 1 ] ;
InstanceCounts [ MeshIndex ] = NumInstances ;
}
AutoInstanceTransformRemapIndices . AddUninitialized ( TransformStarts . Last ( ) + InstanceCounts . Last ( ) ) ;
const int32 NumTransforms = InstancedMeshFacade . GetNumIndices ( ) ;
for ( int32 TransformIndex = 0 ; TransformIndex < NumTransforms ; TransformIndex + + )
{
if ( GeometryCollection - > Children [ TransformIndex ] . Num ( ) = = 0 )
2023-10-11 23:17:16 -04:00
{
2023-12-15 17:46:59 -05:00
const int32 AutoInstanceMeshIndex = InstancedMeshFacade . GetIndex ( TransformIndex ) ;
const int32 WriteIndex = WrittenTransformCounts [ AutoInstanceMeshIndex ] ;
if ( WriteIndex < InstanceCounts [ AutoInstanceMeshIndex ] )
{
const int32 TransformArrayIndex = TransformStarts [ AutoInstanceMeshIndex ] + WriteIndex ;
if ( AutoInstanceTransformRemapIndices . IsValidIndex ( TransformArrayIndex ) )
{
AutoInstanceTransformRemapIndices [ TransformArrayIndex ] = TransformIndex ;
WrittenTransformCounts [ AutoInstanceMeshIndex ] + + ;
}
}
2023-10-11 23:17:16 -04:00
}
}
}
}
2022-10-24 16:24:39 -04:00
void UGeometryCollection : : UpdateGeometryDependentProperties ( )
{
# if WITH_EDITOR
// Note: Currently, computing convex hulls also always computes proximity (if missing) as well as volumes and size.
// If adding a condition where we do not compute convex hulls, make sure to still compute proximity, volumes and size here
UpdateConvexGeometry ( ) ;
# endif
}
2023-01-23 21:44:00 -05:00
void UGeometryCollection : : UpdateConvexGeometryIfMissing ( )
{
2023-07-31 17:46:47 -04:00
const bool bConvexAttributeMissing = ! GeometryCollection - > HasAttribute ( FGeometryCollection : : ConvexHullAttribute , FGeometryCollection : : ConvexGroup ) ;
2023-01-23 21:44:00 -05:00
if ( GeometryCollection & & bConvexAttributeMissing )
{
UpdateConvexGeometry ( ) ;
}
}
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 ,
2022-06-24 11:44:32 -04:00
ConvexProperties . SimplificationThreshold , ConvexProperties . CanExceedFraction , ConvexProperties . RemoveOverlaps , ConvexProperties . OverlapRemovalShrinkPercent ) ;
2022-01-31 12:57:29 -05:00
InvalidateCollection ( ) ;
}
# endif
}
2022-11-08 04:24:06 -05:00
void UGeometryCollection : : PostInitProperties ( )
{
# if WITH_EDITORONLY_DATA
if ( ! HasAnyFlags ( RF_ClassDefaultObject ) )
{
AssetImportData = NewObject < UAssetImportData > ( this , TEXT ( " AssetImportData " ) ) ;
}
# endif
Super : : PostInitProperties ( ) ;
}
2021-05-25 17:13:53 -04:00
2023-07-28 13:39:56 -04:00
void UGeometryCollection : : CacheMaterialDensity ( )
{
CachedDensityFromPhysicsMaterialInGCm3 = 0 ;
UPhysicalMaterial * PhysicsMaterialForDensity = PhysicsMaterial ;
if ( ! PhysicsMaterialForDensity )
{
PhysicsMaterialForDensity = GEngine ? GEngine - > DefaultPhysMaterial : nullptr ;
}
if ( PhysicsMaterialForDensity )
{
2023-07-28 17:50:05 -04:00
CachedDensityFromPhysicsMaterialInGCm3 = PhysicsMaterialForDensity - > Density ;
2023-07-28 13:39:56 -04:00
}
}
2023-04-27 15:40:42 -04:00
float UGeometryCollection : : GetMassOrDensity ( bool & bOutIsDensity ) const
2023-07-28 13:39:56 -04:00
{
return GetMassOrDensityInternal ( bOutIsDensity , /* bCached */ true ) ;
}
float UGeometryCollection : : GetMassOrDensityInternal ( bool & bOutIsDensity , bool bCached ) const
2019-06-08 17:15:34 -04:00
{
2023-04-27 15:40:42 -04:00
bOutIsDensity = bMassAsDensity ;
float MassOrDensity = bMassAsDensity ? Chaos : : KgM3ToKgCm3 ( Mass ) : Mass ;
if ( bDensityFromPhysicsMaterial )
{
2023-07-28 13:39:56 -04:00
if ( bCached & & CachedDensityFromPhysicsMaterialInGCm3 > 0 )
2023-04-27 15:40:42 -04:00
{
bOutIsDensity = true ;
2023-07-28 13:39:56 -04:00
MassOrDensity = Chaos : : GCm3ToKgCm3 ( CachedDensityFromPhysicsMaterialInGCm3 ) ;
}
else
{
UPhysicalMaterial * PhysicsMaterialForDensity = PhysicsMaterial ;
if ( ! PhysicsMaterialForDensity )
{
PhysicsMaterialForDensity = GEngine ? GEngine - > DefaultPhysMaterial : nullptr ;
}
if ( ensureMsgf ( PhysicsMaterialForDensity , TEXT ( " bDensityFromPhysicsMaterial is true but no physics material has been set (and engine default cannot be found ) " ) ) )
{
// materials only provide density
bOutIsDensity = true ;
2023-07-28 17:50:05 -04:00
MassOrDensity = Chaos : : GCm3ToKgCm3 ( PhysicsMaterialForDensity - > Density ) ;
2023-07-28 13:39:56 -04:00
}
2023-04-27 15:40:42 -04:00
}
}
return MassOrDensity ;
2019-06-08 17:15:34 -04:00
}
void UGeometryCollection : : GetSharedSimulationParams ( FSharedSimulationParameters & OutParams ) const
{
2021-05-22 12:07:31 -04:00
const FGeometryCollectionSizeSpecificData & SizeSpecificDefault = GetDefaultSizeSpecificData ( ) ;
2023-07-28 13:39:56 -04:00
// we grab the non cached version because this is going to be used to generate the mass attribute which will eventually cache the density value if necessary
2024-05-23 15:40:38 -04:00
bool bUseMassAsDensity = false ;
OutParams . Mass = GetMassOrDensityInternal ( bUseMassAsDensity , false ) ;
OutParams . bMassAsDensity = bUseMassAsDensity ;
2019-06-08 17:15:34 -04:00
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 ] ) ;
}
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?
}
2024-09-13 21:28:49 -04:00
bool UGeometryCollection : : IsEmpty ( ) const
{
return ( NumElements ( FGeometryCollection : : TransformGroup ) = = 0 ) ;
}
2020-10-22 19:19:16 -04:00
void UGeometryCollection : : Reset ( )
{
if ( GeometryCollection . IsValid ( ) )
{
2023-03-27 18:52:40 -04:00
Modify ( ) ;
2023-03-27 23:42:56 -04:00
GeometryCollection - > Reset ( ) ;
2020-10-22 19:19:16 -04:00
Materials . Empty ( ) ;
2021-02-21 16:04:54 -04:00
EmbeddedGeometryExemplar . Empty ( ) ;
2022-10-21 19:51:57 -04:00
AutoInstanceMeshes . Empty ( ) ;
2020-10-22 19:19:16 -04:00
InvalidateCollection ( ) ;
}
}
2024-10-01 19:11:14 -04:00
namespace UE : : Dataflow : : Private
2024-09-16 23:11:55 -04:00
{
static void SetRandomBoneColor ( TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > & InGeometryCollection )
{
TManagedArray < FLinearColor > & BoneColors = InGeometryCollection - > BoneColor ;
const int32 NumBones = BoneColors . Num ( ) ;
FRandomStream RandomStream ( NumBones ) ;
for ( int32 Idx = 0 ; Idx < NumBones ; + + Idx )
{
const uint8 R = static_cast < uint8 > ( RandomStream . FRandRange ( 5 , 105 ) ) ;
const uint8 G = static_cast < uint8 > ( RandomStream . FRandRange ( 5 , 105 ) ) ;
const uint8 B = static_cast < uint8 > ( RandomStream . FRandRange ( 5 , 105 ) ) ;
BoneColors [ Idx ] = FLinearColor ( FColor ( R , G , B , 255 ) ) ;
}
}
}
2022-12-02 00:40:18 -05:00
void UGeometryCollection : : ResetFrom ( const FManagedArrayCollection & InCollection , const TArray < UMaterial * > & InMaterials , bool bHasInternalMaterials )
2022-10-26 19:04:47 -04:00
{
2024-09-13 21:28:49 -04:00
Reset ( ) ;
2022-10-26 19:04:47 -04:00
if ( GeometryCollection . IsValid ( ) )
{
InCollection . CopyTo ( GeometryCollection . Get ( ) ) ;
// todo(Chaos) : we could certainly run a "dependent attribute update method here instead of having to known about convex specifically
2023-01-23 21:44:00 -05:00
UpdateConvexGeometryIfMissing ( ) ;
2022-10-26 19:04:47 -04:00
Materials . Append ( InMaterials ) ;
2022-12-02 00:40:18 -05:00
InitializeMaterials ( bHasInternalMaterials ) ;
2024-09-16 23:11:55 -04:00
// Randomize BoneColor
2024-10-01 19:11:14 -04:00
UE : : Dataflow : : Private : : SetRandomBoneColor ( GeometryCollection ) ;
2022-10-26 19:04:47 -04:00
}
}
2024-05-22 00:24:38 -04:00
void UGeometryCollection : : ResetFrom ( const FManagedArrayCollection & InCollection , const TArray < UMaterialInterface * > & InMaterialInstances , bool bHasInternalMaterials )
{
2024-09-13 21:28:49 -04:00
Reset ( ) ;
2024-05-22 00:24:38 -04:00
if ( GeometryCollection . IsValid ( ) )
{
InCollection . CopyTo ( GeometryCollection . Get ( ) ) ;
// todo(Chaos) : we could certainly run a "dependent attribute update method here instead of having to known about convex specifically
UpdateConvexGeometryIfMissing ( ) ;
Materials . Append ( InMaterialInstances ) ;
InitializeMaterials ( bHasInternalMaterials ) ;
2024-09-16 23:11:55 -04:00
// Randomize BoneColor
2024-10-01 19:11:14 -04:00
UE : : Dataflow : : Private : : SetRandomBoneColor ( GeometryCollection ) ;
2024-05-22 00:24:38 -04:00
}
}
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 */
2024-09-13 21:28:49 -04:00
int32 UGeometryCollection : : NumElements ( const FName & Group ) const
2018-12-12 11:25:29 -05:00
{
2024-09-13 21:28:49 -04:00
return GeometryCollection ? GeometryCollection - > NumElements ( Group ) : 0 ;
2018-12-12 11:25:29 -05:00
}
/** 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 ( ) ;
}
2024-05-22 13:38:07 -04:00
UMaterialInterface * UGeometryCollection : : GetBoneSelectedMaterial ( )
{
# if WITH_EDITORONLY_DATA
return LoadObject < UMaterialInterface > ( nullptr , GetSelectedMaterialPath ( ) , nullptr , LOAD_None , nullptr ) ;
# else
return nullptr ;
# endif
}
2023-02-11 12:37:57 -05:00
void UGeometryCollection : : InitializeMaterials ( bool bHasLegacyInternalMaterialsPairs )
2018-12-12 11:25:29 -05:00
{
2019-06-08 17:15:34 -04:00
Modify ( ) ;
2023-02-06 18:02:08 -05:00
// Initialize the BoneSelectedMaterial separate from the materials on the collection
2024-05-22 13:38:07 -04:00
UMaterialInterface * BoneSelectedMaterial = GetBoneSelectedMaterial ( ) ;
2019-06-08 17:15:34 -04:00
2022-12-02 00:40:18 -05:00
TManagedArray < int32 > & MaterialIDs = GeometryCollection - > MaterialID ;
2021-05-19 21:03:35 -04:00
// 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 ;
2022-12-02 00:40:18 -05:00
for ( int32 FaceIdx = 0 ; FaceIdx < MaterialIDs . Num ( ) ; + + FaceIdx )
2021-05-19 21:03:35 -04:00
{
2022-12-02 00:40:18 -05:00
int32 FaceMaterialID = MaterialIDs [ FaceIdx ] ;
2021-05-19 21:03:35 -04:00
if ( FaceMaterialID < Materials . Num ( ) & & Materials [ FaceMaterialID ] = = BoneSelectedMaterial )
{
bBoneSelectedMaterialIsUsed = true ;
break ;
}
}
2022-12-02 00:40:18 -05:00
TArray < UMaterialInterface * > FinalMaterials ;
2023-02-11 12:37:57 -05:00
if ( bHasLegacyInternalMaterialsPairs )
2019-06-08 17:15:34 -04:00
{
2022-12-02 00:40:18 -05: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 )
2021-05-19 21:03:35 -04:00
{
2022-12-02 00:40:18 -05:00
UMaterialInterface * ExteriorMaterial = Materials [ MaterialIndex ] ;
if ( ExteriorMaterial = = BoneSelectedMaterial & & ! bBoneSelectedMaterialIsUsed ) // skip unused bone selected material
2021-05-19 21:03:35 -04:00
{
continue ;
}
2022-12-02 00:40:18 -05:00
// If we have an odd number of materials, the last material duplicates itself.
UMaterialInterface * InteriorMaterial = Materials [ MaterialIndex ] ;
while ( + + MaterialIndex < Materials . Num ( ) )
{
if ( Materials [ MaterialIndex ] = = BoneSelectedMaterial & & ! bBoneSelectedMaterialIsUsed ) // skip bone selected material
{
continue ;
}
InteriorMaterial = Materials [ MaterialIndex ] ;
break ;
}
MaterialSet . Add ( FMaterialPair ( ExteriorMaterial , InteriorMaterial ) ) ;
2021-02-09 20:08:13 -04:00
}
2019-06-08 17:15:34 -04:00
2022-12-02 00:40:18 -05:00
// create the final material array only containing unique materials
// alternating exterior and interior materials
TMap < UMaterialInterface * , int32 > ExteriorMaterialPtrToArrayIndex ;
TMap < UMaterialInterface * , int32 > InteriorMaterialPtrToArrayIndex ;
for ( const FMaterialPair & Curr : MaterialSet )
2019-06-08 17:15:34 -04:00
{
2022-12-02 00:40:18 -05:00
// Add base material
TTuple < UMaterialInterface * , int32 > BaseTuple ( Curr . Key , FinalMaterials . Add ( Curr . Key ) ) ;
ExteriorMaterialPtrToArrayIndex . Add ( BaseTuple ) ;
// Add interior material
TTuple < UMaterialInterface * , int32 > InteriorTuple ( Curr . Value , FinalMaterials . Add ( Curr . Value ) ) ;
InteriorMaterialPtrToArrayIndex . Add ( InteriorTuple ) ;
}
// Reassign material ID for each face given the new consolidated array of materials
for ( int32 Material = 0 ; Material < MaterialIDs . Num ( ) ; + + Material )
{
if ( MaterialIDs [ Material ] < Materials . Num ( ) )
2021-02-09 20:08:13 -04:00
{
2022-12-02 00:40:18 -05:00
UMaterialInterface * OldMaterialPtr = Materials [ MaterialIDs [ Material ] ] ;
if ( MaterialIDs [ Material ] % 2 = = 0 )
{
MaterialIDs [ Material ] = * ExteriorMaterialPtrToArrayIndex . Find ( OldMaterialPtr ) ;
}
else
{
MaterialIDs [ Material ] = * InteriorMaterialPtrToArrayIndex . Find ( OldMaterialPtr ) ;
}
2021-02-09 20:08:13 -04:00
}
2022-12-02 00:40:18 -05:00
}
}
else
{
// simple deduping process
for ( int32 MaterialIndex = 0 ; MaterialIndex < Materials . Num ( ) ; + + MaterialIndex )
{
UMaterialInterface * Material = Materials [ MaterialIndex ] ;
if ( Material = = BoneSelectedMaterial & & ! bBoneSelectedMaterialIsUsed ) // skip unused bone selected material
2021-02-09 20:08:13 -04:00
{
2022-12-02 00:40:18 -05:00
continue ;
}
FinalMaterials . AddUnique ( Material ) ;
}
// Reassign material ID for each face given the new consolidated array of materials
for ( int32 MaterialIDIndex = 0 ; MaterialIDIndex < MaterialIDs . Num ( ) ; MaterialIDIndex + + )
{
const int32 OldMaterialID = MaterialIDs [ MaterialIDIndex ] ;
if ( Materials . IsValidIndex ( OldMaterialID ) )
{
UMaterialInterface * Material = Materials [ OldMaterialID ] ;
MaterialIDs [ MaterialIDIndex ] = FinalMaterials . Find ( Material ) ;
2021-02-09 20:08:13 -04:00
}
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
2023-02-06 18:02:08 -05:00
// BoneSelectedMaterial is no longer stored in the general Materials array
BoneSelectedMaterialIndex = INDEX_NONE ;
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
}
2023-02-11 12:37:57 -05:00
int32 UGeometryCollection : : AddNewMaterialSlot ( bool bCopyLastMaterial )
{
Modify ( ) ;
int32 NewIdx = Materials . Emplace ( ) ;
if ( NewIdx > 0 & & bCopyLastMaterial )
{
Materials [ NewIdx ] = Materials [ NewIdx - 1 ] ;
}
2021-02-09 20:08:13 -04:00
2023-02-11 12:37:57 -05:00
InvalidateCollection ( ) ;
return NewIdx ;
}
bool UGeometryCollection : : RemoveLastMaterialSlot ( )
{
if ( Materials . Num ( ) > 1 )
{
Modify ( ) ;
Materials . Pop ( ) ;
InvalidateCollection ( ) ;
return true ;
}
return false ;
}
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
{
2023-08-31 08:56:30 -04:00
if ( ensureMsgf ( GeometryCollection . IsValid ( ) , TEXT ( " Geometry Collection has an invalid internal collection " ) ) )
2020-06-23 18:40:00 -04:00
{
2023-02-16 12:40:53 -05:00
return ( ( EnableNanite & & RenderData & & RenderData - > bHasNaniteData ) | | 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 ) ;
2023-12-18 17:47:34 -05:00
if ( ! StripFlags . IsAudioVisualDataStripped ( ) )
2020-12-01 11:18:19 -04:00
{
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 ) ;
2023-06-12 15:24:20 -04:00
Ar . UsingCustomVersion ( FFortniteMainBranchObjectVersion : : 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 ;
2022-12-13 18:29:19 -05:00
TObjectPtr < UDataflow > StrippedDataflowAsset = nullptr ;
2021-04-20 09:50:07 -04:00
bool bIsCookedOrCooking = Ar . IsCooking ( ) ;
2024-02-21 15:57:23 -05:00
if ( ( bIsCookedOrCooking & & Ar . IsSaving ( ) ) | | ( Ar . IsCountingMemory ( ) & & Ar . IsFilterEditorOnly ( ) ) )
2021-04-20 09:50:07 -04:00
{
# if WITH_EDITOR
2022-11-08 04:24:06 -05:00
if ( bStripOnCook )
2021-04-20 09:50:07 -04:00
{
2023-02-16 12:40:53 -05:00
// TODO: Since non-nanite path now stores mesh data in cooked build we may be able to unify
// the simplification of the Geometry Collection for both nanite and non-nanite cases.
if ( EnableNanite & & HasNaniteData ( ) )
2022-11-08 04:24:06 -05:00
{
// 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 ( ) ;
}
else
{
// non-nanite path where it may be necessary to remove geometry if the geometry collection is rendered using ISMPool or an external rendering system
ArchiveGeometryCollection = CopyCollectionAndRemoveGeometry ( GeometryCollection ) ;
}
2021-04-20 09:50:07 -04:00
}
2023-02-11 13:04:49 -05:00
else
{
// do we need to remove the simplicial attribute ?
if ( false = = FGeometryCollection : : AreCollisionParticlesEnabled ( ) )
{
2023-02-16 04:18:45 -05:00
ArchiveGeometryCollection = TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > ( new FGeometryCollection ) ;
const TArray < FName > NoGroupsToSkip ;
const TArray < TTuple < FName , FName > > AttributesToSkip { { FGeometryDynamicCollection : : SimplicialsAttribute , FTransformCollection : : TransformGroup } } ;
GeometryCollection - > CopyTo ( ArchiveGeometryCollection . Get ( ) , NoGroupsToSkip , AttributesToSkip ) ;
2023-02-11 13:04:49 -05:00
}
}
2022-12-13 18:29:19 -05:00
// The dataflow asset is only needed for the editor, so we just remove it when cooking
StrippedDataflowAsset = DataflowAsset ;
DataflowAsset = nullptr ;
2021-04-20 09:50:07 -04:00
# 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
2022-12-13 18:29:19 -05:00
// Important : this needs to remain after the call to Super::Serialize
if ( StrippedDataflowAsset )
{
DataflowAsset = StrippedDataflowAsset ;
}
2021-05-25 11:59:44 -04:00
2023-12-13 10:30:16 -05:00
if ( ( Ar . IsLoading ( ) | | Ar . IsSaving ( ) ) & & ! SizeSpecificData . Num ( ) )
2021-05-25 11:59:44 -04:00
{
2023-12-13 10:30:16 -05:00
// Validation is necessary when loading old version and when saving newly created version
// that might not have created the defaults yet; the defaults are used during EnsureDataIsCooked.
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 )
{
2023-04-27 15:40:42 -04:00
Mass = Chaos : : KgCm3ToKgM3 ( Mass ) ;
2019-06-08 17:15:34 -04:00
}
}
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 ( ) )
{
2024-05-29 13:10:12 -04:00
constexpr bool bAllowCopyFromDDC = false ;
constexpr bool bIsTransacting = false ; // the surrounding if statement garantees that
EnsureSimulationDataIsCooked ( bIsTransacting , bAllowCopyFromDDC ) ;
2019-06-08 17:15:34 -04:00
}
# endif
2024-07-20 13:48:34 -04:00
if ( Ar . IsLoading ( ) | | ( Ar . IsCountingMemory ( ) & & ! Ar . IsFilterEditorOnly ( ) ) )
2021-04-20 09:50:07 -04:00
{
GeometryCollection - > Serialize ( ChaosAr ) ;
}
else
{
ArchiveGeometryCollection - > Serialize ( ChaosAr ) ;
}
2020-03-11 17:01:25 -04:00
2023-07-31 17:46:47 -04:00
TManagedArray < Chaos : : FImplicitObjectPtr > * NewAttr = ArchiveGeometryCollection - > FindAttributeTyped < Chaos : : FImplicitObjectPtr > (
FGeometryDynamicCollection : : ImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
if ( ! NewAttr & & Ar . IsLoading ( ) )
2020-03-11 17:01:25 -04:00
{
2023-07-31 17:46:47 -04:00
const int32 NumElems = GeometryCollection - > NumElements ( FTransformCollection : : TransformGroup ) ;
2020-03-11 17:01:25 -04:00
2023-07-31 17:46:47 -04:00
TArray < Chaos : : FImplicitObjectPtr > ImplicitObjects ;
ImplicitObjects . SetNum ( NumElems ) ;
2024-04-26 19:09:00 -04:00
const TManagedArray < TUniquePtr < Chaos : : FImplicitObject > > * OldAttrA = ArchiveGeometryCollection - > FindAttributeTyped < TUniquePtr < Chaos : : FImplicitObject > > ( FGeometryDynamicCollection : : ImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
const TManagedArray < TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > > * OldAttrB = ArchiveGeometryCollection - > FindAttributeTyped < TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > > ( FGeometryDynamicCollection : : SharedImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
const TManagedArray < TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > > * OldAttrC = ArchiveGeometryCollection - > FindAttributeTyped < TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > > ( FGeometryDynamicCollection : : ImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
// Some geometry collection can still store several of those arrays
// We need to make sure to remove all of them and keep the last good one
if ( OldAttrA )
2023-07-31 17:46:47 -04:00
{
2021-04-20 09:50:07 -04:00
for ( int32 Index = 0 ; Index < NumElems ; + + Index )
2020-03-11 17:01:25 -04:00
{
2023-07-31 17:46:47 -04:00
if ( ( * OldAttrA ) [ Index ] ! = nullptr )
{
ImplicitObjects [ Index ] = Chaos : : FImplicitObjectPtr ( ( * OldAttrA ) [ Index ] - > DeepCopyGeometry ( ) ) ;
} ;
2020-03-11 17:01:25 -04:00
}
2023-07-31 17:46:47 -04:00
ArchiveGeometryCollection - > RemoveAttribute ( FGeometryDynamicCollection : : ImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
}
2024-04-26 19:09:00 -04:00
if ( OldAttrB )
2023-07-31 17:46:47 -04:00
{
for ( int32 Index = 0 ; Index < NumElems ; + + Index )
{
if ( ( * OldAttrB ) [ Index ] ! = nullptr )
{
ImplicitObjects [ Index ] = Chaos : : FImplicitObjectPtr ( ( * OldAttrB ) [ Index ] - > DeepCopyGeometry ( ) ) ;
}
}
ArchiveGeometryCollection - > RemoveAttribute ( FGeometryDynamicCollection : : SharedImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
}
2024-04-26 19:09:00 -04:00
if ( OldAttrC )
2023-07-31 17:46:47 -04:00
{
for ( int32 Index = 0 ; Index < NumElems ; + + Index )
{
if ( ( * OldAttrC ) [ Index ] ! = nullptr )
{
ImplicitObjects [ Index ] = Chaos : : FImplicitObjectPtr ( ( * OldAttrC ) [ Index ] - > DeepCopyGeometry ( ) ) ;
}
}
ArchiveGeometryCollection - > RemoveAttribute ( FGeometryDynamicCollection : : ImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
}
NewAttr = & ArchiveGeometryCollection - > AddAttribute < Chaos : : FImplicitObjectPtr > ( FGeometryDynamicCollection : : ImplicitsAttribute , FTransformCollection : : TransformGroup ) ;
for ( int32 Index = 0 ; Index < NumElems ; + + Index )
{
( * NewAttr ) [ Index ] = ImplicitObjects [ Index ] ;
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
{
2023-02-16 12:40:53 -05:00
if ( RenderData = = nullptr )
2020-12-01 11:18:19 -04:00
{
2023-02-16 12:40:53 -05:00
RenderData = MakeUnique < FGeometryCollectionRenderData > ( ) ;
2020-12-01 11:18:19 -04:00
}
2020-11-02 21:12:24 -04:00
2023-02-22 17:30:06 -05:00
RenderData - > Serialize ( ChaosAr , * this ) ;
2020-12-01 11:18:19 -04:00
}
2020-11-02 21:12:24 -04:00
}
2023-07-31 17:46:47 -04:00
{
TManagedArray < Chaos : : FConvexPtr > * NewAttr = ArchiveGeometryCollection - > FindAttributeTyped < Chaos : : FConvexPtr > (
FTransformCollection : : ConvexHullAttribute , FTransformCollection : : ConvexGroup ) ;
if ( ! NewAttr & & Ar . IsLoading ( ) )
{
const int32 NumElems = GeometryCollection - > NumElements ( FTransformCollection : : ConvexGroup ) ;
TArray < Chaos : : FConvexPtr > ImplicitObjects ;
ImplicitObjects . SetNum ( NumElems ) ;
if ( TManagedArray < TUniquePtr < Chaos : : FConvex > > * OldAttr = ArchiveGeometryCollection - > FindAttributeTyped < TUniquePtr < Chaos : : FConvex > > (
FTransformCollection : : ConvexHullAttribute , FTransformCollection : : ConvexGroup ) )
{
for ( int32 Index = 0 ; Index < NumElems ; + + Index )
{
if ( ( * OldAttr ) [ Index ] ! = nullptr )
{
ImplicitObjects [ Index ] = Chaos : : FConvexPtr ( ( * OldAttr ) [ Index ] . Release ( ) ) ;
}
}
ArchiveGeometryCollection - > RemoveAttribute ( FTransformCollection : : ConvexHullAttribute , FTransformCollection : : ConvexGroup ) ;
}
NewAttr = & ArchiveGeometryCollection - > AddAttribute < Chaos : : FConvexPtr > ( FTransformCollection : : ConvexHullAttribute , FTransformCollection : : ConvexGroup ) ;
for ( int32 Index = 0 ; Index < NumElems ; + + Index )
{
( * NewAttr ) [ Index ] = ImplicitObjects [ Index ] ;
}
}
}
{
TManagedArray < Chaos : : FImplicitObjectPtr > * NewAttr = ArchiveGeometryCollection - > FindAttributeTyped < Chaos : : FImplicitObjectPtr > (
FGeometryCollection : : ExternalCollisionsAttribute , FGeometryCollection : : TransformGroup ) ;
if ( ! NewAttr & & Ar . IsLoading ( ) )
{
const int32 NumElems = GeometryCollection - > NumElements ( FGeometryCollection : : TransformGroup ) ;
TArray < Chaos : : FImplicitObjectPtr > ImplicitObjects ;
ImplicitObjects . SetNum ( NumElems ) ;
if ( TManagedArray < TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > > * OldAttr = ArchiveGeometryCollection - > FindAttributeTyped < TSharedPtr < Chaos : : FImplicitObject , ESPMode : : ThreadSafe > > (
FGeometryCollection : : ExternalCollisionsAttribute , FGeometryCollection : : TransformGroup ) )
{
for ( int32 Index = 0 ; Index < NumElems ; + + Index )
{
if ( ( * OldAttr ) [ Index ] ! = nullptr )
{
ImplicitObjects [ Index ] = Chaos : : FImplicitObjectPtr ( ( * OldAttr ) [ Index ] - > DeepCopyGeometry ( ) ) ;
}
}
ArchiveGeometryCollection - > RemoveAttribute ( FGeometryCollection : : ExternalCollisionsAttribute , FGeometryCollection : : TransformGroup ) ;
}
NewAttr = & ArchiveGeometryCollection - > AddAttribute < Chaos : : FImplicitObjectPtr > ( FGeometryCollection : : ExternalCollisionsAttribute , FGeometryCollection : : TransformGroup ) ;
for ( int32 Index = 0 ; Index < NumElems ; + + Index )
{
( * NewAttr ) [ Index ] = ImplicitObjects [ Index ] ;
}
}
}
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 ;
}
2022-08-23 17:17:36 -04:00
if ( Ar . CustomVer ( FUE5MainStreamObjectVersion : : GUID ) < FUE5MainStreamObjectVersion : : GeometryCollectionDamagePropagationData )
{
// prior this version, damage propagation was not enabled by default
DamagePropagationData . bEnabled = false ;
}
2023-02-06 18:02:08 -05:00
if ( Ar . IsLoading ( ) & & ! bIsCookedOrCooking & & BoneSelectedMaterialIndex ! = INDEX_NONE )
{
if ( Materials . IsValidIndex ( BoneSelectedMaterialIndex ) )
{
// Remove the material assuming it's the last in the list (otherwise, leave it, as it's not clear why it would be in that state)
if ( BoneSelectedMaterialIndex = = Materials . Num ( ) - 1 )
{
Materials . RemoveAt ( BoneSelectedMaterialIndex ) ;
}
}
BoneSelectedMaterialIndex = INDEX_NONE ;
}
2023-03-03 18:14:55 -05:00
// Make sure the root index is properly set
if ( RootIndex = = INDEX_NONE )
{
UpdateRootIndex ( ) ;
}
2023-09-06 17:00:17 -04:00
// Generate root to leave order lookup
CacheBreadthFirstTransformIndices ( ) ;
2023-10-11 23:17:16 -04:00
// Generate transform remap for AutoInstanceMeshes instances
CacheAutoInstanceTransformRemapIndices ( ) ;
2023-09-06 17:00:17 -04:00
2023-03-27 18:52:40 -04:00
if ( Ar . IsLoading ( ) )
{
FillAutoInstanceMeshesInstancesIfNeeded ( ) ;
}
2021-05-22 12:07:31 -04:00
# if WITH_EDITORONLY_DATA
if ( bCreateSimulationData )
{
CreateSimulationData ( ) ;
}
2021-04-20 09:50:07 -04:00
2023-02-16 12:40:53 -05:00
//for all versions loaded, make sure loaded content is built
2021-05-22 12:07:31 -04:00
if ( Ar . IsLoading ( ) )
2019-06-08 17:15:34 -04:00
{
2023-04-17 15:22:06 -04:00
// note: don't allow copy from DDC here, since we've already loaded the data above, and the DDC data does not include any data migrations performed by the load
2024-05-29 13:10:12 -04:00
constexpr bool bAllowCopyFromDDC = false ;
EnsureSimulationDataIsCooked ( Ar . IsTransacting ( ) , bAllowCopyFromDDC ) ;
2019-06-08 17:15:34 -04:00
}
# endif
2023-06-12 15:24:20 -04:00
if ( Ar . IsLoading ( ) & & Ar . CustomVer ( FFortniteMainBranchObjectVersion : : GUID ) < FFortniteMainBranchObjectVersion : : GeometryCollectionConvertVertexColorToSRGB )
{
// disable sRGB conversion for old assets to keep the default behavior from before this setting existed
// (new assets will default-enable the conversion, because that matches static meshes and is the more-expected behavior)
bConvertVertexColorsToSRGB = false ;
}
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 " ) ;
}
2023-02-01 19:43:43 -05:00
void UGeometryCollection : : SetEnableNanite ( bool bValue )
{
if ( EnableNanite ! = bValue )
{
EnableNanite = bValue ;
2023-02-01 19:44:59 -05:00
# if WITH_EDITOR
2023-02-16 12:40:53 -05:00
RebuildRenderData ( ) ;
2023-02-01 19:44:59 -05:00
# endif
2023-02-01 19:43:43 -05:00
}
}
2023-06-12 15:24:20 -04:00
void UGeometryCollection : : SetConvertVertexColorsToSRGB ( bool bValue )
{
if ( bConvertVertexColorsToSRGB ! = bValue )
{
bConvertVertexColorsToSRGB = bValue ;
# if WITH_EDITOR
RebuildRenderData ( ) ;
# endif
}
}
2023-03-27 18:52:40 -04:00
void UGeometryCollection : : FillAutoInstanceMeshesInstancesIfNeeded ( )
{
// make sure the instanced meshes have their instance count properly set
if ( GeometryCollection & & AutoInstanceMeshes . Num ( ) > 0 & & AutoInstanceMeshes [ 0 ] . NumInstances = = 0 )
{
// make sure to rest all of it first
for ( FGeometryCollectionAutoInstanceMesh & AutoInstanceMesh : AutoInstanceMeshes )
{
AutoInstanceMesh . NumInstances = 0 ;
}
const GeometryCollection : : Facades : : FCollectionInstancedMeshFacade InstancedMeshFacade ( * GeometryCollection ) ;
2024-02-17 21:38:07 -05:00
if ( InstancedMeshFacade . IsValid ( ) )
2023-03-27 18:52:40 -04:00
{
2024-02-17 21:38:07 -05:00
const int32 NumTransforms = GeometryCollection - > Children . Num ( ) ;
for ( int32 TransformIndex = 0 ; TransformIndex < NumTransforms ; TransformIndex + + )
2023-03-27 18:52:40 -04:00
{
2024-02-17 21:38:07 -05:00
// only applies to leaves nodes
if ( GeometryCollection - > Children [ TransformIndex ] . Num ( ) = = 0 )
2023-03-27 18:52:40 -04:00
{
2024-02-17 21:38:07 -05:00
const int32 AutoInstanceMeshIndex = InstancedMeshFacade . GetIndex ( TransformIndex ) ;
if ( AutoInstanceMeshes . IsValidIndex ( AutoInstanceMeshIndex ) )
{
AutoInstanceMeshes [ AutoInstanceMeshIndex ] . NumInstances + + ;
}
2023-03-27 18:52:40 -04:00
}
}
}
2024-02-17 21:38:07 -05:00
else
{
2024-02-23 22:27:38 -05:00
UE_LOG ( LogGeometryCollectionInternal , Warning , TEXT ( " [%s] Could not find AutoInstanceMeshIndex attribute but the asset as instanced meshes assigned, you may need to regenerate this asset " ) , * GetPathName ( ) ) ;
2024-02-17 21:38:07 -05:00
}
2023-03-27 18:52:40 -04:00
}
}
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 ) ;
}
}
}
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
2022-12-13 18:16:59 -05:00
void UGeometryCollection : : CreateSimulationDataIfNeeded ( )
{
if ( IsSimulationDataDirty ( ) | | bGeometryCollectionAlwaysRecreateSimulationData )
{
CreateSimulationData ( ) ;
}
}
2023-02-16 12:40:53 -05:00
void UGeometryCollection : : CreateRenderDataImp ( bool bCopyFromDDC )
2020-07-15 01:49:28 -04:00
{
2023-02-16 12:40:53 -05:00
COOK_STAT ( auto Timer = GeometryCollectionCookStats : : UsageStats . TimeSyncWork ( ) ) ;
2020-07-15 01:49:28 -04:00
2023-02-16 12:40:53 -05:00
// Skips the DDC fetch entirely for testing the builder without adding to the DDC
const static bool bSkipDDC = false ;
2020-07-15 01:49:28 -04:00
2023-02-16 12:40:53 -05: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 ;
FDerivedDataGeometryCollectionRenderDataCooker * GeometryCollectionCooker = new FDerivedDataGeometryCollectionRenderDataCooker ( * this ) ;
2020-07-15 01:49:28 -04:00
2023-02-16 12:40:53 -05:00
if ( GeometryCollectionCooker - > CanBuild ( ) )
2020-07-15 01:49:28 -04:00
{
2023-02-16 12:40:53 -05:00
if ( bSkipDDC )
2020-07-15 01:49:28 -04:00
{
2023-02-16 12:40:53 -05:00
GeometryCollectionCooker - > Build ( DDCData ) ;
COOK_STAT ( Timer . AddMiss ( DDCData . Num ( ) ) ) ;
}
else
{
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-07-15 01:49:28 -04:00
}
2023-02-16 12:40:53 -05:00
if ( bCopyFromDDC )
2020-07-15 01:49:28 -04:00
{
2023-02-16 12:40:53 -05:00
FMemoryReader Ar ( DDCData , true ) ; // Must be persistent for BulkData to serialize
Chaos : : FChaosArchive ChaosAr ( Ar ) ;
2020-07-21 15:17:07 -04:00
2023-02-16 12:40:53 -05:00
RenderData = MakeUnique < FGeometryCollectionRenderData > ( ) ;
2023-02-22 17:30:06 -05:00
RenderData - > Serialize ( ChaosAr , * this ) ;
2020-07-15 01:49:28 -04:00
}
2020-12-01 11:18:19 -04:00
}
2023-02-16 12:40:53 -05:00
}
2020-07-21 15:17:07 -04:00
2023-02-16 12:40:53 -05:00
void UGeometryCollection : : RebuildRenderData ( )
{
if ( RenderDataGuid ! = StateGuid )
2020-12-01 11:18:19 -04:00
{
2023-02-16 12:40:53 -05:00
ReleaseResources ( ) ;
2024-09-19 13:08:02 -04:00
RenderData = FGeometryCollectionRenderData : : Create ( * GetGeometryCollection ( ) , EnableNanite , bEnableNaniteFallback , bUseFullPrecisionUVs , bConvertVertexColorsToSRGB ) ;
2023-02-16 12:40:53 -05:00
InitResources ( ) ;
PropagateMarkDirtyToComponents ( ) ;
RenderDataGuid = StateGuid ;
2020-07-15 01:49:28 -04:00
}
2023-02-16 12:40:53 -05:00
}
2020-07-15 01:49:28 -04:00
2023-02-16 12:40:53 -05:00
void UGeometryCollection : : PropagateMarkDirtyToComponents ( ) const
{
for ( TObjectIterator < UGeometryCollectionComponent > It ( RF_ClassDefaultObject , false , EInternalObjectFlags : : Garbage ) ; It ; + + It )
{
if ( It - > RestCollection = = this )
{
It - > MarkRenderStateDirty ( ) ;
It - > MarkRenderDynamicDataDirty ( ) ;
}
}
2020-07-15 01:49:28 -04:00
}
2023-03-15 12:59:39 -04:00
void UGeometryCollection : : PropagateTransformUpdateToComponents ( ) const
{
for ( TObjectIterator < UGeometryCollectionComponent > It ( RF_ClassDefaultObject , false , EInternalObjectFlags : : Garbage ) ; It ; + + It )
{
if ( It - > RestCollection = = this )
{
// make sure to reset the rest collection to make sure the internal state of the components is up to date
// but we do not apply asset default to avoid overriding the existing overrides
It - > SetRestCollection ( this , false /* bApplyAssetDefaults */ ) ;
}
}
}
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 ) ;
2023-07-31 17:46:47 -04:00
DuplicateGeometryCollection - > AddAttribute < Chaos : : FImplicitObjectPtr > (
2021-04-20 09:50:07 -04:00
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 " ) ;
}
2022-05-10 18:56:28 -04:00
const int32 NumTransforms = GeometryCollection - > NumElements ( FGeometryCollection : : TransformGroup ) ;
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
for ( int TransformIndex = 0 ; TransformIndex < NumTransforms ; 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 ;
}
2022-11-08 04:24:06 -05:00
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > UGeometryCollection : : CopyCollectionAndRemoveGeometry ( const TSharedPtr < const FGeometryCollection , ESPMode : : ThreadSafe > & CollectionToCopy )
{
TSharedPtr < FGeometryCollection , ESPMode : : ThreadSafe > GeometryCollectionToReturn ( new FGeometryCollection ( ) ) ;
const TArray < FName > GroupsToSkip { FGeometryCollection : : GeometryGroup , FGeometryCollection : : VerticesGroup , FGeometryCollection : : FacesGroup } ;
2023-02-07 00:30:09 -05:00
const TArray < TTuple < FName , FName > > AttributesToSkip { { FGeometryDynamicCollection : : SimplicialsAttribute , FTransformCollection : : TransformGroup } } ;
CollectionToCopy - > CopyTo ( GeometryCollectionToReturn . Get ( ) , GroupsToSkip , AttributesToSkip ) ;
2023-02-11 13:04:49 -05:00
if ( FGeometryCollection : : AreCollisionParticlesEnabled ( ) )
2023-02-07 00:30:09 -05:00
{
2023-02-11 13:04:49 -05:00
// recreate the simplicial attribute since we cannot copy it and we skipped it
using FSimplicialUniquePtr = TUniquePtr < FCollisionStructureManager : : FSimplicial > ;
if ( const TManagedArray < FSimplicialUniquePtr > * SourceSimplicials = CollectionToCopy - > FindAttribute < FSimplicialUniquePtr > ( FGeometryDynamicCollection : : SimplicialsAttribute , FTransformCollection : : TransformGroup ) )
2023-02-07 00:30:09 -05:00
{
2023-02-11 13:04:49 -05:00
TManagedArray < FSimplicialUniquePtr > & SimplicialsToWrite = GeometryCollectionToReturn - > AddAttribute < FSimplicialUniquePtr > ( FGeometryDynamicCollection : : SimplicialsAttribute , FTransformCollection : : TransformGroup ) ;
for ( int32 Index = SourceSimplicials - > Num ( ) - 1 ; 0 < = Index ; Index - - )
{
SimplicialsToWrite [ Index ] . Reset ( ( * SourceSimplicials ) [ Index ] ? ( * SourceSimplicials ) [ Index ] - > NewCopy ( ) : nullptr ) ;
}
2023-02-07 00:30:09 -05:00
}
}
2022-11-08 04:24:06 -05:00
2023-02-04 00:32:04 -05:00
// since we are removing the bounding box attribute from the geometry group we need to move it to the transform group
const TManagedArray < FBox > & GeometryBounds = CollectionToCopy - > GetAttribute < FBox > ( " BoundingBox " , " Geometry " ) ;
const TManagedArray < int32 > & TransformToGeometryIndexArray = CollectionToCopy - > TransformToGeometryIndex ;
TManagedArray < FBox > & TransformBounds = GeometryCollectionToReturn - > AddAttribute < FBox > ( " BoundingBox " , " Transform " ) ;
for ( int TransformIndex = 0 ; TransformIndex < TransformBounds . Num ( ) ; TransformIndex + + )
{
const int32 GeometryIndex = TransformToGeometryIndexArray [ TransformIndex ] ;
if ( GeometryIndex ! = INDEX_NONE )
{
TransformBounds [ TransformIndex ] = GeometryBounds [ GeometryIndex ] ;
}
else
{
TransformBounds [ TransformIndex ] . Init ( ) ;
}
}
2022-11-08 04:24:06 -05:00
return GeometryCollectionToReturn ;
}
2019-06-08 17:15:34 -04:00
# endif
2023-03-10 20:20:40 -05:00
FGeometryCollectionRenderResourceSizeInfo UGeometryCollection : : GetRenderResourceSizeInfo ( ) const
{
FGeometryCollectionRenderResourceSizeInfo InfoOut ;
const FGeometryCollectionMeshResources & MeshResources = RenderData - > MeshResource ;
InfoOut . MeshResourcesSize + = MeshResources . IndexBuffer . GetIndexDataSize ( ) ;
InfoOut . MeshResourcesSize + = MeshResources . PositionVertexBuffer . GetAllocatedSize ( ) ;
InfoOut . MeshResourcesSize + = MeshResources . StaticMeshVertexBuffer . GetResourceSize ( ) ;
InfoOut . MeshResourcesSize + = MeshResources . ColorVertexBuffer . GetAllocatedSize ( ) ;
InfoOut . MeshResourcesSize + = MeshResources . BoneMapVertexBuffer . GetAllocatedSize ( ) ;
2023-05-26 00:55:23 -04:00
InfoOut . NaniteResourcesSize + = GetNaniteResourcesSize ( * RenderData - > NaniteResourcesPtr ) ;
2023-03-10 20:20:40 -05:00
return InfoOut ;
}
2020-07-15 01:49:28 -04:00
void UGeometryCollection : : InitResources ( )
{
2023-02-16 12:40:53 -05:00
if ( RenderData )
2020-07-15 01:49:28 -04:00
{
2023-02-22 17:30:06 -05:00
RenderData - > InitResources ( * this ) ;
2020-07-15 01:49:28 -04:00
}
}
void UGeometryCollection : : ReleaseResources ( )
{
2023-02-16 12:40:53 -05:00
if ( RenderData )
2020-07-15 01:49:28 -04:00
{
2023-02-16 12:40:53 -05:00
RenderData - > ReleaseResources ( ) ;
2020-07-15 01:49:28 -04:00
}
}
2018-12-12 11:25:29 -05:00
void UGeometryCollection : : InvalidateCollection ( )
{
StateGuid = FGuid : : NewGuid ( ) ;
2023-03-03 18:14:55 -05:00
UpdateRootIndex ( ) ;
2023-09-06 17:00:17 -04:00
CacheBreadthFirstTransformIndices ( ) ;
2018-12-12 11:25:29 -05:00
}
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 ) ;
}
}
}
2023-03-27 18:52:40 -04:00
int32 FGeometryCollectionAutoInstanceMesh : : GetNumDataPerInstance ( ) const
{
return NumInstances ? ( CustomData . Num ( ) / NumInstances ) : 0 ;
}
2022-12-02 00:40:18 -05:00
bool FGeometryCollectionAutoInstanceMesh : : operator = = ( const FGeometryCollectionAutoInstanceMesh & Other ) const
{
2023-02-24 15:00:49 -05:00
return ( Mesh = = Other . Mesh ) & & ( Materials = = Other . Materials ) ;
2022-12-02 00:40:18 -05:00
}
2022-10-21 19:51:57 -04:00
/** find or add a auto instance mesh and return its index */
const FGeometryCollectionAutoInstanceMesh & UGeometryCollection : : GetAutoInstanceMesh ( int32 AutoInstanceMeshIndex ) const
{
return AutoInstanceMeshes [ AutoInstanceMeshIndex ] ;
}
/** find or add a auto instance mesh from another one and return its index */
2023-03-27 18:52:40 -04:00
int32 UGeometryCollection : : FindOrAddAutoInstanceMesh ( const FGeometryCollectionAutoInstanceMesh & AutoInstanceMesh )
2022-10-21 19:51:57 -04:00
{
2023-03-27 18:52:40 -04:00
int32 AutoInstanceMeshIndex = AutoInstanceMeshes . AddUnique ( AutoInstanceMesh ) ;
FGeometryCollectionAutoInstanceMesh & Instance = AutoInstanceMeshes [ AutoInstanceMeshIndex ] ;
Instance . NumInstances + + ;
return AutoInstanceMeshIndex ;
2022-10-21 19:51:57 -04:00
}
2023-02-24 15:00:49 -05:00
int32 UGeometryCollection : : FindOrAddAutoInstanceMesh ( const UStaticMesh * StaticMesh , const TArray < UMaterialInterface * > & MeshMaterials )
2022-10-21 19:51:57 -04:00
{
2022-12-02 00:40:18 -05:00
FGeometryCollectionAutoInstanceMesh NewMesh ;
2023-02-24 15:00:49 -05:00
NewMesh . Mesh = StaticMesh ;
2022-12-02 00:40:18 -05:00
NewMesh . Materials = MeshMaterials ;
2023-03-27 18:52:40 -04:00
return FindOrAddAutoInstanceMesh ( NewMesh ) ;
2022-10-21 19:51:57 -04:00
}
2023-10-11 18:10:36 -04:00
void UGeometryCollection : : SetAutoInstanceMeshes ( const TArray < FGeometryCollectionAutoInstanceMesh > & InAutoInstanceMeshes )
{
AutoInstanceMeshes = InAutoInstanceMeshes ;
// dedup array and reassign indices
if ( AutoInstanceMeshes . Num ( ) > 0 )
{
TArray < FGeometryCollectionAutoInstanceMesh > UniqueAutoInstanceMeshes ;
TArray < int32 > InstanceMeshIndexRemap ;
UniqueAutoInstanceMeshes . Reserve ( AutoInstanceMeshes . Num ( ) ) ;
InstanceMeshIndexRemap . Reserve ( AutoInstanceMeshes . Num ( ) ) ;
// now we may have two similar entries we need to consolidate them
for ( int32 InstanceMeshIndex = 0 ; InstanceMeshIndex < AutoInstanceMeshes . Num ( ) ; InstanceMeshIndex + + )
{
const FGeometryCollectionAutoInstanceMesh & InstanceMesh = AutoInstanceMeshes [ InstanceMeshIndex ] ;
int32 UniqueInstanceMeshIndex = UniqueAutoInstanceMeshes . Find ( InstanceMesh ) ;
if ( UniqueInstanceMeshIndex = = INDEX_NONE )
{
FGeometryCollectionAutoInstanceMesh UniqueInstanceMesh = InstanceMesh ;
UniqueInstanceMesh . NumInstances = 0 ;
UniqueInstanceMesh . CustomData . Reset ( ) ;
UniqueInstanceMeshIndex = UniqueAutoInstanceMeshes . Add ( UniqueInstanceMesh ) ;
}
2023-10-11 18:11:54 -04:00
// make sure num instances are aggregated
2023-10-11 18:10:36 -04:00
UniqueAutoInstanceMeshes [ UniqueInstanceMeshIndex ] . NumInstances + = InstanceMesh . NumInstances ;
InstanceMeshIndexRemap . Add ( UniqueInstanceMeshIndex ) ;
}
GeometryCollection : : Facades : : FCollectionInstancedMeshFacade InstancedMeshFacade ( * GetGeometryCollection ( ) ) ;
const TManagedArray < TSet < int32 > > & Children = GetGeometryCollection ( ) - > Children ;
// relocate custom data : we cannot just aggregate them because we may have interleaved transform indices with alternating colors
// also adjust the transform index to instance mesh index via the facade
TArray < int32 > DataReadOffsets ;
DataReadOffsets . SetNumZeroed ( AutoInstanceMeshes . Num ( ) ) ;
for ( int32 TransformIndex = 0 ; TransformIndex < InstancedMeshFacade . GetNumIndices ( ) ; TransformIndex + + )
{
// only for leaves
if ( Children [ TransformIndex ] . Num ( ) = = 0 )
{
const int32 OldIndex = InstancedMeshFacade . GetIndex ( TransformIndex ) ;
if ( InstanceMeshIndexRemap . IsValidIndex ( OldIndex ) )
{
const FGeometryCollectionAutoInstanceMesh & OldInstanceMesh = AutoInstanceMeshes [ OldIndex ] ;
const int32 NewIndex = InstanceMeshIndexRemap [ OldIndex ] ;
FGeometryCollectionAutoInstanceMesh & NewInstanceMesh = UniqueAutoInstanceMeshes [ NewIndex ] ;
InstancedMeshFacade . SetIndex ( TransformIndex , NewIndex ) ;
const int32 NumDataPerInstance = OldInstanceMesh . GetNumDataPerInstance ( ) ;
if ( NumDataPerInstance > 0 )
{
const int32 DataReadOffset = DataReadOffsets [ OldIndex ] ;
for ( int32 DataIndex = 0 ; DataIndex < NumDataPerInstance ; DataIndex + + )
{
const float OldData = OldInstanceMesh . CustomData [ DataReadOffset + DataIndex ] ;
NewInstanceMesh . CustomData . Add ( OldData ) ;
}
DataReadOffsets [ OldIndex ] + = NumDataPerInstance ;
}
}
}
}
AutoInstanceMeshes = MoveTemp ( UniqueAutoInstanceMeshes ) ;
}
}
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
2024-04-10 12:22:12 -04:00
void UGeometryCollection : : PostEditUndo ( )
{
PropagateTransformUpdateToComponents ( ) ;
Super : : PostEditUndo ( ) ;
}
2018-12-12 11:25:29 -05:00
void UGeometryCollection : : PostEditChangeProperty ( struct FPropertyChangedEvent & PropertyChangedEvent )
{
2023-02-16 12:40:53 -05:00
bool bDoInvalidateCollection = false ;
bool bValidateSizeSpecificDataDefaults = false ;
bool bDoUpdateConvexGeometry = false ;
bool bRebuildSimulationData = false ;
bool bRebuildRenderData = false ;
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 ( ) ;
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 ;
2023-02-16 12:40:53 -05:00
bRebuildRenderData = true ;
2020-07-21 15:17:07 -04:00
}
2024-09-19 13:08:02 -04:00
else if ( PropertyChangedEvent . Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UGeometryCollection , bEnableNaniteFallback ) )
{
bDoInvalidateCollection = true ;
bRebuildRenderData = true ;
}
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 ;
2023-02-16 12:40:53 -05:00
bRebuildRenderData = true ;
2021-06-01 14:20:47 -04:00
}
2023-06-12 15:24:20 -04:00
else if ( PropertyChangedEvent . Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UGeometryCollection , bConvertVertexColorsToSRGB ) )
{
bRebuildRenderData = true ;
}
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 ;
}
2023-02-16 12:40:53 -05:00
}
else if ( PropertyChangedEvent . ChangeType = = EPropertyChangeType : : Unspecified )
{
// We get here on undo/redo operations.
// Make sure that render data rebuilds.
bRebuildRenderData = true ;
}
2021-05-26 17:46:30 -04:00
2023-02-16 12:40:53 -05:00
if ( bDoInvalidateCollection )
{
InvalidateCollection ( ) ;
}
2021-06-03 21:03:44 -04:00
2023-02-16 12:40:53 -05:00
if ( bValidateSizeSpecificDataDefaults )
{
ValidateSizeSpecificDataDefaults ( ) ;
}
if ( bDoUpdateConvexGeometry )
{
UpdateConvexGeometry ( ) ;
}
if ( bRebuildSimulationData )
{
if ( ! bManualDataCreate )
2022-02-02 07:39:24 -05:00
{
2023-02-16 12:40:53 -05:00
CreateSimulationData ( ) ;
2022-02-02 07:39:24 -05:00
}
2023-02-16 12:40:53 -05:00
}
2022-02-02 07:39:24 -05:00
2023-02-16 12:40:53 -05:00
if ( bRebuildRenderData )
{
RebuildRenderData ( ) ;
2019-06-08 17:15:34 -04:00
}
2024-05-20 04:19:46 -04:00
InvalidateDataflowContents ( ) ;
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 ;
}
2023-02-18 00:01:10 -05:00
void UGeometryCollection : : EnsureDataIsCooked ( bool bInitResources , bool bIsTransacting , bool bIsPersistant , bool bAllowCopyFromDDC )
2024-05-29 13:10:12 -04:00
{
EnsureSimulationDataIsCooked ( bIsTransacting , bAllowCopyFromDDC ) ;
EnsureRenderDataIsCooked ( bInitResources ) ;
}
void UGeometryCollection : : EnsureSimulationDataIsCooked ( bool bIsTransacting , bool bAllowCopyFromDDC = true )
2019-06-08 17:15:34 -04:00
{
2023-02-16 12:40:53 -05:00
if ( StateGuid ! = LastBuiltSimulationDataGuid )
2019-06-08 17:15:34 -04:00
{
2023-02-18 00:01:10 -05:00
CreateSimulationDataImp ( /*bCopyFromDDC=*/ bAllowCopyFromDDC & & ! bIsTransacting ) ;
2024-05-14 22:36:52 -04:00
2023-02-16 12:40:53 -05:00
LastBuiltSimulationDataGuid = StateGuid ;
}
2024-05-14 22:36:52 -04:00
// todo(chaos) - this is temporary solution to make sure the data is computed accordingly if the attribute are missing
// in the future we should probably get rid of this all cooker logic and have a proper dependent attribute system
if ( GeometryCollection )
{
if ( FGeometryCollectionPhysicsProxy : : NeedToInitializeSharedCollisionStructures ( * GeometryCollection ) )
{
FSharedSimulationParameters SharedParams ;
GetSharedSimulationParams ( SharedParams ) ;
Chaos : : FErrorReporter ErrorReporter ( GetName ( ) ) ;
BuildSimulationData ( ErrorReporter , * GeometryCollection , SharedParams ) ;
// important : this is necessary to make sure we compute mass scale on the instances properly
// sadly we cannot call this in BuildSimulationData because we have no access to the asset
CacheMaterialDensity ( ) ;
}
}
2024-05-29 13:10:12 -04:00
}
2024-05-14 22:36:52 -04:00
2024-05-29 13:10:12 -04:00
void UGeometryCollection : : EnsureRenderDataIsCooked ( bool bInitResources )
{
// Render data only goes through DDC when loading and saving ( called from OnPostLoad / OnSave )
2023-02-16 12:40:53 -05:00
// Using DDC during edits isn't worth it especially as we use a continually mutating guid instead of a state hash.
// That ensures that all edits are cache misses (slow) and unnecessarily fill up DDC disk space.
2024-05-29 13:10:12 -04:00
if ( StateGuid ! = LastBuiltRenderDataGuid )
2023-02-16 12:40:53 -05:00
{
CreateRenderDataImp ( /*bCopyFromDDC=*/ bInitResources ) ;
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
{
2023-02-16 12:40:53 -05:00
if ( RenderData )
2021-04-20 09:50:07 -04:00
{
2023-02-22 17:30:06 -05:00
RenderData - > InitResources ( * this ) ;
2021-04-20 09:50:07 -04:00
}
2020-10-15 05:19:18 -04:00
}
2024-05-29 13:10:12 -04:00
2023-02-16 12:40:53 -05:00
LastBuiltRenderDataGuid = StateGuid ;
2019-06-08 17:15:34 -04:00
}
}
2024-05-29 13:10:12 -04:00
2019-06-08 17:15:34 -04:00
# endif
2020-07-15 01:49:28 -04:00
2024-05-29 13:10:12 -04:00
void UGeometryCollection : : PreSave ( FObjectPreSaveContext SaveContext )
{
# if WITH_EDITOR
constexpr bool bInitResources = false ;
2024-08-21 16:22:11 -04:00
constexpr bool bIsTransacting = false ;
constexpr bool bIsPersistant = false ; // note that this has no effect on the call below
constexpr bool bAllowCopyFromDDC = false ;
EnsureDataIsCooked ( bInitResources , bIsTransacting , bIsPersistant , bAllowCopyFromDDC ) ;
2024-05-29 13:10:12 -04:00
# endif
Super : : PreSave ( SaveContext ) ;
}
2020-07-15 01:49:28 -04:00
void UGeometryCollection : : PostLoad ( )
{
Super : : PostLoad ( ) ;
2024-05-29 13:10:12 -04:00
# if WITH_EDITOR
constexpr bool bInitResources = true ;
EnsureRenderDataIsCooked ( bInitResources ) ;
# else
2024-05-28 16:12:37 -04:00
if ( FApp : : CanEverRender ( ) )
{
InitResources ( ) ;
}
2024-05-29 13:10:12 -04:00
# endif
2023-02-16 14:21:21 -05:00
# if WITH_EDITORONLY_DATA
if ( ! RootProxy_DEPRECATED . IsNull ( ) )
{
if ( UStaticMesh * ProxyMesh = Cast < UStaticMesh > ( RootProxy_DEPRECATED . TryLoad ( ) ) )
{
RootProxyData . ProxyMeshes . Add ( TObjectPtr < UStaticMesh > ( ProxyMesh ) ) ;
}
RootProxy_DEPRECATED = nullptr ;
}
2023-02-24 15:00:49 -05:00
for ( int32 MeshIndex = 0 ; MeshIndex < AutoInstanceMeshes . Num ( ) ; MeshIndex + + )
{
FGeometryCollectionAutoInstanceMesh & AutoInstanceMesh = AutoInstanceMeshes [ MeshIndex ] ;
if ( ! AutoInstanceMesh . StaticMesh_DEPRECATED . IsNull ( ) )
{
if ( UStaticMesh * StaticMesh = Cast < UStaticMesh > ( AutoInstanceMesh . StaticMesh_DEPRECATED . TryLoad ( ) ) )
{
AutoInstanceMesh . Mesh = TObjectPtr < UStaticMesh > ( StaticMesh ) ;
}
AutoInstanceMesh . StaticMesh_DEPRECATED = nullptr ;
}
}
2023-02-16 14:21:21 -05:00
# endif
2020-07-15 01:49:28 -04:00
}
void UGeometryCollection : : BeginDestroy ( )
{
Super : : BeginDestroy ( ) ;
ReleaseResources ( ) ;
}
2020-09-01 12:46:08 -04:00
2023-02-16 12:40:53 -05:00
bool UGeometryCollection : : HasMeshData ( ) const
2020-09-01 12:46:08 -04:00
{
2023-02-16 12:40:53 -05:00
return RenderData ! = nullptr & & RenderData - > bHasMeshData ;
2020-09-01 12:46:08 -04:00
}
2023-02-16 12:40:53 -05:00
bool UGeometryCollection : : HasNaniteData ( ) const
2020-09-01 12:46:08 -04:00
{
2023-02-16 12:40:53 -05:00
return RenderData ! = nullptr & & RenderData - > bHasNaniteData ;
2020-09-01 12:46:08 -04:00
}
2023-02-16 12:40:53 -05:00
uint32 UGeometryCollection : : GetNaniteResourceID ( ) const
2020-09-01 12:46:08 -04:00
{
2023-05-26 00:55:23 -04:00
return RenderData - > NaniteResourcesPtr - > RuntimeResourceID ;
2020-09-01 12:46:08 -04:00
}
2023-02-16 12:40:53 -05:00
uint32 UGeometryCollection : : GetNaniteHierarchyOffset ( ) const
2020-09-01 12:46:08 -04:00
{
2023-05-26 00:55:23 -04:00
return RenderData - > NaniteResourcesPtr - > HierarchyOffset ;
2020-09-01 12:46:08 -04:00
}
2023-02-16 12:40:53 -05:00
uint32 UGeometryCollection : : GetNaniteHierarchyOffset ( int32 GeometryIndex , bool bFlattened ) const
2020-09-01 12:46:08 -04:00
{
2023-05-26 00:55:23 -04:00
const Nanite : : FResources & NaniteResources = * RenderData - > NaniteResourcesPtr ;
check ( GeometryIndex > = 0 & & GeometryIndex < NaniteResources . HierarchyRootOffsets . Num ( ) ) ;
uint32 HierarchyOffset = NaniteResources . HierarchyRootOffsets [ GeometryIndex ] ;
2023-02-16 12:40:53 -05:00
if ( bFlattened )
2020-09-01 12:46:08 -04:00
{
2023-05-26 00:55:23 -04:00
HierarchyOffset + = NaniteResources . HierarchyOffset ;
2020-09-01 12:46:08 -04:00
}
2023-02-16 12:40:53 -05:00
return HierarchyOffset ;
2022-09-24 13:57:58 -04:00
}
2023-03-01 15:43:03 -05:00
void UGeometryCollection : : AddAssetUserData ( UAssetUserData * InUserData )
{
if ( InUserData ! = nullptr )
{
UAssetUserData * ExistingData = GetAssetUserDataOfClass ( InUserData - > GetClass ( ) ) ;
if ( ExistingData ! = nullptr )
{
AssetUserData . Remove ( ExistingData ) ;
}
AssetUserData . Add ( InUserData ) ;
}
}
UAssetUserData * UGeometryCollection : : GetAssetUserDataOfClass ( TSubclassOf < UAssetUserData > InUserDataClass )
{
for ( int32 DataIdx = 0 ; DataIdx < AssetUserData . Num ( ) ; DataIdx + + )
{
UAssetUserData * Datum = AssetUserData [ DataIdx ] ;
if ( Datum ! = nullptr & & Datum - > IsA ( InUserDataClass ) )
{
return Datum ;
}
}
return nullptr ;
}
void UGeometryCollection : : RemoveUserDataOfClass ( TSubclassOf < UAssetUserData > InUserDataClass )
{
for ( int32 DataIdx = 0 ; DataIdx < AssetUserData . Num ( ) ; DataIdx + + )
{
UAssetUserData * Datum = AssetUserData [ DataIdx ] ;
if ( Datum ! = nullptr & & Datum - > IsA ( InUserDataClass ) )
{
AssetUserData . RemoveAt ( DataIdx ) ;
return ;
}
}
}
const TArray < UAssetUserData * > * UGeometryCollection : : GetAssetUserDataArray ( ) const
{
return & ToRawPtrTArrayUnsafe ( AssetUserData ) ;
2024-03-22 15:20:59 -04:00
}
2024-05-20 04:19:46 -04:00
TObjectPtr < UDataflowBaseContent > UGeometryCollection : : CreateDataflowContent ( )
{
TObjectPtr < UDataflowBaseContent > BaseContent = NewObject < UDataflowBaseContent > ( ) ;
BaseContent - > SetDataflowOwner ( this ) ;
BaseContent - > SetTerminalAsset ( this ) ;
2024-06-19 08:11:11 -04:00
WriteDataflowContent ( BaseContent ) ;
2024-05-20 04:19:46 -04:00
return BaseContent ;
}
2024-06-19 08:11:11 -04:00
void UGeometryCollection : : WriteDataflowContent ( const TObjectPtr < UDataflowBaseContent > & DataflowContent ) const
2024-05-20 04:19:46 -04:00
{
if ( const TObjectPtr < UDataflowBaseContent > BaseContent = Cast < UDataflowBaseContent > ( DataflowContent ) )
{
BaseContent - > SetDataflowAsset ( DataflowAsset ) ;
BaseContent - > SetDataflowTerminal ( DataflowTerminal ) ;
}
}
2024-06-19 08:11:11 -04:00
void UGeometryCollection : : ReadDataflowContent ( const TObjectPtr < UDataflowBaseContent > & DataflowContent )
{ }
2024-03-22 15:20:59 -04:00
# if WITH_EDITOR
bool UGeometryCollection : : CanEditChange ( const FProperty * InProperty ) const
{
if ( ! Super : : CanEditChange ( InProperty ) )
{
return false ;
}
const FName & Name = InProperty - > GetFName ( ) ;
if ( Name = = GET_MEMBER_NAME_CHECKED ( ThisClass , bOptimizeConvexes ) )
{
return Chaos : : CVars : : bChaosConvexSimplifyUnion = = true ;
}
return true ;
}
2024-04-26 19:09:00 -04:00
# endif