version 2.5.1

This commit is contained in:
Sean Lu
2025-01-08 10:28:35 +08:00
parent 2bfa2ad4c7
commit ae66f9c2fe
91 changed files with 7009 additions and 2005 deletions

View File

@@ -281,7 +281,8 @@ namespace VIVE.OpenXR.Editor
} }
} }
foreach (var feature in settings.GetFeatures<OpenXRFeature>()) var features = settings.GetFeatures<OpenXRFeature>();
foreach (var feature in features)
{ {
if (!feature.enabled) { continue; } if (!feature.enabled) { continue; }
@@ -310,6 +311,17 @@ namespace VIVE.OpenXR.Editor
} }
} }
} }
if (feature is VIVEFocus3Feature)
{
for (int i = 0; i < features.Length; i++)
{
if (features[i] is Enterprise.ViveEnterpriseCommand)
{
features[i].enabled = true;
}
}
}
} }
if (enableHandtracking) if (enableHandtracking)

View File

@@ -51,6 +51,39 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
static GUIContent Label_QuadHeight = new GUIContent("Height", "Height of a Quad Layer"); static GUIContent Label_QuadHeight = new GUIContent("Height", "Height of a Quad Layer");
SerializedProperty Property_QuadHeight; SerializedProperty Property_QuadHeight;
static string PropertyName_EquirectRadius = "m_EquirectRadius";
static GUIContent Label_EquirectRadius = new GUIContent("Radius", "Radius of Equirect Layer");
SerializedProperty Property_EquirectRadius;
static string PropertyName_EquirectScaleX = "m_EquirectScaleX";
static GUIContent Label_EquirectScaleX = new GUIContent("scale.x", "Scale.X of Equirect Layer");
SerializedProperty Property_EquirectScaleX;
static string PropertyName_EquirectScaleY = "m_EquirectScaleY";
static GUIContent Label_EquirectScaleY = new GUIContent("scale.y", "Scale.Y of Equirect Layer");
SerializedProperty Property_EquirectScaleY;
static string PropertyName_EquirectBiasX = "m_EquirectBiasX";
static GUIContent Label_EquirectBiasX = new GUIContent("bias.x", "Bias.X of Equirect Layer");
SerializedProperty Property_EquirectBiasX;
static string PropertyName_EquirectBiasY = "m_EquirectBiasY";
static GUIContent Label_EquirectBiasY = new GUIContent("bias.y", "Bias.Y of Equirect Layer");
SerializedProperty Property_EquirectBiasY;
static string PropertyName_EquirectCentralHorizontalAngle = "m_EquirectCentralHorizontalAngle";
static GUIContent Label_EquirectCentralHorizontalAngle = new GUIContent("CentralHorizontalAngle", "Central Horizontal Angle of Equirect Layer");
SerializedProperty Property_EquirectCentralHorizontalAngle;
static string PropertyName_EquirectUpperVerticalAngle = "m_EquirectUpperVerticalAngle";
static GUIContent Label_EquirectUpperVerticalAngle = new GUIContent("UpperVerticalAngle", "Upper Vertical Angle of Equirect Layer");
SerializedProperty Property_EquirectUpperVerticalAngle;
static string PropertyName_EquirectLowerVerticalAngle = "m_EquirectLowerVerticalAngle";
static GUIContent Label_EquirectLowerVerticalAngle = new GUIContent("LowerVerticalAngle", "Lower Vertical Angle of Equirect Layer");
SerializedProperty Property_EquirectLowerVerticalAngle;
static string PropertyName_CylinderHeight = "m_CylinderHeight"; static string PropertyName_CylinderHeight = "m_CylinderHeight";
static GUIContent Label_CylinderHeight = new GUIContent("Height", "Height of Cylinder Layer"); static GUIContent Label_CylinderHeight = new GUIContent("Height", "Height of Cylinder Layer");
SerializedProperty Property_CylinderHeight; SerializedProperty Property_CylinderHeight;
@@ -138,6 +171,14 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
if (Property_LockMode == null) Property_LockMode = serializedObject.FindProperty(PropertyName_LockMode); if (Property_LockMode == null) Property_LockMode = serializedObject.FindProperty(PropertyName_LockMode);
if (Property_QuadWidth == null) Property_QuadWidth = serializedObject.FindProperty(PropertyName_QuadWidth); if (Property_QuadWidth == null) Property_QuadWidth = serializedObject.FindProperty(PropertyName_QuadWidth);
if (Property_QuadHeight == null) Property_QuadHeight = serializedObject.FindProperty(PropertyName_QuadHeight); if (Property_QuadHeight == null) Property_QuadHeight = serializedObject.FindProperty(PropertyName_QuadHeight);
if (Property_EquirectRadius == null) Property_EquirectRadius = serializedObject.FindProperty(PropertyName_EquirectRadius);
if (Property_EquirectScaleX == null) Property_EquirectScaleX = serializedObject.FindProperty(PropertyName_EquirectScaleX);
if (Property_EquirectScaleY == null) Property_EquirectScaleY = serializedObject.FindProperty(PropertyName_EquirectScaleY);
if (Property_EquirectBiasX == null) Property_EquirectBiasX = serializedObject.FindProperty(PropertyName_EquirectBiasX);
if (Property_EquirectBiasY == null) Property_EquirectBiasY = serializedObject.FindProperty(PropertyName_EquirectBiasY);
if (Property_EquirectCentralHorizontalAngle == null) Property_EquirectCentralHorizontalAngle = serializedObject.FindProperty(PropertyName_EquirectCentralHorizontalAngle);
if (Property_EquirectUpperVerticalAngle == null) Property_EquirectUpperVerticalAngle = serializedObject.FindProperty(PropertyName_EquirectUpperVerticalAngle);
if (Property_EquirectLowerVerticalAngle == null) Property_EquirectLowerVerticalAngle = serializedObject.FindProperty(PropertyName_EquirectLowerVerticalAngle);
if (Property_CylinderHeight == null) Property_CylinderHeight = serializedObject.FindProperty(PropertyName_CylinderHeight); if (Property_CylinderHeight == null) Property_CylinderHeight = serializedObject.FindProperty(PropertyName_CylinderHeight);
if (Property_CylinderArcLength == null) Property_CylinderArcLength = serializedObject.FindProperty(PropertyName_CylinderArcLength); if (Property_CylinderArcLength == null) Property_CylinderArcLength = serializedObject.FindProperty(PropertyName_CylinderArcLength);
if (Property_CylinderRadius == null) Property_CylinderRadius = serializedObject.FindProperty(PropertyName_CylinderRadius); if (Property_CylinderRadius == null) Property_CylinderRadius = serializedObject.FindProperty(PropertyName_CylinderRadius);
@@ -171,6 +212,138 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
EditorGUILayout.PropertyField(Property_LayerShape, new GUIContent(Label_LayerShape)); EditorGUILayout.PropertyField(Property_LayerShape, new GUIContent(Label_LayerShape));
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();
if (Property_LayerShape.intValue == (int)CompositionLayer.LayerShape.Equirect || Property_LayerShape.intValue == (int)CompositionLayer.LayerShape.Equirect2)
{
if (targetCompositionLayer.isPreviewingQuad)
{
targetCompositionLayer.isPreviewingQuad = false;
if (targetCompositionLayer.generatedPreview != null)
{
DestroyImmediate(targetCompositionLayer.generatedPreview);
}
}
if (targetCompositionLayer.isPreviewingCylinder)
{
targetCompositionLayer.isPreviewingCylinder = false;
if (targetCompositionLayer.generatedPreview != null)
{
DestroyImmediate(targetCompositionLayer.generatedPreview);
}
}
if (!FeatureHelpers.GetFeatureWithIdForBuildTarget(BuildTargetGroup.Android, ViveCompositionLayerEquirect.featureId).enabled)
{
EditorGUILayout.HelpBox("The Composition Layer Equirect feature is not enabled in OpenXR Settings.\nEnable it to use Equirect layers.", MessageType.Warning);
}
EditorGUI.indentLevel++;
showLayerParams = EditorGUILayout.Foldout(showLayerParams, "Equirect Parameters");
if (showLayerParams)
{
EditorGUILayout.PropertyField(Property_EquirectRadius, new GUIContent(Label_EquirectRadius));
if (Property_LayerShape.intValue == (int)CompositionLayer.LayerShape.Equirect)
{
EditorGUILayout.PropertyField(Property_EquirectScaleX, new GUIContent(Label_EquirectScaleX));
EditorGUILayout.PropertyField(Property_EquirectScaleY, new GUIContent(Label_EquirectScaleY));
EditorGUILayout.PropertyField(Property_EquirectBiasX, new GUIContent(Label_EquirectBiasX));
EditorGUILayout.PropertyField(Property_EquirectBiasY, new GUIContent(Label_EquirectBiasY));
}
else if (Property_LayerShape.intValue == (int)CompositionLayer.LayerShape.Equirect2)
{
EditorGUILayout.PropertyField(Property_EquirectCentralHorizontalAngle, new GUIContent(Label_EquirectCentralHorizontalAngle));
EditorGUILayout.PropertyField(Property_EquirectUpperVerticalAngle, new GUIContent(Label_EquirectUpperVerticalAngle));
EditorGUILayout.PropertyField(Property_EquirectLowerVerticalAngle, new GUIContent(Label_EquirectLowerVerticalAngle));
}
serializedObject.ApplyModifiedProperties();
}
EditorGUI.indentLevel--;
bool EquirectParamsChanged = targetCompositionLayer.LayerDimensionsChanged();
if (targetCompositionLayer.isPreviewingEquirect)
{
Transform generatedPreviewTransform = targetCompositionLayer.transform.Find(CompositionLayer.EquirectPreviewName);
if (generatedPreviewTransform != null)
{
targetCompositionLayer.generatedPreview = generatedPreviewTransform.gameObject;
if (EquirectParamsChanged)
{
MeshFilter equirectMeshFilter = targetCompositionLayer.generatedPreview.GetComponent<MeshFilter>();
//Generate vertices
equirectMeshFilter.mesh = CompositionLayer.MeshGenerationHelper.GenerateEquirectMesh(targetCompositionLayer.hmd, targetCompositionLayer.EquirectRadius);
targetCompositionLayer.generatedPreview.transform.localPosition = Vector3.zero;
targetCompositionLayer.generatedPreview.transform.localRotation = Quaternion.identity;
targetCompositionLayer.generatedPreview.transform.localScale = targetCompositionLayer.GetNormalizedLocalScale(targetCompositionLayer.transform, Vector3.one);
}
if (targetCompositionLayer.generatedPreview.GetComponent<MeshRenderer>().sharedMaterial.mainTexture != targetCompositionLayer.texture)
{
targetCompositionLayer.generatedPreview.GetComponent<MeshRenderer>().sharedMaterial.mainTexture = targetCompositionLayer.texture;
}
if (GUILayout.Button("Hide Equirect Preview"))
{
targetCompositionLayer.isPreviewingEquirect = false;
if (targetCompositionLayer.generatedPreview != null)
{
DestroyImmediate(targetCompositionLayer.generatedPreview);
}
}
}
else
{
targetCompositionLayer.isPreviewingEquirect = false;
}
}
else
{
if (GUILayout.Button("Show Equirect Preview"))
{
Rect srcRectLeft = FullRect;
if (targetCompositionLayer.isCustomRects && targetCompositionLayer.customRects == CompositionLayer.CustomRectsType.LeftRight)
srcRectLeft = LeftRightRect;
if (targetCompositionLayer.isCustomRects && targetCompositionLayer.customRects == CompositionLayer.CustomRectsType.TopDown)
srcRectLeft = TopDownRect;
targetCompositionLayer.isPreviewingEquirect = true;
//Vector3[] cylinderVertices = CompositionLayer.MeshGenerationHelper.GenerateCylinderVertex(targetCompositionLayer.CylinderAngleOfArc, targetCompositionLayer.CylinderRadius, targetCompositionLayer.CylinderHeight);
//Add components to Game Object
targetCompositionLayer.generatedPreview = new GameObject();
targetCompositionLayer.generatedPreview.hideFlags = HideFlags.HideAndDontSave;
targetCompositionLayer.generatedPreview.name = CompositionLayer.EquirectPreviewName;
targetCompositionLayer.generatedPreview.transform.SetParent(targetCompositionLayer.gameObject.transform);
targetCompositionLayer.generatedPreview.transform.localPosition = Vector3.zero;
targetCompositionLayer.generatedPreview.transform.localRotation = Quaternion.identity;
targetCompositionLayer.generatedPreview.transform.localScale = targetCompositionLayer.GetNormalizedLocalScale(targetCompositionLayer.transform, Vector3.one);
MeshRenderer equirectMeshRenderer = targetCompositionLayer.generatedPreview.AddComponent<MeshRenderer>();
MeshFilter equirectMeshFilter = targetCompositionLayer.generatedPreview.AddComponent<MeshFilter>();
equirectMeshRenderer.sharedMaterial = new Material(Shader.Find("Unlit/Transparent"));
if (targetCompositionLayer.texture != null)
{
equirectMeshRenderer.sharedMaterial.mainTexture = targetCompositionLayer.texture;
equirectMeshRenderer.sharedMaterial.mainTextureOffset = srcRectLeft.position;
equirectMeshRenderer.sharedMaterial.mainTextureScale = srcRectLeft.size;
}
//Generate Mesh
equirectMeshFilter.mesh = CompositionLayer.MeshGenerationHelper.GenerateEquirectMesh(targetCompositionLayer.hmd, targetCompositionLayer.EquirectRadius);
}
}
EditorGUILayout.Space(10);
serializedObject.ApplyModifiedProperties();
}
if (Property_LayerShape.intValue == (int)CompositionLayer.LayerShape.Cylinder) if (Property_LayerShape.intValue == (int)CompositionLayer.LayerShape.Cylinder)
{ {
if (!FeatureHelpers.GetFeatureWithIdForBuildTarget(BuildTargetGroup.Android, ViveCompositionLayerCylinder.featureId).enabled) if (!FeatureHelpers.GetFeatureWithIdForBuildTarget(BuildTargetGroup.Android, ViveCompositionLayerCylinder.featureId).enabled)
@@ -187,6 +360,15 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
} }
} }
if (targetCompositionLayer.isPreviewingEquirect)
{
targetCompositionLayer.isPreviewingEquirect = false;
if (targetCompositionLayer.generatedPreview != null)
{
DestroyImmediate(targetCompositionLayer.generatedPreview);
}
}
Transform generatedQuadTransform = targetCompositionLayer.transform.Find(CompositionLayer.QuadUnderlayMeshName); Transform generatedQuadTransform = targetCompositionLayer.transform.Find(CompositionLayer.QuadUnderlayMeshName);
if (generatedQuadTransform != null) if (generatedQuadTransform != null)
{ {
@@ -280,6 +462,7 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
if (targetCompositionLayer.isPreviewingCylinder) if (targetCompositionLayer.isPreviewingCylinder)
{ {
Transform generatedPreviewTransform = targetCompositionLayer.transform.Find(CompositionLayer.CylinderPreviewName); Transform generatedPreviewTransform = targetCompositionLayer.transform.Find(CompositionLayer.CylinderPreviewName);
if (generatedPreviewTransform != null) if (generatedPreviewTransform != null)
@@ -372,6 +555,15 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
} }
} }
if (targetCompositionLayer.isPreviewingEquirect)
{
targetCompositionLayer.isPreviewingEquirect = false;
if (targetCompositionLayer.generatedPreview != null)
{
DestroyImmediate(targetCompositionLayer.generatedPreview);
}
}
EditorGUI.indentLevel++; EditorGUI.indentLevel++;
showLayerParams = EditorGUILayout.Foldout(showLayerParams, "Quad Parameters"); showLayerParams = EditorGUILayout.Foldout(showLayerParams, "Quad Parameters");
if (showLayerParams) if (showLayerParams)
@@ -507,7 +699,7 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
EditorGUI.indentLevel--; EditorGUI.indentLevel--;
}*/ }*/
if (targetCompositionLayer.textureLeft == targetCompositionLayer.textureRight || targetCompositionLayer.textureRight == null) if((Property_LayerShape.intValue != (int)CompositionLayer.LayerShape.Equirect && Property_LayerShape.intValue != (int)CompositionLayer.LayerShape.Equirect2) && (targetCompositionLayer.textureLeft == targetCompositionLayer.textureRight || targetCompositionLayer.textureRight == null))
{ {
EditorGUILayout.PropertyField(Property_IsCustomRects, Label_IsCustomRects); EditorGUILayout.PropertyField(Property_IsCustomRects, Label_IsCustomRects);
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();

View File

@@ -93,9 +93,9 @@ public static class PackageManagerHelper
case StatusCode.Failure: case StatusCode.Failure:
if (!s_wasRemoved) if (!s_wasRemoved)
{ {
if (m_removeRequest != null) { Debug.LogError("Something wrong when removing package from list. error:" + m_removeRequest.Error.errorCode + "(" + m_removeRequest.Error.message + ")"); }
var request = m_removeRequest; var request = m_removeRequest;
m_removeRequest = null; m_removeRequest = null;
Debug.LogError("Something wrong when removing package from list. error:" + m_removeRequest.Error.errorCode + "(" + m_removeRequest.Error.message + ")");
} }
break; break;
case StatusCode.Success: case StatusCode.Success:

View File

@@ -149,10 +149,15 @@ namespace VIVE.OpenXR.Editor
} }
} }
static int checkPreferenceAssetsFrame = 0;
static void OnUpdate() static void OnUpdate()
{ {
if (!ViveOpenXRAndroidAssigned) { return; } if (!ViveOpenXRAndroidAssigned) { return; }
checkPreferenceAssetsFrame++;
checkPreferenceAssetsFrame %= 1200; // 10s
if (checkPreferenceAssetsFrame != 0) { return; }
CheckPreferenceAssets(); CheckPreferenceAssets();
if (m_AssetAvatar) if (m_AssetAvatar)

View File

@@ -14,6 +14,7 @@ namespace VIVE.OpenXR
"vive.openxr.feature.compositionlayer", "vive.openxr.feature.compositionlayer",
"vive.openxr.feature.compositionlayer.cylinder", "vive.openxr.feature.compositionlayer.cylinder",
"vive.openxr.feature.compositionlayer.colorscalebias", "vive.openxr.feature.compositionlayer.colorscalebias",
CompositionLayer.ViveCompositionLayerEquirect.featureId,
Tracker.ViveWristTracker.featureId, Tracker.ViveWristTracker.featureId,
Hand.ViveHandInteraction.featureId, Hand.ViveHandInteraction.featureId,
"vive.openxr.feature.foveation", "vive.openxr.feature.foveation",

View File

@@ -7,8 +7,17 @@ namespace VIVE.OpenXR.Feature
{ {
public interface IViveFeatureWrapper public interface IViveFeatureWrapper
{ {
/// <summary>
/// OnInstanceCreate might be called multiple times. Because many features might be using the same instance.
/// </summary>
/// <param name="xrInstance"></param>
/// <param name="xrGetInstanceProcAddr"></param>
/// <returns></returns>
public bool OnInstanceCreate(XrInstance xrInstance, IntPtr xrGetInstanceProcAddr); public bool OnInstanceCreate(XrInstance xrInstance, IntPtr xrGetInstanceProcAddr);
/// <summary>
/// OnInstanceDestroy might be called multiple times. Because many features might be using the same instance.
/// </summary>
public void OnInstanceDestroy(); public void OnInstanceDestroy();
} }
@@ -21,6 +30,11 @@ namespace VIVE.OpenXR.Feature
// Set true in yourfeature's OnInstanceCreate // Set true in yourfeature's OnInstanceCreate
public bool IsInited { get; protected set; } = false; public bool IsInited { get; protected set; } = false;
/// <summary>
/// If the feature is inited not successfully, Set this true. Use to avoid multiple inits.
/// </summary>
public bool TryInited { get; protected set; } = false;
public OpenXRHelper.xrGetInstanceProcAddrDelegate xrGetInstanceProcAddr; public OpenXRHelper.xrGetInstanceProcAddrDelegate xrGetInstanceProcAddr;
/// <summary> /// <summary>

View File

@@ -1,24 +1,112 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEngine.Profiling;
namespace VIVE.OpenXR namespace VIVE.OpenXR
{ {
public static class MemoryTools internal static class MemoryTools
{ {
/// <summary>
/// Make sure the input ptr is a OpenXR XrBaseStructure derived struct.
/// </summary>
/// <param name="ptr">the struct to get its next.</param>
/// <returns>the next's value</returns>
public static unsafe IntPtr GetNext(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return IntPtr.Zero;
//Profiler.BeginSample("GetNext");
XrBaseStructure* ptrToStruct = (XrBaseStructure*)ptr.ToPointer();
//Profiler.EndSample();
return ptrToStruct->next;
}
/// <summary>
/// Make sure the input ptr is a OpenXR XrBaseStructure derived struct.
/// </summary>
/// <param name="ptr">the struct to get its type</param>
/// <returns>the struct's type</returns>
public static unsafe XrStructureType GetType(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
throw new Exception("The input pointer is null.");
//Profiler.BeginSample("GetType");
XrBaseStructure* ptrToStruct = (XrBaseStructure*)ptr.ToPointer();
//Profiler.EndSample();
return ptrToStruct->type;
}
public static unsafe XrBaseStructure ToBaseStructure(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
throw new Exception("The input pointer is null.");
//Profiler.BeginSample("ToBaseStructure");
XrBaseStructure* ptrToStruct = (XrBaseStructure*)ptr.ToPointer();
//Profiler.EndSample();
return *ptrToStruct;
}
public static unsafe T PtrToStructure<T>(IntPtr ptr) where T : unmanaged
{
//Profiler.BeginSample("PtrToStructure");
// Not to use Marshal.PtrToStructure<T> because it is slow.
T t = default; // Use new T() will cause GC alloc.
Buffer.MemoryCopy((void*)ptr, &t, sizeof(T), sizeof(T));
//Profiler.EndSample();
return t;
}
public static unsafe void PtrToStructure<T>(IntPtr ptr, ref T t) where T : unmanaged
{
//Profiler.BeginSample("PtrToStructure");
fixed (T* destinationPtr = &t)
{
Buffer.MemoryCopy((void*)ptr, destinationPtr, sizeof(T), sizeof(T));
}
//Profiler.EndSample();
}
public static unsafe void StructureToPtr<T>(T t, IntPtr ptr) where T : unmanaged
{
//Profiler.BeginSample("StructureToPtr");
// Not to use Marshal.StructureToPtr<T> because it is slow.
Buffer.MemoryCopy(&t, (void*)ptr, sizeof(T), sizeof(T));
//Profiler.EndSample();
}
/// <summary> /// <summary>
/// Convert the enum array to IntPtr. Should call <see cref="ReleaseRawMemory(IntPtr)"/> after use. /// Convert the enum array to IntPtr. Should call <see cref="ReleaseRawMemory(IntPtr)"/> after use.
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="array"></param> /// <param name="array"></param>
/// <returns></returns> /// <returns></returns>
public static IntPtr ToIntPtr<T>(T[] array) where T : Enum public static unsafe IntPtr ToIntPtr<T>(T[] array) where T : Enum
{ {
int size = Marshal.SizeOf(typeof(T)) * array.Length; int size = sizeof(int) * array.Length;
IntPtr ptr = Marshal.AllocHGlobal(size); IntPtr ptr = Marshal.AllocHGlobal(size);
int[] intArray = new int[array.Length];
int* intPtr = (int*)ptr.ToPointer();
for (int i = 0; i < array.Length; i++) for (int i = 0; i < array.Length; i++)
intArray[i] = (int)(object)array[i]; {
Marshal.Copy(intArray, 0, ptr, array.Length); // Convert enum to int. This has better performance than Convert.ToInt32.
intPtr[i] = (int)(object)array[i];
}
return ptr;
}
/// <summary>
/// Convert the struct to IntPtr. Should call <see cref="ReleaseRawMemory(IntPtr)"/> after use.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="structure"></param>
/// <returns></returns>
public static IntPtr ToIntPtr<T>(T structure) where T : struct
{
int size = Marshal.SizeOf(structure);
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(structure, ptr, true);
return ptr; return ptr;
} }
@@ -28,7 +116,7 @@ namespace VIVE.OpenXR
/// <typeparam name="T">Data type could be primitive type or struct. Should call <see cref="ReleaseRawMemory(IntPtr)"/> after use.</typeparam> /// <typeparam name="T">Data type could be primitive type or struct. Should call <see cref="ReleaseRawMemory(IntPtr)"/> after use.</typeparam>
/// <param name="refArray">The data array</param> /// <param name="refArray">The data array</param>
/// <returns>The memory handle. Should release by <see cref="ReleaseRawMemory(IntPtr)"/></returns> /// <returns>The memory handle. Should release by <see cref="ReleaseRawMemory(IntPtr)"/></returns>
public static IntPtr MakeRawMemory<T>(T[] refArray) public static unsafe IntPtr MakeRawMemory<T>(T[] refArray) where T : unmanaged
{ {
int size = Marshal.SizeOf(typeof(T)) * refArray.Length; int size = Marshal.SizeOf(typeof(T)) * refArray.Length;
return Marshal.AllocHGlobal(size); return Marshal.AllocHGlobal(size);
@@ -41,16 +129,54 @@ namespace VIVE.OpenXR
/// <param name="array">The output array.</param> /// <param name="array">The output array.</param>
/// <param name="raw">The data source in raw memory form.</param> /// <param name="raw">The data source in raw memory form.</param>
/// <param name="count">Specify the copy count. Count should be less than array length.</param> /// <param name="count">Specify the copy count. Count should be less than array length.</param>
public static void CopyFromRawMemory<T>(T[] array, IntPtr raw, int count = 0) public static unsafe void CopyFromRawMemory<T>(T[] array, IntPtr raw, int count = 0) where T : unmanaged
{ {
//Profiler.BeginSample("CopyFromRawMemory");
int N = array.Length; int N = array.Length;
if (count > 0 && count < array.Length) if (count > 0 && count < array.Length)
N = count; N = count;
int step = Marshal.SizeOf(typeof(T)); int step = sizeof(T);
for (int i = 0; i < N; i++) int bufferSize = step * N;
// Pin array's address. Prevent GC move it.
fixed (T* destPtr = array)
{ {
array[i] = Marshal.PtrToStructure<T>(IntPtr.Add(raw, i * step)); T* sourcePtr = (T*)raw.ToPointer();
Buffer.MemoryCopy(sourcePtr, destPtr, bufferSize, bufferSize);
} }
//Profiler.EndSample();
}
/// <summary>
/// Copy all raw memory to the array. This has higher performance than <see cref="CopyFromRawMemory"/>.
/// Use this method if you have frequent update requirements.
/// You need prepare a byte buffer to store the raw memory. The byte buffer size should be tSize * array.Length.
/// tSize is used for checking the byte buffer size. If tSize is 0, it will use Marshal.SizeOf(typeof(T)).
/// You can save the size at your size to avoid the Marshal.Sizeof(typeof(T)) call repeatedly.
/// </summary>
/// <typeparam name="T">Convert the memory to this type array.</typeparam>
/// <param name="array">The output array.</param>
/// <param name="raw">The data source in raw memory form.</param>
public static unsafe void CopyAllFromRawMemory<T>(T[] array, IntPtr raw) where T : unmanaged
{
#if DEBUG
if (array == null)
throw new ArgumentNullException(nameof(array), "Output array cannot be null.");
if (raw == IntPtr.Zero)
throw new ArgumentNullException(nameof(raw), "Raw memory pointer cannot be null.");
#endif
//Profiler.BeginSample("CopyAllFromRawMemory");
int elementSize = sizeof(T);
int requiredBufferSize = elementSize * array.Length;
// Pin array's address. Prevent GC move it.
fixed (T* destPtr = array)
{
T* sourcePtr = (T*)raw.ToPointer();
Buffer.MemoryCopy(sourcePtr, destPtr, requiredBufferSize, requiredBufferSize);
}
//Profiler.EndSample();
} }
/// <summary> /// <summary>
@@ -59,13 +185,18 @@ namespace VIVE.OpenXR
/// <typeparam name="T">Convert this type array to raw memory.</typeparam> /// <typeparam name="T">Convert this type array to raw memory.</typeparam>
/// <param name="raw">The output data in raw memory form</param> /// <param name="raw">The output data in raw memory form</param>
/// <param name="array">The data source</param> /// <param name="array">The data source</param>
public static void CopyToRawMemory<T>(IntPtr raw, T[] array) public static unsafe void CopyToRawMemory<T>(IntPtr raw, T[] array) where T : unmanaged
{ {
int step = Marshal.SizeOf(typeof(T)); //Profiler.BeginSample("CopyToRawMemory");
for (int i = 0; i < array.Length; i++) int step = sizeof(T);
int bufferSize = step * array.Length;
// Pin array's address. Prevent GC move it.
fixed (T* destPtr = array)
{ {
Marshal.StructureToPtr<T>(array[i], IntPtr.Add(raw, i * step), false); void* ptr = raw.ToPointer();
Buffer.MemoryCopy(destPtr, ptr, bufferSize, bufferSize);
} }
//Profiler.EndSample();
} }
/// <summary> /// <summary>
@@ -76,5 +207,22 @@ namespace VIVE.OpenXR
{ {
Marshal.FreeHGlobal(ptr); Marshal.FreeHGlobal(ptr);
} }
/// <summary>
/// Find a pointer in the next chain. Make sure the input next pointer is a OpenXR XrBaseStructure derived struct.
/// </summary>
/// <param name="target"></param>
/// <param name="next"></param>
/// <returns>true if exist</returns>
public static bool HasPtrInNextChain(IntPtr target, IntPtr next)
{
while (next != IntPtr.Zero)
{
if (next == target)
return true;
next = GetNext(next);
}
return false;
}
} }
} }

View File

@@ -0,0 +1,278 @@
using System;
using System.Runtime.InteropServices;
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.Enterprise
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "VIVE XR Enterprise Command",
Desc = "Support Enterprise request with special command",
Company = "HTC",
OpenxrExtensionStrings = kOpenxrExtensionString,
Version = "0.1",
BuildTargetGroups = new[] { BuildTargetGroup.Android },
FeatureId = featureId,
Hidden = true
)]
#endif
public class ViveEnterpriseCommand : OpenXRFeature
{
#region Log
const string LOG_TAG = "VIVE.OpenXR.Enterprise.Command ";
private static void DEBUG(String msg) { Debug.Log(LOG_TAG + msg); }
private static void ERROR(String msg) { Debug.LogError(LOG_TAG + msg); }
#endregion
/// <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.enterprise.command";
/// <summary>
/// The extension string.
/// </summary>
public const string kOpenxrExtensionString = "XR_HTC_enterprise_command";
#region OpenXR Life Cycle
private static bool m_XrInstanceCreated = false;
private static bool m_XrSessionCreated = false;
private static XrInstance m_XrInstance = 0;
private static XrSession m_XrSession = 0;
private static XrSystemId m_XrSystemId = 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))
{
ERROR($"OnInstanceCreate() {kOpenxrExtensionString} is NOT enabled.");
return false;
}
m_XrInstanceCreated = true;
m_XrInstance = xrInstance;
DEBUG($"OnInstanceCreate() {m_XrInstance}");
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)
{
if (m_XrInstance == xrInstance)
{
m_XrInstanceCreated = false;
m_XrInstance = 0;
}
DEBUG($"OnInstanceDestroy() {xrInstance}");
}
/// <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;
DEBUG($"OnSystemChange() {m_XrSystemId}");
}
/// <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;
DEBUG($"OnSessionCreate() {m_XrSession}");
}
/// <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)
{
DEBUG($"OnSessionDestroy() {xrSession}");
if (m_XrSession == xrSession)
{
m_XrSession = 0;
m_XrSessionCreated = false;
}
}
#endregion
#region OpenXR function delegates
/// xrEnterpriseCommandHTC
private static ViveEnterpriseCommandHelper.xrEnterpriseCommandHTCDelegate xrEnterpriseCommandHTC;
/// xrGetInstanceProcAddr
private static OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddr;
/// <summary>
/// Enterprise command request for special functionality.
/// </summary>
/// <param name="request">The request of enterprise command</param>
/// <param name="result">The result of enterprise command</param>
/// <returns>Return XR_SUCCESS if request successfully. False otherwise.</returns>
private static XrResult EnterpriseCommandHTC(XrEnterpriseCommandBufferHTC request, ref XrEnterpriseCommandBufferHTC result)
{
if (!m_XrSessionCreated)
{
ERROR("EnterpriseCommandHTC() XR_ERROR_SESSION_LOST.");
return XrResult.XR_ERROR_SESSION_LOST;
}
if (!m_XrInstanceCreated)
{
ERROR("EnterpriseCommandHTC() XR_ERROR_INSTANCE_LOST.");
return XrResult.XR_ERROR_INSTANCE_LOST;
}
DEBUG($"EnterpriseCommandHTC() code: {request.code}, data: {CharArrayToString(request.data)}");
return xrEnterpriseCommandHTC(m_XrSession, request, ref result);
}
/// <summary>
/// Get the OpenXR function via XrInstance.
/// </summary>
/// <param name="xrInstance">The XrInstance is provided by the Unity OpenXR Plugin.</param>
/// <returns>Return true if request successfully. False otherwise.</returns>
private bool GetXrFunctionDelegates(XrInstance xrInstance)
{
/// xrGetInstanceProcAddr
if (xrGetInstanceProcAddr != null && xrGetInstanceProcAddr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrGetInstanceProcAddr.");
XrGetInstanceProcAddr = Marshal.GetDelegateForFunctionPointer(
xrGetInstanceProcAddr,
typeof(OpenXRHelper.xrGetInstanceProcAddrDelegate)) as OpenXRHelper.xrGetInstanceProcAddrDelegate;
}
else
{
ERROR("xrGetInstanceProcAddr");
return false;
}
/// xrEnterpriseCommandHTC
if (XrGetInstanceProcAddr(xrInstance, "xrEnterpriseCommandHTC", out IntPtr funcPtr) == XrResult.XR_SUCCESS)
{
if (funcPtr != IntPtr.Zero)
{
DEBUG("Get function pointer of xrEnterpriseCommandHTC.");
xrEnterpriseCommandHTC = Marshal.GetDelegateForFunctionPointer(
funcPtr,
typeof(ViveEnterpriseCommandHelper.xrEnterpriseCommandHTCDelegate)) as ViveEnterpriseCommandHelper.xrEnterpriseCommandHTCDelegate;
}
}
else
{
ERROR("xrEnterpriseCommandHTC");
return false;
}
return true;
}
#endregion
#region Public API
private const int kCharLength = 256;
private const char kEndChar = '\0';
private static char[] charArray = new char[kCharLength];
/// <summary>
/// Request special feature with command, it should take code and command string.
/// </summary>
/// <param name="requestCode">The type of request code is integer.</param>
/// <param name="requestCommand">The maximum length of request command is 256.</param>
/// <param name="resultCode">The output of result code.</param>
/// <param name="resultCommand">The output of result command.</param>
/// <returns>Return true if request successfully. False otherwise.</returns>
public static bool CommandRequest(int requestCode, string requestCommand, out int resultCode, out string resultCommand)
{
resultCode = 0;
resultCommand = string.Empty;
XrEnterpriseCommandBufferHTC request = new XrEnterpriseCommandBufferHTC(requestCode, StringToCharArray(requestCommand));
XrEnterpriseCommandBufferHTC result = new XrEnterpriseCommandBufferHTC(resultCode, StringToCharArray(resultCommand));
if (EnterpriseCommandHTC(request, ref result) == XrResult.XR_SUCCESS)
{
resultCode = result.code;
resultCommand = CharArrayToString(result.data);
DEBUG($"CommandRequest Result code: {resultCode}, data: {resultCommand}");
return true;
}
return false;
}
#endregion
private static char[] StringToCharArray(string str)
{
Array.Clear(charArray, 0, kCharLength);
if (!string.IsNullOrEmpty(str))
{
int arrayLength = Math.Min(str.Length, kCharLength);
for (int i = 0; i < arrayLength; i++)
{
charArray[i] = str[i];
}
charArray[kCharLength - 1] = kEndChar;
}
return charArray;
}
private static string CharArrayToString(char[] charArray)
{
int actualLength = Array.FindIndex(charArray, c => c == kEndChar);
if (actualLength == -1)
{
actualLength = charArray.Length;
}
return new string(charArray, 0, actualLength);
}
}
#region Helper
public struct XrEnterpriseCommandBufferHTC
{
public Int32 code;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public char[] data;
public XrEnterpriseCommandBufferHTC(int in_code, char[] in_data)
{
code = (Int32)in_code;
data = new char[in_data.Length];
Array.Copy(in_data, data, in_data.Length);
}
}
public class ViveEnterpriseCommandHelper
{
/// <summary>
/// The function delegate of xrEnterpriseCommandHTC.
/// </summary>
/// <param name="session">An <see cref="XrSession">XrSession</see> in which the enterprise command will be active.</param>
/// <param name="request">The request of enterprise command</param>
/// <param name="result">The result of enterprise command</param>
/// <returns>Return XR_SUCCESS if request successfully. False otherwise.</returns>
public delegate XrResult xrEnterpriseCommandHTCDelegate(
XrSession session,
XrEnterpriseCommandBufferHTC request,
ref XrEnterpriseCommandBufferHTC result);
}
#endregion
}

View File

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

View File

@@ -10,9 +10,14 @@ namespace VIVE.OpenXR.Feature
/// <summary> /// <summary>
/// To use this wrapper, you need to call CommonWrapper.Instance.OnInstanceCreate() in your feature's OnInstanceCreate(), /// To use this wrapper, you need to call CommonWrapper.Instance.OnInstanceCreate() in your feature's OnInstanceCreate(),
/// and call CommonWrapper.Instance.OnInstanceDestroy() in your feature's OnInstanceDestroy(). /// and call CommonWrapper.Instance.OnInstanceDestroy() in your feature's OnInstanceDestroy().
///
/// Note:
/// In Standardalone's OpenXR MockRuntime, the CreateSwapchain and EnumerateSwapchainImages will work and return success,
/// but the images's native pointer will be null.
/// </summary> /// </summary>
public class CommonWrapper : ViveFeatureWrapperBase<CommonWrapper>, IViveFeatureWrapper internal class CommonWrapper : ViveFeatureWrapperBase<CommonWrapper>, IViveFeatureWrapper
{ {
const string TAG = "CommonWrapper";
OpenXRHelper.xrGetSystemPropertiesDelegate XrGetSystemProperties; OpenXRHelper.xrGetSystemPropertiesDelegate XrGetSystemProperties;
OpenXRHelper.xrCreateSwapchainDelegate XrCreateSwapchain; OpenXRHelper.xrCreateSwapchainDelegate XrCreateSwapchain;
OpenXRHelper.xrDestroySwapchainDelegate XrDestroySwapchain; OpenXRHelper.xrDestroySwapchainDelegate XrDestroySwapchain;
@@ -32,11 +37,13 @@ namespace VIVE.OpenXR.Feature
public bool OnInstanceCreate(XrInstance xrInstance, IntPtr xrGetInstanceProcAddrPtr) public bool OnInstanceCreate(XrInstance xrInstance, IntPtr xrGetInstanceProcAddrPtr)
{ {
if (IsInited) return true; if (IsInited) return true;
if (TryInited) return false;
TryInited = true;
if (xrInstance == 0) if (xrInstance == 0)
throw new Exception("CommonWrapper: xrInstance is null"); throw new Exception("CommonWrapper: xrInstance is null");
Debug.Log("CommonWrapper: OnInstanceCreate()"); Log.D(TAG, "OnInstanceCreate()");
SetGetInstanceProcAddrPtr(xrGetInstanceProcAddrPtr); SetGetInstanceProcAddrPtr(xrGetInstanceProcAddrPtr);
bool ret = true; bool ret = true;
@@ -64,9 +71,11 @@ namespace VIVE.OpenXR.Feature
/// <returns></returns> /// <returns></returns>
public void OnInstanceDestroy() public void OnInstanceDestroy()
{ {
// Do not destroy twice
if (IsInited == false) return;
IsInited = false; IsInited = false;
XrGetSystemProperties = null; XrGetSystemProperties = null;
Debug.Log("CommonWrapper: OnInstanceDestroy()"); Log.D(TAG, "OnInstanceDestroy()");
} }
public XrResult GetInstanceProcAddr(XrInstance instance, string name, out IntPtr function) public XrResult GetInstanceProcAddr(XrInstance instance, string name, out IntPtr function)
@@ -164,12 +173,12 @@ namespace VIVE.OpenXR.Feature
if (formatCapacityInput == 0) if (formatCapacityInput == 0)
{ {
Debug.Log("CommonWrapper: EnumerateSwapchainFormats(ci=" + formatCapacityInput + ")"); Log.D(TAG, "EnumerateSwapchainFormats(ci=" + formatCapacityInput + ")");
return XrEnumerateSwapchainFormats(session, 0, ref formatCountOutput, IntPtr.Zero); return XrEnumerateSwapchainFormats(session, 0, ref formatCountOutput, IntPtr.Zero);
} }
else else
{ {
Debug.Log("CommonWrapper: EnumerateSwapchainFormats(ci=" + formatCapacityInput + ", formats=long[" + formats.Length + "])"); Log.D(TAG, "EnumerateSwapchainFormats(ci=" + formatCapacityInput + ", formats=long[" + formats.Length + "])");
IntPtr formatsPtr = MemoryTools.MakeRawMemory(formats); IntPtr formatsPtr = MemoryTools.MakeRawMemory(formats);
var ret = XrEnumerateSwapchainFormats(session, formatCapacityInput, ref formatCountOutput, formatsPtr); var ret = XrEnumerateSwapchainFormats(session, formatCapacityInput, ref formatCountOutput, formatsPtr);
if (ret == XrResult.XR_SUCCESS) if (ret == XrResult.XR_SUCCESS)
@@ -201,7 +210,7 @@ namespace VIVE.OpenXR.Feature
return XrResult.XR_ERROR_HANDLE_INVALID; return XrResult.XR_ERROR_HANDLE_INVALID;
} }
Profiler.BeginSample("ASW: xrAcqScImg"); Profiler.BeginSample("ASW:xrAcqScImg");
var res = XrAcquireSwapchainImage(swapchain, ref acquireInfo, out index); var res = XrAcquireSwapchainImage(swapchain, ref acquireInfo, out index);
Profiler.EndSample(); Profiler.EndSample();
return res; return res;
@@ -217,7 +226,7 @@ namespace VIVE.OpenXR.Feature
return XrResult.XR_ERROR_HANDLE_INVALID; return XrResult.XR_ERROR_HANDLE_INVALID;
} }
Profiler.BeginSample("ASW: xrWaitScImg"); Profiler.BeginSample("ASW:xrWaitScImg");
var res = XrWaitSwapchainImage(swapchain, ref waitInfo); var res = XrWaitSwapchainImage(swapchain, ref waitInfo);
Profiler.EndSample(); Profiler.EndSample();
return res; return res;
@@ -234,7 +243,7 @@ namespace VIVE.OpenXR.Feature
} }
// Add Profiler // Add Profiler
Profiler.BeginSample("ASW: xrRelScImg"); Profiler.BeginSample("ASW:xrRelScImg");
var res = XrReleaseSwapchainImage(swapchain, ref releaseInfo); var res = XrReleaseSwapchainImage(swapchain, ref releaseInfo);
Profiler.EndSample(); Profiler.EndSample();
return res; return res;

View File

@@ -17,6 +17,8 @@ namespace VIVE.OpenXR.Feature
/// </summary> /// </summary>
public class FutureWrapper : ViveFeatureWrapperBase<FutureWrapper>, IViveFeatureWrapper public class FutureWrapper : ViveFeatureWrapperBase<FutureWrapper>, IViveFeatureWrapper
{ {
const string TAG = "ViveFuture";
public enum XrFutureStateEXT public enum XrFutureStateEXT
{ {
None = 0, // Not defined in extension. A default value. None = 0, // Not defined in extension. A default value.
@@ -76,6 +78,8 @@ namespace VIVE.OpenXR.Feature
public bool OnInstanceCreate(XrInstance xrInstance, IntPtr xrGetInstanceProcAddrPtr) public bool OnInstanceCreate(XrInstance xrInstance, IntPtr xrGetInstanceProcAddrPtr)
{ {
if (IsInited) return true; if (IsInited) return true;
if (TryInited) return false;
TryInited = true;
if (xrInstance == null) if (xrInstance == null)
throw new Exception("FutureWrapper: xrInstance is null"); throw new Exception("FutureWrapper: xrInstance is null");
@@ -85,12 +89,12 @@ namespace VIVE.OpenXR.Feature
throw new Exception("FutureWrapper: xrGetInstanceProcAddr is null"); throw new Exception("FutureWrapper: xrGetInstanceProcAddr is null");
SetGetInstanceProcAddrPtr(xrGetInstanceProcAddrPtr); SetGetInstanceProcAddrPtr(xrGetInstanceProcAddrPtr);
Debug.Log("FutureWrapper: OnInstanceCreate()"); Log.D(TAG, "OnInstanceCreate()");
bool hasFuture = OpenXRRuntime.IsExtensionEnabled("XR_EXT_future"); bool hasFuture = OpenXRRuntime.IsExtensionEnabled("XR_EXT_future");
if (!hasFuture) if (!hasFuture)
{ {
Debug.LogError("FutureWrapper: XR_EXT_future is not enabled. Check your feature's kOpenxrExtensionString."); Log.E(TAG, "FutureWrapper: XR_EXT_future is not enabled. Check your feature's kOpenxrExtensionString.");
return false; return false;
} }
@@ -102,7 +106,7 @@ namespace VIVE.OpenXR.Feature
if (!ret) if (!ret)
{ {
Debug.LogError("FutureWrapper: Failed to get function pointer."); Log.E(TAG,"FutureWrapper: Failed to get function pointer.");
return false; return false;
} }
@@ -112,7 +116,7 @@ namespace VIVE.OpenXR.Feature
public void OnInstanceDestroy() public void OnInstanceDestroy()
{ {
Debug.Log("FutureWrapper: OnInstanceDestroy()"); Log.D(TAG, "OnInstanceDestroy()");
IsInited = false; IsInited = false;
XrPollFutureEXT = null; XrPollFutureEXT = null;
XrCancelFutureEXT = null; XrCancelFutureEXT = null;

View File

@@ -1,6 +1,7 @@
// Copyright HTC Corporation All Rights Reserved. // Copyright HTC Corporation All Rights Reserved.
using System; using System;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
namespace VIVE.OpenXR.Feature namespace VIVE.OpenXR.Feature
@@ -12,9 +13,13 @@ namespace VIVE.OpenXR.Feature
/// </summary> /// </summary>
public class SpaceWrapper : ViveFeatureWrapperBase<SpaceWrapper>, IViveFeatureWrapper public class SpaceWrapper : ViveFeatureWrapperBase<SpaceWrapper>, IViveFeatureWrapper
{ {
const string TAG = "ViveSpaceWrapper";
public delegate XrResult DelegateXrEnumerateReferenceSpaces(XrSession session, uint spaceCapacityInput, out uint spaceCountOutput, [Out] XrReferenceSpaceType[] spaces);
delegate XrResult DelegateXrLocateSpace(XrSpace space, XrSpace baseSpace, XrTime time, ref XrSpaceLocation location); delegate XrResult DelegateXrLocateSpace(XrSpace space, XrSpace baseSpace, XrTime time, ref XrSpaceLocation location);
delegate XrResult DelegateXrDestroySpace(XrSpace space); delegate XrResult DelegateXrDestroySpace(XrSpace space);
DelegateXrEnumerateReferenceSpaces XrEnumerateReferenceSpaces;
OpenXRHelper.xrCreateReferenceSpaceDelegate XrCreateReferenceSpace; OpenXRHelper.xrCreateReferenceSpaceDelegate XrCreateReferenceSpace;
DelegateXrLocateSpace XrLocateSpace; DelegateXrLocateSpace XrLocateSpace;
DelegateXrDestroySpace XrDestroySpace; DelegateXrDestroySpace XrDestroySpace;
@@ -29,17 +34,20 @@ namespace VIVE.OpenXR.Feature
public bool OnInstanceCreate(XrInstance xrInstance, IntPtr GetAddr) public bool OnInstanceCreate(XrInstance xrInstance, IntPtr GetAddr)
{ {
if (IsInited) return true; if (IsInited) return true;
if (TryInited) return false;
TryInited = true;
if (xrInstance == null) if (xrInstance == null)
throw new Exception("ViveSpace: xrInstance is null"); throw new Exception("ViveSpaceWrapper: xrInstance is null");
SetGetInstanceProcAddrPtr(GetAddr); SetGetInstanceProcAddrPtr(GetAddr);
Debug.Log("ViveSpace: OnInstanceCreate()"); Log.D(TAG, "OnInstanceCreate()");
bool ret = true; bool ret = true;
IntPtr funcPtr = IntPtr.Zero; IntPtr funcPtr = IntPtr.Zero;
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrEnumerateReferenceSpaces", out XrEnumerateReferenceSpaces);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrCreateReferenceSpace", out XrCreateReferenceSpace); ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrCreateReferenceSpace", out XrCreateReferenceSpace);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrLocateSpace", out XrLocateSpace); ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrLocateSpace", out XrLocateSpace);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrDestroySpace", out XrDestroySpace); ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrDestroySpace", out XrDestroySpace);
@@ -49,12 +57,35 @@ namespace VIVE.OpenXR.Feature
public void OnInstanceDestroy() public void OnInstanceDestroy()
{ {
// Do not destroy twice
if (IsInited == false) return;
IsInited = false; IsInited = false;
XrEnumerateReferenceSpaces = null;
XrCreateReferenceSpace = null; XrCreateReferenceSpace = null;
XrLocateSpace = null; XrLocateSpace = null;
XrDestroySpace = null; XrDestroySpace = null;
} }
/// <summary>
///
/// </summary>
/// <param name="session"></param>
/// <param name="spaceCapacityInput"></param>
/// <param name="spaceCountOutput"></param>
/// <param name="spaces"></param>
/// <returns></returns>
public XrResult EnumerateReferenceSpaces(XrSession session, int spaceCapacityInput, ref int spaceCountOutput, ref XrReferenceSpaceType[] spaces)
{
spaceCountOutput = 0;
if (!IsInited)
return XrResult.XR_ERROR_HANDLE_INVALID;
if (spaceCapacityInput != 0 && spaces != null && spaces.Length < spaceCapacityInput)
return XrResult.XR_ERROR_SIZE_INSUFFICIENT;
var ret = XrEnumerateReferenceSpaces(session, (uint)spaceCapacityInput, out uint spaceCountOutputXR, spaces);
spaceCountOutput = (int)spaceCountOutputXR;
return ret;
}
/// <summary> /// <summary>
/// Create a reference space without create info. /// Create a reference space without create info.
/// Example: /// Example:
@@ -108,7 +139,7 @@ namespace VIVE.OpenXR.Feature
{ {
if (!IsInited) if (!IsInited)
return XrResult.XR_ERROR_HANDLE_INVALID; return XrResult.XR_ERROR_HANDLE_INVALID;
Debug.Log($"DestroySpace({space})"); Log.D(TAG, $"DestroySpace({space})");
return XrDestroySpace(space); return XrDestroySpace(space);
} }
} }
@@ -124,7 +155,7 @@ namespace VIVE.OpenXR.Feature
public Space(XrSpace space) public Space(XrSpace space)
{ {
Debug.Log($"Space({space})"); Log.D($"Space({space})");
this.space = space; this.space = space;
} }

View File

@@ -5,9 +5,25 @@ using UnityEngine;
using AOT; using AOT;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Linq;
namespace VIVE.OpenXR namespace VIVE.OpenXR
{ {
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
internal class HookHandlerAttribute : Attribute
{
public string xrFuncName { get; }
/// <summary>
/// Set this function to handle the hook process in <see cref="ViveInterceptors.XrGetInstanceProcAddrInterceptor" />
/// </summary>
/// <param name="xrFuncName">The hooked openxr function name</param>
public HookHandlerAttribute(string xrFuncName)
{
this.xrFuncName = xrFuncName;
}
}
/// <summary> /// <summary>
/// This class is made for all features that need to intercept OpenXR API calls. /// This class is made for all features that need to intercept OpenXR API calls.
/// Some APIs will be called by Unity internally, and we need to intercept them in c# to get some information. /// Some APIs will be called by Unity internally, and we need to intercept them in c# to get some information.
@@ -22,6 +38,15 @@ namespace VIVE.OpenXR
/// return ViveInterceptors.Instance.HookGetInstanceProcAddr(func); /// return ViveInterceptors.Instance.HookGetInstanceProcAddr(func);
/// } /// }
/// </summary> /// </summary>
// For extending the ViveInterceptors class, create a new partial class and implement the required functions.
// For example:
// public partial class ViveInterceptors
// {
// [HookHandler("xrYourFunction")]
// private static XrResult OnHookXrYourFunction(XrInstance instance, string name, out IntPtr function)
// { ... }
// }
partial class ViveInterceptors partial class ViveInterceptors
{ {
public const string TAG = "VIVE.OpenXR.ViveInterceptors"; public const string TAG = "VIVE.OpenXR.ViveInterceptors";
@@ -32,8 +57,6 @@ namespace VIVE.OpenXR
return m_sb; return m_sb;
} }
} }
static void DEBUG(StringBuilder msg) { Debug.LogFormat("{0} {1}", TAG, msg); }
static void ERROR(StringBuilder msg) { Debug.LogErrorFormat("{0} {1}", TAG, msg); }
public static ViveInterceptors instance = null; public static ViveInterceptors instance = null;
public static ViveInterceptors Instance public static ViveInterceptors Instance
@@ -48,15 +71,32 @@ namespace VIVE.OpenXR
public ViveInterceptors() public ViveInterceptors()
{ {
Debug.Log("ViveInterceptors"); Log.D("ViveInterceptors");
RegisterFunctions();
} }
public delegate XrResult DelegateXrGetInstanceProcAddr(XrInstance instance, string name, out IntPtr function); delegate XrResult HookHandler(XrInstance instance, string name, out IntPtr function);
private static readonly DelegateXrGetInstanceProcAddr hookXrGetInstanceProcAddrHandle = new DelegateXrGetInstanceProcAddr(XrGetInstanceProcAddrInterceptor); static readonly Dictionary<string, HookHandler> interceptors = new Dictionary<string, HookHandler>();
private static readonly IntPtr hookGetInstanceProcAddrHandlePtr = Marshal.GetFunctionPointerForDelegate(hookXrGetInstanceProcAddrHandle);
static DelegateXrGetInstanceProcAddr XrGetInstanceProcAddrOriginal = null;
[MonoPInvokeCallback(typeof(DelegateXrGetInstanceProcAddr))] private static void RegisterFunctions()
{
var methods = typeof(ViveInterceptors).GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
foreach (var method in methods)
{
var attribute = method.GetCustomAttributes(typeof(HookHandlerAttribute), false).FirstOrDefault() as HookHandlerAttribute;
if (attribute != null)
{
Log.I(TAG, $"Registering hook handler {attribute.xrFuncName}");
interceptors.Add(attribute.xrFuncName, (HookHandler)method.CreateDelegate(typeof(HookHandler)));
}
}
}
private static readonly OpenXRHelper.xrGetInstanceProcAddrDelegate hookXrGetInstanceProcAddrHandle = new OpenXRHelper.xrGetInstanceProcAddrDelegate(XrGetInstanceProcAddrInterceptor);
private static readonly IntPtr hookGetInstanceProcAddrHandlePtr = Marshal.GetFunctionPointerForDelegate(hookXrGetInstanceProcAddrHandle);
static OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddrOriginal = null;
[MonoPInvokeCallback(typeof(OpenXRHelper.xrGetInstanceProcAddrDelegate))]
private static XrResult XrGetInstanceProcAddrInterceptor(XrInstance instance, string name, out IntPtr function) private static XrResult XrGetInstanceProcAddrInterceptor(XrInstance instance, string name, out IntPtr function)
{ {
// Used to check if the original function is already hooked. // Used to check if the original function is already hooked.
@@ -66,64 +106,16 @@ namespace VIVE.OpenXR
return XrResult.XR_SUCCESS; return XrResult.XR_SUCCESS;
} }
// Custom interceptors // Check if the function is intercepted by other features
if (name == "xrWaitFrame" && requiredFunctions.Contains(name)) if (interceptors.ContainsKey(name))
{ {
Debug.Log($"{TAG}: XrGetInstanceProcAddrInterceptor() {name} is intercepted."); // If no request for this function, call the original function directly.
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function); if (!requiredFunctions.Contains(name))
if (ret == XrResult.XR_SUCCESS) return XrGetInstanceProcAddrOriginal(instance, name, out function);
{
XrWaitFrameOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrWaitFrame>(function);
function = xrWaitFrameInterceptorPtr;
}
return ret;
}
if (name == "xrEndFrame" && requiredFunctions.Contains(name)) var ret = interceptors[name](instance, name, out function);
{
Debug.Log($"{TAG}: XrGetInstanceProcAddrInterceptor() {name} is intercepted.");
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret == XrResult.XR_SUCCESS) if (ret == XrResult.XR_SUCCESS)
{ Log.I(TAG, name + " is intercepted");
XrEndFrameOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrEndFrame>(function);
function = xrEndFrameInterceptorPtr;
}
return ret;
}
#if PERFORMANCE_TEST
if (name == "xrLocateSpace" && requiredFunctions.Contains(name))
{
Debug.Log($"{TAG}: XrGetInstanceProcAddrInterceptor() {name} is intercepted.");
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret == XrResult.XR_SUCCESS)
{
XrLocateSpaceOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrLocateSpace>(function);
function = xrLocateSpaceInterceptorPtr;
}
return ret;
}
#endif
if (name == "xrPollEvent" && requiredFunctions.Contains(name))
{
Debug.Log($"{TAG}: XrGetInstanceProcAddrInterceptor() {name} is intercepted.");
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret == XrResult.XR_SUCCESS)
{
xrPollEventOrigin = Marshal.GetDelegateForFunctionPointer < xrPollEventDelegate > (function);
function = xrPollEventPtr;
}
return ret;
}
if (name == "xrBeginSession" && requiredFunctions.Contains(name))
{
Debug.Log($"{TAG}: XrGetInstanceProcAddrInterceptor() {name} is intercepted.");
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret == XrResult.XR_SUCCESS)
{
xrBeginSessionOrigin = Marshal.GetDelegateForFunctionPointer<xrBeginSessionDelegate>(function);
function = xrBeginSessionPtr;
}
return ret; return ret;
} }
@@ -132,23 +124,23 @@ namespace VIVE.OpenXR
public IntPtr HookGetInstanceProcAddr(IntPtr func) public IntPtr HookGetInstanceProcAddr(IntPtr func)
{ {
Debug.Log($"{TAG}: HookGetInstanceProcAddr"); Log.D(TAG, "HookGetInstanceProcAddr");
if (XrGetInstanceProcAddrOriginal == null) if (XrGetInstanceProcAddrOriginal == null)
{ {
Debug.Log($"{TAG}: registering our own xrGetInstanceProcAddr"); Log.D(TAG, "registering our own xrGetInstanceProcAddr");
XrGetInstanceProcAddrOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrGetInstanceProcAddr>(func); XrGetInstanceProcAddrOriginal = Marshal.GetDelegateForFunctionPointer<OpenXRHelper.xrGetInstanceProcAddrDelegate>(func);
#if UNITY_EDITOR #if UNITY_EDITOR
if (Application.isEditor) { if (Application.isEditor) {
// This is a trick to check if the original function is already hooked by this class. Sometimes, the static XrGetInstanceProcAddrOriginal didn't work as expected. // This is a trick to check if the original function is already hooked by this class. Sometimes, the static XrGetInstanceProcAddrOriginal didn't work as expected.
Debug.Log($"{TAG}: Check if duplicate hooked by this script with instance=0 and \"ViveInterceptorHooked\" name. If following a loader error, ignore it."); Log.D(TAG, "Check if duplicate hooked by this script with instance=0 and \"ViveInterceptorHooked\" name. If following a loader error, ignore it.");
// E OpenXR-Loader: Error [SPEC | xrGetInstanceProcAddr | VUID-xrGetInstanceProcAddr-instance-parameter] : XR_NULL_HANDLE for instance but query for ViveInterceptorHooked requires a valid instance // E OpenXR-Loader: Error [SPEC | xrGetInstanceProcAddr | VUID-xrGetInstanceProcAddr-instance-parameter] : XR_NULL_HANDLE for instance but query for ViveInterceptorHooked requires a valid instance
// Call XrGetInstanceProcAddrOriginal to check if the original function is already hooked by this class // Call XrGetInstanceProcAddrOriginal to check if the original function is already hooked by this class
if (XrGetInstanceProcAddrOriginal(0, "ViveInterceptorHooked", out IntPtr function) == XrResult.XR_SUCCESS) if (XrGetInstanceProcAddrOriginal(0, "ViveInterceptorHooked", out IntPtr function) == XrResult.XR_SUCCESS)
{ {
// If it is called successfully, it means the original function is already hooked. So we should return the original function. // If it is called successfully, it means the original function is already hooked. So we should return the original function.
Debug.Log($"{TAG}: Already hooked"); Log.D(TAG, "Already hooked");
return func; return func;
} }
} }
@@ -173,9 +165,34 @@ namespace VIVE.OpenXR
/// <param name="name"></param> /// <param name="name"></param>
public void AddRequiredFunction(string name) public void AddRequiredFunction(string name)
{ {
if (requiredFunctions.Contains(name)) return; Log.D(TAG, $"AddRequiredFunction({name})");
Debug.Log($"{TAG}: AddRequiredFunction({name})"); if (!interceptors.ContainsKey(name))
{
Log.E(TAG, $"AddRequiredFunction({name}) failed. No such function.");
return;
}
if (!requiredFunctions.Contains(name))
requiredFunctions.Add(name); requiredFunctions.Add(name);
// If your function support unregister, you can add the reference count here.
if (name == "xrLocateViews")
xrLocateViewsReferenceCount++;
}
/// <summary>
/// If no need to use this hooked function, call this will remove your requirement.
/// If all requirements are removed, the original function will be called directly.
/// </summary>
/// <param name="name"></param>
public void RemoveRequiredFunction(string name)
{
// If your function support unregister, you can add the reference count here.
if (requiredFunctions.Contains(name))
{
if (name == "xrLocateViews")
xrLocateViewsReferenceCount = Mathf.Max(xrLocateViewsReferenceCount--, 0);
}
} }
} }
} }

View File

@@ -12,6 +12,21 @@ namespace VIVE.OpenXR
{ {
partial class ViveInterceptors partial class ViveInterceptors
{ {
[HookHandler("xrBeginSession")]
private static XrResult OnHookXrBeginSession(XrInstance instance, string name, out IntPtr function)
{
if (xrBeginSessionOrigin == null)
{
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret != XrResult.XR_SUCCESS)
return ret;
xrBeginSessionOrigin = Marshal.GetDelegateForFunctionPointer<xrBeginSessionDelegate>(function);
}
function = xrBeginSessionPtr;
return XrResult.XR_SUCCESS;
}
#region xrBeginSession #region xrBeginSession
public delegate XrResult xrBeginSessionDelegate(XrSession session, ref XrSessionBeginInfo beginInfo); public delegate XrResult xrBeginSessionDelegate(XrSession session, ref XrSessionBeginInfo beginInfo);
private static xrBeginSessionDelegate xrBeginSessionOrigin = null; private static xrBeginSessionDelegate xrBeginSessionOrigin = null;
@@ -19,7 +34,7 @@ namespace VIVE.OpenXR
[MonoPInvokeCallback(typeof(xrBeginSessionDelegate))] [MonoPInvokeCallback(typeof(xrBeginSessionDelegate))]
private static XrResult xrBeginSessionInterceptor(XrSession session, ref XrSessionBeginInfo beginInfo) private static XrResult xrBeginSessionInterceptor(XrSession session, ref XrSessionBeginInfo beginInfo)
{ {
Profiler.BeginSample("ViveInterceptors:BeginSession"); Profiler.BeginSample("VI:BeginSession");
XrResult result = XrResult.XR_ERROR_FUNCTION_UNSUPPORTED; XrResult result = XrResult.XR_ERROR_FUNCTION_UNSUPPORTED;
if (xrBeginSessionOrigin != null) if (xrBeginSessionOrigin != null)
@@ -48,7 +63,8 @@ namespace VIVE.OpenXR
IntPtr fs_begin_info_ptr = new IntPtr(offset); IntPtr fs_begin_info_ptr = new IntPtr(offset);
XrFrameSynchronizationSessionBeginInfoHTC fsBeginInfo = (XrFrameSynchronizationSessionBeginInfoHTC)Marshal.PtrToStructure(fs_begin_info_ptr, typeof(XrFrameSynchronizationSessionBeginInfoHTC)); XrFrameSynchronizationSessionBeginInfoHTC fsBeginInfo = (XrFrameSynchronizationSessionBeginInfoHTC)Marshal.PtrToStructure(fs_begin_info_ptr, typeof(XrFrameSynchronizationSessionBeginInfoHTC));
sb.Clear().Append("xrBeginSessionInterceptor() beginInfo.next = (").Append(fsBeginInfo.type).Append(", ").Append(fsBeginInfo.mode).Append(")"); DEBUG(sb); sb.Clear().Append("xrBeginSessionInterceptor() beginInfo.next = (").Append(fsBeginInfo.type).Append(", ").Append(fsBeginInfo.mode).Append(")");
Log.D(sb);
#endif #endif
} }
@@ -56,7 +72,7 @@ namespace VIVE.OpenXR
} }
else else
{ {
sb.Clear().Append("xrBeginSessionInterceptor() Not assign xrBeginSession!"); ERROR(sb); Log.E("xrBeginSessionInterceptor() Not assign xrBeginSession!");
} }
Profiler.EndSample(); Profiler.EndSample();
@@ -79,7 +95,8 @@ namespace VIVE.OpenXR
{ {
m_EnableFrameSynchronization = active; m_EnableFrameSynchronization = active;
m_FrameSynchronizationMode = mode; m_FrameSynchronizationMode = mode;
sb.Clear().Append("ActivateFrameSynchronization() ").Append(active ? "enable " : "disable ").Append(mode); DEBUG(sb); sb.Clear().Append("ActivateFrameSynchronization() ").Append(active ? "enable " : "disable ").Append(mode);
Log.D(sb);
} }
} }
} }

View File

@@ -0,0 +1,98 @@
// Copyright HTC Corporation All Rights Reserved.
using System.Runtime.InteropServices;
using System;
using AOT;
using UnityEngine.Profiling;
namespace VIVE.OpenXR
{
public partial class ViveInterceptors
{
[HookHandler("xrLocateViews")]
private static XrResult OnHookXrLocateViews(XrInstance instance, string name, out IntPtr function)
{
if (xrLocateViewsOriginal == null)
{
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret != XrResult.XR_SUCCESS)
return ret;
xrLocateViewsOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrLocateViews>(function);
}
function = xrLocateViewsInterceptorPtr;
return XrResult.XR_SUCCESS;
}
public struct XrViewLocateInfo
{
public XrStructureType type;
public IntPtr next;
public XrViewConfigurationType viewConfigurationType;
public XrTime displayTime;
public XrSpace space;
}
public struct XrView
{
public XrStructureType type;
public IntPtr next;
public XrPosef pose;
public XrFovf fov;
}
public enum XrViewStateFlags {
ORIENTATION_VALID_BIT = 0x00000001,
POSITION_VALID_BIT = 0x00000002,
ORIENTATION_TRACKED_BIT = 0x00000004,
POSITION_TRACKED_BIT = 0x00000008,
}
public struct XrViewState
{
public XrStructureType type;
public IntPtr next;
public XrViewStateFlags viewStateFlags;
}
public delegate XrResult DelegateXrLocateViews(XrSession session, IntPtr /*XrViewLocateInfo*/ viewLocateInfo, IntPtr /*XrViewState*/ viewState, uint viewCapacityInput, ref uint viewCountOutput, IntPtr /*XrView*/ views);
private static readonly DelegateXrLocateViews xrLocateViewsInterceptorHandle = new DelegateXrLocateViews(XrLocateViewsInterceptor);
private static readonly IntPtr xrLocateViewsInterceptorPtr = Marshal.GetFunctionPointerForDelegate(xrLocateViewsInterceptorHandle);
static DelegateXrLocateViews xrLocateViewsOriginal = null;
static int xrLocateViewsReferenceCount = 0;
[MonoPInvokeCallback(typeof(DelegateXrLocateViews))]
private static XrResult XrLocateViewsInterceptor(XrSession session, IntPtr viewLocateInfo, IntPtr viewState, uint viewCapacityInput, ref uint viewCountOutput, IntPtr views)
{
// Call the original function if the reference count is less than or equal to 0
if (xrLocateViewsReferenceCount <= 0)
return xrLocateViewsOriginal(session, viewLocateInfo, viewState, viewCapacityInput, ref viewCountOutput, views);
Profiler.BeginSample("VI:LocateViewsA");
XrResult result = XrResult.XR_SUCCESS;
if (instance.BeforeOriginalLocateViews != null)
instance.BeforeOriginalLocateViews(session, viewLocateInfo, viewState, viewCapacityInput, ref viewCountOutput, views);
Profiler.EndSample();
result = xrLocateViewsOriginal(session, viewLocateInfo, viewState, viewCapacityInput, ref viewCountOutput, views);
Profiler.BeginSample("VI:LocateViewsB");
instance.AfterOriginalLocateViews?.Invoke(session, viewLocateInfo, viewState, viewCapacityInput, ref viewCountOutput, views);
Profiler.EndSample();
return result;
}
/// <summary>
/// If you return false, the original function will not be called.
/// </summary>
/// <returns></returns>
public delegate bool DelegateXrLocateViewsInterceptor(XrSession session, IntPtr viewLocateInfo, IntPtr viewState, uint viewCapacityInput, ref uint viewCountOutput, IntPtr views);
/// <summary>
/// Use this to intercept the original function. This will be called before the original function.
/// </summary>
public DelegateXrLocateViewsInterceptor BeforeOriginalLocateViews;
/// <summary>
/// Use this to intercept the original function. This will be called after the original function.
/// </summary>
public DelegateXrLocateViewsInterceptor AfterOriginalLocateViews;
}
}

View File

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

View File

@@ -12,6 +12,20 @@ namespace VIVE.OpenXR
{ {
partial class ViveInterceptors partial class ViveInterceptors
{ {
[HookHandler("xrPollEvent")]
private static XrResult OnHookXrPollEvent(XrInstance instance, string name, out IntPtr function)
{
if (xrPollEventOrigin == null)
{
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret != XrResult.XR_SUCCESS)
return ret;
xrPollEventOrigin = Marshal.GetDelegateForFunctionPointer<xrPollEventDelegate>(function);
}
function = xrPollEventPtr;
return XrResult.XR_SUCCESS;
}
#region xrPollEvent #region xrPollEvent
public delegate XrResult xrPollEventDelegate(XrInstance instance, ref XrEventDataBuffer eventData); public delegate XrResult xrPollEventDelegate(XrInstance instance, ref XrEventDataBuffer eventData);
private static xrPollEventDelegate xrPollEventOrigin = null; private static xrPollEventDelegate xrPollEventOrigin = null;
@@ -19,7 +33,7 @@ namespace VIVE.OpenXR
[MonoPInvokeCallback(typeof(xrPollEventDelegate))] [MonoPInvokeCallback(typeof(xrPollEventDelegate))]
private static XrResult xrPollEventInterceptor(XrInstance instance, ref XrEventDataBuffer eventData) private static XrResult xrPollEventInterceptor(XrInstance instance, ref XrEventDataBuffer eventData)
{ {
Profiler.BeginSample("ViveInterceptors:WaitFrame"); Profiler.BeginSample("VI:PollEvent");
XrResult result = XrResult.XR_SUCCESS; XrResult result = XrResult.XR_SUCCESS;
if (xrPollEventOrigin != null) if (xrPollEventOrigin != null)
@@ -28,7 +42,7 @@ namespace VIVE.OpenXR
if (result == XrResult.XR_SUCCESS) if (result == XrResult.XR_SUCCESS)
{ {
sb.Clear().Append("xrPollEventInterceptor() xrPollEvent ").Append(eventData.type); DEBUG(sb); sb.Clear().Append("xrPollEventInterceptor() xrPollEvent ").Append(eventData.type); Log.D("PollEvent", sb);
switch(eventData.type) switch(eventData.type)
{ {
case XrStructureType.XR_TYPE_EVENT_DATA_PASSTHROUGH_CONFIGURATION_IMAGE_RATE_CHANGED_HTC: case XrStructureType.XR_TYPE_EVENT_DATA_PASSTHROUGH_CONFIGURATION_IMAGE_RATE_CHANGED_HTC:
@@ -41,7 +55,7 @@ namespace VIVE.OpenXR
.Append(", fromImageRatesrc.dstImageRate: ").Append(fromImageRate.dstImageRate) .Append(", fromImageRatesrc.dstImageRate: ").Append(fromImageRate.dstImageRate)
.Append(", toImageRate.srcImageRate: ").Append(toImageRate.srcImageRate) .Append(", toImageRate.srcImageRate: ").Append(toImageRate.srcImageRate)
.Append(", toImageRate.dstImageRate: ").Append(toImageRate.dstImageRate); .Append(", toImageRate.dstImageRate: ").Append(toImageRate.dstImageRate);
DEBUG(sb); Log.D("PollEvent", sb.ToString());
VivePassthroughImageRateChanged.Send(fromImageRate.srcImageRate, fromImageRate.dstImageRate, toImageRate.srcImageRate, toImageRate.dstImageRate); VivePassthroughImageRateChanged.Send(fromImageRate.srcImageRate, fromImageRate.dstImageRate, toImageRate.srcImageRate, toImageRate.dstImageRate);
} }
break; break;
@@ -53,7 +67,7 @@ namespace VIVE.OpenXR
sb.Clear().Append("xrPollEventInterceptor() XR_TYPE_EVENT_DATA_PASSTHROUGH_CONFIGURATION_IMAGE_QUALITY_CHANGED_HTC") sb.Clear().Append("xrPollEventInterceptor() XR_TYPE_EVENT_DATA_PASSTHROUGH_CONFIGURATION_IMAGE_QUALITY_CHANGED_HTC")
.Append(", fromImageQuality: ").Append(fromImageQuality.scale) .Append(", fromImageQuality: ").Append(fromImageQuality.scale)
.Append(", toImageQuality: ").Append(toImageQuality.scale); .Append(", toImageQuality: ").Append(toImageQuality.scale);
DEBUG(sb); Log.D("PollEvent", sb);
VivePassthroughImageQualityChanged.Send(fromImageQuality.scale, toImageQuality.scale); VivePassthroughImageQualityChanged.Send(fromImageQuality.scale, toImageQuality.scale);
} }
break; break;
@@ -65,7 +79,7 @@ namespace VIVE.OpenXR
sb.Clear().Append("xrPollEventInterceptor() XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB") sb.Clear().Append("xrPollEventInterceptor() XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB")
.Append(", fromDisplayRefreshRate: ").Append(fromDisplayRefreshRate) .Append(", fromDisplayRefreshRate: ").Append(fromDisplayRefreshRate)
.Append(", toDisplayRefreshRate: ").Append(toDisplayRefreshRate); .Append(", toDisplayRefreshRate: ").Append(toDisplayRefreshRate);
DEBUG(sb); Log.D("PollEvent", sb);
ViveDisplayRefreshRateChanged.Send(fromDisplayRefreshRate, toDisplayRefreshRate); ViveDisplayRefreshRateChanged.Send(fromDisplayRefreshRate, toDisplayRefreshRate);
} }
break; break;
@@ -87,7 +101,7 @@ namespace VIVE.OpenXR
.Append(", session: ").Append(eventDataSession.session) .Append(", session: ").Append(eventDataSession.session)
.Append(", state: ").Append(eventDataSession.state) .Append(", state: ").Append(eventDataSession.state)
.Append(", isUserPresent: ").Append(isUserPresent); .Append(", isUserPresent: ").Append(isUserPresent);
DEBUG(sb); Log.D("PollEvent", sb);
} }
break; break;
case XrStructureType.XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT: case XrStructureType.XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT:
@@ -97,7 +111,7 @@ namespace VIVE.OpenXR
sb.Clear().Append("xrPollEventInterceptor() XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT") sb.Clear().Append("xrPollEventInterceptor() XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT")
.Append(", session: ").Append(eventDataUserPresence.session) .Append(", session: ").Append(eventDataUserPresence.session)
.Append(", isUserPresent: ").Append(isUserPresent); .Append(", isUserPresent: ").Append(isUserPresent);
DEBUG(sb); Log.D("PollEvent", sb);
} }
break; break;
default: default:
@@ -105,7 +119,7 @@ namespace VIVE.OpenXR
} }
} }
//sb.Clear().Append("xrPollEventInterceptor() xrPollEvent result: ").Append(result).Append(", isUserPresent: ").Append(isUserPresent); DEBUG(sb); //sb.Clear().Append("xrPollEventInterceptor() xrPollEvent result: ").Append(result).Append(", isUserPresent: ").Append(isUserPresent); Log.d("PollEvent", sb);
} }
Profiler.EndSample(); Profiler.EndSample();

View File

@@ -8,6 +8,20 @@ namespace VIVE.OpenXR
{ {
partial class ViveInterceptors partial class ViveInterceptors
{ {
[HookHandler("xrEndFrame")]
private static XrResult OnHookXrEndFrame(XrInstance instance, string name, out IntPtr function)
{
if (XrEndFrameOriginal == null)
{
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret != XrResult.XR_SUCCESS)
return ret;
XrEndFrameOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrEndFrame>(function);
}
function = xrEndFrameInterceptorPtr;
return XrResult.XR_SUCCESS;
}
public struct XrCompositionLayerBaseHeader public struct XrCompositionLayerBaseHeader
{ {
public XrStructureType type; // This base structure itself has no associated XrStructureType value. public XrStructureType type; // This base structure itself has no associated XrStructureType value.
@@ -37,15 +51,16 @@ namespace VIVE.OpenXR
// instance must not null // instance must not null
//if (instance == null) //if (instance == null)
// return XrEndFrameOriginal(session, ref frameEndInfo); // return XrEndFrameOriginal(session, ref frameEndInfo);
Profiler.BeginSample("VI:EndFrame"); Profiler.BeginSample("VI:EndFrameB");
XrResult result = XrResult.XR_SUCCESS; XrResult result = XrResult.XR_SUCCESS;
if (instance.BeforeOriginalEndFrame != null && bool ret = true;
!instance.BeforeOriginalEndFrame(session, ref frameEndInfo, ref result)) if (instance.BeforeOriginalEndFrame != null)
{ ret = instance.BeforeOriginalEndFrame(session, ref frameEndInfo, ref result);
Profiler.EndSample(); Profiler.EndSample();
if (!ret)
return result; return result;
}
result = XrEndFrameOriginal(session, ref frameEndInfo); result = XrEndFrameOriginal(session, ref frameEndInfo);
Profiler.BeginSample("VI:EndFrameA");
instance.AfterOriginalEndFrame?.Invoke(session, ref frameEndInfo, ref result); instance.AfterOriginalEndFrame?.Invoke(session, ref frameEndInfo, ref result);
Profiler.EndSample(); Profiler.EndSample();
return result; return result;

View File

@@ -0,0 +1,91 @@
// Copyright HTC Corporation All Rights Reserved.
using System.Runtime.InteropServices;
using System;
using AOT;
using UnityEngine.Profiling;
namespace VIVE.OpenXR
{
public partial class ViveInterceptors
{
[HookHandler("xrGetVisibilityMaskKHR")]
private static XrResult OnHookXrGetVisibilityMaskKHR(XrInstance instance, string name, out IntPtr function)
{
if (xrGetVisibilityMaskKHROriginal == null)
{
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret != XrResult.XR_SUCCESS)
return ret;
xrGetVisibilityMaskKHROriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrGetVisibilityMaskKHR>(function);
}
function = xrGetVisibilityMaskKHRInterceptorPtr;
return XrResult.XR_SUCCESS;
}
public enum XrVisibilityMaskTypeKHR
{
HIDDEN_TRIANGLE_MESH_KHR = 1,
VISIBLE_TRIANGLE_MESH_KHR = 2,
LINE_LOOP_KHR = 3,
}
public struct XrVisibilityMaskKHR
{
public XrStructureType type;
public IntPtr next;
public uint vertexCapacityInput;
public uint vertexCountOutput;
public IntPtr vertices; // XrVector2f array
public uint indexCapacityInput;
public uint indexCountOutput;
public IntPtr indices; // uint array
}
// XrCompositionLayerSpaceWarpInfoFlagsFB bits
public delegate XrResult DelegateXrGetVisibilityMaskKHR(XrSession session, XrViewConfigurationType viewConfigurationType, uint viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, ref XrVisibilityMaskKHR visibilityMask);
private static readonly DelegateXrGetVisibilityMaskKHR xrGetVisibilityMaskKHRInterceptorHandle = new DelegateXrGetVisibilityMaskKHR(XrGetVisibilityMaskKHRInterceptor);
private static readonly IntPtr xrGetVisibilityMaskKHRInterceptorPtr = Marshal.GetFunctionPointerForDelegate(xrGetVisibilityMaskKHRInterceptorHandle);
static DelegateXrGetVisibilityMaskKHR xrGetVisibilityMaskKHROriginal = null;
[MonoPInvokeCallback(typeof(DelegateXrGetVisibilityMaskKHR))]
private static XrResult XrGetVisibilityMaskKHRInterceptor(XrSession session, XrViewConfigurationType viewConfigurationType, uint viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, ref XrVisibilityMaskKHR visibilityMask)
{
// instance must not null
//if (instance == null)
// return XrGetVisibilityMaskKHROriginal(session, ref frameEndInfo);
Profiler.BeginSample("VI:GetVMB");
XrResult result = XrResult.XR_SUCCESS;
bool ret = true;
if (instance.BeforeOriginalGetVisibilityMaskKHR != null)
ret = instance.BeforeOriginalGetVisibilityMaskKHR(session, viewConfigurationType, viewIndex, visibilityMaskType, ref visibilityMask, ref result);
Profiler.EndSample();
if (!ret)
return result;
result = xrGetVisibilityMaskKHROriginal(session, viewConfigurationType, viewIndex, visibilityMaskType, ref visibilityMask);
Profiler.BeginSample("VI:GetVMA");
instance.AfterOriginalGetVisibilityMaskKHR?.Invoke(session, viewConfigurationType, viewIndex, visibilityMaskType, ref visibilityMask, ref result);
Profiler.EndSample();
return result;
}
/// <summary>
/// If you return false, the original function will not be called.
/// </summary>
/// <param name="session"></param>
/// <param name="frameEndInfo"></param>
/// <param name="result"></param>
/// <returns></returns>
public delegate bool DelegateXrGetVisibilityMaskKHRInterceptor(XrSession session, XrViewConfigurationType viewConfigurationType, uint viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, ref XrVisibilityMaskKHR visibilityMask, ref XrResult result);
/// <summary>
/// Use this to intercept the original function. This will be called before the original function.
/// </summary>
public DelegateXrGetVisibilityMaskKHRInterceptor BeforeOriginalGetVisibilityMaskKHR;
/// <summary>
/// Use this to intercept the original function. This will be called after the original function.
/// </summary>
public DelegateXrGetVisibilityMaskKHRInterceptor AfterOriginalGetVisibilityMaskKHR;
}
}

View File

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

View File

@@ -9,7 +9,20 @@ namespace VIVE.OpenXR
{ {
partial class ViveInterceptors partial class ViveInterceptors
{ {
#region XRWaitFrame [HookHandler("xrWaitFrame")]
private static XrResult OnHookXrWaitFrame(XrInstance instance, string name, out IntPtr function)
{
if (XrWaitFrameOriginal == null)
{
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret != XrResult.XR_SUCCESS)
return ret;
XrWaitFrameOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrWaitFrame>(function);
}
function = xrWaitFrameInterceptorPtr;
return XrResult.XR_SUCCESS;
}
public struct XrFrameWaitInfo public struct XrFrameWaitInfo
{ {
public XrStructureType type; public XrStructureType type;
@@ -103,6 +116,5 @@ namespace VIVE.OpenXR
/// Use this to intercept the original function. This will be called after the original function. /// Use this to intercept the original function. This will be called after the original function.
/// </summary> /// </summary>
public DelegateXrWaitFrameInterceptor AfterOriginalWaitFrame; public DelegateXrWaitFrameInterceptor AfterOriginalWaitFrame;
#endregion XRWaitFrame
} }
} }

View File

@@ -0,0 +1,247 @@
// Copyright HTC Corporation All Rights Reserved.
#if UNITY_ANDROID && !UNITY_EDITOR
using System.Runtime.InteropServices;
#endif
using System.Text;
// Non android will need UnityEngine
using UnityEngine;
namespace VIVE.OpenXR
{
public static class Log
{
public const string TAG = "VIVE.OpenXR";
#if UNITY_ANDROID && !UNITY_EDITOR
[DllImport("liblog.so")]
private static extern int __android_log_print(int prio, string tag, string fmt, string msg);
#endif
// Use ("%s", message) instead of just (message) is because of the following reason:
// In case message contains special characters like %, \n, \r, etc. It will be treated as format string.
// This is a little waste of performance, but it's safer.
/// <summary>
/// Not show in Standalone
/// </summary>
public static void D(string message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(3, TAG, "%s", message); // Android Debug
#endif
}
public static void I(string message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(4, TAG, "%s", message); // Android Info
#else
Debug.Log(message);
#endif
}
public static void W(string message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(5, TAG, "%s", message); // Android Warning
#else
Debug.LogWarning(message);
#endif
}
public static void E(string message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(6, TAG, "%s", message); // Android Error
#else
Debug.LogError(message);
#endif
}
/// <summary>
/// Not show in Standalone
/// </summary>
public static void D(string tag, string message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(3, tag, "%s", message);
#endif
}
public static void I(string tag, string message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(4, tag, "%s", message);
#else
Debug.LogFormat("{0}: {1}", tag, message);
#endif
}
public static void W(string tag, string message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(5, tag, "%s", message); // Android Warning
#else
Debug.LogWarningFormat("{0}: {1}", tag, message);
#endif
}
public static void E(string tag, string message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(6, tag, "%s", message); // Android Error
#else
Debug.LogErrorFormat("{0}: {1}", tag, message);
#endif
}
/// <summary>
/// Not show in Standalone
/// </summary>
public static void D(StringBuilder message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(3, TAG, "%s", message.ToString());
#endif
}
public static void I(StringBuilder message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(4, TAG, "%s", message.ToString());
#else
Debug.Log(message.ToString());
#endif
}
public static void W(StringBuilder message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(5, TAG, "%s", message.ToString()); // Android Warning
#else
Debug.LogWarning(message.ToString());
#endif
}
public static void E(StringBuilder message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(6, TAG, "%s", message.ToString()); // Android Error
#else
Debug.LogError(message.ToString());
#endif
}
/// <summary>
/// Not show in Standalone
/// </summary>
public static void D(string tag, StringBuilder message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(3, tag, "%s", message.ToString());
#endif
}
public static void I(string tag, StringBuilder message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(4, tag, "%s", message.ToString());
#else
Debug.LogFormat("{0}: {1}", tag, message.ToString());
#endif
}
public static void W(string tag, StringBuilder message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(5, tag, "%s", message.ToString()); // Android Warning
#else
Debug.LogWarningFormat("{0}: {1}", tag, message.ToString());
#endif
}
public static void E(string tag, StringBuilder message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(6, tag, "%s", message.ToString()); // Android Error
#else
Debug.LogErrorFormat("{0}: {1}", tag, message.ToString());
#endif
}
/// <summary>
/// Not show in Standalone
/// </summary>
public static void DFmt(string fmt, params object[] args)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(3, TAG, "%s", string.Format(fmt, args));
#endif
}
public static void IFmt(string fmt, params object[] args)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(4, TAG, "%s", string.Format(fmt, args));
#else
Debug.LogFormat(fmt, args);
#endif
}
public static void WFmt(string fmt, params object[] args)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(5, TAG, "%s", string.Format(fmt, args)); // Android Warning
#else
Debug.LogWarningFormat(fmt, args);
#endif
}
public static void EFmt(string fmt, params object[] args)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(6, TAG, "%s", string.Format(fmt, args)); // Android Error
#else
Debug.LogErrorFormat(fmt, args);
#endif
}
/// <summary>
/// Not show in Standalone
/// </summary>
public static void DFmt(string tag, string fmt, params object[] args)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(3, tag, "%s", string.Format(fmt, args));
#endif
}
public static void IFmt(string tag, string fmt, params object[] args)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(4, tag, "%s", string.Format(fmt, args));
#else
Debug.LogFormat("{0}: {1}", tag, string.Format(fmt, args));
#endif
}
public static void WFmt(string tag, string fmt, params object[] args)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(5, tag, "%s", string.Format(fmt, args)); // Android Warning
#else
Debug.LogWarningFormat("{0}: {1}", tag, fmt, string.Format(fmt, args));
#endif
}
public static void EFmt(string tag, string fmt, params object[] args)
{
#if UNITY_ANDROID && !UNITY_EDITOR
__android_log_print(6, tag, "%s", string.Format(fmt, args)); // Android Error
#else
Debug.LogErrorFormat("{0}: {1}", tag, fmt, string.Format(fmt, args));
#endif
}
}
}

View File

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

View File

@@ -58,7 +58,8 @@ namespace VIVE.OpenXR.Common.RenderThread
isFree = true isFree = true
}; };
pool.Insert(index, newItem); pool.Insert(index, newItem);
Debug.Log("RT.MessagePool.Obtain() pool count=" + pool.Count); //Log.d("RT.MessagePool.Obtain<" + typeof(T) + ">() pool count=" + pool.Count); // Not to expose developer's type.
Log.D("RT.MessagePool.Obtain() pool count=" + pool.Count);
return newItem; return newItem;
} }
@@ -101,7 +102,8 @@ namespace VIVE.OpenXR.Common.RenderThread
/// The queueSize should be the double count of message you want to pass to render thread in one frame. /// The queueSize should be the double count of message you want to pass to render thread in one frame.
/// </summary> /// </summary>
/// <param name="queueSize"></param> /// <param name="queueSize"></param>
public PreAllocatedQueue(int queueSize = 2) : base() { public PreAllocatedQueue(int queueSize = 2) : base()
{
for (int i = 0; i < queueSize; i++) for (int i = 0; i < queueSize; i++)
{ {
list.Add(null); list.Add(null);
@@ -221,7 +223,8 @@ namespace VIVE.OpenXR.Common.RenderThread
~RenderThreadTask() ~RenderThreadTask()
{ {
try { CommandList.RemoveAt(id); } finally { } // Remove could be in a random order, and will cause orderId change. DO not remove any of them.
//try { CommandList.Remove(this); } finally { }
} }
void IssuePluginEvent(IntPtr callback, int eventID) void IssuePluginEvent(IntPtr callback, int eventID)
@@ -287,22 +290,28 @@ namespace VIVE.OpenXR.Common.RenderThread
private static void SampleReceiver1(PreAllocatedQueue dataQueue) private static void SampleReceiver1(PreAllocatedQueue dataQueue)
{ {
var msg = dataQueue.Dequeue() as SampleMessage; var msg = dataQueue.Dequeue() as SampleMessage;
// no need to check msg if it is null because your design should avoid it. if (msg != null)
{
// Keep data before release. Use local variable to keep data and release msg early. Should not keep the msg instance itself. // Keep data before release. Use local variable to keep data and release msg early. Should not keep the msg instance itself.
var data = msg.dataPassedToRenderThread; var data = msg.dataPassedToRenderThread;
// Make sure release the msg if finished. Other wise the memory will keep increasing when Obtain. // Make sure release the msg if finished. Other wise the memory will keep increasing when Obtain.
MessagePool.Release(msg); MessagePool.Release(msg);
Debug.Log("Task1, the data passed to render thread: " + data); Debug.Log("Task1, the data passed to render thread: " + data);
} }
}
private static void SampleReceiver2(PreAllocatedQueue dataQueue) private static void SampleReceiver2(PreAllocatedQueue dataQueue)
{ {
var msg = dataQueue.Dequeue() as SampleMessage; var msg = dataQueue.Dequeue() as SampleMessage;
if (msg != null)
{
// Keep data before release. Use local variable to keep data and release msg early. Should not keep the msg instance itself.
var data = msg.dataPassedToRenderThread; var data = msg.dataPassedToRenderThread;
// Make sure release the msg if finished. Other wise the memory will keep increasing when Obtain.
MessagePool.Release(msg); MessagePool.Release(msg);
Debug.Log("Task2, the data passed to render thread: " + data); Debug.Log("Task2, the data passed to render thread: " + data);
} }
}
// Send a message to the render thread every frame. // Send a message to the render thread every frame.
private void Update() private void Update()

View File

@@ -8,6 +8,7 @@ using UnityEngine.XR.OpenXR;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using VIVE.OpenXR.CompositionLayer; using VIVE.OpenXR.CompositionLayer;
using System.Runtime.CompilerServices;
namespace VIVE.OpenXR.CompositionLayer namespace VIVE.OpenXR.CompositionLayer
{ {
@@ -16,15 +17,18 @@ namespace VIVE.OpenXR.CompositionLayer
#if UNITY_EDITOR #if UNITY_EDITOR
[SerializeField] [SerializeField]
public bool isPreviewingCylinder = false; public bool isPreviewingCylinder = false;
public bool isPreviewingEquirect = false;
[SerializeField] [SerializeField]
public bool isPreviewingQuad = false; public bool isPreviewingQuad = false;
[SerializeField] [SerializeField]
public GameObject generatedPreview = null; public GameObject generatedPreview = null;
public const string CylinderPreviewName = "CylinderPreview"; public const string CylinderPreviewName = "CylinderPreview";
public const string EquirectPreviewName = "EquirectPreview";
public const string QuadPreviewName = "QuadPreview"; public const string QuadPreviewName = "QuadPreview";
#endif #endif
public const string CylinderUnderlayMeshName = "Underlay Alpha Mesh (Cylinder)"; public const string CylinderUnderlayMeshName = "Underlay Alpha Mesh (Cylinder)";
public const string EquirectUnderlayMeshName = "Underlay Alpha Mesh (Equirect)";
public const string QuadUnderlayMeshName = "Underlay Alpha Mesh (Quad)"; public const string QuadUnderlayMeshName = "Underlay Alpha Mesh (Quad)";
public const string FallbackMeshName = "FallbackMeshGO"; public const string FallbackMeshName = "FallbackMeshGO";
@@ -56,6 +60,15 @@ namespace VIVE.OpenXR.CompositionLayer
public float QuadHeight { get { return m_QuadHeight; } set { m_QuadHeight = value; } } public float QuadHeight { get { return m_QuadHeight; } set { m_QuadHeight = value; } }
#endif #endif
[SerializeField]
[Min(0.001f)]
private float m_CylinderRadius = 1f;
public float cylinderRadius { get { return m_CylinderRadius; } }
#if UNITY_EDITOR
public float CylinderRadius { get { return m_CylinderRadius; } set { m_CylinderRadius = value; } }
#endif
[SerializeField] [SerializeField]
[Min(0.001f)] [Min(0.001f)]
private float m_CylinderHeight = 1f; private float m_CylinderHeight = 1f;
@@ -74,10 +87,66 @@ namespace VIVE.OpenXR.CompositionLayer
[SerializeField] [SerializeField]
[Min(0.001f)] [Min(0.001f)]
private float m_CylinderRadius = 1f; private float m_EquirectRadius = 1f;
public float cylinderRadius { get { return m_CylinderRadius; } } public float equirectRadius { get { return m_EquirectRadius; } }
#if UNITY_EDITOR #if UNITY_EDITOR
public float CylinderRadius { get { return m_CylinderRadius; } set { m_CylinderRadius = value; } } public float EquirectRadius { get { return m_EquirectRadius; } set { m_EquirectRadius = value; } }
#endif
[SerializeField]
[Range(0.0f, 1.0f)]
private float m_EquirectScaleX = 1.0f;
public float equirectScaleX { get { return m_EquirectScaleX; } }
#if UNITY_EDITOR
public float EquirectScaleX { get { return m_EquirectScaleX; } set { m_EquirectScaleX = value; } }
#endif
[SerializeField]
[Range(0.0f, 1.0f)]
private float m_EquirectScaleY = 1.0f;
public float equirectScaleY { get { return m_EquirectScaleY; } }
#if UNITY_EDITOR
public float EquirectScaleY { get { return m_EquirectScaleY; } set { m_EquirectScaleY = value; } }
#endif
[SerializeField]
[Range(0.0f, 1.0f)]
private float m_EquirectBiasX = 0.0f;
public float equirectBiasX { get { return m_EquirectBiasX; } }
#if UNITY_EDITOR
public float EquirectBiasX { get { return m_EquirectBiasX; } set { m_EquirectBiasX = value; } }
#endif
[SerializeField]
[Range(0.0f, 1.0f)]
private float m_EquirectBiasY = 0.0f;
public float equirectBiasY { get { return m_EquirectBiasY; } }
#if UNITY_EDITOR
public float EquirectBiasY { get { return m_EquirectBiasY; } set { m_EquirectBiasY = value; } }
#endif
[SerializeField]
[Range(0f, 360f)]
private float m_EquirectCentralHorizontalAngle = 360f;
public float equirectCentralHorizontalAngle { get { return m_EquirectCentralHorizontalAngle; } }
#if UNITY_EDITOR
public float EquirectCentralHorizontalAngle { get { return m_EquirectCentralHorizontalAngle; } set { m_EquirectCentralHorizontalAngle = value; } }
#endif
[SerializeField]
[Range(-90f, 90f)]
private float m_EquirectUpperVerticalAngle = 90f;
public float equirectUpperVerticalAngle { get { return m_EquirectUpperVerticalAngle; } }
#if UNITY_EDITOR
public float EquirectUpperVerticalAngle { get { return m_EquirectUpperVerticalAngle; } set { m_EquirectUpperVerticalAngle = value; } }
#endif
[SerializeField]
[Range(-90f, 90f)]
private float m_EquirectLowerVerticalAngle = -90f;
public float equirectLowerVerticalAngle { get { return m_EquirectLowerVerticalAngle; } }
#if UNITY_EDITOR
public float EquirectLowerVerticalAngle { get { return m_EquirectLowerVerticalAngle; } set { m_EquirectLowerVerticalAngle = value; } }
#endif #endif
[SerializeField] [SerializeField]
@@ -171,6 +240,7 @@ namespace VIVE.OpenXR.CompositionLayer
private LayerShape previousLayerShape = LayerShape.Quad; private LayerShape previousLayerShape = LayerShape.Quad;
private float previousQuadWidth = 1f; private float previousQuadWidth = 1f;
private float previousQuadHeight = 1f; private float previousQuadHeight = 1f;
private float previousEquirectRadius = 1f;
private float previousCylinderHeight = 1f; private float previousCylinderHeight = 1f;
private float previousCylinderArcLength = 1f; private float previousCylinderArcLength = 1f;
private float previousCylinderRadius = 1f; private float previousCylinderRadius = 1f;
@@ -192,7 +262,7 @@ namespace VIVE.OpenXR.CompositionLayer
private bool placeholderGenerated = false; private bool placeholderGenerated = false;
private static bool isSynchronized = false; private static bool isSynchronized = false;
private static RenderThreadSynchronizer synchronizer; private static RenderThreadSynchronizer synchronizer;
private Camera hmd; public Camera hmd;
private ViveCompositionLayer compositionLayerFeature = null; private ViveCompositionLayer compositionLayerFeature = null;
@@ -362,6 +432,7 @@ namespace VIVE.OpenXR.CompositionLayer
previousLayerShape = layerShape; previousLayerShape = layerShape;
previousQuadWidth = m_QuadWidth; previousQuadWidth = m_QuadWidth;
previousQuadHeight = m_QuadHeight; previousQuadHeight = m_QuadHeight;
previousEquirectRadius = m_EquirectRadius;
previousCylinderHeight = m_CylinderHeight; previousCylinderHeight = m_CylinderHeight;
previousCylinderArcLength = m_CylinderArcLength; previousCylinderArcLength = m_CylinderArcLength;
previousCylinderRadius = m_CylinderRadius; previousCylinderRadius = m_CylinderRadius;
@@ -690,6 +761,20 @@ namespace VIVE.OpenXR.CompositionLayer
compositionLayerCylinderFeature.Submit_CompositionLayerCylinder(AssignCompositionLayerParamsCylinder(eyeid, botheye), (OpenXR.CompositionLayer.LayerType)layerType, compositionDepth, (eyeid == 0) ? layerID : layerIDRight); compositionLayerCylinderFeature.Submit_CompositionLayerCylinder(AssignCompositionLayerParamsCylinder(eyeid, botheye), (OpenXR.CompositionLayer.LayerType)layerType, compositionDepth, (eyeid == 0) ? layerID : layerIDRight);
} }
break; break;
case LayerShape.Equirect:// TODO added code to submit
ViveCompositionLayerEquirect compositionLayerEquicrectFeature = OpenXRSettings.Instance.GetFeature<ViveCompositionLayerEquirect>();
if (compositionLayerEquicrectFeature != null && compositionLayerEquicrectFeature.EquirectExtensionEnabled)
{
compositionLayerEquicrectFeature.Submit_CompositionLayerEquirect(AssignCompositionLayerParamsEquirect(eyeid), (OpenXR.CompositionLayer.LayerType)layerType, compositionDepth, (eyeid == 0) ? layerID : layerIDRight);
}
break;
case LayerShape.Equirect2:// TODO added code to submit
compositionLayerEquicrectFeature = OpenXRSettings.Instance.GetFeature<ViveCompositionLayerEquirect>();
if (compositionLayerEquicrectFeature != null && compositionLayerEquicrectFeature.Equirect2ExtensionEnabled)
{
compositionLayerEquicrectFeature.Submit_CompositionLayerEquirect2(AssignCompositionLayerParamsEquirect2(eyeid), (OpenXR.CompositionLayer.LayerType)layerType, compositionDepth, (eyeid == 0) ? layerID : layerIDRight);
}
break;
} }
} }
@@ -838,7 +923,7 @@ namespace VIVE.OpenXR.CompositionLayer
else else
{ {
XRInputSubsystem subsystem = null; XRInputSubsystem subsystem = null;
SubsystemManager.GetInstances(inputSubsystems); SubsystemManager.GetSubsystems(inputSubsystems);
if (inputSubsystems.Count > 0) if (inputSubsystems.Count > 0)
{ {
subsystem = inputSubsystems[0]; subsystem = inputSubsystems[0];
@@ -873,6 +958,97 @@ namespace VIVE.OpenXR.CompositionLayer
return CompositionLayerParamsQuad; return CompositionLayerParamsQuad;
} }
XrCompositionLayerEquirectKHR CompositionLayerParamsEquirect = new XrCompositionLayerEquirectKHR();
private XrCompositionLayerEquirectKHR AssignCompositionLayerParamsEquirect(int eyeid)
{
compositionLayerFeature = OpenXRSettings.Instance.GetFeature<ViveCompositionLayer>();
CompositionLayerParamsEquirect.type = XrStructureType.XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR;
CompositionLayerParamsEquirect.layerFlags = ViveCompositionLayerHelper.XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT | ViveCompositionLayerHelper.XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
if (!enabledColorScaleBiasInShader)
{
CompositionLayerParamsEquirect.layerFlags |= ViveCompositionLayerHelper.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
}
CompositionLayerParamsEquirect.subImage.imageRect = layerTextures[eyeid].textureLayout;
CompositionLayerParamsEquirect.subImage.imageArrayIndex = 0;
GetCompositionLayerPose(ref CompositionLayerParamsEquirect.pose); //Update isHeadLock
// HeadLock
CompositionLayerParamsEquirect.space = compositionLayerFeature.HeadLockSpace;
switch (layerVisibility)
{
default:
case Visibility.Both:
CompositionLayerParamsEquirect.eyeVisibility = XrEyeVisibility.XR_EYE_VISIBILITY_BOTH;
break;
case Visibility.Left:
CompositionLayerParamsEquirect.eyeVisibility = XrEyeVisibility.XR_EYE_VISIBILITY_LEFT;
break;
case Visibility.Right:
CompositionLayerParamsEquirect.eyeVisibility = XrEyeVisibility.XR_EYE_VISIBILITY_RIGHT;
break;
}
CompositionLayerParamsEquirect.subImage.imageRect = layerTextures[eyeid].textureLayout;
CompositionLayerParamsEquirect.subImage.imageArrayIndex = 0;
GetCompositionLayerPose(ref CompositionLayerParamsEquirect.pose);
CompositionLayerParamsEquirect.radius = m_EquirectRadius;
CompositionLayerParamsEquirect.scale.x = m_EquirectScaleX;
CompositionLayerParamsEquirect.scale.y = m_EquirectScaleY;
CompositionLayerParamsEquirect.bias.x = m_EquirectBiasX;
CompositionLayerParamsEquirect.bias.y = m_EquirectBiasY;
return CompositionLayerParamsEquirect;
}
XrCompositionLayerEquirect2KHR CompositionLayerParamsEquirect2 = new XrCompositionLayerEquirect2KHR();
private XrCompositionLayerEquirect2KHR AssignCompositionLayerParamsEquirect2(int eyeid)
{
compositionLayerFeature = OpenXRSettings.Instance.GetFeature<ViveCompositionLayer>();
CompositionLayerParamsEquirect2.type = XrStructureType.XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR;
CompositionLayerParamsEquirect2.layerFlags = ViveCompositionLayerHelper.XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT | ViveCompositionLayerHelper.XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
if (!enabledColorScaleBiasInShader)
{
CompositionLayerParamsEquirect2.layerFlags |= ViveCompositionLayerHelper.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
}
CompositionLayerParamsEquirect2.subImage.imageRect = layerTextures[eyeid].textureLayout;
CompositionLayerParamsEquirect2.subImage.imageArrayIndex = 0;
GetCompositionLayerPose(ref CompositionLayerParamsEquirect2.pose); //Update isHeadLock
// HeadLock
CompositionLayerParamsEquirect2.space = compositionLayerFeature.HeadLockSpace;
switch (layerVisibility)
{
default:
case Visibility.Both:
CompositionLayerParamsEquirect2.eyeVisibility = XrEyeVisibility.XR_EYE_VISIBILITY_BOTH;
break;
case Visibility.Left:
CompositionLayerParamsEquirect2.eyeVisibility = XrEyeVisibility.XR_EYE_VISIBILITY_LEFT;
break;
case Visibility.Right:
CompositionLayerParamsEquirect2.eyeVisibility = XrEyeVisibility.XR_EYE_VISIBILITY_RIGHT;
break;
}
CompositionLayerParamsEquirect2.subImage.imageRect = layerTextures[eyeid].textureLayout;
CompositionLayerParamsEquirect2.subImage.imageArrayIndex = 0;
GetCompositionLayerPose(ref CompositionLayerParamsEquirect2.pose);
CompositionLayerParamsEquirect2.radius = m_EquirectRadius;
CompositionLayerParamsEquirect2.centralHorizontalAngle = Mathf.Deg2Rad * m_EquirectCentralHorizontalAngle;
CompositionLayerParamsEquirect2.upperVerticalAngle = Mathf.Deg2Rad * m_EquirectUpperVerticalAngle;
CompositionLayerParamsEquirect2.lowerVerticalAngle = Mathf.Deg2Rad * m_EquirectLowerVerticalAngle;
return CompositionLayerParamsEquirect2;
}
XrCompositionLayerCylinderKHR CompositionLayerParamsCylinder = new XrCompositionLayerCylinderKHR(); XrCompositionLayerCylinderKHR CompositionLayerParamsCylinder = new XrCompositionLayerCylinderKHR();
private XrCompositionLayerCylinderKHR AssignCompositionLayerParamsCylinder(int eyeid, bool botheye) private XrCompositionLayerCylinderKHR AssignCompositionLayerParamsCylinder(int eyeid, bool botheye)
{ {
@@ -893,7 +1069,7 @@ namespace VIVE.OpenXR.CompositionLayer
else else
{ {
XRInputSubsystem subsystem = null; XRInputSubsystem subsystem = null;
SubsystemManager.GetInstances(inputSubsystems); SubsystemManager.GetSubsystems(inputSubsystems);
if (inputSubsystems.Count > 0) if (inputSubsystems.Count > 0)
{ {
subsystem = inputSubsystems[0]; subsystem = inputSubsystems[0];
@@ -1122,7 +1298,15 @@ namespace VIVE.OpenXR.CompositionLayer
{ {
bool isChanged = false; bool isChanged = false;
if (layerShape == LayerShape.Cylinder) if (layerShape == LayerShape.Equirect)
{
if (previousEquirectRadius != m_EquirectRadius)
{
previousEquirectRadius = m_EquirectRadius;
isChanged = true;
}
}
else if (layerShape == LayerShape.Cylinder)
{ {
if (previousAngleOfArc != m_CylinderAngleOfArc || if (previousAngleOfArc != m_CylinderAngleOfArc ||
previousCylinderArcLength != m_CylinderArcLength || previousCylinderArcLength != m_CylinderArcLength ||
@@ -1583,6 +1767,9 @@ namespace VIVE.OpenXR.CompositionLayer
case LayerShape.Cylinder: case LayerShape.Cylinder:
generatedMesh = MeshGenerationHelper.GenerateCylinderMesh(m_CylinderAngleOfArc, MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight)); generatedMesh = MeshGenerationHelper.GenerateCylinderMesh(m_CylinderAngleOfArc, MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight));
break; break;
case LayerShape.Equirect:
generatedMesh = MeshGenerationHelper.GenerateEquirectMesh(hmd, m_EquirectRadius);
break;
} }
generatedFallbackMesh = new GameObject(); generatedFallbackMesh = new GameObject();
@@ -1622,6 +1809,9 @@ namespace VIVE.OpenXR.CompositionLayer
case LayerShape.Cylinder: case LayerShape.Cylinder:
generatedMesh = MeshGenerationHelper.GenerateCylinderMesh(m_CylinderAngleOfArc, MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight)); generatedMesh = MeshGenerationHelper.GenerateCylinderMesh(m_CylinderAngleOfArc, MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight));
break; break;
case LayerShape.Equirect:
generatedMesh = MeshGenerationHelper.GenerateEquirectMesh(hmd, m_EquirectRadius);
break;
} }
generatedFallbackMesh.transform.localScale = GetNormalizedLocalScale(transform, Vector3.one); generatedFallbackMesh.transform.localScale = GetNormalizedLocalScale(transform, Vector3.one);
@@ -1657,6 +1847,26 @@ namespace VIVE.OpenXR.CompositionLayer
switch (layerShape) switch (layerShape)
{ {
case LayerShape.Equirect:
generatedUnderlayMesh = new GameObject();
generatedUnderlayMesh.name = EquirectUnderlayMeshName;
generatedUnderlayMesh.transform.SetParent(transform);
generatedUnderlayMesh.transform.localPosition = Vector3.zero;
generatedUnderlayMesh.transform.localRotation = Quaternion.identity;
generatedUnderlayMesh.transform.localScale = GetNormalizedLocalScale(transform, Vector3.one);
generatedUnderlayMeshRenderer = generatedUnderlayMesh.AddComponent<MeshRenderer>();
generatedUnderlayMeshFilter = generatedUnderlayMesh.AddComponent<MeshFilter>();
if (solidEffect)
generatedUnderlayMeshRenderer.sharedMaterial = new Material(Shader.Find("VIVE/OpenXR/CompositionLayer/UnderlayAlphaZeroSolid"));
else
generatedUnderlayMeshRenderer.sharedMaterial = new Material(Shader.Find("VIVE/OpenXR/CompositionLayer/UnderlayAlphaZero"));
generatedUnderlayMeshRenderer.material.mainTexture = texture;
//Generate Mesh
generatedUnderlayMeshFilter.mesh = MeshGenerationHelper.GenerateEquirectMesh(hmd, m_EquirectRadius);
break;
case LayerShape.Cylinder: case LayerShape.Cylinder:
//Generate vertices //Generate vertices
Vector3[] cylinderVertices = MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight); Vector3[] cylinderVertices = MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight);
@@ -1718,6 +1928,10 @@ namespace VIVE.OpenXR.CompositionLayer
switch (layerShape) switch (layerShape)
{ {
case LayerShape.Equirect:
Destroy(generatedUnderlayMeshFilter.mesh);
generatedUnderlayMeshFilter.mesh = MeshGenerationHelper.GenerateEquirectMesh(hmd, m_EquirectRadius);
break;
case LayerShape.Cylinder: case LayerShape.Cylinder:
//Generate vertices //Generate vertices
Vector3[] cylinderVertices = MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight); Vector3[] cylinderVertices = MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight);
@@ -1774,6 +1988,8 @@ namespace VIVE.OpenXR.CompositionLayer
{ {
Quad = 0, Quad = 0,
Cylinder = 1, Cylinder = 1,
Equirect = 2,
Equirect2 = 3,
} }
public enum Visibility public enum Visibility
@@ -2040,6 +2256,92 @@ namespace VIVE.OpenXR.CompositionLayer
return vertices; return vertices;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector3 InverseTransformVert(in Vector3 vert, in Vector3 position, in Vector3 scale, float worldScale)
{
return new Vector3(
(worldScale * vert.x - position.x) / scale.x,
(worldScale * vert.y - position.y) / scale.y,
(worldScale * vert.z - position.z) / scale.z);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector2 GetSphereUV(float theta, float phi, float expandScale)
{
float thetaU = expandScale * (theta / (2 * Mathf.PI) - 0.5f) + 0.5f;
float phiV = expandScale * phi / Mathf.PI + 0.5f;
return new Vector2(thetaU, phiV);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector3 GetSphereVert(float theta, float phi)
{
return new Vector3(-Mathf.Sin(theta) * Mathf.Cos(phi), Mathf.Sin(phi), -Mathf.Cos(theta) * Mathf.Cos(phi));
}
public static void BuildSphere(List<Vector3> verts, List<Vector2> uv, List<int> triangles, Vector3 position,
Quaternion rotation, Vector3 scale, Rect rect, float worldScale = 800, int latitudes = 128,
int longitudes = 128, float expandCoefficient = 1.0f)
{
position = Quaternion.Inverse(rotation) * position;
latitudes = Mathf.CeilToInt(latitudes * rect.height);
longitudes = Mathf.CeilToInt(longitudes * rect.width);
float minTheta = Mathf.PI * 2.0f * rect.x;
float minPhi = Mathf.PI * (0.5f - rect.y - rect.height);
float thetaScale = Mathf.PI * 2.0f * rect.width / longitudes;
float phiScale = Mathf.PI * rect.height / latitudes;
float expandScale = 1.0f / expandCoefficient;
for (int j = 0; j < latitudes + 1; j += 1)
{
for (int k = 0; k < longitudes + 1; k++)
{
float theta = minTheta + k * thetaScale;
float phi = minPhi + j * phiScale;
Vector2 suv = GetSphereUV(theta, phi, expandScale);
uv.Add(new Vector2((suv.x - rect.x) / rect.width, (suv.y - rect.y) / rect.height));
Vector3 vert = GetSphereVert(theta, phi);
verts.Add(InverseTransformVert(in vert, in position, in scale, worldScale));
}
}
for (int j = 0; j < latitudes; j++)
{
for (int k = 0; k < longitudes; k++)
{
triangles.Add(j * (longitudes + 1) + k);
triangles.Add((j + 1) * (longitudes + 1) + k);
triangles.Add((j + 1) * (longitudes + 1) + k + 1);
triangles.Add((j + 1) * (longitudes + 1) + k + 1);
triangles.Add(j * (longitudes + 1) + k + 1);
triangles.Add(j * (longitudes + 1) + k);
}
}
}
public static Mesh GenerateEquirectMesh(Camera hmd, float equirectRadius)
{
Mesh eqicrectMesh = new Mesh();
List<int> _Tris = new List<int>();
List<Vector2> _UV = new List<Vector2>();
List<Vector3> _Verts = new List<Vector3>();
Rect _Rect = new Rect(0, 0, 1, 1);
BuildSphere(_Verts, _UV, _Tris, Camera.main.transform.position, Camera.main.transform.rotation, equirectRadius* Vector3.one, _Rect);
eqicrectMesh.SetVertices(_Verts);
eqicrectMesh.SetTriangles(_Tris, 0);
eqicrectMesh.SetUVs(0, _UV);
eqicrectMesh.UploadMeshData(false);
return eqicrectMesh;
}
public static Mesh GenerateCylinderMesh(float cylinderAngleOfArc, Vector3[] vertices) public static Mesh GenerateCylinderMesh(float cylinderAngleOfArc, Vector3[] vertices)
{ {
Mesh cylinderMesh = new Mesh(); Mesh cylinderMesh = new Mesh();

View File

@@ -75,7 +75,7 @@ namespace VIVE.OpenXR.Editor.Interaction
boxStyleWarning); boxStyleWarning);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
EditorGUILayout.PropertyField(m_ViveXRTracker); EditorGUILayout.PropertyField(m_ViveXRTracker);
/*
#if UNITY_ANDROID #if UNITY_ANDROID
// ViveHandInteractionExt // ViveHandInteractionExt
GUILayout.Space(20); GUILayout.Space(20);
@@ -88,6 +88,7 @@ namespace VIVE.OpenXR.Editor.Interaction
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
EditorGUILayout.PropertyField(m_KHRHandInteraction); EditorGUILayout.PropertyField(m_KHRHandInteraction);
#endif #endif
*/
#endregion #endregion
ViveInteractions myScript = target as ViveInteractions; ViveInteractions myScript = target as ViveInteractions;
@@ -96,7 +97,7 @@ namespace VIVE.OpenXR.Editor.Interaction
bool viveHandInteraction = myScript.UseViveHandInteraction(); bool viveHandInteraction = myScript.UseViveHandInteraction();
bool viveWristTracker = myScript.UseViveWristTracker(); bool viveWristTracker = myScript.UseViveWristTracker();
bool viveXrTracker = myScript.UseViveXrTracker(); bool viveXrTracker = myScript.UseViveXrTracker();
bool khrHandInteraction = myScript.UseKhrHandInteraction(); //bool khrHandInteraction = myScript.UseKhrHandInteraction();
OpenXRSettings settings = null; OpenXRSettings settings = null;
#if UNITY_ANDROID #if UNITY_ANDROID
@@ -116,7 +117,7 @@ namespace VIVE.OpenXR.Editor.Interaction
feature.enabled = viveXrTracker; feature.enabled = viveXrTracker;
addPathEnumeration = viveXrTracker; addPathEnumeration = viveXrTracker;
} }
if (feature is Hand.ViveHandInteractionExt) { feature.enabled = khrHandInteraction; } //if (feature is Hand.ViveHandInteractionExt) { feature.enabled = khrHandInteraction; }
} }
foreach (var feature in settings.GetFeatures<OpenXRFeature>()) foreach (var feature in settings.GetFeatures<OpenXRFeature>())

View File

@@ -0,0 +1,120 @@
// Copyright HTC Corporation All Rights Reserved.
using System.Collections.Generic;
using UnityEditor;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using AOT;
using UnityEngine;
using System;
using System.Runtime.InteropServices;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
namespace VIVE.OpenXR.CompositionLayer
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "VIVE XR Composition Layer (Equirect)",
Desc = "Enable this feature to enable the Composition Layer Equirect Extension",
Company = "HTC",
DocumentationLink = "..\\Documentation",
OpenxrExtensionStrings = kOpenXRCylinderExtensionString,
Version = "1.0.0",
BuildTargetGroups = new[] { BuildTargetGroup.Android },
FeatureId = featureId
)]
#endif
public class ViveCompositionLayerEquirect : OpenXRFeature
{
const string LOG_TAG = "VIVE.OpenXR.ViveCompositionLayer.Equirect";
static void DEBUG(string msg) { Debug.Log(LOG_TAG + " " + msg); }
static void WARNING(string msg) { Debug.LogWarning(LOG_TAG + " " + msg); }
static void ERROR(string msg) { Debug.LogError(LOG_TAG + " " + msg); }
/// <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.compositionlayer.equirect";
private const string kOpenXRCylinderExtensionString = "XR_KHR_composition_layer_equirect XR_KHR_composition_layer_equirect2";
private bool m_EquirectExtensionEnabled = true;
/// <summary>
/// The extension "XR_KHR_composition_layer_equirect" is enabled or not.
/// </summary>
public bool EquirectExtensionEnabled
{
get { return m_EquirectExtensionEnabled; }
}
private bool m_Equirect2ExtensionEnabled = true;
/// <summary>
/// The extension "XR_KHR_composition_layer_equirect2" is enabled or not.
/// </summary>
public bool Equirect2ExtensionEnabled
{
get { return m_Equirect2ExtensionEnabled; }
}
#region OpenXR Life Cycle
protected override bool OnInstanceCreate(ulong xrInstance)
{
if (!OpenXRRuntime.IsExtensionEnabled("XR_KHR_composition_layer_equirect"))
{
WARNING("OnInstanceCreate() " + "XR_KHR_composition_layer_equirect" + " is NOT enabled.");
m_EquirectExtensionEnabled = false;
return false;
}
if (!OpenXRRuntime.IsExtensionEnabled("XR_KHR_composition_layer_equirect2"))
{
WARNING("OnInstanceCreate() " + "XR_KHR_composition_layer_equirect2" + " is NOT enabled.");
m_Equirect2ExtensionEnabled = false;
return false;
}
return true;
}
#endregion
#region Wrapper Functions
private const string ExtLib = "viveopenxr";
[DllImportAttribute(ExtLib, EntryPoint = "submit_CompositionLayerEquirect")]
public static extern void VIVEOpenXR_Submit_CompositionLayerEquirect(XrCompositionLayerEquirectKHR equirect, LayerType layerType, uint compositionDepth, int layerID);
/// <summary>
/// submit compostion layer of type equirect.
/// </summary>
public void Submit_CompositionLayerEquirect(XrCompositionLayerEquirectKHR equirect, LayerType layerType, uint compositionDepth, int layerID)
{
if (!EquirectExtensionEnabled)
{
ERROR("Submit_CompositionLayerEquirect: " + "XR_KHR_composition_layer_equirect" + " is NOT enabled.");
}
VIVEOpenXR_Submit_CompositionLayerEquirect(equirect, layerType, compositionDepth, layerID);
}
[DllImportAttribute(ExtLib, EntryPoint = "submit_CompositionLayerEquirect2")]
public static extern void VIVEOpenXR_Submit_CompositionLayerEquirect2(XrCompositionLayerEquirect2KHR equirect2, LayerType layerType, uint compositionDepth, int layerID);
/// <summary>
/// submit compostion layer of type equirect2.
/// </summary>
public void Submit_CompositionLayerEquirect2(XrCompositionLayerEquirect2KHR equirect2, LayerType layerType, uint compositionDepth, int layerID)
{
if (!Equirect2ExtensionEnabled)
{
ERROR("Submit_CompositionLayerEquirect2: " + "XR_KHR_composition_layer_equirect2" + " is NOT enabled.");
}
VIVEOpenXR_Submit_CompositionLayerEquirect2(equirect2, layerType, compositionDepth, layerID);
}
#endregion
}
}

View File

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

View File

@@ -215,6 +215,35 @@ namespace VIVE.OpenXR.CompositionLayer
public float aspectRatio; public float aspectRatio;
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct XrCompositionLayerEquirectKHR
{
public XrStructureType type;
public IntPtr next;
public XrCompositionLayerFlags layerFlags;
public XrSpace space;
public XrEyeVisibility eyeVisibility;
public XrSwapchainSubImage subImage;
public XrPosef pose;
public float radius;
public XrVector2f scale;
public XrVector2f bias;
}
[StructLayout(LayoutKind.Sequential)]
public struct XrCompositionLayerEquirect2KHR
{
public XrStructureType type;
public IntPtr next;
public XrCompositionLayerFlags layerFlags;
public XrSpace space;
public XrEyeVisibility eyeVisibility;
public XrSwapchainSubImage subImage;
public XrPosef pose;
public float radius;
public float centralHorizontalAngle;
public float upperVerticalAngle;
public float lowerVerticalAngle;
}
[StructLayout(LayoutKind.Sequential)]
public struct XrSwapchainSubImage public struct XrSwapchainSubImage
{ {
public XrSwapchain swapchain; public XrSwapchain swapchain;

View File

@@ -1,7 +1,6 @@
# 12.1. XR_HTC_frame_synchronization # 12.1. XR_HTC_frame_synchronization
## Overview ## Overview
Traditional, runtime will use the latest frame which will cost jitter. With Frame Synchronization, the render frame will not be discarded for smooth gameplay experience. The application frame loop relies on xrWaitFrame throttling to synchronize application frame submissions with the display. This extension allows the application to set the frame synchronization mode to adjust the interval between the application frame submission time and the corresponding display time according to the demand of the application. The runtime will return the appropriate XrFrameState::predictedDisplayTime returned by xrWaitFrame to throttle the frame loop approaching to the frame rendering time of the application with the consistent good user experience throughout the session.
However, if the GPU cannot consistently finish rendering on time (rendering more than one vsync at a time), jitter will still occur. Therefore, reducing GPU load is key to smooth gameplay.
## Name String ## Name String
XR_HTC_frame_synchronization XR_HTC_frame_synchronization
## Revision ## Revision

View File

@@ -11,6 +11,7 @@ using UnityEngine.InputSystem;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine.XR; using UnityEngine.XR;
using UnityEngine.XR.OpenXR.Input; using UnityEngine.XR.OpenXR.Input;
using System;
using System.Text; using System.Text;
#if UNITY_EDITOR #if UNITY_EDITOR
@@ -30,7 +31,7 @@ namespace VIVE.OpenXR.Hand
/// This <see cref="OpenXRInteractionFeature"/> enables the use of hand interaction profiles in OpenXR. It enables <see cref="ViveHandInteractionExt.kOpenxrExtensionString">XR_EXT_hand_interaction</see> in the underyling runtime. /// This <see cref="OpenXRInteractionFeature"/> enables the use of hand interaction profiles in OpenXR. It enables <see cref="ViveHandInteractionExt.kOpenxrExtensionString">XR_EXT_hand_interaction</see> in the underyling runtime.
/// </summary> /// </summary>
#if UNITY_EDITOR #if UNITY_EDITOR
[OpenXRFeature(UiName = "VIVE XR Hand Interaction Ext", [OpenXRFeature(UiName = "VIVE XR Hand Interaction Ext (Deprecated)",
Hidden = true, Hidden = true,
BuildTargetGroups = new[] { BuildTargetGroup.Android }, BuildTargetGroups = new[] { BuildTargetGroup.Android },
Company = "HTC", Company = "HTC",
@@ -41,6 +42,7 @@ namespace VIVE.OpenXR.Hand
Category = FeatureCategory.Interaction, Category = FeatureCategory.Interaction,
FeatureId = featureId)] FeatureId = featureId)]
#endif #endif
[Obsolete("This class is deprecated. Please use Unity Hand Interaction Profile instead.")]
public class ViveHandInteractionExt : OpenXRInteractionFeature public class ViveHandInteractionExt : OpenXRInteractionFeature
{ {
#region Log #region Log

View File

@@ -0,0 +1,458 @@
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.OpenXR;
using VIVE.OpenXR.Interaction;
#if UNITY_XR_HANDS
using UnityEngine.XR.Hands;
using UnityEngine.XR.Hands.ProviderImplementation;
namespace VIVE.OpenXR.Hand
{
public class ViveHandProvider : XRHandSubsystemProvider
{
#region Hand Interaction
private const string kFeatureAimPos = "PointerPosition";
private const string kFeatureAimRot = "PointerRotation";
private const string kFeatureAimValue = "PointerActivateValue";
private const string kFeatureGripPos = "DevicePosition";
private const string kFeatureGripRot = "DeviceRotation";
private const string kFeatureGripValue = "GraspValue";
private const string kFeaturePinchPos = "PinchPosition";
private const string kFeaturePinchRot = "PinchRotation";
private const string kFeaturePinchValue = "PinchValue";
private const string kFeaturePokePos = "PokePosition";
private const string kFeaturePokeRot = "PokeRotation";
private class HandDevice
{
public Pose aimPose => m_AimPose;
public Pose gripPose => m_GripPose;
public Pose pinchPose => m_PinchPose;
public Pose pokePose => m_PokePose;
public float aimActivateValue => m_AimActivateValue;
public float graspValue => m_GraspValue;
public float pinchValue => m_PinchValue;
private Pose m_AimPose = Pose.identity;
private Pose m_GripPose = Pose.identity;
private Pose m_PinchPose = Pose.identity;
private Pose m_PokePose = Pose.identity;
private float m_AimActivateValue = 0;
private float m_GraspValue = 0;
private float m_PinchValue = 0;
private InputDevice device = default(InputDevice);
private Dictionary<string, InputFeatureUsage<Vector3>> posUsageMapping = new Dictionary<string, InputFeatureUsage<Vector3>>();
private Dictionary<string, InputFeatureUsage<Quaternion>> rotUsageMapping = new Dictionary<string, InputFeatureUsage<Quaternion>>();
private Dictionary<string, InputFeatureUsage<float>> valueUsageMapping = new Dictionary<string, InputFeatureUsage<float>>();
public HandDevice(InputDevice device)
{
this.device = device;
List<InputFeatureUsage> inputFeatures = new List<InputFeatureUsage>();
device.TryGetFeatureUsages(inputFeatures);
for (int i = 0; i < inputFeatures.Count; i++)
{
InputFeatureUsage feature = inputFeatures[i];
switch (feature.name)
{
case kFeatureAimPos:
case kFeatureGripPos:
case kFeaturePinchPos:
case kFeaturePokePos:
posUsageMapping.Add(feature.name, feature.As<Vector3>());
break;
case kFeatureAimRot:
case kFeatureGripRot:
case kFeaturePinchRot:
case kFeaturePokeRot:
rotUsageMapping.Add(feature.name, feature.As<Quaternion>());
break;
case kFeatureAimValue:
case kFeatureGripValue:
case kFeaturePinchValue:
valueUsageMapping.Add(feature.name, feature.As<float>());
break;
default:
break;
}
}
}
public void UpdateInputValue()
{
UpdatePosition();
UpdateRotation();
UpdateValue();
}
private void UpdatePosition()
{
var enumerator = posUsageMapping.GetEnumerator();
while (enumerator.MoveNext())
{
var feature = enumerator.Current;
string featureName = feature.Key;
InputFeatureUsage<Vector3> featureUsage = feature.Value;
if (device.TryGetFeatureValue(featureUsage, out Vector3 position))
{
switch (featureName)
{
case kFeatureAimPos:
m_AimPose.position = position;
break;
case kFeatureGripPos:
m_GripPose.position = position;
break;
case kFeaturePinchPos:
m_PinchPose.position = position;
break;
case kFeaturePokePos:
m_PokePose.position = position;
break;
}
}
}
}
private void UpdateRotation()
{
var enumerator = rotUsageMapping.GetEnumerator();
while (enumerator.MoveNext())
{
var feature = enumerator.Current;
string featureName = feature.Key;
InputFeatureUsage<Quaternion> featureUsage = feature.Value;
if (device.TryGetFeatureValue(featureUsage, out Quaternion rotation))
{
switch (featureName)
{
case kFeatureAimRot:
m_AimPose.rotation = rotation;
break;
case kFeatureGripRot:
m_GripPose.rotation = rotation;
break;
case kFeaturePinchRot:
m_PinchPose.rotation = rotation;
break;
case kFeaturePokeRot:
m_PokePose.rotation = rotation;
break;
}
}
}
}
private void UpdateValue()
{
var enumerator = valueUsageMapping.GetEnumerator();
while (enumerator.MoveNext())
{
var feature = enumerator.Current;
string featureName = feature.Key;
InputFeatureUsage<float> featureUsage = feature.Value;
if (device.TryGetFeatureValue(featureUsage, out float value))
{
switch (featureName)
{
case kFeatureAimValue:
m_AimActivateValue = value;
break;
case kFeatureGripValue:
m_GraspValue = value;
break;
case kFeaturePinchValue:
m_PinchValue = value;
break;
}
}
}
}
}
private static HandDevice leftHandDevice = null;
private static HandDevice rightHandDevice = null;
private const string kInteractionDeviceName = "Vive Hand Interaction Ext OpenXR";
#endregion
private ViveHandTracking viveHand;
public override void Destroy() { }
public override void GetHandLayout(NativeArray<bool> handJointsInLayout)
{
handJointsInLayout[XRHandJointID.Palm.ToIndex()] = true;
handJointsInLayout[XRHandJointID.Wrist.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleTip.ToIndex()] = true;
}
public override void Start()
{
Initialize();
#if UNITY_XR_HANDS_1_5_0
InitHandInteractionDevices();
InputDevices.deviceConnected += DeviceConnected;
InputDevices.deviceDisconnected += DeviceDisconnected;
#endif
}
public override void Stop()
{
#if UNITY_XR_HANDS_1_5_0
InputDevices.deviceConnected -= DeviceConnected;
InputDevices.deviceDisconnected -= DeviceDisconnected;
#endif
}
public override XRHandSubsystem.UpdateSuccessFlags TryUpdateHands(XRHandSubsystem.UpdateType updateType, ref Pose leftHandRootPose, NativeArray<XRHandJoint> leftHandJoints, ref Pose rightHandRootPose, NativeArray<XRHandJoint> rightHandJoints)
{
XRHandSubsystem.UpdateSuccessFlags flags = XRHandSubsystem.UpdateSuccessFlags.None;
if (UpdateHand(true, ref leftHandRootPose, ref leftHandJoints))
{
flags |= XRHandSubsystem.UpdateSuccessFlags.LeftHandRootPose | XRHandSubsystem.UpdateSuccessFlags.LeftHandJoints;
}
if (UpdateHand(false, ref rightHandRootPose, ref rightHandJoints))
{
flags |= XRHandSubsystem.UpdateSuccessFlags.RightHandRootPose | XRHandSubsystem.UpdateSuccessFlags.RightHandJoints;
}
#if UNITY_XR_HANDS_1_5_0
if (updateType == XRHandSubsystem.UpdateType.Dynamic && canSurfaceCommonPoseData)
{
UpdateHandInteraction();
}
#endif
return flags;
}
#if UNITY_XR_HANDS_1_5_0
public override bool canSurfaceCommonPoseData => HandInteractionSupport();
public override bool TryGetAimPose(Handedness handedness, out Pose aimPose)
{
aimPose = Pose.identity;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
aimPose = handDevice.aimPose;
return true;
}
return false;
}
public override bool TryGetAimActivateValue(Handedness handedness, out float aimActivateValue)
{
aimActivateValue = 0;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
aimActivateValue = handDevice.aimActivateValue;
return true;
}
return false;
}
public override bool TryGetGripPose(Handedness handedness, out Pose gripPose)
{
gripPose = Pose.identity;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
gripPose = handDevice.gripPose;
return true;
}
return false;
}
public override bool TryGetGraspValue(Handedness handedness, out float graspValue)
{
graspValue = 0;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
graspValue = handDevice.graspValue;
return true;
}
return false;
}
public override bool TryGetPinchPose(Handedness handedness, out Pose pinchPose)
{
pinchPose = Pose.identity;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
pinchPose = handDevice.pinchPose;
return true;
}
return false;
}
public override bool TryGetPinchValue(Handedness handedness, out float pinchValue)
{
pinchValue = 0;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
pinchValue = handDevice.pinchValue;
return true;
}
return false;
}
public override bool TryGetPokePose(Handedness handedness, out Pose pokePose)
{
pokePose = Pose.identity;
HandDevice handDevice = GetHandDevice(handedness);
if (handDevice != null)
{
pokePose = handDevice.pokePose;
return true;
}
return false;
}
private void DeviceConnected(InputDevice inputDevice)
{
if (inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Left) &&
inputDevice.name == kInteractionDeviceName)
{
leftHandDevice = new HandDevice(inputDevice);
}
if (inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Right) &&
inputDevice.name == kInteractionDeviceName)
{
rightHandDevice = new HandDevice(inputDevice);
}
}
private void DeviceDisconnected(InputDevice inputDevice)
{
if (inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Left) &&
inputDevice.name == kInteractionDeviceName)
{
leftHandDevice = default;
}
if (inputDevice.characteristics.HasFlag(InputDeviceCharacteristics.Right) &&
inputDevice.name == kInteractionDeviceName)
{
rightHandDevice = default;
}
}
private void InitHandInteractionDevices()
{
List<InputDevice> inputDevices = new List<InputDevice>();
InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.HeldInHand |
InputDeviceCharacteristics.HandTracking |
InputDeviceCharacteristics.TrackedDevice, inputDevices);
for (int i = 0; i < inputDevices.Count; i++)
{
InputDevice inputDevice = inputDevices[i];
DeviceConnected(inputDevice);
}
}
private void UpdateHandInteraction()
{
if (leftHandDevice != null)
{
leftHandDevice.UpdateInputValue();
}
if (rightHandDevice != null)
{
rightHandDevice.UpdateInputValue();
}
}
private HandDevice GetHandDevice(Handedness handedness) => handedness == Handedness.Left ? leftHandDevice : rightHandDevice;
private bool HandInteractionSupport()
{
ViveInteractions viveInteractions = OpenXRSettings.Instance.GetFeature<ViveInteractions>();
if (viveInteractions.enabled)
{
return viveInteractions.UseKhrHandInteraction();
}
return false;
}
#endif
private void Initialize()
{
viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
}
private bool UpdateHand(bool isLeft, ref Pose handRootPose, ref NativeArray<XRHandJoint> handJoints)
{
if (!viveHand) { return false; }
bool isValid = viveHand.GetJointLocations(isLeft, out XrHandJointLocationEXT[] viveJoints);
Handedness handedness = isLeft ? Handedness.Left : Handedness.Right;
XRHandJointTrackingState trackingState = XRHandJointTrackingState.None;
for (int jointIndex = XRHandJointID.BeginMarker.ToIndex(); jointIndex < XRHandJointID.EndMarker.ToIndex(); ++jointIndex)
{
XRHandJointID jointID = XRHandJointIDUtility.FromIndex(jointIndex);
int viveIndex = XRHandJointIDToIndex(jointID);
Pose pose = Pose.identity;
if (isValid)
{
pose.position = viveJoints[viveIndex].pose.position.ToUnityVector();
pose.rotation = viveJoints[viveIndex].pose.orientation.ToUnityQuaternion();
trackingState = XRHandJointTrackingState.Pose;
}
handJoints[jointIndex] = XRHandProviderUtility.CreateJoint(handedness, trackingState, jointID, pose);
}
handJoints[XRHandJointID.Wrist.ToIndex()].TryGetPose(out handRootPose);
return isValid;
}
private int XRHandJointIDToIndex(XRHandJointID id)
{
switch (id)
{
case XRHandJointID.Palm:
return 0;
case XRHandJointID.Wrist:
return 1;
default:
return (int)id - 1;
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,102 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using VIVE.OpenXR.Interaction;
#if UNITY_XR_HANDS
using UnityEngine.XR.Hands;
using UnityEngine.XR.Hands.ProviderImplementation;
namespace VIVE.OpenXR.Hand
{
public class ViveHandSubsystem : XRHandSubsystem
{
public const string featureId = "vive.openxr.feature.xrhandsubsystem";
private static XRHandSubsystem subsystem = null;
private XRHandProviderUtility.SubsystemUpdater subsystemUpdater = null;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void RegisterDescriptor()
{
if (!ViveHandTrackingSupport()) { return; }
bool handInteractionSupport = HandInteractionSupport();
var handsSubsystemCinfo = new XRHandSubsystemDescriptor.Cinfo
{
id = featureId,
providerType = typeof(ViveHandProvider),
subsystemTypeOverride = typeof(ViveHandSubsystem),
#if UNITY_XR_HANDS_1_5_0
supportsAimPose = handInteractionSupport,
supportsAimActivateValue = handInteractionSupport,
supportsGraspValue = handInteractionSupport,
supportsGripPose = handInteractionSupport,
supportsPinchPose = handInteractionSupport,
supportsPinchValue = handInteractionSupport,
supportsPokePose = handInteractionSupport,
#endif
};
XRHandSubsystemDescriptor.Register(handsSubsystemCinfo);
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void StartSubsystem()
{
List<XRHandSubsystemDescriptor> descriptors = new List<XRHandSubsystemDescriptor>();
if (subsystem == null || !subsystem.running)
{
descriptors.Clear();
SubsystemManager.GetSubsystemDescriptors(descriptors);
for (int i = 0; i < descriptors.Count; i++)
{
XRHandSubsystemDescriptor descriptor = descriptors[i];
if (descriptor.id == featureId)
{
subsystem = descriptor.Create();
subsystem.Start();
}
}
}
}
protected override void OnStart()
{
base.OnStart();
if (subsystemUpdater == null)
{
subsystemUpdater = new XRHandProviderUtility.SubsystemUpdater(subsystem);
}
subsystemUpdater.Start();
}
protected override void OnStop()
{
base.OnStop();
subsystemUpdater.Stop();
}
protected override void OnDestroy()
{
base.OnDestroy();
subsystemUpdater.Destroy();
subsystemUpdater = null;
}
private static bool ViveHandTrackingSupport()
{
ViveHandTracking viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
return viveHand.enabled;
}
private static bool HandInteractionSupport()
{
ViveInteractions viveInteractions = OpenXRSettings.Instance.GetFeature<ViveInteractions>();
if (viveInteractions.enabled)
{
return viveInteractions.UseKhrHandInteraction();
}
return false;
}
}
}
#endif

View File

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

View File

@@ -9,7 +9,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using AOT;
using UnityEngine.InputSystem; using UnityEngine.InputSystem;
using UnityEngine.InputSystem.LowLevel; using UnityEngine.InputSystem.LowLevel;
@@ -63,48 +62,74 @@ namespace VIVE.OpenXR.Hand
private bool m_XrInstanceCreated = false; private bool m_XrInstanceCreated = false;
private XrInstance m_XrInstance = 0; private XrInstance m_XrInstance = 0;
private static IntPtr xrGetInstanceProcAddr_prev; private static IntPtr xrGetInstanceProcAddr_prev;
private static IntPtr WaitFrame_prev; private static XrTime m_predictedDisplayTime;
private static XrFrameWaitInfo m_frameWaitInfo; private static XrDuration m_predictedDisplayDuration;
private static XrFrameState m_frameState;
private static int sizeOfXrHandJointLocationEXT = Marshal.SizeOf(typeof(XrHandJointLocationEXT));
private static IntPtr handJointLocationsNativeBuffer = IntPtr.Zero;
private static byte[] handJointLocationsByteBuffer = null;
private static int handJointLocationsNativeBufferLength = 0; // Not byte size, it is the number of XrHandJointLocationEXT.
protected override IntPtr HookGetInstanceProcAddr(IntPtr func) protected override IntPtr HookGetInstanceProcAddr(IntPtr func)
{ {
UnityEngine.Debug.Log("EXT: registering our own xrGetInstanceProcAddr"); ViveInterceptors.Instance.AddRequiredFunction("xrWaitFrame");
xrGetInstanceProcAddr_prev = func; if (ViveInterceptors.Instance.BeforeOriginalWaitFrame == null)
return Marshal.GetFunctionPointerForDelegate(m_intercept_xrWaitFrame_xrGetInstanceProcAddr); {
ViveInterceptors.Instance.BeforeOriginalWaitFrame = new ViveInterceptors.DelegateXrWaitFrameInterceptor(BeforeWaitFrame);
} }
[MonoPInvokeCallback(typeof(OpenXRHelper.xrGetInstanceProcAddrDelegate))] else
private static XrResult intercept_xrWaitFrame_xrGetInstanceProcAddr(XrInstance instance, string name, out IntPtr function)
{ {
if (xrGetInstanceProcAddr_prev == null || xrGetInstanceProcAddr_prev == IntPtr.Zero) ViveInterceptors.Instance.BeforeOriginalWaitFrame += BeforeWaitFrame;
{
UnityEngine.Debug.LogError("xrGetInstanceProcAddr_prev is null");
function = IntPtr.Zero;
return XrResult.XR_ERROR_VALIDATION_FAILURE;
} }
// Get delegate of old xrGetInstanceProcAddr. if (ViveInterceptors.Instance.AfterOriginalWaitFrame == null)
var xrGetProc = Marshal.GetDelegateForFunctionPointer<OpenXRHelper.xrGetInstanceProcAddrDelegate>(xrGetInstanceProcAddr_prev);
XrResult result = xrGetProc(instance, name, out function);
if (name == "xrWaitFrame")
{ {
WaitFrame_prev = function; ViveInterceptors.Instance.AfterOriginalWaitFrame = new ViveInterceptors.DelegateXrWaitFrameInterceptor(AfterWaitFrame);
m_intercept_xrWaitFrame = intercepted_xrWaitFrame; }
function = Marshal.GetFunctionPointerForDelegate(m_intercept_xrWaitFrame); ; else
UnityEngine.Debug.Log("Getting xrWaitFrame func"); {
ViveInterceptors.Instance.AfterOriginalWaitFrame += AfterWaitFrame;
}
return ViveInterceptors.Instance.HookGetInstanceProcAddr(func);
} }
return result; private bool BeforeWaitFrame(XrSession session, ref ViveInterceptors.XrFrameWaitInfo frameWaitInfo, ref ViveInterceptors.XrFrameState frameState, ref XrResult result)
}
[MonoPInvokeCallback(typeof(OpenXRHelper.xrWaitFrameDelegate))]
private static int intercepted_xrWaitFrame(ulong session, ref XrFrameWaitInfo frameWaitInfo, ref XrFrameState frameState)
{ {
// Get delegate of prev xrWaitFrame. ViveInterceptors.XrFrameState nextFrameState = new ViveInterceptors.XrFrameState
var xrWaitFrame = Marshal.GetDelegateForFunctionPointer<OpenXRHelper.xrWaitFrameDelegate>(WaitFrame_prev); {
int res = xrWaitFrame(session, ref frameWaitInfo, ref frameState); type = XrStructureType.XR_TYPE_PASSTHROUGH_HAND_TRACKER_FRAME_STATE_HTC,
m_frameWaitInfo = frameWaitInfo; next = frameState.next,
m_frameState = frameState; predictedDisplayPeriod = 0,
return res; predictedDisplayTime = 0,
shouldRender = false
};
frameState.next = MemoryTools.ToIntPtr(nextFrameState);
return true;
}
private bool AfterWaitFrame(XrSession session, ref ViveInterceptors.XrFrameWaitInfo frameWaitInfo, ref ViveInterceptors.XrFrameState frameState, ref XrResult result)
{
m_predictedDisplayTime = frameState.predictedDisplayTime;
m_predictedDisplayDuration = frameState.predictedDisplayPeriod;
IntPtr next = frameState.next;
HashSet<IntPtr> visited = new HashSet<IntPtr>();
int iterationCount = 0;
int maxIterations = 10;
while (next != IntPtr.Zero && !visited.Contains(next))
{
if (iterationCount++ > maxIterations) { break; }
visited.Add(next);
ViveInterceptors.XrFrameState nextFrameState = Marshal.PtrToStructure<ViveInterceptors.XrFrameState>(next);
if (nextFrameState.type == XrStructureType.XR_TYPE_PASSTHROUGH_HAND_TRACKER_FRAME_STATE_HTC &&
nextFrameState.predictedDisplayTime != 0)
{
m_predictedDisplayTime = nextFrameState.predictedDisplayTime;
break;
}
next = nextFrameState.next;
}
return true;
} }
/// <summary> /// <summary>
@@ -140,6 +165,14 @@ namespace VIVE.OpenXR.Hand
InputSystem.onAfterUpdate -= UpdateCallback; InputSystem.onAfterUpdate -= UpdateCallback;
} }
sb.Clear().Append(LOG_TAG).Append("OnInstanceDestroy() ").Append(xrInstance); DEBUG(sb); sb.Clear().Append(LOG_TAG).Append("OnInstanceDestroy() ").Append(xrInstance); DEBUG(sb);
// release buffer
if (handJointLocationsNativeBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(handJointLocationsNativeBuffer);
handJointLocationsNativeBuffer = IntPtr.Zero;
handJointLocationsByteBuffer = null;
handJointLocationsNativeBufferLength = 0;
}
} }
private XrSystemId m_XrSystemId = 0; private XrSystemId m_XrSystemId = 0;
@@ -343,9 +376,6 @@ namespace VIVE.OpenXR.Hand
#endregion #endregion
#region OpenXR function delegates #region OpenXR function delegates
private static readonly OpenXRHelper.xrGetInstanceProcAddrDelegate m_intercept_xrWaitFrame_xrGetInstanceProcAddr
= new OpenXRHelper.xrGetInstanceProcAddrDelegate(intercept_xrWaitFrame_xrGetInstanceProcAddr);
private static OpenXRHelper.xrWaitFrameDelegate m_intercept_xrWaitFrame;
/// xrGetInstanceProcAddr /// xrGetInstanceProcAddr
OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddr; OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddr;
@@ -681,7 +711,7 @@ namespace VIVE.OpenXR.Hand
{ {
XRInputSubsystem subsystem = null; XRInputSubsystem subsystem = null;
SubsystemManager.GetInstances(s_InputSubsystems); SubsystemManager.GetSubsystems(s_InputSubsystems);
if (s_InputSubsystems.Count > 0) if (s_InputSubsystems.Count > 0)
{ {
subsystem = s_InputSubsystems[0]; subsystem = s_InputSubsystems[0];
@@ -795,7 +825,7 @@ namespace VIVE.OpenXR.Hand
return true; return true;
} }
private int lastUpdateFrameL = -1, lastUpdateFrameR = -1; private int lastUpdateFrameL = -1, lastUpdateFrameR = -1, updateFrame = -1;
private void UpdateCallback() private void UpdateCallback()
{ {
// Only allow updating poses once at BeforeRender & Dynamic per frame. // Only allow updating poses once at BeforeRender & Dynamic per frame.
@@ -805,6 +835,10 @@ namespace VIVE.OpenXR.Hand
lastUpdateFrameL = -1; lastUpdateFrameL = -1;
lastUpdateFrameR = -1; lastUpdateFrameR = -1;
} }
if (InputState.currentUpdateType == InputUpdateType.BeforeRender)
{
updateFrame = Time.frameCount;
}
} }
private bool AllowUpdate(bool isLeft) private bool AllowUpdate(bool isLeft)
{ {
@@ -832,90 +866,69 @@ namespace VIVE.OpenXR.Hand
public bool GetJointLocations(bool isLeft, out XrHandJointLocationEXT[] handJointLocation, out XrTime timestamp) public bool GetJointLocations(bool isLeft, out XrHandJointLocationEXT[] handJointLocation, out XrTime timestamp)
{ {
handJointLocation = isLeft ? jointLocationsL : jointLocationsR; handJointLocation = isLeft ? jointLocationsL : jointLocationsR;
timestamp = m_frameState.predictedDisplayTime; long displayTime = m_predictedDisplayTime;
if (Time.frameCount > updateFrame)
{
displayTime += m_predictedDisplayDuration;
}
timestamp = displayTime;
if (!AllowUpdate(isLeft)) { return true; } if (!AllowUpdate(isLeft)) { return true; }
bool ret = false; bool ret = false;
if (isLeft && !hasLeftHandTracker) { return ret; } if (isLeft && !hasLeftHandTracker) { return ret; }
if (!isLeft && !hasRightHandTracker) { return ret; } if (!isLeft && !hasRightHandTracker) { return ret; }
OpenXRHelper.Trace.Begin("GetJointLocations");
TrackingOriginModeFlags origin = GetTrackingOriginMode();
if (origin == TrackingOriginModeFlags.Unknown || origin == TrackingOriginModeFlags.Unbounded) { return ret; }
XrSpace baseSpace = (origin == TrackingOriginModeFlags.Device ? m_ReferenceSpaceLocal : m_ReferenceSpaceStage);
/// Configures XrHandJointsLocateInfoEXT /// Configures XrHandJointsLocateInfoEXT
XrHandJointsLocateInfoEXT locateInfo = new XrHandJointsLocateInfoEXT( XrHandJointsLocateInfoEXT locateInfo = new XrHandJointsLocateInfoEXT(
in_type: XrStructureType.XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, in_type: XrStructureType.XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT,
in_next: IntPtr.Zero, in_next: IntPtr.Zero,
in_baseSpace: baseSpace, in_baseSpace: GetCurrentAppSpace(),
in_time: m_frameState.predictedDisplayTime); in_time: displayTime);
/// Configures XrHandJointLocationsEXT /// Configures XrHandJointLocationsEXT
locations.type = XrStructureType.XR_TYPE_HAND_JOINT_LOCATIONS_EXT; locations.type = XrStructureType.XR_TYPE_HAND_JOINT_LOCATIONS_EXT;
locations.next = IntPtr.Zero; locations.next = IntPtr.Zero;
locations.isActive = false; locations.isActive = false;
locations.jointCount = (uint)(isLeft ? jointLocationsL.Length : jointLocationsR.Length); locations.jointCount = (uint)(handJointLocation.Length);
XrHandJointLocationEXT joint_location_ext_type = default(XrHandJointLocationEXT); int jointLocationsLength = handJointLocation.Length;
int jointLocationsLength = isLeft ? jointLocationsL.Length : jointLocationsR.Length;
locations.jointLocations = Marshal.AllocHGlobal(Marshal.SizeOf(joint_location_ext_type) * jointLocationsLength);
long offset = 0; if (handJointLocationsNativeBuffer == null || handJointLocationsNativeBuffer == IntPtr.Zero)
/*if (IntPtr.Size == 4)
offset = locations.jointLocations.ToInt32();
else
offset = locations.jointLocations.ToInt64();
for (int i = 0; i < jointLocationsLength; i++)
{ {
IntPtr joint_location_ext_ptr = new IntPtr(offset); int N = sizeOfXrHandJointLocationEXT * jointLocationsLength;
handJointLocationsNativeBuffer = Marshal.AllocHGlobal(N);
handJointLocationsByteBuffer = new byte[N];
handJointLocationsNativeBufferLength = jointLocationsLength;
DEBUG($"GetJointLocations() handJointLocationsNativeBuffer[{N}] is allocated.");
}
else if (handJointLocationsNativeBufferLength < jointLocationsLength)
{
Marshal.FreeHGlobal(handJointLocationsNativeBuffer);
int N = sizeOfXrHandJointLocationEXT * jointLocationsLength;
handJointLocationsNativeBuffer = Marshal.AllocHGlobal(N);
handJointLocationsByteBuffer = new byte[N];
handJointLocationsNativeBufferLength = jointLocationsLength;
DEBUG($"GetJointLocations() handJointLocationsNativeBuffer[{N}] is allocated.");
}
if (isLeft) locations.jointLocations = handJointLocationsNativeBuffer;
Marshal.StructureToPtr(jointLocationsL[i], joint_location_ext_ptr, false);
else
Marshal.StructureToPtr(jointLocationsR[i], joint_location_ext_ptr, false);
offset += Marshal.SizeOf(joint_location_ext_type); var retX = LocateHandJointsEXT(
}*/
if (LocateHandJointsEXT(
handTracker: (isLeft ? leftHandTracker : rightHandTracker), handTracker: (isLeft ? leftHandTracker : rightHandTracker),
locateInfo: locateInfo, locateInfo: locateInfo,
locations: ref locations) == XrResult.XR_SUCCESS) locations: ref locations);
if (retX == XrResult.XR_SUCCESS)
{ {
timestamp = locateInfo.time; timestamp = locateInfo.time;
if (locations.isActive) if (locations.isActive)
{ {
if (IntPtr.Size == 4) MemoryTools.CopyAllFromRawMemory(handJointLocation, handJointLocationsNativeBuffer);
offset = locations.jointLocations.ToInt32();
else
offset = locations.jointLocations.ToInt64();
for (int i = 0; i < locations.jointCount; i++)
{
IntPtr joint_location_ext_ptr = new IntPtr(offset);
if (isLeft)
jointLocationsL[i] = (XrHandJointLocationEXT)Marshal.PtrToStructure(joint_location_ext_ptr, typeof(XrHandJointLocationEXT));
else
jointLocationsR[i] = (XrHandJointLocationEXT)Marshal.PtrToStructure(joint_location_ext_ptr, typeof(XrHandJointLocationEXT));
offset += Marshal.SizeOf(joint_location_ext_type);
}
// ToDo: locationFlags?
handJointLocation = isLeft ? jointLocationsL : jointLocationsR;
ret = true; ret = true;
} }
} }
Marshal.FreeHGlobal(locations.jointLocations);
OpenXRHelper.Trace.End();
return ret; return ret;
} }
/// <summary> /// <summary>

View File

@@ -172,10 +172,10 @@ namespace VIVE.OpenXR.Passthrough
/// The alpha value of the passthrough in the range [0, 1]. /// The alpha value of the passthrough in the range [0, 1].
/// </summary> /// </summary>
public float alpha; public float alpha;
public XrPassthroughColorHTC(XrStructureType in_type, IntPtr in_next, float in_alpha) public XrPassthroughColorHTC(float in_alpha)
{ {
type = in_type; type = XrStructureType.XR_TYPE_PASSTHROUGH_COLOR_HTC;
next = in_next; next = IntPtr.Zero;
alpha = in_alpha; alpha = in_alpha;
} }
}; };
@@ -201,7 +201,7 @@ namespace VIVE.OpenXR.Passthrough
/// <summary> /// <summary>
/// An array of XrVector3f. The size of the array must be equal to vertexCount. /// An array of XrVector3f. The size of the array must be equal to vertexCount.
/// </summary> /// </summary>
public XrVector3f[] vertices; public IntPtr vertices; // XrVector3f
/// <summary> /// <summary>
/// The count of indices array in the mesh. /// The count of indices array in the mesh.
/// </summary> /// </summary>
@@ -209,7 +209,7 @@ namespace VIVE.OpenXR.Passthrough
/// <summary> /// <summary>
/// An array of triangle indices. The size of the array must be equal to indexCount. /// An array of triangle indices. The size of the array must be equal to indexCount.
/// </summary> /// </summary>
public UInt32[] indices; public IntPtr indices; // UInt32[]
/// <summary> /// <summary>
/// The XrSpace that defines the projected passthrough's base space for transformations. /// The XrSpace that defines the projected passthrough's base space for transformations.
/// </summary> /// </summary>
@@ -226,21 +226,6 @@ namespace VIVE.OpenXR.Passthrough
/// The XrVector3f that defines the scale of the mesh /// The XrVector3f that defines the scale of the mesh
/// </summary> /// </summary>
public XrVector3f scale; public XrVector3f scale;
public XrPassthroughMeshTransformInfoHTC(XrStructureType in_type, IntPtr in_next, UInt32 in_vertexCount,
XrVector3f[] in_vertices, UInt32 in_indexCount, UInt32[] in_indices, XrSpace in_baseSpace, XrTime in_time,
XrPosef in_pose, XrVector3f in_scale)
{
type = in_type;
next = in_next;
vertexCount = in_vertexCount;
vertices = in_vertices;
indexCount = in_indexCount;
indices = in_indices;
baseSpace = in_baseSpace;
time = in_time;
pose = in_pose;
scale = in_scale;
}
}; };
/// <summary> /// <summary>
@@ -273,11 +258,12 @@ namespace VIVE.OpenXR.Passthrough
/// The XrPassthroughColorHTC describing the color information with the alpha value of the passthrough layer. /// The XrPassthroughColorHTC describing the color information with the alpha value of the passthrough layer.
/// </summary> /// </summary>
public XrPassthroughColorHTC color; public XrPassthroughColorHTC color;
public XrCompositionLayerPassthroughHTC(XrStructureType in_type, IntPtr in_next, XrCompositionLayerFlags in_layerFlags,
public XrCompositionLayerPassthroughHTC(XrCompositionLayerFlags in_layerFlags,
XrSpace in_space, XrPassthroughHTC in_passthrough, XrPassthroughColorHTC in_color) XrSpace in_space, XrPassthroughHTC in_passthrough, XrPassthroughColorHTC in_color)
{ {
type = in_type; type = XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC;
next = in_next; next = IntPtr.Zero;
layerFlags = in_layerFlags; layerFlags = in_layerFlags;
space = in_space; space = in_space;
passthrough = in_passthrough; passthrough = in_passthrough;

View File

@@ -26,7 +26,7 @@ namespace UnityEngine.XR.OpenXR.Features.Interactions
/// </summary> /// </summary>
#if UNITY_EDITOR #if UNITY_EDITOR
[UnityEditor.XR.OpenXR.Features.OpenXRFeature( [UnityEditor.XR.OpenXR.Features.OpenXRFeature(
UiName = "HTC Vive Tracker Profile", UiName = "HTC VIVE Tracker Profile",
BuildTargetGroups = new[] { BuildTargetGroup.Standalone, BuildTargetGroup.WSA }, BuildTargetGroups = new[] { BuildTargetGroup.Standalone, BuildTargetGroup.WSA },
Company = "MASSIVE", Company = "MASSIVE",
Desc = "Allows for mapping input to the HTC Vive Tracker interaction profile.", Desc = "Allows for mapping input to the HTC Vive Tracker interaction profile.",

View File

@@ -3,6 +3,7 @@
using System; using System;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using VIVE.OpenXR.Hand; using VIVE.OpenXR.Hand;
namespace VIVE.OpenXR.Models namespace VIVE.OpenXR.Models
@@ -69,16 +70,43 @@ namespace VIVE.OpenXR.Models
skinMeshRenderer = GetComponentInChildren<SkinnedMeshRenderer>(); skinMeshRenderer = GetComponentInChildren<SkinnedMeshRenderer>();
} }
private void OnEnable()
{
Application.onBeforeRender += BeforeRenderUpdate;
}
private void OnDisable()
{
Application.onBeforeRender -= BeforeRenderUpdate;
}
private void Update() private void Update()
{ {
if (skinMeshRenderer == null) { return; } UpdateHand();
}
private void BeforeRenderUpdate()
{
if (!skinMeshRenderer.enabled) { return; }
UpdateHand();
}
private void UpdateHand()
{
Profiler.BeginSample("HandModelActions");
if (skinMeshRenderer == null) { Profiler.EndSample(); return; }
Profiler.BeginSample("GetJointLocations");
if (!XR_EXT_hand_tracking.Interop.GetJointLocations(m_IsLeft, out XrHandJointLocationEXT[] handJointLocation)) if (!XR_EXT_hand_tracking.Interop.GetJointLocations(m_IsLeft, out XrHandJointLocationEXT[] handJointLocation))
{ {
skinMeshRenderer.enabled = false; skinMeshRenderer.enabled = false;
Profiler.EndSample();
Profiler.EndSample();
return; return;
} }
Profiler.EndSample();
Profiler.BeginSample("UpdateJointPose");
skinMeshRenderer.enabled = !ForceHidden; skinMeshRenderer.enabled = !ForceHidden;
UpdateJointPosition(handJointLocation[(int)XrHandJointEXT.XR_HAND_JOINT_WRIST_EXT], ref m_Wrist); UpdateJointPosition(handJointLocation[(int)XrHandJointEXT.XR_HAND_JOINT_WRIST_EXT], ref m_Wrist);
@@ -114,6 +142,8 @@ namespace VIVE.OpenXR.Models
UpdateJointRotation(handJointLocation[(int)XrHandJointEXT.XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT], ref m_Little_Intermediate); UpdateJointRotation(handJointLocation[(int)XrHandJointEXT.XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT], ref m_Little_Intermediate);
UpdateJointRotation(handJointLocation[(int)XrHandJointEXT.XR_HAND_JOINT_LITTLE_DISTAL_EXT], ref m_Little_Distal); UpdateJointRotation(handJointLocation[(int)XrHandJointEXT.XR_HAND_JOINT_LITTLE_DISTAL_EXT], ref m_Little_Distal);
UpdateJointRotation(handJointLocation[(int)XrHandJointEXT.XR_HAND_JOINT_LITTLE_TIP_EXT], ref m_Little_Tip); UpdateJointRotation(handJointLocation[(int)XrHandJointEXT.XR_HAND_JOINT_LITTLE_TIP_EXT], ref m_Little_Tip);
Profiler.EndSample();
Profiler.EndSample();
} }
private void UpdateJointPosition(XrHandJointLocationEXT pose, ref GameObject joint) private void UpdateJointPosition(XrHandJointLocationEXT pose, ref GameObject joint)

View File

@@ -127,6 +127,9 @@ namespace VIVE.OpenXR
XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC = 1000317001, XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC = 1000317001,
XR_TYPE_PASSTHROUGH_COLOR_HTC = 1000317002, XR_TYPE_PASSTHROUGH_COLOR_HTC = 1000317002,
XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC = 1000317003, XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC = 1000317003,
XR_TYPE_PASSTHROUGH_HAND_TRACKER_FRAME_STATE_HTC = 1000317100,
XR_TYPE_PASSTHROUGH_VIVE_CONTROLLER_FRAME_STATE_HTC = 1000317101,
XR_TYPE_PASSTHROUGH_VIVE_TRACKER_FRAME_STATE_HTC = 1000317102,
XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC = 1000317004, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC = 1000317004,
XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX = 1000033000, XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX = 1000033000,
XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX = 1000033003, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX = 1000033003,
@@ -544,6 +547,24 @@ namespace VIVE.OpenXR
} }
} }
public struct XrBaseStructure
{
public XrStructureType type;
public IntPtr next;
}
public struct XrBaseOutStructure
{
public XrStructureType type;
public IntPtr next;
}
public struct XrBaseInStructure
{
public XrStructureType type;
public IntPtr next;
}
#region 2.18. Coordinate System #region 2.18. Coordinate System
/// <summary> /// <summary>
/// A two-dimensional vector is defined by the XrVector2f structure. /// A two-dimensional vector is defined by the XrVector2f structure.
@@ -3243,7 +3264,7 @@ namespace VIVE.OpenXR
{ {
if (funcPtr != IntPtr.Zero) if (funcPtr != IntPtr.Zero)
{ {
Debug.Log("Get function pointer of " + name); Log.D("Get function pointer of " + name);
func = Marshal.GetDelegateForFunctionPointer<Type>(funcPtr); func = Marshal.GetDelegateForFunctionPointer<Type>(funcPtr);
return true; return true;
} }

View File

@@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEngine.Profiling;
//using VIVE.OpenXR.Utils; //using VIVE.OpenXR.Utils;
using VIVE.OpenXR.Hand; using VIVE.OpenXR.Hand;
@@ -59,20 +60,7 @@ namespace VIVE.OpenXR
if (m_JointLocations.isActive == 1) if (m_JointLocations.isActive == 1)
{ {
long offset = 0; MemoryTools.CopyFromRawMemory(handJointLocation, m_JointLocations.jointLocations, (int)m_JointLocations.jointCount);
XrHandJointLocationEXT joint_location_ext_type = default(XrHandJointLocationEXT);
if (IntPtr.Size == 4)
offset = m_JointLocations.jointLocations.ToInt32();
else
offset = m_JointLocations.jointLocations.ToInt64();
for (int i = 0; i < m_JointLocations.jointCount; i++)
{
IntPtr joint_location_ext_ptr = new IntPtr(offset);
s_JointLocation[isLeft][i] = (XrHandJointLocationEXT)Marshal.PtrToStructure(joint_location_ext_ptr, typeof(XrHandJointLocationEXT));
offset += Marshal.SizeOf(joint_location_ext_type);
}
handJointLocation = s_JointLocation[isLeft]; handJointLocation = s_JointLocation[isLeft];
return true; return true;

View File

@@ -86,13 +86,8 @@ namespace VIVE.OpenXR
{ {
if (ASSERT_FEATURE()) if (ASSERT_FEATURE())
{ {
if (feature.GetJointLocations(isLeft, out XrHandJointLocationEXT[] array, out timestamp)) if (feature.GetJointLocations(isLeft, out handJointLocation, out timestamp))
{ {
if (l_HandJointLocation == null) { l_HandJointLocation = new List<XrHandJointLocationEXT>(); }
l_HandJointLocation.Clear();
for (int i = 0; i < array.Length; i++) { l_HandJointLocation.Add(array[i]); }
handJointLocation = l_HandJointLocation.ToArray();
return true; return true;
} }
} }

View File

@@ -43,27 +43,6 @@ namespace VIVE.OpenXR
return result; return result;
} }
public override void GetOriginEndFrameLayerList(out List<IntPtr> layers)
{
ASSERT_FEATURE();
layers = new List<IntPtr>();
#if UNITY_STANDALONE
if (feature)
feature.GetOriginEndFrameLayerList(out layers);
else
layers = new List<IntPtr>();
#endif
}
public override void SubmitLayers(List<IntPtr> layers)
{
ASSERT_FEATURE();
#if UNITY_STANDALONE
if (feature)
feature.SubmitLayers(layers);
#endif
}
public override XrSpace GetTrackingSpace() public override XrSpace GetTrackingSpace()
{ {
ASSERT_FEATURE(); ASSERT_FEATURE();
@@ -77,10 +56,8 @@ namespace VIVE.OpenXR
public override XrFrameState GetFrameState() public override XrFrameState GetFrameState()
{ {
ASSERT_FEATURE(); ASSERT_FEATURE();
#if UNITY_STANDALONE
if (feature) if (feature)
return feature.GetFrameState(); return feature.GetFrameState();
#endif
return new XrFrameState(); return new XrFrameState();
} }
} }

View File

@@ -2,7 +2,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.InputSystem; using UnityEngine.InputSystem;
using UnityEngine.XR.OpenXR; using UnityEngine.XR.OpenXR;
@@ -107,6 +106,12 @@ namespace VIVE.OpenXR.Toolkits.Common
public static class VIVEInput public static class VIVEInput
{ {
private const string kFloatType = "float";
private const string kVector2Type = "Vector2";
private const string kVector3Type = "Vector3";
private const string kQuaternionType = "Quaternion";
private const string kPoseType = "Pose";
private struct InputActionMapping private struct InputActionMapping
{ {
public DeviceCategory device; public DeviceCategory device;
@@ -115,15 +120,18 @@ namespace VIVE.OpenXR.Toolkits.Common
public HandEvent handEvent; public HandEvent handEvent;
public InputAction inputAction { get; private set; } public InputAction inputAction { get; private set; }
public InputActionMapping(string bindingPath, DeviceCategory device, public InputActionMapping(string in_BindingPath, DeviceCategory in_Device,
PoseState poseState = PoseState.None, ButtonEvent buttonEvent = ButtonEvent.None, HandEvent handEvent = HandEvent.None) PoseState in_PoseState = PoseState.None,
ButtonEvent in_ButtonEvent = ButtonEvent.None,
HandEvent in_HandEvent = HandEvent.None,
string in_Type = "")
{ {
inputAction = new InputAction(binding: bindingPath); inputAction = new InputAction(binding: in_BindingPath, expectedControlType: in_Type);
inputAction.Enable(); inputAction.Enable();
this.device = device; this.device = in_Device;
this.poseState = poseState; this.poseState = in_PoseState;
this.buttonEvent = buttonEvent; this.buttonEvent = in_ButtonEvent;
this.handEvent = handEvent; this.handEvent = in_HandEvent;
} }
public static InputActionMapping Identify => new InputActionMapping("", DeviceCategory.None); public static InputActionMapping Identify => new InputActionMapping("", DeviceCategory.None);
@@ -150,11 +158,11 @@ namespace VIVE.OpenXR.Toolkits.Common
public Vector3 position { get; private set; } public Vector3 position { get; private set; }
public Quaternion rotation { get; private set; } public Quaternion rotation { get; private set; }
public JointData(bool isValid, Vector3 position, Quaternion rotation) public JointData(bool in_IsValid, Vector3 in_Position, Quaternion in_Rotation)
{ {
this.isValid = isValid; this.isValid = in_IsValid;
this.position = position; this.position = in_Position;
this.rotation = rotation; this.rotation = in_Rotation;
} }
public static JointData Identify => new JointData(false, Vector3.zero, Quaternion.identity); public static JointData Identify => new JointData(false, Vector3.zero, Quaternion.identity);
@@ -164,18 +172,44 @@ namespace VIVE.OpenXR.Toolkits.Common
public bool isTracked { get; private set; } public bool isTracked { get; private set; }
public int updateTime { get; private set; } public int updateTime { get; private set; }
public JointData[] joints { get; private set; } public JointData[] joints { get; private set; }
private JointData[] jointBuffer;
public HandData(JointData[] joints) public HandData(JointData[] in_Joints)
{ {
this.joints = joints; jointBuffer = new JointData[(int)HandJointType.Count];
isTracked = !this.joints.Any(x => x.isValid == false); for (int i = 0; i < in_Joints.Length; i++)
{
jointBuffer[i] = in_Joints[i];
}
this.joints = jointBuffer;
isTracked = true;
for (int i = 0; i < this.joints.Length; i++)
{
if (!this.joints[i].isValid)
{
isTracked = false;
break;
}
}
updateTime = Time.frameCount; updateTime = Time.frameCount;
} }
public void Update(JointData[] joints) public void Update(JointData[] in_Joints)
{ {
this.joints = joints; for (int i = 0; i < in_Joints.Length; i++)
isTracked = !this.joints.Any(x => x.isValid == false); {
jointBuffer[i] = in_Joints[i];
}
this.joints = jointBuffer;
isTracked = true;
for (int i = 0; i < this.joints.Length; i++)
{
if (!this.joints[i].isValid)
{
isTracked = false;
break;
}
}
updateTime = Time.frameCount; updateTime = Time.frameCount;
} }
@@ -193,12 +227,16 @@ namespace VIVE.OpenXR.Toolkits.Common
} }
} }
private static bool isInitInputActions = false; private static bool m_IsInitInputActions = false;
private static List<InputActionMapping> inputActions = new List<InputActionMapping>(); private static bool m_IsSupportViveHand = false;
private static HandData leftHand = HandData.Identify; private static bool m_IsSupportXrHand = false;
private static HandData rightHand = HandData.Identify; private static List<InputActionMapping> s_InputActions = new List<InputActionMapping>();
private static HandData m_LeftHand = HandData.Identify;
private static HandData m_RightHand = HandData.Identify;
private static JointData[] m_JointBuffer = new JointData[(int)HandJointType.Count];
#if UNITY_XR_HANDS #if UNITY_XR_HANDS
private static XRHandSubsystem handSubsystem = null; private static XRHandSubsystem m_HandSubsystem = null;
private static List<XRHandSubsystem> m_HandSubsystems = new List<XRHandSubsystem>();
#endif #endif
#region Public Interface #region Public Interface
@@ -221,18 +259,16 @@ namespace VIVE.OpenXR.Toolkits.Common
} }
else else
{ {
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == device && x.poseState == poseState); if (GetInputActionMapping(device, poseState, out InputActionMapping inputActionMapping))
if (inputActionMapping == null) { return false; } {
var inputAction = inputActionMapping.inputAction;
try if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
{ {
eventResult = inputActionMapping.inputAction.ReadValue<float>() > 0; eventResult = inputActionMapping.inputAction.ReadValue<float>() > 0;
return true; return true;
} }
catch (InvalidOperationException)
{
return false;
} }
return false;
} }
} }
@@ -255,18 +291,16 @@ namespace VIVE.OpenXR.Toolkits.Common
} }
else else
{ {
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == device && x.poseState == poseState); if (GetInputActionMapping(device, poseState, out InputActionMapping inputActionMapping))
if (inputActionMapping == null) { return false; } {
var inputAction = inputActionMapping.inputAction;
try if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kVector3Type)
{ {
eventResult = inputActionMapping.inputAction.ReadValue<Vector3>(); eventResult = inputActionMapping.inputAction.ReadValue<Vector3>();
return true; return true;
} }
catch (InvalidOperationException)
{
return false;
} }
return false;
} }
} }
@@ -289,18 +323,16 @@ namespace VIVE.OpenXR.Toolkits.Common
} }
else else
{ {
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == device && x.poseState == poseState); if (GetInputActionMapping(device, poseState, out InputActionMapping inputActionMapping))
if (inputActionMapping == null) { return false; } {
var inputAction = inputActionMapping.inputAction;
try if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kQuaternionType)
{ {
eventResult = inputActionMapping.inputAction.ReadValue<Quaternion>(); eventResult = inputActionMapping.inputAction.ReadValue<Quaternion>();
return true; return true;
} }
catch (InvalidOperationException)
{
return false;
} }
return false;
} }
} }
@@ -315,12 +347,15 @@ namespace VIVE.OpenXR.Toolkits.Common
{ {
CheckInitialize(); CheckInitialize();
eventResult = false; eventResult = false;
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent); if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
if (inputActionMapping != null) {
var inputAction = inputActionMapping.inputAction;
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
{ {
eventResult = inputActionMapping.inputAction.WasPressedThisFrame(); eventResult = inputActionMapping.inputAction.WasPressedThisFrame();
return true; return true;
} }
}
return false; return false;
} }
@@ -335,12 +370,15 @@ namespace VIVE.OpenXR.Toolkits.Common
{ {
CheckInitialize(); CheckInitialize();
eventResult = false; eventResult = false;
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent); if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
if (inputActionMapping != null) {
var inputAction = inputActionMapping.inputAction;
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
{ {
eventResult = inputActionMapping.inputAction.WasReleasedThisFrame(); eventResult = inputActionMapping.inputAction.WasReleasedThisFrame();
return true; return true;
} }
}
return false; return false;
} }
@@ -355,21 +393,16 @@ namespace VIVE.OpenXR.Toolkits.Common
{ {
CheckInitialize(); CheckInitialize();
eventResult = false; eventResult = false;
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent); if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
if (inputActionMapping != null)
{ {
try var inputAction = inputActionMapping.inputAction;
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
{ {
eventResult = inputActionMapping.inputAction.ReadValue<float>() == 1; eventResult = inputActionMapping.inputAction.ReadValue<float>() == 1;
return true; return true;
} }
catch (InvalidOperationException)
{
return false;
}
} }
return false; return false;
} }
/// <summary> /// <summary>
@@ -383,21 +416,16 @@ namespace VIVE.OpenXR.Toolkits.Common
{ {
CheckInitialize(); CheckInitialize();
eventResult = 0f; eventResult = 0f;
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent); if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
if (inputActionMapping != null)
{ {
try var inputAction = inputActionMapping.inputAction;
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
{ {
eventResult = inputActionMapping.inputAction.ReadValue<float>(); eventResult = inputActionMapping.inputAction.ReadValue<float>();
return true; return true;
} }
catch (InvalidOperationException)
{
return false;
}
} }
return false; return false;
} }
/// <summary> /// <summary>
@@ -411,18 +439,14 @@ namespace VIVE.OpenXR.Toolkits.Common
{ {
CheckInitialize(); CheckInitialize();
eventResult = Vector2.zero; eventResult = Vector2.zero;
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetController(handedness) && x.buttonEvent == buttonEvent); if (GetInputActionMapping(GetController(handedness), buttonEvent, out InputActionMapping inputActionMapping))
if (inputActionMapping != null)
{ {
try var inputAction = inputActionMapping.inputAction;
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kVector2Type)
{ {
eventResult = inputActionMapping.inputAction.ReadValue<Vector2>(); eventResult = inputActionMapping.inputAction.ReadValue<Vector2>();
return true; return true;
} }
catch (InvalidOperationException)
{
return false;
}
} }
return false; return false;
} }
@@ -438,18 +462,14 @@ namespace VIVE.OpenXR.Toolkits.Common
{ {
CheckInitialize(); CheckInitialize();
eventResult = 0; eventResult = 0;
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetHand(handedness) && x.handEvent == handEvent); if (GetInputActionMapping(GetHand(handedness), handEvent, out InputActionMapping inputActionMapping))
if (inputActionMapping != null)
{ {
try var inputAction = inputActionMapping.inputAction;
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kFloatType)
{ {
eventResult = inputActionMapping.inputAction.ReadValue<float>(); eventResult = inputActionMapping.inputAction.ReadValue<float>();
return true; return true;
} }
catch (InvalidOperationException)
{
return false;
}
} }
return false; return false;
} }
@@ -465,19 +485,19 @@ namespace VIVE.OpenXR.Toolkits.Common
{ {
CheckInitialize(); CheckInitialize();
eventResult = Pose.identity; eventResult = Pose.identity;
InputActionMapping inputActionMapping = inputActions.FirstOrDefault(x => x.device == GetHand(handedness) && x.handEvent == handEvent); if (GetInputActionMapping(GetHand(handedness), handEvent, out InputActionMapping inputActionMapping))
if (inputActionMapping != null)
{ {
try var inputAction = inputActionMapping.inputAction;
if (inputAction != null && inputAction.enabled && inputAction.expectedControlType == kPoseType)
{ {
# if USE_INPUT_SYSTEM_POSE_CONTROL
UnityEngine.InputSystem.XR.PoseState pose = inputActionMapping.inputAction.ReadValue<UnityEngine.InputSystem.XR.PoseState>();
#else
UnityEngine.XR.OpenXR.Input.Pose pose = inputActionMapping.inputAction.ReadValue<UnityEngine.XR.OpenXR.Input.Pose>(); UnityEngine.XR.OpenXR.Input.Pose pose = inputActionMapping.inputAction.ReadValue<UnityEngine.XR.OpenXR.Input.Pose>();
#endif
eventResult = new Pose(pose.position, pose.rotation); eventResult = new Pose(pose.position, pose.rotation);
return true; return true;
} }
catch (InvalidOperationException)
{
return false;
}
} }
return false; return false;
} }
@@ -495,13 +515,13 @@ namespace VIVE.OpenXR.Toolkits.Common
jointPose = Pose.identity; jointPose = Pose.identity;
if (handedness == Handedness.Left) if (handedness == Handedness.Left)
{ {
jointPose = new Pose(leftHand.joints[(int)joint].position, leftHand.joints[(int)joint].rotation); jointPose = new Pose(m_LeftHand.joints[(int)joint].position, m_LeftHand.joints[(int)joint].rotation);
return leftHand.joints[(int)joint].isValid; return m_LeftHand.joints[(int)joint].isValid;
} }
else else
{ {
jointPose = new Pose(rightHand.joints[(int)joint].position, rightHand.joints[(int)joint].rotation); jointPose = new Pose(m_RightHand.joints[(int)joint].position, m_RightHand.joints[(int)joint].rotation);
return rightHand.joints[(int)joint].isValid; return m_RightHand.joints[(int)joint].isValid;
} }
} }
@@ -513,24 +533,27 @@ namespace VIVE.OpenXR.Toolkits.Common
public static bool IsHandTracked(Handedness handedness) public static bool IsHandTracked(Handedness handedness)
{ {
CheckHandUpdated(); CheckHandUpdated();
return handedness == Handedness.Left ? leftHand.isTracked : rightHand.isTracked; return handedness == Handedness.Left ? m_LeftHand.isTracked : m_RightHand.isTracked;
} }
public static bool IsHandValidate() public static bool IsHandValidate()
{
if (!m_IsInitInputActions)
{ {
ViveHandTracking viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>(); ViveHandTracking viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
if (viveHand) if (viveHand)
{ {
return true; m_IsSupportViveHand = true;
} }
#if UNITY_XR_HANDS #if UNITY_XR_HANDS
HandTracking xrHand = OpenXRSettings.Instance.GetFeature<HandTracking>(); HandTracking xrHand = OpenXRSettings.Instance.GetFeature<HandTracking>();
if (xrHand) if (xrHand)
{ {
return true; m_IsSupportXrHand = true;
} }
#endif #endif
return false; }
return m_IsSupportViveHand || m_IsSupportXrHand;
} }
#endregion #endregion
@@ -538,187 +561,228 @@ namespace VIVE.OpenXR.Toolkits.Common
[RuntimeInitializeOnLoadMethod] [RuntimeInitializeOnLoadMethod]
private static bool CheckInitialize() private static bool CheckInitialize()
{ {
if (!isInitInputActions) if (!m_IsInitInputActions)
{ {
Initialized(); Initialized();
isInitInputActions = true; IsHandValidate();
m_IsInitInputActions = true;
} }
return isInitInputActions; return m_IsInitInputActions;
} }
private static void Initialized() private static void Initialized()
{ {
#region Head #region Head
inputActions.Add(new InputActionMapping("<XRHMD>/isTracked", DeviceCategory.HMD, poseState: PoseState.IsTracked)); s_InputActions.Add(new InputActionMapping("<XRHMD>/isTracked", DeviceCategory.HMD, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyePosition", DeviceCategory.HMD, poseState: PoseState.Position)); s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyePosition", DeviceCategory.HMD, in_PoseState: PoseState.Position, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeRotation", DeviceCategory.HMD, poseState: PoseState.Rotation)); s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeRotation", DeviceCategory.HMD, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeVelocity", DeviceCategory.HMD, poseState: PoseState.Velocity)); s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeVelocity", DeviceCategory.HMD, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAngularVelocity", DeviceCategory.HMD, poseState: PoseState.AngularVelocity)); s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAngularVelocity", DeviceCategory.HMD, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAcceleration", DeviceCategory.HMD, poseState: PoseState.Acceleration)); s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAcceleration", DeviceCategory.HMD, in_PoseState: PoseState.Acceleration, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAngularAcceleration", DeviceCategory.HMD, poseState: PoseState.AngularAcceleration)); s_InputActions.Add(new InputActionMapping("<XRHMD>/centerEyeAngularAcceleration", DeviceCategory.HMD, in_PoseState: PoseState.AngularAcceleration, in_Type: kVector3Type));
#endregion #endregion
#region Eye #region Eye
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/isTracked", DeviceCategory.CenterEye, poseState: PoseState.IsTracked)); s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/isTracked", DeviceCategory.CenterEye, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/position", DeviceCategory.CenterEye, poseState: PoseState.Position)); s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/position", DeviceCategory.CenterEye, in_PoseState: PoseState.Position, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/rotation", DeviceCategory.CenterEye, poseState: PoseState.Rotation)); s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/rotation", DeviceCategory.CenterEye, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/velocity", DeviceCategory.CenterEye, poseState: PoseState.Velocity)); s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/velocity", DeviceCategory.CenterEye, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<EyeGaze>/pose/angularVelocity", DeviceCategory.CenterEye, poseState: PoseState.AngularVelocity)); s_InputActions.Add(new InputActionMapping("<EyeGaze>/pose/angularVelocity", DeviceCategory.CenterEye, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
#endregion #endregion
#region Controller #region Controller
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/isTracked", DeviceCategory.LeftController, poseState: PoseState.IsTracked)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/isTracked", DeviceCategory.LeftController, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/pointerPosition", DeviceCategory.LeftController, poseState: PoseState.Position)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/pointerPosition", DeviceCategory.LeftController, in_PoseState: PoseState.Position, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/pointerRotation", DeviceCategory.LeftController, poseState: PoseState.Rotation)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/pointerRotation", DeviceCategory.LeftController, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceVelocity", DeviceCategory.LeftController, poseState: PoseState.Velocity)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceVelocity", DeviceCategory.LeftController, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAngularVelocity", DeviceCategory.LeftController, poseState: PoseState.AngularVelocity)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAngularVelocity", DeviceCategory.LeftController, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAcceleration", DeviceCategory.LeftController, poseState: PoseState.Acceleration)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAcceleration", DeviceCategory.LeftController, in_PoseState: PoseState.Acceleration, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAngularAcceleration", DeviceCategory.LeftController, poseState: PoseState.AngularAcceleration)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/deviceAngularAcceleration", DeviceCategory.LeftController, in_PoseState: PoseState.AngularAcceleration, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{grip}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.GripValue)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{grip}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.GripValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{gripButton}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.GripPress)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{gripButton}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.GripPress, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{trigger}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.TriggerValue)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{trigger}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.TriggerValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/triggerTouched", DeviceCategory.LeftController, buttonEvent: ButtonEvent.TriggerTouch)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/triggerTouched", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.TriggerTouch, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{triggerButton}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.TriggerPress)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{triggerButton}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.TriggerPress, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxis}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Primary2DAxisValue)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxis}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Primary2DAxisValue, in_Type: kVector2Type));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxisTouch}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Primary2DAxisTouch)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxisTouch}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Primary2DAxisTouch, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxisClick}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Primary2DAxisPress)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primary2DAxisClick}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Primary2DAxisPress, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxis}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Secondary2DAxisValue)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxis}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Secondary2DAxisValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxisTouch}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Secondary2DAxisTouch)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxisTouch}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Secondary2DAxisTouch, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxisClick}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Secondary2DAxisPress)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondary2DAxisClick}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Secondary2DAxisPress, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primaryButton}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.PrimaryButton)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{primaryButton}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.PrimaryButton, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondaryButton}", DeviceCategory.LeftController, buttonEvent: ButtonEvent.SecondaryButton)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/{secondaryButton}", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.SecondaryButton, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/parkingTouched", DeviceCategory.LeftController, buttonEvent: ButtonEvent.ParkingTouch)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/parkingTouched", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.ParkingTouch, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{LeftHand}/menu", DeviceCategory.LeftController, buttonEvent: ButtonEvent.Menu)); s_InputActions.Add(new InputActionMapping("<XRController>{LeftHand}/menu", DeviceCategory.LeftController, in_ButtonEvent: ButtonEvent.Menu, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/isTracked", DeviceCategory.RightController, poseState: PoseState.IsTracked)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/isTracked", DeviceCategory.RightController, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/pointerPosition", DeviceCategory.RightController, poseState: PoseState.Position)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/pointerPosition", DeviceCategory.RightController, in_PoseState: PoseState.Position, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/pointerRotation", DeviceCategory.RightController, poseState: PoseState.Rotation)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/pointerRotation", DeviceCategory.RightController, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceVelocity", DeviceCategory.RightController, poseState: PoseState.Velocity)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceVelocity", DeviceCategory.RightController, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAngularVelocity", DeviceCategory.RightController, poseState: PoseState.AngularVelocity)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAngularVelocity", DeviceCategory.RightController, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAcceleration", DeviceCategory.RightController, poseState: PoseState.Acceleration)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAcceleration", DeviceCategory.RightController, in_PoseState: PoseState.Acceleration, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAngularAcceleration", DeviceCategory.RightController, poseState: PoseState.AngularAcceleration)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/deviceAngularAcceleration", DeviceCategory.RightController, in_PoseState: PoseState.AngularAcceleration, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{grip}", DeviceCategory.RightController, buttonEvent: ButtonEvent.GripValue)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{grip}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.GripValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{gripButton}", DeviceCategory.RightController, buttonEvent: ButtonEvent.GripPress)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{gripButton}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.GripPress, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{trigger}", DeviceCategory.RightController, buttonEvent: ButtonEvent.TriggerValue)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{trigger}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.TriggerValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/triggerTouched", DeviceCategory.RightController, buttonEvent: ButtonEvent.TriggerTouch)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/triggerTouched", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.TriggerTouch, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{triggerButton}", DeviceCategory.RightController, buttonEvent: ButtonEvent.TriggerPress)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{triggerButton}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.TriggerPress, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxis}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Primary2DAxisValue)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxis}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Primary2DAxisValue, in_Type: kVector2Type));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxisTouch}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Primary2DAxisTouch)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxisTouch}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Primary2DAxisTouch, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxisClick}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Primary2DAxisPress)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primary2DAxisClick}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Primary2DAxisPress, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxis}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Secondary2DAxisValue)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxis}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Secondary2DAxisValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxisTouch}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Secondary2DAxisTouch)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxisTouch}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Secondary2DAxisTouch, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxisClick}", DeviceCategory.RightController, buttonEvent: ButtonEvent.Secondary2DAxisPress)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondary2DAxisClick}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.Secondary2DAxisPress, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primaryButton}", DeviceCategory.RightController, buttonEvent: ButtonEvent.PrimaryButton)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{primaryButton}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.PrimaryButton, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondaryButton}", DeviceCategory.RightController, buttonEvent: ButtonEvent.SecondaryButton)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/{secondaryButton}", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.SecondaryButton, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<XRController>{RightHand}/parkingTouched", DeviceCategory.RightController, buttonEvent: ButtonEvent.ParkingTouch)); s_InputActions.Add(new InputActionMapping("<XRController>{RightHand}/parkingTouched", DeviceCategory.RightController, in_ButtonEvent: ButtonEvent.ParkingTouch, in_Type: kFloatType));
#endregion #endregion
#region Hand #region Hand
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/selectValue", DeviceCategory.LeftHand, handEvent: HandEvent.PinchValue)); s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/selectValue", DeviceCategory.LeftHand, in_HandEvent: HandEvent.PinchValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/pointerPose", DeviceCategory.LeftHand, handEvent: HandEvent.PinchPose)); s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/pointerPose", DeviceCategory.LeftHand, in_HandEvent: HandEvent.PinchPose, in_Type: kPoseType));
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/gripValue", DeviceCategory.LeftHand, handEvent: HandEvent.GraspValue)); s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/gripValue", DeviceCategory.LeftHand, in_HandEvent: HandEvent.GraspValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/devicePose", DeviceCategory.LeftHand, handEvent: HandEvent.GraspPose)); s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{LeftHand}/devicePose", DeviceCategory.LeftHand, in_HandEvent: HandEvent.GraspPose, in_Type: kPoseType));
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/selectValue", DeviceCategory.RightHand, handEvent: HandEvent.PinchValue)); s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/selectValue", DeviceCategory.RightHand, in_HandEvent: HandEvent.PinchValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/pointerPose", DeviceCategory.RightHand, handEvent: HandEvent.PinchPose)); s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/pointerPose", DeviceCategory.RightHand, in_HandEvent: HandEvent.PinchPose, in_Type: kPoseType));
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/gripValue", DeviceCategory.RightHand, handEvent: HandEvent.GraspValue)); s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/gripValue", DeviceCategory.RightHand, in_HandEvent: HandEvent.GraspValue, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/devicePose", DeviceCategory.RightHand, handEvent: HandEvent.GraspPose)); s_InputActions.Add(new InputActionMapping("<ViveHandInteraction>{RightHand}/devicePose", DeviceCategory.RightHand, in_HandEvent: HandEvent.GraspPose, in_Type: kPoseType));
#endregion #endregion
#region Tracker #region Tracker
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/isTracked", DeviceCategory.Tracker0, poseState: PoseState.IsTracked)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/isTracked", DeviceCategory.Tracker0, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePosition", DeviceCategory.Tracker0, poseState: PoseState.Position)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePosition", DeviceCategory.Tracker0, in_PoseState: PoseState.Position, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/deviceRotation", DeviceCategory.Tracker0, poseState: PoseState.Rotation)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/deviceRotation", DeviceCategory.Tracker0, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/velocity", DeviceCategory.Tracker0, poseState: PoseState.Velocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/velocity", DeviceCategory.Tracker0, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/angularVelocity", DeviceCategory.Tracker0, poseState: PoseState.AngularVelocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 0}/devicePose/angularVelocity", DeviceCategory.Tracker0, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/isTracked", DeviceCategory.Tracker1, poseState: PoseState.IsTracked)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/isTracked", DeviceCategory.Tracker1, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePosition", DeviceCategory.Tracker1, poseState: PoseState.Position)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePosition", DeviceCategory.Tracker1, in_PoseState: PoseState.Position, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/deviceRotation", DeviceCategory.Tracker1, poseState: PoseState.Rotation)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/deviceRotation", DeviceCategory.Tracker1, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/velocity", DeviceCategory.Tracker1, poseState: PoseState.Velocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/velocity", DeviceCategory.Tracker1, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/angularVelocity", DeviceCategory.Tracker1, poseState: PoseState.AngularVelocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 1}/devicePose/angularVelocity", DeviceCategory.Tracker1, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/isTracked", DeviceCategory.Tracker2, poseState: PoseState.IsTracked)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/isTracked", DeviceCategory.Tracker2, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePosition", DeviceCategory.Tracker2, poseState: PoseState.Position)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePosition", DeviceCategory.Tracker2, in_PoseState: PoseState.Position, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/deviceRotation", DeviceCategory.Tracker2, poseState: PoseState.Rotation)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/deviceRotation", DeviceCategory.Tracker2, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/velocity", DeviceCategory.Tracker2, poseState: PoseState.Velocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/velocity", DeviceCategory.Tracker2, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/angularVelocity", DeviceCategory.Tracker2, poseState: PoseState.AngularVelocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 2}/devicePose/angularVelocity", DeviceCategory.Tracker2, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/isTracked", DeviceCategory.Tracker3, poseState: PoseState.IsTracked)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/isTracked", DeviceCategory.Tracker3, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePosition", DeviceCategory.Tracker3, poseState: PoseState.Position)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePosition", DeviceCategory.Tracker3, in_PoseState: PoseState.Position, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/deviceRotation", DeviceCategory.Tracker3, poseState: PoseState.Rotation)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/deviceRotation", DeviceCategory.Tracker3, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/velocity", DeviceCategory.Tracker3, poseState: PoseState.Velocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/velocity", DeviceCategory.Tracker3, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/angularVelocity", DeviceCategory.Tracker3, poseState: PoseState.AngularVelocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 3}/devicePose/angularVelocity", DeviceCategory.Tracker3, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/isTracked", DeviceCategory.Tracker4, poseState: PoseState.IsTracked)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/isTracked", DeviceCategory.Tracker4, in_PoseState: PoseState.IsTracked, in_Type: kFloatType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePosition", DeviceCategory.Tracker4, poseState: PoseState.Position)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePosition", DeviceCategory.Tracker4, in_PoseState: PoseState.Position, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/deviceRotation", DeviceCategory.Tracker4, poseState: PoseState.Rotation)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/deviceRotation", DeviceCategory.Tracker4, in_PoseState: PoseState.Rotation, in_Type: kQuaternionType));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/velocity", DeviceCategory.Tracker4, poseState: PoseState.Velocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/velocity", DeviceCategory.Tracker4, in_PoseState: PoseState.Velocity, in_Type: kVector3Type));
inputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/angularVelocity", DeviceCategory.Tracker4, poseState: PoseState.AngularVelocity)); s_InputActions.Add(new InputActionMapping("<ViveXRTracker>{Ultimate Tracker 4}/devicePose/angularVelocity", DeviceCategory.Tracker4, in_PoseState: PoseState.AngularVelocity, in_Type: kVector3Type));
#endregion #endregion
} }
private static bool GetInputActionMapping(DeviceCategory device, PoseState poseState, out InputActionMapping inputActionMapping)
{
inputActionMapping = default;
for (int i = 0; i < s_InputActions.Count; i++)
{
var action = s_InputActions[i];
if (action.device == device && action.poseState == poseState)
{
inputActionMapping = action;
return true;
}
}
return false;
}
private static bool GetInputActionMapping(DeviceCategory device, ButtonEvent buttonEvent, out InputActionMapping inputActionMapping)
{
inputActionMapping = default;
for (int i = 0; i < s_InputActions.Count; i++)
{
var action = s_InputActions[i];
if (action.device == device && action.buttonEvent == buttonEvent)
{
inputActionMapping = action;
return true;
}
}
return false;
}
private static bool GetInputActionMapping(DeviceCategory device, HandEvent handEvent, out InputActionMapping inputActionMapping)
{
inputActionMapping = default;
for (int i = 0; i < s_InputActions.Count; i++)
{
var action = s_InputActions[i];
if (action.device == device && action.handEvent == handEvent)
{
inputActionMapping = action;
return true;
}
}
return false;
}
private static void CheckHandUpdated() private static void CheckHandUpdated()
{ {
if (Time.frameCount > leftHand.updateTime || int frameCount = Time.frameCount;
Time.frameCount > rightHand.updateTime) if (frameCount > m_LeftHand.updateTime ||
frameCount > m_RightHand.updateTime)
{ {
ViveHandTracking viveHand = OpenXRSettings.Instance.GetFeature<ViveHandTracking>();
if (viveHand)
{
UpdateViveHand(true, viveHand);
UpdateViveHand(false, viveHand);
}
#if UNITY_XR_HANDS #if UNITY_XR_HANDS
HandTracking xrHand = OpenXRSettings.Instance.GetFeature<HandTracking>(); if (m_IsSupportViveHand || m_IsSupportXrHand)
if (xrHand)
{ {
if (handSubsystem == null || !handSubsystem.running) if (m_HandSubsystem == null || !m_HandSubsystem.running)
{ {
if (handSubsystem != null && !handSubsystem.running) if (m_HandSubsystem != null)
{ {
handSubsystem.updatedHands -= OnUpdatedHands; m_HandSubsystem.updatedHands -= OnUpdatedHands;
handSubsystem = null; m_HandSubsystem = null;
} }
var handSubsystems = new List<XRHandSubsystem>(); m_HandSubsystems.Clear();
SubsystemManager.GetSubsystems(handSubsystems); SubsystemManager.GetSubsystems(m_HandSubsystems);
for (var i = 0; i < handSubsystems.Count; ++i) for (var i = 0; i < m_HandSubsystems.Count; ++i)
{ {
var xrHnad = handSubsystems[i]; var xrHand = m_HandSubsystems[i];
if (xrHnad.running) if (xrHand.running)
{ {
handSubsystem = xrHnad; m_HandSubsystem = xrHand;
m_HandSubsystem.updatedHands += OnUpdatedHands;
break; break;
} }
} }
if (handSubsystem != null && handSubsystem.running) }
}
#else
if (m_IsSupportViveHand)
{ {
handSubsystem.updatedHands += OnUpdatedHands; UpdateViveHand(true);
} UpdateViveHand(false);
}
} }
#endif #endif
} }
} }
private static void UpdateViveHand(bool isLeft, ViveHandTracking viveHand) private static void UpdateViveHand(bool isLeft)
{ {
bool isUpdated = viveHand.GetJointLocations(isLeft, out XrHandJointLocationEXT[] viveJoints); bool isUpdated = XR_EXT_hand_tracking.Interop.GetJointLocations(isLeft, out XrHandJointLocationEXT[] viveJoints);
JointData[] joints = new JointData[viveJoints.Length]; for (int i = 0; i < m_JointBuffer.Length; i++)
for (int i = 0; i < joints.Length; i++)
{ {
bool isValid = isUpdated && bool isValid = isUpdated &&
viveJoints[i].locationFlags.HasFlag(XrSpaceLocationFlags.XR_SPACE_LOCATION_POSITION_TRACKED_BIT) && viveJoints[i].locationFlags.HasFlag(XrSpaceLocationFlags.XR_SPACE_LOCATION_POSITION_TRACKED_BIT) &&
viveJoints[i].locationFlags.HasFlag(XrSpaceLocationFlags.XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT); viveJoints[i].locationFlags.HasFlag(XrSpaceLocationFlags.XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT);
Vector3 position = viveJoints[i].pose.position.ToUnityVector(); Vector3 position = viveJoints[i].pose.position.ToUnityVector();
Quaternion rotation = viveJoints[i].pose.orientation.ToUnityQuaternion(); Quaternion rotation = viveJoints[i].pose.orientation.ToUnityQuaternion();
joints[i] = new JointData(isValid, position, rotation); m_JointBuffer[i] = new JointData(isValid, position, rotation);
} }
if (isLeft) if (isLeft)
{ {
leftHand.Update(joints); m_LeftHand.Update(m_JointBuffer);
} }
else else
{ {
rightHand.Update(joints); m_RightHand.Update(m_JointBuffer);
} }
} }
@@ -732,24 +796,30 @@ namespace VIVE.OpenXR.Toolkits.Common
} }
} }
private static void UpdateXRHand(bool isLeft, XRHandSubsystem xrHnad, bool isUpdated) private static void UpdateXRHand(bool isLeft, XRHandSubsystem xrHand, bool isUpdated)
{ {
JointData[] joints = new JointData[(int)HandJointType.Count]; for (int i = 0; i < m_JointBuffer.Length; i++)
for (int i = 0; i < joints.Length; i++)
{ {
XRHandJointID jointId = JointTypeToXRId(i); XRHandJointID jointId = JointTypeToXRId(i);
XRHandJoint joint = (isLeft ? xrHnad.leftHand : xrHnad.rightHand).GetJoint(jointId); XRHandJoint joint = (isLeft ? xrHand.leftHand : xrHand.rightHand).GetJoint(jointId);
bool isValid = isUpdated && joint.trackingState.HasFlag(XRHandJointTrackingState.Pose);
joint.TryGetPose(out Pose pose); if (isUpdated && joint.trackingState.HasFlag(XRHandJointTrackingState.Pose))
joints[i] = new JointData(isValid, pose.position, pose.rotation);
}
if (isLeft)
{ {
leftHand.Update(joints); joint.TryGetPose(out Pose pose);
m_JointBuffer[i] = new JointData(true, pose.position, pose.rotation);
} }
else else
{ {
rightHand.Update(joints); m_JointBuffer[i] = new JointData(false, Vector3.zero, Quaternion.identity);
}
}
if (isLeft)
{
m_LeftHand.Update(m_JointBuffer);
}
else
{
m_RightHand.Update(m_JointBuffer);
} }
} }

View File

@@ -5,8 +5,7 @@ using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.XR.OpenXR; using UnityEngine.XR.OpenXR;
using System.Threading.Tasks; using System.Linq;
using VIVE.OpenXR;
namespace VIVE.OpenXR.Passthrough namespace VIVE.OpenXR.Passthrough
{ {
@@ -27,13 +26,7 @@ namespace VIVE.OpenXR.Passthrough
return false; return false;
} }
#if UNITY_STANDALONE private static Dictionary<XrPassthroughHTC, PassthroughLayer> layersDict = new Dictionary<XrPassthroughHTC, PassthroughLayer>();
private static Dictionary<XrPassthroughHTC, XrCompositionLayerPassthroughHTC> passthrough2Layer = new Dictionary<XrPassthroughHTC, XrCompositionLayerPassthroughHTC>();
private static Dictionary<XrPassthroughHTC, IntPtr> passthrough2LayerPtr = new Dictionary<XrPassthroughHTC, IntPtr>();
private static Dictionary<XrPassthroughHTC, bool> passthrough2IsUnderLay= new Dictionary<XrPassthroughHTC, bool>();
private static Dictionary<XrPassthroughHTC, XrPassthroughMeshTransformInfoHTC> passthrough2meshTransform = new Dictionary<XrPassthroughHTC, XrPassthroughMeshTransformInfoHTC>();
private static Dictionary<XrPassthroughHTC, IntPtr> passthrough2meshTransformInfoPtr = new Dictionary<XrPassthroughHTC, IntPtr>();
#endif
#region Public APIs #region Public APIs
/// <summary> /// <summary>
@@ -58,42 +51,32 @@ namespace VIVE.OpenXR.Passthrough
} }
XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC( XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC(
XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC, XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC,
#if UNITY_ANDROID
IntPtr.Zero,
#else
new IntPtr(6), //Enter IntPtr(0) for backward compatibility (using createPassthrough to enable the passthrough feature), or enter IntPtr(6) to enable the passthrough feature based on the layer submitted to endframe. new IntPtr(6), //Enter IntPtr(0) for backward compatibility (using createPassthrough to enable the passthrough feature), or enter IntPtr(6) to enable the passthrough feature based on the layer submitted to endframe.
#endif
XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PLANAR_HTC XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PLANAR_HTC
); );
#if UNITY_ANDROID
res = passthroughFeature.CreatePassthroughHTC(createInfo, out passthrough, layerType, compositionDepth, onDestroyPassthroughSessionHandler);
DEBUG("CreatePlanarPassthrough() CreatePassthroughHTC result: " + res + ", passthrough: " + passthrough);
#endif
#if UNITY_STANDALONE
res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough); res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough);
if(res == XrResult.XR_SUCCESS) if(res == XrResult.XR_SUCCESS)
{ {
XrPassthroughColorHTC passthroughColor = new XrPassthroughColorHTC( PassthroughLayer layer = new PassthroughLayer(passthrough, layerType);
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_COLOR_HTC, var xrLayer = PassthroughLayer.MakeEmptyLayer();
in_next: IntPtr.Zero, xrLayer.passthrough = passthrough;
in_alpha: alpha); xrLayer.layerFlags = (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
XrCompositionLayerPassthroughHTC compositionLayerPassthrough = new XrCompositionLayerPassthroughHTC( xrLayer.color.alpha = alpha;
in_type: XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC, layer.SetLayer(xrLayer);
in_next: IntPtr.Zero,
in_layerFlags: (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT, layersDict.Add(passthrough, layer);
in_space: 0,
in_passthrough: passthrough,
in_color: passthroughColor);
passthrough2Layer.Add(passthrough, compositionLayerPassthrough);
IntPtr layerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrCompositionLayerPassthroughHTC)));
passthrough2LayerPtr.Add(passthrough, layerPtr);
if (layerType == CompositionLayer.LayerType.Underlay)
passthrough2IsUnderLay.Add(passthrough, true);
if (layerType == CompositionLayer.LayerType.Overlay)
passthrough2IsUnderLay.Add(passthrough, false);
} }
#endif
if (res == XrResult.XR_SUCCESS) if (res == XrResult.XR_SUCCESS)
{ {
SetPassthroughAlpha(passthrough, alpha); SetPassthroughAlpha(passthrough, alpha);
} }
return res; return res;
} }
@@ -138,54 +121,34 @@ namespace VIVE.OpenXR.Passthrough
XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC( XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC(
XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC, XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC,
#if UNITY_ANDROID
IntPtr.Zero,
#else
new IntPtr(6), //Enter IntPtr(0) for backward compatibility (using createPassthrough to enable the passthrough feature), or enter IntPtr(6) to enable the passthrough feature based on the layer submitted to endframe. new IntPtr(6), //Enter IntPtr(0) for backward compatibility (using createPassthrough to enable the passthrough feature), or enter IntPtr(6) to enable the passthrough feature based on the layer submitted to endframe.
#endif
XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PROJECTED_HTC XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PROJECTED_HTC
); );
#if UNITY_STANDALONE
res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough); res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough);
if (res == XrResult.XR_SUCCESS) if (res == XrResult.XR_SUCCESS)
{ {
XrPassthroughMeshTransformInfoHTC PassthroughMeshTransformInfo = new XrPassthroughMeshTransformInfoHTC( var layer = new PassthroughLayer(passthrough, layerType);
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC, var xrLayer = PassthroughLayer.MakeEmptyLayer();
in_next: IntPtr.Zero, xrLayer.passthrough = passthrough;
in_vertexCount: 0, xrLayer.layerFlags = (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
in_vertices: new XrVector3f[0], xrLayer.space = 0;
in_indexCount: 0, xrLayer.color.alpha = alpha;
in_indices: new UInt32[0], layer.SetLayer(xrLayer);
in_baseSpace: XR_HTC_passthrough.Interop.GetTrackingSpace(), var xrMesh = PassthroughLayer.MakeMeshTransform();
in_time: XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime,
in_pose: new XrPosef(), xrMesh.time = XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime;
in_scale: new XrVector3f() xrMesh.baseSpace = XR_HTC_passthrough.Interop.GetTrackingSpace();
); xrMesh.scale = new XrVector3f(meshScale.x, meshScale.y, meshScale.z);
IntPtr meshTransformInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrPassthroughMeshTransformInfoHTC))); layer.SetMeshTransform(xrMesh);
Marshal.StructureToPtr(PassthroughMeshTransformInfo, meshTransformInfoPtr, false);
XrPassthroughColorHTC passthroughColor = new XrPassthroughColorHTC( layersDict.Add(passthrough, layer);
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_COLOR_HTC,
in_next: IntPtr.Zero,
in_alpha: alpha);
XrCompositionLayerPassthroughHTC compositionLayerPassthrough = new XrCompositionLayerPassthroughHTC(
in_type: XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC,
in_next: meshTransformInfoPtr,
in_layerFlags: (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT,
in_space: 0,
in_passthrough: passthrough,
in_color: passthroughColor);
passthrough2meshTransform.Add(passthrough, PassthroughMeshTransformInfo);
passthrough2meshTransformInfoPtr.Add(passthrough, meshTransformInfoPtr);
passthrough2Layer.Add(passthrough, compositionLayerPassthrough);
IntPtr layerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrCompositionLayerPassthroughHTC)));
passthrough2LayerPtr.Add(passthrough, layerPtr);
if (layerType == CompositionLayer.LayerType.Underlay)
passthrough2IsUnderLay.Add(passthrough, true);
if (layerType == CompositionLayer.LayerType.Overlay)
passthrough2IsUnderLay.Add(passthrough, false);
} }
#endif
#if UNITY_ANDROID
res = passthroughFeature.CreatePassthroughHTC(createInfo, out passthrough, layerType, compositionDepth, onDestroyPassthroughSessionHandler);
DEBUG("CreateProjectedPassthrough() CreatePassthroughHTC result: " + res + ", passthrough: " + passthrough);
#endif
if (res == XrResult.XR_SUCCESS) if (res == XrResult.XR_SUCCESS)
{ {
SetPassthroughAlpha(passthrough, alpha); SetPassthroughAlpha(passthrough, alpha);
@@ -219,54 +182,30 @@ namespace VIVE.OpenXR.Passthrough
XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC( XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC(
XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC, XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC,
#if UNITY_ANDROID
IntPtr.Zero,
#else
new IntPtr(6), //Enter IntPtr(0) for backward compatibility (using createPassthrough to enable the passthrough feature), or enter IntPtr(6) to enable the passthrough feature based on the layer submitted to endframe. new IntPtr(6), //Enter IntPtr(0) for backward compatibility (using createPassthrough to enable the passthrough feature), or enter IntPtr(6) to enable the passthrough feature based on the layer submitted to endframe.
#endif
XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PROJECTED_HTC XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PROJECTED_HTC
); );
#if UNITY_STANDALONE
res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough); res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough);
if (res == XrResult.XR_SUCCESS) if (res == XrResult.XR_SUCCESS)
{ {
XrPassthroughMeshTransformInfoHTC PassthroughMeshTransformInfo = new XrPassthroughMeshTransformInfoHTC( var layer = new PassthroughLayer(passthrough, layerType);
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC, var xrLayer = PassthroughLayer.MakeEmptyLayer();
in_next: IntPtr.Zero, xrLayer.passthrough = passthrough;
in_vertexCount: 0, xrLayer.layerFlags = (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
in_vertices: new XrVector3f[0], xrLayer.color.alpha = alpha;
in_indexCount: 0, layer.SetLayer(xrLayer);
in_indices: new UInt32[0],
in_baseSpace: XR_HTC_passthrough.Interop.GetTrackingSpace(), var xrMesh = PassthroughLayer.MakeMeshTransform();
in_time: XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime, layer.SetMeshTransform(xrMesh, true);
in_pose: new XrPosef(),
in_scale: new XrVector3f() layersDict.Add(passthrough, layer);
);
IntPtr meshTransformInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrPassthroughMeshTransformInfoHTC)));
Marshal.StructureToPtr(PassthroughMeshTransformInfo, meshTransformInfoPtr, false);
XrPassthroughColorHTC passthroughColor = new XrPassthroughColorHTC(
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_COLOR_HTC,
in_next: IntPtr.Zero,
in_alpha: alpha);
XrCompositionLayerPassthroughHTC compositionLayerPassthrough = new XrCompositionLayerPassthroughHTC(
in_type: XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC,
in_next: meshTransformInfoPtr,
in_layerFlags: (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT,
in_space: 0,
in_passthrough: passthrough,
in_color: passthroughColor);
passthrough2meshTransform.Add(passthrough, PassthroughMeshTransformInfo);
passthrough2meshTransformInfoPtr.Add(passthrough, meshTransformInfoPtr);
passthrough2Layer.Add(passthrough, compositionLayerPassthrough);
IntPtr layerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XrCompositionLayerPassthroughHTC)));
passthrough2LayerPtr.Add(passthrough, layerPtr);
if (layerType == CompositionLayer.LayerType.Underlay)
passthrough2IsUnderLay.Add(passthrough, true);
if (layerType == CompositionLayer.LayerType.Overlay)
passthrough2IsUnderLay.Add(passthrough, false);
} }
#endif
#if UNITY_ANDROID
res = passthroughFeature.CreatePassthroughHTC(createInfo, out passthrough, layerType, onDestroyPassthroughSessionHandler);
DEBUG("CreateProjectedPassthrough() CreatePassthroughHTC result: " + res + ", passthrough: " + passthrough);
#endif
if (res == XrResult.XR_SUCCESS) if (res == XrResult.XR_SUCCESS)
{ {
SetPassthroughAlpha(passthrough, alpha); SetPassthroughAlpha(passthrough, alpha);
@@ -275,35 +214,10 @@ namespace VIVE.OpenXR.Passthrough
return res; return res;
} }
#if UNITY_STANDALONE private static void SubmitLayer()
private static async void SubmitLayer()
{ {
await Task.Run(() => { passthroughFeature.SubmitLayers(layersDict.Values.ToList());
int layerListCount = 0;
while(layerListCount == 0)
{
System.Threading.Thread.Sleep(1);
XR_HTC_passthrough.Interop.GetOriginEndFrameLayerList(out List<IntPtr> layerList);//GetOriginEndFrameLayers
layerListCount = layerList.Count;
foreach (var passthrough in passthrough2IsUnderLay.Keys)
{
//Get and submit layer list
if (layerListCount != 0)
{
Marshal.StructureToPtr(passthrough2Layer[passthrough], passthrough2LayerPtr[passthrough], false);
if (passthrough2IsUnderLay[passthrough])
layerList.Insert(0, passthrough2LayerPtr[passthrough]);
else
layerList.Insert(1, passthrough2LayerPtr[passthrough]);
} }
}
if(layerListCount != 0)
XR_HTC_passthrough.Interop.SubmitLayers(layerList);
}
});
}
#endif
/// <summary> /// <summary>
/// To Destroying a passthrough. /// To Destroying a passthrough.
@@ -326,23 +240,17 @@ namespace VIVE.OpenXR.Passthrough
return res; return res;
} }
#if UNITY_STANDALONE if (layersDict.ContainsKey(passthrough))
XrPassthroughHTC pt = passthrough2Layer[passthrough].passthrough; {
XR_HTC_passthrough.xrDestroyPassthroughHTC(pt); XR_HTC_passthrough.xrDestroyPassthroughHTC(passthrough);
passthrough2IsUnderLay.Remove(passthrough); var layer = layersDict[passthrough];
layer.Dispose();
layersDict.Remove(passthrough);
}
SubmitLayer(); SubmitLayer();
passthrough2Layer.Remove(pt);
if(passthrough2LayerPtr.ContainsKey(passthrough)) Marshal.FreeHGlobal(passthrough2LayerPtr[passthrough]);
passthrough2LayerPtr.Remove(passthrough);
if(passthrough2meshTransformInfoPtr.ContainsKey(passthrough)) Marshal.FreeHGlobal(passthrough2meshTransformInfoPtr[passthrough]);
passthrough2meshTransformInfoPtr.Remove(passthrough);
passthrough2meshTransform.Remove(passthrough);
res = XrResult.XR_SUCCESS; res = XrResult.XR_SUCCESS;
#elif UNITY_ANDROID
res = passthroughFeature.DestroyPassthroughHTC(passthrough);
DEBUG("DestroyPassthrough() DestroyPassthroughHTC result: " + res + ", passthrough: " + passthrough);
#endif
return res; return res;
} }
@@ -368,36 +276,18 @@ namespace VIVE.OpenXR.Passthrough
return ret; return ret;
} }
#if UNITY_ANDROID if (layersDict.ContainsKey(passthrough))
if (autoClamp)
{ {
ret = passthroughFeature.SetAlpha(passthrough, Mathf.Clamp01(alpha)); var layer = layersDict[passthrough];
} var xrLayer = layer.GetLayer();
else xrLayer.color.alpha = alpha;
{ layer.SetLayer(xrLayer);
if (alpha < 0f || alpha > 1f)
{
ERROR("SetPassthroughAlpha: Alpha out of range");
return ret;
}
ret = passthroughFeature.SetAlpha(passthrough, alpha);
}
DEBUG("SetPassthroughAlpha() SetAlpha result: " + ret + ", passthrough: " + passthrough);
#endif
#if UNITY_STANDALONE
if (passthrough2Layer.ContainsKey(passthrough))
{
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
layer.color.alpha = alpha;
passthrough2Layer[passthrough] = layer;
SubmitLayer(); SubmitLayer();
ret = true; ret = true;
} }
else else
ret = false; ret = false;
#endif
return ret; return ret;
} }
@@ -425,47 +315,20 @@ namespace VIVE.OpenXR.Passthrough
return ret; return ret;
} }
XrVector3f[] vertexBufferXrVector = new XrVector3f[vertexBuffer.Length]; if (layersDict[passthrough] == null)
for (int i = 0; i < vertexBuffer.Length; i++)
{ {
vertexBufferXrVector[i] = OpenXRHelper.ToOpenXRVector(vertexBuffer[i], convertFromUnityToOpenXR); ERROR("Passthrough layer not found.");
}
uint[] indexBufferUint = new uint[indexBuffer.Length];
for (int i = 0; i < indexBuffer.Length; i++)
{
indexBufferUint[i] = (uint)indexBuffer[i];
}
#if UNITY_STANDALONE
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
MeshTransformInfo.vertexCount = (uint)vertexBuffer.Length;
MeshTransformInfo.vertices = vertexBufferXrVector;
MeshTransformInfo.indexCount = (uint)indexBuffer.Length;
MeshTransformInfo.indices = indexBufferUint;
passthrough2meshTransform[passthrough] = MeshTransformInfo;
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
layer.next = passthrough2meshTransformInfoPtr[passthrough];
passthrough2Layer[passthrough] = layer;
SubmitLayer();
ret = true;
}
else
ret = false;
#endif
//Note: Ignore Clock-Wise definition of index buffer for now as passthrough extension does not have back-face culling
#if UNITY_ANDROID
ret = passthroughFeature.SetMesh(passthrough, (uint)vertexBuffer.Length, vertexBufferXrVector, (uint)indexBuffer.Length, indexBufferUint); ;
DEBUG("SetProjectedPassthroughMesh() SetMesh result: " + ret + ", passthrough: " + passthrough);
#endif
return ret; return ret;
} }
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
layer.SetMeshData(ref xrMesh, vertexBuffer, indexBuffer, convertFromUnityToOpenXR);
layer.SetMeshTransform(xrMesh);
SubmitLayer();
return true;
}
/// <summary> /// <summary>
/// Modifies the mesh transform of a projected passthrough layer. /// Modifies the mesh transform of a projected passthrough layer.
/// </summary> /// </summary>
@@ -508,31 +371,24 @@ namespace VIVE.OpenXR.Passthrough
XrVector3f meshXrScale = OpenXRHelper.ToOpenXRVector(meshScale, false); XrVector3f meshXrScale = OpenXRHelper.ToOpenXRVector(meshScale, false);
#if UNITY_STANDALONE if (layersDict[passthrough] == null)
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{ {
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough]; ERROR("Passthrough layer not found.");
MeshTransformInfo.pose = meshXrPose;
MeshTransformInfo.scale = meshXrScale;
passthrough2meshTransform[passthrough] = MeshTransformInfo;
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
layer.next = passthrough2meshTransformInfoPtr[passthrough];
passthrough2Layer[passthrough] = layer;
SubmitLayer();
ret = true;
}
else
ret = false;
#endif
#if UNITY_ANDROID
ret = passthroughFeature.SetMeshTransform(passthrough, passthroughFeature.GetXrSpaceFromSpaceType(spaceType), meshXrPose, meshXrScale);
DEBUG("SetProjectedPassthroughMeshTransform() SetMeshTransform result: " + ret + ", passthrough: " + passthrough);
#endif
return ret; return ret;
} }
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
xrMesh.pose = meshXrPose;
xrMesh.scale = meshXrScale;
xrMesh.time = XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime;
xrMesh.baseSpace = passthroughFeature.GetXrSpaceFromSpaceType(spaceType);
layer.SetMeshTransform(xrMesh);
SubmitLayer();
return true;
}
/// <summary> /// <summary>
/// Modifies layer type and composition depth of a passthrough layer. /// Modifies layer type and composition depth of a passthrough layer.
/// </summary> /// </summary>
@@ -550,24 +406,20 @@ namespace VIVE.OpenXR.Passthrough
return ret; return ret;
} }
#if UNITY_STANDALONE if (layersDict[passthrough] == null)
if (passthrough2IsUnderLay.ContainsKey(passthrough))
{ {
passthrough2IsUnderLay[passthrough] = layerType == CompositionLayer.LayerType.Underlay ? true : false; ERROR("Passthrough layer not found.");
SubmitLayer();
ret = true;
}
else
ret = false;
#endif
#if UNITY_ANDROID
ret = passthroughFeature.SetLayerType(passthrough, layerType, compositionDepth);
DEBUG("SetPassthroughLayerType() SetLayerType result: " + ret + ", passthrough: " + passthrough);
#endif
return ret; return ret;
} }
var layer = layersDict[passthrough];
layer.LayerType = layerType;
layer.Depth = (int)compositionDepth;
SubmitLayer();
return true;
}
/// <summary> /// <summary>
/// Modifies the space of a projected passthrough layer. /// Modifies the space of a projected passthrough layer.
/// </summary> /// </summary>
@@ -584,30 +436,20 @@ namespace VIVE.OpenXR.Passthrough
return ret; return ret;
} }
#if UNITY_STANDALONE if (layersDict[passthrough] == null)
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{ {
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough]; ERROR("Passthrough layer not found.");
MeshTransformInfo.baseSpace = passthroughFeature.GetXrSpaceFromSpaceType(spaceType);
passthrough2meshTransform[passthrough] = MeshTransformInfo;
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
layer.next = passthrough2meshTransformInfoPtr[passthrough];
passthrough2Layer[passthrough] = layer;
SubmitLayer();
ret = true;
}
else
ret = false;
#endif
#if UNITY_ANDROID
ret = passthroughFeature.SetMeshTransformSpace(passthrough, passthroughFeature.GetXrSpaceFromSpaceType(spaceType));
DEBUG("SetProjectedPassthroughSpaceType() SetMeshTransformSpace result: " + ret + ", passthrough: " + passthrough);
#endif
return ret; return ret;
} }
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
xrMesh.baseSpace = passthroughFeature.GetXrSpaceFromSpaceType(spaceType);
layer.SetMeshTransform(xrMesh);
SubmitLayer();
return true;
}
/// <summary> /// <summary>
/// Modifies the mesh position of a projected passthrough layer. /// Modifies the mesh position of a projected passthrough layer.
/// </summary> /// </summary>
@@ -639,32 +481,20 @@ namespace VIVE.OpenXR.Passthrough
trackingSpaceMeshPosition = trackingSpaceLayerPoseTRS.GetColumn(3); //4th Column of TRS Matrix is the position trackingSpaceMeshPosition = trackingSpaceLayerPoseTRS.GetColumn(3); //4th Column of TRS Matrix is the position
} }
#if UNITY_STANDALONE if (layersDict[passthrough] == null)
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{ {
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough]; ERROR("Passthrough layer not found.");
XrPosef meshXrPose = MeshTransformInfo.pose;
meshXrPose.position = OpenXRHelper.ToOpenXRVector(trackingSpaceMeshPosition, convertFromUnityToOpenXR); ;
MeshTransformInfo.pose = meshXrPose;
passthrough2meshTransform[passthrough] = MeshTransformInfo;
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
layer.next = passthrough2meshTransformInfoPtr[passthrough];
passthrough2Layer[passthrough] = layer;
SubmitLayer();
ret = true;
}
else
ret = false;
#endif
#if UNITY_ANDROID
ret = passthroughFeature.SetMeshTransformPosition(passthrough, OpenXRHelper.ToOpenXRVector(trackingSpaceMeshPosition, convertFromUnityToOpenXR));
DEBUG("SetProjectedPassthroughMeshPosition() SetMeshTransformPosition result: " + ret + ", passthrough: " + passthrough);
#endif
return ret; return ret;
} }
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
xrMesh.pose.position = OpenXRHelper.ToOpenXRVector(trackingSpaceMeshPosition, convertFromUnityToOpenXR);
layer.SetMeshTransform(xrMesh);
SubmitLayer();
return true;
}
/// <summary> /// <summary>
/// Modifies the mesh orientation of a projected passthrough layer. /// Modifies the mesh orientation of a projected passthrough layer.
/// </summary> /// </summary>
@@ -696,32 +526,20 @@ namespace VIVE.OpenXR.Passthrough
trackingSpaceMeshRotation = Quaternion.LookRotation(trackingSpaceLayerPoseTRS.GetColumn(2), trackingSpaceLayerPoseTRS.GetColumn(1)); trackingSpaceMeshRotation = Quaternion.LookRotation(trackingSpaceLayerPoseTRS.GetColumn(2), trackingSpaceLayerPoseTRS.GetColumn(1));
} }
#if UNITY_STANDALONE if (layersDict[passthrough] == null)
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{ {
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough]; ERROR("Passthrough layer not found.");
XrPosef meshXrPose = MeshTransformInfo.pose;
meshXrPose.orientation = OpenXRHelper.ToOpenXRQuaternion(trackingSpaceMeshRotation, convertFromUnityToOpenXR);
MeshTransformInfo.pose = meshXrPose;
passthrough2meshTransform[passthrough] = MeshTransformInfo;
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
layer.next = passthrough2meshTransformInfoPtr[passthrough];
passthrough2Layer[passthrough] = layer;
SubmitLayer();
ret = true;
}
else
ret = false;
#endif
#if UNITY_ANDROID
ret = passthroughFeature.SetMeshTransformOrientation(passthrough, OpenXRHelper.ToOpenXRQuaternion(trackingSpaceMeshRotation, convertFromUnityToOpenXR));
DEBUG("SetProjectedPassthroughMeshOrientation() SetMeshTransformOrientation result: " + ret + ", passthrough: " + passthrough);
#endif
return ret; return ret;
} }
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
xrMesh.pose.orientation = OpenXRHelper.ToOpenXRQuaternion(trackingSpaceMeshRotation, convertFromUnityToOpenXR);
layer.SetMeshTransform(xrMesh);
SubmitLayer();
return true;
}
/// <summary> /// <summary>
/// Modifies the mesh scale of a passthrough layer. /// Modifies the mesh scale of a passthrough layer.
/// </summary> /// </summary>
@@ -738,30 +556,20 @@ namespace VIVE.OpenXR.Passthrough
return ret; return ret;
} }
#if UNITY_STANDALONE if (layersDict[passthrough] == null)
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{ {
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough]; ERROR("Passthrough layer not found.");
MeshTransformInfo.scale = OpenXRHelper.ToOpenXRVector(meshScale, false);
passthrough2meshTransform[passthrough] = MeshTransformInfo;
Marshal.StructureToPtr(MeshTransformInfo, passthrough2meshTransformInfoPtr[passthrough], false);
XrCompositionLayerPassthroughHTC layer = passthrough2Layer[passthrough];
layer.next = passthrough2meshTransformInfoPtr[passthrough];
passthrough2Layer[passthrough] = layer;
SubmitLayer();
ret = true;
}
else
ret = false;
#endif
#if UNITY_ANDROID
ret = passthroughFeature.SetMeshTransformScale(passthrough, OpenXRHelper.ToOpenXRVector(meshScale, false));
DEBUG("SetProjectedPassthroughScale() SetMeshTransformScale result: " + ret + ", passthrough: " + passthrough);
#endif
return ret; return ret;
} }
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
xrMesh.scale = OpenXRHelper.ToOpenXRVector(meshScale, false);
layer.SetMeshTransform(xrMesh);
SubmitLayer();
return true;
}
/// <summary> /// <summary>
/// To get the list of IDs of active passthrough layers. /// To get the list of IDs of active passthrough layers.
/// </summary> /// </summary>

View File

@@ -699,6 +699,7 @@ GameObject:
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 4806409459047702211} - component: {fileID: 4806409459047702211}
- component: {fileID: 5568897672767345397}
- component: {fileID: 1039589470112983849} - component: {fileID: 1039589470112983849}
- component: {fileID: 1039589470112983840} - component: {fileID: 1039589470112983840}
- component: {fileID: 1039589470112983852} - component: {fileID: 1039589470112983852}
@@ -725,6 +726,19 @@ Transform:
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 0 m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5568897672767345397
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4806409459047702212}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 52790aba0e3d55f4fb27aded6c698d8b, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Handedness: 1
--- !u!114 &1039589470112983849 --- !u!114 &1039589470112983849
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@@ -858,6 +858,7 @@ GameObject:
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 7152668487518777764} - component: {fileID: 7152668487518777764}
- component: {fileID: 7057365311429264906}
- component: {fileID: 3431167848623168894} - component: {fileID: 3431167848623168894}
- component: {fileID: 3431167848623168881} - component: {fileID: 3431167848623168881}
- component: {fileID: 3431167848623168882} - component: {fileID: 3431167848623168882}
@@ -884,6 +885,19 @@ Transform:
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 0 m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &7057365311429264906
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7152668487518777765}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 52790aba0e3d55f4fb27aded6c698d8b, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Handedness: 0
--- !u!114 &3431167848623168894 --- !u!114 &3431167848623168894
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@@ -8,12 +8,13 @@
// conditions signed by you and all SDK and API requirements, // conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You." // specifications, and documentation provided by HTC to You."
using System.Collections.Generic;
using System.Text;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using System.Linq; using UnityEngine.InputSystem;
namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{ {
@@ -129,6 +130,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private HandGrabInteractable candidate = null; private HandGrabInteractable candidate = null;
private Pose wristPose = Pose.identity; private Pose wristPose = Pose.identity;
private Quaternion[] fingerJointRotation = new Quaternion[jointsPathMapping.Count]; private Quaternion[] fingerJointRotation = new Quaternion[jointsPathMapping.Count];
private bool isNewInputSystem = false;
#region MonoBehaviours #region MonoBehaviours
@@ -156,6 +158,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
sb.Append("However, you still can record grab pose if you use direct preview mode."); sb.Append("However, you still can record grab pose if you use direct preview mode.");
WARNING(sb); WARNING(sb);
} }
isNewInputSystem = Keyboard.current != null;
} }
private void OnDisable() private void OnDisable()
@@ -199,7 +202,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
} }
} }
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter)) if (IsEnterPressed())
{ {
FindNearInteractable(); FindNearInteractable();
SavePoseWithCandidate(); SavePoseWithCandidate();
@@ -326,6 +329,19 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
return updated; return updated;
} }
private bool IsEnterPressed()
{
if (isNewInputSystem)
{
return (Keyboard.current.enterKey?.wasPressedThisFrame ?? false) ||
(Keyboard.current.numpadEnterKey?.wasPressedThisFrame ?? false);
}
else
{
return Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter);
}
}
/// <summary> /// <summary>
/// Finds the nearest interactable object to the hand. /// Finds the nearest interactable object to the hand.
/// </summary> /// </summary>

View File

@@ -8,7 +8,6 @@
// conditions signed by you and all SDK and API requirements, // conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You." // specifications, and documentation provided by HTC to You."
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
@@ -183,8 +182,9 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{ {
if (!isGrabbable || isGrabbed) { return 0; } if (!isGrabbable || isGrabbed) { return 0; }
Vector3 closestPoint = GetClosestPoint(grabberPos); Vector3 closestPoint = GetClosestPoint(grabberPos);
float distacne = Vector3.Distance(grabberPos, closestPoint); float distanceSqr = (grabberPos - closestPoint).sqrMagnitude;
return distacne > grabDistance ? 0 : 1 - (distacne / grabDistance); float grabDistSqr = grabDistance * grabDistance;
return distanceSqr > grabDistSqr ? 0 : 1 - (distanceSqr / grabDistSqr);
} }
/// <summary> /// <summary>
@@ -263,35 +263,41 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Vector3 GetClosestPoint(Vector3 sourcePos) private Vector3 GetClosestPoint(Vector3 sourcePos)
{ {
Vector3 closestPoint = Vector3.zero; Vector3 closestPoint = Vector3.zero;
float shortDistance = float.MaxValue; float shortDistanceSqr = float.MaxValue;
for (int i = 0; i < allColliders.Count; i++) for (int i = 0; i < allColliders.Count; i++)
{ {
Collider collider = allColliders[i]; Collider collider = allColliders[i];
Vector3 closePoint = collider.ClosestPointOnBounds(sourcePos); Vector3 closePoint = collider.ClosestPointOnBounds(sourcePos);
float distance = Vector3.Distance(sourcePos, closePoint); float distanceSqr = (sourcePos - closePoint).sqrMagnitude;
if (distanceSqr < 0.001f)
{
return closePoint;
}
if (collider.bounds.Contains(closePoint)) if (collider.bounds.Contains(closePoint))
{ {
Vector3 direction = closePoint - sourcePos; Vector3 direction = closePoint - sourcePos;
direction.Normalize(); direction.Normalize();
int hitCount = Physics.RaycastNonAlloc(sourcePos, direction, hitResults, distance); int hitCount = Physics.RaycastNonAlloc(sourcePos, direction, hitResults, Mathf.Sqrt(distanceSqr));
for (int j = 0; j < hitCount; j++) for (int j = 0; j < hitCount; j++)
{ {
RaycastHit hit = hitResults[j]; RaycastHit hit = hitResults[j];
if (hit.collider == collider) if (hit.collider == collider)
{ {
float hitDistance = Vector3.Distance(sourcePos, hit.point); float hitDistanceSqr = (sourcePos - hit.point).sqrMagnitude;
if (distance > hitDistance) if (distanceSqr > hitDistanceSqr)
{ {
distance = hitDistance; distanceSqr = hitDistanceSqr;
closePoint = hit.point; closePoint = hit.point;
} }
} }
} }
} }
if (shortDistance > distance) if (shortDistanceSqr > distanceSqr)
{ {
shortDistance = distance; shortDistanceSqr = distanceSqr;
closestPoint = closePoint; closestPoint = closePoint;
} }
} }
@@ -361,9 +367,12 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// <param name="index">The index of the indicator to show.</param> /// <param name="index">The index of the indicator to show.</param>
private void ShowIndicatorByIndex(int index) private void ShowIndicatorByIndex(int index)
{ {
foreach (var grabPose in m_GrabPoses) for (int i = 0; i < m_GrabPoses.Count; i++)
{ {
grabPose.indicator.SetActive(false); if (index != i)
{
m_GrabPoses[i].indicator.SetActive(false);
}
} }
if (index >= 0 && index < m_GrabPoses.Count && if (index >= 0 && index < m_GrabPoses.Count &&
m_GrabPoses[index].indicator.enableIndicator) m_GrabPoses[index].indicator.enableIndicator)
@@ -379,9 +388,9 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// <param name="isLeft">Whether the hand side is left.</param> /// <param name="isLeft">Whether the hand side is left.</param>
private void ShowAllIndicator(bool isLeft) private void ShowAllIndicator(bool isLeft)
{ {
foreach (var grabPose in m_GrabPoses) for (int i = 0; i < m_GrabPoses.Count; i++)
{ {
grabPose.indicator.SetActive(false); m_GrabPoses[i].indicator.SetActive(false);
} }
foreach (var grabPose in m_GrabPoses) foreach (var grabPose in m_GrabPoses)
{ {

View File

@@ -8,7 +8,6 @@
// conditions signed by you and all SDK and API requirements, // conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You." // specifications, and documentation provided by HTC to You."
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
@@ -79,6 +78,13 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Pose wristPose = Pose.identity; private Pose wristPose = Pose.identity;
private Vector3[] fingerTipPosition = new Vector3[(int)FingerId.Count]; private Vector3[] fingerTipPosition = new Vector3[(int)FingerId.Count];
private const int kMaxCacheSize = 100;
private int lastBufferCount = 0;
private Collider[] colliderBuffer = new Collider[50];
private HandGrabInteractable[] grabbableBuffer = new HandGrabInteractable[50];
private LinkedList<Collider> lruList = new LinkedList<Collider>();
private Dictionary<Collider, LinkedListNode<Collider>> unusedColliders = new Dictionary<Collider, LinkedListNode<Collider>>();
#region MonoBehaviour #region MonoBehaviour
private void Awake() private void Awake()
{ {
@@ -159,7 +165,6 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// </summary> /// </summary>
private void FindCandidate() private void FindCandidate()
{ {
currentCandidate = null;
float distanceScore = float.MinValue; float distanceScore = float.MinValue;
if (GetClosestGrabbable(m_GrabDistance, out HandGrabInteractable grabbable, out float score) && score > distanceScore) if (GetClosestGrabbable(m_GrabDistance, out HandGrabInteractable grabbable, out float score) && score > distanceScore)
{ {
@@ -189,28 +194,47 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
grabbable = null; grabbable = null;
maxScore = 0f; maxScore = 0f;
Collider[] nearColliders = Physics.OverlapSphere(wristPose.position, 0.5f); for (int i = 0; i < lastBufferCount; i++)
List<HandGrabInteractable> nearHandGrabInteractables = new List<HandGrabInteractable>();
for (int i = 0; i < nearColliders.Length; i++)
{ {
HandGrabInteractable interactable = nearColliders[i].GetComponentInParent<HandGrabInteractable>(); HandGrabInteractable interactable = grabbableBuffer[i];
if (interactable && !nearHandGrabInteractables.Contains(interactable)) interactable.ShowIndicator(false, this);
{
nearHandGrabInteractables.Add(interactable);
continue;
}
interactable = nearColliders[i].GetComponentInChildren<HandGrabInteractable>();
if (interactable && !nearHandGrabInteractables.Contains(interactable))
{
nearHandGrabInteractables.Add(interactable);
continue;
}
} }
for (int i = 0; i < nearHandGrabInteractables.Count; i++) int colliderCount = Physics.OverlapSphereNonAlloc(wristPose.position, grabDistance * 5, colliderBuffer);
int interactableCount = 0;
for (int i = 0; i < colliderCount; i++)
{ {
HandGrabInteractable interactable = nearHandGrabInteractables[i]; Collider collider = colliderBuffer[i];
interactable.ShowIndicator(false, this); if (unusedColliders.TryGetValue(collider, out _)) { continue; }
HandGrabInteractable interactable = collider.GetComponentInParent<HandGrabInteractable>()
?? collider.GetComponentInChildren<HandGrabInteractable>();
if (interactable != null)
{
bool isUnique = true;
for (int j = 0; j < interactableCount; j++)
{
if (grabbableBuffer[j] == interactable)
{
isUnique = false;
break;
}
}
if (isUnique)
{
grabbableBuffer[interactableCount++] = interactable;
}
}
else
{
AddUnusedColliders(collider);
}
}
lastBufferCount = interactableCount;
for (int i = 0; i < interactableCount; i++)
{
HandGrabInteractable interactable = grabbableBuffer[i];
for (int j = 0; j < fingerTipPosition.Length; j++) for (int j = 0; j < fingerTipPosition.Length; j++)
{ {
float distanceScore = interactable.CalculateDistanceScore(fingerTipPosition[j], grabDistance); float distanceScore = interactable.CalculateDistanceScore(fingerTipPosition[j], grabDistance);
@@ -279,5 +303,18 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
} }
m_Grabbable.UpdatePositionAndRotation(wristPose); m_Grabbable.UpdatePositionAndRotation(wristPose);
} }
private void AddUnusedColliders(Collider collider)
{
if (lruList.Count >= kMaxCacheSize)
{
var oldest = lruList.First;
unusedColliders.Remove(oldest.Value);
lruList.RemoveFirst();
}
var node = lruList.AddLast(collider);
unusedColliders[collider] = node;
}
} }
} }

View File

@@ -11,7 +11,6 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
@@ -85,7 +84,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Quaternion lastRotation; private Quaternion lastRotation;
private bool isInit = false; private bool isInit = false;
private bool isTracked = true; private bool isTracked = true;
private List<Vector3> collisionDirections = new List<Vector3>(); private const int k_MaxCollisionCount = 100;
private readonly ContactPoint[] contactPointsBuffer = new ContactPoint[k_MaxCollisionCount];
private readonly Vector3[] collisionsDirection = new Vector3[k_MaxCollisionCount];
private readonly object collisionLock = new object();
private int currentCollisionCount = 0;
private bool isGrabbing = false; private bool isGrabbing = false;
#region MonoBehaviour #region MonoBehaviour
@@ -163,7 +166,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
if (isGrabbing) if (isGrabbing)
{ {
#if UNITY_6000_0_OR_NEWER
rootJointRigidbody.linearVelocity = Vector3.zero;
#else
rootJointRigidbody.velocity = Vector3.zero; rootJointRigidbody.velocity = Vector3.zero;
#endif
rootJointRigidbody.angularVelocity = Vector3.zero; rootJointRigidbody.angularVelocity = Vector3.zero;
rootJoint.localPosition = lastRootPos; rootJoint.localPosition = lastRootPos;
rootJoint.localRotation = lastRotation; rootJoint.localRotation = lastRotation;
@@ -175,7 +182,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
} }
} }
#endregion #endregion
private IEnumerator WaitForInit() private IEnumerator WaitForInit()
{ {
@@ -232,12 +239,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
Vector3 vel = (lastRootPos - rootJoint.position) / Time.deltaTime; Vector3 vel = (lastRootPos - rootJoint.position) / Time.deltaTime;
if (IsValidVelocity(vel)) if (IsValidVelocity(vel))
{ {
if (collisionDirections.Count > 0) lock (collisionLock)
{
if (currentCollisionCount > 0)
{ {
float minAngle = float.MaxValue; float minAngle = float.MaxValue;
Vector3 closestDirection = Vector3.zero; Vector3 closestDirection = Vector3.zero;
foreach (Vector3 direction in collisionDirections.ToList())
for (int i = 0; i < currentCollisionCount; i++)
{ {
Vector3 direction = collisionsDirection[i];
float angle = Mathf.Abs(Vector3.Angle(direction, vel)); float angle = Mathf.Abs(Vector3.Angle(direction, vel));
if (angle < minAngle) if (angle < minAngle)
{ {
@@ -245,8 +256,6 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
closestDirection = direction; closestDirection = direction;
} }
} }
collisionDirections.Clear();
Vector3 adjustedDirection = closestDirection; Vector3 adjustedDirection = closestDirection;
if (Vector3.Dot(vel, closestDirection) > 0) if (Vector3.Dot(vel, closestDirection) > 0)
{ {
@@ -257,8 +266,14 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{ {
vel.Normalize(); vel.Normalize();
} }
currentCollisionCount = 0;
} }
}
#if UNITY_6000_0_OR_NEWER
rootJointRigidbody.linearVelocity = vel;
#else
rootJointRigidbody.velocity = vel; rootJointRigidbody.velocity = vel;
#endif
} }
} }
@@ -287,7 +302,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
&& !float.IsInfinity(vector.x) && !float.IsInfinity(vector.y) && !float.IsInfinity(vector.z); && !float.IsInfinity(vector.x) && !float.IsInfinity(vector.y) && !float.IsInfinity(vector.z);
} }
#region Event CallBack #region Event CallBack
/// <summary> /// <summary>
/// When tracking state changing, reset the pose and enable/disable collider. /// When tracking state changing, reset the pose and enable/disable collider.
@@ -299,7 +314,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{ {
lastRootPos = Vector3.zero; lastRootPos = Vector3.zero;
lastRotation = Quaternion.identity; lastRotation = Quaternion.identity;
#if UNITY_6000_0_OR_NEWER
rootJointRigidbody.linearVelocity = Vector3.zero;
#else
rootJointRigidbody.velocity = Vector3.zero; rootJointRigidbody.velocity = Vector3.zero;
#endif
rootJointRigidbody.angularVelocity = Vector3.zero; rootJointRigidbody.angularVelocity = Vector3.zero;
} }
foreach (JointCollider jointCollider in jointsCollider) foreach (JointCollider jointCollider in jointsCollider)
@@ -355,17 +374,21 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
case JointCollider.CollisionState.Stay: case JointCollider.CollisionState.Stay:
if (collision.contactCount > 0 && (collision.rigidbody == null || collision.rigidbody.isKinematic)) if (collision.contactCount > 0 && (collision.rigidbody == null || collision.rigidbody.isKinematic))
{ {
ContactPoint[] contactPoints = new ContactPoint[collision.contactCount]; lock (collisionLock)
collision.GetContacts(contactPoints);
foreach (ContactPoint contactPoint in contactPoints)
{ {
collisionDirections.Add(contactPoint.normal * -1f); currentCollisionCount = Mathf.Min(contactPointsBuffer.Length, collision.contactCount);
collision.GetContacts(contactPointsBuffer);
for (int i = 0; i < currentCollisionCount; i++)
{
collisionsDirection[i] = contactPointsBuffer[i].normal * -1f;
}
} }
} }
break; break;
} }
} }
#endregion #endregion
} }
} }

View File

@@ -635,6 +635,8 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
} }
}, },
}; };
// palm, wrist, thumb, index, middle, ring, pinky
private static readonly int[] fingerGroup = { 1, 1, 4, 5, 5, 5, 5 };
public bool valid = false; public bool valid = false;
public bool isTracked = false; public bool isTracked = false;
@@ -771,14 +773,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
group = 0; group = 0;
index = jointId; index = jointId;
// palm, wrist, thumb, index, middle, ring, pinky for (int i = 0; i < fingerGroup.Length; i++)
int[] fingerGroup = { 1, 1, 4, 5, 5, 5, 5 };
while (index > fingerGroup[group])
{ {
index -= fingerGroup[group]; if (index <= fingerGroup[i])
group += 1; {
group = i;
index -= 1; // Adjust to 0-based index
return;
}
index -= fingerGroup[i];
} }
index -= 1;
} }
} }
@@ -848,32 +852,29 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// <param name="isLeft">True if the hand is left; otherwise, false.</param> /// <param name="isLeft">True if the hand is left; otherwise, false.</param>
private static void GetFingerData(FingerId id, ref FingerData finger, bool isLeft) private static void GetFingerData(FingerId id, ref FingerData finger, bool isLeft)
{ {
JointType[] jointTypes = { }; JointType[] jointTypes = GetJointTypes(id);
switch (id) if (jointTypes == null) return;
{
case FingerId.Thumb: jointTypes = s_ThumbJoints; break; float deltaTime = Time.deltaTime;
case FingerId.Index: jointTypes = s_IndexJoints; break; Vector3 parentVel = Vector3.zero;
case FingerId.Middle: jointTypes = s_MiddleJoints; break;
case FingerId.Ring: jointTypes = s_RingJoints; break;
case FingerId.Pinky: jointTypes = s_PinkyJoints; break;
default: return;
}
for (int i = 0; i < jointTypes.Length; i++) for (int i = 0; i < jointTypes.Length; i++)
{ {
Vector3 parentVel = i == 0 ? Vector3.zero : finger.joints[i - 1].velocity; ref JointData joint = ref finger.joints[i];
JointData lastJoint = finger.joints[i]; Vector3 lastPosition = joint.position;
GetJointData(jointTypes[i], ref finger.joints[i], isLeft);
DataWrapper.GetJointPose(jointTypes[i], ref joint.position, ref joint.rotation, isLeft);
joint.velocity = (joint.position - lastPosition) / deltaTime;
//As the velocity of child node should not be lower than the parent node. //As the velocity of child node should not be lower than the parent node.
//Add the current parent node's velocity multiplied by time to the last position of child node, obtaining the new simulated position. //Add the current parent node's velocity multiplied by time to the last position of child node, obtaining the new simulated position.
if (parentVel.magnitude > finger.joints[i].velocity.magnitude) if (parentVel.magnitude > joint.velocity.magnitude)
{ {
lastJoint.position += parentVel * Time.deltaTime; joint.position += parentVel * deltaTime;
finger.joints[i] = lastJoint;
} }
parentVel = joint.velocity;
} }
// Since the thumb does not have joint3, it is replaced by joint2.
if (id == FingerId.Thumb) if (id == FingerId.Thumb)
{ {
finger.joints[(int)JointId.Tip] = finger.joint3; finger.joints[(int)JointId.Tip] = finger.joint3;
@@ -885,6 +886,19 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
} }
} }
private static JointType[] GetJointTypes(FingerId id)
{
return id switch
{
FingerId.Thumb => s_ThumbJoints,
FingerId.Index => s_IndexJoints,
FingerId.Middle => s_MiddleJoints,
FingerId.Ring => s_RingJoints,
FingerId.Pinky => s_PinkyJoints,
_ => null
};
}
/// <summary> /// <summary>
/// Update the data for the left or right hand. /// Update the data for the left or right hand.
/// </summary> /// </summary>
@@ -1067,16 +1081,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
Vector3 thumbTip = thumbData.tip.position; Vector3 thumbTip = thumbData.tip.position;
Vector3 thumbJoint2 = thumbData.joint2.position; Vector3 thumbJoint2 = thumbData.joint2.position;
Vector3 thumbJoint1 = thumbData.joint1.position; Vector3 thumbJoint1 = thumbData.joint1.position;
Vector3[] fingerPos = { fingerData.tip.position,
fingerData.joint3.position,
fingerData.joint2.position};
float distance = float.PositiveInfinity; float distance = float.PositiveInfinity;
for (int i = 0; i < fingerPos.Length; i++) distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.tip.position, thumbTip, thumbJoint2));
{ distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.tip.position, thumbJoint2, thumbJoint1));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerPos[i], thumbTip, thumbJoint2));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerPos[i], thumbJoint2, thumbJoint1)); distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint3.position, thumbTip, thumbJoint2));
} distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint3.position, thumbJoint2, thumbJoint1));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint2.position, thumbTip, thumbJoint2));
distance = Mathf.Min(distance, CalculateShortestDistance(fingerData.joint2.position, thumbJoint2, thumbJoint1));
return distance; return distance;
} }
@@ -1732,9 +1746,16 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// <param name="enable">True to enable the indicator, false to deactivate it.</param> /// <param name="enable">True to enable the indicator, false to deactivate it.</param>
public void SetActive(bool enable) public void SetActive(bool enable)
{ {
if (target != null) if (target)
{ {
target.SetActive(enable); if (enable)
{
target.transform.localScale = Vector3.one;
}
else
{
target.transform.localScale = Vector3.zero;
}
} }
} }

View File

@@ -18,11 +18,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
protected override void OnDisable() protected override void OnDisable()
{ {
base.OnDisable(); base.OnDisable();
if (keepUpdate)
{
keepUpdate = false; keepUpdate = false;
StopCoroutine(UpdatePose());
}
} }
public void SetHandMeshRenderer(HandMeshManager handMeshRenderer) public void SetHandMeshRenderer(HandMeshManager handMeshRenderer)
@@ -44,21 +40,15 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{ {
yield return new WaitUntil(() => m_Initialized); yield return new WaitUntil(() => m_Initialized);
base.OnEnable(); base.OnEnable();
if (!keepUpdate)
{
keepUpdate = true; keepUpdate = true;
StartCoroutine(UpdatePose());
}
} }
private IEnumerator UpdatePose() private void Update()
{ {
while (keepUpdate) if (!keepUpdate) { return; }
{
yield return new WaitForFixedUpdate();
HandPose handPose = HandPoseProvider.GetHandPose(m_HandMesh.isLeft ? HandPoseType.HAND_LEFT : HandPoseType.HAND_RIGHT); HandPose handPose = HandPoseProvider.GetHandPose(m_HandMesh.isLeft ? HandPoseType.HAND_LEFT : HandPoseType.HAND_RIGHT);
m_IsTracked = handPose.IsTracked(); m_IsTracked = handPose.IsTracked();
if (!m_IsTracked) { return; }
for (int i = 0; i < poseCount; i++) for (int i = 0; i < poseCount; i++)
{ {
@@ -80,5 +70,4 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
} }
} }
} }
}
} }

View File

@@ -18,11 +18,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
protected override void OnDisable() protected override void OnDisable()
{ {
base.OnDisable(); base.OnDisable();
if (keepUpdate)
{
keepUpdate = false; keepUpdate = false;
StopCoroutine(UpdatePose());
}
} }
public override void SetType(HandPoseType poseType) public override void SetType(HandPoseType poseType)
@@ -43,25 +39,18 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{ {
yield return new WaitUntil(() => m_Initialized); yield return new WaitUntil(() => m_Initialized);
base.OnEnable(); base.OnEnable();
if (!keepUpdate)
{
keepUpdate = true; keepUpdate = true;
StartCoroutine(UpdatePose());
}
} }
private IEnumerator UpdatePose() private void Update()
{ {
Vector3 position = Vector3.zero; if (!keepUpdate) { return; }
Quaternion rotation = Quaternion.identity;
while (keepUpdate)
{
yield return new WaitForEndOfFrame();
HandData handData = CachedHand.Get(isLeft); HandData handData = CachedHand.Get(isLeft);
m_IsTracked = handData.isTracked; m_IsTracked = handData.isTracked;
if (!m_IsTracked) { continue; } if (!m_IsTracked) { return; }
Vector3 position = Vector3.zero;
Quaternion rotation = Quaternion.identity;
for (int i = 0; i < poseCount; i++) for (int i = 0; i < poseCount; i++)
{ {
if (handData.GetJointPosition((JointType)i, ref position) && handData.GetJointRotation((JointType)i, ref rotation)) if (handData.GetJointPosition((JointType)i, ref position) && handData.GetJointRotation((JointType)i, ref rotation))
@@ -81,5 +70,4 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
} }
} }
} }
}
} }

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
@@ -9,13 +10,15 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
[SerializeField] [SerializeField]
private float forceMultiplier = 1.0f; private float forceMultiplier = 1.0f;
private readonly int MIN_POSE_SAMPLES = 2; private const int MIN_POSE_SAMPLES = 2;
private readonly int MAX_POSE_SAMPLES = 10; private const int MAX_POSE_SAMPLES = 10;
private readonly float MIN_VELOCITY = 0.5f; private readonly float MIN_VELOCITY = 0.5f;
private Rigidbody interactableRigidbody; private Rigidbody interactableRigidbody;
private List<Pose> movementPoses = new List<Pose>(); private Pose[] movementPoses = new Pose[MAX_POSE_SAMPLES];
private List<float> timestamps = new List<float>(); private float[] timestamps = new float[MAX_POSE_SAMPLES];
private int currentPoseIndex = 0;
private int poseCount = 0;
private bool isBegin = false; private bool isBegin = false;
private bool isEnd = false; private bool isEnd = false;
private object lockVel = new object(); private object lockVel = new object();
@@ -36,7 +39,11 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
if (isEnd) if (isEnd)
{ {
#if UNITY_6000_0_OR_NEWER
interactableRigidbody.linearVelocity = Vector3.zero;
#else
interactableRigidbody.velocity = Vector3.zero; interactableRigidbody.velocity = Vector3.zero;
#endif
interactableRigidbody.angularVelocity = Vector3.zero; interactableRigidbody.angularVelocity = Vector3.zero;
Vector3 velocity = CalculateVelocity(); Vector3 velocity = CalculateVelocity();
@@ -46,8 +53,10 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
} }
interactableRigidbody = null; interactableRigidbody = null;
movementPoses.Clear(); Array.Clear(movementPoses, 0, MAX_POSE_SAMPLES);
timestamps.Clear(); Array.Clear(timestamps, 0, MAX_POSE_SAMPLES);
currentPoseIndex = 0;
poseCount = 0;
isEnd = false; isEnd = false;
} }
} }
@@ -55,28 +64,29 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private void RecordMovement() private void RecordMovement()
{ {
float time = Time.time; float time = Time.time;
if (movementPoses.Count == 0 ||
timestamps[movementPoses.Count - 1] != time)
{
movementPoses.Add(new Pose(interactableRigidbody.position, interactableRigidbody.rotation));
timestamps.Add(time);
}
if (movementPoses.Count > MAX_POSE_SAMPLES) int lastIndex = (currentPoseIndex + poseCount - 1) % MAX_POSE_SAMPLES;
if (poseCount == 0 || timestamps[lastIndex] != time)
{ {
movementPoses.RemoveAt(0); movementPoses[currentPoseIndex] = new Pose(interactableRigidbody.position, interactableRigidbody.rotation);
timestamps.RemoveAt(0); timestamps[currentPoseIndex] = time;
if (poseCount < MAX_POSE_SAMPLES)
{
poseCount++;
}
currentPoseIndex = (currentPoseIndex + 1) % MAX_POSE_SAMPLES;
} }
} }
private Vector3 CalculateVelocity() private Vector3 CalculateVelocity()
{ {
if (movementPoses.Count >= MIN_POSE_SAMPLES) if (poseCount >= MIN_POSE_SAMPLES)
{ {
List<Vector3> velocities = new List<Vector3>(); List<Vector3> velocities = new List<Vector3>();
for (int i = 0; i < movementPoses.Count - 1; i++) for (int i = 0; i < poseCount - 1; i++)
{ {
for (int j = i + 1; j < movementPoses.Count; j++) for (int j = i + 1; j < poseCount; j++)
{ {
velocities.Add(GetVelocity(i, j)); velocities.Add(GetVelocity(i, j));
} }
@@ -89,9 +99,9 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Vector3 GetVelocity(int idx1, int idx2) private Vector3 GetVelocity(int idx1, int idx2)
{ {
if (idx1 < 0 || idx1 >= movementPoses.Count if (idx1 < 0 || idx1 >= poseCount
|| idx2 < 0 || idx2 >= movementPoses.Count || idx2 < 0 || idx2 >= poseCount
|| movementPoses.Count < MIN_POSE_SAMPLES) || poseCount < MIN_POSE_SAMPLES)
{ {
return Vector3.zero; return Vector3.zero;
} }

View File

@@ -13,7 +13,7 @@
"WindowsStandalone64" "WindowsStandalone64"
], ],
"excludePlatforms": [], "excludePlatforms": [],
"allowUnsafeCode": false, "allowUnsafeCode": true,
"overrideReferences": false, "overrideReferences": false,
"precompiledReferences": [], "precompiledReferences": [],
"autoReferenced": true, "autoReferenced": true,
@@ -24,6 +24,11 @@
"expression": "1.3.0", "expression": "1.3.0",
"define": "UNITY_XR_HANDS" "define": "UNITY_XR_HANDS"
}, },
{
"name": "com.unity.xr.hands",
"expression": "1.5.0",
"define": "UNITY_XR_HANDS_1_5_0"
},
{ {
"name": "com.unity.xr.interaction.toolkit", "name": "com.unity.xr.interaction.toolkit",
"expression": "0.9.4-preview", "expression": "0.9.4-preview",

View File

@@ -48,7 +48,7 @@ namespace VIVE.OpenXR
public class VIVEFocus3Profile : OpenXRInteractionFeature public class VIVEFocus3Profile : OpenXRInteractionFeature
{ {
#region Log #region Log
const string LOG_TAG = "VIVE.OpenXR.VIVEFocus3Profile"; const string LOG_TAG = "VIVE.OpenXR.VIVEFocus3Profile ";
StringBuilder m_sb = null; StringBuilder m_sb = null;
StringBuilder sb { StringBuilder sb {
get { get {
@@ -56,8 +56,8 @@ namespace VIVE.OpenXR
return m_sb; return m_sb;
} }
} }
void DEBUG(StringBuilder msg) { Debug.LogFormat("{0} {1}", LOG_TAG, msg); } void DEBUG(StringBuilder msg) { Debug.Log(LOG_TAG + msg); }
void ERROR(StringBuilder msg) { Debug.LogErrorFormat("{0} {1}", LOG_TAG, msg); } void ERROR(StringBuilder msg) { Debug.LogError(LOG_TAG + msg); }
#endregion #endregion
private static VIVEFocus3Profile m_Instance = null; private static VIVEFocus3Profile m_Instance = null;
@@ -88,11 +88,13 @@ namespace VIVE.OpenXR
return m_sb; return m_sb;
} }
} }
void DEBUG(StringBuilder msg) { Debug.LogFormat("{0} {1}", LOG_TAG, msg); } void DEBUG(StringBuilder msg) { Debug.Log(LOG_TAG + msg); }
void ERROR(StringBuilder msg) { Debug.LogErrorFormat("{0} {1}", LOG_TAG, msg); } void ERROR(StringBuilder msg) { Debug.LogError(LOG_TAG + msg); }
#endregion #endregion
#region Action Path #region Action Path
#region Button
/// <summary> /// <summary>
/// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control) that represents the <see cref="VIVEFocus3Profile.thumbstick"/> OpenXR binding. /// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control) that represents the <see cref="VIVEFocus3Profile.thumbstick"/> OpenXR binding.
/// </summary> /// </summary>
@@ -145,7 +147,7 @@ namespace VIVE.OpenXR
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="triggerClick"/> OpenXR binding. /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="triggerClick"/> OpenXR binding.
/// </summary> /// </summary>
[Preserve, InputControl(aliases = new[] { "indexButton", "triggerButton" }, usage = "TriggerButton")] [Preserve, InputControl(aliases = new[] { "indexButton", "triggerButton" }, usage = "TriggerButton")]
public ButtonControl triggerPressed { get; private set; } public ButtonControl triggerPressed { get; private set; } // InputControl(offset = 20)
/// <summary> /// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="triggerTouch"/> OpenXR binding. /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="triggerTouch"/> OpenXR binding.
@@ -157,7 +159,7 @@ namespace VIVE.OpenXR
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="thumbstickClick"/> OpenXR binding. /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="thumbstickClick"/> OpenXR binding.
/// </summary> /// </summary>
[Preserve, InputControl(aliases = new[] { "JoystickOrPadPressed", "thumbstickClick", "joystickClicked", "primary2DAxisClick" }, usage = "Primary2DAxisClick")] [Preserve, InputControl(aliases = new[] { "JoystickOrPadPressed", "thumbstickClick", "joystickClicked", "primary2DAxisClick" }, usage = "Primary2DAxisClick")]
public ButtonControl thumbstickClicked { get; private set; } public ButtonControl thumbstickClicked { get; private set; } // InputControl(offset = 22)
/// <summary> /// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="thumbstickTouch"/> OpenXR binding. /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="thumbstickTouch"/> OpenXR binding.
@@ -169,31 +171,31 @@ namespace VIVE.OpenXR
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="thumbrest"/> OpenXR binding. /// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="thumbrest"/> OpenXR binding.
/// </summary> /// </summary>
[Preserve, InputControl(aliases = new[] { "ParkingTouched", "parkingTouched" })] [Preserve, InputControl(aliases = new[] { "ParkingTouched", "parkingTouched" })]
public ButtonControl thumbrestTouched { get; private set; } public ButtonControl thumbrestTouched { get; private set; } // InputControl(offset = 24)
#endregion
/// <summary> /// <summary>
/// A <see cref="PoseControl"/> that represents the <see cref="gripPose"/> OpenXR binding. The grip pose represents the location of the user's palm or holding a motion controller. /// A <see cref="PoseControl"/> that represents the <see cref="gripPose"/> OpenXR binding. The grip pose represents the location of the user's palm or holding a motion controller.
/// </summary> /// </summary>
[Preserve, InputControl(offset = 0, aliases = new[] { "device", "gripPose" }, usage = "Device")] [Preserve, InputControl(offset = 0, aliases = new[] { "device", "gripPose" }, usage = "Device")]
public PoseControl devicePose { get; private set; } public PoseControl devicePose { get; private set; }
/// <summary> /// <summary>
/// A <see cref="PoseControl"/> that represents the <see cref="VIVEFocus3Profile.aim"/> OpenXR binding. The pointer pose represents the tip of the controller pointing forward. /// A <see cref="PoseControl"/> that represents the <see cref="VIVEFocus3Profile.aim"/> OpenXR binding. The pointer pose represents the tip of the controller pointing forward.
/// </summary> /// </summary>
[Preserve, InputControl(offset = 0, aliases = new[] { "aimPose", "pointerPose" }, usage = "Pointer")] [Preserve, InputControl(offset = 0, aliases = new[] { "aimPose", "pointerPose" }, usage = "Pointer")]
public PoseControl pointer { get; private set; } public PoseControl pointer { get; private set; }
#if UNITY_ANDROID
/// <summary>
/// A <see cref="PoseControl"/> representing the <see cref="VIVEFocus3Profile.pokePose"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(offset = 0, alias = "indexTip", usage = "Poke")]
public PoseControl pokePose { get; private set; }
#if UNITY_ANDROID
/// <summary> /// <summary>
/// A <see cref="PoseControl"/> representing the <see cref="VIVEFocus3Profile.pinchPose"/> OpenXR binding. /// A <see cref="PoseControl"/> representing the <see cref="VIVEFocus3Profile.pinchPose"/> OpenXR binding.
/// </summary> /// </summary>
[Preserve, InputControl(offset = 0, usage = "Pinch")] [Preserve, InputControl(offset = 0, usage = "Pinch")]
public PoseControl pinchPose { get; private set; } public PoseControl pinchPose { get; private set; }
/// <summary>
/// A <see cref="PoseControl"/> representing the <see cref="VIVEFocus3Profile.pokePose"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(offset = 0, alias = "indexTip", usage = "Poke")]
public PoseControl pokePose { get; private set; }
#endif #endif
/// <summary> /// <summary>
@@ -227,28 +229,29 @@ namespace VIVE.OpenXR
/// </summary> /// </summary>
[Preserve, InputControl(offset = 104, noisy = true, alias = "pointerOrientation")] [Preserve, InputControl(offset = 104, noisy = true, alias = "pointerOrientation")]
public QuaternionControl pointerRotation { get; private set; } public QuaternionControl pointerRotation { get; private set; }
#if UNITY_ANDROID
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the poke position. This value is equivalent to mapping pokePose/position.
/// </summary>
[Preserve, InputControl(offset = 152, noisy = true)]
public Vector3Control pokePosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the poke orientation. This value is equivalent to mapping pokePose/rotation.
/// </summary>
[Preserve, InputControl(offset = 164, noisy = true)]
public QuaternionControl pokeRotation { get; private set; }
#if UNITY_ANDROID
/// <summary> /// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the pinch position. This value is equivalent to mapping pinchPose/position. /// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the pinch position. This value is equivalent to mapping pinchPose/position.
/// </summary> /// </summary>
[Preserve, InputControl(offset = 212, noisy = true)] [Preserve, InputControl(offset = 152, noisy = true)]
public Vector3Control pinchPosition { get; private set; } public Vector3Control pinchPosition { get; private set; }
/// <summary> /// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the pinch orientation. This value is equivalent to mapping pinchPose/rotation. /// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the pinch orientation. This value is equivalent to mapping pinchPose/rotation.
/// </summary> /// </summary>
[Preserve, InputControl(offset = 224, noisy = true)] [Preserve, InputControl(offset = 164, noisy = true)]
public QuaternionControl pinchRotation { get; private set; } public QuaternionControl pinchRotation { get; private set; }
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the poke position. This value is equivalent to mapping pokePose/position.
/// </summary>
[Preserve, InputControl(offset = 212, noisy = true)]
public Vector3Control pokePosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the poke orientation. This value is equivalent to mapping pokePose/rotation.
/// </summary>
[Preserve, InputControl(offset = 224, noisy = true)]
public QuaternionControl pokeRotation { get; private set; }
#endif #endif
/// <summary> /// <summary>
/// A <see cref="HapticControl"/> that represents the <see cref="VIVEFocus3Profile.haptic"/> binding. /// A <see cref="HapticControl"/> that represents the <see cref="VIVEFocus3Profile.haptic"/> binding.

View File

@@ -1,13 +1,13 @@
// Copyright HTC Corporation All Rights Reserved. // Copyright HTC Corporation All Rights Reserved.
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.XR; using UnityEngine.XR;
using System.Text;
#if ENABLE_INPUT_SYSTEM #if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem; using UnityEngine.InputSystem;
#endif #endif
namespace VIVE.OpenXR namespace VIVE.OpenXR
{ {
[DisallowMultipleComponent] [DisallowMultipleComponent]
@@ -43,12 +43,6 @@ namespace VIVE.OpenXR
private float m_CameraHeight = 1.5f; private float m_CameraHeight = 1.5f;
public float CameraHeight { get { return m_CameraHeight; } set { m_CameraHeight = value; } } public float CameraHeight { get { return m_CameraHeight; } set { m_CameraHeight = value; } }
[System.Obsolete("This variable is deprecated. Please use CameraHeight instead.")]
[SerializeField]
private float m_CameraYOffset = 1;
[System.Obsolete("This variable is deprecated. Please use CameraHeight instead.")]
public float CameraYOffset { get { return m_CameraYOffset; } set { m_CameraYOffset = value; } }
#if ENABLE_INPUT_SYSTEM #if ENABLE_INPUT_SYSTEM
[SerializeField] [SerializeField]
private InputActionAsset m_ActionAsset; private InputActionAsset m_ActionAsset;
@@ -56,10 +50,14 @@ namespace VIVE.OpenXR
#endif #endif
#endregion #endregion
static List<XRInputSubsystem> s_InputSubsystems = new List<XRInputSubsystem>(); private static readonly List<XRInputSubsystem> s_InputSubsystems = new List<XRInputSubsystem>();
private static readonly object lockObj = new object();
private float m_LastRecenteredTime = 0.0f;
#region MonoBehaviour
private void OnEnable() private void OnEnable()
{ {
SubsystemManager.GetInstances(s_InputSubsystems); UpdateInputSubsystems();
for (int i = 0; i < s_InputSubsystems.Count; i++) for (int i = 0; i < s_InputSubsystems.Count; i++)
{ {
s_InputSubsystems[i].trackingOriginUpdated += TrackingOriginUpdated; s_InputSubsystems[i].trackingOriginUpdated += TrackingOriginUpdated;
@@ -74,29 +72,12 @@ namespace VIVE.OpenXR
} }
private void OnDisable() private void OnDisable()
{ {
SubsystemManager.GetInstances(s_InputSubsystems); UpdateInputSubsystems();
for (int i = 0; i < s_InputSubsystems.Count; i++) for (int i = 0; i < s_InputSubsystems.Count; i++)
{ {
s_InputSubsystems[i].trackingOriginUpdated -= TrackingOriginUpdated; s_InputSubsystems[i].trackingOriginUpdated -= TrackingOriginUpdated;
} }
} }
float m_LastRecenteredTime = 0.0f;
private void TrackingOriginUpdated(XRInputSubsystem obj)
{
m_LastRecenteredTime = Time.time;
sb.Clear().Append("TrackingOriginUpdated() m_LastRecenteredTime: ").Append(m_LastRecenteredTime); DEBUG(sb);
}
XRInputSubsystem m_InputSystem = null;
void UpdateInputSystem()
{
SubsystemManager.GetInstances(s_InputSubsystems);
if (s_InputSubsystems.Count > 0)
{
m_InputSystem = s_InputSubsystems[0];
}
}
private void Awake() private void Awake()
{ {
if (m_Instance == null) if (m_Instance == null)
@@ -107,38 +88,18 @@ namespace VIVE.OpenXR
{ {
Destroy(this); Destroy(this);
} }
UpdateInputSystem();
if (m_InputSystem != null)
{
sb.Clear().Append("Awake() TrySetTrackingOriginMode ").Append(m_TrackingOrigin); DEBUG(sb);
m_InputSystem.TrySetTrackingOriginMode(m_TrackingOrigin);
TrackingOriginModeFlags mode = m_InputSystem.GetTrackingOriginMode();
sb.Clear().Append("Awake() Tracking mode is set to ").Append(mode); DEBUG(sb);
} }
else
{
sb.Clear().Append("Awake() no XRInputSubsystem."); DEBUG(sb);
}
m_TrackingOriginEx = m_TrackingOrigin;
}
private void Update() private void Update()
{ {
UpdateInputSystem(); TrackingOriginModeFlags mode = GetTrackingOriginMode();
if (m_InputSystem != null) if ((mode != m_TrackingOrigin || m_TrackingOriginEx != m_TrackingOrigin) &&
m_TrackingOrigin != TrackingOriginModeFlags.Unknown &&
SetTrackingOriginMode(m_TrackingOrigin))
{ {
TrackingOriginModeFlags mode = m_InputSystem.GetTrackingOriginMode(); mode = GetTrackingOriginMode();
if ((mode != m_TrackingOrigin || m_TrackingOriginEx != m_TrackingOrigin) && m_TrackingOrigin != TrackingOriginModeFlags.Unknown)
{
m_InputSystem.TrySetTrackingOriginMode(m_TrackingOrigin);
mode = m_InputSystem.GetTrackingOriginMode();
sb.Clear().Append("Update() Tracking mode is set to " + mode); sb.Clear().Append("Update() Tracking mode is set to " + mode);
m_TrackingOriginEx = m_TrackingOrigin; m_TrackingOriginEx = m_TrackingOrigin;
} }
}
if (m_CameraOffset != null && m_TrackingOrigin == TrackingOriginModeFlags.Device) if (m_CameraOffset != null && m_TrackingOrigin == TrackingOriginModeFlags.Device)
{ {
@@ -149,5 +110,66 @@ namespace VIVE.OpenXR
m_CameraOffset.transform.localPosition = cameraPosOffset; m_CameraOffset.transform.localPosition = cameraPosOffset;
} }
} }
#endregion
private bool SetTrackingOriginMode(TrackingOriginModeFlags value)
{
lock (lockObj)
{
UpdateInputSubsystems();
for (int i = 0; i < s_InputSubsystems.Count; i++)
{
var subsys = s_InputSubsystems[i];
if (!subsys.running)
{
continue;
}
if (subsys.TrySetTrackingOriginMode(value))
{
return true;
}
Debug.LogWarning($"Failed to set TrackingOriginModeFlags({value}) to XRInputSubsystem: {subsys.subsystemDescriptor?.id ?? "Unknown"}");
}
return false;
}
}
private TrackingOriginModeFlags GetTrackingOriginMode()
{
lock (lockObj)
{
UpdateInputSubsystems();
for(int i=0; i< s_InputSubsystems.Count; i++)
{
var subsys = s_InputSubsystems[i];
if (!subsys.running)
{
continue;
}
return subsys.GetTrackingOriginMode();
}
return TrackingOriginModeFlags.Unknown;
}
}
private void UpdateInputSubsystems()
{
s_InputSubsystems.Clear();
#if UNITY_6000_0_OR_NEWER
SubsystemManager.GetSubsystems(s_InputSubsystems);
#else
SubsystemManager.GetInstances(s_InputSubsystems);
#endif
}
private void TrackingOriginUpdated(XRInputSubsystem obj)
{
m_LastRecenteredTime = Time.time;
sb.Clear().Append("TrackingOriginUpdated() m_LastRecenteredTime: ").Append(m_LastRecenteredTime); DEBUG(sb);
}
} }
} }

View File

@@ -124,7 +124,7 @@ namespace VIVE.OpenXR.Samples.Anchor
void GetXRInputSubsystem() void GetXRInputSubsystem()
{ {
List<XRInputSubsystem> xrSubsystemList = new List<XRInputSubsystem>(); List<XRInputSubsystem> xrSubsystemList = new List<XRInputSubsystem>();
SubsystemManager.GetInstances(xrSubsystemList); SubsystemManager.GetSubsystems(xrSubsystemList);
foreach (var xrSubsystem in xrSubsystemList) foreach (var xrSubsystem in xrSubsystemList)
{ {
if (xrSubsystem.running) if (xrSubsystem.running)
@@ -675,6 +675,12 @@ namespace VIVE.OpenXR.Samples.Anchor
if (task.IsCompleted) if (task.IsCompleted)
{ {
Task<(XrResult, string, byte[])> t = task as Task<(XrResult, string, byte[])>; Task<(XrResult, string, byte[])> t = task as Task<(XrResult, string, byte[])>;
if (t == null)
{
tasks.Remove(task);
break;
}
if (t.Result.Item1 == XrResult.XR_SUCCESS) if (t.Result.Item1 == XrResult.XR_SUCCESS)
{ {
// write to file // write to file

View File

@@ -349,9 +349,9 @@
}, },
{ {
"name": "IsTracked", "name": "IsTracked",
"type": "Value", "type": "Button",
"id": "384094ab-6290-4de1-9b73-6dd7fae94298", "id": "384094ab-6290-4de1-9b73-6dd7fae94298",
"expectedControlType": "Analog", "expectedControlType": "Button",
"processors": "", "processors": "",
"interactions": "", "interactions": "",
"initialStateCheck": true "initialStateCheck": true
@@ -1230,9 +1230,9 @@
}, },
{ {
"name": "IsTracked", "name": "IsTracked",
"type": "Value", "type": "Button",
"id": "d1478f77-9424-45e1-bbe0-949fcfaec599", "id": "d1478f77-9424-45e1-bbe0-949fcfaec599",
"expectedControlType": "Analog", "expectedControlType": "Button",
"processors": "", "processors": "",
"interactions": "", "interactions": "",
"initialStateCheck": true "initialStateCheck": true

View File

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

View File

@@ -0,0 +1,71 @@
// Copyright HTC Corporation All Rights Reserved.
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using UnityEngine.XR;
using VIVE.OpenXR;
[RequireComponent(typeof(Text))]
public class DebugIsTrackedOffset : MonoBehaviour
{
public InputActionReference isTracked1 = null;
public InputActionReference isTracked2 = null;
public InputActionReference isTracked3 = null;
public InputActionReference isTracked4 = null;
private Text m_Text = null;
private void Start()
{
m_Text = GetComponent<Text>();
}
void Update()
{
if (m_Text == null) { return; }
m_Text.text = "";
{
if (OpenXRHelper.GetButton(isTracked1, out bool value, out string msg))
{
m_Text.text += isTracked1.action.name + ": " + value;
}
else
{
m_Text.text += msg;
}
}
m_Text.text += "\n";
{
if (OpenXRHelper.GetButton(isTracked2, out bool value, out string msg))
{
m_Text.text += isTracked2.action.name + ": " + value;
}
else
{
m_Text.text += msg;
}
}
m_Text.text += "\n";
{
if (OpenXRHelper.GetButton(isTracked3, out bool value, out string msg))
{
m_Text.text += isTracked3.action.name + ": " + value;
}
else
{
m_Text.text += msg;
}
}
m_Text.text += "\n";
{
if (OpenXRHelper.GetButton(isTracked4, out bool value, out string msg))
{
m_Text.text += isTracked4.action.name + ": " + value;
}
else
{
m_Text.text += msg;
}
}
}
}

View File

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

View File

@@ -0,0 +1,136 @@
// Copyright HTC Corporation All Rights Reserved.
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using UnityEngine.XR;
using VIVE.OpenXR;
[RequireComponent(typeof(Text))]
public class DebugPoseData : MonoBehaviour
{
public string PoseName = "";
public InputActionReference isTracked = null;
public InputActionReference trackingState = null;
public InputActionReference position = null;
public InputActionReference rotation = null;
public InputActionReference pose = null;
private Text m_Text = null;
private void Start()
{
m_Text = GetComponent<Text>();
}
void Update()
{
if (m_Text == null) { return; }
m_Text.text = PoseName + " ----";
if (isTracked != null)
{
m_Text.text += "\nisTracked: ";
{
if (OpenXRHelper.GetButton(isTracked, out bool value, out string msg))
{
m_Text.text += value;
}
else
{
m_Text.text += msg;
}
}
}
if (trackingState != null)
{
m_Text.text += "\ntrackingState: ";
{
if (OpenXRHelper.GetInteger(trackingState, out InputTrackingState value, out string msg))
{
m_Text.text += value;
}
else
{
m_Text.text += msg;
}
}
}
if (position != null)
{
m_Text.text += "\nposition: ";
{
if (OpenXRHelper.GetVector3(position, out Vector3 value, out string msg))
{
m_Text.text += "(" + value.x.ToString("N3") + ", " + value.y.ToString("N3") + ", " + value.z.ToString("N3") + ")";
}
else
{
m_Text.text += msg;
}
}
}
if (rotation != null)
{
m_Text.text += "\nrotation: ";
{
if (OpenXRHelper.GetQuaternion(rotation, out Quaternion value, out string msg))
{
m_Text.text += "(" + value.x.ToString("N3") + ", " + value.y.ToString("N3") + ", " + value.z.ToString("N3") + ", " + value.w.ToString("N3") + ")";
}
else
{
m_Text.text += msg;
}
}
}
if (pose != null)
{
m_Text.text += "\npose.isTracked: ";
{
if (OpenXRHelper.GetPoseIsTracked(pose, out bool value, out string msg))
{
m_Text.text += value;
}
else
{
m_Text.text += msg;
}
}
m_Text.text += "\npose.trackingState: ";
{
if (OpenXRHelper.GetPoseTrackingState(pose, out InputTrackingState value, out string msg))
{
m_Text.text += value;
}
else
{
m_Text.text += msg;
}
}
m_Text.text += "\npose.position: ";
{
if (OpenXRHelper.GetPosePosition(pose, out Vector3 value, out string msg))
{
m_Text.text += "(" + value.x.ToString("N3") + ", " + value.y.ToString("N3") + ", " + value.z.ToString("N3") + ")";
}
else
{
m_Text.text += msg;
}
}
m_Text.text += "\npose.rotation: ";
{
if (OpenXRHelper.GetPoseRotation(pose, out Quaternion value, out string msg))
{
m_Text.text += "(" + value.x.ToString("N3") + ", " + value.y.ToString("N3") + ", " + value.z.ToString("N3") + ", " + value.w.ToString("N3") + ")";
}
else
{
m_Text.text += msg;
}
}
}
}
}

View File

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

View File

@@ -111,7 +111,14 @@ namespace VIVE.OpenXR.Samples
rotationTracked = ((uint)trackingState & (uint)InputTrackingState.Rotation) != 0; rotationTracked = ((uint)trackingState & (uint)InputTrackingState.Rotation) != 0;
bool tracked = isActive /*&& positionTracked */&& rotationTracked; // Show the object with 3DoF. bool tracked = isActive /*&& positionTracked */&& rotationTracked; // Show the object with 3DoF.
// Temporary workaround for PC platform: The isTracked value for HandInteractionEXT always returns false.
// For now, forcing it to true using a macro. This will be properly fixed in the next patch.
#if UNITY_STANDALONE
if (IsActive.action.ToString() == "Hand/isTrackedR" || IsActive.action.ToString() == "Hand/isTrackedL")
m_ObjectToHide.SetActive(true);
#else
m_ObjectToHide.SetActive(tracked); m_ObjectToHide.SetActive(tracked);
#endif
} }
} }
} }

View File

@@ -0,0 +1,439 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &165655209
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 165655211}
- component: {fileID: 165655210}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &165655210
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 165655209}
m_Enabled: 1
serializedVersion: 10
m_Type: 1
m_Shape: 0
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
m_Intensity: 1
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize: 10
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!4 &165655211
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 165655209}
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!1001 &577647561
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 7207139244497761804, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_Name
value: VRSRig_withController
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_RootOrder
value: 2
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244497761807, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244786812522, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_ClearFlags
value: 2
objectReference: {fileID: 0}
- target: {fileID: 7207139244786812522, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_BackGroundColor.b
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244786812522, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_BackGroundColor.g
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7207139244786812522, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
propertyPath: m_BackGroundColor.r
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
--- !u!1 &577647562 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 7207139244497761804, guid: aa6466f3484ac344fb3c59a5b6398f84, type: 3}
m_PrefabInstance: {fileID: 577647561}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &1436813407
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 4106666293350236145, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_Name
value: VRSInputManager
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_RootOrder
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalPosition.x
value: -0.20003967
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalPosition.y
value: 0.3311797
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalPosition.z
value: 1.3696996
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4106666293350236147, guid: 247f35baba2bd814c96bea592859803d, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 247f35baba2bd814c96bea592859803d, type: 3}
--- !u!1 &1888556275
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1888556277}
- component: {fileID: 1888556276}
m_Layer: 0
m_Name: Underlay
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1888556276
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1888556275}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 221c4e845ba39fa4396461ac8c3b9e8e, type: 3}
m_Name:
m_EditorClassIdentifier:
isPreviewingCylinder: 0
isPreviewingEquirect: 1
isPreviewingQuad: 0
generatedPreview: {fileID: 0}
layerType: 2
compositionDepth: 0
layerShape: 3
layerVisibility: 0
m_QuadWidth: 1
m_QuadHeight: 1
m_CylinderRadius: 1
m_CylinderHeight: 1
m_CylinderArcLength: 1
m_EquirectRadius: 10
m_EquirectScaleX: 1
m_EquirectScaleY: 1
m_EquirectBiasX: 0
m_EquirectBiasY: 0
m_EquirectCentralHorizontalAngle: 360
m_EquirectUpperVerticalAngle: 90
m_EquirectLowerVerticalAngle: -90
m_CylinderAngleOfArc: 180
lockMode: 0
isDynamicLayer: 0
isExternalSurface: 0
isCustomRects: 0
customRects: 2
externalSurfaceWidth: 1280
externalSurfaceHeight: 720
applyColorScaleBias: 0
solidEffect: 0
colorScale: {r: 1, g: 1, b: 1, a: 1}
colorBias: {r: 0, g: 0, b: 0, a: 0}
isProtectedSurface: 0
texture: {fileID: 2800000, guid: 536e6f3c92ead484baf6cebabecc58a7, type: 3}
textureRight: {fileID: 0}
renderPriority: 0
trackingOrigin: {fileID: 577647562}
generatedUnderlayMesh: {fileID: 0}
generatedFallbackMesh: {fileID: 0}
hmd: {fileID: 0}
--- !u!4 &1888556277
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1888556275}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c44817993abad6145928810ed11e7e49
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,135 @@
fileFormatVersion: 2
guid: 536e6f3c92ead484baf6cebabecc58a7
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 4096
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -22,6 +22,7 @@ Material:
RenderType: Transparent RenderType: Transparent
disabledShaderPasses: disabledShaderPasses:
- GRABPASS - GRABPASS
- ALWAYS
m_SavedProperties: m_SavedProperties:
serializedVersion: 3 serializedVersion: 3
m_TexEnvs: m_TexEnvs:

View File

@@ -54,6 +54,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "068b86ec-3f14-4d24-9b42-7057d00ab904",
"path": "<HandInteraction>{LeftHand}/isTracked",
"interactions": "",
"processors": "",
"groups": "",
"action": "isTrackedL",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "b605cbf6-38fb-422a-b12d-48e386a67e9a", "id": "b605cbf6-38fb-422a-b12d-48e386a67e9a",
@@ -65,6 +76,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "fa2d2138-eb75-4cce-8088-3445f1560e97",
"path": "<HandInteraction>{RightHand}/isTracked",
"interactions": "",
"processors": "",
"groups": "",
"action": "isTrackedR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "9535518b-92b1-45ff-9525-624d0c52de13", "id": "9535518b-92b1-45ff-9525-624d0c52de13",
@@ -76,6 +98,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "4331ebf5-824f-405f-8a29-a4c4049c23d9",
"path": "<HandInteraction>{RightHand}/trackingState",
"interactions": "",
"processors": "",
"groups": "",
"action": "trackingStateR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "1ccbb62c-6370-4507-847e-8fda100510e8", "id": "1ccbb62c-6370-4507-847e-8fda100510e8",
@@ -86,6 +119,17 @@
"action": "trackingStateL", "action": "trackingStateL",
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
},
{
"name": "",
"id": "f4e2d931-5b80-4e10-8e95-37c99a3d9536",
"path": "<HandInteraction>{LeftHand}/trackingState",
"interactions": "",
"processors": "",
"groups": "",
"action": "trackingStateL",
"isComposite": false,
"isPartOfComposite": false
} }
] ]
}, },
@@ -160,6 +204,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "0afb0794-9c98-41f7-9f58-8a1e64bc8bdc",
"path": "<HandInteraction>{LeftHand}/devicePose",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseL",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "d41d33db-8b6c-4f21-9459-fd203551d990", "id": "d41d33db-8b6c-4f21-9459-fd203551d990",
@@ -171,6 +226,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "d46b4d0f-f908-4cd0-aece-22eb2318f8e7",
"path": "<HandInteraction>{RightHand}/devicePose",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "48b33d4f-e9f9-4890-b836-d7303386c8b0", "id": "48b33d4f-e9f9-4890-b836-d7303386c8b0",
@@ -182,6 +248,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "005e532f-bb88-4636-8604-3c3dbf891803",
"path": "<HandInteraction>{LeftHand}/graspValue",
"interactions": "",
"processors": "",
"groups": "",
"action": "ValueL",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "e43dc5cd-3e96-4453-b6b2-818250c91436", "id": "e43dc5cd-3e96-4453-b6b2-818250c91436",
@@ -193,6 +270,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "ddd425a1-b196-4a6c-bbba-69f3fa9b44b8",
"path": "<HandInteraction>{RightHand}/graspValue",
"interactions": "",
"processors": "",
"groups": "",
"action": "ValueR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "3e8a289a-aa43-44fd-bbdf-ed15035ad5ef", "id": "3e8a289a-aa43-44fd-bbdf-ed15035ad5ef",
@@ -204,6 +292,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "9c47003b-b29e-49a8-8ee5-7700bdf3ef66",
"path": "<HandInteraction>{RightHand}/graspReady",
"interactions": "",
"processors": "",
"groups": "",
"action": "ReadyR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "79e10ffe-7276-4a95-b380-9d244bc2b213", "id": "79e10ffe-7276-4a95-b380-9d244bc2b213",
@@ -214,6 +313,17 @@
"action": "ReadyL", "action": "ReadyL",
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
},
{
"name": "",
"id": "5f1f8ba8-8258-4293-8a1c-b7680ae212c0",
"path": "<HandInteraction>{LeftHand}/graspReady",
"interactions": "",
"processors": "",
"groups": "",
"action": "ReadyL",
"isComposite": false,
"isPartOfComposite": false
} }
] ]
}, },
@@ -230,6 +340,24 @@
"interactions": "", "interactions": "",
"initialStateCheck": false "initialStateCheck": false
}, },
{
"name": "PositionL",
"type": "PassThrough",
"id": "3c743437-254f-480d-ab2a-fbb7fa3a1c75",
"expectedControlType": "Vector3",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "RotationL",
"type": "PassThrough",
"id": "a61c5a21-e370-4bd7-91cc-4939db98a735",
"expectedControlType": "Quaternion",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{ {
"name": "ValueL", "name": "ValueL",
"type": "Value", "type": "Value",
@@ -257,6 +385,24 @@
"interactions": "", "interactions": "",
"initialStateCheck": false "initialStateCheck": false
}, },
{
"name": "PositionR",
"type": "PassThrough",
"id": "eb88b286-d41a-4441-8680-eae89ddd9427",
"expectedControlType": "Vector3",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "RotationR",
"type": "PassThrough",
"id": "4b410388-aabc-4cef-944e-68d5f68bcc44",
"expectedControlType": "Quaternion",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{ {
"name": "ValueR", "name": "ValueR",
"type": "Value", "type": "Value",
@@ -288,6 +434,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "45cf0dab-fbfc-478f-aa3b-f74eafb029e9",
"path": "<HandInteraction>{LeftHand}/pointer",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseL",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "cbaae569-a034-4ce6-8cdd-eef5586aaa7e", "id": "cbaae569-a034-4ce6-8cdd-eef5586aaa7e",
@@ -299,6 +456,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "bb49f848-f6b0-4a1a-b60c-1f08a8bdffcc",
"path": "<HandInteraction>{RightHand}/pointer",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "514be0ed-99f4-4f3a-a53b-672c0caeb1d5", "id": "514be0ed-99f4-4f3a-a53b-672c0caeb1d5",
@@ -310,6 +478,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "8e248108-0a74-421f-b2b6-0172ccf49da8",
"path": "<HandInteraction>{LeftHand}/pointerActivateValue",
"interactions": "",
"processors": "",
"groups": "",
"action": "ValueL",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "b3c9d90b-0ad0-42c6-9cda-1ac1d74719a5", "id": "b3c9d90b-0ad0-42c6-9cda-1ac1d74719a5",
@@ -321,6 +500,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "afb0658c-57a3-4f84-99ce-f2b5731b081a",
"path": "<HandInteraction>{RightHand}/pointerActivateValue",
"interactions": "",
"processors": "",
"groups": "",
"action": "ValueR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "03ca7d96-43df-406f-8b41-c3b8168cbcbc", "id": "03ca7d96-43df-406f-8b41-c3b8168cbcbc",
@@ -332,6 +522,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "ff1d9683-a045-4394-95f3-8b8637109b91",
"path": "<HandInteraction>{RightHand}/pointerActivateReady",
"interactions": "",
"processors": "",
"groups": "",
"action": "ReadyR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "0f20788a-3543-4fd0-8e4e-9ad56108877e", "id": "0f20788a-3543-4fd0-8e4e-9ad56108877e",
@@ -342,6 +543,299 @@
"action": "ReadyL", "action": "ReadyL",
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
},
{
"name": "",
"id": "4df69cb3-1d60-4aab-9af4-528400022e93",
"path": "<HandInteraction>{LeftHand}/pointerActivateReady",
"interactions": "",
"processors": "",
"groups": "",
"action": "ReadyL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "4af711ee-8f25-4a6b-900b-cce9a68655de",
"path": "<ViveHandInteractionExt>{LeftHand}/pointerPosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "056d875e-56e5-4783-b73c-7d2a83407530",
"path": "<HandInteraction>{LeftHand}/pointerPosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "d47309f6-c5d1-4892-bf76-e51faa8b6137",
"path": "<ViveHandInteractionExt>{LeftHand}/pointerRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "f4fade07-9a27-4a3a-9145-87fc4e6fc282",
"path": "<HandInteraction>{LeftHand}/pointerRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "61444e1e-91f4-45a7-8104-93317a4fcfa8",
"path": "<ViveHandInteractionExt>{RightHand}/pointerPosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "d66724bb-6f33-46eb-8205-3912e3cdb72d",
"path": "<HandInteraction>{RightHand}/pointerPosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "3f05dfd2-7dcb-46ee-a8c8-20c921c62793",
"path": "<ViveHandInteractionExt>{RightHand}/pointerRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "c3aa63db-3ff8-4206-b62a-d1caf6ffafd5",
"path": "<HandInteraction>{RightHand}/pointerRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationR",
"isComposite": false,
"isPartOfComposite": false
}
]
},
{
"name": "HandPoke",
"id": "a4cfc781-c114-4451-96d5-857c3a9385fa",
"actions": [
{
"name": "PoseL",
"type": "PassThrough",
"id": "e9feeab8-c68c-47d7-8560-8f3b2c44d2bf",
"expectedControlType": "Pose",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "PositionL",
"type": "PassThrough",
"id": "eed73641-933c-4836-9ed7-f0f28ddbf9ec",
"expectedControlType": "Vector3",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "RotationL",
"type": "PassThrough",
"id": "5ad8d488-2973-487b-a19f-c8eb588c67d3",
"expectedControlType": "Quaternion",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "PoseR",
"type": "PassThrough",
"id": "1bac4e9e-ce3d-4218-bbca-255ef780cf6c",
"expectedControlType": "Pose",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "PositionR",
"type": "PassThrough",
"id": "cdd9430c-70f2-4854-b3ae-81b884e87168",
"expectedControlType": "Vector3",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "RotationR",
"type": "PassThrough",
"id": "81746764-95ef-48ce-b2e1-e05330f97e05",
"expectedControlType": "Quaternion",
"processors": "",
"interactions": "",
"initialStateCheck": false
}
],
"bindings": [
{
"name": "",
"id": "efd73d26-df7d-4b90-93c2-202a5f70c05c",
"path": "<ViveHandInteractionExt>{LeftHand}/pokePose",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "8e9539c4-4aca-471f-b843-bd282a33616b",
"path": "<HandInteraction>{LeftHand}/pokePose",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "124f3c45-0d83-4302-9f2a-cb945f7c268e",
"path": "<ViveHandInteractionExt>{RightHand}/pokePose",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "d6bd90fd-f8ab-4cc7-ab90-c604788b32e8",
"path": "<HandInteraction>{RightHand}/pokePose",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "29fcebb4-1111-4c52-becf-a20a4919c8bd",
"path": "<ViveHandInteractionExt>{RightHand}/pokePosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "3f1a484f-a430-4f62-9587-47944d3ceb8a",
"path": "<HandInteraction>{RightHand}/pokePosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "72bb3809-4dba-4b8c-a35a-6c2078873256",
"path": "<ViveHandInteractionExt>{LeftHand}/pokeRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "c64e7c60-8e41-47d7-80b3-8f8dd7c17071",
"path": "<HandInteraction>{LeftHand}/pokeRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "cae2d11b-bd7f-4fc4-b247-c21af26cf2d5",
"path": "<ViveHandInteractionExt>{RightHand}/pokeRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "59f0ff0b-c894-4fb7-b775-7a8dbc56c718",
"path": "<HandInteraction>{RightHand}/pokeRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "79dfac35-3c6f-45b2-8045-eeba5534cb14",
"path": "<ViveHandInteractionExt>{LeftHand}/pokePosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "6b420474-04e5-46bb-b76f-a4aef922dac4",
"path": "<HandInteraction>{LeftHand}/pokePosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionL",
"isComposite": false,
"isPartOfComposite": false
} }
] ]
}, },
@@ -358,6 +852,24 @@
"interactions": "", "interactions": "",
"initialStateCheck": false "initialStateCheck": false
}, },
{
"name": "PositionL",
"type": "PassThrough",
"id": "d0f34fc0-7d91-44ad-8fcb-2be82414f6ba",
"expectedControlType": "Vector3",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "RotationL",
"type": "PassThrough",
"id": "69f4a637-3eaf-490d-9de8-d9a08bff9fff",
"expectedControlType": "Quaternion",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{ {
"name": "ValueL", "name": "ValueL",
"type": "Value", "type": "Value",
@@ -385,6 +897,24 @@
"interactions": "", "interactions": "",
"initialStateCheck": false "initialStateCheck": false
}, },
{
"name": "PositionR",
"type": "PassThrough",
"id": "d46fd2f7-9611-4d4f-bc93-12999b1f862e",
"expectedControlType": "Vector3",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "RotationR",
"type": "PassThrough",
"id": "5ea8b91a-29fb-4e5a-bb65-f61664a39b2a",
"expectedControlType": "Quaternion",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{ {
"name": "ValueR", "name": "ValueR",
"type": "Value", "type": "Value",
@@ -416,6 +946,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "e73a46a3-8913-44c6-a015-713f387ff238",
"path": "<HandInteraction>{LeftHand}/pinchPose",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseL",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "92e779f7-ba6f-417d-9f4c-9d5f81790686", "id": "92e779f7-ba6f-417d-9f4c-9d5f81790686",
@@ -427,6 +968,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "8c9406c8-c451-43cc-8a39-b8ec5d841c2b",
"path": "<HandInteraction>{RightHand}/pinchPose",
"interactions": "",
"processors": "",
"groups": "",
"action": "PoseR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "f5f748fd-da48-423b-864a-340e9934041f", "id": "f5f748fd-da48-423b-864a-340e9934041f",
@@ -438,6 +990,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "dbc9eb68-a3a8-4309-b690-2215efd2af77",
"path": "<HandInteraction>{LeftHand}/pinchValue",
"interactions": "",
"processors": "",
"groups": "",
"action": "ValueL",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "838dbd9a-6c54-4959-9a92-0168b20d3632", "id": "838dbd9a-6c54-4959-9a92-0168b20d3632",
@@ -449,6 +1012,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "79ebe950-0644-4adb-a13d-fd1d5e109e57",
"path": "<HandInteraction>{RightHand}/pinchValue",
"interactions": "",
"processors": "",
"groups": "",
"action": "ValueR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "30bc3116-8581-42b7-9a73-8f4ce570083e", "id": "30bc3116-8581-42b7-9a73-8f4ce570083e",
@@ -460,6 +1034,17 @@
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{
"name": "",
"id": "e50e1257-1b2b-46ab-99b2-231ccee5eeb6",
"path": "<HandInteraction>{RightHand}/pinchReady",
"interactions": "",
"processors": "",
"groups": "",
"action": "ReadyR",
"isComposite": false,
"isPartOfComposite": false
},
{ {
"name": "", "name": "",
"id": "9591b4cc-cf0b-4096-91ae-848358b0f366", "id": "9591b4cc-cf0b-4096-91ae-848358b0f366",
@@ -470,52 +1055,103 @@
"action": "ReadyL", "action": "ReadyL",
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}
]
}, },
{
"name": "HandPoke",
"id": "a4cfc781-c114-4451-96d5-857c3a9385fa",
"actions": [
{
"name": "PoseL",
"type": "PassThrough",
"id": "e9feeab8-c68c-47d7-8560-8f3b2c44d2bf",
"expectedControlType": "Pose",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "PoseR",
"type": "PassThrough",
"id": "1bac4e9e-ce3d-4218-bbca-255ef780cf6c",
"expectedControlType": "Pose",
"processors": "",
"interactions": "",
"initialStateCheck": false
}
],
"bindings": [
{ {
"name": "", "name": "",
"id": "efd73d26-df7d-4b90-93c2-202a5f70c05c", "id": "136c49a3-8f2b-476b-9adf-98e7ed1e6e9a",
"path": "<ViveHandInteractionExt>{LeftHand}/pokePose", "path": "<HandInteraction>{LeftHand}/pinchReady",
"interactions": "", "interactions": "",
"processors": "", "processors": "",
"groups": "", "groups": "",
"action": "PoseL", "action": "ReadyL",
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
}, },
{ {
"name": "", "name": "",
"id": "124f3c45-0d83-4302-9f2a-cb945f7c268e", "id": "9221267c-62a0-47cb-aeba-aca47714c033",
"path": "<ViveHandInteractionExt>{RightHand}/pokePose", "path": "<ViveHandInteractionExt>{LeftHand}/pinchRotation",
"interactions": "", "interactions": "",
"processors": "", "processors": "",
"groups": "", "groups": "",
"action": "PoseR", "action": "RotationL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "b4dcfb93-89e5-45cf-bde0-6c2adea454b3",
"path": "<HandInteraction>{LeftHand}/pinchRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "b841def8-addf-4eae-808f-5160a5ff3ed5",
"path": "<ViveHandInteractionExt>{LeftHand}/pinchPosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "3253d57e-11aa-4449-8960-16e8911854d5",
"path": "<HandInteraction>{LeftHand}/pinchPosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionL",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "88a63c73-43a1-469c-99b0-ef08bd0b95e7",
"path": "<ViveHandInteractionExt>{RightHand}/pinchPosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "bf69fb00-cf5a-40da-a774-437f1ea76d44",
"path": "<HandInteraction>{RightHand}/pinchPosition",
"interactions": "",
"processors": "",
"groups": "",
"action": "PositionR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "7f0a8dc7-c33a-4811-ad95-367df499cfb8",
"path": "<ViveHandInteractionExt>{RightHand}/pinchRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationR",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "ef207392-905c-4a08-9e1f-7bdf0b66069a",
"path": "<HandInteraction>{RightHand}/pinchRotation",
"interactions": "",
"processors": "",
"groups": "",
"action": "RotationR",
"isComposite": false, "isComposite": false,
"isPartOfComposite": false "isPartOfComposite": false
} }

View File

@@ -1768,6 +1768,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -1808,6 +1809,18 @@ MonoBehaviour:
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: 5c275b7c-6878-407c-acb9-66806a61261b
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: m_Name:
m_Type: 0 m_Type: 0
@@ -1826,7 +1839,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &672225543 --- !u!1 &672225543
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -2227,6 +2239,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -2245,6 +2258,14 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Position Input m_Action: Position Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: 226fcfb5-99d1-4280-be7d-6cab3c65b50e
m_Path: <HandInteraction>{RightHand}/pinchPosition
m_Interactions:
m_Processors:
m_Groups:
m_Action: Position Input
m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_RotationInput: m_RotationInput:
@@ -2265,6 +2286,26 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Rotation Input m_Action: Rotation Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: bcafb8fd-f86e-42bf-90ac-af906ad3c602
m_Path: <HandInteraction>{RightHand}/pinchRotation
m_Interactions:
m_Processors:
m_Groups:
m_Action: Rotation Input
m_Flags: 0
m_Flags: 0
m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: de44ecc7-66b7-4528-a659-367b18da0fbc
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
@@ -2285,7 +2326,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1001 &743277234 --- !u!1001 &743277234
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -2939,6 +2979,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -2957,6 +2998,14 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Position Input m_Action: Position Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: 4364030c-a105-4d8e-a293-2110f00c6bd2
m_Path: <HandInteraction>{LeftHand}/pinchPosition
m_Interactions:
m_Processors:
m_Groups:
m_Action: Position Input
m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_RotationInput: m_RotationInput:
@@ -2977,6 +3026,26 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Rotation Input m_Action: Rotation Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: a3e41bb8-f7e1-4d78-982f-efb634541fad
m_Path: <HandInteraction>{LeftHand}/pinchRotation
m_Interactions:
m_Processors:
m_Groups:
m_Action: Rotation Input
m_Flags: 0
m_Flags: 0
m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: c406c9d0-8b04-4a9b-8176-c2f2ecb97e6d
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
@@ -2997,7 +3066,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &1007103283 --- !u!1 &1007103283
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -3361,6 +3429,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -3401,6 +3470,18 @@ MonoBehaviour:
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: 03a60622-a192-4d59-b71c-846ad1399680
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: m_Name:
m_Type: 0 m_Type: 0
@@ -3419,7 +3500,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1001 &1226082257 --- !u!1001 &1226082257
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -3736,6 +3816,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -3754,6 +3835,14 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Position Input m_Action: Position Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: 34a62fdc-c1b6-4cf1-a7de-b7024d3ca2cf
m_Path: <HandInteraction>{LeftHand}/pointerPosition
m_Interactions:
m_Processors:
m_Groups:
m_Action: Position Input
m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_RotationInput: m_RotationInput:
@@ -3774,6 +3863,26 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Rotation Input m_Action: Rotation Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: 6e74078d-e467-4dc6-8023-a29a8e78d576
m_Path: <HandInteraction>{LeftHand}/pointerRotation
m_Interactions:
m_Processors:
m_Groups:
m_Action: Rotation Input
m_Flags: 0
m_Flags: 0
m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: 6a3020fa-bbda-4b50-adfe-31d7c651a205
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
@@ -3794,7 +3903,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &1414890483 --- !u!1 &1414890483
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -4053,6 +4161,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -4071,6 +4180,14 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Position Input m_Action: Position Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: 449e07f6-b6de-4297-8c24-68fa0c54203b
m_Path: <HandInteraction>{RightHand}/devicePosition
m_Interactions:
m_Processors:
m_Groups:
m_Action: Position Input
m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_RotationInput: m_RotationInput:
@@ -4091,6 +4208,26 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Rotation Input m_Action: Rotation Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: 2d2d7513-e9e2-44fe-a2f3-8519275ddf39
m_Path: <HandInteraction>{RightHand}/deviceRotation
m_Interactions:
m_Processors:
m_Groups:
m_Action: Rotation Input
m_Flags: 0
m_Flags: 0
m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: f109a673-1db0-4c0a-90b3-7d2f485e71e1
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
@@ -4111,7 +4248,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1001 &1495351303 --- !u!1001 &1495351303
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -4760,6 +4896,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -4778,6 +4915,14 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Position Input m_Action: Position Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: a98522ae-3d15-4f68-8b52-3e0b07bac073
m_Path: <HandInteraction>{RightHand}/pokePosition
m_Interactions:
m_Processors:
m_Groups:
m_Action: Position Input
m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_RotationInput: m_RotationInput:
@@ -4798,6 +4943,26 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Rotation Input m_Action: Rotation Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: a5a97017-b5d5-497d-b9e8-a4c31f49c490
m_Path: <HandInteraction>{RightHand}/pokeRotation
m_Interactions:
m_Processors:
m_Groups:
m_Action: Rotation Input
m_Flags: 0
m_Flags: 0
m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: 1105b297-66c4-46e5-a497-8c5fada26fca
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
@@ -4818,7 +4983,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &1708107229 --- !u!1 &1708107229
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -5771,6 +5935,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -5811,6 +5976,18 @@ MonoBehaviour:
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: dbd06a1e-0881-4702-b7ef-a4bb81c023fd
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: m_Name:
m_Type: 0 m_Type: 0
@@ -5829,7 +6006,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &1947228662 --- !u!1 &1947228662
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -5893,6 +6069,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -5911,6 +6088,14 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Position Input m_Action: Position Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: b51f75c3-0d11-4a26-b603-185a4f559861
m_Path: <HandInteraction>{LeftHand}/pokePosition
m_Interactions:
m_Processors:
m_Groups:
m_Action: Position Input
m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_RotationInput: m_RotationInput:
@@ -5931,6 +6116,26 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Rotation Input m_Action: Rotation Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: 59e61b20-ab73-411d-8b56-ac6f0e182f9d
m_Path: <HandInteraction>{LeftHand}/pokeRotation
m_Interactions:
m_Processors:
m_Groups:
m_Action: Rotation Input
m_Flags: 0
m_Flags: 0
m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: 52fe8957-1665-4732-a1a1-f95cc70a1c78
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
@@ -5951,7 +6156,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &1962967395 --- !u!1 &1962967395
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -6093,6 +6297,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -6111,6 +6316,14 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Position Input m_Action: Position Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: 2b53a195-ce43-4708-a385-e61a8c6ec293
m_Path: <HandInteraction>{LeftHand}/devicePosition
m_Interactions:
m_Processors:
m_Groups:
m_Action: Position Input
m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_RotationInput: m_RotationInput:
@@ -6131,6 +6344,26 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Rotation Input m_Action: Rotation Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: 5717e88d-f9be-4c5d-a42b-a82e179bc64d
m_Path: <HandInteraction>{LeftHand}/deviceRotation
m_Interactions:
m_Processors:
m_Groups:
m_Action: Rotation Input
m_Flags: 0
m_Flags: 0
m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: ec3ea843-1c14-4b82-a1ca-3e61d0da8985
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
@@ -6151,7 +6384,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &2064717940 --- !u!1 &2064717940
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -6215,6 +6447,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -6255,6 +6488,18 @@ MonoBehaviour:
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: eb274547-769d-45f6-890b-abda078e5899
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: m_Name:
m_Type: 0 m_Type: 0
@@ -6273,7 +6518,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &2073298331 --- !u!1 &2073298331
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -6504,6 +6748,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -6522,6 +6767,14 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Position Input m_Action: Position Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: b9726b6c-9ecb-4694-982a-9099c7c1df5e
m_Path: <HandInteraction>{RightHand}/pointerPosition
m_Interactions:
m_Processors:
m_Groups:
m_Action: Position Input
m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_RotationInput: m_RotationInput:
@@ -6542,6 +6795,26 @@ MonoBehaviour:
m_Groups: m_Groups:
m_Action: Rotation Input m_Action: Rotation Input
m_Flags: 0 m_Flags: 0
- m_Name:
m_Id: fdb8ffda-f0d5-4c9b-b785-6afb920dafa8
m_Path: <HandInteraction>{RightHand}/pointerRotation
m_Interactions:
m_Processors:
m_Groups:
m_Action: Rotation Input
m_Flags: 0
m_Flags: 0
m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: 0b86eacc-f773-400d-98a7-92e950a58b04
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
@@ -6562,7 +6835,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!4 &543450651583740275 stripped --- !u!4 &543450651583740275 stripped
Transform: Transform:
m_CorrespondingSourceObject: {fileID: 5562507940235781211, guid: a6579de606ad5b54893722f363b5371d, type: 3} m_CorrespondingSourceObject: {fileID: 5562507940235781211, guid: a6579de606ad5b54893722f363b5371d, type: 3}
@@ -7983,6 +8255,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -8023,6 +8296,18 @@ MonoBehaviour:
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: 8d1a2e5f-8b6f-4fa9-a4d9-b17c00a26569
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: Position m_Name: Position
m_Type: 0 m_Type: 0
@@ -8057,7 +8342,6 @@ MonoBehaviour:
m_Action: Rotation m_Action: Rotation
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &6088718223833369450 --- !u!1 &6088718223833369450
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -8172,6 +8456,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -8212,6 +8497,18 @@ MonoBehaviour:
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: 7b3328e4-c5ac-4bf5-86d8-e72901205f35
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: Position m_Name: Position
m_Type: 0 m_Type: 0
@@ -8246,7 +8543,6 @@ MonoBehaviour:
m_Action: Rotation m_Action: Rotation
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &6088718223950534255 --- !u!1 &6088718223950534255
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -8736,6 +9032,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 0 m_UseReference: 0
m_Action: m_Action:
@@ -8776,6 +9073,18 @@ MonoBehaviour:
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 0} m_Reference: {fileID: 0}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name: Tracking State Input
m_Type: 0
m_ExpectedControlType:
m_Id: ae1fc38a-9c71-495c-aab6-ed33ddf01498
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: Position m_Name: Position
m_Type: 0 m_Type: 0
@@ -8810,7 +9119,6 @@ MonoBehaviour:
m_Action: Rotation m_Action: Rotation
m_Flags: 0 m_Flags: 0
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1001 &7278110509245602027 --- !u!1001 &7278110509245602027
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@@ -27,7 +27,7 @@ namespace UnityEngine.XR.OpenXR.Samples.ControllerSample
if (m_ActionReference != null if (m_ActionReference != null
&& m_ActionReference.action != null && m_ActionReference.action != null
&& m_ActionReference.action.controls.Count > 0 //&& m_ActionReference.action.controls.Count > 0 // The Count of InputActionProperty will become 0 after switching interaction profiles.
&& m_ActionReference.action.enabled == true) && m_ActionReference.action.enabled == true)
{ {
m_TargetGameobject.SetActive(true); m_TargetGameobject.SetActive(true);

View File

@@ -24,7 +24,7 @@ namespace UnityEngine.XR.OpenXR.Samples.ControllerSample
if (m_TimeRemainingTillChange <= 0.0f) if (m_TimeRemainingTillChange <= 0.0f)
{ {
List<XRInputSubsystem> inputSubsystems = new List<XRInputSubsystem>(); List<XRInputSubsystem> inputSubsystems = new List<XRInputSubsystem>();
SubsystemManager.GetInstances(inputSubsystems); SubsystemManager.GetSubsystems(inputSubsystems);
XRInputSubsystem subsystem = inputSubsystems?[0]; XRInputSubsystem subsystem = inputSubsystems?[0];
if (subsystem != null) if (subsystem != null)
{ {

View File

@@ -138,7 +138,7 @@ namespace UnityEngine.XR.OpenXR.Samples.ControllerSample
XRInputSubsystem subsystem = null; XRInputSubsystem subsystem = null;
SubsystemManager.GetInstances(s_InputSubsystems); SubsystemManager.GetSubsystems(s_InputSubsystems);
if(s_InputSubsystems.Count > 0) if(s_InputSubsystems.Count > 0)
{ {
subsystem = s_InputSubsystems[0]; subsystem = s_InputSubsystems[0];

View File

@@ -0,0 +1,37 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
namespace VIVE.OpenXR.Samples.OpenXRInput
{
public class RemoveRenderMask : MonoBehaviour
{
private void OnEnable()
{
StartCoroutine(RemoveOcclusionMask());
}
IEnumerator RemoveOcclusionMask()
{
// Find DisplaySubsystem
XRDisplaySubsystem display = null;
List<XRDisplaySubsystem> displaySubsystems = new List<XRDisplaySubsystem>();
do
{
SubsystemManager.GetSubsystems(displaySubsystems);
foreach (var d in displaySubsystems)
{
if (d.running)
{
display = d;
break;
}
}
yield return null;
} while (display == null);
Debug.Log("RemoveOcclusionMask XRSettings.occlusionMaskScale = 0");
XRSettings.occlusionMaskScale = 0;
XRSettings.useOcclusionMesh = false;
}
}
}

View File

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

View File

@@ -29,7 +29,7 @@ public class PlaneDetectionTestHandle : MonoBehaviour
void GetXRInputSubsystem() void GetXRInputSubsystem()
{ {
List<XRInputSubsystem> xrSubsystemList = new List<XRInputSubsystem>(); List<XRInputSubsystem> xrSubsystemList = new List<XRInputSubsystem>();
SubsystemManager.GetInstances(xrSubsystemList); SubsystemManager.GetSubsystems(xrSubsystemList);
foreach (var xrSubsystem in xrSubsystemList) foreach (var xrSubsystem in xrSubsystemList)
{ {
if (xrSubsystem.running) if (xrSubsystem.running)

View File

@@ -96,7 +96,11 @@ public class Controller : MonoBehaviour
{ {
GameObject ball = Instantiate(sphere, spawnPoint); GameObject ball = Instantiate(sphere, spawnPoint);
Rigidbody rb = ball.GetComponent<Rigidbody>(); Rigidbody rb = ball.GetComponent<Rigidbody>();
#if UNITY_6000_0_OR_NEWER
rb.linearVelocity = ball.transform.parent.forward * shootVelocity;
#else
rb.velocity = ball.transform.parent.forward * shootVelocity; rb.velocity = ball.transform.parent.forward * shootVelocity;
#endif
rb.isKinematic = false; rb.isKinematic = false;
ball.transform.parent = null; ball.transform.parent = null;
} }

View File

@@ -21,7 +21,11 @@ namespace UnityEngine.XR.OpenXR.Samples.MeshingFeature
{ {
if (transform.position.y < -10) if (transform.position.y < -10)
{ {
#if UNITY_6000_0_OR_NEWER
rb.linearVelocity = Vector3.zero;
#else
rb.velocity = Vector3.zero; rb.velocity = Vector3.zero;
#endif
rb.angularVelocity = Vector3.zero; rb.angularVelocity = Vector3.zero;
rb.MovePosition(starting); rb.MovePosition(starting);
} }

View File

@@ -85,7 +85,7 @@ namespace UnityEngine.XR.OpenXR.Samples.MeshingFeature
} }
var meshSubsystems = new List<XRMeshSubsystem>(); var meshSubsystems = new List<XRMeshSubsystem>();
SubsystemManager.GetInstances(meshSubsystems); SubsystemManager.GetSubsystems(meshSubsystems);
if (meshSubsystems.Count == 1) if (meshSubsystems.Count == 1)
{ {
s_MeshSubsystem = meshSubsystems[0]; s_MeshSubsystem = meshSubsystems[0];

View File

@@ -23,6 +23,11 @@
"autoReferenced": true, "autoReferenced": true,
"defineConstraints": [], "defineConstraints": [],
"versionDefines": [ "versionDefines": [
{
"name": "com.unity.textmeshpro",
"expression": "3.2.0-pre.10",
"define": "UNITY_TEXT_MESH_PRO_3_2_0_PRE_10_OR_NEWER"
},
{ {
"name": "com.unity.xr.openxr", "name": "com.unity.xr.openxr",
"expression": "1.6.0", "expression": "1.6.0",
@@ -32,11 +37,6 @@
"name": "com.unity.xr.openxr", "name": "com.unity.xr.openxr",
"expression": "1.9.1", "expression": "1.9.1",
"define": "UNITY_XR_OPENXR_1_9_1" "define": "UNITY_XR_OPENXR_1_9_1"
},
{
"name": "com.unity.textmeshpro",
"expression": "3.2.0-pre.10",
"define": "UNITY_TEXT_MESH_PRO_3_2_0_PRE_10_OR_NEWER"
} }
], ],
"noEngineReferences": false "noEngineReferences": false

View File

@@ -23034,7 +23034,7 @@ GameObject:
- component: {fileID: 785420544} - component: {fileID: 785420544}
- component: {fileID: 785420543} - component: {fileID: 785420543}
- component: {fileID: 785420542} - component: {fileID: 785420542}
- component: {fileID: 785420541} - component: {fileID: 785420545}
m_Layer: 5 m_Layer: 5
m_Name: QuitBtn m_Name: QuitBtn
m_TagString: Untagged m_TagString: Untagged
@@ -23063,18 +23063,6 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: -96} m_AnchoredPosition: {x: 0, y: -96}
m_SizeDelta: {x: 86.2, y: 30} m_SizeDelta: {x: 86.2, y: 30}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &785420541
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 785420539}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b661f25ed5b57874290a0bafb5ad8234, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &785420542 --- !u!114 &785420542
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -23119,8 +23107,8 @@ MonoBehaviour:
m_OnClick: m_OnClick:
m_PersistentCalls: m_PersistentCalls:
m_Calls: m_Calls:
- m_Target: {fileID: 785420541} - m_Target: {fileID: 785420545}
m_TargetAssemblyTypeName: Wave.Essence.Extra.QuitApplication, Wave.Essence m_TargetAssemblyTypeName: VIVE.OpenXR.Toolkits.Common.LeaveScene, VIVE.OpenXR.Toolkits
m_MethodName: ExitGame m_MethodName: ExitGame
m_Mode: 1 m_Mode: 1
m_Arguments: m_Arguments:
@@ -23169,6 +23157,18 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 785420539} m_GameObject: {fileID: 785420539}
m_CullTransparentMesh: 1 m_CullTransparentMesh: 1
--- !u!114 &785420545
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 785420539}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 46285a19de0bb1b4f849a4b0bcfc5c0f, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &792366970 --- !u!1 &792366970
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -68792,6 +68792,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 1 m_UseReference: 1
m_Action: m_Action:
@@ -68816,6 +68817,18 @@ MonoBehaviour:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: 3113219943245244623, guid: 7731a6c81e069424eb7df31b19b84b41, type: 3} m_Reference: {fileID: 3113219943245244623, guid: 7731a6c81e069424eb7df31b19b84b41, type: 3}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name:
m_Type: 0
m_ExpectedControlType:
m_Id: 49637aaa-d811-48fe-9f86-4076b1bbf006
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: m_Name:
m_Type: 0 m_Type: 0
@@ -68834,7 +68847,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!4 &2336634745151424894 --- !u!4 &2336634745151424894
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -68947,6 +68959,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 1 m_UseReference: 1
m_Action: m_Action:
@@ -68971,6 +68984,18 @@ MonoBehaviour:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: -5246335118593862002, guid: 7731a6c81e069424eb7df31b19b84b41, type: 3} m_Reference: {fileID: -5246335118593862002, guid: 7731a6c81e069424eb7df31b19b84b41, type: 3}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name:
m_Type: 0
m_ExpectedControlType:
m_Id: 49846443-d944-470e-969c-29e6fe616f69
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: m_Name:
m_Type: 0 m_Type: 0
@@ -68989,7 +69014,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &2336634745461817778 --- !u!1 &2336634745461817778
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -69698,6 +69722,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_TrackingType: 0 m_TrackingType: 0
m_UpdateType: 0 m_UpdateType: 0
m_IgnoreTrackingState: 0
m_PositionInput: m_PositionInput:
m_UseReference: 1 m_UseReference: 1
m_Action: m_Action:
@@ -69722,6 +69747,18 @@ MonoBehaviour:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_Reference: {fileID: -3341103204585363708, guid: 7731a6c81e069424eb7df31b19b84b41, type: 3} m_Reference: {fileID: -3341103204585363708, guid: 7731a6c81e069424eb7df31b19b84b41, type: 3}
m_TrackingStateInput:
m_UseReference: 0
m_Action:
m_Name:
m_Type: 0
m_ExpectedControlType:
m_Id: 346b5aa3-6f99-4b26-847e-776c912c914e
m_Processors:
m_Interactions:
m_SingletonActionBindings: []
m_Flags: 0
m_Reference: {fileID: 0}
m_PositionAction: m_PositionAction:
m_Name: m_Name:
m_Type: 0 m_Type: 0
@@ -69740,7 +69777,6 @@ MonoBehaviour:
m_Interactions: m_Interactions:
m_SingletonActionBindings: [] m_SingletonActionBindings: []
m_Flags: 0 m_Flags: 0
m_HasMigratedActions: 1
--- !u!1 &2336634746049650654 --- !u!1 &2336634746049650654
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@@ -1,7 +1,7 @@
{ {
"name": "com.htc.upm.vive.openxr", "name": "com.htc.upm.vive.openxr",
"displayName": "VIVE OpenXR Plugin", "displayName": "VIVE OpenXR Plugin",
"version": "2.5.0", "version": "2.5.1",
"unity": "2021.3", "unity": "2021.3",
"description": "The \"VIVE OpenXR Plugin\" package enables your application to run on VIVE devices. \nThis package is a bridge between VIVE devides and Unity OpenXR.\nThis package complements Unity's \"OpenXR Plugin\" package, and enables you to use extra features, as listed in the following.\n\n- Controller Input\n- Hand Tracking\n- Wrist Tracking\n- Eye Gaze\n- CompositionLayer\n- Facial Tracking\n\n\nYou can view the documentation for additional information.", "description": "The \"VIVE OpenXR Plugin\" package enables your application to run on VIVE devices. \nThis package is a bridge between VIVE devides and Unity OpenXR.\nThis package complements Unity's \"OpenXR Plugin\" package, and enables you to use extra features, as listed in the following.\n\n- Controller Input\n- Hand Tracking\n- Wrist Tracking\n- Eye Gaze\n- CompositionLayer\n- Facial Tracking\n\n\nYou can view the documentation for additional information.",
"keywords": [ "keywords": [
@@ -15,9 +15,10 @@
"url": "https://www.htc.com" "url": "https://www.htc.com"
}, },
"dependencies": { "dependencies": {
"com.unity.inputsystem": "1.4.3",
"com.unity.xr.management": "4.2.1", "com.unity.xr.management": "4.2.1",
"com.unity.xr.openxr": "1.3.1" "com.unity.inputsystem": "1.7.0",
"com.unity.xr.openxr": "1.12.1",
"com.unity.xr.interaction.toolkit": "2.5.4"
}, },
"samples": [ "samples": [
{ {
@@ -33,6 +34,6 @@
], ],
"type": "library", "type": "library",
"hideInEditor": false, "hideInEditor": false,
"documentationUrl": "https://developer.vive.com/resources/openxr/openxr-mobile/tutorials/unity/getting-started-openxr-mobile/", "documentationUrl": "https://developer.vive.com/resources/openxr/unity/tutorials/setup-and-installation/getting-started-with-openxr/",
"changelogUrl": "https://developer.vive.com/resources/openxr/openxr-mobile/download/latest/" "changelogUrl": "https://developer.vive.com/resources/openxr/unity/download/latest/"
} }