// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "BonePose.h" #include "BoneControllers/AnimNode_ModifyBone.h" #include "Animation/AnimSingleNodeInstance.h" #include "Animation/AnimSingleNodeInstanceProxy.h" #include "AnimNodes/AnimNode_CurveSource.h" #include "AnimNodes/AnimNode_PoseBlendNode.h" #include "AnimNodes/AnimNode_CopyPoseFromMesh.h" #include "AnimPreviewInstance.generated.h" /** Enum to know how montage is being played */ UENUM() enum EMontagePreviewType : int { /** Playing montage in usual way. */ EMPT_Normal, /** Playing all sections. */ EMPT_AllSections, EMPT_MAX, }; /** Proxy override for this UAnimInstance-derived class */ USTRUCT() struct ANIMGRAPH_API FAnimPreviewInstanceProxy : public FAnimSingleNodeInstanceProxy { GENERATED_BODY() public: FAnimPreviewInstanceProxy() { bCanProcessAdditiveAnimations = true; } FAnimPreviewInstanceProxy(UAnimInstance* InAnimInstance) : FAnimSingleNodeInstanceProxy(InAnimInstance) , SkeletalControlAlpha(1.0f) , bEnableControllers(true) , bSetKey(false) { bCanProcessAdditiveAnimations = true; } virtual void Initialize(UAnimInstance* InAnimInstance) override; virtual void Update(float DeltaSeconds) override; virtual void UpdateAnimationNode(const FAnimationUpdateContext& InContext) override; virtual bool Evaluate(FPoseContext& Output) override; virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds) override; virtual void SetAnimationAsset(UAnimationAsset* NewAsset, USkeletalMeshComponent* MeshComponent, bool bIsLooping, float InPlayRate) override; void ResetModifiedBone(bool bCurveController = false); FAnimNode_ModifyBone* FindModifiedBone(const FName& InBoneName, bool bCurveController = false); FAnimNode_ModifyBone& ModifyBone(const FName& InBoneName, bool bCurveController = false); void RemoveBoneModification(const FName& InBoneName, bool bCurveController = false); void EnableControllers(bool bEnable) { bEnableControllers = bEnable; } void SetSkeletalControlAlpha(float InSkeletalControlAlpha) { SkeletalControlAlpha = FMath::Clamp(InSkeletalControlAlpha, 0.f, 1.f); } #if WITH_EDITOR void SetKey() { bSetKey = true; } FDelegateHandle AddKeyCompleteDelegate(FSimpleMulticastDelegate::FDelegate InOnSetKeyCompleteDelegate) { return OnSetKeyCompleteDelegate.Add(InOnSetKeyCompleteDelegate); } void RemoveKeyCompleteDelegate(FDelegateHandle InDelegateHandle) { OnSetKeyCompleteDelegate.Remove(InDelegateHandle); } #endif void RefreshCurveBoneControllers(UAnimationAsset* AssetToRefreshFrom); TArray& GetBoneControllers() { return BoneControllers; } TArray& GetCurveBoneControllers() { return CurveBoneControllers; } virtual void AddImpulseAtLocation(FVector Impulse, FVector Location, FName BoneName = NAME_None) {} /** Sets an external debug skeletal mesh component to use to debug */ void SetDebugSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent); /** Gets the external debug skeletal mesh component we are debugging */ USkeletalMeshComponent* GetDebugSkeletalMeshComponent() const; private: void UpdateCurveController(); void ApplyBoneControllers(TArray &InBoneControllers, FComponentSpacePoseContext& ComponentSpacePoseContext); void SetKeyImplementation(const FCompactPose& PreControllerInLocalSpace, const FCompactPose& PostControllerInLocalSpace); void AddKeyToSequence(UAnimSequence* Sequence, float Time, const FName& BoneName, const FTransform& AdditiveTransform); private: /** Controllers for individual bones */ TArray BoneControllers; /** Curve modifiers */ TArray CurveBoneControllers; /** External curve for in-editor curve sources (such as audio) */ FAnimNode_CurveSource CurveSource; /** Pose blend node for evaluating pose assets (for previewing curve sources) */ FAnimNode_PoseBlendNode PoseBlendNode; /** Allows us to copy a pose from the mesh being debugged */ FAnimNode_CopyPoseFromMesh CopyPoseNode; /** * Delegate to call after Key is set */ FSimpleMulticastDelegate OnSetKeyCompleteDelegate; /** Shared parameters for previewing blendspace or animsequence **/ float SkeletalControlAlpha; /* * Used to determine if controller has to be applied or not * Used to disable controller during editing */ bool bEnableControllers; /* * When this flag is true, it sets key */ bool bSetKey; }; /** * This Instance only contains one AnimationAsset, and produce poses * Used by Preview in AnimGraph, Playing single animation in Kismet2 and etc */ UCLASS(transient, NotBlueprintable, noteditinlinenew) class ANIMGRAPH_API UAnimPreviewInstance : public UAnimSingleNodeInstance { GENERATED_UCLASS_BODY() /** Shared parameters for previewing blendspace or animsequence **/ UPROPERTY(transient) TEnumAsByte MontagePreviewType; UPROPERTY(transient) int32 MontagePreviewStartSectionIdx; //~ Begin UObject Interface virtual void Serialize(FArchive& Ar) override; //~ End UObject Interface //~ Begin UAnimInstance Interface virtual void NativeInitializeAnimation() override; virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override; virtual bool CanRunParallelWork() const { return false; } protected: virtual void Montage_Advance(float DeltaTime) override; //~ End UAnimInstance Interface public: /** Set SkeletalControl Alpha**/ void SetSkeletalControlAlpha(float SkeletalControlAlpha); UAnimSequence* GetAnimSequence(); //~ Begin UAnimSingleNodeInstance Interface virtual void RestartMontage(UAnimMontage* Montage, FName FromSection = FName()) override; virtual void SetAnimationAsset(UAnimationAsset* NewAsset, bool bIsLooping = true, float InPlayRate = 1.f) override; //~ End UAnimSingleNodeInstance Interface /** Montage preview functions */ void MontagePreview_JumpToStart(); void MontagePreview_JumpToEnd(); void MontagePreview_JumpToPreviewStart(); void MontagePreview_Restart(); void MontagePreview_PreviewNormal(int32 FromSectionIdx = INDEX_NONE, bool bPlay = true); void MontagePreview_SetLoopNormal(bool bIsLooping, int32 PreferSectionIdx = INDEX_NONE); void MontagePreview_PreviewAllSections(bool bPlay = true); void MontagePreview_SetLoopAllSections(bool bIsLooping); void MontagePreview_SetLoopAllSetupSections(bool bIsLooping); void MontagePreview_ResetSectionsOrder(); void MontagePreview_SetLooping(bool bIsLooping); void MontagePreview_SetPlaying(bool bIsPlaying); void MontagePreview_SetReverse(bool bInReverse); void MontagePreview_StepForward(); void MontagePreview_StepBackward(); void MontagePreview_JumpToPosition(float NewPosition); int32 MontagePreview_FindFirstSectionAsInMontage(int32 AnySectionIdx); int32 MontagePreview_FindLastSection(int32 StartSectionIdx); float MontagePreview_CalculateStepLength(); void MontagePreview_RemoveBlendOut(); bool IsPlayingMontage() { return GetActiveMontageInstance() != NULL; } /** * Finds an already modified bone * @param InBoneName The name of the bone modification to find * @return the bone modification or NULL if no current modification was found */ FAnimNode_ModifyBone* FindModifiedBone(const FName& InBoneName, bool bCurveController=false); /** * Modifies a single bone. Create a new FAnimNode_ModifyBone if one does not exist for the passed-in bone. * @param InBoneName The name of the bone to modify * @return the new or existing bone modification */ FAnimNode_ModifyBone& ModifyBone(const FName& InBoneName, bool bCurveController=false); /** * Removes an existing bone modification * @param InBoneName The name of the existing modification to remove */ void RemoveBoneModification(const FName& InBoneName, bool bCurveController=false); /** * Reset all bone modified */ void ResetModifiedBone(bool bCurveController=false); /** * Returns all currently active bone controllers on this instance's proxy */ const TArray& GetBoneControllers(); #if WITH_EDITOR /** * Convert current modified bone transforms (BoneControllers) to transform curves (CurveControllers) * it does based on CurrentTime. This function does not set key directly here. * It does wait until next update, and it gets the delta of transform before applying curves, and * creates curves from it, so you'll need delegate if you'd like to do something after (set with SetKeyCompleteDelegate) */ void SetKey(); /** * Add the delegate to be called when a key is set. * * @param Delegate To be called once set key is completed */ FDelegateHandle AddKeyCompleteDelegate(FSimpleMulticastDelegate::FDelegate InOnSetKeyCompleteDelegate); /** * Add the delegate to be called when a key is set. * * @param Delegate To be called once set key is completed */ void RemoveKeyCompleteDelegate(FDelegateHandle InDelegateHandle); #endif /** * Refresh Curve Bone Controllers based on TransformCurves from Animation data */ void RefreshCurveBoneControllers(); /** * Enable Controllers * This is used by when editing, when controller has to be disabled */ void EnableControllers(bool bEnable); /** Preview physics interaction */ void AddImpulseAtLocation(FVector Impulse, FVector Location, FName BoneName = NAME_None); /** Sets an external debug skeletal mesh component to use to debug */ void SetDebugSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent); /** Gets the external debug skeletal mesh component we are debugging */ USkeletalMeshComponent* GetDebugSkeletalMeshComponent() const; };