add support for htc vive focus vision hmd auto-detection and various htc hmds auto-detection support on android

This commit is contained in:
Mamadou Babaei
2025-02-14 12:10:33 +01:00
parent 96b4949472
commit 2af9abd2bb
10 changed files with 290 additions and 40 deletions
+3
View File
@@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Introduced the `Meta XR` plugin compatibility.
- Introduced the `ViveOpenXR` plugin compatibility.
- Added the `FSGPluginUtils` utility class for other plugins or modules availability detection such as `Meta XR` and `ViveOpenXR`.
- Added various HTC HMDs auto-detection support on Android.
- Added support for HTC VIVE Focus Vision HMD auto-detection.
### Fixed
@@ -29,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Bumped the SenseGlove Unreal Engine Marketplace Packager `v0.5.0-7df1183`.
- Bumped the copyright years.
- This is the last release to support Unreal Engine `5.2`. From `v2.5.x` onwards only UE `5.3` and newer will be supported.
- The `ESGViveHMDDetectionPriority` enum items has changed and is no longer backward-compatible.
### Documentation
@@ -6,4 +6,33 @@ Provides the tracking settings related to head-mounted displays (HDMs) and their
## ViveHMDDetectionPriority
Determines which VIVE HMD to prioritize for detection, as the current detection mechanism cannot differentiate between the HTC VIVE Focus 3 and the HTC VIVE XR Elite.
Determines which VIVE HMD to prioritize for detection, as the current detection mechanism cannot differentiate between HTC VIVE Focus Vision, HTC VIVE XR Elite, and HTC VIVE Focus 3.
The following values are possible:
```cpp
/*
* The HTC VIVE HMD detection priority for HTC devices that we cannot distinguish.
*/
UENUM(BlueprintType)
enum class ESGViveHMDDetectionPriority : uint8
{
/* First try to detect HTC VIVE Focus Vision, then XR Elite, and then Focus 3. */
FocusVision_XRElite_Focus3 UMETA(DisplayName = "Focus Vision (1st), XR Elite (2nd), Focus3 (3rd)"),
/* First try to detect HTC VIVE Focus Vision, then Focus 3, and then XR Elite. */
FocusVision_Focus3_XRElite UMETA(DisplayName = "Focus Vision (1st), Focus3 (2nd), XR Elite (3rd)"),
/* First try to detect HTC VIVE XR Elite, then Focus Vision, and then Focus 3. */
XRElite_FocusVision_Focus3 UMETA(DisplayName = "XR Elite (1st), Focus Vision (2nd), Focus3 (3rd)"),
/* First try to detect HTC VIVE XR Elite, then Focus 3, and then Focus Vision. */
XRElite_Focus3_FocusVision UMETA(DisplayName = "XR Elite (1st), Focus3 (2nd), Focus Vision (3rd)"),
/* First try to detect HTC VIVE Focus 3, then Focus Vision, and then XR Elite. */
Focus3_FocusVision_XRElite UMETA(DisplayName = "Focus3 (1st), Focus Vision (2nd), XR Elite (3rd)"),
/* First try to detect HTC VIVE Focus 3, then XR Elite, and then Focus Vision. */
Focus3_XRElite_FocusVision UMETA(DisplayName = "Focus3 (1st), XR Elite (2nd), Focus Vision (3rd)"),
};
```
@@ -26,10 +26,11 @@ At the moment the following hardware are supported:
> [!CAUTION]
> Due to highly experimental nature of the HMD auto-detection feature, the HTC
> VIVE Focus 3 and HTC XR Elite cannot be distinguished from each other in the
> current iteration. However, since the tracker devices and offsets for both
> headsets are the same, this should not affect performance or functionality.
> The order in which the HMD is detected can be specified through the
> VIVE Focus Vision, HTC VIVE Focus 3, and HTC VIVE XR Elite cannot be
> distinguished from each other in the current iteration. However, since the
> tracker devices and offsets for all these headsets are the same, this should
> not affect the performance or any functionality. The order in which the HMD is
> detected can be specified through the
> [HMD-tracker setting `ViveHMDDetectionPriority`](../hmd-tracking.html#vivehmddetectionpriority).
## TrackingHardwareLocationOffsetLeftHand
@@ -37,7 +37,7 @@
FSGHMDTrackingSettings::FSGHMDTrackingSettings()
: FSGHMDTrackingSettings{
ESGViveHMDDetectionPriority::HtcViveFocus3First
ESGViveHMDDetectionPriority::FocusVision_XRElite_Focus3
}
{
}
@@ -54,7 +54,7 @@ struct SENSEGLOVESETTINGS_API FSGHMDTrackingSettings
public:
/**
* Determines which VIVE HMD to prioritize for detection, as the current detection mechanism cannot differentiate
* between the HTC VIVE Focus 3 and the HTC VIVE XR Elite.
* between HTC VIVE Focus Vision, HTC VIVE XR Elite, and HTC VIVE Focus 3.
*/
UPROPERTY(Config, EditDefaultsOnly, Category="HMD Tracking")
ESGViveHMDDetectionPriority ViveHMDDetectionPriority;
@@ -70,11 +70,11 @@ public:
* the tracking hardware.
*
* Caution:
* Due to highly experimental nature of the HMD auto-detection feature, the HTC VIVE Focus 3 and HTC XR Elite
* cannot be distinguished from each other in the current iteration. However, since the tracker devices and offsets
* for both headsets are the same, this should not affect performance or functionality.
* The order in which the HMD is detected can be specified through the HMD-tracker setting
* `ViveHMDDetectionPriority`.
* Due to highly experimental nature of the HMD auto-detection feature, the HTC VIVE Focus Vision, HTC VIVE XR
* Elite, and HTC VIVE Focus Vision cannot be distinguished from each other in the current iteration. However,
* since the tracker devices and offsets for all these headsets are the same, this should not affect the
* performance or any functionality. The order in which the HMD is detected can be specified through the
* HMD-tracker setting `ViveHMDDetectionPriority`.
*/
UPROPERTY(Config, EditDefaultsOnly, Category = "Wrist Tracking")
ESGPositionalTrackingHardware TrackingHardware;
@@ -150,13 +150,19 @@ bool FSGHMDTracker::IsHtcVivePro()
/// NOTE
// VIVE Pro:
// - Official Spec: 1440 x 1600 pixels per eye (2880 x 1600 pixels combined)
// - Unreal OpenXR Resolution: 4936 x 2740
// - Unreal OpenXR Resolution (PCVR): 4936 x 2740
// VIVE Focus 3:
// - Official Spec: 2448 x 2448 pixels per eye (4896 x 2448 pixels combined)
// - Unreal OpenXR Resolution: 5016 x 2508
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): ?
// VIVE XR Elite
// - Official Spec: 1920 x 1920 pixels per eye (3840 x 1920 pixels combined)
// - Unreal OpenXR Resolution: 5016 x 2508
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): ?
// VIVE Focus Vision
// - Official Spec: 2448 x 2448 pixels per eye (4896 x 2448 pixels combined)
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): 1720 x 1720
if (HmdMonitorInfo.ResolutionX < 5000 && HmdMonitorInfo.ResolutionY > 2700)
{
bResolutionMatches = true;
@@ -173,6 +179,13 @@ bool FSGHMDTracker::IsHtcVivePro()
bool FSGHMDTracker::IsHtcViveFocus3()
{
#if PLATFORM_ANDROID
static const FName DeviceIdentifier{TEXT("WAVE:SUE")};
const FName DeviceName{GetDeviceName()};
const bool bNameMatches = DeviceName == DeviceIdentifier;
#else /* PLATFORM_ANDROID */
static const FName DeviceIdentifier{TEXT("Vive OpenXR: Vive SRanipal")};
static const FString ViveDeviceIdentifier{TEXT("Vive")};
static const FString SRanipalDeviceIdentifier{TEXT("SRanipal")};
@@ -186,11 +199,12 @@ bool FSGHMDTracker::IsHtcViveFocus3()
bNameMatches = DeviceNameString.Contains(ViveDeviceIdentifier)
|| DeviceNameString.Contains(SRanipalDeviceIdentifier);
}
#endif /* PLATFORM_ANDROID */
/// NOTE
/// For the time being since we cannot distinguish between VIVE Focus 3 and VIVE XR Elite using resolution checks,
/// we skip the resolution checks altogether and assume it's not a VIVE Pro, as VIVE Pro won't come with Android
/// support.
/// For the time being since we cannot distinguish between VIVE Focus Vision, VIVE XR Elite, and VIVE Focus 3 using
/// resolution checks, we skip the resolution checks altogether and assume it's not a VIVE Pro, as VIVE Pro won't
/// come with Android support.
#if PLATFORM_ANDROID
bool bResolutionMatches = true;
#else /* PLATFORM_ANDROID */
@@ -209,15 +223,21 @@ bool FSGHMDTracker::IsHtcViveFocus3()
/// NOTE
// VIVE Pro:
// - Official Spec: 1440 x 1600 pixels per eye (2880 x 1600 pixels combined)
// - Unreal OpenXR Resolution: 4936 x 2740
// - Unreal OpenXR Resolution (PCVR): 4936 x 2740
// VIVE Focus 3:
// - Official Spec: 2448 x 2448 pixels per eye (4896 x 2448 pixels combined)
// - Unreal OpenXR Resolution: 5016 x 2508
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): ?
// VIVE XR Elite
// - Official Spec: 1920 x 1920 pixels per eye (3840 x 1920 pixels combined)
// - Unreal OpenXR Resolution: 5016 x 2508
if (HmdMonitorInfo.ResolutionX > 5000
&& (HmdMonitorInfo.ResolutionY > 2500 && HmdMonitorInfo.ResolutionY < 2700))
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): ?
// VIVE Focus Vision
// - Official Spec: 2448 x 2448 pixels per eye (4896 x 2448 pixels combined)
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): 1720 x 1720
if (HmdMonitorInfo.ResolutionX > 5000 &&
(HmdMonitorInfo.ResolutionY > 2500 && HmdMonitorInfo.ResolutionY < 2700))
{
bResolutionMatches = true;
}
@@ -233,6 +253,13 @@ bool FSGHMDTracker::IsHtcViveFocus3()
bool FSGHMDTracker::IsHtcViveXRElite()
{
#if PLATFORM_ANDROID
static const FName DeviceIdentifier{TEXT("WAVE:SUE")};
const FName DeviceName{GetDeviceName()};
const bool bNameMatches = DeviceName == DeviceIdentifier;
#else /* PLATFORM_ANDROID */
static const FName DeviceIdentifier{TEXT("Vive OpenXR: Vive SRanipal")};
static const FString ViveDeviceIdentifier{TEXT("Vive")};
static const FString SRanipalDeviceIdentifier{TEXT("SRanipal")};
@@ -246,11 +273,12 @@ bool FSGHMDTracker::IsHtcViveXRElite()
bNameMatches = DeviceNameString.Contains(ViveDeviceIdentifier)
|| DeviceNameString.Contains(SRanipalDeviceIdentifier);
}
#endif /* PLATFORM_ANDROID */
/// NOTE
/// For the time being since we cannot distinguish between VIVE Focus 3 and VIVE XR Elite using resolution checks,
/// we skip the resolution checks altogether and assume it's not a VIVE Pro, as VIVE Pro won't come with Android
/// support.
/// For the time being since we cannot distinguish between VIVE Focus Vision, VIVE XR Elite, and VIVE Focus 3 using
/// resolution checks, we skip the resolution checks altogether and assume it's not a VIVE Pro, as VIVE Pro won't
/// come with Android support.
#if PLATFORM_ANDROID
bool bResolutionMatches = true;
#else /* PLATFORM_ANDROID */
@@ -269,13 +297,93 @@ bool FSGHMDTracker::IsHtcViveXRElite()
/// NOTE
// VIVE Pro:
// - Official Spec: 1440 x 1600 pixels per eye (2880 x 1600 pixels combined)
// - Unreal OpenXR Resolution: 4936 x 2740
// - Unreal OpenXR Resolution (PCVR): 4936 x 2740
// VIVE Focus 3:
// - Official Spec: 2448 x 2448 pixels per eye (4896 x 2448 pixels combined)
// - Unreal OpenXR Resolution: 5016 x 2508
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): ?
// VIVE XR Elite
// - Official Spec: 1920 x 1920 pixels per eye (3840 x 1920 pixels combined)
// - Unreal OpenXR Resolution: 5016 x 2508
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): ?
// VIVE Focus Vision
// - Official Spec: 2448 x 2448 pixels per eye (4896 x 2448 pixels combined)
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): 1720 x 1720
if (HmdMonitorInfo.ResolutionX > 5000 &&
(HmdMonitorInfo.ResolutionY > 2500 && HmdMonitorInfo.ResolutionY < 2700))
{
bResolutionMatches = true;
}
}
}
}
#endif /* PLATFORM_ANDROID */
const bool bMatched = bNameMatches && bResolutionMatches;
return bMatched;
}
bool FSGHMDTracker::IsHtcViveFocusVision()
{
#if PLATFORM_ANDROID
static const FName DeviceIdentifier{TEXT("WAVE:SUE")};
const FName DeviceName{GetDeviceName()};
const bool bNameMatches = DeviceName == DeviceIdentifier;
#else /* PLATFORM_ANDROID */
static const FName DeviceIdentifier{TEXT("Vive OpenXR: Vive SRanipal")};
static const FString ViveDeviceIdentifier{TEXT("Vive")};
static const FString SRanipalDeviceIdentifier{TEXT("SRanipal")};
const FName DeviceName{GetDeviceName()};
bool bNameMatches = DeviceName == DeviceIdentifier;
if (!bNameMatches)
{
const FString DeviceNameString{GetDeviceName().ToString()};
bNameMatches = DeviceNameString.Contains(ViveDeviceIdentifier)
|| DeviceNameString.Contains(SRanipalDeviceIdentifier);
}
#endif /* PLATFORM_ANDROID */
/// NOTE
/// For the time being since we cannot distinguish between VIVE Focus Vision, VIVE XR Elite, and VIVE Focus 3 using
/// resolution checks, we skip the resolution checks altogether and assume it's not a VIVE Pro, as VIVE Pro won't
/// come with Android support.
#if PLATFORM_ANDROID
bool bResolutionMatches = true;
#else /* PLATFORM_ANDROID */
bool bResolutionMatches = false;
if (bNameMatches)
{
if (GEngine && GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowed())
{
IHeadMountedDisplay* Device{GEngine->XRSystem->GetHMDDevice()};
if (Device)
{
IHeadMountedDisplay::MonitorInfo HmdMonitorInfo;
Device->GetHMDMonitorInfo(HmdMonitorInfo);
/// NOTE
// VIVE Pro:
// - Official Spec: 1440 x 1600 pixels per eye (2880 x 1600 pixels combined)
// - Unreal OpenXR Resolution (PCVR): 4936 x 2740
// VIVE Focus 3:
// - Official Spec: 2448 x 2448 pixels per eye (4896 x 2448 pixels combined)
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): ?
// VIVE XR Elite
// - Official Spec: 1920 x 1920 pixels per eye (3840 x 1920 pixels combined)
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): ?
// VIVE Focus Vision
// - Official Spec: 2448 x 2448 pixels per eye (4896 x 2448 pixels combined)
// - Unreal OpenXR Resolution (PCVR): 5016 x 2508
// - Unreal OpenXR Resolution (Standalone): 1720 x 1720
if (HmdMonitorInfo.ResolutionX > 5000 &&
(HmdMonitorInfo.ResolutionY > 2500 && HmdMonitorInfo.ResolutionY < 2700))
{
@@ -315,9 +423,34 @@ ESGHeadMountedDisplayDevice FSGHMDTracker::GetDeviceType()
const USGSettings* Settings{USGSettings::GetInstance()};
ensureAlwaysMsgf(Settings, TEXT("The settings subsystem has not been initialized!"));
if (Settings->GetTrackingSettings().HMDTrackingSettings.ViveHMDDetectionPriority ==
ESGViveHMDDetectionPriority::HtcViveFocus3First)
ESGViveHMDDetectionPriority::FocusVision_XRElite_Focus3)
{
if (IsHtcViveFocusVision())
{
return ESGHeadMountedDisplayDevice::HtcViveFocusVision;
}
if (IsHtcViveXRElite())
{
return ESGHeadMountedDisplayDevice::HtcViveXRElite;
}
if (IsHtcViveFocus3())
{
return ESGHeadMountedDisplayDevice::HtcViveFocus3;
}
}
if (Settings->GetTrackingSettings().HMDTrackingSettings.ViveHMDDetectionPriority ==
ESGViveHMDDetectionPriority::FocusVision_Focus3_XRElite)
{
if (IsHtcViveFocusVision())
{
return ESGHeadMountedDisplayDevice::HtcViveFocusVision;
}
if (IsHtcViveFocus3())
{
return ESGHeadMountedDisplayDevice::HtcViveFocus3;
@@ -328,7 +461,28 @@ ESGHeadMountedDisplayDevice FSGHMDTracker::GetDeviceType()
return ESGHeadMountedDisplayDevice::HtcViveXRElite;
}
}
else
if (Settings->GetTrackingSettings().HMDTrackingSettings.ViveHMDDetectionPriority ==
ESGViveHMDDetectionPriority::XRElite_FocusVision_Focus3)
{
if (IsHtcViveXRElite())
{
return ESGHeadMountedDisplayDevice::HtcViveXRElite;
}
if (IsHtcViveFocusVision())
{
return ESGHeadMountedDisplayDevice::HtcViveFocusVision;
}
if (IsHtcViveFocus3())
{
return ESGHeadMountedDisplayDevice::HtcViveFocus3;
}
}
if (Settings->GetTrackingSettings().HMDTrackingSettings.ViveHMDDetectionPriority ==
ESGViveHMDDetectionPriority::XRElite_Focus3_FocusVision)
{
if (IsHtcViveXRElite())
{
@@ -339,6 +493,49 @@ ESGHeadMountedDisplayDevice FSGHMDTracker::GetDeviceType()
{
return ESGHeadMountedDisplayDevice::HtcViveFocus3;
}
if (IsHtcViveFocusVision())
{
return ESGHeadMountedDisplayDevice::HtcViveFocusVision;
}
}
if (Settings->GetTrackingSettings().HMDTrackingSettings.ViveHMDDetectionPriority ==
ESGViveHMDDetectionPriority::Focus3_FocusVision_XRElite)
{
if (IsHtcViveFocus3())
{
return ESGHeadMountedDisplayDevice::HtcViveFocus3;
}
if (IsHtcViveFocusVision())
{
return ESGHeadMountedDisplayDevice::HtcViveFocusVision;
}
if (IsHtcViveXRElite())
{
return ESGHeadMountedDisplayDevice::HtcViveXRElite;
}
}
if (Settings->GetTrackingSettings().HMDTrackingSettings.ViveHMDDetectionPriority ==
ESGViveHMDDetectionPriority::Focus3_XRElite_FocusVision)
{
if (IsHtcViveFocus3())
{
return ESGHeadMountedDisplayDevice::HtcViveFocus3;
}
if (IsHtcViveXRElite())
{
return ESGHeadMountedDisplayDevice::HtcViveXRElite;
}
if (IsHtcViveFocusVision())
{
return ESGHeadMountedDisplayDevice::HtcViveFocusVision;
}
}
return ESGHeadMountedDisplayDevice::None;
@@ -95,9 +95,14 @@ public:
*/
static bool IsHtcViveXRElite();
/**
* Checks whether the HMD device is HTC VIVE Focus Vision, or not.
*/
static bool IsHtcViveFocusVision();
FORCEINLINE static bool IsAHtcViveDevice()
{
return IsHtcVivePro() || IsHtcViveFocus3() || IsHtcViveXRElite();
return IsHtcVivePro() || IsHtcViveFocus3() || IsHtcViveXRElite() || IsHtcViveFocusVision();
}
static ESGHeadMountedDisplayDevice GetDeviceType();
@@ -64,17 +64,32 @@ enum class ESGHeadMountedDisplayDevice : uint8
/* The HTC VIVE XR Elite HMD. */
HtcViveXRElite UMETA(DisplayName = "HTC VIVE XR Elite"),
/* The HTC VIVE Focus 3 HMD. */
HtcViveFocusVision UMETA(DisplayName = "HTC VIVE Focus Vision"),
};
/*
* The
* The HTC VIVE HMD detection priority for HTC devices that we cannot distinguish.
*/
UENUM(BlueprintType)
enum class ESGViveHMDDetectionPriority : uint8
{
/* First try to detect HTC VIVE Focus 3. */
HtcViveFocus3First UMETA(DisplayName = "HTC VIVE Focus 3 First"),
/* First try to detect HTC VIVE Focus Vision, then XR Elite, and then Focus 3. */
FocusVision_XRElite_Focus3 UMETA(DisplayName = "Focus Vision (1st), XR Elite (2nd), Focus3 (3rd)"),
/* First try to detect HTC VIVE XR Elite. */
HtcViveXREliteFirst UMETA(DisplayName = "HTC VIVE XR Elite First"),
};
/* First try to detect HTC VIVE Focus Vision, then Focus 3, and then XR Elite. */
FocusVision_Focus3_XRElite UMETA(DisplayName = "Focus Vision (1st), Focus3 (2nd), XR Elite (3rd)"),
/* First try to detect HTC VIVE XR Elite, then Focus Vision, and then Focus 3. */
XRElite_FocusVision_Focus3 UMETA(DisplayName = "XR Elite (1st), Focus Vision (2nd), Focus3 (3rd)"),
/* First try to detect HTC VIVE XR Elite, then Focus 3, and then Focus Vision. */
XRElite_Focus3_FocusVision UMETA(DisplayName = "XR Elite (1st), Focus3 (2nd), Focus Vision (3rd)"),
/* First try to detect HTC VIVE Focus 3, then Focus Vision, and then XR Elite. */
Focus3_FocusVision_XRElite UMETA(DisplayName = "Focus3 (1st), Focus Vision (2nd), XR Elite (3rd)"),
/* First try to detect HTC VIVE Focus 3, then XR Elite, and then Focus Vision. */
Focus3_XRElite_FocusVision UMETA(DisplayName = "Focus3 (1st), XR Elite (2nd), Focus Vision (3rd)"),
};