Removed files

This commit is contained in:
LongLy 2024-11-18 16:18:51 -07:00
parent 27ce0e7c26
commit b7c20351c8
8 changed files with 0 additions and 1399 deletions

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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");

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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

View File

@ -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;
};