// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Engine/EngineTypes.h" #include "Chaos/ChaosEngineInterface.h" #include "PhysicsAssetUtils.generated.h" class UBodySetup; class UPhysicsAsset; class UPhysicsConstraintTemplate; class USkeletalMesh; class USkeletalMeshComponent; UENUM() enum EPhysAssetFitGeomType : int { EFG_Box UMETA(DisplayName="Box"), EFG_Sphyl UMETA(DisplayName="Capsule"), EFG_Sphere UMETA(DisplayName="Sphere"), EFG_TaperedCapsule UMETA(DisplayName="Tapered Capsule (Cloth Only)"), EFG_SingleConvexHull UMETA(DisplayName="Single Convex Hull"), EFG_MultiConvexHull UMETA(DisplayName="Multi Convex Hull"), EFG_LevelSet UMETA(DisplayName="Level Set (Experimental, Cloth Only)"), EFG_SkinnedLevelSet UMETA(DisplayName="Skinned Level Set (Experimental, Cloth Only)"), EFG_MLLevelSet UMETA(Hidden), EFG_SkinnedTriangleMesh UMETA(Hidden), }; UENUM() enum EPhysAssetFitVertWeight : int { EVW_AnyWeight UMETA(DisplayName="Any Weight"), EVW_DominantWeight UMETA(DisplayName="Dominant Weight"), }; /** Parameters for PhysicsAsset creation */ USTRUCT() struct FPhysAssetCreateParams { GENERATED_BODY() FPhysAssetCreateParams() { MinBoneSize = 20.0f; MinWeldSize = KINDA_SMALL_NUMBER; GeomType = EFG_Sphyl; VertWeight = EVW_DominantWeight; bAutoOrientToBone = true; bCreateConstraints = true; bWalkPastSmall = true; bBodyForAll = false; bDisableCollisionsByDefault = true; AngularConstraintMode = ACM_Limited; HullCount = 4; MaxHullVerts = 16; LevelSetResolution = 8; LatticeResolution = 8; } /** Bones that are shorter than this value will be ignored for body creation */ UPROPERTY(EditAnywhere, Category = "Body Creation") float MinBoneSize; /** Bones that are smaller than this value will be merged together for body creation */ UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "Body Creation") float MinWeldSize; /** The geometry type that should be used when creating bodies */ UPROPERTY(EditAnywhere, Category = "Body Creation", meta=(DisplayName="Primitive Type")) TEnumAsByte GeomType; /** How vertices are mapped to bones when approximating them with bodies */ UPROPERTY(EditAnywhere, Category = "Body Creation", meta=(DisplayName="Vertex Weighting Type")) TEnumAsByte VertWeight; /** Whether to automatically orient the created bodies to their corresponding bones */ UPROPERTY(EditAnywhere, Category = "Body Creation") bool bAutoOrientToBone; /** Whether to create constraints between adjacent created bodies */ UPROPERTY(EditAnywhere, Category = "Constraint Creation") bool bCreateConstraints; /** Whether to skip small bones entirely (rather than merge them with adjacent bones) */ UPROPERTY(EditAnywhere, Category = "Body Creation", meta=(DisplayName="Walk Past Small Bones")) bool bWalkPastSmall; /** Forces creation of a body for each bone */ UPROPERTY(EditAnywhere, Category = "Body Creation", meta=(DisplayName="Create Body for All Bones")) bool bBodyForAll; /** Whether to disable collision of body with other bodies on creation */ UPROPERTY(EditAnywhere, Category = "Body Creation") bool bDisableCollisionsByDefault; /** The type of angular constraint to create between bodies */ UPROPERTY(EditAnywhere, Category = "Constraint Creation", meta=(EditCondition="bCreateConstraints")) TEnumAsByte AngularConstraintMode; /** When creating multiple convex hulls, the maximum number that will be created. */ UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "Body Creation", meta = (EditCondition = "GeomType == EPhysAssetFitGeomType::EFG_MultiConvexHull", EditConditionHides)) int32 HullCount; /** When creating convex hulls, the maximum verts that should be created */ UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "Body Creation", meta = (EditCondition = "GeomType == EPhysAssetFitGeomType::EFG_MultiConvexHull || GeomType == EPhysAssetFitGeomType::EFG_SingleConvexHull", EditConditionHides)) int32 MaxHullVerts; /** When creating level sets, the grid resolution to use */ UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "Body Creation", meta = (ClampMin = 1, UIMin = 10, UIMax = 100, ClampMax = 500, EditCondition = "GeomType == EPhysAssetFitGeomType::EFG_LevelSet || GeomType == EPhysAssetFitGeomType::EFG_SkinnedLevelSet", EditConditionHides)) int32 LevelSetResolution; /** When creating skinned level sets, the embedding grid resolution to use*/ UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "Body Creation", meta = (ClampMin = 1, UIMin = 10, UIMax = 100, ClampMax = 500, EditCondition = "GeomType == EPhysAssetFitGeomType::EFG_SkinnedLevelSet", EditConditionHides)) int32 LatticeResolution; }; class UPhysicsAsset; class UPhysicsConstraintTemplate; struct FBoneVertInfo; /** Collection of functions to create and setup PhysicsAssets */ namespace FPhysicsAssetUtils { /** * Given a USkeletalMesh, construct a new PhysicsAsset automatically, using the vertices weighted to each bone to calculate approximate collision geometry. * Ball-and-socket joints will be created for every joint by default. * * @param PhysicsAsset The PhysicsAsset instance to setup * @param SkelMesh The Skeletal Mesh to create the physics asset from * @param Params Additional creation parameters * @param OutErrorMessage Additional error information * @param bSetToMesh Whether or not to apply the physics asset to SkelMesh immediately */ PHYSICSUTILITIES_API bool CreateFromSkeletalMesh(UPhysicsAsset* PhysicsAsset, USkeletalMesh* SkelMesh, const FPhysAssetCreateParams& Params, FText& OutErrorMessage, bool bSetToMesh = true, bool bShowProgress = true); /** Replaces any collision already in the BodySetup with an auto-generated one using the parameters provided. * * @warning Certain physics geometry types, such as multi-convex hull, must recreate internal caches every time this function is called. * If you find you're calling this function repeatedly for different bone indices on the same mesh, * CreateFromSkeletalMesh or CreateCollisionsFromBones will provide better performance. * * @param bs BodySetup to create the collision for * @param skelMesh The SkeletalMesh we create collision for * @param BoneIndex Index of the bone the collision is created for * @param Params Additional parameters to control the creation * @param Info The vertices to create the collision for * @return Returns true if successfully created collision from bone */ PHYSICSUTILITIES_API bool CreateCollisionFromBone( UBodySetup* bs, USkeletalMesh* skelMesh, int32 BoneIndex, const FPhysAssetCreateParams& Params, const FBoneVertInfo& Info ); /** Replaces any collision already in the BodySetup with an auto-generated one using the parameters provided. * * @param bs BodySetup to create the collision for * @param skelMesh The SkeletalMesh we create collision for * @param BoneIndices Indices of the bones the collisions are created for * @param Params Additional parameters to control the creation * @param Info The vertices to create the collision for * @return Returns true if successfully created collision from all specified bones */ PHYSICSUTILITIES_API bool CreateCollisionFromBones( UBodySetup* bs, USkeletalMesh* skelMesh, const TArray& BoneIndices, FPhysAssetCreateParams& Params, const FBoneVertInfo& Info ); /** Replaces any collision already in the with an auto-generated ones using the parameters provided. * * @param PhysicsAsset The PhysicsAsset instance to update * @param SkelMesh The Skeletal Mesh to create the physics asset from * @param BodyIndices Indices of the existing BodySetups the collisions are created for * @param Params Additional parameters to control the creation * @param Infos The vertices to create the collisions for (parallel array to BodyIndices) * @param OutSuccessfulBodyIndices Newly created BodySetup indices. * @return Returns true if successfully created collision from all specified bodies */ PHYSICSUTILITIES_API bool CreateCollisionsFromBones(UPhysicsAsset* PhysicsAsset, USkeletalMesh* SkelMesh, const TArray& BodyIndices, const FPhysAssetCreateParams& Params, const TArray& Infos, TArray& OutSuccessfulBodyIndices); /** * Given a USkeletalMesh, generate a Skinned Triangle Mesh primitive and add it to the root body (creating a new one if needed). * * @param PhysicsAsset The PhysicsAsset instance to update * @param SkelMesh The Skeletal Mesh to create the physics asset from * @param LODIndex SkelMesh LOD index to use. * @param Params Additional creation parameters * @param OutErrorMessage Additional error information * @return Index of body under which the new Skinned Triangle Mesh primitive was created (or INDEX_NONE if failure) */ PHYSICSUTILITIES_API int32 GenerateSkinnedTriangleMesh(UPhysicsAsset* PhysicsAsset, USkeletalMesh* SkelMesh, int32 LODIndex, const FPhysAssetCreateParams& Params, FText& OutErrorMessage, bool bShowProgress = true); /** * Does a few things: * - add any collision primitives from body2 into body1 (adjusting the tm of each). * - reconnect any constraints between 'add body' to 'base body', destroying any between them. * - update collision disable table for any pairs including 'add body' */ PHYSICSUTILITIES_API void WeldBodies(UPhysicsAsset* PhysAsset, int32 BaseBodyIndex, int32 AddBodyIndex, USkeletalMeshComponent* SkelComp); /** * Creates a new constraint * * @param PhysAsset The PhysicsAsset to create the constraint for * @param InConstraintName Name of the constraint * @param InConstraintSetup Optional constraint setup * @return Returns the index of the newly created constraint. **/ PHYSICSUTILITIES_API int32 CreateNewConstraint(UPhysicsAsset* PhysAsset, FName InConstraintName, UPhysicsConstraintTemplate* InConstraintSetup = NULL); /** * Destroys the specified constraint * * @param PhysAsset The PhysicsAsset for which the constraint should be destroyed * @param ConstraintIndex The index of the constraint to destroy */ PHYSICSUTILITIES_API void DestroyConstraint(UPhysicsAsset* PhysAsset, int32 ConstraintIndex); /** * Create a new BodySetup and default BodyInstance if there is not one for this body already. * * @param PhysAsset The PhysicsAsset to create the body for * @param InBodyName Name of the new body * @return The Index of the newly created body. */ PHYSICSUTILITIES_API int32 CreateNewBody(UPhysicsAsset* const PhysAsset, const FName InBodyName, const FPhysAssetCreateParams& Params); /** * Destroys the specified body * * @param PhysAsset The PhysicsAsset for which the body should be destroyed * @param BodyIndex Index of the body to destroy */ PHYSICSUTILITIES_API void DestroyBody(UPhysicsAsset* const PhysAsset, const int32 BodyIndex); /** * Initialize a new BodySetup at a specified index in the physics asset and create a default BodyInstance if there is not one for this body already. * * @param PhysAsset The PhysicsAsset to create the body for * @param InBodyName Name of the new body * @param Params Parameters used when configuring the body * @param BodyIndex Index of the body to initialize in the Physics Asset */ PHYSICSUTILITIES_API void RecreateBody(UPhysicsAsset* const PhysAsset, const FName InBodyName, const FPhysAssetCreateParams& Params, const int32 BodyIndex); /** * Whether or not Constraints are allowed to be created (due to asset list filtering) */ PHYSICSUTILITIES_API bool CanCreateConstraints(); PHYSICSUTILITIES_API void SanitizeRestrictedContent(UPhysicsAsset* PhysAsset); };