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

方法:继承FAnimNode_Base创建自定义动画节点。重写Evaluate部分。创建相应的AnimGraphNode。可参考前一篇http://blog.csdn.net/u010831746/article/details/50733287

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。

 

主要代码:

AnimNode_EvaluatePose.h

/*!
 * \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//

};

AnimNode_EvaluatePose.cpp

//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();
	}
}



posted on 2016-03-29 18:03  Corgi  阅读(1752)  评论(0编辑  收藏  举报