From 8dea65ed40b1ec6ef7c3e7e32f09ecfd41453159 Mon Sep 17 00:00:00 2001 From: Mamadou Babaei Date: Tue, 9 Sep 2025 09:30:42 +0200 Subject: [PATCH] get rid of SGPawn::Tick, introduce SGPawn::HandVelocitySamplerFramerate, and make hand velocity sampler timer-based instead of tick-based --- Handbook/src/appendix/changelog.md | 3 + .../SenseGlove/GameFramework/SGPawn.cpp | 60 ++++++++++++++++--- .../Public/SenseGlove/GameFramework/SGPawn.h | 4 +- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/Handbook/src/appendix/changelog.md b/Handbook/src/appendix/changelog.md index 5b19fc7d..85bb682f 100644 --- a/Handbook/src/appendix/changelog.md +++ b/Handbook/src/appendix/changelog.md @@ -21,6 +21,7 @@ This minor release focuses on delivering performance improvements, made possible - Added third-party module `SGLogThirdPartyLibs`. - Added third-party module `SGLoguruThirdPartyLibs`. - Added third-party module `SGWjwwoodSerialThirdPartyLibs` to replace `SGSerialThirdPartyLibs` while retaining `SGSerialThirdPartyLibs` for a different purpose. See the relevant comment in the Changed section below. +- Added UPROPERTY `SGPawn::HandVelocitySamplerFramerate` to control the hand velocity sampler's timer interval. This allows getting rid of `SGPawn::Tick()` for improved performance and reliability, which also improves chopiness on low frame-rates. ### Fixed @@ -33,6 +34,7 @@ This minor release focuses on delivering performance improvements, made possible - As a result of SenseGlove libraries >= `v2.300.0` changing it's directory structure, the `ThirdParty` folder's directory structure has been revamped. - Renamed third-party module `SGSerialThirdPartyLibs` to `SGWjwwoodSerialThirdPartyLibs` since SenseGlove libraries >= `v2.300.0` ships a new static library named `sgserial`. Thus, to avoid confusion and naming conflicts the third-party `serial` static library is now provided by the `SGWjwwoodSerialThirdPartyLibs` module and `sgserial` is provided by the `SGSerialThirdPartyLibs` module. - `FSGGloveTrackingSettings::GloveConnectivityCheckInterval` settings have been renamed to `FSGGloveTrackingSettings::DataRetrievalRefreshRate` for adoption other than glove connectivity use cases. +- The hand velocity sampler is now timer-based instead of being tick-based and the update interval is controlled via `SGPawn::HandVelocitySamplerFramerate`. ### Removed @@ -41,6 +43,7 @@ This minor release focuses on delivering performance improvements, made possible - Cleaned up remnants of the long-removed Unreal Engine `5.2` from third-party module `*.Build.cs` files. - Cleaned up remnants of the long-removed Unreal Engine `5.2` from `SenseGlove.Build.cs`, `SenseGloveKismet.Build.cs`, `SenseGloveTracking.Build.cs`, files. - Cleaned up remnants of the long-removed Unreal Engine `5.2` from `SenseGloveTracking` module. +- `SGPawn::Tick()` is no longer handled in order to improve performance and reliability. The hand velocity sampler is now timer-based instead of being tick-based and the update interval is controlled via `SGPawn::HandVelocitySamplerFramerate`. ### Documentation diff --git a/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPawn.cpp b/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPawn.cpp index 319adc6b..c949f7df 100644 --- a/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPawn.cpp +++ b/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPawn.cpp @@ -40,6 +40,7 @@ #include "Components/SphereComponent.h" #include "Kismet/KismetMathLibrary.h" #include "Runtime/Launch/Resources/Version.h" +#include "TimerManager.h" #include "UObject/UObjectGlobals.h" #include "XRDeviceVisualizationComponent.h" @@ -47,8 +48,9 @@ #include "SenseGlove/Components/SGTouchComponent.h" #include "SenseGlove/Components/SGVirtualHandComponent.h" #include "SenseGlove/Components/SGWristTrackerComponent.h" -#include "SGSettings/SGSettings.h" +#include "SGBuildHacks/SGPlatform.h" #include "SGLog/SGLog.h" +#include "SGSettings/SGSettings.h" struct ASGPawn::FImpl { @@ -56,6 +58,12 @@ struct ASGPawn::FImpl * Static methods ************************/ + /************************ + * Member variables + ************************/ + + FTimerHandle HandVelocitySamplerTimer; + /************************ * Owner object ************************/ @@ -146,6 +154,7 @@ struct ASGPawn::FImpl void SetRightHandGrabbedActor(AActor* Actor) const; void RecordHandVelocity(FSGGrabState& GrabState, const float DeltaSeconds) const; + void StartHandVelocitySamplerTimer(); void Release(FSGGrabState& GrabState) const; @@ -491,6 +500,7 @@ ASGPawn::ASGPawn(const FObjectInitializer& ObjectInitializer) RightPinkyFingertipTouchCollider->SetCollisionObjectType(ECC_Pawn); Pimpl->SetFingerColliderCollisionEnabled(RightPinkyFingertipTouchCollider, true); + HandVelocitySamplerFramerate = 60.0f; MaxNumberOfHandVelocitySamples = 10; LeftHandGrabState = FSGGrabState{ @@ -577,6 +587,8 @@ void ASGPawn::BeginPlay() Pimpl->BindFingerGrabOverlapEvents(); Pimpl->BindFingerTouchOverlapEvents(); + + Pimpl->StartHandVelocitySamplerTimer(); } void ASGPawn::EndPlay(const EEndPlayReason::Type EndPlayReason) @@ -589,14 +601,6 @@ void ASGPawn::EndPlay(const EEndPlayReason::Type EndPlayReason) Pimpl->UnbindFingerTouchOverlapEvents(); } -void ASGPawn::Tick(const float DeltaSeconds) -{ - Super::Tick(DeltaSeconds); - - Pimpl->RecordHandVelocity(LeftHandGrabState, DeltaSeconds); - Pimpl->RecordHandVelocity(RightHandGrabState, DeltaSeconds); -} - void ASGPawn::PreInitializeComponents() { Super::PreInitializeComponents(); @@ -2211,6 +2215,44 @@ void ASGPawn::FImpl::RecordHandVelocity(FSGGrabState& GrabState, const float Del GrabState.PreviousHandLocation = GrabState.Hand->GetComponentLocation(); } +void ASGPawn::FImpl::StartHandVelocitySamplerTimer() +{ + const UWorld* World{Owner->GetWorld()}; + if (!ensureAlwaysMsgf(World, TEXT("Invalid world!"))) + { + SGLOG_ERROR("The SGPawn hand velocity sampler timer has failed to start!"); + return; + } + + SGLOG("Starting SGPawn's hand-velocity sampler timer..."); + + FTimerDelegate Handler; + Handler.BindLambda([= SG_CAPTURE_THIS]()-> void + { + const float DeltaSeconds = World->GetDeltaSeconds(); + RecordHandVelocity(Owner->LeftHandGrabState, DeltaSeconds); + RecordHandVelocity(Owner->RightHandGrabState, DeltaSeconds); + }); + + const float Interval = 1.0f / Owner->HandVelocitySamplerFramerate; + + FTimerManager& TimerManager = World->GetTimerManager(); + TimerManager.SetTimer( + HandVelocitySamplerTimer, Handler, Interval, + true, -1.0f); + + if (ensureAlwaysMsgf(TimerManager.IsTimerActive(HandVelocitySamplerTimer), + TEXT("HandVelocitySamplerTimer is not active"))) + { + SGLOG("The SGPawn hand velocity sampler timer has been started successfully!"); + SGLOG("The SGPawn hand velocity sampler interval is: ", Interval); + } + else + { + SGLOG_ERROR("The SGPawn hand velocity sampler timer has failed to start!"); + } +} + void ASGPawn::FImpl::Release(FSGGrabState& GrabState) const { if (!IsValid(GrabState.GrabbedActor)) diff --git a/Source/SenseGlove/Public/SenseGlove/GameFramework/SGPawn.h b/Source/SenseGlove/Public/SenseGlove/GameFramework/SGPawn.h index 0f40d592..34b9b12b 100644 --- a/Source/SenseGlove/Public/SenseGlove/GameFramework/SGPawn.h +++ b/Source/SenseGlove/Public/SenseGlove/GameFramework/SGPawn.h @@ -199,6 +199,9 @@ private: UPROPERTY(EditAnywhere, Category="SenseGlove", meta=(AllowPrivateAccess="false")) USphereComponent* RightPinkyFingertipTouchCollider; + UPROPERTY(EditAnywhere, Category="SenseGlove", meta=(AllowPrivateAccess="false")) + float HandVelocitySamplerFramerate; + UPROPERTY(EditAnywhere, Category="SenseGlove", meta=(AllowPrivateAccess="false")) int32 MaxNumberOfHandVelocitySamples; @@ -379,7 +382,6 @@ public: public: virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; - virtual void Tick(float DeltaSeconds) override; virtual void PreInitializeComponents() override; virtual void PostInitializeComponents() override;