【UE5】CPP中使用ControlRig蓝图节点示例
模板
需要.Build中添加编译要用到的模块
PrivateDependencyModuleNames.AddRange(new string[]
{
"ControlRig",
"RigVM",
"AnimationCore"
});

.h
#include "CoreMinimal.h"
#include "Units/Execution/RigUnit_DynamicHierarchy.h"
#include "ControlRig.h"
#include "Rigs/RigHierarchy.h"
#include "RigUnit_HybridAnim.generated.h"
#pragma region 初始化Array
//初始化Array
USTRUCT(meta = (DisplayName = "SetupArray"), Category = "ConstructionEvent")
struct HYBRIDANIM_API FRigUnit_SetupArray : public FRigUnit_DynamicHierarchyBaseMutable
{
GENERATED_BODY()
RIGVM_METHOD()
virtual void Execute() override;
UPROPERTY(meta=(Output))
TArray<FRigElementKey> FootArray;
};
#pragma endregion
.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ControlRigFunctions/RigUnit_HybridAnim.h"
#pragma region 初始化Array
//初始化Array
FRigUnit_SetupArray_Execute()
{
}
#pragma endregion
这种方式相当于建立一个controlrig的公开函数库,不需要controlrig蓝图继承

注意:
| 类型 | Execute 引脚 | 典型用途 |
|---|---|---|
| FRigUnit | ❌ 无 | 纯数学计算(Add、Multiply、Lerp、SpringInterpolate 等),结果仅依赖输入,无内部状态 |
| FRigUnitMutable | ✅ 有 | 需要缓存状态的操作(执行顺序敏感、有中间变量需要跨帧保留) |
| FRigUnit_DynamicHierarchyBaseMutable | ✅ 有 | 动态层级修改(添加/移除骨骼、修改层级结构),必须按序执行 |
ControlRig节点迁移到C++的基本流程

逻辑代码迁移到C++自定义ControlRig节点:
RigUnit_ProceduralCharacter.h
#pragma region 计算脚部的目标朝向
//计算脚部的目标朝向
USTRUCT(meta = (DisplayName = "GetFootTargetAngle"))
struct PROCEDURALANIM_API FRigUnit_GetFootTargetAngle : public FRigUnit
{
GENERATED_BODY()
RIGVM_METHOD()
virtual void Execute() override;
UPROPERTY(meta = (Input))
FVector RigSpaceVelocity;
UPROPERTY(meta = (Output))
float FootTargetZAngle;
};
FVector EulerFromQuat(const FQuat& Rotation, EEulerRotationOrder RotationOrder = EEulerRotationOrder::ZYX, bool bUseUEHandyness = false);
FQuat FromTwoVectors(const FVector& A, const FVector& B);
#pragma endregion
RigUnit_ProceduralCharacter.cpp
#pragma region 计算脚部的目标朝向
FRigUnit_GetFootTargetAngle_Execute()
{
const float OriginalZAngle = AnimationCore::EulerFromQuat(
FromTwoVectors(FVector(0,1,0),RigSpaceVelocity)
).Z;
if (OriginalZAngle > 100)
{
FootTargetZAngle = OriginalZAngle - 180;
}
else if (OriginalZAngle < -100)
{
FootTargetZAngle = OriginalZAngle + 180;
}
else
{
FootTargetZAngle = OriginalZAngle;
}
}
FQuat FromTwoVectors(const FVector& A, const FVector& B)
{
if (A.IsNearlyZero() || B.IsNearlyZero())
{
return FQuat::Identity;
}
return FRigVMMathLibrary::FindQuatBetweenVectors(A, B);
}
#pragma endregion

对于一些蓝图和实际C++API名字不一致的节点
搜DisplayName="蓝图节点名"找对应的C++API
比如:Interpolate节点
如何在节点中获取Transform
URigHierarchy* Hierarchy = ExecuteContext.Hierarchy;
if(!Hierarchy)
{
return;
}
FRigElementKey HeadRig = FRigElementKey(TEXT("head"), ERigElementType::Bone);
FTransform HeadTransform = Hierarchy->GetGlobalTransform(HeadRig);



浙公网安备 33010602011771号