improved virtual hand model animation
This commit is contained in:
@@ -48,41 +48,6 @@
|
|||||||
#include "SGCore/SGHandPose.h"
|
#include "SGCore/SGHandPose.h"
|
||||||
#include "SGLog/SGLog.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()
|
FSGVirtualHandAnimInstanceProxy::FSGVirtualHandAnimInstanceProxy()
|
||||||
: FAnimInstanceProxy()
|
: FAnimInstanceProxy()
|
||||||
{
|
{
|
||||||
@@ -128,44 +93,8 @@ void FSGVirtualHandAnimInstanceProxy::PreEvaluateAnimation(UAnimInstance* InAnim
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const USGHandPose* HandPose = Hand->GetHandPose();
|
BonesRotations.Empty();
|
||||||
if (!IsValid(HandPose))
|
BonesRotations = Hand->GetFingersBonesRotations();
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
||||||
@@ -197,7 +126,7 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
|||||||
FComponentSpacePoseContext PoseContext(this);
|
FComponentSpacePoseContext PoseContext(this);
|
||||||
PoseContext.Pose.InitPose(Output.Pose);
|
PoseContext.Pose.InitPose(Output.Pose);
|
||||||
|
|
||||||
for (const TTuple<FName, FRotator>& Bone: BoneMap)
|
for (const TTuple<FName, FRotator>& Bone: BonesRotations)
|
||||||
{
|
{
|
||||||
FName BoneName(Bone.Key);
|
FName BoneName(Bone.Key);
|
||||||
FRotator BoneRotation(Bone.Value);
|
FRotator BoneRotation(Bone.Value);
|
||||||
@@ -213,8 +142,7 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
|||||||
FAnimNode_ModifyBone BoneController;
|
FAnimNode_ModifyBone BoneController;
|
||||||
BoneController.BoneToModify = MoveTemp(BoneReference);
|
BoneController.BoneToModify = MoveTemp(BoneReference);
|
||||||
BoneController.RotationMode = EBoneModificationMode::BMM_Replace;
|
BoneController.RotationMode = EBoneModificationMode::BMM_Replace;
|
||||||
//BoneController.RotationSpace = EBoneControlSpace::BCS_WorldSpace;
|
BoneController.RotationSpace = EBoneControlSpace::BCS_ParentBoneSpace;
|
||||||
BoneController.RotationSpace = EBoneControlSpace::BCS_ComponentSpace;
|
|
||||||
BoneController.Rotation = MoveTemp(BoneRotation);
|
BoneController.Rotation = MoveTemp(BoneRotation);
|
||||||
|
|
||||||
if (BoneController.IsValidToEvaluate(HandSkeleton, PoseContext.Pose.GetPose().GetBoneContainer()))
|
if (BoneController.IsValidToEvaluate(HandSkeleton, PoseContext.Pose.GetPose().GetBoneContainer()))
|
||||||
@@ -229,17 +157,8 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
|
|||||||
BoneController.BoneToModify.GetCompactPoseIndex(
|
BoneController.BoneToModify.GetCompactPoseIndex(
|
||||||
PoseContext.Pose.GetPose().GetBoneContainer())
|
PoseContext.Pose.GetPose().GetBoneContainer())
|
||||||
};
|
};
|
||||||
const FTransform BoneTransformBefore{PoseContext.Pose.GetComponentSpaceTransform(PoseBoneIndex)};
|
|
||||||
PoseContext.Pose.LocalBlendCSBoneTransforms(BoneTransforms, 1.0f);
|
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);
|
PoseContext.Pose.ConvertComponentPosesToLocalPoses(PoseContext.Pose, Output.Pose);
|
||||||
|
|
||||||
HandMeshComponent->MarkRenderStateDirty();
|
HandMeshComponent->MarkRenderStateDirty();
|
||||||
|
|||||||
@@ -79,6 +79,12 @@ struct ASGVirtualHand::FImpl
|
|||||||
return Path;
|
return Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************
|
||||||
|
* Member variables
|
||||||
|
************************/
|
||||||
|
|
||||||
|
TMap<FName, FTransform> InitialBonesTransforms;
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
* Owner object
|
* Owner object
|
||||||
************************/
|
************************/
|
||||||
@@ -105,16 +111,64 @@ struct ASGVirtualHand::FImpl
|
|||||||
|
|
||||||
bool IsEditor() const;
|
bool IsEditor() const;
|
||||||
|
|
||||||
void SetHandMesh(USkeletalMesh* VirtualHandMesh, bool bReinitPos) const;
|
void SetHandMesh(USkeletalMesh* VirtualHandMesh, bool bReinitPos);
|
||||||
|
|
||||||
FString GetDefaultMeshPath() const;
|
FString GetDefaultMeshPath() const;
|
||||||
bool IsUsingUserMesh() const;
|
bool IsUsingUserMesh() const;
|
||||||
USkeletalMesh* LoadDefaultMesh() const;
|
USkeletalMesh* LoadDefaultMesh() const;
|
||||||
void SetDefaultMesh() const;
|
void SetDefaultMesh();
|
||||||
|
|
||||||
|
void CacheInitialBonesTransforms();
|
||||||
|
|
||||||
bool CheckGlove() const;
|
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)
|
ASGVirtualHand::ASGVirtualHand(const FObjectInitializer& ObjectInitializer)
|
||||||
: Super(ObjectInitializer),
|
: Super(ObjectInitializer),
|
||||||
#if ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 )
|
#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 FString SkeletalMeshPath(Pimpl->GetDefaultMeshPath());
|
||||||
const ConstructorHelpers::FObjectFinder<USkeletalMesh> SkeletalMesh(*SkeletalMeshPath);
|
const ConstructorHelpers::FObjectFinder<USkeletalMesh> SkeletalMesh(*SkeletalMeshPath);
|
||||||
ensureAlwaysMsgf(SkeletalMesh.Succeeded() && SkeletalMesh.Object,
|
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);
|
Pimpl->SetHandMesh(SkeletalMesh.Object, true);
|
||||||
|
|
||||||
Glove = nullptr;
|
Glove = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASGVirtualHand::BeginPlay()
|
||||||
|
{
|
||||||
|
Super::BeginPlay();
|
||||||
|
|
||||||
|
Pimpl->CacheInitialBonesTransforms();
|
||||||
|
}
|
||||||
|
|
||||||
void ASGVirtualHand::Tick(const float DeltaSeconds)
|
void ASGVirtualHand::Tick(const float DeltaSeconds)
|
||||||
{
|
{
|
||||||
#if WITH_EDITOR
|
#if WITH_EDITOR
|
||||||
@@ -174,7 +235,7 @@ void ASGVirtualHand::Tick(const float DeltaSeconds)
|
|||||||
|
|
||||||
Super::Tick(DeltaSeconds);
|
Super::Tick(DeltaSeconds);
|
||||||
|
|
||||||
(void)Pimpl->CheckGlove();
|
(void) Pimpl->CheckGlove();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASGVirtualHand::ShouldTickIfViewportsOnly() const
|
bool ASGVirtualHand::ShouldTickIfViewportsOnly() const
|
||||||
@@ -200,21 +261,26 @@ void ASGVirtualHand::OnConstruction(const FTransform& Transform)
|
|||||||
{
|
{
|
||||||
Pimpl->SetDefaultMesh();
|
Pimpl->SetDefaultMesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pimpl->CacheInitialBonesTransforms();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASGVirtualHand::EditorTick(float DeltaSeconds)
|
void ASGVirtualHand::EditorTick(float DeltaSeconds)
|
||||||
{
|
{
|
||||||
(void)Pimpl->CheckGlove();
|
(void) Pimpl->CheckGlove();
|
||||||
}
|
}
|
||||||
|
|
||||||
USkeletalMesh* ASGVirtualHand::GetHandMesh() const
|
USkeletalMesh* ASGVirtualHand::GetHandMesh() const
|
||||||
{
|
{
|
||||||
|
ensureAlwaysMsgf(IsValid(Mesh), TEXT("Invalid Mesh object!"));
|
||||||
|
|
||||||
return
|
return
|
||||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 1
|
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 1
|
||||||
Mesh->GetSkeletalMeshAsset();
|
Mesh->GetSkeletalMeshAsset()
|
||||||
#else
|
#else
|
||||||
Mesh->SkeletalMesh;
|
Mesh->SkeletalMesh
|
||||||
#endif /* ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 */
|
#endif /* ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 */
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASGVirtualHand::SetHandMesh(USkeletalMesh* VirtualHandMesh, const bool bReinitPos) const
|
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);
|
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
|
bool ASGVirtualHand::IsGloveConnected() const
|
||||||
{
|
{
|
||||||
return Pimpl->CheckGlove();
|
return Pimpl->CheckGlove();
|
||||||
@@ -239,6 +351,81 @@ USGHandPose* ASGVirtualHand::GetHandPose()
|
|||||||
return HandPose;
|
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)
|
ASGVirtualHand::FImpl::FImpl(ASGVirtualHand* InOwner)
|
||||||
: Owner(InOwner)
|
: Owner(InOwner)
|
||||||
{
|
{
|
||||||
@@ -246,13 +433,16 @@ ASGVirtualHand::FImpl::FImpl(ASGVirtualHand* InOwner)
|
|||||||
|
|
||||||
ASGVirtualHand::FImpl::~FImpl() = default;
|
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(VirtualHandMesh), TEXT("Invalid VirtualHandMesh object!"));
|
||||||
ensureAlwaysMsgf(IsValid(Owner->Mesh), TEXT("Invalid Mesh object!"));
|
ensureAlwaysMsgf(IsValid(Owner->Mesh), TEXT("Invalid Mesh object!"));
|
||||||
ensureAlwaysMsgf(IsValid(Owner->AnimInstanceClass), TEXT("Invalid AnimInstanceClass object!"));
|
ensureAlwaysMsgf(IsValid(Owner->AnimInstanceClass), TEXT("Invalid AnimInstanceClass object!"));
|
||||||
|
|
||||||
Owner->Mesh->SetSkeletalMesh(VirtualHandMesh, bReinitPos);
|
Owner->Mesh->SetSkeletalMesh(VirtualHandMesh, bReinitPos);
|
||||||
|
|
||||||
|
CacheInitialBonesTransforms();
|
||||||
|
|
||||||
Owner->Mesh->SetAnimInstanceClass(Owner->AnimInstanceClass);
|
Owner->Mesh->SetAnimInstanceClass(Owner->AnimInstanceClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,11 +521,26 @@ USkeletalMesh* ASGVirtualHand::FImpl::LoadDefaultMesh() const
|
|||||||
return SkeletalMesh;
|
return SkeletalMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASGVirtualHand::FImpl::SetDefaultMesh() const
|
void ASGVirtualHand::FImpl::SetDefaultMesh()
|
||||||
{
|
{
|
||||||
SetHandMesh(LoadDefaultMesh(), true);
|
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
|
bool ASGVirtualHand::FImpl::CheckGlove() const
|
||||||
{
|
{
|
||||||
const bool bGloveWasPresent = IsValid(Owner->Glove);
|
const bool bGloveWasPresent = IsValid(Owner->Glove);
|
||||||
|
|||||||
@@ -44,45 +44,41 @@
|
|||||||
USTRUCT()
|
USTRUCT()
|
||||||
struct SENSEGLOVE_API FSGVirtualHandAnimInstanceProxy : public FAnimInstanceProxy
|
struct SENSEGLOVE_API FSGVirtualHandAnimInstanceProxy : public FAnimInstanceProxy
|
||||||
{
|
{
|
||||||
GENERATED_USTRUCT_BODY()
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const FName& GetLeftHandBoneName(int32 Finger, int32 Joint);
|
TMap<FName, FRotator> BonesRotations;
|
||||||
static const FName& GetRightHandBoneName(int32 Finger, int32 Joint);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TMap<FName, FRotator> BoneMap;
|
FSGVirtualHandAnimInstanceProxy();
|
||||||
|
FSGVirtualHandAnimInstanceProxy(UAnimInstance* Instance);
|
||||||
public:
|
|
||||||
FSGVirtualHandAnimInstanceProxy();
|
|
||||||
FSGVirtualHandAnimInstanceProxy(UAnimInstance* Instance);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Called when our anim instance is being initialized */
|
/** Called when our anim instance is being initialized */
|
||||||
virtual void Initialize(UAnimInstance* InAnimInstance) override;
|
virtual void Initialize(UAnimInstance* InAnimInstance) override;
|
||||||
|
|
||||||
/** Called when our anim instance is being uninitialized */
|
/** Called when our anim instance is being uninitialized */
|
||||||
virtual void Uninitialize(UAnimInstance* InAnimInstance) override;
|
virtual void Uninitialize(UAnimInstance* InAnimInstance) override;
|
||||||
|
|
||||||
/** Called before update so we can copy any data we need */
|
/** Called before update so we can copy any data we need */
|
||||||
virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds) override;
|
virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds) override;
|
||||||
|
|
||||||
/** Update override point */
|
/** Update override point */
|
||||||
virtual void Update(float DeltaSeconds) override;
|
virtual void Update(float DeltaSeconds) override;
|
||||||
|
|
||||||
/** Called on the game thread pre-evaluate. */
|
/** Called on the game thread pre-evaluate. */
|
||||||
virtual void PreEvaluateAnimation(UAnimInstance* InAnimInstance) override;
|
virtual void PreEvaluateAnimation(UAnimInstance* InAnimInstance) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate override point
|
* Evaluate override point
|
||||||
* @return true if this function is implemented, false otherwise.
|
* @return true if this function is implemented, false otherwise.
|
||||||
* Note: the node graph will not be evaluated if this function returns true
|
* Note: the node graph will not be evaluated if this function returns true
|
||||||
*/
|
*/
|
||||||
virtual bool Evaluate(FPoseContext& Output) override;
|
virtual bool Evaluate(FPoseContext& Output) override;
|
||||||
|
|
||||||
/** Called after update so we can copy any data we need */
|
/** Called after update so we can copy any data we need */
|
||||||
virtual void PostUpdate(UAnimInstance* InAnimInstance) const override;
|
virtual void PostUpdate(UAnimInstance* InAnimInstance) const override;
|
||||||
|
|
||||||
/** Called after evaluate so we can do any game thread work we need to */
|
/** Called after evaluate so we can do any game thread work we need to */
|
||||||
virtual void PostEvaluate(UAnimInstance* InAnimInstance) override;
|
virtual void PostEvaluate(UAnimInstance* InAnimInstance) override;
|
||||||
};
|
};
|
||||||
@@ -35,8 +35,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Containers/Array.h"
|
||||||
#include "GameFramework/Actor.h"
|
#include "GameFramework/Actor.h"
|
||||||
|
#include "Math/Rotator.h"
|
||||||
|
#include "Math/Transform.h"
|
||||||
#include "Templates/UniquePtr.h"
|
#include "Templates/UniquePtr.h"
|
||||||
|
#include "UObject/NameTypes.h"
|
||||||
|
|
||||||
#include "SGVirtualHand.generated.h"
|
#include "SGVirtualHand.generated.h"
|
||||||
|
|
||||||
@@ -53,6 +57,13 @@ class SENSEGLOVE_API ASGVirtualHand : public AActor
|
|||||||
{
|
{
|
||||||
GENERATED_UCLASS_BODY()
|
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:
|
private:
|
||||||
struct FImpl;
|
struct FImpl;
|
||||||
|
|
||||||
@@ -68,7 +79,7 @@ private:
|
|||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
||||||
USceneComponent* SceneRoot;
|
USceneComponent* SceneRoot;
|
||||||
|
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
||||||
USkeletalMeshComponent* Mesh;
|
USkeletalMeshComponent* Mesh;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="SenseGlove", meta=(AllowPrivateAccess="true"))
|
||||||
@@ -145,12 +156,15 @@ protected:
|
|||||||
AnimInstanceClass = InAnimInstanceClass;
|
AnimInstanceClass = InAnimInstanceClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void BeginPlay() override;
|
||||||
|
|
||||||
public:
|
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:
|
protected:
|
||||||
virtual void EditorTick(float DeltaSeconds);
|
virtual void EditorTick(float DeltaSeconds);
|
||||||
@@ -160,7 +174,17 @@ public:
|
|||||||
void SetHandMesh(USkeletalMesh* VirtualHandMesh, bool bReinitPos) const;
|
void SetHandMesh(USkeletalMesh* VirtualHandMesh, bool bReinitPos) const;
|
||||||
|
|
||||||
USkeleton* GetHandSkeleton() const;
|
USkeleton* GetHandSkeleton() const;
|
||||||
|
const FReferenceSkeleton& GetHandRefSkeleton() const;
|
||||||
|
|
||||||
bool IsGloveConnected() const;
|
bool IsGloveConnected() const;
|
||||||
USGHandPose* GetHandPose();
|
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