智慧 + 毅力 = 无所不能

正确性、健壮性、可靠性、效率、易用性、可读性、可复用性、兼容性、可移植性...

导航

[UE4][Custom Animation Graph Node]Evaluate Pose by Curve

Posted on 2018-02-12 11:24  Bill Yuan  阅读(656)  评论(0编辑  收藏  举报

转自:http://www.cnblogs.com/corgi/p/5405447.html

目的:根据曲线值获得当前动作帧。用于实现各种通过曲线同步的功能。

方法:继承FAnimNode_Base创建自定义动画节点。重写Evaluate部分。创建相应的AnimGraphNode。

Evaluate : 1. 根据曲线Value(Y轴)值获得Time(X轴)值。

曲线KeyArray所在位置。AnimSequenceBase : RawCurveData.

类型AnimCurveTypes.h:FRawCurveTracks

曲线记录是TArray<FRichCurveKey>。每个key中存有Time和Value。根据输入的CurveValue,遍历Array查找Value最接近的Key,返回Time。

2.根据Time值获得动画POS

AnimSequence->GetAnimationPose(…, Time, …)输出Pose。

/*! 
 * \file AnimNode_EvaluatePose.h 
 * \date 2016/03/29 17:45 
 * 
 * \author: Jia Zhipeng 
 * Contact: jiazhipeng@pwrd.com 
 * 
 * \brief: 根据曲线获得当前Pose. Get Pose based on curve value. 
 * 
 * \note:  
*/  
#pragma once  
#include "Animation/AnimNodeBase.h"  
//#include "AnimNode_SkeletalControlBase.h"  
#include "AnimNode_EvaluatePose.generated.h"  
  
USTRUCT()  
struct FAnimNode_EvaluatePose :public FAnimNode_Base  
{  
    GENERATED_USTRUCT_BODY()  
  
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta = (PinShownByDefault))  
    UAnimSequenceBase* Sequence;  
  
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta = (PinShownByDefault))  
        FName CurveName;  
  
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta = (PinShownByDefault))  
        float CurveValue;  
  
    UAnimInstance* MyInstance;  
public:  
    //  Constructor  
    FAnimNode_EvaluatePose();  
  
    // FAnimNode_Base interface  
    virtual void Initialize(const FAnimationInitializeContext& Context) override;  
    virtual void CacheBones(const FAnimationCacheBonesContext& Context) override;  
    virtual void Evaluate(FPoseContext& Output) override;  
    virtual void OverrideAsset(UAnimationAsset* NewAsset) override;  
    virtual void GatherDebugData(FNodeDebugData& DebugData) override;  
    // End of FAnimNode_Base interface//  
  
};  
//Iterate Animation's curve's keys to get current time  
void FAnimNode_EvaluatePose::Evaluate(FPoseContext& Output)  
{     
//CurveValue is connected to AnimInstance’s variable in AnimBlueprint, but it is not updated when executing this node. So how to get variable of AnimInstance? 2 ways.  
//1. EvaluateGraphExposedInputs.Execute(Output); Cause crash. Explore this method in the future.  
//2. Get property from AnimInstance. But in this way, the variable’s name has to be specified. Temporarily use this method.  
    UFloatProperty* FloatProp = Cast<UFloatProperty>(PW_PropertyTools::FindProperty(MyInstance, TEXT("Horiz Movement Speed")));  
    if (!FloatProp)  
    {  
        UE_LOG(LogTemp, Warning, TEXT("Horiz Movement Speed Not found"));  
        return;  
    }  
    float HorzSpeed = FloatProp->GetPropertyValue_InContainer(MyInstance);  
    CurveValue = HorzSpeed;  
      
    USkeleton* Skeleton = Sequence->GetSkeleton();  
    if (!Skeleton)  
    {  
        UE_LOG(LogTemp, Warning, TEXT("FAnimNode_EvaluatePose::Evaluate fail to find skeleton"));  
        return;  
    }  
    FSmartNameMapping* NameMapping = Skeleton->SmartNames.GetContainer(USkeleton::AnimCurveMappingName);  
    // retrieve curve  
    USkeleton::AnimCurveUID Uid;  
    if (!NameMapping->Exists(CurveName))  
    {  
        UE_LOG(LogTemp, Warning, TEXT("FAnimNode_EvaluatePose::Evaluate fail to find curve %s"), *CurveName.ToString());  
        return;  
    }  
  
    Uid = *NameMapping->FindUID(CurveName);  
    FFloatCurve * CurveToCompute = static_cast<FFloatCurve*>(Sequence->RawCurveData.GetCurveData(Uid));  
    if (!CurveToCompute)  
    {  
        UE_LOG(LogTemp, Warning, TEXT("FAnimNode_EvaluatePose::Evaluate fail to find curve %s"), *CurveName.ToString());  
        return;  
    }  
  
    auto FloatCurve = CurveToCompute->FloatCurve;  
    float OutTime = 0.0f;  
    BinarySeach(FloatCurve, CurveValue, OutTime);  
    if ((Sequence != NULL) && (Output.AnimInstance->CurrentSkeleton->IsCompatible(Sequence->GetSkeleton())))  
    {  
        Sequence->GetAnimationPose(Output.Pose, Output.Curve, FAnimExtractContext(OutTime, Output.AnimInstance->ShouldExtractRootMotion()));  
    }  
    else  
    {  
        Output.ResetToRefPose();  
    }  
}