Files
UnrealEngineUWP/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_HandIKRetargeting.cpp
Thomas Sarkanen 1dee2903c0 Added schematic view of animation graphs
Initial basic implementation, more features to follow.
Accessed via the context menu of a graph track.
Shows anim graph nodes in a linearized tree similar to ShowDebug ANIMATION.
Select a node to 'pin' all the properties that it traced (multi select supported) to the bottom of the window.
Scrub the timeline to see those properties change over time.
Asset references use clickable hyperlinks to go to the specified asset editor.

#rb Jurre.deBaare

[CL 11041140 by Thomas Sarkanen in Dev-Core branch]
2020-01-17 03:32:34 -05:00

137 lines
5.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BoneControllers/AnimNode_HandIKRetargeting.h"
#include "Animation/AnimTrace.h"
/////////////////////////////////////////////////////
// FAnimNode_HandIKRetargeting
FAnimNode_HandIKRetargeting::FAnimNode_HandIKRetargeting()
: HandFKWeight(0.5f)
{
}
void FAnimNode_HandIKRetargeting::GatherDebugData(FNodeDebugData& DebugData)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(GatherDebugData)
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
DebugLine += FString::Printf(TEXT(" HandFKWeight: %f)"), HandFKWeight);
for (int32 BoneIndex = 0; BoneIndex < IKBonesToMove.Num(); BoneIndex++)
{
DebugLine += FString::Printf(TEXT(", %s)"), *IKBonesToMove[BoneIndex].BoneName.ToString());
}
DebugLine += FString::Printf(TEXT(")"));
DebugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(DebugData);
}
void FAnimNode_HandIKRetargeting::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(EvaluateSkeletalControl_AnyThread)
checkSlow(OutBoneTransforms.Num() == 0);
const FBoneContainer& BoneContainer = Output.Pose.GetPose().GetBoneContainer();
FVector FKLocation = FVector::ZeroVector;
FVector IKLocation = FVector::ZeroVector;
if (FAnimWeight::IsFullWeight(HandFKWeight))
{
const FCompactPoseBoneIndex RightHandFKBoneIndex = RightHandFK.GetCompactPoseIndex(BoneContainer);
const FCompactPoseBoneIndex RightHandIKBoneIndex = RightHandIK.GetCompactPoseIndex(BoneContainer);
FKLocation = Output.Pose.GetComponentSpaceTransform(RightHandFKBoneIndex).GetTranslation();
IKLocation = Output.Pose.GetComponentSpaceTransform(RightHandIKBoneIndex).GetTranslation();
}
else if (!FAnimWeight::IsRelevant(HandFKWeight))
{
const FCompactPoseBoneIndex LeftHandFKBoneIndex = LeftHandFK.GetCompactPoseIndex(BoneContainer);
const FCompactPoseBoneIndex LeftHandIKBoneIndex = LeftHandIK.GetCompactPoseIndex(BoneContainer);
FKLocation = Output.Pose.GetComponentSpaceTransform(LeftHandFKBoneIndex).GetTranslation();
IKLocation = Output.Pose.GetComponentSpaceTransform(LeftHandIKBoneIndex).GetTranslation();
}
else
{
const FCompactPoseBoneIndex RightHandFKBoneIndex = RightHandFK.GetCompactPoseIndex(BoneContainer);
const FCompactPoseBoneIndex RightHandIKBoneIndex = RightHandIK.GetCompactPoseIndex(BoneContainer);
const FCompactPoseBoneIndex LeftHandFKBoneIndex = LeftHandFK.GetCompactPoseIndex(BoneContainer);
const FCompactPoseBoneIndex LeftHandIKBoneIndex = LeftHandIK.GetCompactPoseIndex(BoneContainer);
const FVector RightHandFKLocation = Output.Pose.GetComponentSpaceTransform(RightHandFKBoneIndex).GetTranslation();
const FVector RightHandIKLocation = Output.Pose.GetComponentSpaceTransform(RightHandIKBoneIndex).GetTranslation();
const FVector LeftHandFKLocation = Output.Pose.GetComponentSpaceTransform(LeftHandFKBoneIndex).GetTranslation();
const FVector LeftHandIKLocation = Output.Pose.GetComponentSpaceTransform(LeftHandIKBoneIndex).GetTranslation();
// Compute weight FK and IK hand location. And translation from IK to FK.
FKLocation = FMath::Lerp<FVector>(LeftHandFKLocation, RightHandFKLocation, HandFKWeight);
IKLocation = FMath::Lerp<FVector>(LeftHandIKLocation, RightHandIKLocation, HandFKWeight);
}
const FVector IK_To_FK_Translation = FKLocation - IKLocation;
// If we're not translating, don't send any bones to update.
if (!IK_To_FK_Translation.IsNearlyZero())
{
// Move desired bones
for (const FBoneReference& BoneReference : IKBonesToMove)
{
if (BoneReference.IsValidToEvaluate(BoneContainer))
{
const FCompactPoseBoneIndex BoneIndex = BoneReference.GetCompactPoseIndex(BoneContainer);
FTransform BoneTransform = Output.Pose.GetComponentSpaceTransform(BoneIndex);
BoneTransform.AddToTranslation(IK_To_FK_Translation);
OutBoneTransforms.Add(FBoneTransform(BoneIndex, BoneTransform));
}
}
if (OutBoneTransforms.Num() > 0)
{
OutBoneTransforms.Sort(FCompareBoneTransformIndex());
}
}
#if ANIM_TRACE_ENABLED
TRACE_ANIM_NODE_VALUE(Output, TEXT("Hand FK Weight"), HandFKWeight);
#endif
}
bool FAnimNode_HandIKRetargeting::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
if (RightHandFK.IsValidToEvaluate(RequiredBones)
&& LeftHandFK.IsValidToEvaluate(RequiredBones)
&& RightHandIK.IsValidToEvaluate(RequiredBones)
&& LeftHandIK.IsValidToEvaluate(RequiredBones))
{
// we need at least one bone to move valid.
for (int32 BoneIndex = 0; BoneIndex < IKBonesToMove.Num(); BoneIndex++)
{
if (IKBonesToMove[BoneIndex].IsValidToEvaluate(RequiredBones))
{
return true;
}
}
}
return false;
}
void FAnimNode_HandIKRetargeting::InitializeBoneReferences(const FBoneContainer& RequiredBones)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(InitializeBoneReferences)
RightHandFK.Initialize(RequiredBones);
LeftHandFK.Initialize(RequiredBones);
RightHandIK.Initialize(RequiredBones);
LeftHandIK.Initialize(RequiredBones);
for (int32 BoneIndex = 0; BoneIndex < IKBonesToMove.Num(); BoneIndex++)
{
IKBonesToMove[BoneIndex].Initialize(RequiredBones);
}
}