// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "ClothingAssetBase.h" #include "ClothConfigBase.h" #include "ClothLODData.h" #include "ClothConfig_Legacy.h" #include "ClothLODData_Legacy.h" #include "ClothingSimulationInteractor.h" #include "Algo/AnyOf.h" #include "ClothingAsset.generated.h" DECLARE_LOG_CATEGORY_EXTERN(LogClothingAsset, Log, All); class UPhysicsAsset; struct FSkelMeshSection; namespace ClothingAssetUtils { /** * Helper struct to hold binding information on a clothing asset, used to * enumerate all of the bindings on a skeletal mesh with * \c GetAllMeshClothingAssetBindings() below. */ struct FClothingAssetMeshBinding { UClothingAssetCommon* Asset; int32 LODIndex; int32 SectionIndex; int32 AssetInternalLodIndex; }; #if WITH_EDITOR /** * Given a skeletal mesh model, find all of the currently bound clothing assets and their binding information * @param MeshModel - The skeletal mesh imported model to extract binding from * @param OutBindings - The list of bindings to write to */ void CLOTHINGSYSTEMRUNTIMECOMMON_API GetAllMeshClothingAssetBindings( const USkeletalMesh* InSkelMesh, TArray& OutBindings); /** * Similar to above, but only inspects the specified LOD. */ void CLOTHINGSYSTEMRUNTIMECOMMON_API GetAllLodMeshClothingAssetBindings( const USkeletalMesh* InSkelMesh, TArray& OutBindings, int32 InLodIndex); /** * Clears the clothing tracking struct of a section. */ CLOTHINGSYSTEMRUNTIMECOMMON_API void ClearSectionClothingData(FSkelMeshSection& InSection); #endif } /** * Custom data wrapper for clothing assets. */ class UE_DEPRECATED(5.0, "Redundant class.") UClothingAssetCustomData; UCLASS(Abstract, MinimalAPI) class UClothingAssetCustomData : public UObject { GENERATED_BODY() }; /** * Common flags used by InvalidateCachedData. */ enum class EClothingCachedDataFlagsCommon : uint8 { None = 0, InverseMasses = 1 << 0, NumInfluences = 1 << 1, SelfCollisionData = 1 << 2, Tethers = 1 << 3, All = 0xFF }; ENUM_CLASS_FLAGS(EClothingCachedDataFlagsCommon); /** * Implementation of non-solver specific, but common Engine related functionality. * * Solver specific implementations may wish to override this class to construct * their own default instances of child classes, such as \c ClothSimConfig and * \c CustomData, as well as override the \c AddNewLod() factory to build their * own implementation of \c UClothLODDataBase. */ UCLASS(hidecategories = Object, BlueprintType, MinimalAPI) class UClothingAssetCommon : public UClothingAssetBase { GENERATED_BODY() public: CLOTHINGSYSTEMRUNTIMECOMMON_API UClothingAssetCommon(const FObjectInitializer& ObjectInitializer); #if WITH_EDITOR /** * Create weights for skinning the render mesh to our simulation mesh, and * weights to drive our sim mesh from the skeleton. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual bool BindToSkeletalMesh(USkeletalMesh* InSkelMesh, const int32 InMeshLodIndex, const int32 InSectionIndex, const int32 InAssetLodIndex) override; /** * Helper that invokes \c UnbindFromSkeletalMesh() for each avilable entry in * \p InSkelMesh->GetImportedModel()'s LODModel. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void UnbindFromSkeletalMesh(USkeletalMesh* InSkelMesh) override; CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void UnbindFromSkeletalMesh(USkeletalMesh* InSkelMesh, const int32 InMeshLodIndex) override; /** * Update all extra LOD deformer mappings. * This should be called whenever the raytracing LOD bias has changed. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void UpdateAllLODBiasMappings(USkeletalMesh* SkeletalMesh) override; /** * Callback envoked after weights have been edited. * Calls \c PushWeightsToMesh() on each \c ClothLodData, and invalidates cached data. * Optionaly recalculate the owner's sections fixed vertex data based on this asset masks, and invalidate the DDC for this asset. */ CLOTHINGSYSTEMRUNTIMECOMMON_API void ApplyParameterMasks(bool bUpdateFixedVertData = false, bool bInvalidateDerivedDataCache = true); /** * Builds the LOD transition data. * When we transition between LODs we skin the incoming mesh to the outgoing mesh * in exactly the same way the render mesh is skinned to create a smooth swap */ CLOTHINGSYSTEMRUNTIMECOMMON_API void BuildLodTransitionData(); //~ Begin UObject interface /** * Stop any simulation from using this asset. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void PreEditUndo() override; /** * Restart simulation using this asset after undo change. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void PostEditUndo() override; //~ End UObject interface #endif // WITH_EDITOR /** * Rebuilds the \c UsedBoneIndices array from looking up the entries in the * \c UsedBoneNames array, in the \p InSkelMesh's reference skeleton. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void RefreshBoneMapping(USkeletalMesh* InSkelMesh) override; /** Calculates the preferred root bone for the simulation. */ CLOTHINGSYSTEMRUNTIMECOMMON_API void CalculateReferenceBoneIndex(); /** Returns \c true if \p InLodIndex is a valid LOD id (index into \c ClothLodData). */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual bool IsValidLod(int32 InLodIndex) const override; /** Returns the number of valid LOD's (length of the \c ClothLodData array). */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual int32 GetNumLods() const override; #if WITH_EDITORONLY_DATA /** * Called on the clothing asset when the base data (physical mesh, config etc.) * has changed, so any intermediate generated data can be regenerated. */ virtual void InvalidateAllCachedData() override { InvalidateFlaggedCachedData(EClothingCachedDataFlagsCommon::All); } /** * Called on the clothing asset when the base data (physical mesh, config etc.) * has changed, so any intermediate generated data can be regenerated. */ CLOTHINGSYSTEMRUNTIMECOMMON_API void InvalidateFlaggedCachedData(EClothingCachedDataFlagsCommon Flags); #endif // WITH_EDITORONLY_DATA #if WITH_EDITOR /** * Add a new LOD class instance. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual int32 AddNewLod() override; /* Called after changes in any of the asset properties. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& ChainEvent) override; #endif // WITH_EDITOR /** Return a const cloth config pointer of the desired cloth config type, or nullptr if there isn't any suitable. */ template::IsDerived>::Type> const ClothConfigType* GetClothConfig() const { auto const* const ClothConfig = ClothConfigs.Find(ClothConfigType::StaticClass()->GetFName()); return ClothConfig ? ExactCast(*ClothConfig) : nullptr; } /** Return a cloth config pointer of the desired cloth config type, or nullptr if there isn't any suitable. */ template::IsDerived>::Type> ClothConfigType* GetClothConfig() { auto const* const ClothConfig = ClothConfigs.Find(ClothConfigType::StaticClass()->GetFName()); return ClothConfig ? ExactCast(*ClothConfig) : nullptr; } /** Migrate deprecated objects. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void PostLoad() override; #if WITH_EDITORONLY_DATA static CLOTHINGSYSTEMRUNTIMECOMMON_API void DeclareConstructClasses(TArray& OutConstructClasses, const UClass* SpecificSubclass); #endif /** Serialize deprecated objects. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void Serialize(FArchive& Ar) override; /** Propagate the shared simulation configs between assets. Called after all cloth assets sharing the same simulation are loaded. */ CLOTHINGSYSTEMRUNTIMECOMMON_API virtual void PostUpdateAllAssets() override; // The physics asset to extract collisions from when building a simulation. UPROPERTY(EditAnywhere, Category = Config) TObjectPtr PhysicsAsset; // Simulation specific cloth parameters. // Use GetClothConfig() to retrieve the correct parameters/config type for the desired cloth simulation system. UPROPERTY(VisibleAnywhere, BlueprintReadOnly, EditFixedSize, Instanced, Category = Config) TMap> ClothConfigs; #if WITH_EDITORONLY_DATA // Shared by all cloth instances in a skeletal mesh // Only supported with Chaos Cloth for now // This may not be editable on unused cloth assets UPROPERTY() TObjectPtr ClothSharedSimConfig_DEPRECATED; // Parameters for how the NVcloth behaves. // These will have no effect on Chaos cloth UPROPERTY() TObjectPtr ClothSimConfig_DEPRECATED; // Parameters for how Chaos cloth behaves // These will not affect NVcloth // For now, we have two configuration parameters so that we can switch between chaos and // non chaos at will without losing the original NVcloth data UPROPERTY() TObjectPtr ChaosClothSimConfig_DEPRECATED; // Deprecated. Use LodData instead UPROPERTY() TArray> ClothLodData_DEPRECATED; #endif // The actual asset data, listed by LOD. UPROPERTY() TArray LodData; // Tracks which clothing LOD each skel mesh LOD corresponds to (LodMap[SkelLod]=ClothingLod). UPROPERTY() TArray LodMap; // List of bones this asset uses inside its parent mesh. UPROPERTY() TArray UsedBoneNames; // List of the indices for the bones in UsedBoneNames, used for remapping. UPROPERTY() TArray UsedBoneIndices; // Bone to treat as the root of the simulation space. UPROPERTY() int32 ReferenceBoneIndex; #if WITH_EDITORONLY_DATA PRAGMA_DISABLE_DEPRECATION_WARNINGS UE_DEPRECATED(5.5, "This property is obsolete.") UPROPERTY(Meta = (DeprecatedProperty, DeprecationMessage = "This property is obsolete.")) TObjectPtr CustomData; PRAGMA_ENABLE_DEPRECATION_WARNINGS /** * Deprecated property for transitioning the \c FClothConfig struct to the * \c UClothConfigBase array, in a new property called \c ClothConfigs. */ UPROPERTY() FClothConfig_Legacy ClothConfig_DEPRECATED; #endif private: // Add or replace a new cloth config of the specified type. template::IsDerived>::Type> void SetClothConfig(ClothConfigType* ClothConfig) { check(ClothConfig); ClothConfigs.Add(ClothConfig->GetClass()->GetFName(), static_cast(ClothConfig)); } // Create and add any missing cloth configs. // If a config from a different factory exists already, the newly // created config will attempt to initialize its parameters from it. // Return true when at least one config has been added, false otherwise. CLOTHINGSYSTEMRUNTIMECOMMON_API bool AddClothConfigs(); // Propagate the shared simulation configs between assets. // Also migrate all deprecated shared parameters which have been moved to the per cloth configs if required. // Called after a cloth asset is created or loaded. CLOTHINGSYSTEMRUNTIMECOMMON_API void PropagateSharedConfigs(bool bMigrateSharedConfigToConfig=false); // Return true when any one of the cloth configs fullfill the predicate. // Used to select which type of data to cache. template bool AnyOfClothConfigs(PredicateType Predicate) const { return Algo::AnyOf(ClothConfigs, [&Predicate](const TPair>& ClothConfig) { return Predicate(*ClothConfig.Value); }); } #if WITH_EDITOR // Add extra cloth deformer mappings to cope with a different raytracing LOD than the one currently rendered. CLOTHINGSYSTEMRUNTIMECOMMON_API void UpdateLODBiasMappings(const USkeletalMesh* SkeletalMesh, int32 UpdatedLODIndex, int32 SectionIndex); // Clear all defomer section that relies on the specified cloth sim data bound to the specified LOD section CLOTHINGSYSTEMRUNTIMECOMMON_API void ClearLODBiasMappings(const USkeletalMesh* SkeletalMesh, int32 UpdatedLODIndex, int32 SectionIndex); // Helper functions used in PostPropertyChangeCb CLOTHINGSYSTEMRUNTIMECOMMON_API void ReregisterComponentsUsingClothing(); CLOTHINGSYSTEMRUNTIMECOMMON_API void ForEachInteractorUsingClothing(TFunction Func); #endif // WITH_EDITOR };