Files
UnrealEngine/Engine/Source/Runtime/HeadMountedDisplay/Public/IXRTrackingSystem.h
2025-05-18 13:04:45 +08:00

470 lines
19 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "HeadMountedDisplayTypes.h"
#include "IIdentifiableXRDevice.h"
#include "UObject/ObjectMacros.h"
#include "Features/IModularFeature.h"
#include "StereoRendering.h"
class IXRCamera;
class UARPin;
class FSceneViewFamily;
struct FWorldContext;
class FARSupportInterface;
class IOpenXRHMD;
/**
* Struct representing the properties of an external tracking sensor.
*/
struct FXRSensorProperties
{
/** The field of view of the sensor to the left in degrees */
float LeftFOV;
/** The field of view of the sensor to the right in degrees */
float RightFOV;
/** The upwards field of view of the sensor in degrees */
float TopFOV;
/** The downwards field of view of the sensor in degrees */
float BottomFOV;
/** The near plane of the sensor's effective tracking area */
float NearPlane;
/** The far plane of the sensor's effective tracking area */
float FarPlane;
/** The focal distance of the camera. Can be zero if this does not make sense for the type of tracking sensor. */
float CameraDistance;
};
/**
* Main access point to an XR tracking system. Use it to enumerate devices and query their poses.
*/
class IXRTrackingSystem : public IModularFeature, public IXRSystemIdentifier
{
public:
static FName GetModularFeatureName()
{
static const FName FeatureName = FName(TEXT("XRTrackingSystem"));
return FeatureName;
}
/**
* Returns version string.
*/
virtual FString GetVersionString() const = 0;
/**
* Returns device specific flags.
*/
virtual int32 GetXRSystemFlags() const = 0;
/**
* Device id 0 is reserved for an HMD. This should represent the HMD or the first HMD in case multiple HMDs are supported.
* Other devices can have arbitrary ids defined by each system.
* If a tracking system does not support tracking HMDs, device ID zero should be treated as invalid.
*/
static constexpr int32 HMDDeviceId = 0;
/**
* Whether or not the system supports positional tracking (either via sensor or other means)
*/
virtual bool DoesSupportPositionalTracking() const = 0;
/**
* Return true if the default camera implementation should query the current pose at the start of the render frame and apply late update.
* In order to support late update, the plugin should refresh the current pose just before rendering starts.
* A good point to insert the update is in OnBeginRendering_GameThread or OnBeginRendering_RenderThread.
*
* Note that for backwards compatibility with plugins written before 4.19, this method defaults to returning 'true'
*/
virtual bool DoesSupportLateUpdate() const { return true; }
/**
* Return true if the default camera implementation should query the current projection matrix at the start of the render frame and apply late update.
* In order to support late update, the plugin should refresh the current projection matrix just before rendering starts.
* A good point to insert the update is in OnBeginRendering_GameThread or OnBeginRendering_RenderThread.
*
* Note that late projection update isn't compatible with all XR implementations because of projection matrix fetch restrictions.
*/
virtual bool DoesSupportLateProjectionUpdate() const { return false; }
/**
* If the system currently has valid tracking positions. If not supported at all, returns false.
*/
virtual bool HasValidTrackingPosition() = 0;
/**
* Reports all devices currently available to the system, optionally limiting the result to a given class of devices.
*
* @param OutDevices The device ids of available devices will be appended to this array.
* @param Type Optionally limit the list of devices to a certain type.
*/
virtual bool EnumerateTrackedDevices(TArray<int32>& OutDevices, EXRTrackedDeviceType Type = EXRTrackedDeviceType::Any) = 0;
/**
* Get the count of tracked devices
* @param Type Optionally limit the count to a certain type
* @return the count of matching tracked devices
*/
virtual uint32 CountTrackedDevices(EXRTrackedDeviceType Type = EXRTrackedDeviceType::Any) = 0;
/**
* Check current tracking status of a device.
* @param DeviceId the device to request status for.
* @return true if the system currently has valid tracking info for the given device ID.
*/
virtual bool IsTracking(int32 DeviceId) = 0;
/**
* Temporary method until Morpheus controller code has been refactored.
*/
virtual void RebaseObjectOrientationAndPosition(FVector& Position, FQuat& Orientation) const {};
/**
* Get the current pose for a device.
* This method must be callable both on the render thread and the game thread.
* For devices that don't support positional tracking, OutPosition will be at the base position.
*
* @param DeviceId the device to request the pose for.
* @param OutOrientation The current orientation of the device
* @param OutPosition The current position of the device
* @return true if the pose is valid or not.
*/
virtual bool GetCurrentPose(int32 DeviceId, FQuat& OutOrientation, FVector& OutPosition) = 0;
/**
* If the device id represents a head mounted display, fetches the relative position of the given eye relative to the eye.
* If the device is does not represent a stereoscopic tracked camera, orientation and position should be identity and zero and the return value should be false.
*
* @param DeviceId the device to request the eye pose for.
* @param ViewIndex the view the pose should be requested for, if passing in INDEX_NONE, the method should return a zero offset.
* @param OutOrientation The orientation of the eye relative to the device orientation.
* @param OutPosition The position of the eye relative to the tracked device
* @return true if the pose is valid or not. If the device is not a stereoscopic device, return false.
*/
virtual bool GetRelativeEyePose(int32 DeviceId, int32 ViewIndex, FQuat& OutOrientation, FVector& OutPosition) = 0;
/**
* If the device id represents a tracking sensor, reports the frustum properties in game-world space of the sensor.
* @param DeviceId the device to request information for.
* @param OutOrientation The current orientation of the device.
* @param OutPosition The current position of the device.
* @param OutSensorProperties A struct containing the tracking sensor properties.
* @return true if the device tracking is valid and supports returning tracking sensor properties.
*/
virtual bool GetTrackingSensorProperties(int32 DeviceId, FQuat& OutOrientation, FVector& OutPosition, FXRSensorProperties& OutSensorProperties) = 0;
/**
* If the device id represents a tracking sensor, reports the device type.
* @param DeviceId the device to request information for.
* @return the device type enum.
*/
virtual EXRTrackedDeviceType GetTrackedDeviceType(int32 DeviceId) const = 0;
/**
* If the device id represents a tracking sensor, reports the serial number as a string if the device supports it.
* @param DeviceId the device to request information for.
* @return the serial number of the device if it's available.
*/
virtual FString GetTrackedDevicePropertySerialNumber(int32 DeviceId) = 0;
/**
* Sets tracking origin (either 'eye'-level or 'floor'-level).
*/
virtual void SetTrackingOrigin(EHMDTrackingOrigin::Type NewOrigin) = 0;
/**
* Returns current tracking origin.
*/
virtual EHMDTrackingOrigin::Type GetTrackingOrigin() const = 0;
/**
* Returns the system's latest known tracking-to-world transform.
* Useful for translating poses from GetCurrentPose() into unreal world space.
*/
virtual FTransform GetTrackingToWorldTransform() const = 0;
/**
* This method should return the world to meters scale for the current frame.
* Should be callable on both the render and the game threads.
* @return the current world to meter scale.
*/
virtual float GetWorldToMetersScale() const = 0;
/**
* Computes a transform to convert from 'Floor' origin space to 'Eye' origin space.
* Useful when changing between the two different TrackingOrigin spaces.
* Invert the transform to get the opposite.
*
* @param OutFloorToEye [out] The returned floor-to-eye transform.
* @return True if the transform was successfully constructed.
*/
virtual bool GetFloorToEyeTrackingTransform(FTransform& OutFloorToEye) const = 0;
/**
* Refreshes the system's known tracking-to-world transform.
* Helpful for clients if they change the world's representation of the XR origin, or if they want to override the system calculated
* transform - calling this will update the known transform returned by GetTrackingToWorldTransform().
*/
virtual void UpdateTrackingToWorldTransform(const FTransform& TrackingToWorldOverride) = 0;
/**
* Get the offset, in device space, of the reported device (screen / eye) position to the center of the head.
*
* @return a vector containing the offset coordinates, ZeroVector if not supported.
*/
virtual FVector GetAudioListenerOffset(int32 DeviceId = HMDDeviceId) const { return FVector::ZeroVector; }
/**
* Resets orientation by setting roll and pitch to 0, assuming that current yaw is forward direction and assuming
* current position as a 'zero-point' (for positional tracking).
*
* @param Yaw (in) the desired yaw to be set after orientation reset.
*/
virtual void ResetOrientationAndPosition(float Yaw = 0.f) = 0;
/**
* Resets orientation by setting roll and pitch to 0, assuming that current yaw is forward direction. Position is not changed.
*
* @param Yaw (in) the desired yaw to be set after orientation reset.
*/
virtual void ResetOrientation(float Yaw = 0.f) {}
/**
* Resets position, assuming current position as a 'zero-point'.
*/
virtual void ResetPosition() {}
/**
* Sets base orientation by setting yaw, pitch, roll, assuming that this is forward direction.
* Position is not changed.
*
* @param BaseRot (in) the desired orientation to be treated as a base orientation.
*/
virtual void SetBaseRotation(const FRotator& BaseRot) {}
/**
* Returns current base orientation of HMD as yaw-pitch-roll combination.
*/
virtual FRotator GetBaseRotation() const { return FRotator::ZeroRotator; }
/**
* Sets base orientation, assuming that this is forward direction.
* Position is not changed.
*
* @param BaseOrient (in) the desired orientation to be treated as a base orientation.
*/
virtual void SetBaseOrientation(const FQuat& BaseOrient) {}
/**
* Returns current base orientation of HMD as a quaternion.
*/
virtual FQuat GetBaseOrientation() const { return FQuat::Identity; }
/**
* Sets base position of the HMD.
*
* @param BasePosition (in) the desired offset to be treated as a base position.
*/
virtual void SetBasePosition(const FVector& BasePosition) {};
/**
* Returns current base position of HMD.
*/
virtual FVector GetBasePosition() const { return FVector::ZeroVector; }
/**
* Called to calibrate the offset transform between an external tracking source and the internal tracking source
* (e.g. mocap tracker to and HMD tracker). This should be called once per session, or when the physical relationship
* between the external tracker and internal tracker changes (e.g. it was bumped or reattached). After calibration,
* calling UpdateExternalTrackingPosition will try to correct the internal tracker to the calibrated offset to prevent
* drift between the two systems
*
* @param ExternalTrackingTransform (in) The transform in world-coordinates, of the reference marker of the external tracking system
*/
virtual void CalibrateExternalTrackingSource(const FTransform& ExternalTrackingTransform) {}
/**
* Called after calibration to attempt to pull the internal tracker (e.g. HMD tracking) in line with the external tracker
* (e.g. mocap tracker). This will set the internal tracker's base offset and rotation to match and realign the two systems.
* This can be called every tick, or whenever realignment is desired. Note that this may cause choppy movement if the two
* systems diverge relative to each other, or a big jump if called infrequently when there has been significant drift
*
* @param ExternalTrackingTransform (in) The transform in world-coordinates, of the reference marker of the external tracking system
*/
virtual void UpdateExternalTrackingPosition(const FTransform& ExternalTrackingTransform) {}
/**
* Get the IXCamera instance for the given device.
*
* @param DeviceId the device the camera should track.
* @return a shared pointer to an IXRCamera.
*/
virtual class TSharedPtr< class IXRCamera, ESPMode::ThreadSafe > GetXRCamera(int32 DeviceId = HMDDeviceId) = 0;
/**
* Access HMD rendering-related features.
*
* @return a IHeadmountedDisplay pointer or a nullptr if this tracking system does not support head mounted displays.
*/
virtual class IHeadMountedDisplay* GetHMDDevice() { return nullptr; }
/**
* Access Stereo rendering device associated with this XR system.
* If GetHMDDevice() returns non-null, this method should also return a vaild instance.
*
* @return a IStereoRendering pointer or a nullptr if this tracking system does not support stereo rendering.
*/
virtual class TSharedPtr< class IStereoRendering, ESPMode::ThreadSafe > GetStereoRenderingDevice()
{
check(GetHMDDevice() == nullptr);
return nullptr;
}
/**
* Deprecated, and will be removed in a future release.
* Access optional HMD input override interface.
*
* @return a IXRInput pointer or a nullptr if not supported
*/
UE_DEPRECATED(5.6, "IXRInput is deprecated and will be removed in a future release.")
virtual class IXRInput* GetXRInput() { return nullptr; }
/**
* Access optionsal ARCompositionComponent
**/
virtual TSharedPtr<FARSupportInterface, ESPMode::ThreadSafe> GetARCompositionComponent() { return nullptr; }
virtual const TSharedPtr<const FARSupportInterface, ESPMode::ThreadSafe> GetARCompositionComponent() const { return nullptr; }
/**
* Access the loading screen interface associated with this tracking system, if any.
*
* @return an IXRLoadingScreen pointer or a nullptr if this tracking system does not support loading screens.
*/
virtual class IXRLoadingScreen* GetLoadingScreen() { return nullptr; }
/*** XR System related methods moved from IHeadMountedDisplay ***/
/**
* Returns true, if head tracking is allowed. Most common case: it returns true when GEngine->IsStereoscopic3D() is true,
* but some overrides are possible.
*/
virtual bool IsHeadTrackingAllowed() const = 0;
/**
* Same as IsHeadTrackingAllowed, but returns false if the World is not using VR (such as with the non-VR PIE instances when using VR Preview)
**/
HEADMOUNTEDDISPLAY_API virtual bool IsHeadTrackingAllowedForWorld(UWorld & World) const;
/**
* Can be used to enforce tracking even when stereo rendering is disabled.
* The default implementation does not allow enforcing tracking and always returns false.
* This method is called both from the game and render threads.
*/
virtual bool IsHeadTrackingEnforced() const { return false; }
/**
* Can be used to enforce tracking even when stereo rendering is disabled.
* The default implementation does not allow enforcing tracking and ignores the argument.
*/
virtual void SetHeadTrackingEnforced(bool bEnabled) {};
/**
* This method is called when playing begins. Useful to reset all runtime values stored in the plugin.
*/
virtual void OnBeginPlay(FWorldContext& InWorldContext) {}
/**
* This method is called when playing ends. Useful to reset all runtime values stored in the plugin.
*/
virtual void OnEndPlay(FWorldContext& InWorldContext) {}
/**
* This method is called when new game frame begins (called on a game thread).
*/
virtual bool OnStartGameFrame(FWorldContext& WorldContext) { return false; }
/**
* This method is called when game frame ends (called on a game thread).
*/
virtual bool OnEndGameFrame(FWorldContext& WorldContext) { return false; }
/*** Methods designed to be called from IXRCamera implementations ***/
/**
* Called just before rendering the current frame on the render thread. Invoked before applying late update, so plugins that want to refresh poses on the
* render thread prior to late update. Use this to perform any initializations prior to rendering.
*/
UE_DEPRECATED(5.6, "Use the FRDGBuilder overload instead")
virtual void OnBeginRendering_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& ViewFamily) final {}
HEADMOUNTEDDISPLAY_API virtual void OnBeginRendering_RenderThread(FRDGBuilder& GraphBuilder, FSceneViewFamily& ViewFamily);
/**
* Called just before rendering the current frame on the game frame.
*/
UE_DEPRECATED(5.6, "Use the FSceneViewFamily overload instead")
virtual void OnBeginRendering_GameThread() final {}
virtual void OnBeginRendering_GameThread(FSceneViewFamily& InViewFamily)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
OnBeginRendering_GameThread();
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
/**
* Called just after the late update on the render thread passing back the current relative transform.
*/
UE_DEPRECATED(5.6, "Use the FRDGBuilder overload instead")
virtual void OnLateUpdateApplied_RenderThread(FRHICommandListImmediate& RHICmdList, const FTransform& NewRelativeTransform) final {}
HEADMOUNTEDDISPLAY_API virtual void OnLateUpdateApplied_RenderThread(FRDGBuilder& GraphBuilder, const FTransform& NewRelativeTransform);
/**
* Platform Agnostic Query about HMD details
*/
HEADMOUNTEDDISPLAY_API virtual void GetHMDData(UObject* WorldContext, FXRHMDData& HMDData);
/**
* Platform Agnostic Query about MotionControllers details
*/
UE_DEPRECATED(5.5, "Deprecated along with UHeadMountedDisplayFunctionLibrary::GetMotionControllerData")
virtual void GetMotionControllerData(UObject* WorldContext, const EControllerHand Hand, FXRMotionControllerData& MotionControllerData) = 0;
virtual void GetMotionControllerState(UObject* WorldContext, const EXRSpaceType XRSpaceType, const EControllerHand Hand, const EXRControllerPoseType XRControllerPoseType, FXRMotionControllerState& MotionControllerState) = 0;
virtual void GetHandTrackingState(UObject* WorldContext, const EXRSpaceType XRSpaceType, const EControllerHand Hand, FXRHandTrackingState& HandTrackingState) = 0;
virtual bool GetCurrentInteractionProfile(const EControllerHand Hand, FString& InteractionProfile) = 0;
virtual EXRDeviceConnectionResult::Type ConnectRemoteXRDevice(const FString& IpAddress, const int32 BitRate)
{
return EXRDeviceConnectionResult::FeatureNotSupported;
}
virtual void DisconnectRemoteXRDevice() {}
/**
* Get the bounds of the area where the user can freely move while remaining tracked centered around the specified origin
*/
virtual FVector2D GetPlayAreaBounds(EHMDTrackingOrigin::Type Origin) const { return FVector2D::ZeroVector; }
/**
* Get the transform of the specified tracking origin, if available.
*/
virtual bool GetTrackingOriginTransform(TEnumAsByte<EHMDTrackingOrigin::Type> Origin, FTransform& OutTransform) const { return false; }
/**
* Get the transform and dimensions of the area where the user can freely move while remaining tracked centered around the specified origin transform
*/
virtual bool GetPlayAreaRect(FTransform& OutTransform, FVector2D& OutRect) const { return false; }
/**
* Get the IOpenXRHMD interface, if there is one.
*/
virtual IOpenXRHMD* GetIOpenXRHMD() { return nullptr; }
};