Download

FVector output pin on a custom animation node

Hey everyone,

I’m trying to make a simple custom animation node that will return me the Vector position of a bone. I’m currently trying to add the output pin and I can’t find how to do it. I saw on a thread that I should do something similar to this (from this thread):



void UCustomGraphNodeClass::CreateOutputPins()
{
const UAnimationGraphSchema* Schema = GetDefault<UAnimationGraphSchema>();
CreatePin(EGPD_Output, Schema->PC_Struct, Text("Pose", FPoseLink::StaticStruct(), /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("Pose"));
}


The problem is that there is not StaticStruct() function in FVector. I’m pretty lost here.

A few other questions:

  • After I manage to add the output pin to the AnimGraphNode, how do I use it in the AnimNode?
  • What does CopyPinDefaultsToNodeData and CopyNodeDataToPreviewNode do? When are they called? How does GET_MEMBER_NAME_STRING_CHECKED and GetDefaultValue work?

I don’t think it’s really relevant, but here is my code in case anyone wants to see it.
[SPOILER]
AnimGraphNode_GetBoneLocation.h



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "AnimGraphNode_Base.h"
#include "AnimNode_GetBoneLocation.h"
#include "AnimGraphNode_GetBoneLocation.generated.h"

/**
 *
 */
UCLASS()
class SHOOTERGAME_API UAnimGraphNode_GetBoneLocation : public UAnimGraphNode_Base
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, Category = Settings)
    FAnimNode_GetBoneLocation Node;

public:

    UAnimGraphNode_GetBoneLocation(const FObjectInitializer& ObjectInitializer);

    // UEdGraphNode interface
    virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
    virtual FText GetTooltipText() const override;
    // End of UEdGraphNode interface

protected:
    // UAnimGraphNode_Base interface
    virtual void ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog) override;
    virtual FEditorModeID GetEditorMode() const override;
    virtual void CopyNodeDataToPreviewNode(FAnimNode_Base* InPreviewNode) override;
    virtual void CopyPinDefaultsToNodeData(UEdGraphPin* InPin) override;
    // End of UAnimGraphNode_Base interface


private:
    virtual void CreateOutputPins() override;

};


AnimGraphNode_GetBoneLocation.cpp



// Fill out your copyright notice in the Description page of Project Settings.

#include "AnimGraphNode_GetBoneLocation.h"
#include "AnimNodeEditModes.h"
#include "Kismet2/CompilerResultsLog.h"
#include "EdGraph/EdGraphNodeUtils.h"
#include "UObject/ObjectMacros.h"
#include "UnrealWidget.h"
#include "Classes/AnimationGraphSchema.h"

#define LOCTEXT_NAMESPACE "CustomAnimNodes"

UAnimGraphNode_GetBoneLocation::UAnimGraphNode_GetBoneLocation(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
}

FText UAnimGraphNode_GetBoneLocation::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
    if (TitleType == ENodeTitleType::MenuTitle && Node.Bone.BoneName != NAME_None)
    {
        FFormatNamedArguments args = FFormatNamedArguments();
        args.Add(TEXT("BoneName"), FText::FromName(Node.Bone.BoneName));
        return FText::Format(LOCTEXT("AnimGraphNode_GetBoneLocation_MenuTitle", "Get Bone Location ({BoneName})"), args);
    }
    else
    {
        return LOCTEXT("AnimGraphNode_GetBoneLocation_ListTitle", "Get Bone Location");
    }
}

FText UAnimGraphNode_GetBoneLocation::GetTooltipText() const
{
    return FText::FromString(TEXT("Get the location of a bone."));
}

void UAnimGraphNode_GetBoneLocation::ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog)
{
    if (Node.Bone.BoneName == NAME_None)
    {
        MessageLog.Warning(*LOCTEXT("AnimGraphNode_GetBoneLocation_NoBoneSelectedWarning", "@@ - No bone selected. Please select a bone to get its location.").ToString(), this);
    }
}

FEditorModeID UAnimGraphNode_GetBoneLocation::GetEditorMode() const
{
    return AnimNodeEditModes::ObserveBone;
}

void UAnimGraphNode_GetBoneLocation::CopyNodeDataToPreviewNode(FAnimNode_Base* InPreviewNode)
{
    FAnimNode_GetBoneLocation* inNode = static_cast<FAnimNode_GetBoneLocation*>(InPreviewNode);

    inNode->Bone = Node.Bone;
}

void UAnimGraphNode_GetBoneLocation::CopyPinDefaultsToNodeData(UEdGraphPin* InPin)
{
    /*
    if (InPin->GetName() == GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_GetBoneLocation, Bone))
    {
        GetDefaultValue(GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_GetBoneLocation, Bone), Node.Bone);
    }
    */
}

void UAnimGraphNode_GetBoneLocation::CreateOutputPins()
{
    const UAnimationGraphSchema* Schema = GetDefault<UAnimationGraphSchema>();

    FCreatePinParams pinParams = FCreatePinParams();
    pinParams.bIsConst = false;
    pinParams.bIsReference = false;

    //What do I do here?
    CreatePin(EGPD_Output, Schema->PC_Struct, TEXT("Bone Location"), pinParams);
}

#undef LOCTEXT_NAMESPACE


AnimNode_GetBoneLocation.h



#pragma once

#include "Core.h"
#include "Engine.h"
#include "Engine/Classes/Animation/AnimNodeBase.h"
#include "AnimNode_GetBoneLocation.generated.h"

USTRUCT(BlueprintInternalUseOnly)
struct SHOOTERGAME_API FAnimNode_GetBoneLocation : public FAnimNode_Base
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links)
    FPoseLink LocalPose;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = InputPins)
    FVector Location;

    UPROPERTY(EditAnywhere, Category = Settings, meta = (PinHiddenByDefault))
    FBoneReference Bone;

    // FAnimNode_Base interface
    virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
    virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
    virtual void Evaluate_AnyThread(FPoseContext& Output) override;
    // End of FAnimNode_Base interface


};



AnimNode_GetBoneLocation.cpp



#include "AnimNode_GetBoneLocation.h"

void FAnimNode_GetBoneLocation::Initialize_AnyThread(const FAnimationInitializeContext& Context)
{
}

void FAnimNode_GetBoneLocation::Update_AnyThread(const FAnimationUpdateContext& Context)
{

}

void FAnimNode_GetBoneLocation::Evaluate_AnyThread(FPoseContext& Output)
{

}



[/SPOILER]

If anyone has any other relevant information or tips on this I’d greatly appreciate it. I’m slowly trying to get this to work, but I haven’t wrapped my head around this quite yet.

TBaseStructure<FVector>::Get() should work as the replacement for FVector::StaticStruct().

Thank you very much! The output pin now shows up.

So, did you manage to get your outputs?
I have exposed mine, setted its value and the editor even see its value, but as soon as it reaches the next node its value is reseted