Use blueprint retarget pose graph
This commit is contained in:
@@ -4,7 +4,7 @@ DefaultAIClassTag=(TagName="Class.Saber")
|
||||
bApplyPlayerClassMeshToPlayers=True
|
||||
bApplyPlayerClassMeshToAI=False
|
||||
!PlayerClassMeshes=ClearArray
|
||||
+PlayerClassMeshes=(ClassTag=(TagName="Class.Saber"),PlayerMesh="/Game/AGame/Character/Ida/SK_MMO_ADVANCED_F_01_AGame.SK_MMO_ADVANCED_F_01_AGame",PlayerRetargeter="/Game/AGame/Animation/Retargeters/RTG_Manny_To_Ida.RTG_Manny_To_Ida")
|
||||
+PlayerClassMeshes=(ClassTag=(TagName="Class.Saber"),PlayerMesh="/Game/AGame/Character/Ida/SK_MMO_ADVANCED_F_01_AGame.SK_MMO_ADVANCED_F_01_AGame",PlayerDisplayAnimClass="/Game/AGame/Animation/Retargeters/ABP_Retargeter.ABP_Retargeter_C",PlayerRetargeter="/Game/AGame/Animation/Retargeters/RTG_Manny_To_Ida.RTG_Manny_To_Ida")
|
||||
+PlayerClassMeshes=(ClassTag=(TagName="Class.Lancer"),PlayerMesh=None,PlayerRetargeter=)
|
||||
+PlayerClassMeshes=(ClassTag=(TagName="Class.Archer"),PlayerMesh=None,PlayerRetargeter=)
|
||||
+PlayerClassMeshes=(ClassTag=(TagName="Class.Rider"),PlayerMesh=None,PlayerRetargeter=)
|
||||
|
||||
Binary file not shown.
@@ -252,7 +252,10 @@ TSubclassOf<UAnimInstance> UPHYCharacterMeshBridgeComponent::ResolveRetargetDisp
|
||||
|
||||
if (UClass* CurrentAnimClass = DisplayMeshComponent->GetAnimClass())
|
||||
{
|
||||
return CurrentAnimClass;
|
||||
if (CurrentAnimClass != UPHYRetargetPoseAnimInstance::StaticClass())
|
||||
{
|
||||
return CurrentAnimClass;
|
||||
}
|
||||
}
|
||||
|
||||
const UPHYAnimationSettings* Settings = GetDefault<UPHYAnimationSettings>();
|
||||
|
||||
@@ -7,84 +7,7 @@
|
||||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "Retargeter/IKRetargeter.h"
|
||||
|
||||
FPHYRetargetPoseAnimInstanceProxy::FPHYRetargetPoseAnimInstanceProxy(UAnimInstance* InAnimInstance, FAnimNode_RetargetPoseFromMesh* InRetargetNode)
|
||||
: FAnimInstanceProxy(InAnimInstance)
|
||||
, RetargetNode(InRetargetNode)
|
||||
{
|
||||
}
|
||||
|
||||
void FPHYRetargetPoseAnimInstanceProxy::Initialize(UAnimInstance* InAnimInstance)
|
||||
{
|
||||
FAnimInstanceProxy::Initialize(InAnimInstance);
|
||||
|
||||
if (RetargetNode)
|
||||
{
|
||||
FAnimationInitializeContext InitContext(this);
|
||||
RetargetNode->Initialize_AnyThread(InitContext);
|
||||
}
|
||||
}
|
||||
|
||||
void FPHYRetargetPoseAnimInstanceProxy::PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds)
|
||||
{
|
||||
FAnimInstanceProxy::PreUpdate(InAnimInstance, DeltaSeconds);
|
||||
|
||||
if (RetargetNode && RetargetNode->HasPreUpdate())
|
||||
{
|
||||
RetargetNode->PreUpdate(InAnimInstance);
|
||||
}
|
||||
}
|
||||
|
||||
void FPHYRetargetPoseAnimInstanceProxy::CacheBones()
|
||||
{
|
||||
if (bBoneCachesInvalidated && RetargetNode)
|
||||
{
|
||||
FAnimationCacheBonesContext Context(this);
|
||||
RetargetNode->CacheBones_AnyThread(Context);
|
||||
bBoneCachesInvalidated = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FPHYRetargetPoseAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
||||
{
|
||||
if (!RetargetNode)
|
||||
{
|
||||
Output.ResetToRefPose();
|
||||
return true;
|
||||
}
|
||||
|
||||
RetargetNode->Evaluate_AnyThread(Output);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FPHYRetargetPoseAnimInstanceProxy::UpdateAnimationNode(const FAnimationUpdateContext& InContext)
|
||||
{
|
||||
UpdateCounter.Increment();
|
||||
|
||||
if (RetargetNode)
|
||||
{
|
||||
RetargetNode->Update_AnyThread(InContext);
|
||||
}
|
||||
}
|
||||
|
||||
void FPHYRetargetPoseAnimInstanceProxy::ConfigureRetargetPose(UIKRetargeter* InRetargeter, USkeletalMeshComponent* InSourceMeshComponent)
|
||||
{
|
||||
if (!RetargetNode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RetargetNode->IKRetargeterAsset = InRetargeter;
|
||||
RetargetNode->RetargetFrom = ERetargetSourceMode::CustomSkeletalMeshComponent;
|
||||
RetargetNode->SourceMeshComponent = InSourceMeshComponent;
|
||||
RetargetNode->bSuppressWarnings = false;
|
||||
|
||||
if (FIKRetargetProcessor* Processor = RetargetNode->GetRetargetProcessor())
|
||||
{
|
||||
Processor->SetNeedsInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
bool UPHYRetargetPoseAnimInstance::ConfigureRetargetPoseFromMesh(USkeletalMeshComponent* InSourceMeshComponent, FSoftObjectPath InRetargeterPath)
|
||||
bool UPHYRetargetPoseAnimInstance::ConfigureRetargetPoseFromMesh(USkeletalMeshComponent* InSourceMeshComponent, const FSoftObjectPath InRetargeterPath)
|
||||
{
|
||||
RetargetSourceMeshComponent = InSourceMeshComponent;
|
||||
RetargeterPath = InRetargeterPath;
|
||||
@@ -110,21 +33,6 @@ bool UPHYRetargetPoseAnimInstance::ConfigureRetargetPoseFromMesh(USkeletalMeshCo
|
||||
return false;
|
||||
}
|
||||
|
||||
FPHYRetargetPoseAnimInstanceProxy& Proxy = GetProxyOnGameThread<FPHYRetargetPoseAnimInstanceProxy>();
|
||||
Proxy.ConfigureRetargetPose(LoadedRetargeter, RetargetSourceMeshComponent);
|
||||
// AnimGraph 中的 Retarget Pose From Mesh 节点通过属性绑定读取 LoadedRetargeter。
|
||||
return true;
|
||||
}
|
||||
|
||||
void UPHYRetargetPoseAnimInstance::NativeInitializeAnimation()
|
||||
{
|
||||
Super::NativeInitializeAnimation();
|
||||
|
||||
FPHYRetargetPoseAnimInstanceProxy& Proxy = GetProxyOnGameThread<FPHYRetargetPoseAnimInstanceProxy>();
|
||||
Proxy.Initialize(this);
|
||||
Proxy.ConfigureRetargetPose(LoadedRetargeter, RetargetSourceMeshComponent);
|
||||
}
|
||||
|
||||
FAnimInstanceProxy* UPHYRetargetPoseAnimInstance::CreateAnimInstanceProxy()
|
||||
{
|
||||
return new FPHYRetargetPoseAnimInstanceProxy(this, &RetargetNode);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYClassComponent)
|
||||
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "Animation/AnimInstance.h"
|
||||
#include "AbilitySystem/Attributes/PHYAttributeCalculationLibrary.h"
|
||||
#include "AbilitySystem/Attributes/PHYCombatAttributeSet.h"
|
||||
#include "AbilitySystem/Attributes/PHYCoreAttributeSet.h"
|
||||
@@ -92,6 +93,25 @@ USkeletalMesh* UPHYClassComponent::GetConfiguredPlayerMesh() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TSubclassOf<UAnimInstance> UPHYClassComponent::GetConfiguredPlayerDisplayAnimClass() const
|
||||
{
|
||||
const UPHYClassSettings* ClassSettings = GetDefault<UPHYClassSettings>();
|
||||
if (!ClassSettings || !CurrentClassTag.IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (const FPHYPlayerClassMeshConfig& MeshConfig : ClassSettings->PlayerClassMeshes)
|
||||
{
|
||||
if (MeshConfig.ClassTag == CurrentClassTag)
|
||||
{
|
||||
return MeshConfig.PlayerDisplayAnimClass.LoadSynchronous();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FSoftObjectPath UPHYClassComponent::GetConfiguredPlayerRetargeter() const
|
||||
{
|
||||
const UPHYClassSettings* ClassSettings = GetDefault<UPHYClassSettings>();
|
||||
@@ -139,7 +159,7 @@ bool UPHYClassComponent::ApplyConfiguredPlayerMeshIfAllowed(AActor* AvatarActor)
|
||||
}
|
||||
|
||||
MeshBridge->InitializeMeshBridge(Character, Character->GetDisplayMeshComponent());
|
||||
return MeshBridge->ApplyDisplayMesh(PlayerMesh, nullptr, PlayerRetargeter);
|
||||
return MeshBridge->ApplyDisplayMesh(PlayerMesh, GetConfiguredPlayerDisplayAnimClass(), PlayerRetargeter);
|
||||
}
|
||||
|
||||
bool UPHYClassComponent::ApplyClassAttributesToAbilitySystem(UAbilitySystemComponent* AbilitySystemComponent) const
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Animation/AnimInstance.h"
|
||||
#include "Animation/AnimInstanceProxy.h"
|
||||
#include "AnimNodes/AnimNode_RetargetPoseFromMesh.h"
|
||||
#include "UObject/SoftObjectPath.h"
|
||||
#include "PHYRetargetPoseAnimInstance.generated.h"
|
||||
|
||||
@@ -12,46 +10,19 @@ class UIKRetargeter;
|
||||
class USkeletalMeshComponent;
|
||||
|
||||
/**
|
||||
* @brief 显示层 Retarget Pose From Mesh 动画实例代理。
|
||||
* @brief PHY 显示层 Retarget 动画实例基类。
|
||||
*
|
||||
* 代理直接驱动 UE IKRig 的 FAnimNode_RetargetPoseFromMesh,用于把 SourceMesh 的运动姿态重定向到显示层 Mesh。
|
||||
* 该类只保存 SourceMesh 和 IK Retargeter 运行时参数,不再由 C++ 自动执行 AnimGraph 节点;
|
||||
* 具体的 Retarget Pose From Mesh 节点必须在派生 AnimBlueprint 中显式连接。
|
||||
*/
|
||||
USTRUCT()
|
||||
struct PHY_API FPHYRetargetPoseAnimInstanceProxy : public FAnimInstanceProxy
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
friend class UPHYRetargetPoseAnimInstance;
|
||||
|
||||
FPHYRetargetPoseAnimInstanceProxy() = default;
|
||||
FPHYRetargetPoseAnimInstanceProxy(UAnimInstance* InAnimInstance, FAnimNode_RetargetPoseFromMesh* InRetargetNode);
|
||||
protected:
|
||||
virtual void Initialize(UAnimInstance* InAnimInstance) override;
|
||||
virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds) override;
|
||||
virtual void CacheBones() override;
|
||||
virtual bool Evaluate(FPoseContext& Output) override;
|
||||
virtual void UpdateAnimationNode(const FAnimationUpdateContext& InContext) override;
|
||||
|
||||
/** @brief 配置 Retarget 节点使用的源 Mesh 与 IK Retargeter。 */
|
||||
void ConfigureRetargetPose(UIKRetargeter* InRetargeter, USkeletalMeshComponent* InSourceMeshComponent);
|
||||
|
||||
private:
|
||||
FAnimNode_RetargetPoseFromMesh* RetargetNode = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief PHY 显示层原生 Retarget Pose 动画实例。
|
||||
*
|
||||
* MeshBridge 在异骨架显示层路径中使用该类,把 ACharacter::GetMesh() 的运动姿态通过 IK Retargeter 输出到 DisplayMesh。
|
||||
*/
|
||||
UCLASS(Transient, BlueprintType)
|
||||
UCLASS(Transient, BlueprintType, Blueprintable)
|
||||
class PHY_API UPHYRetargetPoseAnimInstance : public UAnimInstance
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief 设置 Retarget Pose From Mesh 的运行时输入。
|
||||
* @brief 设置 Retarget AnimBlueprint 读取的运行时输入。
|
||||
* @param InSourceMeshComponent 提供运动姿态的源 Mesh 组件。
|
||||
* @param InRetargeterPath IK Retargeter 资产软路径。
|
||||
* @return SourceMesh 与 Retargeter 均有效时返回 true。
|
||||
@@ -63,29 +34,24 @@ public:
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Animation")
|
||||
USkeletalMeshComponent* GetRetargetSourceMeshComponent() const { return RetargetSourceMeshComponent; }
|
||||
|
||||
/** @brief 获取当前已加载的 IK Retargeter 资产,供 AnimBlueprint 节点绑定。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Animation")
|
||||
UIKRetargeter* GetLoadedRetargeter() const { return LoadedRetargeter; }
|
||||
|
||||
/** @brief 获取当前 IK Retargeter 资产路径。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Animation")
|
||||
FSoftObjectPath GetRetargeterPath() const { return RetargeterPath; }
|
||||
|
||||
|
||||
virtual void NativeInitializeAnimation() override;
|
||||
protected:
|
||||
virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override;
|
||||
|
||||
private:
|
||||
/** @brief Retarget Pose From Mesh 运行时节点。 */
|
||||
UPROPERTY()
|
||||
FAnimNode_RetargetPoseFromMesh RetargetNode;
|
||||
|
||||
/** @brief 当前用于重定向的源 Mesh 组件。 */
|
||||
UPROPERTY(Transient)
|
||||
UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Animation")
|
||||
TObjectPtr<USkeletalMeshComponent> RetargetSourceMeshComponent;
|
||||
|
||||
/** @brief 当前使用的 IK Retargeter 资产。 */
|
||||
UPROPERTY(Transient)
|
||||
/** @brief 当前使用的 IK Retargeter 资产,AnimBlueprint 的节点应绑定到该属性或 Getter。 */
|
||||
UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Animation")
|
||||
TObjectPtr<UIKRetargeter> LoadedRetargeter;
|
||||
|
||||
/** @brief 当前 IK Retargeter 资产软路径。 */
|
||||
UPROPERTY(Transient)
|
||||
UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Animation")
|
||||
FSoftObjectPath RetargeterPath;
|
||||
};
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#include "UObject/SoftObjectPath.h"
|
||||
#include "PHYClassComponent.generated.h"
|
||||
|
||||
class USkeletalMesh;
|
||||
class UAbilitySystemComponent;
|
||||
class UAnimInstance;
|
||||
class USkeletalMesh;
|
||||
|
||||
/**
|
||||
* @brief PHY 职业组件。
|
||||
@@ -44,6 +45,10 @@ public:
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Class")
|
||||
USkeletalMesh* GetConfiguredPlayerMesh() const;
|
||||
|
||||
/** @brief 按当前职业读取配置的显示层 AnimClass,未配置时返回空并交给动画默认配置。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Class")
|
||||
TSubclassOf<UAnimInstance> GetConfiguredPlayerDisplayAnimClass() const;
|
||||
|
||||
/** @brief 按当前职业读取配置的玩家 IK Retargeter 软路径,未配置时返回空路径。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Class")
|
||||
FSoftObjectPath GetConfiguredPlayerRetargeter() const;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "UObject/SoftObjectPtr.h"
|
||||
#include "PHYClassSettings.generated.h"
|
||||
|
||||
class UAnimInstance;
|
||||
class USkeletalMesh;
|
||||
|
||||
/**
|
||||
@@ -74,6 +75,10 @@ public:
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Class")
|
||||
TSoftObjectPtr<USkeletalMesh> PlayerMesh;
|
||||
|
||||
/** @brief 玩家使用该职业时优先使用的显示层 AnimClass,留空时回退动画默认配置。 */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Class")
|
||||
TSoftClassPtr<UAnimInstance> PlayerDisplayAnimClass;
|
||||
|
||||
/** @brief 玩家使用该职业时优先使用的 IK Retargeter 软路径,留空时回退动画默认配置。 */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Class")
|
||||
FSoftObjectPath PlayerRetargeter;
|
||||
|
||||
Reference in New Issue
Block a user