diff --git a/Source/SenseGlove/Private/SenseGlove/Animation/SGVirtualHandAnimInstanceProxy.cpp b/Source/SenseGlove/Private/SenseGlove/Animation/SGVirtualHandAnimInstanceProxy.cpp index bfd207b8..156e5c7a 100644 --- a/Source/SenseGlove/Private/SenseGlove/Animation/SGVirtualHandAnimInstanceProxy.cpp +++ b/Source/SenseGlove/Private/SenseGlove/Animation/SGVirtualHandAnimInstanceProxy.cpp @@ -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> 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> 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> JointRotations = HandPose->GetJointRotations(); - - for (int32 FingerIndex = 0; FingerIndex < JointRotations.Num(); ++FingerIndex) - { - const TArray& 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& Bone: BoneMap) + for (const TTuple& 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(); diff --git a/Source/SenseGlove/Private/SenseGlove/GameFramework/SGVirtualHand.cpp b/Source/SenseGlove/Private/SenseGlove/GameFramework/SGVirtualHand.cpp index 3aeae2aa..ea452793 100644 --- a/Source/SenseGlove/Private/SenseGlove/GameFramework/SGVirtualHand.cpp +++ b/Source/SenseGlove/Private/SenseGlove/GameFramework/SGVirtualHand.cpp @@ -79,6 +79,12 @@ struct ASGVirtualHand::FImpl return Path; } + /************************ + * Member variables + ************************/ + + TMap 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>& ASGVirtualHand::GetLeftHandFingerBoneNames() +{ + static const TArray> 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>& ASGVirtualHand::GetRightHandFingerBoneNames() +{ + static const TArray> 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>& 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>& 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 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& 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::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 ASGVirtualHand::GetFingersBonesRotations() +{ + TMap Rotations; + + const USGHandPose* HandPose = GetHandPose(); + if (!IsValid(HandPose)) + { + return MoveTemp(Rotations); + } + + const TArray> HandAngles = HandPose->GetHandAngles(); + + for (int32 FingerIndex = 0; FingerIndex < HandAngles.Num(); ++FingerIndex) + { + const TArray& 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); diff --git a/Source/SenseGlove/Public/SenseGlove/Animation/SGVirtualHandAnimInstanceProxy.h b/Source/SenseGlove/Public/SenseGlove/Animation/SGVirtualHandAnimInstanceProxy.h index 2b3150e1..469ae774 100644 --- a/Source/SenseGlove/Public/SenseGlove/Animation/SGVirtualHandAnimInstanceProxy.h +++ b/Source/SenseGlove/Public/SenseGlove/Animation/SGVirtualHandAnimInstanceProxy.h @@ -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 BonesRotations; public: - TMap 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; }; \ No newline at end of file diff --git a/Source/SenseGlove/Public/SenseGlove/GameFramework/SGVirtualHand.h b/Source/SenseGlove/Public/SenseGlove/GameFramework/SGVirtualHand.h index d01e982d..bcab4444 100644 --- a/Source/SenseGlove/Public/SenseGlove/GameFramework/SGVirtualHand.h +++ b/Source/SenseGlove/Public/SenseGlove/GameFramework/SGVirtualHand.h @@ -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>& GetLeftHandFingerBoneNames(); + static const TArray>& 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& GetInitialBonesTransforms() const; + bool GetInitialBoneTransform(int32 Finger, int32 Joint, FTransform& OutTransform) const; + bool GetInitialBoneRotation(int32 Finger, int32 Joint, FRotator& OutRotation) const; + + TMap GetFingersBonesRotations(); }; \ No newline at end of file