本文整理汇总了C++中FBoneContainer类的典型用法代码示例。如果您正苦于以下问题:C++ FBoneContainer类的具体用法?C++ FBoneContainer怎么用?C++ FBoneContainer使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了FBoneContainer类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: ConvertPoseToMeshSpace
void FAnimationRuntime::ConvertPoseToMeshSpace(const TArray<FTransform> & LocalTransforms, TArray<FTransform> & MeshSpaceTransforms, const FBoneContainer& RequiredBones)
{
const int32 NumBones = RequiredBones.GetNumBones();
// right now all this does is to convert to SpaceBases
check( NumBones == LocalTransforms.Num() );
check( NumBones == MeshSpaceTransforms.Num() );
const FTransform* LocalTransformsData = LocalTransforms.GetData();
FTransform* SpaceBasesData = MeshSpaceTransforms.GetData();
const TArray<FBoneIndexType> & RequiredBoneIndexArray = RequiredBones.GetBoneIndicesArray();
// First bone is always root bone, and it doesn't have a parent.
{
check( RequiredBoneIndexArray[0] == 0 );
MeshSpaceTransforms[0] = LocalTransforms[0];
}
const int32 NumRequiredBones = RequiredBoneIndexArray.Num();
for(int32 i=1; i<NumRequiredBones; i++)
{
const int32 BoneIndex = RequiredBoneIndexArray[i];
FPlatformMisc::Prefetch(SpaceBasesData + BoneIndex);
// For all bones below the root, final component-space transform is relative transform * component-space transform of parent.
const int32 ParentIndex = RequiredBones.GetParentBoneIndex(BoneIndex);
FPlatformMisc::Prefetch(SpaceBasesData + ParentIndex);
FTransform::Multiply(SpaceBasesData + BoneIndex, LocalTransformsData + BoneIndex, SpaceBasesData + ParentIndex);
checkSlow( MeshSpaceTransforms[BoneIndex].IsRotationNormalized() );
checkSlow( !MeshSpaceTransforms[BoneIndex].ContainsNaN() );
}
}
示例2: EvaluateBoneTransforms
void FAnimNode_RotationMultiplier::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer & RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
if ( Multiplier != 0.f )
{
// Reference bone
const TArray<FTransform> & LocalRefPose = RequiredBones.GetRefPoseArray();
const FQuat RefQuat = LocalRefPose[TargetBone.BoneIndex].GetRotation();
FQuat NewQuat;
MultiplyQuatBasedOnSourceIndex(LocalRefPose, MeshBases, RotationAxisToRefer, SourceBone.BoneIndex, Multiplier, RefQuat, NewQuat);
FTransform NewLocalTransform = MeshBases.GetLocalSpaceTransform(TargetBone.BoneIndex);
NewLocalTransform.SetRotation(NewQuat);
const int32 ParentIndex = RequiredBones.GetParentBoneIndex(TargetBone.BoneIndex);
if( ParentIndex != INDEX_NONE )
{
const FTransform ParentTM = MeshBases.GetComponentSpaceTransform(ParentIndex);
FTransform NewTransform = NewLocalTransform * ParentTM;
OutBoneTransforms.Add( FBoneTransform(TargetBone.BoneIndex, NewTransform) );
}
else
{
OutBoneTransforms.Add( FBoneTransform(TargetBone.BoneIndex, NewLocalTransform) );
}
}
}
示例3: InitializeTransform
void FAnimationRuntime::InitializeTransform(const FBoneContainer& RequiredBones, /*inout*/ FTransformArrayA2 & Atoms)
{
check( Atoms.Num() == RequiredBones.GetNumBones() );
const TArray<FBoneIndexType> & RequiredBoneIndices = RequiredBones.GetBoneIndicesArray();
for (int32 j = 0; j < RequiredBoneIndices.Num(); ++j)
{
const int32 BoneIndex = RequiredBoneIndices[j];
Atoms[BoneIndex].SetIdentity();
}
}
示例4: FillWithRefPose
void FAnimationRuntime::FillWithRefPose(TArray<FTransform> & OutAtoms, const FBoneContainer& RequiredBones)
{
// Copy Target Asset's ref pose.
OutAtoms = RequiredBones.GetRefPoseArray();
// If retargeting is disabled, copy ref pose from Skeleton, rather than mesh.
// this is only used in editor and for debugging.
if( RequiredBones.GetDisableRetargeting() )
{
checkSlow( RequiredBones.IsValid() );
// Only do this if we have a mesh. otherwise we're not retargeting animations.
if( RequiredBones.GetSkeletalMeshAsset() )
{
TArray<int32> const & PoseToSkeletonBoneIndexArray = RequiredBones.GetPoseToSkeletonBoneIndexArray();
TArray<FBoneIndexType> const & RequireBonesIndexArray = RequiredBones.GetBoneIndicesArray();
TArray<FTransform> const & SkeletonRefPose = RequiredBones.GetSkeletonAsset()->GetRefLocalPoses();
for (int32 ArrayIndex = 0; ArrayIndex<RequireBonesIndexArray.Num(); ArrayIndex++)
{
int32 const & PoseBoneIndex = RequireBonesIndexArray[ArrayIndex];
int32 const & SkeletonBoneIndex = PoseToSkeletonBoneIndexArray[PoseBoneIndex];
// Pose bone index should always exist in Skeleton
checkSlow(SkeletonBoneIndex != INDEX_NONE);
OutAtoms[PoseBoneIndex] = SkeletonRefPose[SkeletonBoneIndex];
}
}
}
}
示例5: CreateMaskWeights
void FAnimationRuntime::CreateMaskWeights(TArray<FPerBoneBlendWeight> & BoneBlendWeights, const TArray<FInputBlendPose> &BlendFilters, const FBoneContainer& RequiredBones, const USkeleton* Skeleton)
{
if ( Skeleton )
{
const TArray<FBoneIndexType> & RequiredBoneIndices = RequiredBones.GetBoneIndicesArray();
BoneBlendWeights.Empty(RequiredBoneIndices.Num());
BoneBlendWeights.AddZeroed(RequiredBoneIndices.Num());
// base mask bone
for (int32 PoseIndex=0; PoseIndex<BlendFilters.Num(); ++PoseIndex)
{
const FInputBlendPose& BlendPose = BlendFilters[PoseIndex];
for (int32 BranchIndex=0; BranchIndex<BlendPose.BranchFilters.Num(); ++BranchIndex)
{
const FBranchFilter& BranchFilter = BlendPose.BranchFilters[BranchIndex];
int32 MaskBoneIndex = RequiredBones.GetPoseBoneIndexForBoneName(BranchFilter.BoneName);
// how much weight increase Per depth
float MaxWeight = (BranchFilter.BlendDepth > 0) ? 1.f : -1.f;
float IncreaseWeightPerDepth = (BranchFilter.BlendDepth != 0) ? (1.f/((float)BranchFilter.BlendDepth)) : 1.f;
// go through skeleton tree requiredboneindices
for (int32 BoneIndex = 0; BoneIndex<RequiredBoneIndices.Num(); ++BoneIndex)
{
int32 MeshBoneIndex = RequiredBoneIndices[BoneIndex];
int32 Depth = RequiredBones.GetDepthBetweenBones(MeshBoneIndex, MaskBoneIndex);
// if Depth == -1, it's not a child
if( Depth != -1 )
{
// when you write to buffer, you'll need to match with BasePoses BoneIndex
FPerBoneBlendWeight& BoneBlendWeight = BoneBlendWeights[BoneIndex];
BoneBlendWeight.SourceIndex = PoseIndex;
float BlendIncrease = IncreaseWeightPerDepth * (float)(Depth + 1);
BoneBlendWeight.BlendWeight = FMath::Clamp<float>(BoneBlendWeight.BlendWeight + BlendIncrease, 0.f, 1.f);
}
}
}
}
}
}
示例6: ApplyWeightToTransform
/**
* Scale transforms by Weight.
* Result is obviously NOT normalized.
*/
void FAnimationRuntime::ApplyWeightToTransform(const FBoneContainer& RequiredBones, /*inout*/ FTransformArrayA2& Atoms, float Weight)
{
const TArray<FBoneIndexType> & RequiredBoneIndices = RequiredBones.GetBoneIndicesArray();
ScalarRegister MultWeight(Weight);
for (int32 j = 0; j < RequiredBoneIndices.Num(); ++j)
{
const int32 BoneIndex = RequiredBoneIndices[j];
Atoms[BoneIndex] *= MultWeight;
}
}
示例7: Initialize
bool FBoneReference::Initialize(const FBoneContainer& RequiredBones)
{
BoneName = *BoneName.ToString().Trim().TrimTrailing();
BoneIndex = RequiredBones.GetPoseBoneIndexForBoneName(BoneName);
// If bone name is not found, look into the master skeleton to see if it's found there.
// SkeletalMeshes can exclude bones from the master skeleton, and that's OK.
// If it's not found in the master skeleton, the bone does not exist at all! so we should report it as a warning.
if( (BoneIndex == INDEX_NONE) && RequiredBones.GetSkeletonAsset() )
{
if( RequiredBones.GetSkeletonAsset()->GetReferenceSkeleton().FindBoneIndex(BoneName) == INDEX_NONE )
{
UE_LOG(LogAnimation, Warning, TEXT("FBoneReference::Initialize BoneIndex for Bone '%s' does not exist in Skeleton '%s'"),
*BoneName.ToString(), *GetNameSafe(RequiredBones.GetSkeletonAsset()));
}
}
return (BoneIndex != INDEX_NONE);
}
示例8: IsValidToEvaluate
bool FAnimNode_Fabrik::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
{
// Allow evaluation if all parameters are initialized and TipBone is child of RootBone
return
(
TipBone.IsValid(RequiredBones)
&& RootBone.IsValid(RequiredBones)
&& Precision > 0
&& RequiredBones.BoneIsChildOf(TipBone.BoneIndex, RootBone.BoneIndex)
);
}
示例9:
void FA2CSPose::AllocateLocalPoses(const FBoneContainer& InBoneContainer, const FTransformArrayA2 & LocalBones)
{
check( InBoneContainer.IsValid() );
BoneContainer = &InBoneContainer;
Bones = LocalBones;
ComponentSpaceFlags.Init(0, Bones.Num());
// root is same, so set root first
check(ComponentSpaceFlags.Num() > 0);
ComponentSpaceFlags[0] = 1;
}
示例10: GetPerBoneInterpolationIndex
// @todo fixme: slow approach. If the perbone gets popular, we should change this to array of weight
// we should think about changing this to
int32 UBlendSpaceBase::GetPerBoneInterpolationIndex(int32 BoneIndex, const FBoneContainer& RequiredBones) const
{
for (int32 Iter=0; Iter<PerBoneBlend.Num(); ++Iter)
{
// we would like to make sure if
if (PerBoneBlend[Iter].BoneReference.IsValid(RequiredBones) && RequiredBones.BoneIsChildOf(BoneIndex, PerBoneBlend[Iter].BoneReference.BoneIndex))
{
return Iter;
}
}
return INDEX_NONE;
}
示例11: CombineWithAdditiveAnimations
void FAnimationRuntime::CombineWithAdditiveAnimations(int32 NumAdditivePoses, const FTransformArrayA2** SourceAdditivePoses, const float* SourceAdditiveWeights, const FBoneContainer& RequiredBones, /*inout*/ FTransformArrayA2& Atoms)
{
const TArray<FBoneIndexType> & RequiredBoneIndices = RequiredBones.GetBoneIndicesArray();
for (int32 PoseIndex = 0; PoseIndex < NumAdditivePoses; ++PoseIndex)
{
const ScalarRegister VBlendWeight(SourceAdditiveWeights[PoseIndex]);
const FTransformArrayA2& SourceAtoms = *SourceAdditivePoses[PoseIndex];
for (int32 j = 0; j < RequiredBoneIndices.Num(); ++j)
{
const int32 BoneIndex = RequiredBoneIndices[j];
FTransform SourceAtom = SourceAtoms[BoneIndex];
FTransform::BlendFromIdentityAndAccumulate(Atoms[BoneIndex], SourceAtom, VBlendWeight);
}
}
}
示例12: EvaluateBoneTransforms
void FAnimNode_TwoBoneIK::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer & RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
// Get indices of the lower and upper limb bones and check validity.
bool bInvalidLimb = false;
const int32 EndBoneIndex = IKBone.BoneIndex;
const int32 LowerLimbIndex = RequiredBones.GetParentBoneIndex(EndBoneIndex);
if (LowerLimbIndex == INDEX_NONE)
{
bInvalidLimb = true;
}
const int32 UpperLimbIndex = RequiredBones.GetParentBoneIndex(LowerLimbIndex);
if (UpperLimbIndex == INDEX_NONE)
{
bInvalidLimb = true;
}
const bool bInBoneSpace = (EffectorLocationSpace == BCS_ParentBoneSpace) || (EffectorLocationSpace == BCS_BoneSpace);
const int32 EffectorSpaceBoneIndex = bInBoneSpace ? RequiredBones.GetPoseBoneIndexForBoneName(EffectorSpaceBoneName) : INDEX_NONE;
if (bInBoneSpace && ((EffectorSpaceBoneIndex == INDEX_NONE) || !RequiredBones.Contains(EffectorSpaceBoneIndex)))
{
bInvalidLimb = true;
}
// If we walked past the root, this controlled is invalid, so return no affected bones.
if( bInvalidLimb )
{
return;
}
// Get Local Space transforms for our bones. We do this first in case they already are local.
// As right after we get them in component space. (And that does the auto conversion).
// We might save one transform by doing local first...
const FTransform EndBoneLocalTransform = MeshBases.GetLocalSpaceTransform(IKBone.BoneIndex);
// Now get those in component space...
FTransform UpperLimbCSTransform = MeshBases.GetComponentSpaceTransform(UpperLimbIndex);
FTransform LowerLimbCSTransform = MeshBases.GetComponentSpaceTransform(LowerLimbIndex);
FTransform EndBoneCSTransform = MeshBases.GetComponentSpaceTransform(IKBone.BoneIndex);
// Get current position of root of limb.
// All position are in Component space.
const FVector RootPos = UpperLimbCSTransform.GetTranslation();
const FVector InitialJointPos = LowerLimbCSTransform.GetTranslation();
const FVector InitialEndPos = EndBoneCSTransform.GetTranslation();
// Transform EffectorLocation from EffectorLocationSpace to ComponentSpace.
FTransform EffectorTransform(EffectorLocation);
FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, EffectorTransform, EffectorSpaceBoneIndex, EffectorLocationSpace);
// This is our reach goal.
FVector DesiredPos = EffectorTransform.GetTranslation();
FVector DesiredDelta = DesiredPos - RootPos;
float DesiredLength = DesiredDelta.Size();
// Check to handle case where DesiredPos is the same as RootPos.
FVector DesiredDir;
if (DesiredLength < (float)KINDA_SMALL_NUMBER)
{
DesiredLength = (float)KINDA_SMALL_NUMBER;
DesiredDir = FVector(1,0,0);
}
else
{
DesiredDir = DesiredDelta / DesiredLength;
}
// Get joint target (used for defining plane that joint should be in).
FTransform JointTargetTransform(JointTargetLocation);
const int32 JointTargetSpaceBoneIndex = (JointTargetLocationSpace == BCS_ParentBoneSpace || JointTargetLocationSpace == BCS_BoneSpace) ? RequiredBones.GetPoseBoneIndexForBoneName(JointTargetSpaceBoneName) : INDEX_NONE;
FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, JointTargetTransform, JointTargetSpaceBoneIndex, JointTargetLocationSpace);
FVector JointTargetPos = JointTargetTransform.GetTranslation();
FVector JointTargetDelta = JointTargetPos - RootPos;
float JointTargetLength = JointTargetDelta.Size();
// Same check as above, to cover case when JointTarget position is the same as RootPos.
FVector JointPlaneNormal, JointBendDir;
if (JointTargetLength < (float)KINDA_SMALL_NUMBER)
{
JointBendDir = FVector(0,1,0);
JointPlaneNormal = FVector(0,0,1);
}
else
{
JointPlaneNormal = DesiredDir ^ JointTargetDelta;
// If we are trying to point the limb in the same direction that we are supposed to displace the joint in,
// we have to just pick 2 random vector perp to DesiredDir and each other.
if (JointPlaneNormal.Size() < (float)KINDA_SMALL_NUMBER)
{
DesiredDir.FindBestAxisVectors(JointPlaneNormal, JointBendDir);
}
else
{
JointPlaneNormal.Normalize();
//.........这里部分代码省略.........
示例13: IsValid
bool FBoneReference::IsValid(const FBoneContainer& RequiredBones) const
{
return (BoneIndex != INDEX_NONE && RequiredBones.Contains(BoneIndex));
}
示例14: EvaluateBoneTransforms
void FAnimNode_Trail::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer& RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
check(OutBoneTransforms.Num() == 0);
if( ChainLength < 2 )
{
return;
}
// The incoming BoneIndex is the 'end' of the spline chain. We need to find the 'start' by walking SplineLength bones up hierarchy.
// Fail if we walk past the root bone.
int32 WalkBoneIndex = TrailBone.BoneIndex;
TArray<int32> ChainBoneIndices;
ChainBoneIndices.AddZeroed(ChainLength);
ChainBoneIndices[ChainLength - 1] = WalkBoneIndex;
for (int32 i = 1; i < ChainLength; i++)
{
// returns to avoid a crash
// @TODO : shows an error message why failed
if (WalkBoneIndex == 0)
{
return;
}
// Get parent bone.
WalkBoneIndex = RequiredBones.GetParentBoneIndex(WalkBoneIndex);
//Insert indices at the start of array, so that parents are before children in the array.
int32 TransformIndex = ChainLength - (i + 1);
ChainBoneIndices[TransformIndex] = WalkBoneIndex;
}
OutBoneTransforms.AddZeroed(ChainLength);
// If we have >0 this frame, but didn't last time, record positions of all the bones.
// Also do this if number has changed or array is zero.
bool bHasValidStrength = (Alpha > 0.f);
if(TrailBoneLocations.Num() != ChainLength || (bHasValidStrength && !bHadValidStrength))
{
TrailBoneLocations.Empty();
TrailBoneLocations.AddZeroed(ChainLength);
for(int32 i=0; i<ChainBoneIndices.Num(); i++)
{
int32 ChildIndex = ChainBoneIndices[i];
FTransform ChainTransform = MeshBases.GetComponentSpaceTransform(ChildIndex);
TrailBoneLocations[i] = ChainTransform.GetTranslation();
}
OldLocalToWorld = SkelComp->GetTransformMatrix();
}
bHadValidStrength = bHasValidStrength;
// transform between last frame and now.
FMatrix OldToNewTM = OldLocalToWorld * SkelComp->GetTransformMatrix().InverseFast();
// Add fake velocity if present to all but root bone
if(!FakeVelocity.IsZero())
{
FVector FakeMovement = -FakeVelocity * ThisTimstep;
if (bActorSpaceFakeVel && SkelComp->GetOwner())
{
const FTransform BoneToWorld(SkelComp->GetOwner()->GetActorRotation(), SkelComp->GetOwner()->GetActorLocation());
FakeMovement = BoneToWorld.TransformVector(FakeMovement);
}
FakeMovement = SkelComp->GetTransformMatrix().InverseTransformVector(FakeMovement);
// Then add to each bone
for(int32 i=1; i<TrailBoneLocations.Num(); i++)
{
TrailBoneLocations[i] += FakeMovement;
}
}
// Root bone of trail is not modified.
int32 RootIndex = ChainBoneIndices[0];
FTransform ChainTransform = MeshBases.GetComponentSpaceTransform(RootIndex);
OutBoneTransforms[0] = FBoneTransform(RootIndex, ChainTransform);
TrailBoneLocations[0] = ChainTransform.GetTranslation();
// Starting one below head of chain, move bones.
for(int32 i=1; i<ChainBoneIndices.Num(); i++)
{
// Parent bone position in component space.
int32 ParentIndex = ChainBoneIndices[i-1];
FVector ParentPos = TrailBoneLocations[i-1];
FVector ParentAnimPos = MeshBases.GetComponentSpaceTransform(ParentIndex).GetTranslation();
// Child bone position in component space.
int32 ChildIndex = ChainBoneIndices[i];
FVector ChildPos = OldToNewTM.TransformPosition(TrailBoneLocations[i]); // move from 'last frames component' frame to 'this frames component' frame
FVector ChildAnimPos = MeshBases.GetComponentSpaceTransform(ChildIndex).GetTranslation();
// Desired parent->child offset.
FVector TargetDelta = (ChildAnimPos - ParentAnimPos);
//.........这里部分代码省略.........
示例15: EvaluateBoneTransforms
void FAnimNode_Fabrik::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer& RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
// IsValidToEvaluate validated our inputs, we don't need to check pre-requisites again.
int32 const RootIndex = RootBone.BoneIndex;
// Update EffectorLocation if it is based off a bone position
FTransform CSEffectorTransform = FTransform(EffectorTransform);
FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, CSEffectorTransform, EffectorTransformBone.BoneIndex, EffectorTransformSpace);
FVector const CSEffectorLocation = CSEffectorTransform.GetLocation();
// @fixme - we need better to draw widgets and debug information in editor.
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (bEnableDebugDraw)
{
// Show end effector position.
DrawDebugBox(SkelComp->GetWorld(), CSEffectorLocation, FVector(Precision), FColor::Green, true, 0.1f);
DrawDebugCoordinateSystem(SkelComp->GetWorld(), CSEffectorLocation, CSEffectorTransform.GetRotation().Rotator(), 5.f, true, 0.1f);
}
#endif
// Gather all bone indices between root and tip.
TArray<int32> BoneIndices;
{
int32 BoneIndex = TipBone.BoneIndex;
do
{
BoneIndices.Insert(BoneIndex, 0);
BoneIndex = RequiredBones.GetParentBoneIndex(BoneIndex);
} while (BoneIndex != RootIndex);
BoneIndices.Insert(BoneIndex, 0);
}
// Maximum length of skeleton segment at full extension
float MaximumReach = 0;
// Gather transforms
int32 const NumTransforms = BoneIndices.Num();
OutBoneTransforms.AddUninitialized(NumTransforms);
// Gather chain links. These are non zero length bones.
TArray<FABRIKChainLink> Chain;
Chain.Reserve(NumTransforms);
// Start with Root Bone
{
int32 const & RootBoneIndex = BoneIndices[0];
FTransform const BoneCSTransform = MeshBases.GetComponentSpaceTransform(RootBoneIndex);
OutBoneTransforms[0] = FBoneTransform(RootBoneIndex, BoneCSTransform);
Chain.Add(FABRIKChainLink(BoneCSTransform.GetLocation(), 0.f, RootBoneIndex, 0));
}
// Go through remaining transforms
for (int32 TransformIndex = 1; TransformIndex < NumTransforms; TransformIndex++)
{
int32 const & BoneIndex = BoneIndices[TransformIndex];
FTransform const BoneCSTransform = MeshBases.GetComponentSpaceTransform(BoneIndex);
FVector const BoneCSPosition = BoneCSTransform.GetLocation();
OutBoneTransforms[TransformIndex] = FBoneTransform(BoneIndex, BoneCSTransform);
// Calculate the combined length of this segment of skeleton
float const BoneLength = FVector::Dist(BoneCSPosition, OutBoneTransforms[TransformIndex-1].Transform.GetLocation());
if (!FMath::IsNearlyZero(BoneLength))
{
Chain.Add(FABRIKChainLink(BoneCSPosition, BoneLength, BoneIndex, TransformIndex));
MaximumReach += BoneLength;
}
else
{
// Mark this transform as a zero length child of the last link.
// It will inherit position and delta rotation from parent link.
FABRIKChainLink & ParentLink = Chain[Chain.Num()-1];
ParentLink.ChildZeroLengthTransformIndices.Add(TransformIndex);
}
}
bool bBoneLocationUpdated = false;
float const RootToTargetDist = FVector::Dist(Chain[0].Position, CSEffectorLocation);
int32 const NumChainLinks = Chain.Num();
// FABRIK algorithm - bone translation calculation
// If the effector is further away than the distance from root to tip, simply move all bones in a line from root to effector location
if (RootToTargetDist > MaximumReach)
{
for (int32 LinkIndex = 1; LinkIndex < NumChainLinks; LinkIndex++)
{
FABRIKChainLink const & ParentLink = Chain[LinkIndex - 1];
FABRIKChainLink & CurrentLink = Chain[LinkIndex];
CurrentLink.Position = ParentLink.Position + (CSEffectorLocation - ParentLink.Position).GetUnsafeNormal() * CurrentLink.Length;
}
bBoneLocationUpdated = true;
}
else // Effector is within reach, calculate bone translations to position tip at effector location
{
int32 const TipBoneLinkIndex = NumChainLinks - 1;
// Check distance between tip location and effector location
float Slop = FVector::Dist(Chain[TipBoneLinkIndex].Position, CSEffectorLocation);
//.........这里部分代码省略.........