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

Hello, How to assign Node data to the output pin?