// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "AnimationModifier.h" #include "MeshDescription.h" #include "UObject/ObjectPtr.h" #include "RelativeBodyAnimModifier.generated.h" class UPhysicsAsset; class URelativeBodyAnimNotifyBase; class USkeletalMesh; struct FAnimPose; struct FReferenceSkeleton; USTRUCT(BlueprintType) struct FRelativeBodySourceData { GENERATED_BODY() /** The names of either controls of body modifiers (depending on context) */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicalIKRetargeter) TArray BodyIndicesParentBodyIndices; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicalIKRetargeter) TArray BodyIndicesToIgnore; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicalIKRetargeter) TArray IsDomainBody; /*Source Data*/ TArray SourceRetargetGlobalPose; TArray> SourceVertexIndicesInfluencedByBodyIndices; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicalIKRetargeter) TArray SourceVLocations; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicalIKRetargeter) TArray BodyIndicesToSourceBoneIndices; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicalIKRetargeter) TArray SourceBoneIndicesToBodyIndices; }; /** * Animation modifier for baking relative body relationships into anim notify */ UCLASS(meta = (IsBlueprintBase = true)) class RELATIVEBODYANIMUTILS_API URelativeBodyAnimModifier : public UAnimationModifier { GENERATED_BODY() public: /** Begin UAnimationModifier interface */ virtual void OnApply_Implementation(UAnimSequence* InAnimation) override; virtual void OnRevert_Implementation(UAnimSequence* InAnimation) override; /** End UAnimationModifier interface */ public: /** Rate used to sample the animation */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (Units = "Hz", UIMin = 1)) int SampleRate = 30; /** Threshold for determining if a bone pair can be considered to be having contact */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings") float ContactThreshold = 150.0f; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (TitleProperty = "SkeletalMeshAsset")) TObjectPtr SkeletalMeshAsset; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (TitleProperty = "PhysicsAssetOverride")) TObjectPtr PhysicsAssetOverride; /** Bodies to be checked against contact bodies */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (TitleProperty = "DomainBodyNames")) TArray DomainBodyNames; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Settings", meta = (TitleProperty = "ContactBodyNames")) TArray ContactBodyNames; // Relative Body Notify subclass to create UPROPERTY(EditAnywhere, Category = "Settings", meta = (TitleProperty = "PhysicalIKRetargeterNotifyClass")) TSubclassOf NotifyClass = nullptr; private: FMeshDescription MeshDescription; FRelativeBodySourceData CachedBodySourceData; UPROPERTY(VisibleAnywhere, AdvancedDisplay, meta = (Category = "Settings")) int32 LODIndex = 0; /** Keep track of to be generated tracks during modifier application */ UPROPERTY(VisibleAnywhere, AdvancedDisplay, meta = (Category = "Settings")) TSet GeneratedNotifyTracks; UPhysicsAsset* GetPhysicsAsset() const; void CacheBodyDataForSourceMesh(FRelativeBodySourceData& OutSourceData); void GetRefToAnimPoseMatrices(TArray& OutRefToPose, const FAnimPose& AnimPose) const; void GetSkinnedVertices(TArray& VLocations, const TArray& CacheToLocals); };