Files
UnrealEngine/Engine/Plugins/Animation/IKRig/Source/IKRigDeveloper/Private/AnimGraphNode_RetargetPoseFromMesh.cpp
2025-05-18 13:04:45 +08:00

167 lines
5.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimGraphNode_RetargetPoseFromMesh.h"
#include "Animation/AnimInstance.h"
#include "Kismet2/CompilerResultsLog.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(AnimGraphNode_RetargetPoseFromMesh)
#define LOCTEXT_NAMESPACE "AnimGraphNode_IKRig"
const FName UAnimGraphNode_RetargetPoseFromMesh::AnimModeName(TEXT("IKRig.IKRigEditor.IKRigEditMode"));
void UAnimGraphNode_RetargetPoseFromMesh::Draw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* PreviewSkelMeshComp) const
{
}
FText UAnimGraphNode_RetargetPoseFromMesh::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
if (Node.RetargetFrom == ERetargetSourceMode::SourcePosePin)
{
return LOCTEXT("AnimGraphNode_IKRetargeter_Title_FromInput", "Retarget Input Pose");
}
return LOCTEXT("AnimGraphNode_IKRetargeter_Title", "Retarget Pose From Mesh");
}
void UAnimGraphNode_RetargetPoseFromMesh::CopyNodeDataToPreviewNode(FAnimNode_Base* InPreviewNode)
{
FAnimNode_RetargetPoseFromMesh* IKRetargeterNode = static_cast<FAnimNode_RetargetPoseFromMesh*>(InPreviewNode);
}
FEditorModeID UAnimGraphNode_RetargetPoseFromMesh::GetEditorMode() const
{
return AnimModeName;
}
void UAnimGraphNode_RetargetPoseFromMesh::CustomizePinData(UEdGraphPin* Pin, FName SourcePropertyName, int32 ArrayIndex) const
{
Super::CustomizePinData(Pin, SourcePropertyName, ArrayIndex);
if (Pin->PinName == GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_RetargetPoseFromMesh, SourceMeshComponent))
{
Pin->bHidden = Node.RetargetFrom != ERetargetSourceMode::CustomSkeletalMeshComponent;
}
if (Pin->PinName == GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_RetargetPoseFromMesh, Source))
{
const bool bCopyingFromOtherComponent = Node.RetargetFrom != ERetargetSourceMode::SourcePosePin;
Pin->bHidden = bCopyingFromOtherComponent;
Pin->bNotConnectable = bCopyingFromOtherComponent;
}
}
UObject* UAnimGraphNode_RetargetPoseFromMesh::GetJumpTargetForDoubleClick() const
{
return Node.IKRetargeterAsset;
}
void UAnimGraphNode_RetargetPoseFromMesh::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
const FName PropertyName = (PropertyChangedEvent.Property ? PropertyChangedEvent.Property->GetFName() : NAME_None);
if ((PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_RetargetPoseFromMesh, RetargetFrom)))
{
ReconstructNode();
}
}
void UAnimGraphNode_RetargetPoseFromMesh::ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog)
{
Super::ValidateAnimNodeDuringCompilation(ForSkeleton, MessageLog);
// validate source mesh component is not null
if (Node.RetargetFrom == ERetargetSourceMode::CustomSkeletalMeshComponent)
{
const bool bIsLinked = IsPinExposedAndLinked(GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_RetargetPoseFromMesh, SourceMeshComponent));
const bool bIsBound = IsPinExposedAndBound(GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_RetargetPoseFromMesh, SourceMeshComponent));
if (!(bIsLinked || bIsBound))
{
MessageLog.Error(TEXT("@@ requires a source Skeletal Mesh Component to be plugged in."), this);
return;
}
}
// validate IK Rig asset has been assigned
if (!Node.IKRetargeterAsset)
{
UEdGraphPin* Pin = FindPin(GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_RetargetPoseFromMesh, IKRetargeterAsset));
if (Pin == nullptr)
{
// retarget asset unassigned
MessageLog.Error(TEXT("@@ does not have an IK Retargeter asset assigned."), this);
}
return;
}
// validate SOURCE IK Rig asset has been assigned
const UIKRigDefinition* SourceIKRig = Node.IKRetargeterAsset->GetIKRig(ERetargetSourceOrTarget::Source);
if (!SourceIKRig)
{
MessageLog.Warning(TEXT("@@ has an IK Retargeter that is missing a source IK Rig asset."), this);
}
// validate TARGET IK Rig asset has been assigned
const UIKRigDefinition* TargetIKRig = Node.IKRetargeterAsset->GetIKRig(ERetargetSourceOrTarget::Target);
if (!TargetIKRig)
{
MessageLog.Warning(TEXT("@@ has an IK Retargeter that is missing a target IK Rig asset."), this);
}
if (!(SourceIKRig && TargetIKRig))
{
return;
}
// pull messages out of the processor's log
if (!Node.bSuppressWarnings)
{
if (const FIKRetargetProcessor* Processor = Node.GetRetargetProcessor())
{
const TArray<FText>& Warnings = Processor->Log.GetWarnings();
for (const FText& Warning : Warnings)
{
MessageLog.Warning(*Warning.ToString());
}
const TArray<FText>& Errors = Processor->Log.GetErrors();
for (const FText& Error : Errors)
{
MessageLog.Error(*Error.ToString());
}
}
}
if (ForSkeleton && !Node.bSuppressWarnings)
{
// validate that target bone chains exist on this skeleton
const FReferenceSkeleton &RefSkel = ForSkeleton->GetReferenceSkeleton();
const TArray<FBoneChain> &TargetBoneChains = TargetIKRig->GetRetargetChains();
for (const FBoneChain &Chain : TargetBoneChains)
{
if (RefSkel.FindBoneIndex(Chain.StartBone.BoneName) == INDEX_NONE)
{
MessageLog.Warning(*FText::Format(LOCTEXT("StartBoneNotFound", "@@ - Start Bone '{0}' in target IK Rig Bone Chain not found."), FText::FromName(Chain.StartBone.BoneName)).ToString(), this);
}
if (RefSkel.FindBoneIndex(Chain.EndBone.BoneName) == INDEX_NONE)
{
MessageLog.Warning(*FText::Format(LOCTEXT("EndBoneNotFound", "@@ - End Bone '{0}' in target IK Rig Bone Chain not found."), FText::FromName(Chain.EndBone.BoneName)).ToString(), this);
}
}
}
}
void UAnimGraphNode_RetargetPoseFromMesh::PreloadRequiredAssets()
{
Super::PreloadRequiredAssets();
if (Node.IKRetargeterAsset)
{
PreloadObject(Node.IKRetargeterAsset);
PreloadObject(Node.IKRetargeterAsset->GetIKRigWriteable(ERetargetSourceOrTarget::Source));
PreloadObject(Node.IKRetargeterAsset->GetIKRigWriteable(ERetargetSourceOrTarget::Target));
}
}
#undef LOCTEXT_NAMESPACE