Removed files
This commit is contained in:
parent
27ce0e7c26
commit
b7c20351c8
@ -1,161 +0,0 @@
|
|||||||
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
|
||||||
|
|
||||||
|
|
||||||
#include "Data/OLSMaskAnimationData.h"
|
|
||||||
|
|
||||||
void FOLSMaskAnimation::CacheAdditiveCurves()
|
|
||||||
{
|
|
||||||
#if WITH_EDITOR
|
|
||||||
if (!Animation)
|
|
||||||
{
|
|
||||||
CurvesToModify.Reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MaskPoseTime = FMath::Clamp(MaskPoseTime, 0.f, Animation->GetPlayLength());
|
|
||||||
|
|
||||||
//Set values for Arms Spaces To 0 Before Filling them from the Weights.
|
|
||||||
MaskingWeights.RightArmWeights.ArmLocalSpaceBlend = 0.f;
|
|
||||||
MaskingWeights.RightArmWeights.ArmMeshSpaceBlend = 0.f;
|
|
||||||
MaskingWeights.LeftArmWeights.ArmLocalSpaceBlend = 0.f;
|
|
||||||
MaskingWeights.LeftArmWeights.ArmMeshSpaceBlend = 0.f;
|
|
||||||
|
|
||||||
//Fill arm spaces values with weights
|
|
||||||
if (MaskingWeights.RightArmWeights.ArmAdditiveMode == EOLSAdditiveMode::ELocalSpace)
|
|
||||||
{
|
|
||||||
MaskingWeights.RightArmWeights.ArmLocalSpaceBlend = 1.f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MaskingWeights.RightArmWeights.ArmMeshSpaceBlend = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MaskingWeights.LeftArmWeights.ArmAdditiveMode == EOLSAdditiveMode::ELocalSpace)
|
|
||||||
{
|
|
||||||
MaskingWeights.LeftArmWeights.ArmLocalSpaceBlend = 1.f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MaskingWeights.LeftArmWeights.ArmMeshSpaceBlend = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurvesToModify.Reset();
|
|
||||||
|
|
||||||
// Legs
|
|
||||||
CurvesToModify.Add(MaskLegsMeshSpaceCurveName, 1);
|
|
||||||
CurvesToModify.Add(MaskLegsLocalSpaceCurveName, 0);
|
|
||||||
CurvesToModify.Add(MaskLegsCurveName, MaskingWeights.LegsWeights.MaskWeight);
|
|
||||||
CurvesToModify.Add(MaskLegsAddCurveName, MaskingWeights.LegsWeights.MaskAdditive);
|
|
||||||
Weights.LegsWeights.OverrideAlpha = MaskingWeights.LegsWeights.MaskWeight;
|
|
||||||
Weights.LegsWeights.AdditiveAlpha = MaskingWeights.LegsWeights.MaskAdditive;
|
|
||||||
|
|
||||||
// Pelvis
|
|
||||||
CurvesToModify.Add(MaskPelvisMeshSpaceCurveName, 1);
|
|
||||||
CurvesToModify.Add(MaskPelvisLocalSpaceCurveName, 0);
|
|
||||||
CurvesToModify.Add(MaskPelvisCurveName, MaskingWeights.PelvisWeights.MaskWeight);
|
|
||||||
CurvesToModify.Add(MaskPelvisAddCurveName, MaskingWeights.PelvisWeights.MaskAdditive);
|
|
||||||
Weights.PelvisWeights.OverrideAlpha = MaskingWeights.PelvisWeights.MaskWeight;
|
|
||||||
Weights.PelvisWeights.AdditiveAlpha = MaskingWeights.PelvisWeights.MaskAdditive;
|
|
||||||
|
|
||||||
// Spine
|
|
||||||
CurvesToModify.Add(MaskSpineMeshSpaceCurveName, 1);
|
|
||||||
CurvesToModify.Add(MaskSpineLocalSpaceCurveName, 0);
|
|
||||||
CurvesToModify.Add(MaskSpineCurveName, MaskingWeights.SpineWeights.MaskWeight);
|
|
||||||
CurvesToModify.Add(MaskSpineAddCurveName, MaskingWeights.SpineWeights.MaskAdditive);
|
|
||||||
Weights.SpineWeights.OverrideAlpha = MaskingWeights.SpineWeights.MaskWeight;
|
|
||||||
Weights.SpineWeights.AdditiveAlpha = MaskingWeights.SpineWeights.MaskAdditive;
|
|
||||||
|
|
||||||
// Head
|
|
||||||
CurvesToModify.Add(MaskHeadMeshSpaceCurveName, 1);
|
|
||||||
CurvesToModify.Add(MaskHeadLocalSpaceCurveName, 0);
|
|
||||||
CurvesToModify.Add(MaskHeadCurveName, MaskingWeights.HeadWeights.MaskWeight);
|
|
||||||
CurvesToModify.Add(MaskHeadAddCurveName, MaskingWeights.HeadWeights.MaskAdditive);
|
|
||||||
Weights.HeadWeights.OverrideAlpha = MaskingWeights.HeadWeights.MaskWeight;
|
|
||||||
Weights.HeadWeights.AdditiveAlpha = MaskingWeights.HeadWeights.MaskAdditive;
|
|
||||||
|
|
||||||
// Right Arm
|
|
||||||
CurvesToModify.Add(MaskRightArmCurveName, MaskingWeights.RightArmWeights.MaskWeights.MaskWeight);
|
|
||||||
CurvesToModify.Add(RightArmMeshSpaceCurveName, MaskingWeights.RightArmWeights.ArmMeshSpaceBlend);
|
|
||||||
CurvesToModify.Add(RightArmLocalSpaceCurveName, MaskingWeights.RightArmWeights.ArmLocalSpaceBlend);
|
|
||||||
CurvesToModify.Add(MaskRightArmAddCurveName, MaskingWeights.RightArmWeights.MaskWeights.MaskAdditive);
|
|
||||||
Weights.RightArmWeights.OverrideAlpha = MaskingWeights.RightArmWeights.MaskWeights.MaskWeight;
|
|
||||||
Weights.RightArmWeights.AdditiveAlpha = MaskingWeights.RightArmWeights.MaskWeights.MaskAdditive;
|
|
||||||
Weights.RightArmWeights.LocalSpaceBlendAlpha = MaskingWeights.RightArmWeights.ArmLocalSpaceBlend;
|
|
||||||
Weights.RightArmWeights.MeshSpaceBlendAlpha = MaskingWeights.RightArmWeights.ArmMeshSpaceBlend;
|
|
||||||
|
|
||||||
// Left Arm
|
|
||||||
CurvesToModify.Add(LeftArmMeshSpaceCurveName, MaskingWeights.LeftArmWeights.ArmMeshSpaceBlend);
|
|
||||||
CurvesToModify.Add(LeftArmLocalSpaceCurveName, MaskingWeights.LeftArmWeights.ArmLocalSpaceBlend);
|
|
||||||
CurvesToModify.Add(MaskLeftArmCurveName, MaskingWeights.LeftArmWeights.MaskWeights.MaskWeight);
|
|
||||||
CurvesToModify.Add(MaskLeftArmAddCurveName, MaskingWeights.LeftArmWeights.MaskWeights.MaskAdditive);
|
|
||||||
Weights.LeftArmWeights.OverrideAlpha = MaskingWeights.LeftArmWeights.MaskWeights.MaskWeight;
|
|
||||||
Weights.LeftArmWeights.AdditiveAlpha = MaskingWeights.LeftArmWeights.MaskWeights.MaskAdditive;
|
|
||||||
Weights.LeftArmWeights.LocalSpaceBlendAlpha = MaskingWeights.LeftArmWeights.ArmLocalSpaceBlend;
|
|
||||||
Weights.LeftArmWeights.MeshSpaceBlendAlpha = MaskingWeights.LeftArmWeights.ArmMeshSpaceBlend;
|
|
||||||
|
|
||||||
// Right Hand
|
|
||||||
CurvesToModify.Add(RightHandMeshSpaceCurveName, 0);
|
|
||||||
CurvesToModify.Add(RightHandLocalSpaceCurveName, 1);
|
|
||||||
CurvesToModify.Add(RightHandCurveName, MaskingWeights.RightHandWeights.MaskWeight);
|
|
||||||
CurvesToModify.Add(MaskRightHandAddCurveName, MaskingWeights.RightHandWeights.MaskAdditive);
|
|
||||||
Weights.RightHandWeights.OverrideAlpha = MaskingWeights.RightHandWeights.MaskWeight;
|
|
||||||
Weights.RightHandWeights.AdditiveAlpha = MaskingWeights.RightHandWeights.MaskAdditive;
|
|
||||||
Weights.RightHandWeights.LocalSpaceBlendAlpha = 1.f;
|
|
||||||
Weights.RightHandWeights.MeshSpaceBlendAlpha = 0.f;
|
|
||||||
|
|
||||||
// Left Hand
|
|
||||||
CurvesToModify.Add(LeftHandMeshSpaceCurveName, 0);
|
|
||||||
CurvesToModify.Add(LeftHandLocalSpaceCurveName, 1);
|
|
||||||
CurvesToModify.Add(LeftHandCurveName, MaskingWeights.LeftHandWeights.MaskWeight);
|
|
||||||
CurvesToModify.Add(MaskLeftHandAddCurveName, MaskingWeights.LeftHandWeights.MaskAdditive);
|
|
||||||
Weights.LeftHandWeights.OverrideAlpha = MaskingWeights.LeftHandWeights.MaskWeight;
|
|
||||||
Weights.LeftHandWeights.AdditiveAlpha = MaskingWeights.LeftHandWeights.MaskAdditive;
|
|
||||||
Weights.LeftHandWeights.LocalSpaceBlendAlpha = 1.f;
|
|
||||||
Weights.LeftHandWeights.MeshSpaceBlendAlpha = 0.f;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void FOLSGaitMasks::CacheAdditiveCurves()
|
|
||||||
{
|
|
||||||
#if WITH_EDITOR
|
|
||||||
ForwardMask.CacheAdditiveCurves();
|
|
||||||
RightMask.CacheAdditiveCurves();
|
|
||||||
LeftMask.CacheAdditiveCurves();
|
|
||||||
BackwardMask.CacheAdditiveCurves();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void FOLSStanceMaskSets::CacheAdditiveCurves()
|
|
||||||
{
|
|
||||||
#if WITH_EDITOR
|
|
||||||
for (TPair<FGameplayTag, FOLSGaitMasks>& pair : GaitMasks)
|
|
||||||
{
|
|
||||||
pair.Value.CacheAdditiveCurves();
|
|
||||||
}
|
|
||||||
|
|
||||||
IdleMask.CacheAdditiveCurves();
|
|
||||||
AimMask.CacheAdditiveCurves();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
const FOLSGaitMasks* FOLSStanceMaskSets::SelectGaitMasksByGait(const FGameplayTag& gait)
|
|
||||||
{
|
|
||||||
return GaitMasks.Find(gait);
|
|
||||||
}
|
|
||||||
|
|
||||||
const FOLSMaskAnimation& FOLSStanceMaskSets::GetIdleMask() const
|
|
||||||
{
|
|
||||||
return IdleMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FOLSMaskAnimation& FOLSStanceMaskSets::GetAimMask() const
|
|
||||||
{
|
|
||||||
return AimMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FOLSStanceMaskSets::GetAimBlendInOut(float& outBlendIn, float& outBlendOut) const
|
|
||||||
{
|
|
||||||
outBlendIn = AimBlendInTime;
|
|
||||||
outBlendOut = AimBlendOutTime;
|
|
||||||
}
|
|
@ -1,495 +0,0 @@
|
|||||||
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
|
||||||
|
|
||||||
|
|
||||||
#include "Nodes/AnimNode_OLSMask.h"
|
|
||||||
|
|
||||||
#include "Animation/AnimInstanceProxy.h"
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::Initialize_AnyThread(const FAnimationInitializeContext& context)
|
|
||||||
{
|
|
||||||
// Don't call SUPER since it's empty.
|
|
||||||
|
|
||||||
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Initialize_AnyThread)
|
|
||||||
FAnimNode_Base::Initialize_AnyThread(context);
|
|
||||||
|
|
||||||
AnimationPose.Initialize(context);
|
|
||||||
MaskPose.Initialize(context);
|
|
||||||
BaseAdditivePose.Initialize(context);
|
|
||||||
|
|
||||||
|
|
||||||
for (int32 index = 0; index < BlendMasks.Num(); ++index)
|
|
||||||
{
|
|
||||||
if (BlendMasks[index].bShouldAddSlot)
|
|
||||||
{
|
|
||||||
BlendMasks[index].Slot.SlotName = BlendMasks[index].SlotName;
|
|
||||||
BlendMasks[index].Slot.Source = MaskPose;
|
|
||||||
BlendMasks[index].Slot.Initialize_AnyThread(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!context.AnimInstanceProxy->GetSkeleton())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invalidate the cached per-bone blend weights from the skeleton
|
|
||||||
InvalidatePerBoneBlendWeights();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::CacheBones_AnyThread(const FAnimationCacheBonesContext& context)
|
|
||||||
{
|
|
||||||
// Don't call SUPER since it's empty.
|
|
||||||
|
|
||||||
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(CacheBones_AnyThread)
|
|
||||||
AnimationPose.CacheBones(context);
|
|
||||||
BaseAdditivePose.CacheBones(context);
|
|
||||||
MaskPose.CacheBones(context);
|
|
||||||
const int32 numBlendMasks = BlendMasks.Num();
|
|
||||||
for (int32 maskIndex = 0; maskIndex < numBlendMasks; ++maskIndex)
|
|
||||||
{
|
|
||||||
const FOLSMaskSettings currentMask = BlendMasks[maskIndex];
|
|
||||||
const FName blendProfileName = BlendMasks[maskIndex].BlendProfileName;
|
|
||||||
if (const TObjectPtr<UBlendProfile> blendProfile = context.AnimInstanceProxy->GetSkeleton()->GetBlendProfile(
|
|
||||||
blendProfileName))
|
|
||||||
{
|
|
||||||
BlendMasks[maskIndex].BlendProfile = blendProfile;
|
|
||||||
}
|
|
||||||
if (BlendMasks[maskIndex].bShouldAddSlot)
|
|
||||||
{
|
|
||||||
BlendMasks[maskIndex].Slot.CacheBones_AnyThread(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateCachedBoneData(context.AnimInstanceProxy->GetRequiredBones(), context.AnimInstanceProxy->GetSkeleton());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::Update_AnyThread(const FAnimationUpdateContext& Context)
|
|
||||||
{
|
|
||||||
// Don't call SUPER since it's empty.
|
|
||||||
|
|
||||||
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Update_AnyThread)
|
|
||||||
bHasRelevantPoses = false;
|
|
||||||
if (BlendMasks.Num() > 0)
|
|
||||||
{
|
|
||||||
if (IsLODEnabled(Context.AnimInstanceProxy))
|
|
||||||
{
|
|
||||||
GetEvaluateGraphExposedInputs().Execute(Context);
|
|
||||||
|
|
||||||
if (!bHasRelevantPoses)
|
|
||||||
{
|
|
||||||
MaskPose.Update(Context);
|
|
||||||
BaseAdditivePose.Update(Context);
|
|
||||||
AnimationPose.Update(Context);
|
|
||||||
for (int32 Index = 0; Index < BlendMasks.Num(); ++Index)
|
|
||||||
{
|
|
||||||
if (BlendMasks[Index].bShouldAddSlot)
|
|
||||||
{
|
|
||||||
BlendMasks[Index].Slot.Update_AnyThread(Context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateCachedBoneData(Context.AnimInstanceProxy->GetRequiredBones(),
|
|
||||||
Context.AnimInstanceProxy->GetSkeleton());
|
|
||||||
|
|
||||||
bHasRelevantPoses = true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear BlendWeights if disabled by LODThreshold.
|
|
||||||
for (int32 ChildIndex = 0; ChildIndex < MaskBlendWeights.Num(); ++ChildIndex)
|
|
||||||
{
|
|
||||||
MaskBlendWeights[ChildIndex].LocalSpaceBlendAlpha = 0.0f;
|
|
||||||
MaskBlendWeights[ChildIndex].MeshSpaceBlendAlpha = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationPose.Update(Context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::Evaluate_AnyThread(FPoseContext& output)
|
|
||||||
{
|
|
||||||
// Don't call SUPER since it's empty.
|
|
||||||
|
|
||||||
if (BlendMasks.Num() > 0)
|
|
||||||
{
|
|
||||||
AnimationPose.Evaluate(output);
|
|
||||||
FPoseContext animationPoseContext(output);
|
|
||||||
animationPoseContext = output;
|
|
||||||
|
|
||||||
FPoseContext updatedAnimationPoseContext(output);
|
|
||||||
updatedAnimationPoseContext = animationPoseContext;
|
|
||||||
|
|
||||||
FPoseContext maskPoseContext(output);
|
|
||||||
MaskPose.Evaluate(maskPoseContext);
|
|
||||||
|
|
||||||
FPoseContext baseAddPoseContext(output);
|
|
||||||
BaseAdditivePose.Evaluate(baseAddPoseContext);
|
|
||||||
|
|
||||||
FPoseContext baseMSAddPoseContext(output);
|
|
||||||
baseMSAddPoseContext = baseAddPoseContext;
|
|
||||||
|
|
||||||
FPoseContext animationLocalSpaceAdditive(output);
|
|
||||||
animationLocalSpaceAdditive = animationPoseContext;
|
|
||||||
|
|
||||||
FPoseContext animationMeshSpaceAdditive(output);
|
|
||||||
animationMeshSpaceAdditive = animationPoseContext;
|
|
||||||
|
|
||||||
MakeAdditivePose(animationLocalSpaceAdditive, baseAddPoseContext, false);
|
|
||||||
MakeAdditivePose(animationMeshSpaceAdditive, baseMSAddPoseContext, true);
|
|
||||||
|
|
||||||
for (int32 maskIndex = 0; maskIndex < BlendMasks.Num(); ++maskIndex)
|
|
||||||
{
|
|
||||||
//Apply Blending For Each Mask
|
|
||||||
TArray<FCompactPose> lsTargetBlendPoses;
|
|
||||||
lsTargetBlendPoses.SetNum(1);
|
|
||||||
|
|
||||||
TArray<FCompactPose> msTargetBlendPoses;
|
|
||||||
msTargetBlendPoses.SetNum(1);
|
|
||||||
|
|
||||||
TArray<FBlendedCurve> lsTargetBlendCurves;
|
|
||||||
lsTargetBlendCurves.SetNum(1);
|
|
||||||
|
|
||||||
TArray<FBlendedCurve> msTargetBlendCurves;
|
|
||||||
msTargetBlendCurves.SetNum(1);
|
|
||||||
|
|
||||||
TArray<UE::Anim::FStackAttributeContainer> lsTargetBlendAttributes;
|
|
||||||
lsTargetBlendAttributes.SetNum(1);
|
|
||||||
|
|
||||||
TArray<UE::Anim::FStackAttributeContainer> msTargetBlendAttributes;
|
|
||||||
msTargetBlendAttributes.SetNum(1);
|
|
||||||
|
|
||||||
FPoseContext outMaskPoseContext(output);
|
|
||||||
(BlendMasks[maskIndex].bShouldAddSlot)
|
|
||||||
? BlendMasks[maskIndex].Slot.Evaluate_AnyThread(outMaskPoseContext)
|
|
||||||
: BlendMasks[maskIndex].Slot.Evaluate_AnyThread(outMaskPoseContext);
|
|
||||||
|
|
||||||
UpdateWeightsFromCurves(output.AnimInstanceProxy->GetSkeleton(), outMaskPoseContext, maskIndex);
|
|
||||||
|
|
||||||
FAnimationPoseData inOutAnimationPoseData(outMaskPoseContext);
|
|
||||||
const FAnimationPoseData additiveAnimationPoseData(
|
|
||||||
BlendMasks[maskIndex].bUseMeshSpaceAdditive ? animationMeshSpaceAdditive : animationLocalSpaceAdditive);
|
|
||||||
if (FAnimWeight::IsRelevant(MaskBlendWeights[maskIndex].AdditiveAlpha))
|
|
||||||
{
|
|
||||||
FAnimationRuntime::AccumulateAdditivePose(inOutAnimationPoseData, additiveAnimationPoseData,
|
|
||||||
MaskBlendWeights[maskIndex].AdditiveAlpha,
|
|
||||||
BlendMasks[maskIndex].bUseMeshSpaceAdditive
|
|
||||||
? AAT_RotationOffsetMeshSpace
|
|
||||||
: AAT_LocalSpaceBase);
|
|
||||||
outMaskPoseContext.Pose.NormalizeRotations();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FPoseContext currentPoseContext(animationPoseContext);
|
|
||||||
FAnimationPoseData blendedAnimationPoseData(currentPoseContext);
|
|
||||||
const FAnimationPoseData animationPoseOneData(animationPoseContext);
|
|
||||||
const FAnimationPoseData animationPoseTwoData(outMaskPoseContext);
|
|
||||||
|
|
||||||
|
|
||||||
TArray<float> lsDesiredBlendWeight;
|
|
||||||
lsDesiredBlendWeight.Add(MaskBlendWeights[maskIndex].LocalSpaceBlendAlpha);
|
|
||||||
TArray<float> msDesiredBlendWeight;
|
|
||||||
msDesiredBlendWeight.Add(MaskBlendWeights[maskIndex].MeshSpaceBlendAlpha);
|
|
||||||
FAnimationRuntime::UpdateDesiredBoneWeight(AllBoneBlendWeights[maskIndex].LocalSpaceDesiredBoneBlendWeights,
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalSpaceCurrentBoneBlendWeights,
|
|
||||||
lsDesiredBlendWeight);
|
|
||||||
FAnimationRuntime::UpdateDesiredBoneWeight(AllBoneBlendWeights[maskIndex].MeshSpaceDesiredBoneBlendWeights,
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshSpaceCurrentBoneBlendWeights,
|
|
||||||
msDesiredBlendWeight);
|
|
||||||
|
|
||||||
FAnimationRuntime::BlendTwoPosesTogether(animationPoseOneData, animationPoseTwoData,
|
|
||||||
(1.0f - MaskBlendWeights[maskIndex].OverrideAlpha),
|
|
||||||
blendedAnimationPoseData);
|
|
||||||
|
|
||||||
FPoseContext msCurrentPoseContext(animationPoseContext);
|
|
||||||
msCurrentPoseContext = currentPoseContext;
|
|
||||||
if (FAnimWeight::IsRelevant(MaskBlendWeights[maskIndex].LocalSpaceBlendAlpha))
|
|
||||||
{
|
|
||||||
lsTargetBlendPoses[0].MoveBonesFrom(currentPoseContext.Pose);
|
|
||||||
lsTargetBlendCurves[0].MoveFrom(currentPoseContext.Curve);
|
|
||||||
lsTargetBlendAttributes[0].MoveFrom(currentPoseContext.CustomAttributes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lsTargetBlendPoses[0].ResetToRefPose(animationPoseContext.Pose.GetBoneContainer());
|
|
||||||
lsTargetBlendCurves[0].InitFrom(output.Curve);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAnimWeight::IsRelevant(MaskBlendWeights[maskIndex].MeshSpaceBlendAlpha))
|
|
||||||
{
|
|
||||||
msTargetBlendPoses[0].MoveBonesFrom(msCurrentPoseContext.Pose);
|
|
||||||
msTargetBlendCurves[0].MoveFrom(msCurrentPoseContext.Curve);
|
|
||||||
msTargetBlendAttributes[0].MoveFrom(msCurrentPoseContext.CustomAttributes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msTargetBlendPoses[0].ResetToRefPose(animationPoseContext.Pose.GetBoneContainer());
|
|
||||||
msTargetBlendCurves[0].InitFrom(output.Curve);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter to make sure it only includes curves that are linked to the correct bone filter
|
|
||||||
UE::Anim::FNamedValueArrayUtils::RemoveByPredicate(animationPoseContext.Curve,
|
|
||||||
AllBoneBlendWeights[maskIndex].
|
|
||||||
LocalCurvePoseSourceIndices,
|
|
||||||
[](const UE::Anim::FCurveElement& inOutBasePoseElement,
|
|
||||||
const UE::Anim::FCurveElementIndexed&
|
|
||||||
inSourceIndexElement)
|
|
||||||
{
|
|
||||||
// if source index is set, remove base pose curve value
|
|
||||||
return (inSourceIndexElement.Index != INDEX_NONE);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Filter to make sure it only includes curves that are linked to the correct bone filter
|
|
||||||
UE::Anim::FNamedValueArrayUtils::RemoveByPredicate(animationPoseContext.Curve,
|
|
||||||
AllBoneBlendWeights[maskIndex].
|
|
||||||
MeshCurvePoseSourceIndices,
|
|
||||||
[](const UE::Anim::FCurveElement& inOutBasePoseElement,
|
|
||||||
const UE::Anim::FCurveElementIndexed&
|
|
||||||
inSourceIndexElement)
|
|
||||||
{
|
|
||||||
// if source index is set, remove base pose curve value
|
|
||||||
return (inSourceIndexElement.Index != INDEX_NONE);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
FAnimationRuntime::EBlendPosesPerBoneFilterFlags msBlendFlags =
|
|
||||||
FAnimationRuntime::EBlendPosesPerBoneFilterFlags::None;
|
|
||||||
msBlendFlags |= FAnimationRuntime::EBlendPosesPerBoneFilterFlags::MeshSpaceRotation;
|
|
||||||
|
|
||||||
FAnimationRuntime::EBlendPosesPerBoneFilterFlags lsBlendFlags =
|
|
||||||
FAnimationRuntime::EBlendPosesPerBoneFilterFlags::None;
|
|
||||||
if (FAnimWeight::IsRelevant(MaskBlendWeights[maskIndex].LocalSpaceBlendAlpha))
|
|
||||||
{
|
|
||||||
FAnimationPoseData animationPoseData(output);
|
|
||||||
FAnimationRuntime::BlendPosesPerBoneFilter(updatedAnimationPoseContext.Pose, lsTargetBlendPoses,
|
|
||||||
updatedAnimationPoseContext.Curve, lsTargetBlendCurves,
|
|
||||||
updatedAnimationPoseContext.CustomAttributes,
|
|
||||||
lsTargetBlendAttributes, animationPoseData,
|
|
||||||
AllBoneBlendWeights[maskIndex].
|
|
||||||
LocalSpaceCurrentBoneBlendWeights, lsBlendFlags,
|
|
||||||
BlendMasks[maskIndex].CurveBlendOption);
|
|
||||||
updatedAnimationPoseContext = output;
|
|
||||||
updatedAnimationPoseContext.Pose.NormalizeRotations();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAnimWeight::IsRelevant(MaskBlendWeights[maskIndex].MeshSpaceBlendAlpha))
|
|
||||||
{
|
|
||||||
FAnimationPoseData MSAnimationPoseData(output);
|
|
||||||
FAnimationRuntime::BlendPosesPerBoneFilter(updatedAnimationPoseContext.Pose, msTargetBlendPoses,
|
|
||||||
updatedAnimationPoseContext.Curve, msTargetBlendCurves,
|
|
||||||
updatedAnimationPoseContext.CustomAttributes,
|
|
||||||
msTargetBlendAttributes, MSAnimationPoseData,
|
|
||||||
AllBoneBlendWeights[maskIndex].
|
|
||||||
MeshSpaceCurrentBoneBlendWeights, msBlendFlags,
|
|
||||||
BlendMasks[maskIndex].CurveBlendOption);
|
|
||||||
updatedAnimationPoseContext = output;
|
|
||||||
updatedAnimationPoseContext.Pose.NormalizeRotations();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationPose.Evaluate(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::InvalidatePerBoneBlendWeights()
|
|
||||||
{
|
|
||||||
RequiredBonesSerialNumber = 0;
|
|
||||||
SkeletonGuid = FGuid();
|
|
||||||
VirtualBoneGuid = FGuid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::InvalidateCachedBoneData()
|
|
||||||
{
|
|
||||||
RequiredBonesSerialNumber = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::RebuildPerBoneBlendWeights(const USkeleton* skeleton)
|
|
||||||
{
|
|
||||||
if (skeleton)
|
|
||||||
{
|
|
||||||
if (BlendMasks.Num() > 0)
|
|
||||||
{
|
|
||||||
PerBoneBlendWeights.SetNum(BlendMasks.Num());
|
|
||||||
TArray<UBlendProfile*> currentBlendProfile;
|
|
||||||
for (int32 Index = 0; Index < BlendMasks.Num(); ++Index)
|
|
||||||
{
|
|
||||||
if (BlendMasks[Index].BlendProfile && BlendMasks[Index].BlendProfile->IsBlendMask())
|
|
||||||
{
|
|
||||||
currentBlendProfile.Reset();
|
|
||||||
currentBlendProfile.Add(BlendMasks[Index].BlendProfile);
|
|
||||||
FAnimationRuntime::CreateMaskWeights(PerBoneBlendWeights[Index].PerBoneBlendWeights,
|
|
||||||
currentBlendProfile, skeleton);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const FReferenceSkeleton& refSkeleton = skeleton->GetReferenceSkeleton();
|
|
||||||
const int32 numBones = refSkeleton.GetNum();
|
|
||||||
PerBoneBlendWeights[Index].PerBoneBlendWeights.Reset(numBones);
|
|
||||||
// We only store non-zero weights in blend masks. Initialize all to zero.
|
|
||||||
PerBoneBlendWeights[Index].PerBoneBlendWeights.AddZeroed(numBones);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SkeletonGuid = skeleton->GetGuid();
|
|
||||||
VirtualBoneGuid = skeleton->GetVirtualBoneGuid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FAnimNode_OLSMask::ArePerBoneBlendWeightsValid(const USkeleton* skeleton) const
|
|
||||||
{
|
|
||||||
return (skeleton && skeleton->GetGuid() == SkeletonGuid && skeleton->GetVirtualBoneGuid() == VirtualBoneGuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::UpdateCachedBoneData(const FBoneContainer& requiredBones, const USkeleton* skeleton)
|
|
||||||
{
|
|
||||||
if (requiredBones.GetSerialNumber() == RequiredBonesSerialNumber)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requiredBones.GetBoneIndicesArray().Num() > 0)
|
|
||||||
{
|
|
||||||
if (!ArePerBoneBlendWeightsValid(skeleton))
|
|
||||||
{
|
|
||||||
RebuildPerBoneBlendWeights(skeleton);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32 Index = 0; Index < BlendMasks.Num(); ++Index)
|
|
||||||
{
|
|
||||||
UpdateBodyPartCachedBoneData(requiredBones, skeleton, Index);
|
|
||||||
}
|
|
||||||
|
|
||||||
RequiredBonesSerialNumber = requiredBones.GetSerialNumber();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::UpdateBodyPartCachedBoneData(const FBoneContainer& requiredBones, const USkeleton* skeleton,
|
|
||||||
const int32 maskIndex)
|
|
||||||
{
|
|
||||||
const TArray<FBoneIndexType>& requiredBoneIndices = requiredBones.GetBoneIndicesArray();
|
|
||||||
const int32 numRequiredBones = requiredBoneIndices.Num();
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalSpaceDesiredBoneBlendWeights.SetNumZeroed(numRequiredBones);
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshSpaceDesiredBoneBlendWeights.SetNumZeroed(numRequiredBones);
|
|
||||||
for (int32 requiredBoneIndex = 0; requiredBoneIndex < numRequiredBones; requiredBoneIndex++)
|
|
||||||
{
|
|
||||||
const int32 skeletonBoneIndex = requiredBones.GetSkeletonIndex(FCompactPoseBoneIndex(requiredBoneIndex));
|
|
||||||
if (ensure(skeletonBoneIndex != INDEX_NONE))
|
|
||||||
{
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalSpaceDesiredBoneBlendWeights[requiredBoneIndex] = PerBoneBlendWeights[
|
|
||||||
maskIndex].PerBoneBlendWeights[skeletonBoneIndex];
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshSpaceDesiredBoneBlendWeights[requiredBoneIndex] = PerBoneBlendWeights[
|
|
||||||
maskIndex].PerBoneBlendWeights[skeletonBoneIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalSpaceCurrentBoneBlendWeights.Reset(
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalSpaceDesiredBoneBlendWeights.Num());
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshSpaceCurrentBoneBlendWeights.Reset(
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshSpaceDesiredBoneBlendWeights.Num());
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalSpaceCurrentBoneBlendWeights.AddZeroed(
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalSpaceDesiredBoneBlendWeights.Num());
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshSpaceCurrentBoneBlendWeights.AddZeroed(
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshSpaceDesiredBoneBlendWeights.Num());
|
|
||||||
TArray<float> lsDesiredBlendWeight;
|
|
||||||
lsDesiredBlendWeight.Add(MaskBlendWeights[maskIndex].LocalSpaceBlendAlpha);
|
|
||||||
TArray<float> msDesiredBlendWeight;
|
|
||||||
msDesiredBlendWeight.Add(MaskBlendWeights[maskIndex].MeshSpaceBlendAlpha);
|
|
||||||
FAnimationRuntime::UpdateDesiredBoneWeight(AllBoneBlendWeights[maskIndex].LocalSpaceDesiredBoneBlendWeights,
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalSpaceCurrentBoneBlendWeights,
|
|
||||||
lsDesiredBlendWeight);
|
|
||||||
FAnimationRuntime::UpdateDesiredBoneWeight(AllBoneBlendWeights[maskIndex].MeshSpaceDesiredBoneBlendWeights,
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshSpaceCurrentBoneBlendWeights,
|
|
||||||
msDesiredBlendWeight);
|
|
||||||
|
|
||||||
// Build curve source indices
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalCurvePoseSourceIndices.Empty();
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalCurvePoseSourceIndices.Reserve(skeleton->GetNumCurveMetaData());
|
|
||||||
skeleton->ForEachCurveMetaData(
|
|
||||||
[this, &requiredBones, maskIndex](const FName& curveName, const FCurveMetaData& metaData)
|
|
||||||
{
|
|
||||||
for (const FBoneReference& linkedBone : metaData.LinkedBones)
|
|
||||||
{
|
|
||||||
FCompactPoseBoneIndex compactPoseIndex = linkedBone.GetCompactPoseIndex(requiredBones);
|
|
||||||
if (compactPoseIndex != INDEX_NONE)
|
|
||||||
{
|
|
||||||
if (AllBoneBlendWeights[maskIndex].LocalSpaceDesiredBoneBlendWeights[compactPoseIndex.GetInt()].BlendWeight > 0.f)
|
|
||||||
{
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalCurvePoseSourceIndices.Add(
|
|
||||||
curveName,
|
|
||||||
AllBoneBlendWeights[maskIndex].LocalSpaceDesiredBoneBlendWeights[compactPoseIndex.GetInt()].
|
|
||||||
SourceIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Build curve source indices
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshCurvePoseSourceIndices.Empty();
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshCurvePoseSourceIndices.Reserve(skeleton->GetNumCurveMetaData());
|
|
||||||
skeleton->ForEachCurveMetaData(
|
|
||||||
[this, &requiredBones, maskIndex](const FName& curveName, const FCurveMetaData& metaData)
|
|
||||||
{
|
|
||||||
for (const FBoneReference& linkedBone : metaData.LinkedBones)
|
|
||||||
{
|
|
||||||
FCompactPoseBoneIndex compactPoseIndex = linkedBone.GetCompactPoseIndex(requiredBones);
|
|
||||||
if (compactPoseIndex != INDEX_NONE)
|
|
||||||
{
|
|
||||||
if (AllBoneBlendWeights[maskIndex].MeshSpaceDesiredBoneBlendWeights[compactPoseIndex.GetInt()].
|
|
||||||
BlendWeight > 0.f)
|
|
||||||
{
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshCurvePoseSourceIndices.Add(
|
|
||||||
curveName,
|
|
||||||
AllBoneBlendWeights[maskIndex].MeshSpaceDesiredBoneBlendWeights[compactPoseIndex.GetInt()].
|
|
||||||
SourceIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::UpdateWeightsFromCurves(const USkeleton* skeleton, const FPoseContext& desiredCurvesPose,
|
|
||||||
const int32 index)
|
|
||||||
{
|
|
||||||
if (BlendMasks[index].WeightCurves.OverrideCurve != NAME_None)
|
|
||||||
{
|
|
||||||
MaskBlendWeights[index].OverrideAlpha = desiredCurvesPose.Curve.Get(
|
|
||||||
BlendMasks[index].WeightCurves.OverrideCurve);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BlendMasks[index].WeightCurves.AdditiveCurve != NAME_None)
|
|
||||||
{
|
|
||||||
MaskBlendWeights[index].AdditiveAlpha = desiredCurvesPose.Curve.Get(
|
|
||||||
BlendMasks[index].WeightCurves.AdditiveCurve);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BlendMasks[index].WeightCurves.LocalSpaceBlendCurve != NAME_None)
|
|
||||||
{
|
|
||||||
MaskBlendWeights[index].LocalSpaceBlendAlpha = desiredCurvesPose.Curve.Get(
|
|
||||||
BlendMasks[index].WeightCurves.LocalSpaceBlendCurve);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BlendMasks[index].WeightCurves.MeshSpaceBlendCurve != NAME_None)
|
|
||||||
{
|
|
||||||
MaskBlendWeights[index].MeshSpaceBlendAlpha = desiredCurvesPose.Curve.Get(
|
|
||||||
BlendMasks[index].WeightCurves.MeshSpaceBlendCurve);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAnimNode_OLSMask::MakeAdditivePose(FPoseContext& outAdditivePose, FPoseContext& outBasePose,
|
|
||||||
const bool shouldUseMeshSpaceAdditive)
|
|
||||||
{
|
|
||||||
if (shouldUseMeshSpaceAdditive)
|
|
||||||
{
|
|
||||||
FAnimationRuntime::ConvertPoseToMeshRotation(outAdditivePose.Pose);
|
|
||||||
FAnimationRuntime::ConvertPoseToMeshRotation(outBasePose.Pose);
|
|
||||||
}
|
|
||||||
|
|
||||||
FAnimationRuntime::ConvertPoseToAdditive(outAdditivePose.Pose, outBasePose.Pose);
|
|
||||||
outAdditivePose.Curve.ConvertToAdditive(outBasePose.Curve);
|
|
||||||
|
|
||||||
UE::Anim::Attributes::ConvertToAdditive(outBasePose.CustomAttributes, outAdditivePose.CustomAttributes);
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
|
||||||
|
|
||||||
|
|
||||||
#include "Nodes/AnimNode_SlotCustom.h"
|
|
||||||
|
|
||||||
#include "Animation/AnimInstanceProxy.h"
|
|
||||||
#include "Animation/AnimNode_Inertialization.h"
|
|
||||||
|
|
||||||
void FAnimNode_SlotCustom::Update_AnyThread(const FAnimationUpdateContext& context)
|
|
||||||
{
|
|
||||||
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Update_AnyThread)
|
|
||||||
// Update weights.
|
|
||||||
context.AnimInstanceProxy->GetSlotWeight(SlotName, WeightData.SlotNodeWeight, WeightData.SourceWeight, WeightData.TotalNodeWeight);
|
|
||||||
|
|
||||||
// Update cache in AnimInstance.
|
|
||||||
context.AnimInstanceProxy->UpdateSlotNodeWeight(SlotName, WeightData.SlotNodeWeight, context.GetFinalBlendWeight());
|
|
||||||
|
|
||||||
UE::Anim::FSlotInertializationRequest inertializationRequest;
|
|
||||||
if (context.AnimInstanceProxy->GetSlotInertializationRequest(SlotName, inertializationRequest))
|
|
||||||
{
|
|
||||||
UE::Anim::IInertializationRequester* inertializationRequestr = context.GetMessage<UE::Anim::IInertializationRequester>();
|
|
||||||
if (inertializationRequestr)
|
|
||||||
{
|
|
||||||
inertializationRequestr->RequestInertialization(inertializationRequest.Get<0>(), inertializationRequest.Get<1>());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FAnimNode_Inertialization::LogRequestError(context, Source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool shouldUpdateSource = (bAlwaysUpdateSourcePose || FAnimWeight::IsRelevant(WeightData.SourceWeight));
|
|
||||||
if (shouldUpdateSource)
|
|
||||||
{
|
|
||||||
const float SourceWeight = FMath::Max(FAnimWeight::GetSmallestRelevantWeight(), WeightData.SourceWeight);
|
|
||||||
Source.Update(context.FractionalWeight(SourceWeight));
|
|
||||||
}
|
|
||||||
#if ANIM_TRACE_ENABLED
|
|
||||||
TRACE_ANIM_NODE_VALUE(context, TEXT("Name"), SlotName);
|
|
||||||
TRACE_ANIM_NODE_VALUE(context, TEXT("Slot Weight"), WeightData.SlotNodeWeight);
|
|
||||||
TRACE_ANIM_NODE_VALUE(context, TEXT("Pose Source"), (WeightData.SourceWeight <= ZERO_ANIMWEIGHT_THRESH));
|
|
||||||
|
|
||||||
context.AnimInstanceProxy->TraceMontageEvaluationData(context, SlotName);
|
|
||||||
#endif
|
|
||||||
}
|
|
@ -1,274 +0,0 @@
|
|||||||
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
|
||||||
#include "GameplayTagContainer.h"
|
|
||||||
#include "UObject/Object.h"
|
|
||||||
#include "OLSMaskAnimationData.generated.h"
|
|
||||||
|
|
||||||
//Enums
|
|
||||||
UENUM(BlueprintType)
|
|
||||||
enum class EOLSAdditiveMode : uint8
|
|
||||||
{
|
|
||||||
EMeshSpace UMETA(DisplayName = "MeshSpace"),
|
|
||||||
ELocalSpace UMETA(DisplayName = "LocalSpace"),
|
|
||||||
};
|
|
||||||
|
|
||||||
//Structs
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FOLSNodeMaskWeights
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite,EditAnywhere, Category=Config,meta=(ClampMin = "0.0" , ClampMax = "1.0") )
|
|
||||||
float OverrideAlpha = 0.0f;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite,EditAnywhere, Category=Config ,meta=(ClampMin = "0.0" , ClampMax = "1.0"))
|
|
||||||
float AdditiveAlpha = 0.0f;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite,EditAnywhere, Category=Config ,meta=(ClampMin = "0.0" , ClampMax = "1.0"))
|
|
||||||
float MeshSpaceBlendAlpha = 1.0f;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite,EditAnywhere, Category=Config ,meta=(ClampMin = "0.0" , ClampMax = "1.0"))
|
|
||||||
float LocalSpaceBlendAlpha = 0.0f;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FOLSMaskWeights
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves", meta=(ClampMin = "0.0", ClampMax = "1.0"))
|
|
||||||
float MaskWeight = 0;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves", meta=(ClampMin = "0.0", ClampMax = "1.0"))
|
|
||||||
float MaskAdditive = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FOLSArmMaskWeights
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
EOLSAdditiveMode ArmAdditiveMode = EOLSAdditiveMode::ELocalSpace;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSMaskWeights MaskWeights;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadOnly,Category = "Mask Curves")
|
|
||||||
float ArmMeshSpaceBlend = 0.0f;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadOnly,Category = "Mask Curves")
|
|
||||||
float ArmLocalSpaceBlend = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FOLSMaskingWeights
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSMaskWeights LegsWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSMaskWeights PelvisWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSMaskWeights SpineWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSMaskWeights HeadWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSArmMaskWeights RightArmWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSMaskWeights RightHandWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSArmMaskWeights LeftArmWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSMaskWeights LeftHandWeights;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FOLSCapturedMaskingWeights
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSNodeMaskWeights LegsWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSNodeMaskWeights PelvisWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSNodeMaskWeights SpineWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSNodeMaskWeights HeadWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSNodeMaskWeights RightArmWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSNodeMaskWeights RightHandWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSNodeMaskWeights LeftArmWeights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Mask Curves")
|
|
||||||
FOLSNodeMaskWeights LeftHandWeights;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FOLSMaskAnimation
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Animation")
|
|
||||||
TObjectPtr<class UAnimSequence> Animation = nullptr;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "Masking Curves", meta = (HideDefault))
|
|
||||||
FOLSCapturedMaskingWeights Weights;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Animation")
|
|
||||||
FOLSMaskingWeights MaskingWeights;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "Masking Curves", meta = (HideDefault))
|
|
||||||
TMap<FName, float> CurvesToModify;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Animation")
|
|
||||||
float MaskPoseTime = 0.f;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
#if WITH_EDITOR
|
|
||||||
void CacheAdditiveCurves();
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FOLSGaitMasks
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Animation")
|
|
||||||
FOLSMaskAnimation ForwardMask;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Animation")
|
|
||||||
FOLSMaskAnimation RightMask;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Animation")
|
|
||||||
FOLSMaskAnimation LeftMask;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Animation")
|
|
||||||
FOLSMaskAnimation BackwardMask;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
#if WITH_EDITOR
|
|
||||||
void CacheAdditiveCurves();
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FOLSStanceMaskSets
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
#if WITH_EDITOR
|
|
||||||
void CacheAdditiveCurves();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const FOLSGaitMasks* SelectGaitMasksByGait(const FGameplayTag& gait);
|
|
||||||
const FOLSMaskAnimation& GetIdleMask() const;
|
|
||||||
const FOLSMaskAnimation& GetAimMask() const;
|
|
||||||
FORCEINLINE void GetAimBlendInOut(float& outBlendIn, float& outBlendOut) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stance Mask Sets")
|
|
||||||
TMap<FGameplayTag, FOLSGaitMasks> GaitMasks;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stance Mask Sets")
|
|
||||||
FOLSMaskAnimation IdleMask;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stance Mask Sets")
|
|
||||||
FOLSMaskAnimation AimMask;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stance Mask Sets")
|
|
||||||
float AimBlendInTime = .4f;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stance Mask Sets")
|
|
||||||
float AimBlendOutTime = .4f;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Legs
|
|
||||||
static const FName MaskLegsCurveName = FName("LegsMask");
|
|
||||||
static const FName MaskLegsLocalSpaceCurveName = FName("LegsMask_LS");
|
|
||||||
static const FName MaskLegsMeshSpaceCurveName = FName("LegsMask_MS");
|
|
||||||
static const FName MaskLegsAddCurveName = FName("LegsMask_Add");
|
|
||||||
|
|
||||||
// Pelvis
|
|
||||||
static const FName MaskPelvisCurveName = FName("PelvisMask");
|
|
||||||
static const FName MaskPelvisLocalSpaceCurveName = FName("PelvisMask_LS");
|
|
||||||
static const FName MaskPelvisMeshSpaceCurveName = FName("PelvisMask_MS");
|
|
||||||
static const FName MaskPelvisAddCurveName = FName("PelvisMask_Add");
|
|
||||||
|
|
||||||
// Spine
|
|
||||||
static const FName MaskSpineCurveName = FName("SpineMask");
|
|
||||||
static const FName MaskSpineLocalSpaceCurveName = FName("SpineMask_LS");
|
|
||||||
static const FName MaskSpineMeshSpaceCurveName = FName("SpineMask_MS");
|
|
||||||
static const FName MaskSpineAddCurveName = FName("SpineMask_Add");
|
|
||||||
|
|
||||||
// Head
|
|
||||||
static const FName MaskHeadCurveName = FName("HeadMask");
|
|
||||||
static const FName MaskHeadLocalSpaceCurveName = FName("HeadMask_LS");
|
|
||||||
static const FName MaskHeadMeshSpaceCurveName = FName("HeadMask_MS");
|
|
||||||
static const FName MaskHeadAddCurveName = FName("HeadMask_Add");
|
|
||||||
|
|
||||||
// Right Arm
|
|
||||||
static const FName MaskRightArmCurveName = FName("RightArmMask");
|
|
||||||
static const FName RightArmLocalSpaceCurveName = FName("RightArmMask_LS");
|
|
||||||
static const FName RightArmMeshSpaceCurveName = FName("RightArmMask_MS");
|
|
||||||
static const FName MaskRightArmAddCurveName = FName("RightArmMask_Add");
|
|
||||||
|
|
||||||
// Left Arm
|
|
||||||
static const FName MaskLeftArmCurveName = FName("LeftArmMask");
|
|
||||||
static const FName LeftArmLocalSpaceCurveName = FName("LeftArmMask_LS");
|
|
||||||
static const FName LeftArmMeshSpaceCurveName = FName("LeftArmMask_MS");
|
|
||||||
static const FName MaskLeftArmAddCurveName = FName("LeftArmMask_Add");
|
|
||||||
|
|
||||||
// Right Hand
|
|
||||||
static const FName RightHandCurveName = FName("RightHandMask");
|
|
||||||
static const FName RightHandLocalSpaceCurveName = FName("RightHandMask_LS");
|
|
||||||
static const FName RightHandMeshSpaceCurveName = FName("RightHandMask_MS");
|
|
||||||
static const FName MaskRightHandAddCurveName = FName("RightHandMask_Add");
|
|
||||||
|
|
||||||
// Left Hand
|
|
||||||
static const FName LeftHandCurveName = FName("LeftHandMask");
|
|
||||||
static const FName LeftHandLocalSpaceCurveName = FName("LeftHandMask_LS");
|
|
||||||
static const FName LeftHandMeshSpaceCurveName = FName("LeftHandMask_MS");
|
|
||||||
static const FName MaskLeftHandAddCurveName = FName("LeftHandMask_Add");
|
|
||||||
|
|
||||||
// Masking Group
|
|
||||||
static const FName MaskingGroupName = FName("Standing Mask");
|
|
@ -1,209 +0,0 @@
|
|||||||
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
|
||||||
#include "AnimNode_SlotCustom.h"
|
|
||||||
#include "Data/OLSMaskAnimationData.h"
|
|
||||||
#include "AnimNode_OLSMask.generated.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
USTRUCT(BlueprintInternalUseOnly)
|
|
||||||
struct FOLSWeightCurves
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category=Config)
|
|
||||||
FName OverrideCurve = NAME_None;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category=Config)
|
|
||||||
FName AdditiveCurve = NAME_None;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category=Config)
|
|
||||||
FName LocalSpaceBlendCurve = NAME_None;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category=Config)
|
|
||||||
FName MeshSpaceBlendCurve = NAME_None;
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintInternalUseOnly)
|
|
||||||
struct FOLSMaskSettings
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category=Config)
|
|
||||||
FName BlendProfileName = NAME_None;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category=Config)
|
|
||||||
bool bUseMeshSpaceAdditive = false;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category=Config)
|
|
||||||
bool bShouldAddSlot = false;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Config)
|
|
||||||
TEnumAsByte<ECurveBlendOption::Type> CurveBlendOption = ECurveBlendOption::Override;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Config)
|
|
||||||
FOLSWeightCurves WeightCurves;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Config)
|
|
||||||
FName SlotName = FAnimSlotGroup::DefaultSlotName;
|
|
||||||
|
|
||||||
// Transient properties should be declared at the end
|
|
||||||
UPROPERTY(Transient)
|
|
||||||
TObjectPtr<class UBlendProfile> BlendProfile = nullptr;
|
|
||||||
|
|
||||||
// Slot To Add If Needed
|
|
||||||
FAnimNode_SlotCustom Slot;
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintInternalUseOnly)
|
|
||||||
struct FOLSPerBoneWeights
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// Constructor to reserve memory for the arrays.
|
|
||||||
// Assuming using Unreal's mannequin.
|
|
||||||
FOLSPerBoneWeights()
|
|
||||||
{
|
|
||||||
LocalSpaceDesiredBoneBlendWeights.Reserve(32);
|
|
||||||
MeshSpaceDesiredBoneBlendWeights.Reserve(32);
|
|
||||||
LocalSpaceCurrentBoneBlendWeights.Reserve(32);
|
|
||||||
MeshSpaceCurrentBoneBlendWeights.Reserve(32);
|
|
||||||
LocalCurvePoseSourceIndices.Reserve(32);
|
|
||||||
MeshCurvePoseSourceIndices.Reserve(32);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
TArray<FPerBoneBlendWeight> LocalSpaceDesiredBoneBlendWeights;
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
TArray<FPerBoneBlendWeight> MeshSpaceDesiredBoneBlendWeights;
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
TArray<FPerBoneBlendWeight> LocalSpaceCurrentBoneBlendWeights;
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
TArray<FPerBoneBlendWeight> MeshSpaceCurrentBoneBlendWeights;
|
|
||||||
|
|
||||||
// Using a more memory-efficient representation for the curves
|
|
||||||
TBaseBlendedCurve<FDefaultAllocator, UE::Anim::FCurveElementIndexed> LocalCurvePoseSourceIndices;
|
|
||||||
TBaseBlendedCurve<FDefaultAllocator, UE::Anim::FCurveElementIndexed> MeshCurvePoseSourceIndices;
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintInternalUseOnly)
|
|
||||||
struct FOLSPerBoneBlendWeights
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
TArray<FPerBoneBlendWeight> PerBoneBlendWeights;
|
|
||||||
};
|
|
||||||
|
|
||||||
USTRUCT(BlueprintInternalUseOnly)
|
|
||||||
struct OLSANIMATION_API FAnimNode_OLSMask : public FAnimNode_Base
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
FAnimNode_OLSMask()
|
|
||||||
: bHasRelevantPoses(false)
|
|
||||||
, LODThreshold(INDEX_NONE)
|
|
||||||
, RequiredBonesSerialNumber(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// FAnimNode_Base interface
|
|
||||||
virtual void Initialize_AnyThread(const FAnimationInitializeContext& context) override;
|
|
||||||
virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& context) override;
|
|
||||||
virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
|
|
||||||
virtual void Evaluate_AnyThread(FPoseContext& output) override;
|
|
||||||
virtual int32 GetLODThreshold() const override { return LODThreshold; }
|
|
||||||
|
|
||||||
// Invalidate the cached per-bone blend weights from the skeleton
|
|
||||||
void InvalidatePerBoneBlendWeights();
|
|
||||||
|
|
||||||
// Invalidates the cached bone data so it is recalculated the next time this node is updated
|
|
||||||
void InvalidateCachedBoneData();
|
|
||||||
|
|
||||||
// Rebuild cache per bone blend weights from the skeleton
|
|
||||||
void RebuildPerBoneBlendWeights(const USkeleton* skeleton);
|
|
||||||
|
|
||||||
// Check whether per-bone blend weights are valid according to the skeleton (GUID check)
|
|
||||||
bool ArePerBoneBlendWeightsValid(const USkeleton* skeleton) const;
|
|
||||||
|
|
||||||
// Update cached data if required
|
|
||||||
void UpdateCachedBoneData(const FBoneContainer& requiredBones, const USkeleton* skeleton);
|
|
||||||
|
|
||||||
void UpdateBodyPartCachedBoneData(const FBoneContainer& requiredBones, const USkeleton* skeleton, const int32 maskIndex);
|
|
||||||
|
|
||||||
void UpdateWeightsFromCurves(const USkeleton* skeleton, const FPoseContext& desiredCurvesPose, const int32 index);
|
|
||||||
|
|
||||||
static void MakeAdditivePose(FPoseContext& outAdditivePose,FPoseContext& outBasePose, const bool shouldUseMeshSpaceAdditive);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Links)
|
|
||||||
FPoseLink AnimationPose;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Links)
|
|
||||||
FPoseLink MaskPose;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Links)
|
|
||||||
FPoseLink BaseAdditivePose;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite, Category=Config)
|
|
||||||
TArray<FOLSMaskSettings> BlendMasks;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Runtime, meta=(PinShownByDefault))
|
|
||||||
TArray<FOLSNodeMaskWeights> MaskBlendWeights;
|
|
||||||
|
|
||||||
uint8 bHasRelevantPoses : 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Max LOD that this node is allowed to run
|
|
||||||
* For example if you have LODThreadhold to be 2, it will run until LOD 2 (based on 0 index)
|
|
||||||
* when the component LOD becomes 3, it will stop update/evaluate
|
|
||||||
* currently transition would be issue and that has to be re-visited
|
|
||||||
*/
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Performance, meta = (DisplayName = "LOD Threshold"))
|
|
||||||
int32 LODThreshold = 0;
|
|
||||||
|
|
||||||
// transient data to handle weight and target weight
|
|
||||||
// this array changes based on required bones
|
|
||||||
UPROPERTY()
|
|
||||||
TArray<FOLSPerBoneWeights> AllBoneBlendWeights;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// Per-bone weights for the skeleton. Serialized as these are only relative to the skeleton, but can potentially
|
|
||||||
// be regenerated at runtime if the GUIDs dont match.
|
|
||||||
UPROPERTY()
|
|
||||||
TArray<FOLSPerBoneBlendWeights> PerBoneBlendWeights;
|
|
||||||
|
|
||||||
// Guids for skeleton used to determine whether the PerBoneBlendWeights need rebuilding
|
|
||||||
UPROPERTY()
|
|
||||||
FGuid SkeletonGuid;
|
|
||||||
|
|
||||||
// Guid for virtual bones used to determine whether the PerBoneBlendWeights need rebuilding
|
|
||||||
UPROPERTY()
|
|
||||||
FGuid VirtualBoneGuid;
|
|
||||||
|
|
||||||
// Serial number of the required bones container
|
|
||||||
uint16 RequiredBonesSerialNumber : 1;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
friend class UAnimGraphNode_KLSMask;
|
|
||||||
};
|
|
@ -1,21 +0,0 @@
|
|||||||
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
|
||||||
#include "AnimNodes/AnimNode_Slot.h"
|
|
||||||
#include "UObject/Object.h"
|
|
||||||
#include "AnimNode_SlotCustom.generated.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
USTRUCT(BlueprintInternalUseOnly)
|
|
||||||
struct OLSANIMATION_API FAnimNode_SlotCustom : public FAnimNode_Slot
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual void Update_AnyThread(const FAnimationUpdateContext& context) override;
|
|
||||||
};
|
|
@ -1,150 +0,0 @@
|
|||||||
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
|
||||||
|
|
||||||
|
|
||||||
#include "Nodes/AnimGraphNode_OLSMask.h"
|
|
||||||
|
|
||||||
#include "Kismet2/BlueprintEditorUtils.h"
|
|
||||||
|
|
||||||
#define LOCTEXT_NAMESPACE "OLSNodes"
|
|
||||||
|
|
||||||
UAnimGraphNode_OLSMask::UAnimGraphNode_OLSMask(const FObjectInitializer& objectInitializer) : Super(objectInitializer)
|
|
||||||
{
|
|
||||||
Node.BlendMasks.Reserve(1);
|
|
||||||
Node.MaskBlendWeights.Reserve(1);
|
|
||||||
Node.AllBoneBlendWeights.Reserve(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
FLinearColor UAnimGraphNode_OLSMask::GetNodeTitleColor() const
|
|
||||||
{
|
|
||||||
return FLinearColor(0.0f, 204.0f, 204.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
FText UAnimGraphNode_OLSMask::GetTooltipText() const
|
|
||||||
{
|
|
||||||
return LOCTEXT("AnimGraphNode_OLSMask_Tooltip", "OLS Mask Node");
|
|
||||||
}
|
|
||||||
|
|
||||||
FText UAnimGraphNode_OLSMask::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
|
||||||
{
|
|
||||||
return LOCTEXT("AnimGraphNode_OLSMaskBlend_Title", "Per Body Part Mask");
|
|
||||||
}
|
|
||||||
|
|
||||||
void UAnimGraphNode_OLSMask::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
|
||||||
{
|
|
||||||
const FName PropertyName = (PropertyChangedEvent.Property ? PropertyChangedEvent.Property->GetFName() : NAME_None);
|
|
||||||
|
|
||||||
|
|
||||||
if (PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_OLSMask, BlendMasks))
|
|
||||||
{
|
|
||||||
FScopedTransaction Transaction(LOCTEXT("AddedBlendMask", "Add Blend Mask"));
|
|
||||||
Modify();
|
|
||||||
|
|
||||||
const int32 NumMasks = Node.BlendMasks.Num();
|
|
||||||
Node.MaskBlendWeights.SetNum(NumMasks);
|
|
||||||
Node.AllBoneBlendWeights.SetNum(NumMasks);
|
|
||||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint());
|
|
||||||
ReconstructNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
FString UAnimGraphNode_OLSMask::GetNodeCategory() const
|
|
||||||
{
|
|
||||||
return TEXT("Blends|OLS Nodes");
|
|
||||||
}
|
|
||||||
|
|
||||||
void UAnimGraphNode_OLSMask::PreloadRequiredAssets()
|
|
||||||
{
|
|
||||||
const TObjectPtr<UAnimBlueprint> animBlueprint = GetAnimBlueprint();
|
|
||||||
if (animBlueprint && !GIsCookerLoadingPackage && animBlueprint->TargetSkeleton)
|
|
||||||
{
|
|
||||||
const int32 numBlendMasks = Node.BlendMasks.Num();
|
|
||||||
if (numBlendMasks > 0)
|
|
||||||
{
|
|
||||||
for (int32 maskIndex = 0; maskIndex < numBlendMasks; ++maskIndex)
|
|
||||||
{
|
|
||||||
const FName blendProfileName = Node.BlendMasks[maskIndex].BlendProfileName;
|
|
||||||
if (const TObjectPtr<UBlendProfile> blendProfile = animBlueprint->TargetSkeleton->GetBlendProfile(
|
|
||||||
blendProfileName))
|
|
||||||
{
|
|
||||||
Node.BlendMasks[maskIndex].BlendProfile = blendProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TObjectPtr<UBlendProfile> blendMask = Node.BlendMasks[maskIndex].BlendProfile;
|
|
||||||
PreloadObject(blendMask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Super::PreloadRequiredAssets();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UAnimGraphNode_OLSMask::BakeDataDuringCompilation(FCompilerResultsLog& MessageLog)
|
|
||||||
{
|
|
||||||
const TObjectPtr<UAnimBlueprint> animBlueprint = GetAnimBlueprint();
|
|
||||||
if (!GIsCookerLoadingPackage && animBlueprint->TargetSkeleton)
|
|
||||||
{
|
|
||||||
const int32 numBlendMasks = Node.BlendMasks.Num();
|
|
||||||
for (int32 maskIndex = 0; maskIndex < numBlendMasks; ++maskIndex)
|
|
||||||
{
|
|
||||||
const FOLSMaskSettings& currentMask = Node.BlendMasks[maskIndex];
|
|
||||||
const FName& blendProfileName = Node.BlendMasks[maskIndex].BlendProfileName;
|
|
||||||
if (const TObjectPtr<UBlendProfile> bendProfile = animBlueprint->TargetSkeleton->GetBlendProfile(
|
|
||||||
blendProfileName))
|
|
||||||
{
|
|
||||||
Node.BlendMasks[maskIndex].BlendProfile = bendProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentMask.bShouldAddSlot)
|
|
||||||
{
|
|
||||||
animBlueprint->TargetSkeleton->RegisterSlotNode(currentMask.SlotName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UAnimGraphNode_OLSMask::ValidateAnimNodeDuringCompilation(USkeleton* skeleton, FCompilerResultsLog& MessageLog)
|
|
||||||
{
|
|
||||||
if (skeleton)
|
|
||||||
{
|
|
||||||
// ensure to cache the per-bone blend weights
|
|
||||||
if (!Node.ArePerBoneBlendWeightsValid(skeleton))
|
|
||||||
{
|
|
||||||
Node.RebuildPerBoneBlendWeights(skeleton);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Node.BlendMasks.Num() > 0)
|
|
||||||
{
|
|
||||||
const int32 numBlendMasks = Node.BlendMasks.Num();
|
|
||||||
for (int32 maskIndex = 0; maskIndex < numBlendMasks; ++maskIndex)
|
|
||||||
{
|
|
||||||
const FName& blendProfileName = Node.BlendMasks[maskIndex].BlendProfileName;
|
|
||||||
const TObjectPtr<UBlendProfile> blendProfile = skeleton->GetBlendProfile(blendProfileName);
|
|
||||||
if (blendProfile)
|
|
||||||
{
|
|
||||||
Node.BlendMasks[maskIndex].BlendProfile = blendProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!blendProfile)
|
|
||||||
{
|
|
||||||
MessageLog.Error(
|
|
||||||
*FText::Format(
|
|
||||||
LOCTEXT("BlendProfileIsNull", "@@ has null BlendMask In Index {0}. "),
|
|
||||||
FText::AsNumber(maskIndex)).ToString(), this, blendProfile);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!blendProfile->IsBlendMask())
|
|
||||||
{
|
|
||||||
MessageLog.Error(
|
|
||||||
*FText::Format(LOCTEXT("BlendProfileModeError",
|
|
||||||
"@@ is using a BlendProfile(@@) without a BlendMask mode In Index {0}. "), FText::AsNumber(
|
|
||||||
maskIndex)).ToString(), this, blendProfile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Super::ValidateAnimNodeDuringCompilation(skeleton, MessageLog);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef LOCTEXT_NAMESPACE
|
|
@ -1,44 +0,0 @@
|
|||||||
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
|
||||||
#include "AnimGraphNode_Base.h"
|
|
||||||
#include "Nodes/AnimNode_OLSMask.h"
|
|
||||||
#include "AnimGraphNode_OLSMask.generated.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
UCLASS(MinimalAPI)
|
|
||||||
class UAnimGraphNode_OLSMask : public UAnimGraphNode_Base
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UAnimGraphNode_OLSMask(const FObjectInitializer& objectInitializer);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// UEdGraphNode interface
|
|
||||||
virtual FLinearColor GetNodeTitleColor() const override;
|
|
||||||
virtual FText GetTooltipText() const override;
|
|
||||||
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
|
|
||||||
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
|
|
||||||
// End of UEdGraphNode interface
|
|
||||||
|
|
||||||
// UAnimGraphNode_Base interface
|
|
||||||
virtual FString GetNodeCategory() const override;
|
|
||||||
virtual void PreloadRequiredAssets() override;
|
|
||||||
virtual void BakeDataDuringCompilation(class FCompilerResultsLog& MessageLog) override;
|
|
||||||
// End of UAnimGraphNode_Base interface
|
|
||||||
|
|
||||||
// Gives each visual node a chance to validate that they are still valid in the context of the compiled class, giving a last shot at error or warning generation after primary compilation is finished
|
|
||||||
virtual void ValidateAnimNodeDuringCompilation(class USkeleton* skeleton, class FCompilerResultsLog& MessageLog) override;
|
|
||||||
// End of UAnimGraphNode_Base interface
|
|
||||||
|
|
||||||
private:
|
|
||||||
UPROPERTY(EditAnywhere, Category=Settings)
|
|
||||||
FAnimNode_OLSMask Node;
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user