improved virtual hand model animation
This commit is contained in:
@@ -48,41 +48,6 @@
|
||||
#include "SGCore/SGHandPose.h"
|
||||
#include "SGLog/SGLog.h"
|
||||
|
||||
const FName& FSGVirtualHandAnimInstanceProxy::GetLeftHandBoneName(const int32 Finger, const int32 Joint)
|
||||
{
|
||||
static const TArray<TArray<FName>> BoneNames{
|
||||
{FName(TEXT("thumb_01_l")), FName(TEXT("thumb_02_l")), FName(TEXT("thumb_03_l"))},
|
||||
{FName(TEXT("index_01_l")), FName(TEXT("index_02_l")), FName(TEXT("index_03_l"))},
|
||||
{FName(TEXT("middle_01_l")), FName(TEXT("middle_02_l")), FName(TEXT("middle_03_l"))},
|
||||
{FName(TEXT("ring_01_l")), FName(TEXT("ring_02_l")), FName(TEXT("ring_03_l"))},
|
||||
{FName(TEXT("pinky_01_l")), FName(TEXT("pinky_02_l")), FName(TEXT("pinky_03_l"))},
|
||||
};
|
||||
|
||||
ensureAlwaysMsgf(Finger < BoneNames.Num(), TEXT("Finger index is out of bound!"));
|
||||
ensureAlwaysMsgf(Joint < BoneNames[Finger].Num(), TEXT("Joint index is out of bound!"));
|
||||
|
||||
const FName& BoneName = BoneNames[Finger][Joint];
|
||||
return BoneName;
|
||||
}
|
||||
|
||||
const FName& FSGVirtualHandAnimInstanceProxy::GetRightHandBoneName(const int32 Finger, const int32 Joint)
|
||||
{
|
||||
static const TArray<TArray<FName>> BoneNames{
|
||||
{FName(TEXT("thumb_01_r")), FName(TEXT("thumb_02_r")), FName(TEXT("thumb_03_r"))},
|
||||
{FName(TEXT("index_01_r")), FName(TEXT("index_02_r")), FName(TEXT("index_03_r"))},
|
||||
{FName(TEXT("middle_01_r")), FName(TEXT("middle_02_r")), FName(TEXT("middle_03_r"))},
|
||||
{FName(TEXT("ring_01_r")), FName(TEXT("ring_02_r")), FName(TEXT("ring_03_r"))},
|
||||
{FName(TEXT("pinky_01_r")), FName(TEXT("pinky_02_r")), FName(TEXT("pinky_03_r"))},
|
||||
};
|
||||
|
||||
ensureAlwaysMsgf(Finger < BoneNames.Num(), TEXT("Finger index is out of bound!"));
|
||||
ensureAlwaysMsgf(Joint < BoneNames[Finger].Num(), TEXT("Joint index is out of bound!"));
|
||||
|
||||
const FName& BoneName = BoneNames[Finger][Joint];
|
||||
return BoneName;
|
||||
}
|
||||
|
||||
|
||||
FSGVirtualHandAnimInstanceProxy::FSGVirtualHandAnimInstanceProxy()
|
||||
: FAnimInstanceProxy()
|
||||
{
|
||||
@@ -128,44 +93,8 @@ void FSGVirtualHandAnimInstanceProxy::PreEvaluateAnimation(UAnimInstance* InAnim
|
||||
return;
|
||||
}
|
||||
|
||||
const USGHandPose* HandPose = Hand->GetHandPose();
|
||||
if (!IsValid(HandPose))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BoneMap.Empty();
|
||||
|
||||
const TArray<TArray<FRotator>> JointRotations = HandPose->GetJointRotations();
|
||||
|
||||
for (int32 FingerIndex = 0; FingerIndex < JointRotations.Num(); ++FingerIndex)
|
||||
{
|
||||
const TArray<FRotator>& FingerJointRotations = JointRotations[FingerIndex];
|
||||
|
||||
for (int32 JointIndex = 0; JointIndex < FingerJointRotations.Num(); ++JointIndex)
|
||||
{
|
||||
// FIXME ?
|
||||
// Ignore the 4th joint.
|
||||
if (JointIndex >= 3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FRotator JointRotation{FingerJointRotations[JointIndex]};
|
||||
/*const FRotator JointRotation{FingerJointRotations[JointIndex]};
|
||||
const FQuat JointQuat{JointRotation.Quaternion()};
|
||||
const FRotator ReferenceRotation{Hand->GetActorRotation()};
|
||||
const FQuat ReferenceQuat{ReferenceRotation.Quaternion()};
|
||||
FRotator BoneRotation{ReferenceQuat * JointQuat};*/
|
||||
|
||||
FName BoneName(Hand->IsRight()
|
||||
? GetRightHandBoneName(FingerIndex, JointIndex)
|
||||
: GetLeftHandBoneName(FingerIndex, JointIndex));
|
||||
|
||||
//BoneMap.Emplace(MoveTemp(BoneName), MoveTemp(BoneRotation));
|
||||
BoneMap.Emplace(MoveTemp(BoneName), MoveTemp(JointRotation));
|
||||
}
|
||||
}
|
||||
BonesRotations.Empty();
|
||||
BonesRotations = Hand->GetFingersBonesRotations();
|
||||
}
|
||||
|
||||
bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
||||
@@ -197,7 +126,7 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
||||
FComponentSpacePoseContext PoseContext(this);
|
||||
PoseContext.Pose.InitPose(Output.Pose);
|
||||
|
||||
for (const TTuple<FName, FRotator>& Bone: BoneMap)
|
||||
for (const TTuple<FName, FRotator>& Bone: BonesRotations)
|
||||
{
|
||||
FName BoneName(Bone.Key);
|
||||
FRotator BoneRotation(Bone.Value);
|
||||
@@ -213,8 +142,7 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
||||
FAnimNode_ModifyBone BoneController;
|
||||
BoneController.BoneToModify = MoveTemp(BoneReference);
|
||||
BoneController.RotationMode = EBoneModificationMode::BMM_Replace;
|
||||
//BoneController.RotationSpace = EBoneControlSpace::BCS_WorldSpace;
|
||||
BoneController.RotationSpace = EBoneControlSpace::BCS_ComponentSpace;
|
||||
BoneController.RotationSpace = EBoneControlSpace::BCS_ParentBoneSpace;
|
||||
BoneController.Rotation = MoveTemp(BoneRotation);
|
||||
|
||||
if (BoneController.IsValidToEvaluate(HandSkeleton, PoseContext.Pose.GetPose().GetBoneContainer()))
|
||||
@@ -229,17 +157,8 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
||||
BoneController.BoneToModify.GetCompactPoseIndex(
|
||||
PoseContext.Pose.GetPose().GetBoneContainer())
|
||||
};
|
||||
const FTransform BoneTransformBefore{PoseContext.Pose.GetComponentSpaceTransform(PoseBoneIndex)};
|
||||
|
||||
PoseContext.Pose.LocalBlendCSBoneTransforms(BoneTransforms, 1.0f);
|
||||
const FTransform BoneTransformAfter{PoseContext.Pose.GetComponentSpaceTransform(PoseBoneIndex)};
|
||||
|
||||
SGLOG("BoneController.Rotation", BoneController.Rotation);
|
||||
SGLOG("BoneTransforms[0].Transform.GetRotation()", BoneTransforms[0].Transform.GetRotation().Rotator());
|
||||
SGLOG("BoneTransformBefore.Rotation", BoneTransformBefore.Rotator());
|
||||
SGLOG("BoneTransformAfter.Rotation", BoneTransformAfter.Rotator());
|
||||
|
||||
// Output.Pose[PoseBoneIndex].SetRotation(
|
||||
// PoseContext.Pose.GetComponentSpaceTransform(PoseBoneIndex).GetRotation());
|
||||
PoseContext.Pose.ConvertComponentPosesToLocalPoses(PoseContext.Pose, Output.Pose);
|
||||
|
||||
HandMeshComponent->MarkRenderStateDirty();
|
||||
|
||||
@@ -79,6 +79,12 @@ struct ASGVirtualHand::FImpl
|
||||
return Path;
|
||||
}
|
||||
|
||||
/************************
|
||||
* Member variables
|
||||
************************/
|
||||
|
||||
TMap<FName, FTransform> InitialBonesTransforms;
|
||||
|
||||
/************************
|
||||
* Owner object
|
||||
************************/
|
||||
@@ -105,16 +111,64 @@ struct ASGVirtualHand::FImpl
|
||||
|
||||
bool IsEditor() const;
|
||||
|
||||
void SetHandMesh(USkeletalMesh* VirtualHandMesh, bool bReinitPos) const;
|
||||
void SetHandMesh(USkeletalMesh* VirtualHandMesh, bool bReinitPos);
|
||||
|
||||
FString GetDefaultMeshPath() const;
|
||||
bool IsUsingUserMesh() const;
|
||||
USkeletalMesh* LoadDefaultMesh() const;
|
||||
void SetDefaultMesh() const;
|
||||
void SetDefaultMesh();
|
||||
|
||||
void CacheInitialBonesTransforms();
|
||||
|
||||
bool CheckGlove() const;
|
||||
};
|
||||
|
||||
const TArray<TArray<FName>>& ASGVirtualHand::GetLeftHandFingerBoneNames()
|
||||
{
|
||||
static const TArray<TArray<FName>> BoneNames{
|
||||
{FName(TEXT("thumb_01_l")), FName(TEXT("thumb_02_l")), FName(TEXT("thumb_03_l"))},
|
||||
{FName(TEXT("index_01_l")), FName(TEXT("index_02_l")), FName(TEXT("index_03_l"))},
|
||||
{FName(TEXT("middle_01_l")), FName(TEXT("middle_02_l")), FName(TEXT("middle_03_l"))},
|
||||
{FName(TEXT("ring_01_l")), FName(TEXT("ring_02_l")), FName(TEXT("ring_03_l"))},
|
||||
{FName(TEXT("pinky_01_l")), FName(TEXT("pinky_02_l")), FName(TEXT("pinky_03_l"))},
|
||||
};
|
||||
return BoneNames;
|
||||
}
|
||||
|
||||
const TArray<TArray<FName>>& ASGVirtualHand::GetRightHandFingerBoneNames()
|
||||
{
|
||||
static const TArray<TArray<FName>> BoneNames{
|
||||
{FName(TEXT("thumb_01_r")), FName(TEXT("thumb_02_r")), FName(TEXT("thumb_03_r"))},
|
||||
{FName(TEXT("index_01_r")), FName(TEXT("index_02_r")), FName(TEXT("index_03_r"))},
|
||||
{FName(TEXT("middle_01_r")), FName(TEXT("middle_02_r")), FName(TEXT("middle_03_r"))},
|
||||
{FName(TEXT("ring_01_r")), FName(TEXT("ring_02_r")), FName(TEXT("ring_03_r"))},
|
||||
{FName(TEXT("pinky_01_r")), FName(TEXT("pinky_02_r")), FName(TEXT("pinky_03_r"))},
|
||||
};
|
||||
return BoneNames;
|
||||
}
|
||||
|
||||
const FName& ASGVirtualHand::GetLeftHandFingerBoneName(const int32 Finger, const int32 Joint)
|
||||
{
|
||||
const TArray<TArray<FName>>& BoneNames{GetLeftHandFingerBoneNames()};
|
||||
|
||||
ensureAlwaysMsgf(Finger < BoneNames.Num(), TEXT("Finger index is out of bound!"));
|
||||
ensureAlwaysMsgf(Joint < BoneNames[Finger].Num(), TEXT("Joint index is out of bound!"));
|
||||
|
||||
const FName& BoneName{BoneNames[Finger][Joint]};
|
||||
return BoneName;
|
||||
}
|
||||
|
||||
const FName& ASGVirtualHand::GetRightHandFingerBoneName(const int32 Finger, const int32 Joint)
|
||||
{
|
||||
const TArray<TArray<FName>>& BoneNames{GetRightHandFingerBoneNames()};
|
||||
|
||||
ensureAlwaysMsgf(Finger < BoneNames.Num(), TEXT("Finger index is out of bound!"));
|
||||
ensureAlwaysMsgf(Joint < BoneNames[Finger].Num(), TEXT("Joint index is out of bound!"));
|
||||
|
||||
const FName& BoneName{BoneNames[Finger][Joint]};
|
||||
return BoneName;
|
||||
}
|
||||
|
||||
ASGVirtualHand::ASGVirtualHand(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer),
|
||||
#if ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 )
|
||||
@@ -156,12 +210,19 @@ ASGVirtualHand::ASGVirtualHand(const FObjectInitializer& ObjectInitializer)
|
||||
const FString SkeletalMeshPath(Pimpl->GetDefaultMeshPath());
|
||||
const ConstructorHelpers::FObjectFinder<USkeletalMesh> SkeletalMesh(*SkeletalMeshPath);
|
||||
ensureAlwaysMsgf(SkeletalMesh.Succeeded() && SkeletalMesh.Object,
|
||||
TEXT("Failed to load the skeletal mesh: '%s'"), *SkeletalMeshPath);
|
||||
TEXT("Failed to load the skeletal mesh: '%s'"), *SkeletalMeshPath);
|
||||
Pimpl->SetHandMesh(SkeletalMesh.Object, true);
|
||||
|
||||
Glove = nullptr;
|
||||
}
|
||||
|
||||
void ASGVirtualHand::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
Pimpl->CacheInitialBonesTransforms();
|
||||
}
|
||||
|
||||
void ASGVirtualHand::Tick(const float DeltaSeconds)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
@@ -174,7 +235,7 @@ void ASGVirtualHand::Tick(const float DeltaSeconds)
|
||||
|
||||
Super::Tick(DeltaSeconds);
|
||||
|
||||
(void)Pimpl->CheckGlove();
|
||||
(void) Pimpl->CheckGlove();
|
||||
}
|
||||
|
||||
bool ASGVirtualHand::ShouldTickIfViewportsOnly() const
|
||||
@@ -200,21 +261,26 @@ void ASGVirtualHand::OnConstruction(const FTransform& Transform)
|
||||
{
|
||||
Pimpl->SetDefaultMesh();
|
||||
}
|
||||
|
||||
Pimpl->CacheInitialBonesTransforms();
|
||||
}
|
||||
|
||||
void ASGVirtualHand::EditorTick(float DeltaSeconds)
|
||||
{
|
||||
(void)Pimpl->CheckGlove();
|
||||
(void) Pimpl->CheckGlove();
|
||||
}
|
||||
|
||||
USkeletalMesh* ASGVirtualHand::GetHandMesh() const
|
||||
{
|
||||
ensureAlwaysMsgf(IsValid(Mesh), TEXT("Invalid Mesh object!"));
|
||||
|
||||
return
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 1
|
||||
Mesh->GetSkeletalMeshAsset();
|
||||
Mesh->GetSkeletalMeshAsset()
|
||||
#else
|
||||
Mesh->SkeletalMesh;
|
||||
Mesh->SkeletalMesh
|
||||
#endif /* ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 */
|
||||
;
|
||||
}
|
||||
|
||||
void ASGVirtualHand::SetHandMesh(USkeletalMesh* VirtualHandMesh, const bool bReinitPos) const
|
||||
@@ -222,6 +288,52 @@ void ASGVirtualHand::SetHandMesh(USkeletalMesh* VirtualHandMesh, const bool bRei
|
||||
Pimpl->SetHandMesh(VirtualHandMesh, bReinitPos);
|
||||
}
|
||||
|
||||
USkeleton* ASGVirtualHand::GetHandSkeleton() const
|
||||
{
|
||||
ensureAlwaysMsgf(IsValid(Mesh), TEXT("Invalid Mesh object!"));
|
||||
|
||||
USkeletalMesh* SkeletalMesh =
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 1
|
||||
Mesh->GetSkeletalMeshAsset()
|
||||
#else
|
||||
Mesh->SkeletalMesh
|
||||
#endif /* ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 */
|
||||
;
|
||||
|
||||
ensureAlwaysMsgf(IsValid(SkeletalMesh), TEXT("Invalid SkeletalMesh object!"));
|
||||
|
||||
return
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 1
|
||||
SkeletalMesh->GetSkeleton()
|
||||
#else
|
||||
SkeletalMesh->Skeleton
|
||||
#endif /* ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 */
|
||||
;
|
||||
}
|
||||
|
||||
const FReferenceSkeleton& ASGVirtualHand::GetHandRefSkeleton() const
|
||||
{
|
||||
ensureAlwaysMsgf(IsValid(Mesh), TEXT("Invalid Mesh object!"));
|
||||
|
||||
USkeletalMesh* SkeletalMesh =
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 1
|
||||
Mesh->GetSkeletalMeshAsset()
|
||||
#else
|
||||
Mesh->SkeletalMesh
|
||||
#endif /* ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 */
|
||||
;
|
||||
|
||||
ensureAlwaysMsgf(IsValid(SkeletalMesh), TEXT("Invalid SkeletalMesh object!"));
|
||||
|
||||
return
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 1
|
||||
SkeletalMesh->GetRefSkeleton()
|
||||
#else
|
||||
SkeletalMesh->RefSkeleton
|
||||
#endif /* ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 */
|
||||
;
|
||||
}
|
||||
|
||||
bool ASGVirtualHand::IsGloveConnected() const
|
||||
{
|
||||
return Pimpl->CheckGlove();
|
||||
@@ -239,6 +351,81 @@ USGHandPose* ASGVirtualHand::GetHandPose()
|
||||
return HandPose;
|
||||
}
|
||||
|
||||
const FName& ASGVirtualHand::GetFingerBoneName(const int32 Finger, const int32 Joint) const
|
||||
{
|
||||
const FName& Name{IsRight()
|
||||
? GetRightHandFingerBoneName(Finger, Joint)
|
||||
: GetLeftHandFingerBoneName(Finger, Joint)};
|
||||
return Name;
|
||||
}
|
||||
|
||||
const TMap<FName, FTransform>& ASGVirtualHand::GetInitialBonesTransforms() const
|
||||
{
|
||||
return Pimpl->InitialBonesTransforms;
|
||||
}
|
||||
|
||||
bool ASGVirtualHand::GetInitialBoneTransform(const int32 Finger, const int32 Joint,
|
||||
FTransform& OutTransform) const
|
||||
{
|
||||
const FName& BoneName{GetFingerBoneName(Finger, Joint)};
|
||||
|
||||
const uint32 Hash = TDefaultMapHashableKeyFuncs<FName, FTransform, false>::GetKeyHash(BoneName);
|
||||
FTransform* Transform{Pimpl->InitialBonesTransforms.FindByHash(Hash, BoneName)};
|
||||
if (!Transform)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutTransform = MoveTemp(*Transform);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASGVirtualHand::GetInitialBoneRotation(const int32 Finger, const int32 Joint, FRotator& OutRotation) const
|
||||
{
|
||||
FTransform Transform;
|
||||
if (!GetInitialBoneTransform(Finger, Joint, Transform))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutRotation = Transform.GetRotation().Rotator();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TMap<FName, FRotator> ASGVirtualHand::GetFingersBonesRotations()
|
||||
{
|
||||
TMap<FName, FRotator> Rotations;
|
||||
|
||||
const USGHandPose* HandPose = GetHandPose();
|
||||
if (!IsValid(HandPose))
|
||||
{
|
||||
return MoveTemp(Rotations);
|
||||
}
|
||||
|
||||
const TArray<TArray<FVector>> HandAngles = HandPose->GetHandAngles();
|
||||
|
||||
for (int32 FingerIndex = 0; FingerIndex < HandAngles.Num(); ++FingerIndex)
|
||||
{
|
||||
const TArray<FVector>& FingerJointAngles = HandAngles[FingerIndex];
|
||||
|
||||
for (int32 JointIndex = 0; JointIndex < FingerJointAngles.Num(); ++JointIndex)
|
||||
{
|
||||
const FVector& FingerJointAngle{FingerJointAngles[JointIndex]};
|
||||
FRotator InitialBoneRotation;
|
||||
if (GetInitialBoneRotation(FingerIndex, JointIndex, InitialBoneRotation))
|
||||
{
|
||||
FName BoneName{GetFingerBoneName(FingerIndex, JointIndex)};
|
||||
FRotator BoneRotation{(InitialBoneRotation.Vector() + FingerJointAngle).Rotation()};
|
||||
Rotations.Emplace(MoveTemp(BoneName), MoveTemp(BoneRotation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MoveTemp(Rotations);
|
||||
}
|
||||
|
||||
ASGVirtualHand::FImpl::FImpl(ASGVirtualHand* InOwner)
|
||||
: Owner(InOwner)
|
||||
{
|
||||
@@ -246,13 +433,16 @@ ASGVirtualHand::FImpl::FImpl(ASGVirtualHand* InOwner)
|
||||
|
||||
ASGVirtualHand::FImpl::~FImpl() = default;
|
||||
|
||||
void ASGVirtualHand::FImpl::SetHandMesh(USkeletalMesh* VirtualHandMesh, const bool bReinitPos) const
|
||||
void ASGVirtualHand::FImpl::SetHandMesh(USkeletalMesh* VirtualHandMesh, const bool bReinitPos)
|
||||
{
|
||||
ensureAlwaysMsgf(IsValid(VirtualHandMesh), TEXT("Invalid VirtualHandMesh object!"));
|
||||
ensureAlwaysMsgf(IsValid(Owner->Mesh), TEXT("Invalid Mesh object!"));
|
||||
ensureAlwaysMsgf(IsValid(Owner->AnimInstanceClass), TEXT("Invalid AnimInstanceClass object!"));
|
||||
|
||||
Owner->Mesh->SetSkeletalMesh(VirtualHandMesh, bReinitPos);
|
||||
|
||||
CacheInitialBonesTransforms();
|
||||
|
||||
Owner->Mesh->SetAnimInstanceClass(Owner->AnimInstanceClass);
|
||||
}
|
||||
|
||||
@@ -331,11 +521,26 @@ USkeletalMesh* ASGVirtualHand::FImpl::LoadDefaultMesh() const
|
||||
return SkeletalMesh;
|
||||
}
|
||||
|
||||
void ASGVirtualHand::FImpl::SetDefaultMesh() const
|
||||
void ASGVirtualHand::FImpl::SetDefaultMesh()
|
||||
{
|
||||
SetHandMesh(LoadDefaultMesh(), true);
|
||||
}
|
||||
|
||||
void ASGVirtualHand::FImpl::CacheInitialBonesTransforms()
|
||||
{
|
||||
InitialBonesTransforms.Empty();
|
||||
|
||||
ensureAlwaysMsgf(IsValid(Owner->Mesh), TEXT("Invalid Mesh object!"));
|
||||
|
||||
const int32 NumBones = Owner->Mesh->GetNumBones();
|
||||
for (int32 i = 0; i < NumBones; ++i)
|
||||
{
|
||||
const FName BoneName{Owner->Mesh->GetBoneName(i)};
|
||||
FTransform BoneTransform{Owner->Mesh->GetSocketTransform(BoneName, RTS_ParentBoneSpace)};
|
||||
InitialBonesTransforms.Emplace(BoneName, MoveTemp(BoneTransform));
|
||||
}
|
||||
}
|
||||
|
||||
bool ASGVirtualHand::FImpl::CheckGlove() const
|
||||
{
|
||||
const bool bGloveWasPresent = IsValid(Owner->Glove);
|
||||
|
||||
@@ -44,45 +44,41 @@
|
||||
USTRUCT()
|
||||
struct SENSEGLOVE_API FSGVirtualHandAnimInstanceProxy : public FAnimInstanceProxy
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
public:
|
||||
static const FName& GetLeftHandBoneName(int32 Finger, int32 Joint);
|
||||
static const FName& GetRightHandBoneName(int32 Finger, int32 Joint);
|
||||
TMap<FName, FRotator> BonesRotations;
|
||||
|
||||
public:
|
||||
TMap<FName, FRotator> BoneMap;
|
||||
|
||||
public:
|
||||
FSGVirtualHandAnimInstanceProxy();
|
||||
FSGVirtualHandAnimInstanceProxy(UAnimInstance* Instance);
|
||||
FSGVirtualHandAnimInstanceProxy();
|
||||
FSGVirtualHandAnimInstanceProxy(UAnimInstance* Instance);
|
||||
|
||||
protected:
|
||||
/** Called when our anim instance is being initialized */
|
||||
virtual void Initialize(UAnimInstance* InAnimInstance) override;
|
||||
/** Called when our anim instance is being initialized */
|
||||
virtual void Initialize(UAnimInstance* InAnimInstance) override;
|
||||
|
||||
/** Called when our anim instance is being uninitialized */
|
||||
virtual void Uninitialize(UAnimInstance* InAnimInstance) override;
|
||||
/** Called when our anim instance is being uninitialized */
|
||||
virtual void Uninitialize(UAnimInstance* InAnimInstance) override;
|
||||
|
||||
/** Called before update so we can copy any data we need */
|
||||
virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds) override;
|
||||
/** Called before update so we can copy any data we need */
|
||||
virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds) override;
|
||||
|
||||
/** Update override point */
|
||||
virtual void Update(float DeltaSeconds) override;
|
||||
/** Update override point */
|
||||
virtual void Update(float DeltaSeconds) override;
|
||||
|
||||
/** Called on the game thread pre-evaluate. */
|
||||
virtual void PreEvaluateAnimation(UAnimInstance* InAnimInstance) override;
|
||||
/** Called on the game thread pre-evaluate. */
|
||||
virtual void PreEvaluateAnimation(UAnimInstance* InAnimInstance) override;
|
||||
|
||||
/**
|
||||
* Evaluate override point
|
||||
* @return true if this function is implemented, false otherwise.
|
||||
* Note: the node graph will not be evaluated if this function returns true
|
||||
*/
|
||||
virtual bool Evaluate(FPoseContext& Output) override;
|
||||
/**
|
||||
* Evaluate override point
|
||||
* @return true if this function is implemented, false otherwise.
|
||||
* Note: the node graph will not be evaluated if this function returns true
|
||||
*/
|
||||
virtual bool Evaluate(FPoseContext& Output) override;
|
||||
|
||||
/** Called after update so we can copy any data we need */
|
||||
virtual void PostUpdate(UAnimInstance* InAnimInstance) const override;
|
||||
/** Called after update so we can copy any data we need */
|
||||
virtual void PostUpdate(UAnimInstance* InAnimInstance) const override;
|
||||
|
||||
/** Called after evaluate so we can do any game thread work we need to */
|
||||
virtual void PostEvaluate(UAnimInstance* InAnimInstance) override;
|
||||
/** Called after evaluate so we can do any game thread work we need to */
|
||||
virtual void PostEvaluate(UAnimInstance* InAnimInstance) override;
|
||||
};
|
||||
@@ -35,8 +35,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Containers/Array.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Math/Rotator.h"
|
||||
#include "Math/Transform.h"
|
||||
#include "Templates/UniquePtr.h"
|
||||
#include "UObject/NameTypes.h"
|
||||
|
||||
#include "SGVirtualHand.generated.h"
|
||||
|
||||
@@ -53,6 +57,13 @@ class SENSEGLOVE_API ASGVirtualHand : public AActor
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
public:
|
||||
static const TArray<TArray<FName>>& GetLeftHandFingerBoneNames();
|
||||
static const TArray<TArray<FName>>& GetRightHandFingerBoneNames();
|
||||
|
||||
static const FName& GetLeftHandFingerBoneName(int32 Finger, int32 Joint);
|
||||
static const FName& GetRightHandFingerBoneName(int32 Finger, int32 Joint);
|
||||
|
||||
private:
|
||||
struct FImpl;
|
||||
|
||||
@@ -68,7 +79,7 @@ private:
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
||||
USceneComponent* SceneRoot;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
||||
USkeletalMeshComponent* Mesh;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
||||
@@ -145,12 +156,15 @@ protected:
|
||||
AnimInstanceClass = InAnimInstanceClass;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
public:
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
|
||||
virtual bool ShouldTickIfViewportsOnly() const override;
|
||||
virtual bool ShouldTickIfViewportsOnly() const override;
|
||||
|
||||
virtual void OnConstruction(const FTransform& Transform) override;
|
||||
virtual void OnConstruction(const FTransform& Transform) override;
|
||||
|
||||
protected:
|
||||
virtual void EditorTick(float DeltaSeconds);
|
||||
@@ -160,7 +174,17 @@ public:
|
||||
void SetHandMesh(USkeletalMesh* VirtualHandMesh, bool bReinitPos) const;
|
||||
|
||||
USkeleton* GetHandSkeleton() const;
|
||||
const FReferenceSkeleton& GetHandRefSkeleton() const;
|
||||
|
||||
bool IsGloveConnected() const;
|
||||
USGHandPose* GetHandPose();
|
||||
|
||||
public:
|
||||
const FName& GetFingerBoneName(int32 Finger, int32 Joint) const;
|
||||
|
||||
const TMap<FName, FTransform>& GetInitialBonesTransforms() const;
|
||||
bool GetInitialBoneTransform(int32 Finger, int32 Joint, FTransform& OutTransform) const;
|
||||
bool GetInitialBoneRotation(int32 Finger, int32 Joint, FRotator& OutRotation) const;
|
||||
|
||||
TMap<FName, FRotator> GetFingersBonesRotations();
|
||||
};
|
||||
Reference in New Issue
Block a user