Custom output pins in UE5

Context: I used Livelink for Blender plugin to send data frame-by-frame from Blender to UE5. The node BlenderUnreal Livelink appears in AnimGraph as below

Problem statement: I want to custom this node so that it produces 4 output pins. In the code, the struct FRGBRokokoAnimNode (RGBRokokoAnimNode.h) and the class UFRGBRokokoAnimGraphNode (FRGBRokokoAnimGraphNode.h) are, I guess, mainly responsible for the node interface in the AnimGraph, with the former reading & processing data from Blender.

This is the struct declaration

USTRUCT()
struct RGBPOSELIVELINK_API FRGBRokokoAnimNode : public FAnimNode_SkeletalControlBase
{
GENERATED_USTRUCT_BODY()

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = RGBSkeletalControl, meta = (PinShownByDefault))
FName RGBMocapActorName;

UPROPERTY(EditAnywhere, Category = RGBSkeletalControl)
URGBRokokoBoneMap* BoneMapOverride;

//For bone rotations
TMap<FName, float> LiveLinkCurvesCpp;

float ScaleFactor;

FVector NormalizedForward;
FVector GetVectorFromCurvesCpp(const FString BoneName);
FVector CalculateNormalCpp(const FVector A, const FVector B, const FVector C);

float CalculateHeightCpp();

FTransform GetTransformFromCurvesCpp(const FString BoneName);

float CalculateScaleFactorCpp(float ManequinHeight, float HeightFromSolver);

void TranslationMethodCpp();

void RotationMethodCpp(TMap<FName, FTransform>& sourceBoneFinalTransforms);
FTransform CalcTransformForRotation(const FString FirstBone, const FString SecondBone, const bool useXZ = false, const bool invertForward = false);

TArray BoneReferencesArray;
bool firstTime;
TArray CopyOfOutBoneTransforms;

//Bone References;
FBoneReference rShldrBend;
FBoneReference rForearmBend;
FBoneReference rHand;
FBoneReference lShldrBend;
FBoneReference lForearmBend;
FBoneReference lHand;
FBoneReference rThighBend;
FBoneReference rShin;
FBoneReference rFoot;
FBoneReference lThighBend;
FBoneReference lShin;
FBoneReference lFoot;
FBoneReference abdomenUpper;
FBoneReference hip;
FBoneReference head;
FBoneReference neck;
FBoneReference spine;

void ApplyBoneRotation(TMap<FName, FTransform> sourceBoneFinalTransforms , FName boneName, FBoneReference boneReference, FCSPose& MeshBases);
void ApplyBonePosition(TMap<FName, FTransform> sourceBoneFinalTransforms , FName boneName, FBoneReference boneReference, FCSPose& MeshBases);
public:

// Constructor
FRGBRokokoAnimNode();

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = “foot contact”, meta = (PinShownByDefault))
float footContact;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = “Test”, meta = (PinShownByDefault))
UTestAnimNode* TestPtr;

// FAnimNode_Base interface
// Display Debug Information
virtual void GatherDebugData(FNodeDebugData& DebugData) override;

// FAnimNode_SkeletalControlBase interface
// Change the position of the logic functions to achieve
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray& OutBoneTransforms) override;
// used to determine the effectiveness of bone
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;

virtual bool HasPreUpdate() const { return true; }
virtual void PreUpdate(const UAnimInstance* InAnimInstance) override;

FLiveLinkSubjectName GetLiveLinkSubjectName();
private:
// FAnimNode_SkeletalControlBase interface
// Initialize the bones references
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
// End of FAnimNode_SkeletalControlBase interface

FLiveLinkClientReference LiveLinkClient_GameThread;
ILiveLinkClient* LiveLinkClient_AnyThread;
};

This is the class declaration

UCLASS()
class RGBPOSELIVELINK_API UFRGBRokokoAnimGraphNode : public UAnimGraphNode_SkeletalControlBase
{
GENERATED_UCLASS_BODY()

//GT
UPROPERTY(EditAnywhere, Category = Settings)
FRGBRokokoAnimNode Node;
//TEST
//UPROPERTY(EditAnywhere, Category = Settings)
// UTestAnimNode* Node;

// UEdGraphNode interface
// mouse over Node prompt text
virtual FText GetTooltipText() const override;
// Node name text
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
// End of UEdGraphNode interface

protected:
// UAnimGraphNode_SkeletalControlBase interface
// returns the controller description
virtual FText GetControllerDescription() const override;

// returns AnimNode cited
// GT
virtual const FAnimNode_SkeletalControlBase* GetNode() const override {
return &Node;
}
// TEST
//virtual const FAnimNode_SkeletalControlBase* GetNode() const override { return &Node; }
};

Solution experiments: I attempted to create 1 output pin first and later broadcast to 4 output pins

  1. As I understand, to create a custom output pin, UFUNCTION() is needed but it can’t be declared under USTRUCT() scope and therefore not suitable to put it in the FRGBRokokoAnimNode struct, I tried to put it in the class UFRGBRokokoAnimGraphNode but after I compiled successfully, the output pin is still invisible in the node

  2. Intermidiate class: I created an intermidiate class to be able to use UFUNCTION(), this class is later included in the struct and class mentioned as a pointer type so that I can call to the UFUNCTION(). But the result is the input pin TestPtr in the image above instead of the output pin.

Set up (in both Blender and UE5): To install and experiment with the plugin, please see the instructions here

I have read other similar questions but found no solutions (I’m a beginner and can miss out some important things :frowning_face:). Thanks for your time.

1 Like