replace QueueVibroLevels with SendCustomWaveform

This commit is contained in:
Mamadou Babaei
2025-11-18 03:19:26 +01:00
parent 4395bc3021
commit 2407a706d2
7 changed files with 126 additions and 157 deletions
+18
View File
@@ -22,6 +22,16 @@ This minor release focuses on delivering performance improvements, made possible
- 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.
- Added UPROPERTY `USGTouchComponent::VibrotactileAmplitude`.
- Added UPROPERTY `USGTouchComponent::VibrotactileFrequency`.
- Added method `USGTouchComponent::GetVibrotactileAmplitude()`.
- Added method `USGTouchComponent::SetVibrotactileAmplitude()`.
- Added method `USGTouchComponent::GetVibrotactileFrequency()`.
- Added method `USGTouchComponent::SetVibrotactileFrequency()`.
- Added Blueprint-accessible method `USGTouchComponentKismetLibrary::GetVibrotactileAmplitude()`.
- Added Blueprint-accessible method `USGTouchComponentKismetLibrary::SetVibrotactileAmplitude()`.
- Added Blueprint-accessible method `USGTouchComponentKismetLibrary::GetVibrotactileFrequency()`.
- Added Blueprint-accessible method `USGTouchComponentKismetLibrary::SetVibrotactileFrequency()`.
### Fixed
@@ -42,6 +52,8 @@ This minor release focuses on delivering performance improvements, made possible
- `USGWristTrackerComponent::GetHandTrackingState()` signature has changed.
- `USGVirtualHandComponentKismetLibrary::GetMotionControllerData()` signature has changed.
- `USGVirtualHandComponentKismetLibrary::GetHandTrackingState()` signature has changed.
- `SGPawn` and `SGTouchComponent` no longer use the legacy `QueueVibroLevels` method for applying vibrotactile feedback. Instead it's been replaced with `SendCustomWaveform`.
- Changed `USGTouchComponent::VibrotactileDuration` UPROPERTY's maximum value to `1.0f`. Previously it was uncapped, and now any value beyond `1.0f` seconds is clamped.
### Removed
@@ -55,11 +67,17 @@ This minor release focuses on delivering performance improvements, made possible
- `USGWristTrackerComponent::GetMotionControllerState()` has been removed.
- `USGVirtualHandComponentKismetLibrary::GetMotionControllerState()` has been removed.
- `USGWristTrackerComponentKismetLibrary::GetMotionControllerState()` has been removed.
- `USGTouchComponent::VibrotactileLevel` UPROPERTY has been removed.
- `USGTouchComponent::GetVibrotactileLevel()` method has been removed.
- `USGTouchComponent::SetVibrotactileLevel()` method has been removed.
- `USGTouchComponentKismetLibrary::GetVibrotactileLevel()` method has been removed and is no longer available to Blueprint.
- `USGTouchComponentKismetLibrary::SetVibrotactileLevel()` method has been removed and is no longer available to Blueprint.
### Documentation
- Added [{fmt} Formatting Library License](../license/fmt-formatting-library.html) section.
- Added [Loguru Logging Library License](../license/loguru-loggin-library.html) section.
- Updated [Setting up the Touch System](../getting-started/setup-touch-system/index.html) section to reflect the recent touch system changes.
## [2.6.3] - 2025-06-27
@@ -103,8 +103,9 @@ USGTouchComponent::USGTouchComponent(const FObjectInitializer& ObjectInitializer
{
ForceFeedbackLevel = 1.0f;
VibrotactileDuration = 0.25f;
VibrotactileLevel = 0.0f;
VibrotactileAmplitude = 1.0f;
VibrotactileDuration = 1.0f;
VibrotactileFrequency= 500.0f;
}
USGTouchComponent::FImpl::FImpl(USGTouchComponent* InOwner)
@@ -36,8 +36,6 @@
#include "SenseGlove/GameFramework/SGPlayerController.h"
#include "Runtime/Launch/Resources/Version.h"
#include "Engine/TimerHandle.h"
#include "TimerManager.h"
#include "SenseGlove/Components/SGTouchComponent.h"
#include "SenseGlove/Components/SGVirtualHandComponent.h"
@@ -45,6 +43,7 @@
#include "SenseGlove/Haptics/SGGrabState.h"
#include "SenseGlove/Haptics/SGTouchState.h"
#include "SGBuildHacks/SGPlatform.h"
#include "SGCore/SGCustomWaveform.h"
#include "SGCore/SGHapticGlove.h"
struct ASGPlayerController::FImpl
@@ -55,11 +54,6 @@ struct ASGPlayerController::FImpl
static float GetForceFeedbackLevel(const AActor* Actor);
static float GetVibrotactileDuration(const AActor* ActorThumbTouching, const AActor* ActorIndexTouching,
const AActor* ActorMiddleTouching, const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching);
static float GetVibrotactileLevel(const AActor* Actor);
static TArray<float> GetForceFeedbackLevels(
const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
@@ -67,19 +61,10 @@ struct ASGPlayerController::FImpl
const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching);
static TArray<float> GetVibrotactileLevels(
const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
const AActor* ActorMiddleTouching,
const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching);
/************************
* Member variables
************************/
FTimerHandle TouchVibrotactileStopTimer;
/************************
* Owner object
************************/
@@ -104,6 +89,8 @@ struct ASGPlayerController::FImpl
* Methods
************************/
USGCustomWaveform* GetCustomWaveform(const AActor* Actor);
void UpdateHapticsFeedback(const FSGTouchState& TouchState);
};
@@ -121,74 +108,6 @@ float ASGPlayerController::FImpl::GetForceFeedbackLevel(const AActor* Actor)
return 0.0f;
}
float ASGPlayerController::FImpl::GetVibrotactileDuration(const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
const AActor* ActorMiddleTouching,
const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching)
{
if (IsValid(ActorThumbTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorThumbTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
if (IsValid(ActorIndexTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorIndexTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
if (IsValid(ActorMiddleTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorMiddleTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
if (IsValid(ActorRingTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorRingTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
if (IsValid(ActorPinkyTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorPinkyTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
return 0.0f;
}
float ASGPlayerController::FImpl::GetVibrotactileLevel(const AActor* Actor)
{
if (IsValid(Actor))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(Actor);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileLevel();
}
}
return 0.0f;
}
TArray<float> ASGPlayerController::FImpl::GetForceFeedbackLevels(
const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
@@ -213,30 +132,6 @@ TArray<float> ASGPlayerController::FImpl::GetForceFeedbackLevels(
return ForceFeedbackLevels;
}
TArray<float> ASGPlayerController::FImpl::GetVibrotactileLevels(
const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
const AActor* ActorMiddleTouching,
const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching)
{
const float ThumbVibrotactileLevel = GetVibrotactileLevel(ActorThumbTouching);
const float IndexVibrotactileLevel = GetVibrotactileLevel(ActorIndexTouching);
const float MiddleVibrotactileLevel = GetVibrotactileLevel(ActorMiddleTouching);
const float RingVibrotactileLevel = GetVibrotactileLevel(ActorRingTouching);
const float PinkyVibrotactileLevel = GetVibrotactileLevel(ActorPinkyTouching);
const TArray<float> ForceFeedbackLevels{
ThumbVibrotactileLevel,
IndexVibrotactileLevel,
MiddleVibrotactileLevel,
RingVibrotactileLevel,
PinkyVibrotactileLevel,
};
return ForceFeedbackLevels;
}
ASGPlayerController::ASGPlayerController(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer),
Pimpl(TUniquePtr<FImpl, FImplDeleter>(new FImpl{this}, PimplDeleter))
@@ -330,6 +225,29 @@ ASGPlayerController::FImpl::FImpl(ASGPlayerController* InOwner)
ASGPlayerController::FImpl::~FImpl() = default;
USGCustomWaveform* ASGPlayerController::FImpl::GetCustomWaveform(const AActor* Actor)
{
float Amplitude = 0.0f;
float Duration = 0.0f;
float Frequency = 0.0f;
if (IsValid(Actor))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(Actor);
if (IsValid(TouchComponent))
{
Amplitude = TouchComponent->GetVibrotactileAmplitude();
Duration = TouchComponent->GetVibrotactileDuration();
Frequency = TouchComponent->GetVibrotactileFrequency();
}
}
USGCustomWaveform* CustomWaveform{
USGCustomWaveform::NewCustomWaveform(Owner, Amplitude, Duration, Frequency)
};
return CustomWaveform;
}
void ASGPlayerController::FImpl::UpdateHapticsFeedback(const FSGTouchState& TouchState)
{
static const TArray<float> VibrotactileOffCommand{0.0f, 0.0f, 0.0, 0.0, 0.0f};
@@ -359,44 +277,43 @@ void ASGPlayerController::FImpl::UpdateHapticsFeedback(const FSGTouchState& Touc
};
Glove->QueueForceFeedbackLevels(MoveTemp(ForceFeedbackLevels));
// Queue the Vibrotactile command...
TArray<float> VibrotactileLevels{
GetVibrotactileLevels(
TouchState.ActorThumbTouching, TouchState.ActorIndexTouching, TouchState.ActorMiddleTouching,
TouchState.ActorRingTouching, TouchState.ActorPinkyTouching)
};
Glove->QueueVibroLevels(MoveTemp(VibrotactileLevels));
// Send the haptics commands!
Glove->SendHaptics();
// Stop the Vibrotactile command after the timeout if any haptic feedback is ongoing.
const float VibrotactileDuration = FImpl::GetVibrotactileDuration(
TouchState.ActorThumbTouching, TouchState.ActorIndexTouching, TouchState.ActorMiddleTouching,
TouchState.ActorRingTouching, TouchState.ActorPinkyTouching);
Owner->GetWorldTimerManager().ClearTimer(TouchVibrotactileStopTimer);
FTimerDelegate TouchVibrotactileStopHandler;
TouchVibrotactileStopHandler.BindLambda([= SG_CAPTURE_THIS]()-> void
// Send Vibrotactile to the thumb finger if it's touching an actor...
if (IsValid(TouchState.ActorThumbTouching))
{
if (!IsValid(Glove))
{
return;
}
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorThumbTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::ThumbTip);
}
const bool bGloveConnected = Glove->IsConnected();
if (!bGloveConnected)
{
return;
}
// Send Vibrotactile to the index finger if it's touching an actor...
if (IsValid(TouchState.ActorIndexTouching))
{
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorIndexTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::IndexTip);
}
Glove->QueueVibroLevels(VibrotactileOffCommand);
Glove->SendHaptics();
});
// Send Vibrotactile to the middle finger if it's touching an actor...
if (IsValid(TouchState.ActorMiddleTouching))
{
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorMiddleTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::MiddleTip);
}
Owner->GetWorldTimerManager().SetTimer(
TouchVibrotactileStopTimer, TouchVibrotactileStopHandler, VibrotactileDuration, false, -1.0f);
// Send Vibrotactile to the ring finger if it's touching an actor...
if (IsValid(TouchState.ActorRingTouching))
{
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorRingTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::RingTip);
}
// Send Vibrotactile to the pinky finger if it's touching an actor...
if (IsValid(TouchState.ActorPinkyTouching))
{
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorPinkyTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::PinkyTip);
}
}
void ASGPlayerController::FImplDeleter::operator()(const FImpl* P) const
@@ -57,12 +57,17 @@ private:
meta=(AllowPrivateAccess="false", ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0"))
float ForceFeedbackLevel;
UPROPERTY(EditAnywhere, Category="SenseGlove", meta=(AllowPrivateAccess="false", ClampMin = "0.0", UIMin = "0.0"))
UPROPERTY(EditAnywhere, Category="SenseGlove",
meta=(AllowPrivateAccess="false", ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0"))
float VibrotactileAmplitude;
UPROPERTY(EditAnywhere, Category="SenseGlove",
meta=(AllowPrivateAccess="false", ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0"))
float VibrotactileDuration;
UPROPERTY(EditAnywhere, Category="SenseGlove",
meta=(AllowPrivateAccess="false", ClampMin = "0.0", ClampMax = "100.0", UIMin = "0.0", UIMax = "100.0"))
float VibrotactileLevel;
meta=(AllowPrivateAccess="false", ClampMin = "10.0", ClampMax = "500.0", UIMin = "10.0", UIMax = "500.0"))
float VibrotactileFrequency;
private:
struct FImpl;
@@ -86,6 +91,16 @@ public:
ForceFeedbackLevel = Level;
}
FORCEINLINE float GetVibrotactileAmplitude() const
{
return VibrotactileAmplitude;
}
FORCEINLINE void SetVibrotactileAmplitude(const float Amplitude)
{
VibrotactileAmplitude = Amplitude;
}
FORCEINLINE float GetVibrotactileDuration() const
{
return VibrotactileDuration;
@@ -95,13 +110,14 @@ public:
{
VibrotactileDuration = Duration;
}
FORCEINLINE float GetVibrotactileLevel() const
FORCEINLINE float GetVibrotactileFrequency() const
{
return VibrotactileLevel;
return VibrotactileFrequency;
}
FORCEINLINE void SetVibrotactileLevel(const float Level)
FORCEINLINE void SetVibrotactileFrequency(const float Frequency)
{
VibrotactileLevel = Level;
VibrotactileFrequency = Frequency;
}
};
@@ -60,14 +60,14 @@ void UTouchComponentKismetLibrary::SetForceFeedbackLevel(USGTouchComponent* Touc
TouchComponent->SetForceFeedbackLevel(Level);
}
float UTouchComponentKismetLibrary::GetVibrotactileLevel(const USGTouchComponent* TouchComponent)
float UTouchComponentKismetLibrary::GetVibrotactileAmplitude(const USGTouchComponent* TouchComponent)
{
return TouchComponent->GetVibrotactileLevel();
return TouchComponent->GetVibrotactileAmplitude();
}
void UTouchComponentKismetLibrary::SetVibrotactileLevel(USGTouchComponent* TouchComponent, const float Level)
void UTouchComponentKismetLibrary::SetVibrotactileAmplitude(USGTouchComponent* TouchComponent, const float Amplitude)
{
TouchComponent->SetVibrotactileLevel(Level);
TouchComponent->SetVibrotactileAmplitude(Amplitude);
}
float UTouchComponentKismetLibrary::GetVibrotactileDuration(const USGTouchComponent* TouchComponent)
@@ -78,4 +78,15 @@ float UTouchComponentKismetLibrary::GetVibrotactileDuration(const USGTouchCompon
void UTouchComponentKismetLibrary::SetVibrotactileDuration(USGTouchComponent* TouchComponent, const float Duration)
{
TouchComponent->SetVibrotactileDuration(Duration);
}
}
float UTouchComponentKismetLibrary::GetVibrotactileFrequency(const USGTouchComponent* TouchComponent)
{
return TouchComponent->GetVibrotactileFrequency();
}
void UTouchComponentKismetLibrary::SetVibrotactileFrequency(USGTouchComponent* TouchComponent, const float Frequency)
{
TouchComponent->SetVibrotactileFrequency(Frequency);
}
@@ -61,14 +61,20 @@ public:
static void SetForceFeedbackLevel(UPARAM(ref) USGTouchComponent* TouchComponent, float Level);
UFUNCTION(BlueprintPure, Category="SenseGlove | Components | Touch Component")
static float GetVibrotactileLevel(const USGTouchComponent* TouchComponent);
static float GetVibrotactileAmplitude(const USGTouchComponent* TouchComponent);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Touch Component")
static void SetVibrotactileLevel(UPARAM(ref) USGTouchComponent* TouchComponent, float Level);
static void SetVibrotactileAmplitude(UPARAM(ref) USGTouchComponent* TouchComponent, float Amplitude);
UFUNCTION(BlueprintPure, Category="SenseGlove | Components | Touch Component")
static float GetVibrotactileDuration(const USGTouchComponent* TouchComponent);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Touch Component")
static void SetVibrotactileDuration(UPARAM(ref) USGTouchComponent* TouchComponent, float Duration);
UFUNCTION(BlueprintPure, Category="SenseGlove | Components | Touch Component")
static float GetVibrotactileFrequency(const USGTouchComponent* TouchComponent);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Touch Component")
static void SetVibrotactileFrequency(UPARAM(ref) USGTouchComponent* TouchComponent, float Frequency);
};