496 lines
20 KiB
C++
496 lines
20 KiB
C++
// © 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);
|
|
}
|