You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Merging
//Tasks/Fortnite/Dev-UEA-ControlRig/Engine/...
to //Fortnite/Main/Engine/...
Original CL: 6081637
#jira: UEA-490
#rb lina.halper
#ROBOMERGE-OWNER: ben.marsh
#ROBOMERGE-AUTHOR: helge.mathee
#ROBOMERGE-SOURCE: CL 6098916 via CL 6100686 via CL 6100754
#ROBOMERGE-BOT: BUILD (Main -> Dev-Build)
[CL 6124553 by helge mathee in Dev-Build branch]
This commit is contained in:
@@ -85,7 +85,7 @@ struct FRigUnit_AimBone_DebugSettings
|
||||
* Aligns the rotation of a primary and secondary axis of a bone to a world target.
|
||||
* Note: This node operates in world space!
|
||||
*/
|
||||
USTRUCT(meta=(DisplayName="Aim", Keywords="Lookat"))
|
||||
USTRUCT(meta=(DisplayName="Aim", Category="Hierarchy", Keywords="Lookat"))
|
||||
struct FRigUnit_AimBone : public FRigUnit_HighlevelBaseMutable
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
@@ -1,57 +1,123 @@
|
||||
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
||||
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "RigUnit_FABRIK.h"
|
||||
#include "Units/RigUnitContext.h"
|
||||
|
||||
void FRigUnit_FABRIK::Execute(const FRigUnitContext& Context)
|
||||
{
|
||||
FRigHierarchyRef& HierarchyRef = ExecuteContext.HierarchyReference;
|
||||
FRigHierarchy* Hierarchy = (FRigHierarchy*)(Context.HierarchyReference.Get());
|
||||
if (Hierarchy == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Context.State == EControlRigState::Init)
|
||||
{
|
||||
const FRigHierarchy* Hierarchy = HierarchyRef.Get();
|
||||
if (Hierarchy)
|
||||
{
|
||||
FullLimbLength = 0.f;
|
||||
BoneIndices.Reset();
|
||||
|
||||
// verify the chain
|
||||
const int32 RootIndex = Hierarchy->GetIndex(StartJoint);
|
||||
if (RootIndex != INDEX_NONE)
|
||||
// verify the chain
|
||||
const int32 RootIndex = Hierarchy->GetIndex(StartBone);
|
||||
if (RootIndex != INDEX_NONE)
|
||||
{
|
||||
int32 CurrentIndex = EffectorIndex = Hierarchy->GetIndex(EffectorBone);
|
||||
while (CurrentIndex != INDEX_NONE)
|
||||
{
|
||||
int32 CurrentIndex = Hierarchy->GetIndex(EndJoint);
|
||||
while (CurrentIndex != INDEX_NONE)
|
||||
// ensure the chain
|
||||
int32 ParentIndex = Hierarchy->GetParentIndex(CurrentIndex);
|
||||
if (ParentIndex != INDEX_NONE)
|
||||
{
|
||||
// ensure the chain
|
||||
int32 ParentIndex = Hierarchy->GetParentIndex(CurrentIndex);
|
||||
if (ParentIndex != INDEX_NONE)
|
||||
{
|
||||
// set length for upper/lower length
|
||||
FTransform ParentTransform = Hierarchy->GetGlobalTransform(ParentIndex);
|
||||
FTransform CurrentTransform = Hierarchy->GetGlobalTransform(CurrentIndex);
|
||||
FVector Length = ParentTransform.GetLocation() - CurrentTransform.GetLocation();
|
||||
FullLimbLength += Length.Size();
|
||||
}
|
||||
|
||||
if (ParentIndex == RootIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentIndex = ParentIndex;
|
||||
BoneIndices.Add(CurrentIndex);
|
||||
}
|
||||
|
||||
if (ParentIndex == RootIndex)
|
||||
{
|
||||
BoneIndices.Add(RootIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
CurrentIndex = ParentIndex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UnitLogHelpers::PrintMissingHierarchy(RigUnitName);
|
||||
|
||||
Chain.Reserve(BoneIndices.Num());
|
||||
}
|
||||
}
|
||||
else if (Context.State == EControlRigState::Update)
|
||||
{
|
||||
if (FullLimbLength > 0.f)
|
||||
if (BoneIndices.Num() > 0)
|
||||
{
|
||||
UnitLogHelpers::PrintUnimplemented(RigUnitName);
|
||||
// Gather chain links. These are non zero length bones.
|
||||
Chain.Reset();
|
||||
|
||||
TArray<FTransform> Transforms;
|
||||
Transforms.AddDefaulted(BoneIndices.Num());
|
||||
|
||||
float MaximumReach = 0.f;
|
||||
int32 const NumChainLinks = BoneIndices.Num();
|
||||
const int32 RootIndex = BoneIndices.Last();
|
||||
Chain.Add(FABRIKChainLink(Hierarchy->GetGlobalTransform(RootIndex).GetLocation(), 0.f, RootIndex, 0));
|
||||
Transforms[0] = Hierarchy->GetGlobalTransform(RootIndex);
|
||||
|
||||
// start from child to up
|
||||
for (int32 ChainIndex = BoneIndices.Num() - 2; ChainIndex >= 0 ; --ChainIndex)
|
||||
{
|
||||
const FTransform& BoneTransform = Hierarchy->GetGlobalTransform(BoneIndices[ChainIndex]);
|
||||
const FTransform& ParentTransform = Hierarchy->GetGlobalTransform(BoneIndices[ChainIndex + 1]);
|
||||
|
||||
// Calculate the combined length of this segment of skeleton
|
||||
float const BoneLength = FVector::Dist(BoneTransform.GetLocation(), ParentTransform.GetLocation());
|
||||
|
||||
const int32 TransformIndex = Chain.Num();
|
||||
Chain.Add(FABRIKChainLink(BoneTransform.GetLocation(), BoneLength, BoneIndices[ChainIndex], TransformIndex));
|
||||
MaximumReach += BoneLength;
|
||||
|
||||
Transforms[TransformIndex] = BoneTransform;
|
||||
}
|
||||
|
||||
|
||||
bool bBoneLocationUpdated = AnimationCore::SolveFabrik(Chain, EffectorTransform.GetLocation(), MaximumReach, Precision, MaxIterations);
|
||||
// If we moved some bones, update bone transforms.
|
||||
if (bBoneLocationUpdated)
|
||||
{
|
||||
// FABRIK algorithm - re-orientation of bone local axes after translation calculation
|
||||
for (int32 LinkIndex = 0; LinkIndex < NumChainLinks - 1; LinkIndex++)
|
||||
{
|
||||
const FABRIKChainLink& CurrentLink = Chain[LinkIndex];
|
||||
const FABRIKChainLink& ChildLink = Chain[LinkIndex + 1];
|
||||
|
||||
// Calculate pre-translation vector between this bone and child
|
||||
FVector const OldDir = (Hierarchy->GetGlobalTransform(ChildLink.BoneIndex).GetLocation() - Hierarchy->GetGlobalTransform(CurrentLink.BoneIndex).GetLocation()).GetUnsafeNormal();
|
||||
|
||||
// Get vector from the post-translation bone to it's child
|
||||
FVector const NewDir = (ChildLink.Position - CurrentLink.Position).GetUnsafeNormal();
|
||||
|
||||
// Calculate axis of rotation from pre-translation vector to post-translation vector
|
||||
FVector const RotationAxis = FVector::CrossProduct(OldDir, NewDir).GetSafeNormal();
|
||||
float const RotationAngle = FMath::Acos(FVector::DotProduct(OldDir, NewDir));
|
||||
FQuat const DeltaRotation = FQuat(RotationAxis, RotationAngle);
|
||||
// We're going to multiply it, in order to not have to re-normalize the final quaternion, it has to be a unit quaternion.
|
||||
checkSlow(DeltaRotation.IsNormalized());
|
||||
|
||||
// Calculate absolute rotation and set it
|
||||
FTransform& CurrentBoneTransform = Transforms[CurrentLink.TransformIndex];
|
||||
CurrentBoneTransform.SetRotation(DeltaRotation * CurrentBoneTransform.GetRotation());
|
||||
CurrentBoneTransform.NormalizeRotation();
|
||||
CurrentBoneTransform.SetTranslation(CurrentLink.Position);
|
||||
}
|
||||
|
||||
// fill up the last data transform
|
||||
const FABRIKChainLink & CurrentLink = Chain[NumChainLinks - 1];
|
||||
FTransform& CurrentBoneTransform = Transforms[CurrentLink.TransformIndex];
|
||||
CurrentBoneTransform.SetTranslation(CurrentLink.Position);
|
||||
CurrentBoneTransform.SetRotation(Hierarchy->GetGlobalTransform(CurrentLink.BoneIndex).GetRotation());
|
||||
|
||||
for (int32 LinkIndex = 0; LinkIndex < NumChainLinks; LinkIndex++)
|
||||
{
|
||||
FABRIKChainLink const & LocalLink = Chain[LinkIndex];
|
||||
Hierarchy->SetGlobalTransform(LocalLink.BoneIndex, Transforms[LocalLink.TransformIndex]);
|
||||
}
|
||||
|
||||
Hierarchy->SetGlobalTransform(EffectorIndex, EffectorTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,48 +2,61 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Units/RigUnit.h"
|
||||
#include "Hierarchy.h"
|
||||
#include "ControlRigDefines.h"
|
||||
#include "Units/Highlevel/RigUnit_HighlevelBase.h"
|
||||
#include "FABRIK.h"
|
||||
#include "RigUnit_FABRIK.generated.h"
|
||||
|
||||
/**
|
||||
* Spec define: TBD
|
||||
/**
|
||||
* The FABRIK solver can solve N-Bone chains using
|
||||
* the Forward and Backward Reaching Inverse Kinematics algorithm.
|
||||
* For now this node supports single effector chains only.
|
||||
*/
|
||||
|
||||
// make it abstract since it's not working yet
|
||||
USTRUCT(meta=(DisplayName="FABRIK", Category="Transforms", Abstract))
|
||||
struct CONTROLRIG_API FRigUnit_FABRIK : public FRigUnitMutable
|
||||
USTRUCT(meta=(DisplayName="Basic FABRIK", Category="Hierarchy", Keywords="N-Bone,IK"))
|
||||
struct FRigUnit_FABRIK : public FRigUnit_HighlevelBaseMutable
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
virtual void Execute(const FRigUnitContext& Context) override;
|
||||
|
||||
FRigUnit_FABRIK()
|
||||
: Precision(1.f)
|
||||
, MaxIterations(10)
|
||||
, FullLimbLength(0.f)
|
||||
{}
|
||||
{
|
||||
EffectorIndex = INDEX_NONE;
|
||||
Precision = 1.f;
|
||||
MaxIterations = 10;
|
||||
EffectorTransform = FTransform::Identity;
|
||||
}
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "FABRIK", meta = (Input))
|
||||
FName StartJoint;
|
||||
/**
|
||||
* The first bone in the chain to solve
|
||||
*/
|
||||
UPROPERTY(meta = (Input, Constant, BoneName))
|
||||
FName StartBone;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "FABRIK", meta = (Input))
|
||||
FName EndJoint;
|
||||
/**
|
||||
* The last bone in the chain to solve - the effector
|
||||
*/
|
||||
UPROPERTY(meta = (Input, Constant, BoneName))
|
||||
FName EffectorBone;
|
||||
|
||||
/** Tolerance for final tip location delta from EffectorLocation*/
|
||||
UPROPERTY(EditAnywhere, Category = Solver)
|
||||
/**
|
||||
* The transform of the effector in global space
|
||||
*/
|
||||
UPROPERTY(meta = (Input))
|
||||
FTransform EffectorTransform;
|
||||
|
||||
/**
|
||||
* The precision to use for the fabrik solver
|
||||
*/
|
||||
UPROPERTY(meta = (Input, Constant))
|
||||
float Precision;
|
||||
|
||||
/** Maximum number of iterations allowed, to control performance. */
|
||||
UPROPERTY(EditAnywhere, Category = Solver)
|
||||
/**
|
||||
* The maximum number of iterations. Values between 4 and 16 are common.
|
||||
*/
|
||||
UPROPERTY(meta = (Input))
|
||||
int32 MaxIterations;
|
||||
|
||||
private:
|
||||
TArray<FABRIKChainLink> ChainLink;
|
||||
|
||||
// by default, it is full skeleton length
|
||||
// we can support stretch option
|
||||
float FullLimbLength;
|
||||
TArray<FABRIKChainLink> Chain;
|
||||
TArray<int32> BoneIndices;
|
||||
int32 EffectorIndex;
|
||||
};
|
||||
|
||||
@@ -40,7 +40,7 @@ struct FRigUnit_TwoBoneIKSimple_DebugSettings
|
||||
* Aligns the rotation of a primary and secondary axis of a bone to a world target.
|
||||
* Note: This node operates in world space!
|
||||
*/
|
||||
USTRUCT(meta=(DisplayName="Basic IK", Keywords="TwoBone,IK"))
|
||||
USTRUCT(meta=(DisplayName="Basic IK", Category="Hierarchy", Keywords="TwoBone,IK"))
|
||||
struct FRigUnit_TwoBoneIKSimple : public FRigUnit_HighlevelBaseMutable
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
@@ -148,7 +148,7 @@ void FAnimNode_Fabrik::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseCont
|
||||
FABRIKChainLink const & ChildLink = Chain[LinkIndex + 1];
|
||||
|
||||
// Calculate pre-translation vector between this bone and child
|
||||
FVector const OldDir = (GetCurrentLocation(Output.Pose, ChildLink.BoneIndex) - GetCurrentLocation(Output.Pose, CurrentLink.BoneIndex)).GetUnsafeNormal();
|
||||
FVector const OldDir = (GetCurrentLocation(Output.Pose, FCompactPoseBoneIndex(ChildLink.BoneIndex)) - GetCurrentLocation(Output.Pose, FCompactPoseBoneIndex(CurrentLink.BoneIndex))).GetUnsafeNormal();
|
||||
|
||||
// Get vector from the post-translation bone to it's child
|
||||
FVector const NewDir = (ChildLink.Position - CurrentLink.Position).GetUnsafeNormal();
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
float Length;
|
||||
|
||||
/** Bone Index in SkeletalMesh */
|
||||
FCompactPoseBoneIndex BoneIndex;
|
||||
int32 BoneIndex;
|
||||
|
||||
/** Transform Index that this control will output */
|
||||
int32 TransformIndex;
|
||||
@@ -45,21 +45,30 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
FABRIKChainLink(const FVector& InPosition, const float& InLength, const FCompactPoseBoneIndex& InBoneIndex, const int32& InTransformIndex)
|
||||
FABRIKChainLink(const FVector& InPosition, const float InLength, const FCompactPoseBoneIndex& InBoneIndex, const int32& InTransformIndex)
|
||||
: Position(InPosition)
|
||||
, Length(InLength)
|
||||
, BoneIndex(InBoneIndex)
|
||||
, BoneIndex(InBoneIndex.GetInt())
|
||||
, TransformIndex(InTransformIndex)
|
||||
, DefaultDirToParent(FVector(-1.f, 0.f, 0.f))
|
||||
{
|
||||
}
|
||||
|
||||
FABRIKChainLink(const FVector& InPosition, const float& InLength, const FCompactPoseBoneIndex& InBoneIndex, const int32& InTransformIndex, const FVector& InDefaultDirToParent)
|
||||
FABRIKChainLink(const FVector& InPosition, const float InLength, const FCompactPoseBoneIndex& InBoneIndex, const int32& InTransformIndex, const FVector& InDefaultDirToParent)
|
||||
: Position(InPosition)
|
||||
, Length(InLength)
|
||||
, BoneIndex(InBoneIndex.GetInt())
|
||||
, TransformIndex(InTransformIndex)
|
||||
, DefaultDirToParent(InDefaultDirToParent)
|
||||
{
|
||||
}
|
||||
|
||||
FABRIKChainLink(const FVector& InPosition, const float InLength, const int32 InBoneIndex, const int32 InTransformIndex)
|
||||
: Position(InPosition)
|
||||
, Length(InLength)
|
||||
, BoneIndex(InBoneIndex)
|
||||
, TransformIndex(InTransformIndex)
|
||||
, DefaultDirToParent(InDefaultDirToParent)
|
||||
, DefaultDirToParent(FVector(-1.f, 0.f, 0.f))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -79,7 +88,7 @@ namespace AnimationCore
|
||||
* @param Precision Precision
|
||||
* @param MaxIteration Number of Max Iteration
|
||||
*
|
||||
* @return true if modified. False if not.
|
||||
* @return true if modified. False if not.
|
||||
*/
|
||||
ANIMATIONCORE_API bool SolveFabrik(TArray<FABRIKChainLink>& InOutChain, const FVector& TargetPosition, float MaximumReach, float Precision, int32 MaxIteration);
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user