1 Commits

Author SHA1 Message Date
Sean Lu
2bfa2ad4c7 version 2.5.0 2024-12-06 15:44:37 +08:00
269 changed files with 2222 additions and 60000 deletions

150
.gitattributes vendored
View File

@@ -1,24 +1,132 @@
# Set the default behavior, in case people don't have core.autocrlf set.
#https://gist.githubusercontent.com/nemotoo/b8a1c3a0f1225bb9231979f389fd4f3f/raw/dc3e8cab80fc62d1c60db70c761b1ffa636aa796/.gitattributes
#grafted from https://hextantstudios.com/unity-gitattributes/
# Macro for Unity YAML-based asset files.
[attr]unityyaml -text merge=unityyamlmerge diff
# Macro for all binary files that should use Git LFS.
[attr]lfs -text filter=lfs diff=lfs merge=lfs
# Default to auto-normalized line endings.
* text=auto
## Unity ##
*.txt text
*.cs diff=csharp text
*.cginc text
*.shader text
*.mat merge=unityyamlmerge eol=lf
*.anim merge=unityyamlmerge eol=lf
*.unity merge=unityyamlmerge eol=lf
*.prefab merge=unityyamlmerge eol=lf
*.physicsMaterial2D merge=unityyamlmerge eol=lf
*.physicsMaterial merge=unityyamlmerge eol=lf
*.physicMaterial merge=unityyamlmerge eol=lf
*.asset merge=unityyamlmerge eol=lf
*.meta merge=unityyamlmerge eol=lf
*.controller merge=unityyamlmerge eol=lf
*.flare merge=unityyamlmerge eol=lf
# Code
*.cs text diff=csharp
# Unity Text Assets
*.meta unityyaml
*.unity unityyaml
*.asset unityyaml
*.prefab unityyaml
*.mat unityyaml
#asink: anim files can get large
*.anim unityyaml lfs
*.controller unityyaml
*.overrideController unityyaml
*.physicMaterial unityyaml
*.physicsMaterial2D unityyaml
*.playable unityyaml
*.mask unityyaml
*.brush unityyaml
*.flare unityyaml
*.fontsettings unityyaml
*.guiskin unityyaml
*.giparams unityyaml
*.renderTexture unityyaml
*.spriteatlas unityyaml
*.terrainlayer unityyaml
*.mixer unityyaml
*.shadervariants unityyaml
*.preset unityyaml
*.asmdef -text diff
# Unity Binary Assets
*.cubemap lfs
*.unitypackage lfs
# Note: Unity terrain assets must have "-Terrain" suffix.
*-[Tt]errain.asset -unityyaml lfs
# Note: Unity navmesh assets must have "-NavMesh" suffix.
*-[Nn]av[Mm]esh.asset -unityyaml lfs
## git-lfs ##
#Image
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
#Audio
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
#Video
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
#3D Object
*.FBX -text
*.fbx -text
*.blend -text
*.obj -text
*.FBX filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
#ETC
*.a filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.unitypackage filter=lfs diff=lfs merge=lfs -text
*.aif filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.rns filter=lfs diff=lfs merge=lfs -text
*.reason filter=lfs diff=lfs merge=lfs -text
*.lxo filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.aar filter=lfs diff=lfs merge=lfs -text
*.lighting filter=lfs diff=lfs merge=lfs -text
#/LocalPackages (tests_withnewpackage)
#$ find . -type f | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort -u
#$ find ./* -type f | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort -u
#LICENSE
#LICENSE_WaveSDKNativeBinary
#aar
#anim
#apk
#asmdef
#asset
#bat
#controller
#cs
#default
#dll
#docx
#dummy
#exe
#exr
#fbx
#gitignored
#ini
#inputactions
#json
#lighting
#mat
#md
#meta
#mtl
#obj
#physicMaterial
#png
#prefab
#preset
#renderTexture
#setting
#shader
#so
#tm1
#tmp
#txt
#unity
#unitypackage
#wav
#xml
*.hdr filter=lfs diff=lfs merge=lfs -text
*.lighting filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text

View File

@@ -281,8 +281,7 @@ namespace VIVE.OpenXR.Editor
}
}
var features = settings.GetFeatures<OpenXRFeature>();
foreach (var feature in features)
foreach (var feature in settings.GetFeatures<OpenXRFeature>())
{
if (!feature.enabled) { continue; }
@@ -311,17 +310,6 @@ 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)

View File

@@ -51,39 +51,6 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
static GUIContent Label_QuadHeight = new GUIContent("Height", "Height of a Quad Layer");
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 GUIContent Label_CylinderHeight = new GUIContent("Height", "Height of Cylinder Layer");
SerializedProperty Property_CylinderHeight;
@@ -171,14 +138,6 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
if (Property_LockMode == null) Property_LockMode = serializedObject.FindProperty(PropertyName_LockMode);
if (Property_QuadWidth == null) Property_QuadWidth = serializedObject.FindProperty(PropertyName_QuadWidth);
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_CylinderArcLength == null) Property_CylinderArcLength = serializedObject.FindProperty(PropertyName_CylinderArcLength);
if (Property_CylinderRadius == null) Property_CylinderRadius = serializedObject.FindProperty(PropertyName_CylinderRadius);
@@ -212,138 +171,6 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
EditorGUILayout.PropertyField(Property_LayerShape, new GUIContent(Label_LayerShape));
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 (!FeatureHelpers.GetFeatureWithIdForBuildTarget(BuildTargetGroup.Android, ViveCompositionLayerCylinder.featureId).enabled)
@@ -360,15 +187,6 @@ 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);
if (generatedQuadTransform != null)
{
@@ -462,7 +280,6 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
if (targetCompositionLayer.isPreviewingCylinder)
{
Transform generatedPreviewTransform = targetCompositionLayer.transform.Find(CompositionLayer.CylinderPreviewName);
if (generatedPreviewTransform != null)
@@ -555,15 +372,6 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
}
}
if (targetCompositionLayer.isPreviewingEquirect)
{
targetCompositionLayer.isPreviewingEquirect = false;
if (targetCompositionLayer.generatedPreview != null)
{
DestroyImmediate(targetCompositionLayer.generatedPreview);
}
}
EditorGUI.indentLevel++;
showLayerParams = EditorGUILayout.Foldout(showLayerParams, "Quad Parameters");
if (showLayerParams)
@@ -699,7 +507,7 @@ namespace VIVE.OpenXR.CompositionLayer.Editor
EditorGUI.indentLevel--;
}*/
if((Property_LayerShape.intValue != (int)CompositionLayer.LayerShape.Equirect && Property_LayerShape.intValue != (int)CompositionLayer.LayerShape.Equirect2) && (targetCompositionLayer.textureLeft == targetCompositionLayer.textureRight || targetCompositionLayer.textureRight == null))
if (targetCompositionLayer.textureLeft == targetCompositionLayer.textureRight || targetCompositionLayer.textureRight == null)
{
EditorGUILayout.PropertyField(Property_IsCustomRects, Label_IsCustomRects);
serializedObject.ApplyModifiedProperties();

View File

@@ -93,9 +93,9 @@ public static class PackageManagerHelper
case StatusCode.Failure:
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;
m_removeRequest = null;
Debug.LogError("Something wrong when removing package from list. error:" + m_removeRequest.Error.errorCode + "(" + m_removeRequest.Error.message + ")");
}
break;
case StatusCode.Success:

View File

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

View File

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

View File

@@ -7,17 +7,8 @@ namespace VIVE.OpenXR.Feature
{
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);
/// <summary>
/// OnInstanceDestroy might be called multiple times. Because many features might be using the same instance.
/// </summary>
public void OnInstanceDestroy();
}
@@ -30,11 +21,6 @@ namespace VIVE.OpenXR.Feature
// Set true in yourfeature's OnInstanceCreate
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;
/// <summary>

View File

@@ -1,112 +1,24 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine.Profiling;
namespace VIVE.OpenXR
{
internal static class MemoryTools
public 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>
/// Convert the enum array to IntPtr. Should call <see cref="ReleaseRawMemory(IntPtr)"/> after use.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="array"></param>
/// <returns></returns>
public static unsafe IntPtr ToIntPtr<T>(T[] array) where T : Enum
public static IntPtr ToIntPtr<T>(T[] array) where T : Enum
{
int size = sizeof(int) * array.Length;
int size = Marshal.SizeOf(typeof(T)) * array.Length;
IntPtr ptr = Marshal.AllocHGlobal(size);
int* intPtr = (int*)ptr.ToPointer();
int[] intArray = new int[array.Length];
for (int i = 0; i < array.Length; i++)
{
// 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);
intArray[i] = (int)(object)array[i];
Marshal.Copy(intArray, 0, ptr, array.Length);
return ptr;
}
@@ -116,7 +28,7 @@ namespace VIVE.OpenXR
/// <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>
/// <returns>The memory handle. Should release by <see cref="ReleaseRawMemory(IntPtr)"/></returns>
public static unsafe IntPtr MakeRawMemory<T>(T[] refArray) where T : unmanaged
public static IntPtr MakeRawMemory<T>(T[] refArray)
{
int size = Marshal.SizeOf(typeof(T)) * refArray.Length;
return Marshal.AllocHGlobal(size);
@@ -129,54 +41,16 @@ namespace VIVE.OpenXR
/// <param name="array">The output array.</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>
public static unsafe void CopyFromRawMemory<T>(T[] array, IntPtr raw, int count = 0) where T : unmanaged
public static void CopyFromRawMemory<T>(T[] array, IntPtr raw, int count = 0)
{
//Profiler.BeginSample("CopyFromRawMemory");
int N = array.Length;
if (count > 0 && count < array.Length)
N = count;
int step = sizeof(T);
int bufferSize = step * N;
// Pin array's address. Prevent GC move it.
fixed (T* destPtr = array)
int step = Marshal.SizeOf(typeof(T));
for (int i = 0; i < N; i++)
{
T* sourcePtr = (T*)raw.ToPointer();
Buffer.MemoryCopy(sourcePtr, destPtr, bufferSize, bufferSize);
array[i] = Marshal.PtrToStructure<T>(IntPtr.Add(raw, i * step));
}
//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>
@@ -185,18 +59,13 @@ namespace VIVE.OpenXR
/// <typeparam name="T">Convert this type array to raw memory.</typeparam>
/// <param name="raw">The output data in raw memory form</param>
/// <param name="array">The data source</param>
public static unsafe void CopyToRawMemory<T>(IntPtr raw, T[] array) where T : unmanaged
public static void CopyToRawMemory<T>(IntPtr raw, T[] array)
{
//Profiler.BeginSample("CopyToRawMemory");
int step = sizeof(T);
int bufferSize = step * array.Length;
// Pin array's address. Prevent GC move it.
fixed (T* destPtr = array)
int step = Marshal.SizeOf(typeof(T));
for (int i = 0; i < array.Length; i++)
{
void* ptr = raw.ToPointer();
Buffer.MemoryCopy(destPtr, ptr, bufferSize, bufferSize);
Marshal.StructureToPtr<T>(array[i], IntPtr.Add(raw, i * step), false);
}
//Profiler.EndSample();
}
/// <summary>
@@ -207,22 +76,5 @@ namespace VIVE.OpenXR
{
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

@@ -1,278 +0,0 @@
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

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

View File

@@ -10,14 +10,9 @@ namespace VIVE.OpenXR.Feature
/// <summary>
/// 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().
///
/// 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>
internal class CommonWrapper : ViveFeatureWrapperBase<CommonWrapper>, IViveFeatureWrapper
public class CommonWrapper : ViveFeatureWrapperBase<CommonWrapper>, IViveFeatureWrapper
{
const string TAG = "CommonWrapper";
OpenXRHelper.xrGetSystemPropertiesDelegate XrGetSystemProperties;
OpenXRHelper.xrCreateSwapchainDelegate XrCreateSwapchain;
OpenXRHelper.xrDestroySwapchainDelegate XrDestroySwapchain;
@@ -37,13 +32,11 @@ namespace VIVE.OpenXR.Feature
public bool OnInstanceCreate(XrInstance xrInstance, IntPtr xrGetInstanceProcAddrPtr)
{
if (IsInited) return true;
if (TryInited) return false;
TryInited = true;
if (xrInstance == 0)
throw new Exception("CommonWrapper: xrInstance is null");
Log.D(TAG, "OnInstanceCreate()");
Debug.Log("CommonWrapper: OnInstanceCreate()");
SetGetInstanceProcAddrPtr(xrGetInstanceProcAddrPtr);
bool ret = true;
@@ -71,11 +64,9 @@ namespace VIVE.OpenXR.Feature
/// <returns></returns>
public void OnInstanceDestroy()
{
// Do not destroy twice
if (IsInited == false) return;
IsInited = false;
XrGetSystemProperties = null;
Log.D(TAG, "OnInstanceDestroy()");
Debug.Log("CommonWrapper: OnInstanceDestroy()");
}
public XrResult GetInstanceProcAddr(XrInstance instance, string name, out IntPtr function)
@@ -173,12 +164,12 @@ namespace VIVE.OpenXR.Feature
if (formatCapacityInput == 0)
{
Log.D(TAG, "EnumerateSwapchainFormats(ci=" + formatCapacityInput + ")");
Debug.Log("CommonWrapper: EnumerateSwapchainFormats(ci=" + formatCapacityInput + ")");
return XrEnumerateSwapchainFormats(session, 0, ref formatCountOutput, IntPtr.Zero);
}
else
{
Log.D(TAG, "EnumerateSwapchainFormats(ci=" + formatCapacityInput + ", formats=long[" + formats.Length + "])");
Debug.Log("CommonWrapper: EnumerateSwapchainFormats(ci=" + formatCapacityInput + ", formats=long[" + formats.Length + "])");
IntPtr formatsPtr = MemoryTools.MakeRawMemory(formats);
var ret = XrEnumerateSwapchainFormats(session, formatCapacityInput, ref formatCountOutput, formatsPtr);
if (ret == XrResult.XR_SUCCESS)
@@ -210,7 +201,7 @@ namespace VIVE.OpenXR.Feature
return XrResult.XR_ERROR_HANDLE_INVALID;
}
Profiler.BeginSample("ASW:xrAcqScImg");
Profiler.BeginSample("ASW: xrAcqScImg");
var res = XrAcquireSwapchainImage(swapchain, ref acquireInfo, out index);
Profiler.EndSample();
return res;
@@ -226,7 +217,7 @@ namespace VIVE.OpenXR.Feature
return XrResult.XR_ERROR_HANDLE_INVALID;
}
Profiler.BeginSample("ASW:xrWaitScImg");
Profiler.BeginSample("ASW: xrWaitScImg");
var res = XrWaitSwapchainImage(swapchain, ref waitInfo);
Profiler.EndSample();
return res;
@@ -243,7 +234,7 @@ namespace VIVE.OpenXR.Feature
}
// Add Profiler
Profiler.BeginSample("ASW:xrRelScImg");
Profiler.BeginSample("ASW: xrRelScImg");
var res = XrReleaseSwapchainImage(swapchain, ref releaseInfo);
Profiler.EndSample();
return res;

View File

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

View File

@@ -1,7 +1,6 @@
// Copyright HTC Corporation All Rights Reserved.
using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace VIVE.OpenXR.Feature
@@ -13,13 +12,9 @@ namespace VIVE.OpenXR.Feature
/// </summary>
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 DelegateXrDestroySpace(XrSpace space);
DelegateXrEnumerateReferenceSpaces XrEnumerateReferenceSpaces;
OpenXRHelper.xrCreateReferenceSpaceDelegate XrCreateReferenceSpace;
DelegateXrLocateSpace XrLocateSpace;
DelegateXrDestroySpace XrDestroySpace;
@@ -34,20 +29,17 @@ namespace VIVE.OpenXR.Feature
public bool OnInstanceCreate(XrInstance xrInstance, IntPtr GetAddr)
{
if (IsInited) return true;
if (TryInited) return false;
TryInited = true;
if (xrInstance == null)
throw new Exception("ViveSpaceWrapper: xrInstance is null");
throw new Exception("ViveSpace: xrInstance is null");
SetGetInstanceProcAddrPtr(GetAddr);
Log.D(TAG, "OnInstanceCreate()");
Debug.Log("ViveSpace: OnInstanceCreate()");
bool ret = true;
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, "xrLocateSpace", out XrLocateSpace);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrDestroySpace", out XrDestroySpace);
@@ -57,35 +49,12 @@ namespace VIVE.OpenXR.Feature
public void OnInstanceDestroy()
{
// Do not destroy twice
if (IsInited == false) return;
IsInited = false;
XrEnumerateReferenceSpaces = null;
XrCreateReferenceSpace = null;
XrLocateSpace = 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>
/// Create a reference space without create info.
/// Example:
@@ -139,7 +108,7 @@ namespace VIVE.OpenXR.Feature
{
if (!IsInited)
return XrResult.XR_ERROR_HANDLE_INVALID;
Log.D(TAG, $"DestroySpace({space})");
Debug.Log($"DestroySpace({space})");
return XrDestroySpace(space);
}
}
@@ -155,7 +124,7 @@ namespace VIVE.OpenXR.Feature
public Space(XrSpace space)
{
Log.D($"Space({space})");
Debug.Log($"Space({space})");
this.space = space;
}

View File

@@ -5,25 +5,9 @@ using UnityEngine;
using AOT;
using System.Collections.Generic;
using System.Text;
using System.Linq;
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>
/// 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.
@@ -38,15 +22,6 @@ namespace VIVE.OpenXR
/// return ViveInterceptors.Instance.HookGetInstanceProcAddr(func);
/// }
/// </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
{
public const string TAG = "VIVE.OpenXR.ViveInterceptors";
@@ -57,6 +32,8 @@ namespace VIVE.OpenXR
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
@@ -71,32 +48,15 @@ namespace VIVE.OpenXR
public ViveInterceptors()
{
Log.D("ViveInterceptors");
RegisterFunctions();
Debug.Log("ViveInterceptors");
}
delegate XrResult HookHandler(XrInstance instance, string name, out IntPtr function);
static readonly Dictionary<string, HookHandler> interceptors = new Dictionary<string, HookHandler>();
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);
public delegate XrResult DelegateXrGetInstanceProcAddr(XrInstance instance, string name, out IntPtr function);
private static readonly DelegateXrGetInstanceProcAddr hookXrGetInstanceProcAddrHandle = new DelegateXrGetInstanceProcAddr(XrGetInstanceProcAddrInterceptor);
private static readonly IntPtr hookGetInstanceProcAddrHandlePtr = Marshal.GetFunctionPointerForDelegate(hookXrGetInstanceProcAddrHandle);
static OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddrOriginal = null;
static DelegateXrGetInstanceProcAddr XrGetInstanceProcAddrOriginal = null;
[MonoPInvokeCallback(typeof(OpenXRHelper.xrGetInstanceProcAddrDelegate))]
[MonoPInvokeCallback(typeof(DelegateXrGetInstanceProcAddr))]
private static XrResult XrGetInstanceProcAddrInterceptor(XrInstance instance, string name, out IntPtr function)
{
// Used to check if the original function is already hooked.
@@ -106,16 +66,64 @@ namespace VIVE.OpenXR
return XrResult.XR_SUCCESS;
}
// Check if the function is intercepted by other features
if (interceptors.ContainsKey(name))
// Custom interceptors
if (name == "xrWaitFrame" && requiredFunctions.Contains(name))
{
// If no request for this function, call the original function directly.
if (!requiredFunctions.Contains(name))
return XrGetInstanceProcAddrOriginal(instance, name, out function);
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)
Log.I(TAG, name + " is intercepted");
{
XrWaitFrameOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrWaitFrame>(function);
function = xrWaitFrameInterceptorPtr;
}
return ret;
}
if (name == "xrEndFrame" && requiredFunctions.Contains(name))
{
Debug.Log($"{TAG}: XrGetInstanceProcAddrInterceptor() {name} is intercepted.");
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret == XrResult.XR_SUCCESS)
{
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;
}
@@ -124,23 +132,23 @@ namespace VIVE.OpenXR
public IntPtr HookGetInstanceProcAddr(IntPtr func)
{
Log.D(TAG, "HookGetInstanceProcAddr");
Debug.Log($"{TAG}: HookGetInstanceProcAddr");
if (XrGetInstanceProcAddrOriginal == null)
{
Log.D(TAG, "registering our own xrGetInstanceProcAddr");
XrGetInstanceProcAddrOriginal = Marshal.GetDelegateForFunctionPointer<OpenXRHelper.xrGetInstanceProcAddrDelegate>(func);
Debug.Log($"{TAG}: registering our own xrGetInstanceProcAddr");
XrGetInstanceProcAddrOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrGetInstanceProcAddr>(func);
#if UNITY_EDITOR
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.
Log.D(TAG, "Check if duplicate hooked by this script with instance=0 and \"ViveInterceptorHooked\" name. If following a loader error, ignore it.");
Debug.Log($"{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
// 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 it is called successfully, it means the original function is already hooked. So we should return the original function.
Log.D(TAG, "Already hooked");
Debug.Log($"{TAG}: Already hooked");
return func;
}
}
@@ -165,34 +173,9 @@ namespace VIVE.OpenXR
/// <param name="name"></param>
public void AddRequiredFunction(string name)
{
Log.D(TAG, $"AddRequiredFunction({name})");
if (!interceptors.ContainsKey(name))
{
Log.E(TAG, $"AddRequiredFunction({name}) failed. No such function.");
return;
}
if (!requiredFunctions.Contains(name))
if (requiredFunctions.Contains(name)) return;
Debug.Log($"{TAG}: AddRequiredFunction({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,21 +12,6 @@ namespace VIVE.OpenXR
{
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
public delegate XrResult xrBeginSessionDelegate(XrSession session, ref XrSessionBeginInfo beginInfo);
private static xrBeginSessionDelegate xrBeginSessionOrigin = null;
@@ -34,7 +19,7 @@ namespace VIVE.OpenXR
[MonoPInvokeCallback(typeof(xrBeginSessionDelegate))]
private static XrResult xrBeginSessionInterceptor(XrSession session, ref XrSessionBeginInfo beginInfo)
{
Profiler.BeginSample("VI:BeginSession");
Profiler.BeginSample("ViveInterceptors:BeginSession");
XrResult result = XrResult.XR_ERROR_FUNCTION_UNSUPPORTED;
if (xrBeginSessionOrigin != null)
@@ -63,8 +48,7 @@ namespace VIVE.OpenXR
IntPtr fs_begin_info_ptr = new IntPtr(offset);
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(")");
Log.D(sb);
sb.Clear().Append("xrBeginSessionInterceptor() beginInfo.next = (").Append(fsBeginInfo.type).Append(", ").Append(fsBeginInfo.mode).Append(")"); DEBUG(sb);
#endif
}
@@ -72,7 +56,7 @@ namespace VIVE.OpenXR
}
else
{
Log.E("xrBeginSessionInterceptor() Not assign xrBeginSession!");
sb.Clear().Append("xrBeginSessionInterceptor() Not assign xrBeginSession!"); ERROR(sb);
}
Profiler.EndSample();
@@ -95,8 +79,7 @@ namespace VIVE.OpenXR
{
m_EnableFrameSynchronization = active;
m_FrameSynchronizationMode = mode;
sb.Clear().Append("ActivateFrameSynchronization() ").Append(active ? "enable " : "disable ").Append(mode);
Log.D(sb);
sb.Clear().Append("ActivateFrameSynchronization() ").Append(active ? "enable " : "disable ").Append(mode); DEBUG(sb);
}
}
}

View File

@@ -1,98 +0,0 @@
// 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

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

View File

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

View File

@@ -8,20 +8,6 @@ namespace VIVE.OpenXR
{
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 XrStructureType type; // This base structure itself has no associated XrStructureType value.
@@ -51,16 +37,15 @@ namespace VIVE.OpenXR
// instance must not null
//if (instance == null)
// return XrEndFrameOriginal(session, ref frameEndInfo);
Profiler.BeginSample("VI:EndFrameB");
Profiler.BeginSample("VI:EndFrame");
XrResult result = XrResult.XR_SUCCESS;
bool ret = true;
if (instance.BeforeOriginalEndFrame != null)
ret = instance.BeforeOriginalEndFrame(session, ref frameEndInfo, ref result);
if (instance.BeforeOriginalEndFrame != null &&
!instance.BeforeOriginalEndFrame(session, ref frameEndInfo, ref result))
{
Profiler.EndSample();
if (!ret)
return result;
}
result = XrEndFrameOriginal(session, ref frameEndInfo);
Profiler.BeginSample("VI:EndFrameA");
instance.AfterOriginalEndFrame?.Invoke(session, ref frameEndInfo, ref result);
Profiler.EndSample();
return result;

View File

@@ -1,91 +0,0 @@
// 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

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

View File

@@ -9,20 +9,7 @@ namespace VIVE.OpenXR
{
partial class ViveInterceptors
{
[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;
}
#region XRWaitFrame
public struct XrFrameWaitInfo
{
public XrStructureType type;
@@ -116,5 +103,6 @@ namespace VIVE.OpenXR
/// Use this to intercept the original function. This will be called after the original function.
/// </summary>
public DelegateXrWaitFrameInterceptor AfterOriginalWaitFrame;
#endregion XRWaitFrame
}
}

View File

@@ -1,247 +0,0 @@
// 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

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

View File

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

View File

@@ -8,7 +8,6 @@ using UnityEngine.XR.OpenXR;
using System.Collections.Generic;
using System.Linq;
using VIVE.OpenXR.CompositionLayer;
using System.Runtime.CompilerServices;
namespace VIVE.OpenXR.CompositionLayer
{
@@ -17,18 +16,15 @@ namespace VIVE.OpenXR.CompositionLayer
#if UNITY_EDITOR
[SerializeField]
public bool isPreviewingCylinder = false;
public bool isPreviewingEquirect = false;
[SerializeField]
public bool isPreviewingQuad = false;
[SerializeField]
public GameObject generatedPreview = null;
public const string CylinderPreviewName = "CylinderPreview";
public const string EquirectPreviewName = "EquirectPreview";
public const string QuadPreviewName = "QuadPreview";
#endif
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 FallbackMeshName = "FallbackMeshGO";
@@ -60,15 +56,6 @@ namespace VIVE.OpenXR.CompositionLayer
public float QuadHeight { get { return m_QuadHeight; } set { m_QuadHeight = value; } }
#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]
[Min(0.001f)]
private float m_CylinderHeight = 1f;
@@ -87,66 +74,10 @@ namespace VIVE.OpenXR.CompositionLayer
[SerializeField]
[Min(0.001f)]
private float m_EquirectRadius = 1f;
public float equirectRadius { get { return m_EquirectRadius; } }
private float m_CylinderRadius = 1f;
public float cylinderRadius { get { return m_CylinderRadius; } }
#if UNITY_EDITOR
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; } }
public float CylinderRadius { get { return m_CylinderRadius; } set { m_CylinderRadius = value; } }
#endif
[SerializeField]
@@ -240,7 +171,6 @@ namespace VIVE.OpenXR.CompositionLayer
private LayerShape previousLayerShape = LayerShape.Quad;
private float previousQuadWidth = 1f;
private float previousQuadHeight = 1f;
private float previousEquirectRadius = 1f;
private float previousCylinderHeight = 1f;
private float previousCylinderArcLength = 1f;
private float previousCylinderRadius = 1f;
@@ -262,7 +192,7 @@ namespace VIVE.OpenXR.CompositionLayer
private bool placeholderGenerated = false;
private static bool isSynchronized = false;
private static RenderThreadSynchronizer synchronizer;
public Camera hmd;
private Camera hmd;
private ViveCompositionLayer compositionLayerFeature = null;
@@ -432,7 +362,6 @@ namespace VIVE.OpenXR.CompositionLayer
previousLayerShape = layerShape;
previousQuadWidth = m_QuadWidth;
previousQuadHeight = m_QuadHeight;
previousEquirectRadius = m_EquirectRadius;
previousCylinderHeight = m_CylinderHeight;
previousCylinderArcLength = m_CylinderArcLength;
previousCylinderRadius = m_CylinderRadius;
@@ -761,20 +690,6 @@ namespace VIVE.OpenXR.CompositionLayer
compositionLayerCylinderFeature.Submit_CompositionLayerCylinder(AssignCompositionLayerParamsCylinder(eyeid, botheye), (OpenXR.CompositionLayer.LayerType)layerType, compositionDepth, (eyeid == 0) ? layerID : layerIDRight);
}
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;
}
}
@@ -923,7 +838,7 @@ namespace VIVE.OpenXR.CompositionLayer
else
{
XRInputSubsystem subsystem = null;
SubsystemManager.GetSubsystems(inputSubsystems);
SubsystemManager.GetInstances(inputSubsystems);
if (inputSubsystems.Count > 0)
{
subsystem = inputSubsystems[0];
@@ -958,97 +873,6 @@ namespace VIVE.OpenXR.CompositionLayer
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();
private XrCompositionLayerCylinderKHR AssignCompositionLayerParamsCylinder(int eyeid, bool botheye)
{
@@ -1069,7 +893,7 @@ namespace VIVE.OpenXR.CompositionLayer
else
{
XRInputSubsystem subsystem = null;
SubsystemManager.GetSubsystems(inputSubsystems);
SubsystemManager.GetInstances(inputSubsystems);
if (inputSubsystems.Count > 0)
{
subsystem = inputSubsystems[0];
@@ -1298,15 +1122,7 @@ namespace VIVE.OpenXR.CompositionLayer
{
bool isChanged = false;
if (layerShape == LayerShape.Equirect)
{
if (previousEquirectRadius != m_EquirectRadius)
{
previousEquirectRadius = m_EquirectRadius;
isChanged = true;
}
}
else if (layerShape == LayerShape.Cylinder)
if (layerShape == LayerShape.Cylinder)
{
if (previousAngleOfArc != m_CylinderAngleOfArc ||
previousCylinderArcLength != m_CylinderArcLength ||
@@ -1767,9 +1583,6 @@ namespace VIVE.OpenXR.CompositionLayer
case LayerShape.Cylinder:
generatedMesh = MeshGenerationHelper.GenerateCylinderMesh(m_CylinderAngleOfArc, MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight));
break;
case LayerShape.Equirect:
generatedMesh = MeshGenerationHelper.GenerateEquirectMesh(hmd, m_EquirectRadius);
break;
}
generatedFallbackMesh = new GameObject();
@@ -1809,9 +1622,6 @@ namespace VIVE.OpenXR.CompositionLayer
case LayerShape.Cylinder:
generatedMesh = MeshGenerationHelper.GenerateCylinderMesh(m_CylinderAngleOfArc, MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight));
break;
case LayerShape.Equirect:
generatedMesh = MeshGenerationHelper.GenerateEquirectMesh(hmd, m_EquirectRadius);
break;
}
generatedFallbackMesh.transform.localScale = GetNormalizedLocalScale(transform, Vector3.one);
@@ -1847,26 +1657,6 @@ namespace VIVE.OpenXR.CompositionLayer
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:
//Generate vertices
Vector3[] cylinderVertices = MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight);
@@ -1928,10 +1718,6 @@ namespace VIVE.OpenXR.CompositionLayer
switch (layerShape)
{
case LayerShape.Equirect:
Destroy(generatedUnderlayMeshFilter.mesh);
generatedUnderlayMeshFilter.mesh = MeshGenerationHelper.GenerateEquirectMesh(hmd, m_EquirectRadius);
break;
case LayerShape.Cylinder:
//Generate vertices
Vector3[] cylinderVertices = MeshGenerationHelper.GenerateCylinderVertex(m_CylinderAngleOfArc, m_CylinderRadius, m_CylinderHeight);
@@ -1988,8 +1774,6 @@ namespace VIVE.OpenXR.CompositionLayer
{
Quad = 0,
Cylinder = 1,
Equirect = 2,
Equirect2 = 3,
}
public enum Visibility
@@ -2256,92 +2040,6 @@ namespace VIVE.OpenXR.CompositionLayer
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)
{
Mesh cylinderMesh = new Mesh();

View File

@@ -416,7 +416,6 @@ namespace VIVE.OpenXR.CompositionLayer.Passthrough
#if UNITY_ANDROID
return passthroughFeature.HTCPassthrough_DestroyPassthrough(passthroughID);
#endif
return false;
}
/// <summary>
@@ -475,7 +474,6 @@ namespace VIVE.OpenXR.CompositionLayer.Passthrough
else
return false;
#endif
return false;
}
/// <summary>
@@ -547,7 +545,6 @@ namespace VIVE.OpenXR.CompositionLayer.Passthrough
#if UNITY_ANDROID
return passthroughFeature.HTCPassthrough_SetMesh(passthroughID, (uint)vertexBuffer.Length, vertexBufferXrVector, (uint)indexBuffer.Length, indexBufferUint); ;
#endif
return false;
}
/// <summary>
@@ -626,7 +623,6 @@ namespace VIVE.OpenXR.CompositionLayer.Passthrough
#if UNITY_ANDROID
return passthroughFeature.HTCPassthrough_SetMeshTransform(passthroughID, passthroughFeature.GetXrSpaceFromSpaceType(spaceType), meshXrPose, meshXrScale);
#endif
return false;
}
/// <summary>
@@ -665,7 +661,7 @@ namespace VIVE.OpenXR.CompositionLayer.Passthrough
#if UNITY_ANDROID
return passthroughFeature.HTCPassthrough_SetLayerType(passthroughID, layerType, compositionDepth);
#endif
return false;
}
/// <summary>
@@ -706,7 +702,6 @@ namespace VIVE.OpenXR.CompositionLayer.Passthrough
#if UNITY_ANDROID
return passthroughFeature.HTCPassthrough_SetMeshTransformSpace(passthroughID, passthroughFeature.GetXrSpaceFromSpaceType(spaceType));
#endif
return false;
}
/// <summary>
@@ -769,7 +764,6 @@ namespace VIVE.OpenXR.CompositionLayer.Passthrough
#if UNITY_ANDROID
return passthroughFeature.HTCPassthrough_SetMeshTransformPosition(passthroughID, OpenXRHelper.ToOpenXRVector(trackingSpaceMeshPosition, convertFromUnityToOpenXR));
#endif
return false;
}
/// <summary>
@@ -832,7 +826,6 @@ namespace VIVE.OpenXR.CompositionLayer.Passthrough
#if UNITY_ANDROID
return passthroughFeature.HTCPassthrough_SetMeshTransformOrientation(passthroughID, OpenXRHelper.ToOpenXRQuaternion(trackingSpaceMeshRotation, convertFromUnityToOpenXR));
#endif
return false;
}
/// <summary>
@@ -874,7 +867,6 @@ namespace VIVE.OpenXR.CompositionLayer.Passthrough
#if UNITY_ANDROID
return passthroughFeature.HTCPassthrough_SetMeshTransformScale(passthroughID, OpenXRHelper.ToOpenXRVector(meshScale, false));
#endif
return false;
}
/// <summary>

View File

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

View File

@@ -1,120 +0,0 @@
// 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

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

View File

@@ -215,35 +215,6 @@ namespace VIVE.OpenXR.CompositionLayer
public float aspectRatio;
}
[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 XrSwapchain swapchain;

View File

@@ -1,6 +1,7 @@
# 12.1. XR_HTC_frame_synchronization
## Overview
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.
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.
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
XR_HTC_frame_synchronization
## Revision

View File

@@ -209,7 +209,7 @@ namespace VIVE.OpenXR.Hand
/// </summary>
protected override void RegisterDeviceLayout()
{
// sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(kDeviceLocalizedName); DEBUG(sb);
sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(kDeviceLocalizedName); DEBUG(sb);
InputSystem.RegisterLayout(typeof(HandInteractionDevice),
kLayoutName,
matches: new InputDeviceMatcher()
@@ -222,7 +222,7 @@ namespace VIVE.OpenXR.Hand
/// </summary>
protected override void UnregisterDeviceLayout()
{
// sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
InputSystem.RemoveLayout(kLayoutName);
}

View File

@@ -11,7 +11,6 @@ using UnityEngine.InputSystem;
using System.Collections.Generic;
using UnityEngine.XR;
using UnityEngine.XR.OpenXR.Input;
using System;
using System.Text;
#if UNITY_EDITOR
@@ -31,7 +30,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.
/// </summary>
#if UNITY_EDITOR
[OpenXRFeature(UiName = "VIVE XR Hand Interaction Ext (Deprecated)",
[OpenXRFeature(UiName = "VIVE XR Hand Interaction Ext",
Hidden = true,
BuildTargetGroups = new[] { BuildTargetGroup.Android },
Company = "HTC",
@@ -42,7 +41,6 @@ namespace VIVE.OpenXR.Hand
Category = FeatureCategory.Interaction,
FeatureId = featureId)]
#endif
[Obsolete("This class is deprecated. Please use Unity Hand Interaction Profile instead.")]
public class ViveHandInteractionExt : OpenXRInteractionFeature
{
#region Log
@@ -226,7 +224,7 @@ namespace VIVE.OpenXR.Hand
#region Supported component paths
/// <summary>
/// Constant for a pose interaction binding '.../input/aim/pose' OpenXR Input Binding.<br></br>
/// Typically used for aiming at objects out of arm<EFBFBD><EFBFBD>s reach. When using a hand interaction profile, it is typically paired with <see cref="pointerActivateValue"/> to optimize aiming ray stability while performing the gesture.<br></br>
/// Typically used for aiming at objects out of arm¡¦s reach. When using a hand interaction profile, it is typically paired with <see cref="pointerActivateValue"/> to optimize aiming ray stability while performing the gesture.<br></br>
/// When using a controller interaction profile, the "aim" pose is typically paired with a trigger or a button for aim and fire operations.
/// </summary>
public const string aim = "/input/aim/pose";
@@ -245,7 +243,7 @@ namespace VIVE.OpenXR.Hand
/// <summary>
/// Constant for a pose interaction binding '.../input/grip/pose' OpenXR Input Binding.<br></br>
/// Typically used for holding a large object in the user<EFBFBD><EFBFBD>s hand. When using a hand interaction profile, it is typically paired with <see cref="graspValue"/> for the user to directly manipulate an object held in a hand.<br></br>
/// Typically used for holding a large object in the user¡¦s hand. When using a hand interaction profile, it is typically paired with <see cref="graspValue"/> for the user to directly manipulate an object held in a hand.<br></br>
/// When using a controller interaction profile, the "grip" pose is typically paired with a "squeeze" button or trigger that gives the user the sense of tightly holding an object.
/// </summary>
public const string grip = "/input/grip/pose";
@@ -319,7 +317,7 @@ namespace VIVE.OpenXR.Hand
/// </summary>
protected override void RegisterDeviceLayout()
{
// sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(kDeviceLocalizedName); DEBUG(sb);
sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(kDeviceLocalizedName); DEBUG(sb);
InputSystem.RegisterLayout(typeof(HandInteractionExtDevice),
kLayoutName,
matches: new InputDeviceMatcher()
@@ -332,7 +330,7 @@ namespace VIVE.OpenXR.Hand
/// </summary>
protected override void UnregisterDeviceLayout()
{
// sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
InputSystem.RemoveLayout(kLayoutName);
}

View File

@@ -1,458 +0,0 @@
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

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

View File

@@ -1,102 +0,0 @@
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

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

View File

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

View File

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

View File

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

View File

@@ -208,7 +208,7 @@ namespace VIVE.OpenXR.Tracker
/// </summary>
protected override void RegisterDeviceLayout()
{
// sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(kDeviceLocalizedName); DEBUG(sb);
sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(kDeviceLocalizedName); DEBUG(sb);
InputSystem.RegisterLayout(typeof(WristTrackerDevice),
kLayoutName,
matches: new InputDeviceMatcher()
@@ -221,7 +221,7 @@ namespace VIVE.OpenXR.Tracker
/// </summary>
protected override void UnregisterDeviceLayout()
{
// sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
InputSystem.RemoveLayout(kLayoutName);
}

View File

@@ -581,7 +581,7 @@ namespace VIVE.OpenXR.Tracker
/// </summary>
protected override void RegisterDeviceLayout()
{
// sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(@kProducts); DEBUG(sb);
sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(@kProducts); DEBUG(sb);
InputSystem.RegisterLayout(typeof(XrTrackerDevice),
kLayoutName,
matches: new InputDeviceMatcher()
@@ -594,7 +594,7 @@ namespace VIVE.OpenXR.Tracker
/// </summary>
protected override void UnregisterDeviceLayout()
{
// sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
InputSystem.RemoveLayout(kLayoutName);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 B

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

After

Width:  |  Height:  |  Size: 131 B

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

After

Width:  |  Height:  |  Size: 131 B

View File

@@ -3,7 +3,6 @@
using System;
using System.Text;
using UnityEngine;
using UnityEngine.Profiling;
using VIVE.OpenXR.Hand;
namespace VIVE.OpenXR.Models
@@ -70,43 +69,16 @@ namespace VIVE.OpenXR.Models
skinMeshRenderer = GetComponentInChildren<SkinnedMeshRenderer>();
}
private void OnEnable()
{
Application.onBeforeRender += BeforeRenderUpdate;
}
private void OnDisable()
{
Application.onBeforeRender -= BeforeRenderUpdate;
}
private void Update()
{
UpdateHand();
}
if (skinMeshRenderer == null) { return; }
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))
{
skinMeshRenderer.enabled = false;
Profiler.EndSample();
Profiler.EndSample();
return;
}
Profiler.EndSample();
Profiler.BeginSample("UpdateJointPose");
skinMeshRenderer.enabled = !ForceHidden;
UpdateJointPosition(handJointLocation[(int)XrHandJointEXT.XR_HAND_JOINT_WRIST_EXT], ref m_Wrist);
@@ -142,8 +114,6 @@ 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_DISTAL_EXT], ref m_Little_Distal);
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)

View File

@@ -127,9 +127,6 @@ namespace VIVE.OpenXR
XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC = 1000317001,
XR_TYPE_PASSTHROUGH_COLOR_HTC = 1000317002,
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_SESSION_CREATE_INFO_OVERLAY_EXTX = 1000033000,
XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX = 1000033003,
@@ -547,24 +544,6 @@ 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
/// <summary>
/// A two-dimensional vector is defined by the XrVector2f structure.
@@ -3264,7 +3243,7 @@ namespace VIVE.OpenXR
{
if (funcPtr != IntPtr.Zero)
{
Log.D("Get function pointer of " + name);
Debug.Log("Get function pointer of " + name);
func = Marshal.GetDelegateForFunctionPointer<Type>(funcPtr);
return true;
}

View File

@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine.Profiling;
//using VIVE.OpenXR.Utils;
using VIVE.OpenXR.Hand;
@@ -60,7 +59,20 @@ namespace VIVE.OpenXR
if (m_JointLocations.isActive == 1)
{
MemoryTools.CopyFromRawMemory(handJointLocation, m_JointLocations.jointLocations, (int)m_JointLocations.jointCount);
long offset = 0;
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];
return true;

View File

@@ -86,8 +86,13 @@ namespace VIVE.OpenXR
{
if (ASSERT_FEATURE())
{
if (feature.GetJointLocations(isLeft, out handJointLocation, out timestamp))
if (feature.GetJointLocations(isLeft, out XrHandJointLocationEXT[] array, 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;
}
}

View File

@@ -43,6 +43,27 @@ namespace VIVE.OpenXR
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()
{
ASSERT_FEATURE();
@@ -56,8 +77,10 @@ namespace VIVE.OpenXR
public override XrFrameState GetFrameState()
{
ASSERT_FEATURE();
#if UNITY_STANDALONE
if (feature)
return feature.GetFrameState();
#endif
return new XrFrameState();
}
}

View File

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

View File

@@ -5,7 +5,8 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using System.Linq;
using System.Threading.Tasks;
using VIVE.OpenXR;
namespace VIVE.OpenXR.Passthrough
{
@@ -26,7 +27,13 @@ namespace VIVE.OpenXR.Passthrough
return false;
}
private static Dictionary<XrPassthroughHTC, PassthroughLayer> layersDict = new Dictionary<XrPassthroughHTC, PassthroughLayer>();
#if UNITY_STANDALONE
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
/// <summary>
@@ -51,32 +58,42 @@ namespace VIVE.OpenXR.Passthrough
}
XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC(
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.
#endif
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);
if(res == XrResult.XR_SUCCESS)
{
PassthroughLayer layer = new PassthroughLayer(passthrough, layerType);
var xrLayer = PassthroughLayer.MakeEmptyLayer();
xrLayer.passthrough = passthrough;
xrLayer.layerFlags = (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
xrLayer.color.alpha = alpha;
layer.SetLayer(xrLayer);
layersDict.Add(passthrough, layer);
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: IntPtr.Zero,
in_layerFlags: (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT,
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)
{
SetPassthroughAlpha(passthrough, alpha);
}
return res;
}
@@ -121,34 +138,54 @@ namespace VIVE.OpenXR.Passthrough
XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC(
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.
#endif
XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PROJECTED_HTC
);
#if UNITY_STANDALONE
res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough);
if (res == XrResult.XR_SUCCESS)
{
var layer = new PassthroughLayer(passthrough, layerType);
var xrLayer = PassthroughLayer.MakeEmptyLayer();
xrLayer.passthrough = passthrough;
xrLayer.layerFlags = (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
xrLayer.space = 0;
xrLayer.color.alpha = alpha;
layer.SetLayer(xrLayer);
var xrMesh = PassthroughLayer.MakeMeshTransform();
xrMesh.time = XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime;
xrMesh.baseSpace = XR_HTC_passthrough.Interop.GetTrackingSpace();
xrMesh.scale = new XrVector3f(meshScale.x, meshScale.y, meshScale.z);
layer.SetMeshTransform(xrMesh);
layersDict.Add(passthrough, layer);
XrPassthroughMeshTransformInfoHTC PassthroughMeshTransformInfo = new XrPassthroughMeshTransformInfoHTC(
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC,
in_next: IntPtr.Zero,
in_vertexCount: 0,
in_vertices: new XrVector3f[0],
in_indexCount: 0,
in_indices: new UInt32[0],
in_baseSpace: XR_HTC_passthrough.Interop.GetTrackingSpace(),
in_time: XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime,
in_pose: new XrPosef(),
in_scale: new XrVector3f()
);
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, compositionDepth, onDestroyPassthroughSessionHandler);
DEBUG("CreateProjectedPassthrough() CreatePassthroughHTC result: " + res + ", passthrough: " + passthrough);
#endif
if (res == XrResult.XR_SUCCESS)
{
SetPassthroughAlpha(passthrough, alpha);
@@ -182,30 +219,54 @@ namespace VIVE.OpenXR.Passthrough
XrPassthroughCreateInfoHTC createInfo = new XrPassthroughCreateInfoHTC(
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.
#endif
XrPassthroughFormHTC.XR_PASSTHROUGH_FORM_PROJECTED_HTC
);
#if UNITY_STANDALONE
res = XR_HTC_passthrough.xrCreatePassthroughHTC(createInfo, out passthrough);
if (res == XrResult.XR_SUCCESS)
{
var layer = new PassthroughLayer(passthrough, layerType);
var xrLayer = PassthroughLayer.MakeEmptyLayer();
xrLayer.passthrough = passthrough;
xrLayer.layerFlags = (UInt64)XrCompositionLayerFlagBits.XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
xrLayer.color.alpha = alpha;
layer.SetLayer(xrLayer);
var xrMesh = PassthroughLayer.MakeMeshTransform();
layer.SetMeshTransform(xrMesh, true);
layersDict.Add(passthrough, layer);
XrPassthroughMeshTransformInfoHTC PassthroughMeshTransformInfo = new XrPassthroughMeshTransformInfoHTC(
in_type: XrStructureType.XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC,
in_next: IntPtr.Zero,
in_vertexCount: 0,
in_vertices: new XrVector3f[0],
in_indexCount: 0,
in_indices: new UInt32[0],
in_baseSpace: XR_HTC_passthrough.Interop.GetTrackingSpace(),
in_time: XR_HTC_passthrough.Interop.GetFrameState().predictedDisplayTime,
in_pose: new XrPosef(),
in_scale: new XrVector3f()
);
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)
{
SetPassthroughAlpha(passthrough, alpha);
@@ -214,10 +275,35 @@ namespace VIVE.OpenXR.Passthrough
return res;
}
private static void SubmitLayer()
#if UNITY_STANDALONE
private static async void SubmitLayer()
{
passthroughFeature.SubmitLayers(layersDict.Values.ToList());
await Task.Run(() => {
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>
/// To Destroying a passthrough.
@@ -240,17 +326,23 @@ namespace VIVE.OpenXR.Passthrough
return res;
}
if (layersDict.ContainsKey(passthrough))
{
XR_HTC_passthrough.xrDestroyPassthroughHTC(passthrough);
var layer = layersDict[passthrough];
layer.Dispose();
layersDict.Remove(passthrough);
}
#if UNITY_STANDALONE
XrPassthroughHTC pt = passthrough2Layer[passthrough].passthrough;
XR_HTC_passthrough.xrDestroyPassthroughHTC(pt);
passthrough2IsUnderLay.Remove(passthrough);
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;
#elif UNITY_ANDROID
res = passthroughFeature.DestroyPassthroughHTC(passthrough);
DEBUG("DestroyPassthrough() DestroyPassthroughHTC result: " + res + ", passthrough: " + passthrough);
#endif
return res;
}
@@ -276,18 +368,36 @@ namespace VIVE.OpenXR.Passthrough
return ret;
}
if (layersDict.ContainsKey(passthrough))
#if UNITY_ANDROID
if (autoClamp)
{
var layer = layersDict[passthrough];
var xrLayer = layer.GetLayer();
xrLayer.color.alpha = alpha;
layer.SetLayer(xrLayer);
ret = passthroughFeature.SetAlpha(passthrough, Mathf.Clamp01(alpha));
}
else
{
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();
ret = true;
}
else
ret = false;
#endif
return ret;
}
@@ -315,18 +425,45 @@ namespace VIVE.OpenXR.Passthrough
return ret;
}
if (layersDict[passthrough] == null)
XrVector3f[] vertexBufferXrVector = new XrVector3f[vertexBuffer.Length];
for (int i = 0; i < vertexBuffer.Length; i++)
{
ERROR("Passthrough layer not found.");
return ret;
vertexBufferXrVector[i] = OpenXRHelper.ToOpenXRVector(vertexBuffer[i], convertFromUnityToOpenXR);
}
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
layer.SetMeshData(ref xrMesh, vertexBuffer, indexBuffer, convertFromUnityToOpenXR);
layer.SetMeshTransform(xrMesh);
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();
return true;
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;
}
/// <summary>
@@ -371,22 +508,29 @@ namespace VIVE.OpenXR.Passthrough
XrVector3f meshXrScale = OpenXRHelper.ToOpenXRVector(meshScale, false);
if (layersDict[passthrough] == null)
#if UNITY_STANDALONE
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{
ERROR("Passthrough layer not found.");
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);
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
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();
return true;
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;
}
/// <summary>
@@ -406,18 +550,22 @@ namespace VIVE.OpenXR.Passthrough
return ret;
}
if (layersDict[passthrough] == null)
#if UNITY_STANDALONE
if (passthrough2IsUnderLay.ContainsKey(passthrough))
{
ERROR("Passthrough layer not found.");
return ret;
}
var layer = layersDict[passthrough];
layer.LayerType = layerType;
layer.Depth = (int)compositionDepth;
passthrough2IsUnderLay[passthrough] = layerType == CompositionLayer.LayerType.Underlay ? true : false;
SubmitLayer();
return true;
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;
}
/// <summary>
@@ -436,18 +584,28 @@ namespace VIVE.OpenXR.Passthrough
return ret;
}
if (layersDict[passthrough] == null)
#if UNITY_STANDALONE
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{
ERROR("Passthrough layer not found.");
return ret;
}
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
xrMesh.baseSpace = passthroughFeature.GetXrSpaceFromSpaceType(spaceType);
layer.SetMeshTransform(xrMesh);
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
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();
return true;
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;
}
/// <summary>
@@ -481,18 +639,30 @@ namespace VIVE.OpenXR.Passthrough
trackingSpaceMeshPosition = trackingSpaceLayerPoseTRS.GetColumn(3); //4th Column of TRS Matrix is the position
}
if (layersDict[passthrough] == null)
#if UNITY_STANDALONE
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{
ERROR("Passthrough layer not found.");
return ret;
}
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
xrMesh.pose.position = OpenXRHelper.ToOpenXRVector(trackingSpaceMeshPosition, convertFromUnityToOpenXR);
layer.SetMeshTransform(xrMesh);
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
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();
return true;
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;
}
/// <summary>
@@ -526,18 +696,30 @@ namespace VIVE.OpenXR.Passthrough
trackingSpaceMeshRotation = Quaternion.LookRotation(trackingSpaceLayerPoseTRS.GetColumn(2), trackingSpaceLayerPoseTRS.GetColumn(1));
}
if (layersDict[passthrough] == null)
#if UNITY_STANDALONE
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{
ERROR("Passthrough layer not found.");
return ret;
}
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
xrMesh.pose.orientation = OpenXRHelper.ToOpenXRQuaternion(trackingSpaceMeshRotation, convertFromUnityToOpenXR);
layer.SetMeshTransform(xrMesh);
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
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();
return true;
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;
}
/// <summary>
@@ -556,18 +738,28 @@ namespace VIVE.OpenXR.Passthrough
return ret;
}
if (layersDict[passthrough] == null)
#if UNITY_STANDALONE
if (passthrough2meshTransformInfoPtr.ContainsKey(passthrough))
{
ERROR("Passthrough layer not found.");
return ret;
}
var layer = layersDict[passthrough];
var xrMesh = layer.GetMesh();
xrMesh.scale = OpenXRHelper.ToOpenXRVector(meshScale, false);
layer.SetMeshTransform(xrMesh);
XrPassthroughMeshTransformInfoHTC MeshTransformInfo = passthrough2meshTransform[passthrough];
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();
return true;
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;
}
/// <summary>

View File

@@ -699,7 +699,6 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 4806409459047702211}
- component: {fileID: 5568897672767345397}
- component: {fileID: 1039589470112983849}
- component: {fileID: 1039589470112983840}
- component: {fileID: 1039589470112983852}
@@ -726,19 +725,6 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 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
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@@ -858,7 +858,6 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 7152668487518777764}
- component: {fileID: 7057365311429264906}
- component: {fileID: 3431167848623168894}
- component: {fileID: 3431167848623168881}
- component: {fileID: 3431167848623168882}
@@ -885,19 +884,6 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 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
MonoBehaviour:
m_ObjectHideFlags: 0

View File

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

View File

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

View File

@@ -8,6 +8,7 @@
// conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You."
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
@@ -78,13 +79,6 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Pose wristPose = Pose.identity;
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
private void Awake()
{
@@ -165,6 +159,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
/// </summary>
private void FindCandidate()
{
currentCandidate = null;
float distanceScore = float.MinValue;
if (GetClosestGrabbable(m_GrabDistance, out HandGrabInteractable grabbable, out float score) && score > distanceScore)
{
@@ -194,47 +189,28 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
grabbable = null;
maxScore = 0f;
for (int i = 0; i < lastBufferCount; i++)
Collider[] nearColliders = Physics.OverlapSphere(wristPose.position, 0.5f);
List<HandGrabInteractable> nearHandGrabInteractables = new List<HandGrabInteractable>();
for (int i = 0; i < nearColliders.Length; i++)
{
HandGrabInteractable interactable = grabbableBuffer[i];
HandGrabInteractable interactable = nearColliders[i].GetComponentInParent<HandGrabInteractable>();
if (interactable && !nearHandGrabInteractables.Contains(interactable))
{
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++)
{
HandGrabInteractable interactable = nearHandGrabInteractables[i];
interactable.ShowIndicator(false, this);
}
int colliderCount = Physics.OverlapSphereNonAlloc(wristPose.position, grabDistance * 5, colliderBuffer);
int interactableCount = 0;
for (int i = 0; i < colliderCount; i++)
{
Collider collider = colliderBuffer[i];
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++)
{
float distanceScore = interactable.CalculateDistanceScore(fingerTipPosition[j], grabDistance);
@@ -303,18 +279,5 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
}
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,6 +11,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
@@ -84,11 +85,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
private Quaternion lastRotation;
private bool isInit = false;
private bool isTracked = true;
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 List<Vector3> collisionDirections = new List<Vector3>();
private bool isGrabbing = false;
#region MonoBehaviour
@@ -166,11 +163,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
if (isGrabbing)
{
#if UNITY_6000_0_OR_NEWER
rootJointRigidbody.linearVelocity = Vector3.zero;
#else
rootJointRigidbody.velocity = Vector3.zero;
#endif
rootJointRigidbody.angularVelocity = Vector3.zero;
rootJoint.localPosition = lastRootPos;
rootJoint.localRotation = lastRotation;
@@ -182,7 +175,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
}
}
#endregion
#endregion
private IEnumerator WaitForInit()
{
@@ -239,16 +232,12 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
Vector3 vel = (lastRootPos - rootJoint.position) / Time.deltaTime;
if (IsValidVelocity(vel))
{
lock (collisionLock)
{
if (currentCollisionCount > 0)
if (collisionDirections.Count > 0)
{
float minAngle = float.MaxValue;
Vector3 closestDirection = Vector3.zero;
for (int i = 0; i < currentCollisionCount; i++)
foreach (Vector3 direction in collisionDirections.ToList())
{
Vector3 direction = collisionsDirection[i];
float angle = Mathf.Abs(Vector3.Angle(direction, vel));
if (angle < minAngle)
{
@@ -256,6 +245,8 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
closestDirection = direction;
}
}
collisionDirections.Clear();
Vector3 adjustedDirection = closestDirection;
if (Vector3.Dot(vel, closestDirection) > 0)
{
@@ -266,14 +257,8 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{
vel.Normalize();
}
currentCollisionCount = 0;
}
}
#if UNITY_6000_0_OR_NEWER
rootJointRigidbody.linearVelocity = vel;
#else
rootJointRigidbody.velocity = vel;
#endif
}
}
@@ -302,7 +287,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
&& !float.IsInfinity(vector.x) && !float.IsInfinity(vector.y) && !float.IsInfinity(vector.z);
}
#region Event CallBack
#region Event CallBack
/// <summary>
/// When tracking state changing, reset the pose and enable/disable collider.
@@ -314,11 +299,7 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{
lastRootPos = Vector3.zero;
lastRotation = Quaternion.identity;
#if UNITY_6000_0_OR_NEWER
rootJointRigidbody.linearVelocity = Vector3.zero;
#else
rootJointRigidbody.velocity = Vector3.zero;
#endif
rootJointRigidbody.angularVelocity = Vector3.zero;
}
foreach (JointCollider jointCollider in jointsCollider)
@@ -374,21 +355,17 @@ namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
case JointCollider.CollisionState.Stay:
if (collision.contactCount > 0 && (collision.rigidbody == null || collision.rigidbody.isKinematic))
{
lock (collisionLock)
ContactPoint[] contactPoints = new ContactPoint[collision.contactCount];
collision.GetContacts(contactPoints);
foreach (ContactPoint contactPoint in contactPoints)
{
currentCollisionCount = Mathf.Min(contactPointsBuffer.Length, collision.contactCount);
collision.GetContacts(contactPointsBuffer);
for (int i = 0; i < currentCollisionCount; i++)
{
collisionsDirection[i] = contactPointsBuffer[i].normal * -1f;
}
collisionDirections.Add(contactPoint.normal * -1f);
}
}
break;
}
}
#endregion
#endregion
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,7 +13,7 @@
"WindowsStandalone64"
],
"excludePlatforms": [],
"allowUnsafeCode": true,
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
@@ -24,11 +24,6 @@
"expression": "1.3.0",
"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",
"expression": "0.9.4-preview",

View File

@@ -282,7 +282,7 @@ namespace VIVE.OpenXR
/// </summary>
protected override void RegisterDeviceLayout()
{
// Debug.LogFormat("VIVECosmosProfile RegisterDeviceLayout() {0} , product: {1}", kLayoutName, kDeviceLocalizedName);
Debug.LogFormat("VIVECosmosProfile RegisterDeviceLayout() {0} , product: {1}", kLayoutName, kDeviceLocalizedName);
InputSystem.RegisterLayout(typeof(ViveCosmosController),
kLayoutName,
matches: new InputDeviceMatcher()
@@ -295,7 +295,7 @@ namespace VIVE.OpenXR
/// </summary>
protected override void UnregisterDeviceLayout()
{
// Debug.LogFormat("VIVECosmosProfile UnregisterDeviceLayout() {0}", kLayoutName);
Debug.LogFormat("VIVECosmosProfile UnregisterDeviceLayout() {0}", kLayoutName);
InputSystem.RemoveLayout(kLayoutName);
}

View File

@@ -48,7 +48,7 @@ namespace VIVE.OpenXR
public class VIVEFocus3Profile : OpenXRInteractionFeature
{
#region Log
const string LOG_TAG = "VIVE.OpenXR.VIVEFocus3Profile ";
const string LOG_TAG = "VIVE.OpenXR.VIVEFocus3Profile";
StringBuilder m_sb = null;
StringBuilder sb {
get {
@@ -56,8 +56,8 @@ namespace VIVE.OpenXR
return m_sb;
}
}
void DEBUG(StringBuilder msg) { Debug.Log(LOG_TAG + msg); }
void ERROR(StringBuilder msg) { Debug.LogError(LOG_TAG + msg); }
void DEBUG(StringBuilder msg) { Debug.LogFormat("{0} {1}", LOG_TAG, msg); }
void ERROR(StringBuilder msg) { Debug.LogErrorFormat("{0} {1}", LOG_TAG, msg); }
#endregion
private static VIVEFocus3Profile m_Instance = null;
@@ -88,13 +88,11 @@ namespace VIVE.OpenXR
return m_sb;
}
}
void DEBUG(StringBuilder msg) { Debug.Log(LOG_TAG + msg); }
void ERROR(StringBuilder msg) { Debug.LogError(LOG_TAG + msg); }
void DEBUG(StringBuilder msg) { Debug.LogFormat("{0} {1}", LOG_TAG, msg); }
void ERROR(StringBuilder msg) { Debug.LogErrorFormat("{0} {1}", LOG_TAG, msg); }
#endregion
#region Action Path
#region Button
/// <summary>
/// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control) that represents the <see cref="VIVEFocus3Profile.thumbstick"/> OpenXR binding.
/// </summary>
@@ -147,7 +145,7 @@ namespace VIVE.OpenXR
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="triggerClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "indexButton", "triggerButton" }, usage = "TriggerButton")]
public ButtonControl triggerPressed { get; private set; } // InputControl(offset = 20)
public ButtonControl triggerPressed { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="triggerTouch"/> OpenXR binding.
@@ -159,7 +157,7 @@ namespace VIVE.OpenXR
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="thumbstickClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "JoystickOrPadPressed", "thumbstickClick", "joystickClicked", "primary2DAxisClick" }, usage = "Primary2DAxisClick")]
public ButtonControl thumbstickClicked { get; private set; } // InputControl(offset = 22)
public ButtonControl thumbstickClicked { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="thumbstickTouch"/> OpenXR binding.
@@ -171,31 +169,31 @@ namespace VIVE.OpenXR
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="thumbrest"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "ParkingTouched", "parkingTouched" })]
public ButtonControl thumbrestTouched { get; private set; } // InputControl(offset = 24)
#endregion
public ButtonControl thumbrestTouched { get; private set; }
/// <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.
/// </summary>
[Preserve, InputControl(offset = 0, aliases = new[] { "device", "gripPose" }, usage = "Device")]
public PoseControl devicePose { get; private set; }
/// <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.
/// </summary>
[Preserve, InputControl(offset = 0, aliases = new[] { "aimPose", "pointerPose" }, usage = "Pointer")]
public PoseControl pointer { get; private set; }
#if UNITY_ANDROID
/// <summary>
/// A <see cref="PoseControl"/> representing the <see cref="VIVEFocus3Profile.pinchPose"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(offset = 0, usage = "Pinch")]
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; }
/// <summary>
/// A <see cref="PoseControl"/> representing the <see cref="VIVEFocus3Profile.pinchPose"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(offset = 0, usage = "Pinch")]
public PoseControl pinchPose { get; private set; }
#endif
/// <summary>
@@ -229,29 +227,28 @@ namespace VIVE.OpenXR
/// </summary>
[Preserve, InputControl(offset = 104, noisy = true, alias = "pointerOrientation")]
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 pinch position. This value is equivalent to mapping pinchPose/position.
/// </summary>
[Preserve, InputControl(offset = 152, noisy = true)]
public Vector3Control pinchPosition { get; private set; }
/// <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.
/// </summary>
[Preserve, InputControl(offset = 164, noisy = true)]
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)]
[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 = 224, noisy = true)]
[Preserve, InputControl(offset = 164, noisy = true)]
public QuaternionControl pokeRotation { get; private set; }
/// <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.
/// </summary>
[Preserve, InputControl(offset = 212, noisy = true)]
public Vector3Control pinchPosition { get; private set; }
/// <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.
/// </summary>
[Preserve, InputControl(offset = 224, noisy = true)]
public QuaternionControl pinchRotation { get; private set; }
#endif
/// <summary>
/// A <see cref="HapticControl"/> that represents the <see cref="VIVEFocus3Profile.haptic"/> binding.
@@ -500,7 +497,7 @@ namespace VIVE.OpenXR
/// </summary>
protected override void RegisterDeviceLayout()
{
// sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(kDeviceLocalizedName); DEBUG(sb);
sb.Clear().Append("RegisterDeviceLayout() ").Append(kLayoutName).Append(", product: ").Append(kDeviceLocalizedName); DEBUG(sb);
InputSystem.RegisterLayout(typeof(VIVEFocus3Controller),
kLayoutName,
matches: new InputDeviceMatcher()
@@ -513,7 +510,7 @@ namespace VIVE.OpenXR
/// </summary>
protected override void UnregisterDeviceLayout()
{
// sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
sb.Clear().Append("UnregisterDeviceLayout() ").Append(kLayoutName); DEBUG(sb);
InputSystem.RemoveLayout(kLayoutName);
}

View File

@@ -1,13 +1,13 @@
// Copyright HTC Corporation All Rights Reserved.
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.XR;
using System.Text;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
namespace VIVE.OpenXR
{
[DisallowMultipleComponent]
@@ -43,6 +43,12 @@ namespace VIVE.OpenXR
private float m_CameraHeight = 1.5f;
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
[SerializeField]
private InputActionAsset m_ActionAsset;
@@ -50,14 +56,10 @@ namespace VIVE.OpenXR
#endif
#endregion
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
static List<XRInputSubsystem> s_InputSubsystems = new List<XRInputSubsystem>();
private void OnEnable()
{
UpdateInputSubsystems();
SubsystemManager.GetInstances(s_InputSubsystems);
for (int i = 0; i < s_InputSubsystems.Count; i++)
{
s_InputSubsystems[i].trackingOriginUpdated += TrackingOriginUpdated;
@@ -72,12 +74,29 @@ namespace VIVE.OpenXR
}
private void OnDisable()
{
UpdateInputSubsystems();
SubsystemManager.GetInstances(s_InputSubsystems);
for (int i = 0; i < s_InputSubsystems.Count; i++)
{
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()
{
if (m_Instance == null)
@@ -88,18 +107,38 @@ namespace VIVE.OpenXR
{
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()
{
TrackingOriginModeFlags mode = GetTrackingOriginMode();
if ((mode != m_TrackingOrigin || m_TrackingOriginEx != m_TrackingOrigin) &&
m_TrackingOrigin != TrackingOriginModeFlags.Unknown &&
SetTrackingOriginMode(m_TrackingOrigin))
UpdateInputSystem();
if (m_InputSystem != null)
{
mode = GetTrackingOriginMode();
TrackingOriginModeFlags mode = m_InputSystem.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);
m_TrackingOriginEx = m_TrackingOrigin;
}
}
if (m_CameraOffset != null && m_TrackingOrigin == TrackingOriginModeFlags.Device)
{
@@ -110,66 +149,5 @@ namespace VIVE.OpenXR
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()
{
List<XRInputSubsystem> xrSubsystemList = new List<XRInputSubsystem>();
SubsystemManager.GetSubsystems(xrSubsystemList);
SubsystemManager.GetInstances(xrSubsystemList);
foreach (var xrSubsystem in xrSubsystemList)
{
if (xrSubsystem.running)
@@ -675,12 +675,6 @@ namespace VIVE.OpenXR.Samples.Anchor
if (task.IsCompleted)
{
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)
{
// write to file

View File

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

View File

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

View File

@@ -1,71 +0,0 @@
// 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

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

View File

@@ -1,136 +0,0 @@
// 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

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

View File

@@ -111,14 +111,7 @@ namespace VIVE.OpenXR.Samples
rotationTracked = ((uint)trackingState & (uint)InputTrackingState.Rotation) != 0;
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);
#endif
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 B

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

After

Width:  |  Height:  |  Size: 131 B

Some files were not shown because too many files have changed in this diff Show More