Files
UnrealEngine/Engine/Source/Developer/PhysicsUtilities/Public/PhysicsAssetUtils.h
2025-05-18 13:04:45 +08:00

248 lines
12 KiB
C++

// 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<EPhysAssetFitGeomType> GeomType;
/** How vertices are mapped to bones when approximating them with bodies */
UPROPERTY(EditAnywhere, Category = "Body Creation", meta=(DisplayName="Vertex Weighting Type"))
TEnumAsByte<EPhysAssetFitVertWeight> 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<EAngularConstraintMotion> 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<int32>& 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<int32>& BodyIndices, const FPhysAssetCreateParams& Params, const TArray<FBoneVertInfo>& Infos, TArray<int32>& 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);
};