version 2.5.0

This commit is contained in:
Sean Lu
2024-12-06 15:44:37 +08:00
parent dfdcd0fd7f
commit 2bfa2ad4c7
966 changed files with 238216 additions and 77239 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5db32a7a9200d2642abc5f23c5e33984
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
# 12.38. XR_EXT_user_presence
## Name String
XR_EXT_user_presence
## Revision
1
## New Enum Constants
[XrStructureType](https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XrStructureType) enumeration is extended with:
- XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT
- XR_TYPE_SYSTEM_USER_PRESENCE_PROPERTIES_EXT
## New Structures
- [XrSystemUserPresencePropertiesEXT](https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XrSystemUserPresencePropertiesEXT)
- [XrEventDataUserPresenceChangedEXT ](https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XrEventDataUserPresenceChangedEXT)
## VIVE Plugin
Enable "VIVE XR User Presence" in "Project Settings > XR Plugin-in Management > OpenXR > Android Tab > OpenXR Feature Groups" to use the user presence feature provided by VIVE OpenXR plugin.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4cf0d8092d0049c4abd5759298b85224
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 74669924917bad84397fc3c9ca50a853
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,252 @@
// Copyright HTC Corporation All Rights Reserved.
using System;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.XR.OpenXR.Features;
#endif
namespace VIVE.OpenXR.UserPresence
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "VIVE XR User Presence",
BuildTargetGroups = new[] { BuildTargetGroup.Android },
Company = "HTC",
Desc = "Support the User Presence extension.",
DocumentationLink = "..\\Documentation",
OpenxrExtensionStrings = kOpenxrExtensionString,
Version = "1.0.0",
FeatureId = featureId)]
#endif
public class ViveUserPresence : OpenXRFeature
{
#region Log
const string LOG_TAG = "VIVE.OpenXR.UserPresence.ViveUserPresence";
StringBuilder m_sb = null;
StringBuilder sb {
get {
if (m_sb == null) { m_sb = new StringBuilder(); }
return m_sb;
}
}
void DEBUG(StringBuilder msg) { Debug.LogFormat("{0} {1}", LOG_TAG, msg); }
void WARNING(StringBuilder msg) { Debug.LogWarningFormat("{0} {1}", LOG_TAG, msg); }
void ERROR(StringBuilder msg) { Debug.LogErrorFormat("{0} {1}", LOG_TAG, msg); }
#endregion
/// <summary>
/// OpenXR specification <see href="https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_EXT_user_presence">12.39. XR_EXT_user_presence</see>.
/// </summary>
public const string kOpenxrExtensionString = "XR_EXT_user_presence";
/// <summary>
/// The feature id string. This is used to give the feature a well known id for reference.
/// </summary>
public const string featureId = "vive.openxr.feature.userpresence";
#region OpenXR Life Cycle
/// <inheritdoc />
protected override IntPtr HookGetInstanceProcAddr(IntPtr func)
{
sb.Clear().Append("HookGetInstanceProcAddr() xrPollEvent"); DEBUG(sb);
ViveInterceptors.Instance.AddRequiredFunction("xrPollEvent");
return ViveInterceptors.Instance.HookGetInstanceProcAddr(func);
}
private bool m_XrInstanceCreated = false;
private XrInstance m_XrInstance = 0;
/// <summary>
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateInstance">xrCreateInstance</see> is done.
/// </summary>
/// <param name="xrInstance">The created instance.</param>
/// <returns>True for valid <see cref="XrInstance">XrInstance</see></returns>
protected override bool OnInstanceCreate(ulong xrInstance)
{
if (!OpenXRRuntime.IsExtensionEnabled(kOpenxrExtensionString))
{
sb.Clear().Append("OnInstanceCreate() ").Append(kOpenxrExtensionString).Append(" is NOT enabled."); WARNING(sb);
return false;
}
m_XrInstance = xrInstance;
m_XrInstanceCreated = true;
sb.Clear().Append("OnInstanceCreate() ").Append(m_XrInstance); DEBUG(sb);
return GetXrFunctionDelegates(m_XrInstance);
}
/// <summary>
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrDestroyInstance">xrDestroyInstance</see> is done.
/// </summary>
/// <param name="xrInstance">The instance to destroy.</param>
protected override void OnInstanceDestroy(ulong xrInstance)
{
sb.Clear().Append("OnInstanceDestroy() ").Append(xrInstance).Append(", current: ").Append(m_XrInstance); DEBUG(sb);
if (m_XrInstance == xrInstance)
{
m_XrInstanceCreated = false;
m_XrInstance = 0;
}
}
private bool m_XrSessionCreated = false;
private XrSession m_XrSession = 0;
/// <summary>
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrCreateSession">xrCreateSession</see> is done.
/// </summary>
/// <param name="xrSession">The created session ID.</param>
protected override void OnSessionCreate(ulong xrSession)
{
m_XrSession = xrSession;
m_XrSessionCreated = true;
CheckUserPresenceSupport();
sb.Clear().Append("OnSessionCreate() ").Append(m_XrSession).Append(", support User Presence: ").Append(SupportedUserPresence()); DEBUG(sb);
}
/// <summary>
/// Called when <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrDestroySession">xrDestroySession</see> is done.
/// </summary>
/// <param name="xrSession">The session ID to destroy.</param>
protected override void OnSessionDestroy(ulong xrSession)
{
sb.Clear().Append("OnSessionDestroy() ").Append(xrSession).Append(", current: ").Append(m_XrSession); DEBUG(sb);
if (m_XrSession == xrSession)
{
m_XrSessionCreated = false;
m_XrSession = 0;
}
}
private XrSystemId m_XrSystemId = 0;
/// <summary>
/// Called when the <see cref="XrSystemId">XrSystemId</see> retrieved by <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrGetSystem">xrGetSystem</see> is changed.
/// </summary>
/// <param name="xrSystem">The system id.</param>
protected override void OnSystemChange(ulong xrSystem)
{
m_XrSystemId = xrSystem;
sb.Clear().Append("OnSystemChange() " + m_XrSystemId); DEBUG(sb);
}
#endregion
#region OpenXR function delegates
OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddr;
OpenXRHelper.xrGetSystemPropertiesDelegate xrGetSystemProperties;
/// <summary>
/// An application can call GetSystemProperties to retrieve information about the system such as vendor ID, system name, and graphics and tracking properties.
/// </summary>
/// <param name="properties">Points to an instance of the XrSystemProperties structure, that will be filled with returned information.</param>
/// <returns>XR_SUCCESS for success.</returns>
private XrResult GetSystemProperties(ref XrSystemProperties properties)
{
if (!m_XrSessionCreated)
{
sb.Clear().Append("GetSystemProperties() XR_ERROR_SESSION_LOST."); ERROR(sb);
return XrResult.XR_ERROR_SESSION_LOST;
}
if (!m_XrInstanceCreated)
{
sb.Clear().Append("GetSystemProperties() XR_ERROR_INSTANCE_LOST."); ERROR(sb);
return XrResult.XR_ERROR_INSTANCE_LOST;
}
return xrGetSystemProperties(m_XrInstance, m_XrSystemId, ref properties);
}
private bool GetXrFunctionDelegates(XrInstance xrInstance)
{
/// xrGetInstanceProcAddr
if (xrGetInstanceProcAddr != null && xrGetInstanceProcAddr != IntPtr.Zero)
{
sb.Clear().Append("Get function pointer of xrGetInstanceProcAddr."); DEBUG(sb);
XrGetInstanceProcAddr = Marshal.GetDelegateForFunctionPointer(
xrGetInstanceProcAddr,
typeof(OpenXRHelper.xrGetInstanceProcAddrDelegate)) as OpenXRHelper.xrGetInstanceProcAddrDelegate;
}
else
{
sb.Clear().Append("xrGetInstanceProcAddr"); ERROR(sb);
return false;
}
IntPtr funcPtr = IntPtr.Zero;
/// xrGetSystemProperties
if (XrGetInstanceProcAddr(xrInstance, "xrGetSystemProperties", out funcPtr) == XrResult.XR_SUCCESS)
{
if (funcPtr != IntPtr.Zero)
{
sb.Clear().Append("Get function pointer of xrGetSystemProperties."); DEBUG(sb);
xrGetSystemProperties = Marshal.GetDelegateForFunctionPointer(
funcPtr,
typeof(OpenXRHelper.xrGetSystemPropertiesDelegate)) as OpenXRHelper.xrGetSystemPropertiesDelegate;
}
}
else
{
sb.Clear().Append("xrGetSystemProperties"); ERROR(sb);
return false;
}
return true;
}
#endregion
private bool m_SupportUserPresence = false;
XrSystemProperties systemProperties;
XrSystemUserPresencePropertiesEXT userPresenceProperties;
private void CheckUserPresenceSupport()
{
m_SupportUserPresence = false;
if (!m_XrSessionCreated)
{
sb.Clear().Append("CheckUserPresenceSupport() session is not created."); ERROR(sb);
return;
}
userPresenceProperties.type = XrStructureType.XR_TYPE_SYSTEM_USER_PRESENCE_PROPERTIES_EXT;
systemProperties.type = XrStructureType.XR_TYPE_SYSTEM_PROPERTIES;
systemProperties.next = Marshal.AllocHGlobal(Marshal.SizeOf(userPresenceProperties));
long offset = 0;
if (IntPtr.Size == 4)
offset = systemProperties.next.ToInt32();
else
offset = systemProperties.next.ToInt64();
IntPtr userPresencePropertiesPtr = new IntPtr(offset);
Marshal.StructureToPtr(userPresenceProperties, userPresencePropertiesPtr, false);
#pragma warning disable 0618
if (GetSystemProperties(ref systemProperties) == XrResult.XR_SUCCESS)
#pragma warning restore 0618
{
if (IntPtr.Size == 4)
offset = systemProperties.next.ToInt32();
else
offset = systemProperties.next.ToInt64();
userPresencePropertiesPtr = new IntPtr(offset);
userPresenceProperties = (XrSystemUserPresencePropertiesEXT)Marshal.PtrToStructure(userPresencePropertiesPtr, typeof(XrSystemUserPresencePropertiesEXT));
sb.Clear().Append("CheckUserPresenceSupport() userPresenceProperties.supportsUserPresence: ").Append((UInt32)userPresenceProperties.supportsUserPresence); DEBUG(sb);
m_SupportUserPresence = userPresenceProperties.supportsUserPresence > 0;
}
else
{
sb.Clear().Append("CheckUserPresenceSupport() GetSystemProperties failed."); ERROR(sb);
}
Marshal.FreeHGlobal(systemProperties.next);
}
public bool SupportedUserPresence() { return m_SupportUserPresence; }
public bool IsUserPresent()
{
if (!SupportedUserPresence()) { return true; } // user is always present
return ViveInterceptors.Instance.IsUserPresent();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2ee23cf0de5b808448a73058d233d254
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
// Copyright HTC Corporation All Rights Reserved.
using System;
using System.Runtime.InteropServices;
namespace VIVE.OpenXR.UserPresence
{
// -------------------- 12.39. XR_EXT_user_presence --------------------
#region New Structures
/// <summary>
/// The application can use the XrSystemUserPresencePropertiesEXT event in xrGetSystemProperties to detect if the given system supports the sensing of user presence.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct XrSystemUserPresencePropertiesEXT
{
/// <summary>
/// The <see cref="XrStructureType"/> of this structure.
/// </summary>
public XrStructureType type;
/// <summary>
/// NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.
/// </summary>
public IntPtr next;
/// <summary>
/// An <see cref="XrBool32"/> value that indicates whether the system supports user presence sensing.
/// </summary>
public XrBool32 supportsUserPresence;
}
/// <summary>
/// The XrEventDataUserPresenceChangedEXT event is queued for retrieval using xrPollEvent when the user presence is changed, as well as when a session starts running.<br></br>
/// Receiving XrEventDataUserPresenceChangedEXT with the isUserPresent is XR_TRUE indicates that the system has detected the presence of a user in the XR experience.For example, this may indicate that the user has put on the headset, or has entered the tracking area of a non-head-worn XR system.<br></br>
/// Receiving XrEventDataUserPresenceChangedEXT with the isUserPresent is XR_FALSE indicates that the system has detected the absence of a user in the XR experience.For example, this may indicate that the user has removed the headset or has stepped away from the tracking area of a non-head-worn XR system.<br></br>
/// The runtime must queue this event upon a successful call to the xrBeginSession function, regardless of the value of isUserPresent, so that the application can be in sync on the state when a session begins running.<br></br>
/// The runtime must return a valid XrSession handle for a running session.<br></br>
/// After the application calls xrEndSession, a running session is ended and the runtime must not enqueue any more user presence events.Therefore, the application will no longer observe any changes of the isUserPresent until another running session.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct XrEventDataUserPresenceChangedEXT
{
/// <summary>
/// The <see cref="XrStructureType"/> of this structure.
/// </summary>
public XrStructureType type;
/// <summary>
/// NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.
/// </summary>
public IntPtr next;
/// <summary>
/// The <see cref="XrSession"/> that is receiving the notification.
/// </summary>
public XrSession session;
/// <summary>
/// An <see cref="XrBool32"/> value for new state of user presence after the change.
/// </summary>
public XrBool32 isUserPresent;
/// <summary>
/// The XR_EXT_user_presence extension must be enabled prior to using XrEventDataUserPresenceChangedEXT.
/// </summary>
public XrEventDataUserPresenceChangedEXT(XrStructureType in_type, IntPtr in_next, XrSession in_session, XrBool32 in_present)
{
type = in_type;
next = in_next;
session = in_session;
isUserPresent = in_present;
}
/// <summary>
/// Retrieves the identity value of XrEventDataUserPresenceChangedEXT.
/// </summary>
public static XrEventDataUserPresenceChangedEXT identity {
get {
return new XrEventDataUserPresenceChangedEXT(XrStructureType.XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT, IntPtr.Zero, 0, true); // user is default present
}
}
public static bool Get(XrEventDataBuffer eventDataBuffer, out XrEventDataUserPresenceChangedEXT eventDataUserPresenceChangedEXT)
{
eventDataUserPresenceChangedEXT = identity;
if (eventDataBuffer.type == XrStructureType.XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT)
{
eventDataUserPresenceChangedEXT.next = eventDataBuffer.next;
eventDataUserPresenceChangedEXT.session = BitConverter.ToUInt64(eventDataBuffer.varying, 0);
eventDataUserPresenceChangedEXT.isUserPresent = BitConverter.ToUInt32(eventDataBuffer.varying, 8);
return true;
}
return false;
}
}
#endregion
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fe60bb878e8f2df42b202a83e565ab7f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: