345 lines
12 KiB
C++
345 lines
12 KiB
C++
/**
|
|
* @file
|
|
*
|
|
* @author Mamadou Babaei <mamadou@senseglove.com>
|
|
*
|
|
* @section LICENSE
|
|
*
|
|
* (The MIT License)
|
|
*
|
|
* Copyright (c) 2020 - 2024 SenseGlove
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
* @section DESCRIPTION
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
#include "SGTracking/SGHMDTracker.h"
|
|
|
|
#include "Engine/Engine.h"
|
|
#include "IHeadMountedDisplay.h"
|
|
#include "IXRTrackingSystem.h"
|
|
|
|
#include "SGSettings/SGSettings.h"
|
|
|
|
FName FSGHMDTracker::GetDeviceName()
|
|
{
|
|
if (GEngine && GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowed())
|
|
{
|
|
const IHeadMountedDisplay* Device{GEngine->XRSystem->GetHMDDevice()};
|
|
if (Device)
|
|
{
|
|
const FName DeviceName{Device->GetHMDName()};
|
|
return DeviceName;
|
|
}
|
|
}
|
|
return NAME_None;
|
|
}
|
|
|
|
bool FSGHMDTracker::IsMetaQuest2()
|
|
{
|
|
static const FName MetaQuest2DeviceIdentifier{TEXT("Meta Quest 2")};
|
|
static const FName OculusQuest2DeviceIdentifier{TEXT("Oculus Quest2")};
|
|
static const FString Quest2DeviceIdentifier1{TEXT("Quest 2")};
|
|
static const FString Quest2DeviceIdentifier2{TEXT("Quest2")};
|
|
|
|
const FName DeviceName{GetDeviceName()};
|
|
bool bMatched = DeviceName == MetaQuest2DeviceIdentifier || DeviceName == OculusQuest2DeviceIdentifier;
|
|
if (!bMatched)
|
|
{
|
|
const FString DeviceNameString{GetDeviceName().ToString()};
|
|
bMatched = DeviceNameString.Contains(Quest2DeviceIdentifier1)
|
|
|| DeviceNameString.Contains(Quest2DeviceIdentifier2);
|
|
}
|
|
|
|
return bMatched;
|
|
}
|
|
|
|
bool FSGHMDTracker::IsMetaQuestPro()
|
|
{
|
|
static const FName MetaQuestProDeviceIdentifier{TEXT("Meta Quest Pro")};
|
|
static const FName OculusQuestProDeviceIdentifier{TEXT("Oculus QuestPro")};
|
|
static const FString QuestProDeviceIdentifier1{TEXT("Quest Pro")};
|
|
static const FString QuestProDeviceIdentifier2{TEXT("QuestPro")};
|
|
|
|
const FName DeviceName{GetDeviceName()};
|
|
bool bMatched = DeviceName == MetaQuestProDeviceIdentifier || DeviceName == OculusQuestProDeviceIdentifier;
|
|
if (!bMatched)
|
|
{
|
|
const FString DeviceNameString{GetDeviceName().ToString()};
|
|
bMatched = DeviceNameString.Contains(QuestProDeviceIdentifier1)
|
|
|| DeviceNameString.Contains(QuestProDeviceIdentifier2);
|
|
}
|
|
|
|
return bMatched;
|
|
}
|
|
|
|
bool FSGHMDTracker::IsMetaQuest3()
|
|
{
|
|
static const FName MetaQuest3DeviceIdentifier{TEXT("Meta Quest 3")};
|
|
static const FName OculusQuest3DeviceIdentifier{TEXT("Oculus Quest3")};
|
|
static const FString Quest3DeviceIdentifier1{TEXT("Quest 3")};
|
|
static const FString Quest3DeviceIdentifier2{TEXT("Quest3")};
|
|
|
|
const FName DeviceName{GetDeviceName()};
|
|
bool bMatched = DeviceName == MetaQuest3DeviceIdentifier || DeviceName == OculusQuest3DeviceIdentifier;
|
|
if (!bMatched)
|
|
{
|
|
const FString DeviceNameString{GetDeviceName().ToString()};
|
|
bMatched = DeviceNameString.Contains(Quest3DeviceIdentifier1)
|
|
|| DeviceNameString.Contains(Quest3DeviceIdentifier2);
|
|
}
|
|
|
|
return bMatched;
|
|
}
|
|
|
|
bool FSGHMDTracker::IsHtcVivePro()
|
|
{
|
|
#if PLATFORM_ANDROID
|
|
return false;
|
|
#else /* PLATFORM_ANDROID */
|
|
static const FName DeviceIdentifier{TEXT("Vive OpenXR: Vive SRanipal")};
|
|
static const FString ViveDeviceIdentifier{TEXT("Vive")};
|
|
static const FString SRanipalDeviceIdentifier{TEXT("SRanipal")};
|
|
|
|
static const FName DeviceIdentifier2{TEXT("SteamVR/OpenXR : lighthouse")};
|
|
static const FString LighthouseIdentifier{TEXT("lighthouse")};
|
|
|
|
const FName DeviceName{GetDeviceName()};
|
|
|
|
bool bNameMatches = DeviceName == DeviceIdentifier || DeviceName == DeviceIdentifier2;
|
|
if (!bNameMatches)
|
|
{
|
|
const FString DeviceNameString{GetDeviceName().ToString()};
|
|
bNameMatches = DeviceNameString.Contains(ViveDeviceIdentifier)
|
|
|| DeviceNameString.Contains(SRanipalDeviceIdentifier)
|
|
|| DeviceNameString.Contains(LighthouseIdentifier);
|
|
}
|
|
|
|
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: 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
|
|
// 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 > 2700)
|
|
{
|
|
bResolutionMatches = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const bool bMatched = bNameMatches && bResolutionMatches;
|
|
|
|
return bMatched;
|
|
#endif /* PLATFORM_ANDROID */
|
|
}
|
|
|
|
bool FSGHMDTracker::IsHtcViveFocus3()
|
|
{
|
|
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);
|
|
}
|
|
|
|
/// 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.
|
|
#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: 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
|
|
// 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))
|
|
{
|
|
bResolutionMatches = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* PLATFORM_ANDROID */
|
|
|
|
const bool bMatched = bNameMatches && bResolutionMatches;
|
|
|
|
return bMatched;
|
|
}
|
|
|
|
bool FSGHMDTracker::IsHtcViveXRElite()
|
|
{
|
|
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);
|
|
}
|
|
|
|
/// 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.
|
|
#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: 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
|
|
// 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))
|
|
{
|
|
bResolutionMatches = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* PLATFORM_ANDROID */
|
|
|
|
const bool bMatched = bNameMatches && bResolutionMatches;
|
|
|
|
return bMatched;
|
|
}
|
|
|
|
ESGHeadMountedDisplayDevice FSGHMDTracker::GetDeviceType()
|
|
{
|
|
if (IsMetaQuest2())
|
|
{
|
|
return ESGHeadMountedDisplayDevice::MetaQuest2;
|
|
}
|
|
|
|
if (IsMetaQuestPro())
|
|
{
|
|
return ESGHeadMountedDisplayDevice::MetaQuestPro;
|
|
}
|
|
|
|
if (IsMetaQuest3())
|
|
{
|
|
return ESGHeadMountedDisplayDevice::MetaQuest3;
|
|
}
|
|
|
|
if (IsHtcVivePro())
|
|
{
|
|
return ESGHeadMountedDisplayDevice::HtcVivePro;
|
|
}
|
|
|
|
const USGSettings* Settings{USGSettings::GetInstance()};
|
|
ensureAlwaysMsgf(Settings, TEXT("The settings subsystem has not been initialized!"));
|
|
if (Settings->GetTrackingSettings().HMDTrackingSettings.ViveHMDDetectionPriority ==
|
|
ESGViveHMDDetectionPriority::HtcViveFocus3First)
|
|
{
|
|
if (IsHtcViveFocus3())
|
|
{
|
|
return ESGHeadMountedDisplayDevice::HtcViveFocus3;
|
|
}
|
|
|
|
if (IsHtcViveXRElite())
|
|
{
|
|
return ESGHeadMountedDisplayDevice::HtcViveXRElite;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (IsHtcViveXRElite())
|
|
{
|
|
return ESGHeadMountedDisplayDevice::HtcViveXRElite;
|
|
}
|
|
|
|
if (IsHtcViveFocus3())
|
|
{
|
|
return ESGHeadMountedDisplayDevice::HtcViveFocus3;
|
|
}
|
|
}
|
|
|
|
return ESGHeadMountedDisplayDevice::None;
|
|
} |