This commit is contained in:
2025-11-13 17:40:28 +08:00
parent 962ab49609
commit 10156da245
5503 changed files with 805282 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 51e35b2149654cc5b668f78d0f52bba6
timeCreated: 1738739439

View File

@@ -0,0 +1,133 @@
#if PICO_OPENXR_SDK
using System;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.XR.PXR;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.NativeTypes;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
namespace Unity.XR.OpenXR.Features.PICOSupport
{
public enum SystemDisplayFrequency
{
Default,
RefreshRate72 = 72,
RefreshRate90 = 90,
RefreshRate120 = 120,
}
#if UNITY_EDITOR
[OpenXRFeature(UiName = "OpenXR Display Refresh Rate",
Hidden = false,
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
Company = "PICO",
OpenxrExtensionStrings = extensionString,
Version = PXR_Constants.SDKVersion,
FeatureId = featureId)]
#endif
public class DisplayRefreshRateFeature : OpenXRFeatureBase
{
public const string featureId = "com.pico.openxr.feature.refreshrate";
public const string extensionString = "XR_FB_display_refresh_rate";
public static bool isExtensionEnable => OpenXRRuntime.IsExtensionEnabled(extensionString);
public override string GetExtensionString()
{
return extensionString;
}
public override void SessionCreate(ulong xrSessionId)
{
PXR_OpenXRProjectSetting projectConfig = PXR_OpenXRProjectSetting.GetProjectConfig();
if (projectConfig.displayFrequency != SystemDisplayFrequency.Default)
{
SetDisplayRefreshRate(projectConfig.displayFrequency);
}
}
public static bool SetDisplayRefreshRate(SystemDisplayFrequency DisplayFrequency)
{
PLog.e(extensionString,$"SetDisplayRefreshRate:{DisplayFrequency}");
float rate = 0;
switch (DisplayFrequency)
{
case SystemDisplayFrequency.Default:
return true;
case SystemDisplayFrequency.RefreshRate72:
rate = 72;
break;
case SystemDisplayFrequency.RefreshRate90:
rate = 90;
break;
case SystemDisplayFrequency.RefreshRate120:
rate = 120;
break;
}
return SetDisplayRefreshRate(rate);
}
public static bool GetDisplayRefreshRate(ref float displayRefreshRate)
{
if (!isExtensionEnable)
{
return false;
}
return Pxr_GetDisplayRefreshRate(ref displayRefreshRate) == (int)XrResult.Success;
}
public static bool SetDisplayRefreshRate(float displayRefreshRate)
{
if (!isExtensionEnable)
{
return false;
}
return Pxr_SetDisplayRefreshRate(displayRefreshRate) == (int)XrResult.Success;
}
[Obsolete("Please use GetDisplayFrequenciesAvailable")]
public static int GetDisplayRefreshRateCount()
{
return 0;
}
[Obsolete("Please use GetDisplayFrequenciesAvailable")]
public static bool TryGetSupportedDisplayRefreshRates(
Allocator allocator, out NativeArray<float> refreshRates)
{
refreshRates = default;
return false;
}
public static float[] GetDisplayFrequenciesAvailable()
{
if (!isExtensionEnable)
{
return null;
}
float[] configArray = { 0 };
int configCount = 0;
IntPtr configHandle = IntPtr.Zero;
bool ret = false;
ret = Pxr_GetDisplayRefreshRatesAvailable(ref configCount, ref configHandle);
if (ret)
{
configArray = new float[configCount];
Marshal.Copy(configHandle, configArray, 0, configCount);
}
return configArray;
}
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int Pxr_GetDisplayRefreshRate(ref float displayRefreshRate);
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int Pxr_SetDisplayRefreshRate(float refreshRate);
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern bool Pxr_GetDisplayRefreshRatesAvailable(ref int configCount, ref IntPtr configArray);
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f13a1b00c8524d6495757293c2324596
timeCreated: 1738739475

View File

@@ -0,0 +1,156 @@
#if PICO_OPENXR_SDK
using UnityEditor;
using UnityEngine.XR.OpenXR.Features;
using System.Runtime.InteropServices;
using System;
using Unity.XR.OpenXR.Features.PICOSupport;
using Unity.XR.PXR;
using UnityEngine;
using UnityEngine.XR.OpenXR;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
[OpenXRFeature(UiName = "OpenXR Foveation",
BuildTargetGroups = new[] { BuildTargetGroup.Android },
OpenxrExtensionStrings = extensionList,
Company = "PICO",
Version = PXR_Constants.SDKVersion,
FeatureId = featureId)]
#endif
public class FoveationFeature : OpenXRFeatureBase
{
public const string extensionList = "XR_FB_foveation " +
"XR_FB_foveation_configuration " +
"XR_FB_foveation_vulkan " +
"XR_META_foveation_eye_tracked " +
"XR_META_vulkan_swapchain_create_info " +
"XR_FB_swapchain_update_state ";
public const string featureId = "com.pico.openxr.feature.foveation";
private static string TAG = "FoveationFeature";
public enum FoveatedRenderingLevel
{
Off = 0,
Low = 1,
Medium = 2,
High = 3
}
public enum FoveatedRenderingMode
{
FixedFoveatedRendering = 0,
EyeTrackedFoveatedRendering = 1
}
private static UInt32 _foveatedRenderingLevel = 0;
private static UInt32 _useDynamicFoveation = 0;
public static bool isExtensionEnable => OpenXRRuntime.IsExtensionEnabled("XR_FB_foveation");
public override string GetExtensionString()
{
return extensionList;
}
public override void SessionCreate(ulong xrSessionId)
{
if (!isExtensionEnable)
{
return ;
}
PXR_OpenXRProjectSetting projectConfig = PXR_OpenXRProjectSetting.GetProjectConfig();
if (projectConfig.foveationEnable)
{
PICO_setFoveationEyeTracked(projectConfig.foveatedRenderingMode ==
FoveatedRenderingMode.EyeTrackedFoveatedRendering);
foveatedRenderingLevel = projectConfig.foveatedRenderingLevel;
}
}
public static FoveatedRenderingLevel foveatedRenderingLevel
{
get
{
if (!isExtensionEnable)
{
return FoveatedRenderingLevel.Off;
}
UInt32 level;
FBGetFoveationLevel(out level);
PLog.i(TAG,$" foveatedRenderingLevel get if level= {level}");
return (FoveatedRenderingLevel)level;
}
set
{
if (!isExtensionEnable)
{
return;
}
PLog.e(TAG,$" foveatedRenderingLevel set if value= {value}");
_foveatedRenderingLevel = (UInt32)value;
FBSetFoveationLevel(xrSession, _foveatedRenderingLevel, 0.0f, _useDynamicFoveation);
}
}
public static bool useDynamicFoveatedRendering
{
get
{
if (!isExtensionEnable)
{
return false;
}
UInt32 dynamic;
FBGetFoveationLevel(out dynamic);
return dynamic != 0;
}
set
{
if (!isExtensionEnable)
{
return ;
}
if (value)
_useDynamicFoveation = 1;
else
_useDynamicFoveation = 0;
FBSetFoveationLevel(xrSession, _foveatedRenderingLevel, 0.0f, _useDynamicFoveation);
}
}
public static bool supportsFoveationEyeTracked
{
get
{
if (!isExtensionEnable)
{
return false;
}
bool supported=false;
Pxr_GetEyeTrackingFoveationRenderingSupported(ref supported);
return supported;
}
}
#region OpenXR Plugin DLL Imports
[DllImport("UnityOpenXR", EntryPoint = "FBSetFoveationLevel")]
private static extern void FBSetFoveationLevel(UInt64 session, UInt32 level, float verticalOffset, UInt32 dynamic);
[DllImport("UnityOpenXR", EntryPoint = "FBGetFoveationLevel")]
private static extern void FBGetFoveationLevel(out UInt32 level);
[DllImport("UnityOpenXR", EntryPoint = "FBGetFoveationDynamic")]
private static extern void FBGetFoveationDynamic(out UInt32 dynamic);
#endregion
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern bool Pxr_GetEyeTrackingFoveationRenderingSupported(ref bool supported);
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern void PICO_setFoveationEyeTracked(bool value);
}
#endif

View File

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

View File

@@ -0,0 +1,128 @@
#if PICO_OPENXR_SDK
using System;
using System.Collections.Generic;
using Unity.XR.CoreUtils;
using Unity.XR.PXR;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.OpenXR;
namespace Unity.XR.OpenXR.Features.PICOSupport
{
public class LayerBase : MonoBehaviour
{
public static int ID = 0;
private Transform overlayTransform;
private Camera xrRig;
private Vector3 modelTranslations;
private Quaternion modelRotations;
private Vector3 modelScales ;
private XROrigin cameraRig;
private XROrigin lastcameraRig;
public bool isXROriginChange = false;
private float offsetY = 0;
bool isUpdateOffsetY= false;
private Vector3 cameraPosOri;
private TrackingOriginModeFlags lastTrackingOriginMod = TrackingOriginModeFlags.Unknown;
public void Awake()
{
ID++;
lastcameraRig=cameraRig=FindActiveXROrigin();
overlayTransform = GetComponent<Transform>();
PXR_Plugin.System.RecenterSuccess+=()=>
{
isUpdateOffsetY = true;
};
#if UNITY_ANDROID && !UNITY_EDITOR
if (overlayTransform != null)
{
MeshRenderer render = overlayTransform.GetComponent<MeshRenderer>();
if (render != null)
{
render.enabled = false;
}
}
#endif
}
XROrigin FindActiveXROrigin()
{
XROrigin[] xrOrigins = FindObjectsOfType<XROrigin>();
foreach (XROrigin xrOrigin in xrOrigins)
{
if (xrOrigin.gameObject.activeInHierarchy)
{
return xrOrigin;
}
}
return null;
}
private void OnDestroy()
{
ID--;
}
public void UpdateCoords(bool isCreate = false)
{
if (isXROriginChange)
{
cameraRig=FindActiveXROrigin();
isUpdateOffsetY=cameraRig!= lastcameraRig;
lastcameraRig = cameraRig;
}
if (isCreate)
{
cameraPosOri=cameraRig.transform.position;
}
if (isCreate||cameraRig.CurrentTrackingOriginMode != lastTrackingOriginMod ||isUpdateOffsetY)
{
if (cameraRig.CurrentTrackingOriginMode == TrackingOriginModeFlags.Floor)
{
offsetY= cameraRig.Camera.transform.position.y;
}
Debug.Log("CurrentTrackingOriginMode:"+cameraRig.CurrentTrackingOriginMode+" offsetY:"+offsetY);
isUpdateOffsetY=false;
lastTrackingOriginMod = cameraRig.CurrentTrackingOriginMode;
}
var worldInsightModel = GetTransformMatrixForPassthrough(overlayTransform.localToWorldMatrix);
modelTranslations=worldInsightModel.GetPosition();
modelRotations = worldInsightModel.rotation;
modelScales = overlayTransform.lossyScale;
}
private Matrix4x4 GetTransformMatrixForPassthrough(Matrix4x4 worldFromObj)
{
Matrix4x4 trackingSpaceFromWorld =
(cameraRig != null) ? cameraRig.CameraFloorOffsetObject.transform.worldToLocalMatrix : Matrix4x4.identity;
return trackingSpaceFromWorld * worldFromObj;
}
public void GetCurrentTransform(ref GeometryInstanceTransform geometryInstanceTransform)
{
geometryInstanceTransform.pose.position.x = modelTranslations.x;
geometryInstanceTransform.pose.position.y = modelTranslations.y-offsetY+ (cameraRig.CurrentTrackingOriginMode == TrackingOriginModeFlags.Floor
? (cameraRig.transform.position.y - cameraPosOri.y)
: 0);
geometryInstanceTransform.pose.position.z = -modelTranslations.z;
geometryInstanceTransform.pose.orientation.x = -modelRotations.x;
geometryInstanceTransform.pose.orientation.y = -modelRotations.y;
geometryInstanceTransform.pose.orientation.z = modelRotations.z;
geometryInstanceTransform.pose.orientation.w = modelRotations.w;
geometryInstanceTransform.scale.x = modelScales.x;
geometryInstanceTransform.scale.y = modelScales.y;
geometryInstanceTransform.scale.z = 1;
geometryInstanceTransform.isFloor = cameraRig.CurrentTrackingOriginMode == TrackingOriginModeFlags.Floor;
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7d95410458cc9bf46a74d78dcba2294f
timeCreated: 1695197751

View File

@@ -0,0 +1,54 @@
#if PICO_OPENXR_SDK
using System.Runtime.InteropServices;
using Unity.XR.PXR;
using UnityEngine.XR.OpenXR;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
namespace Unity.XR.OpenXR.Features.PICOSupport
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "OpenXR Composition Layer Secure Content",
Hidden = false,
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
Company = "PICO",
OpenxrExtensionStrings = extensionString,
Version = PXR_Constants.SDKVersion,
FeatureId = featureId)]
#endif
public class LayerSecureContentFeature : OpenXRFeatureBase
{
public const string featureId = "com.pico.openxr.feature.LayerSecureContent";
public const string extensionString = "XR_FB_composition_layer_secure_content";
public static bool isExtensionEnable => OpenXRRuntime.IsExtensionEnabled(extensionString);
public override string GetExtensionString()
{
return extensionString;
}
public override void SessionCreate(ulong xrSessionId)
{
PXR_OpenXRProjectSetting projectConfig = PXR_OpenXRProjectSetting.GetProjectConfig();
if (projectConfig.useContentProtect)
{
SetSecureContentFlag(projectConfig.contentProtectFlags);
}
}
public static void SetSecureContentFlag(SecureContentFlag flag)
{
if (!isExtensionEnable)
{
return;
}
SetSecureContentFlag((int)flag);
}
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern void SetSecureContentFlag(int state);
}
}
#endif

View File

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

View File

@@ -0,0 +1,96 @@
#if PICO_OPENXR_SDK
using System;
using System.Collections.Generic;
using Unity.XR.PXR;
using UnityEditor;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
namespace Unity.XR.OpenXR.Features.PICOSupport
{
public abstract class OpenXRFeatureBase : OpenXRFeature
{
protected static ulong xrInstance = 0ul;
protected static ulong xrSession = 0ul;
protected override bool OnInstanceCreate(ulong instance)
{
xrInstance = instance;
xrSession = 0ul;
InstanceCreate(instance);
return true;
}
protected override void OnSessionCreate(ulong xrSessionId)
{
xrSession = xrSessionId;
base.OnSessionCreate(xrSessionId);
SessionCreate(xrSessionId);
}
public bool isExtensionEnabled(string extensionUrl)
{
string[] exts = extensionUrl.Split(' ');
if (exts.Length > 0)
{
foreach (var _ext in exts)
{
if (!string.IsNullOrEmpty(_ext) && !OpenXRRuntime.IsExtensionEnabled(_ext))
{
PLog.e("OpenXRFeatureBase", _ext + " is not enabled");
return false;
}
}
}
else
{
if (!string.IsNullOrEmpty(extensionUrl) && !OpenXRRuntime.IsExtensionEnabled(extensionUrl))
{
PLog.e("OpenXRFeatureBase", extensionUrl + " is not enabled");
return false;
}
}
return true;
}
public virtual void InstanceCreate(ulong instance) {}
public virtual void SessionCreate(ulong xrSessionId) {}
public abstract string GetExtensionString();
#if UNITY_EDITOR
protected override void GetValidationChecks(List<ValidationRule> rules, BuildTargetGroup targetGroup)
{
var settings = OpenXRSettings.GetSettingsForBuildTargetGroup(targetGroup);
rules.Add(new ValidationRule(this)
{
message = "No PICO OpenXR Features selected.",
checkPredicate = () =>
{
if (null == settings)
return false;
foreach (var feature in settings.GetFeatures<OpenXRFeature>())
{
if (feature is OpenXRExtensions)
{
return feature.enabled;
}
}
return false;
},
fixIt = () =>
{
if (null == settings)
return ;
var openXRExtensions = settings.GetFeature<OpenXRExtensions>();
if (openXRExtensions != null)
{
openXRExtensions.enabled = true;
}
},
error = true
});
}
#endif
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 03de18223d234dd4914b78bf7b2ad088
timeCreated: 1738739629

View File

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

View File

@@ -0,0 +1,251 @@
#if PICO_OPENXR_SDK
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Unity.XR.PXR;
using UnityEngine;
#if AR_FOUNDATION_5||AR_FOUNDATION_6
using UnityEngine.XR.ARSubsystems;
#endif
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
namespace Unity.XR.OpenXR.Features.PICOSupport
{
public enum XrBodyJointSetBD
{
XR_BODY_JOINT_SET_DEFAULT_BD = 0, //default joint set XR_BODY_JOINT_SET_BODY_STAR_WITHOUT_ARM_BD
XR_BODY_JOINT_SET_BODY_START_WITHOUT_ARM_BD = 1,
XR_BODY_JOINT_SET_BODY_FULL_STAR_BD = 2
}
#if UNITY_EDITOR
[OpenXRFeature(UiName = "PICO Body Tracking",
Hidden = false,
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
Company = "PICO",
OpenxrExtensionStrings = extensionString,
Version = PXR_Constants.SDKVersion,
FeatureId = featureId)]
#endif
public class BodyTrackingFeature : OpenXRFeatureBase
{
public const string featureId = "com.pico.openxr.feature.PICO_BodyTracking";
public const string extensionString = "XR_BD_body_tracking XR_PICO_body_tracking2";
public static bool isEnable => OpenXRRuntime.IsExtensionEnabled("XR_BD_body_tracking");
public override string GetExtensionString()
{
return extensionString;
}
[Obsolete("Please use StartBodyTracking(BodyJointSet JointSet, BodyTrackingBoneLength boneLength)")]
public static bool StartBodyTracking(XrBodyJointSetBD Mode)
{
if (!isEnable)
{
return false;
}
BodyTrackingBoneLength boneLength=new BodyTrackingBoneLength();
return StartBodyTracking((BodyJointSet)Mode, boneLength)==0;
}
/// <summary>Starts body tracking.</summary>
/// <param name="mode">Specifies the body tracking mode (default or high-accuracy).</param>
/// <param name="boneLength">Specifies lengths (unit: cm) for the bones of the avatar, which is only available for the `BTM_FULL_BODY_HIGH` mode.
/// Bones that are not set lengths for will use the default values.
/// </param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int StartBodyTracking(BodyJointSet JointSet, BodyTrackingBoneLength boneLength)
{
if (!isEnable)
{
return 1;
}
BodyTrackingStartInfo startInfo = new BodyTrackingStartInfo();
startInfo.jointSet = JointSet;
startInfo.BoneLength = boneLength;
return Pxr_StartBodyTracking(ref startInfo);
}
/// <summary>Launches the PICO Motion Tracker app to perform calibration.
/// - For PICO Motion Tracker (Beta), the user needs to follow the instructions on the home of the PICO Motion Tracker app to complete calibration.
/// - For PICO Motion Tracker (Official), "single-glance calibration" will be performed. When a user has a glance at the PICO Motion Tracker on their lower legs, calibration is completed.
/// </summary>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int StartMotionTrackerCalibApp()
{
if (!isEnable)
{
return 1;
}
return Pxr_StartBodyTrackingCalibApp();
}
public static bool IsBodyTrackingSupported()
{
if (!isEnable)
{
return false;
}
bool supported=false;
Pxr_GetBodyTrackingSupported(ref supported);
return supported;
}
/// <summary>
/// Gets the data about the poses of body joints.
/// </summary>
/// <param name="predictTime">Reserved parameter, pass `0`.</param>
/// <param name="bodyTrackerResult">Contains the data about the poses of body joints, including position, action, and more.</param>
[Obsolete("Please use GetBodyTrackingData",true)]
public static bool GetBodyTrackingPose(ref BodyTrackerResult bodyTrackerResult)
{
return false;
}
/// <summary>Stops body tracking.</summary>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int StopBodyTracking()
{
return Pxr_StopBodyTracking();
}
[Obsolete("Please use StopBodyTracking")]
private void OnDestroy()
{
if (!isEnable)
{
return;
}
StopBodyTracking();
}
[Obsolete("Please use StartMotionTrackerCalibApp")]
public static void OpenFitnessBandCalibrationAPP()
{
StartMotionTrackerCalibApp();
}
/// <summary>Gets body tracking data.</summary>
/// <param name="getInfo"> Specifies the display time and the data filtering flags.
/// For the display time, for example, when it is set to 0.1 second, it means predicting the pose of the tracked node 0.1 seconds ahead.
/// </param>
/// <param name="data">Returns the array of data for all tracked nodes.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public unsafe static int GetBodyTrackingData(ref BodyTrackingGetDataInfo getInfo, ref BodyTrackingData data)
{
if (!isEnable)
{
return 1;
}
int val = -1;
{
val = Pxr_GetBodyTrackingData(ref getInfo, ref data);
for (int i = 0; i < (int)BodyTrackerRole.ROLE_NUM; i++)
{
data.roleDatas[i].localPose.PosZ = -data.roleDatas[i].localPose.PosZ;
data.roleDatas[i].localPose.RotQz = -data.roleDatas[i].localPose.RotQz;
data.roleDatas[i].localPose.RotQw = -data.roleDatas[i].localPose.RotQw;
data.roleDatas[i].velo[3] = -data.roleDatas[i].velo[3];
data.roleDatas[i].acce[3] = -data.roleDatas[i].acce[3];
data.roleDatas[i].wvelo[3] = -data.roleDatas[i].wvelo[3];
data.roleDatas[i].wacce[3] = -data.roleDatas[i].wacce[3];
}
}
return val;
}
/// <summary>Gets the state of PICO Motion Tracker and, if any, the reason for an exception.</summary>
/// <param name="isTracking">Indicates whether the PICO Motion Tracker is tracking normally:
/// - `true`: is tracking
/// - `false`: tracking lost
/// </param>
/// <param name="state">Returns the information about body tracking state.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int GetBodyTrackingState(ref bool isTracking, ref BodyTrackingStatus state)
{
int val = -1;
{
val = Pxr_GetBodyTrackingState(ref isTracking, ref state);
}
return val;
}
#if AR_FOUNDATION_5||AR_FOUNDATION_6
public bool isBodyTracking=false;
static List<XRHumanBodySubsystemDescriptor> s_HumanBodyDescriptors = new List<XRHumanBodySubsystemDescriptor>();
protected override void OnSubsystemCreate()
{
base.OnSubsystemCreate();
if (isBodyTracking)
{
CreateSubsystem<XRHumanBodySubsystemDescriptor, XRHumanBodySubsystem>(
s_HumanBodyDescriptors,
PXR_HumanBodySubsystem.k_SubsystemId);
}
}
protected override void OnSubsystemStart()
{
if (isBodyTracking)
{
StartSubsystem<XRHumanBodySubsystem>();
}
}
protected override void OnSubsystemStop()
{
if (isBodyTracking)
{
StopSubsystem<XRHumanBodySubsystem>();
}
}
protected override void OnSubsystemDestroy()
{
if (isBodyTracking)
{
DestroySubsystem<XRHumanBodySubsystem>();
}
}
#endif
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int Pxr_StartBodyTrackingCalibApp();
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int Pxr_GetBodyTrackingSupported(ref bool supported);
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int Pxr_StartBodyTracking(ref BodyTrackingStartInfo startInfo);
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int Pxr_StopBodyTracking();
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int Pxr_GetBodyTrackingState(ref bool isTracking, ref BodyTrackingStatus state);
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int Pxr_GetBodyTrackingData(ref BodyTrackingGetDataInfo getInfo, ref BodyTrackingData data);
}
}
#endif

View File

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

View File

@@ -0,0 +1,55 @@
#if PICO_OPENXR_SDK
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Unity.XR.PXR;
using UnityEditor;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
namespace Unity.XR.OpenXR.Features.PICOSupport
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "PICO Scene Capture",
Hidden = false,
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
Company = "PICO",
OpenxrExtensionStrings = extensionString,
Version = "1.0.0",
FeatureId = featureId)]
#endif
public class PICOSceneCapture: OpenXRFeature
{
public const string featureId = "com.pico.openxr.feature.scenecapture";
public const string extensionString = "XR_PICO_scene_capture XR_PICO_spatial_sensing XR_EXT_future";
public static bool isEnable => OpenXRRuntime.IsExtensionEnabled("XR_PICO_scene_capture");
protected override void OnSessionCreate(ulong xrSession)
{
base.OnSessionCreate(xrSession);
PXR_Plugin.MixedReality.UPxr_CreateSceneCaptureSenseDataProvider();
}
protected override void OnSessionExiting(ulong xrSession)
{
PXR_MixedReality.GetSenseDataProviderState(PxrSenseDataProviderType.SceneCapture, out var providerState);
if (providerState == PxrSenseDataProviderState.Running)
{
PXR_MixedReality.StopSenseDataProvider(PxrSenseDataProviderType.SceneCapture);
}
PXR_Plugin.MixedReality.UPxr_DestroySenseDataProvider(
PXR_Plugin.MixedReality.UPxr_GetSenseDataProviderHandle(PxrSenseDataProviderType.SceneCapture));
base.OnSessionExiting(xrSession);
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a0b5403262c64d5888bf5672e1e1f3bb
timeCreated: 1721806849

View File

@@ -0,0 +1,96 @@
#if PICO_OPENXR_SDK
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Unity.XR.PXR;
using UnityEditor;
using UnityEngine;
#if AR_FOUNDATION_5||AR_FOUNDATION_6
using UnityEngine.XR.ARSubsystems;
#endif
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
namespace Unity.XR.OpenXR.Features.PICOSupport
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "PICO Spatial Anchor",
Hidden = false,
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
Company = "PICO",
OpenxrExtensionStrings = extensionString,
Version = "1.0.0",
FeatureId = featureId)]
#endif
public class PICOSpatialAnchor: OpenXRFeature
{
public const string featureId = "com.pico.openxr.feature.spatialanchor";
public const string extensionString = "XR_PICO_spatial_anchor XR_PICO_spatial_sensing XR_EXT_future";
public static bool isEnable => OpenXRRuntime.IsExtensionEnabled("XR_PICO_spatial_anchor");
protected override void OnSessionCreate(ulong xrSession)
{
base.OnSessionCreate(xrSession);
PXR_Plugin.MixedReality.UPxr_CreateSpatialAnchorSenseDataProvider();
}
protected override void OnSessionExiting(ulong xrSession)
{
PXR_MixedReality.GetSenseDataProviderState(PxrSenseDataProviderType.SpatialAnchor, out var providerState);
if (providerState == PxrSenseDataProviderState.Running)
{
PXR_MixedReality.StopSenseDataProvider(PxrSenseDataProviderType.SpatialAnchor);
}
PXR_Plugin.MixedReality.UPxr_DestroySenseDataProvider(
PXR_Plugin.MixedReality.UPxr_GetSenseDataProviderHandle(PxrSenseDataProviderType.SpatialAnchor));
base.OnSessionExiting(xrSession);
}
#if AR_FOUNDATION_5||AR_FOUNDATION_6
public bool isAnchorSubsystem=false;
static List<XRAnchorSubsystemDescriptor> anchorSubsystemDescriptors = new List<XRAnchorSubsystemDescriptor>();
protected override void OnSubsystemCreate()
{
base.OnSubsystemCreate();
if (isAnchorSubsystem)
{
CreateSubsystem<XRAnchorSubsystemDescriptor, XRAnchorSubsystem>(
anchorSubsystemDescriptors,
PXR_AnchorSubsystem.k_SubsystemId);
}
}
protected override void OnSubsystemStart()
{
if (isAnchorSubsystem)
{
StartSubsystem<XRAnchorSubsystem>();
}
}
protected override void OnSubsystemStop()
{
if (isAnchorSubsystem)
{
StopSubsystem<XRAnchorSubsystem>();
}
}
protected override void OnSubsystemDestroy()
{
if (isAnchorSubsystem)
{
DestroySubsystem<XRAnchorSubsystem>();
}
}
#endif
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a8b7731b990240c0b289e41fb880787b
timeCreated: 1721806849

View File

@@ -0,0 +1,72 @@
#if PICO_OPENXR_SDK
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
// using Unity.XR.CoreUtils;
using Unity.XR.PXR;
using UnityEditor;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
namespace Unity.XR.OpenXR.Features.PICOSupport
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "PICO Spatial Mesh",
Hidden = false,
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
Company = "PICO",
OpenxrExtensionStrings = extensionString,
Version = "1.0.0",
FeatureId = featureId)]
#endif
public class PICOSpatialMesh: OpenXRFeature
{
public const string featureId = "com.pico.openxr.feature.spatialmesh";
public const string extensionString = "XR_PICO_spatial_mesh XR_PICO_spatial_sensing XR_EXT_future";
private static List<XRMeshSubsystemDescriptor> meshSubsystemDescriptors = new List<XRMeshSubsystemDescriptor>();
public PxrMeshLod LOD;
private XRMeshSubsystem subsystem;
public static bool isEnable => OpenXRRuntime.IsExtensionEnabled("XR_PICO_spatial_mesh");
protected override void OnSubsystemCreate()
{
base.OnSubsystemCreate();
PXR_Plugin.Pxr_SetMeshLOD(Convert.ToUInt16(LOD));
}
protected override void OnSessionCreate(ulong xrSession)
{
base.OnSessionCreate(xrSession);
CreateSubsystem<XRMeshSubsystemDescriptor, XRMeshSubsystem>(meshSubsystemDescriptors, "PICO Mesh");
}
protected override void OnSubsystemStop()
{
base.OnSubsystemStop();
StopSubsystem<XRMeshSubsystem>();
}
protected override void OnSubsystemDestroy()
{
base.OnSubsystemDestroy();
PXR_Plugin.MixedReality.UPxr_DisposeMesh();
DestroySubsystem<XRMeshSubsystem>();
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b1248416ce414cd0a788c5240bec5766
timeCreated: 1721806849

View File

@@ -0,0 +1,541 @@
#if PICO_OPENXR_SDK
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Unity.XR.CoreUtils;
using Unity.XR.PXR;
using UnityEditor;
using UnityEngine;
#if AR_FOUNDATION_5||AR_FOUNDATION_6
using UnityEngine.XR.ARSubsystems;
#endif
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.NativeTypes;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
namespace Unity.XR.OpenXR.Features.PICOSupport
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "OpenXR Passthrough",
Hidden = false,
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
Company = "PICO",
OpenxrExtensionStrings = extensionString,
Version = PXR_Constants.SDKVersion,
FeatureId = featureId)]
#endif
public class PassthroughFeature : OpenXRFeatureBase
{
public const string featureId = "com.pico.openxr.feature.passthrough";
public const string extensionString = "XR_FB_passthrough";
public const int XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB = 256;
private static byte[] colorData;
private static uint Size = 0;
private static bool isInit = false;
private static bool isPause = false;
private static int _enableVideoSeeThrough=-1;
public static event Action<bool> EnableVideoSeeThroughAction;
private static bool isRefreshRecenterSpace = false;
public static bool isExtensionEnable => OpenXRRuntime.IsExtensionEnabled(extensionString);
[HideInInspector]
public static bool EnableVideoSeeThrough
{
get => _enableVideoSeeThrough==1;
set
{
if (value)
{
if (_enableVideoSeeThrough != 1)
{
_enableVideoSeeThrough = 1;
EnableSeeThroughManual(value);
if (EnableVideoSeeThroughAction != null)
{
EnableVideoSeeThroughAction(value);
}
}
}
else
{
if (_enableVideoSeeThrough == 1)
{
_enableVideoSeeThrough = 0;
EnableSeeThroughManual(value);
if (EnableVideoSeeThroughAction != null)
{
EnableVideoSeeThroughAction(value);
}
}
}
}
}
protected override void OnSessionBegin(ulong xrSessionId)
{
if (!isRefreshRecenterSpace)
{
OpenXRSettings.RefreshRecenterSpace();
isRefreshRecenterSpace = true;
}
}
public override string GetExtensionString()
{
return extensionString;
}
public static void PassthroughStart()
{
passthroughStart();
isPause = false;
}
public static void PassthroughPause()
{
passthroughPause();
isPause = true;
}
//This interface has been changed to a private interface.
//Please use the EnableVideoSeeThrough .
private static bool EnableSeeThroughManual(bool value)
{
if (!isExtensionEnable)
{
return false;
}
if (!isInit)
{
isInit = initializePassthrough();
}
if (value)
{
createFullScreenLayer();
if (!isPause)
{
passthroughStart();
}
}
else
{
passthroughPause();
}
return true;
}
public static void Destroy()
{
if (!isExtensionEnable)
{
return;
}
Passthrough_Destroy();
}
private void OnDestroy()
{
Destroy();
}
private static void AllocateColorMapData(uint size)
{
if (colorData != null && size != colorData.Length)
{
Clear();
}
if (colorData == null)
{
colorData = new byte[size];
}
}
private static void Clear()
{
if (colorData != null)
{
colorData = null;
}
}
private static void WriteVector3ToColorMap(int colorIndex, ref Vector3 color)
{
for (int c = 0; c < 3; c++)
{
byte[] bytes = BitConverter.GetBytes(color[c]);
Buffer.BlockCopy(bytes, 0, colorData, colorIndex * 12 + c * 4, 4);
}
}
private static void WriteFloatToColorMap(int index, float value)
{
byte[] bytes = BitConverter.GetBytes(value);
Buffer.BlockCopy(bytes, 0, colorData, index * sizeof(float), sizeof(float));
}
private static void WriteColorToColorMap(int colorIndex, ref Color color)
{
for (int c = 0; c < 4; c++)
{
byte[] bytes = BitConverter.GetBytes(color[c]);
Buffer.BlockCopy(bytes, 0, colorData, colorIndex * 16 + c * 4, 4);
}
}
public static unsafe void SetBrightnessContrastSaturation(ref PassthroughStyle style, float brightness = 0.0f,
float contrast = 0.0f, float saturation = 0.0f)
{
style.enableColorMap = true;
style.TextureColorMapType = PassthroughColorMapType.BrightnessContrastSaturation;
Size = 3 * sizeof(float);
AllocateColorMapData(Size);
WriteFloatToColorMap(0, brightness);
WriteFloatToColorMap(1, contrast);
WriteFloatToColorMap(2, saturation);
fixed (byte* p = colorData)
{
style.TextureColorMapData = (IntPtr)p;
}
style.TextureColorMapDataSize = Size;
StringBuilder str = new StringBuilder();
for (int i = 0; i < Size; i++)
{
str.Append(colorData[i]);
}
Debug.Log("SetPassthroughStyle SetBrightnessContrastSaturation colorData" + str);
}
public static unsafe void SetColorMapbyMonoToMono(ref PassthroughStyle style, int[] values)
{
if (values.Length != XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB)
throw new ArgumentException("Must provide exactly 256 values");
style.enableColorMap = true;
style.TextureColorMapType = PassthroughColorMapType.MonoToMono;
Size = XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB * 4;
AllocateColorMapData(Size);
Buffer.BlockCopy(values, 0, colorData, 0, (int)Size);
fixed (byte* p = colorData)
{
style.TextureColorMapData = (IntPtr)p;
}
style.TextureColorMapDataSize = Size;
}
public static unsafe void SetColorMapbyMonoToRgba(ref PassthroughStyle style, Color[] values)
{
if (values.Length != XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB)
throw new ArgumentException("Must provide exactly 256 colors");
style.TextureColorMapType = PassthroughColorMapType.MonoToRgba;
style.enableColorMap = true;
Size = XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB * 4 * 4;
AllocateColorMapData(Size);
for (int i = 0; i < XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB; i++)
{
WriteColorToColorMap(i, ref values[i]);
}
fixed (byte* p = colorData)
{
style.TextureColorMapData = (IntPtr)p;
}
style.TextureColorMapDataSize = Size;
}
public static _PassthroughStyle ToPassthroughStyle(PassthroughStyle c)
{
_PassthroughStyle mPassthroughStyle = new _PassthroughStyle();
mPassthroughStyle.enableEdgeColor = (uint)(c.enableEdgeColor ? 1 : 0);
mPassthroughStyle.enableColorMap = (uint)(c.enableColorMap ? 1 : 0);
mPassthroughStyle.TextureOpacityFactor = c.TextureOpacityFactor;
mPassthroughStyle.TextureColorMapType = c.TextureColorMapType;
mPassthroughStyle.TextureColorMapDataSize = c.TextureColorMapDataSize;
mPassthroughStyle.TextureColorMapData = c.TextureColorMapData;
mPassthroughStyle.EdgeColor = new Colorf()
{ r = c.EdgeColor.r, g = c.EdgeColor.g, b = c.EdgeColor.b, a = c.EdgeColor.a };
return mPassthroughStyle;
}
public static void SetPassthroughStyle(PassthroughStyle style)
{
setPassthroughStyle(ToPassthroughStyle(style));
}
public static bool IsPassthroughSupported()
{
return isPassthroughSupported();
}
public static unsafe bool CreateTriangleMesh(int id, Vector3[] vertices, int[] triangles,
GeometryInstanceTransform transform)
{
if (vertices == null || triangles == null || vertices.Length == 0 || triangles.Length == 0)
{
return false;
}
if (!isInit)
{
isInit = initializePassthrough();
}
int vertexCount = vertices.Length;
int triangleCount = triangles.Length;
Size = (uint)vertexCount * 3 * 4;
AllocateColorMapData(Size);
for (int i = 0; i < vertexCount; i++)
{
WriteVector3ToColorMap(i, ref vertices[i]);
}
IntPtr vertexDataPtr = IntPtr.Zero;
fixed (byte* p = colorData)
{
vertexDataPtr = (IntPtr)p;
}
StringBuilder str = new StringBuilder();
for (int i = 0; i < 3 * 4; i++)
{
str.Append(colorData[i]);
}
Debug.Log("CreateTriangleMesh vertexDataPtr colorData" + str);
str.Clear();
Size = (uint)triangleCount * 4;
AllocateColorMapData(Size);
Buffer.BlockCopy(triangles, 0, colorData, 0, (int)Size);
IntPtr triangleDataPtr = IntPtr.Zero;
fixed (byte* p = colorData)
{
triangleDataPtr = (IntPtr)p;
}
for (int i = 0; i < colorData.Length; i++)
{
str.Append(colorData[i]);
}
// Debug.Log("CreateTriangleMesh triangleDataPtr colorData" + str);
//
// Debug.Log("CreateTriangleMesh vertexDataPtr=" + vertexDataPtr + " vertexCount=" + vertexCount);
// Debug.Log("CreateTriangleMesh triangleDataPtr=" + triangleDataPtr + " triangleCount=" + triangleCount);
XrResult result =
createTriangleMesh(id, vertexDataPtr, vertexCount, triangleDataPtr, triangleCount, transform);
Clear();
if (result == XrResult.Success)
{
return true;
}
return false;
}
public static void UpdateMeshTransform(int id, GeometryInstanceTransform transform)
{
updatePassthroughMeshTransform(id, transform);
}
#if UNITY_EDITOR
/// <summary>
/// Validation Rules for ARCameraFeature.
/// </summary>
protected override void GetValidationChecks(List<ValidationRule> rules, BuildTargetGroup targetGroup)
{
var AdditionalRules = new ValidationRule[]
{
new ValidationRule(this)
{
message = "Passthrough requires Camera clear flags set to solid color with alpha value zero.",
checkPredicate = () =>
{
var xrOrigin = FindObjectsOfType<XROrigin>();
if (xrOrigin != null && xrOrigin.Length > 0)
{
if (!xrOrigin[0].enabled) return true;
}
else
{
return true;
}
var camera = xrOrigin[0].Camera;
if (camera == null) return true;
return camera.clearFlags == CameraClearFlags.SolidColor && Mathf.Approximately(camera.backgroundColor.a, 0);
},
fixItAutomatic = true,
fixItMessage = "Set your XR Origin camera's Clear Flags to solid color with alpha value zero.",
fixIt = () =>
{
var xrOrigin = FindObjectsOfType<XROrigin>();
if (xrOrigin!=null&&xrOrigin.Length>0)
{
if (xrOrigin[0].enabled)
{
var camera = xrOrigin[0].Camera;
if (camera != null )
{
camera.clearFlags = CameraClearFlags.SolidColor;
Color clearColor = camera.backgroundColor;
clearColor.a = 0;
camera.backgroundColor = clearColor;
}
}
}
},
error = false
}
};
rules.AddRange(AdditionalRules);
}
#endif
#if AR_FOUNDATION_5||AR_FOUNDATION_6
public bool isCameraSubsystem=false;
static List<XRCameraSubsystemDescriptor> s_CameraDescriptors = new List<XRCameraSubsystemDescriptor>();
protected override void OnSubsystemCreate()
{
base.OnSubsystemCreate();
if (isCameraSubsystem)
{
CreateSubsystem<XRCameraSubsystemDescriptor, XRCameraSubsystem>(
s_CameraDescriptors,
PXR_CameraSubsystem.k_SubsystemId);
}
}
protected override void OnSubsystemStart()
{
if (isCameraSubsystem)
{
StartSubsystem<XRCameraSubsystem>();
}
}
protected override void OnSubsystemStop()
{
if (isCameraSubsystem)
{
StopSubsystem<XRCameraSubsystem>();
}
}
protected override void OnSubsystemDestroy()
{
if (isCameraSubsystem)
{
DestroySubsystem<XRCameraSubsystem>();
}
}
#endif
protected override void OnSessionStateChange(int oldState, int newState)
{
base.OnSessionStateChange(oldState, newState);
if (newState == 1)
{
#if AR_FOUNDATION_5||AR_FOUNDATION_6
if (isCameraSubsystem)
{
StopSubsystem<XRCameraSubsystem>();
}else{
if (_enableVideoSeeThrough!=-1)
{
EnableSeeThroughManual(false);
}
}
#else
if (_enableVideoSeeThrough!=-1)
{
EnableSeeThroughManual(false);
}
#endif
}
else if (newState == 5)
{
#if AR_FOUNDATION_5||AR_FOUNDATION_6
if (isCameraSubsystem)
{
StartSubsystem<XRCameraSubsystem>();
}else{
if (_enableVideoSeeThrough!=-1)
{
EnableSeeThroughManual(EnableVideoSeeThrough);
}
}
#else
if (_enableVideoSeeThrough!=-1)
{
EnableSeeThroughManual(EnableVideoSeeThrough);
}
#endif
}
}
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_InitializePassthrough", CallingConvention = CallingConvention.Cdecl)]
private static extern bool initializePassthrough();
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_CreateFullScreenLayer", CallingConvention = CallingConvention.Cdecl)]
private static extern bool createFullScreenLayer();
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_PassthroughStart", CallingConvention = CallingConvention.Cdecl)]
private static extern void passthroughStart();
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_PassthroughPause", CallingConvention = CallingConvention.Cdecl)]
private static extern void passthroughPause();
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_SetPassthroughStyle", CallingConvention = CallingConvention.Cdecl)]
private static extern void setPassthroughStyle(_PassthroughStyle style);
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_IsPassthroughSupported", CallingConvention = CallingConvention.Cdecl)]
private static extern bool isPassthroughSupported();
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_Passthrough_Destroy", CallingConvention = CallingConvention.Cdecl)]
private static extern void Passthrough_Destroy();
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_CreateTriangleMesh", CallingConvention = CallingConvention.Cdecl)]
private static extern XrResult createTriangleMesh(int id, IntPtr vertices, int vertexCount, IntPtr triangles,
int triangleCount, GeometryInstanceTransform transform);
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_UpdatePassthroughMeshTransform",
CallingConvention = CallingConvention.Cdecl)]
private static extern void updatePassthroughMeshTransform(int id, GeometryInstanceTransform transform);
}
}
#endif

View File

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

View File

@@ -0,0 +1,86 @@
#if PICO_OPENXR_SDK
using System;
using Unity.XR.PXR;
using UnityEngine;
namespace Unity.XR.OpenXR.Features.PICOSupport
{
public class PassthroughLayerFeature : LayerBase
{
private int id = 0;
private Vector3[] vertices;
private int[] triangles;
private Mesh mesh;
private bool isPassthroughSupported = false;
private bool isCreateTriangleMesh = false;
private void Awake()
{
base.Awake();
id = ID;
}
private void Start()
{
MeshFilter meshFilter = this.gameObject.GetComponent<MeshFilter>();
if (meshFilter == null)
{
Debug.LogError("Passthrough GameObject does not have a mesh component.");
return;
}
mesh = meshFilter.sharedMesh;
vertices = mesh.vertices;
triangles = mesh.triangles;
isPassthroughSupported = PassthroughFeature.IsPassthroughSupported();
}
private void Update()
{
if (isPassthroughSupported && !isCreateTriangleMesh)
{
GeometryInstanceTransform Transform = new GeometryInstanceTransform();
UpdateCoords(true);
GetCurrentTransform(ref Transform);
isCreateTriangleMesh = PassthroughFeature.CreateTriangleMesh(id, vertices, triangles, Transform);
}
}
private void OnEnable()
{
Camera.onPostRender += OnPostRenderCallBack;
}
private void OnDisable()
{
Camera.onPostRender -= OnPostRenderCallBack;
}
private void OnPostRenderCallBack(Camera cam)
{
GeometryInstanceTransform Transform = new GeometryInstanceTransform();
UpdateCoords();
GetCurrentTransform(ref Transform);
PassthroughFeature.UpdateMeshTransform(id, Transform);
}
void OnApplicationPause(bool pause)
{
if (isCreateTriangleMesh)
{
if (pause)
{
PassthroughFeature.PassthroughPause();
}
else
{
PassthroughFeature.PassthroughStart();
}
}
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d56a853c0545c25418b6e768fdff0d71
timeCreated: 1694522562

View File

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

View File

@@ -0,0 +1,742 @@
#if PICO_OPENXR_SDK
using System.Collections.Generic;
using UnityEngine.Scripting;
using UnityEngine.XR.OpenXR.Input;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.XR;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if USE_INPUT_SYSTEM_POSE_CONTROL
using PoseControl = UnityEngine.InputSystem.XR.PoseControl;
#else
using PoseControl = UnityEngine.XR.OpenXR.Input.PoseControl;
#endif
namespace UnityEngine.XR.OpenXR.Features.Interactions
{
/// <summary>
/// This <see cref="OpenXRInteractionFeature"/> enables the use of PICO TouchControllers interaction profiles in OpenXR.
/// </summary>
#if UNITY_EDITOR
[UnityEditor.XR.OpenXR.Features.OpenXRFeature(UiName = "PICO4 Touch Controller Profile",
BuildTargetGroups = new[] { BuildTargetGroup.Android },
Company = "PICO",
Desc = "Allows for mapping input to the PICO4 Touch Controller interaction profile.",
OpenxrExtensionStrings = extensionString,
Version = "1.0.0",
Category = UnityEditor.XR.OpenXR.Features.FeatureCategory.Interaction,
FeatureId = featureId
)]
#endif
public class PICO4ControllerProfile : OpenXRInteractionFeature
{
/// <summary>
/// The feature id string. This is used to give the feature a well known id for reference.
/// </summary>
public const string featureId = "com.unity.openxr.feature.input.PICO4touch";
/// <summary>
/// An Input System device based on the hand interaction profile in the PICO Touch Controller</a>.
/// </summary>
[Preserve, InputControlLayout(displayName = "PICO4 Touch Controller (OpenXR)", commonUsages = new[] { "LeftHand", "RightHand" })]
public class PICO4TouchController : XRControllerWithRumble
{
/// <summary>
/// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control) that represents the <see cref="PICO4TouchControllerProfile.thumbstick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "Primary2DAxis", "Joystick" }, usage = "Primary2DAxis")]
public Vector2Control thumbstick { get; private set; }
/// <summary>
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the <see cref="PICO4TouchControllerProfile.squeezeValue"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "GripAxis", "squeeze" }, usage = "Grip")]
public AxisControl grip { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.squeezeClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "GripButton", "squeezeClicked" }, usage = "GripButton")]
public ButtonControl gripPressed { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.menu"/> OpenXR bindings.
/// </summary>
[Preserve, InputControl(aliases = new[] { "Primary", "menuButton" }, usage = "Menu")]
public ButtonControl menu { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.system"/> OpenXR bindings.
/// </summary>
[Preserve, InputControl(aliases = new[] { "systemButton" }, usage = "system")]
public ButtonControl system { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.buttonA"/> <see cref="PICO4TouchControllerProfile.buttonX"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "A", "X", "buttonA", "buttonX" }, usage = "PrimaryButton")]
public ButtonControl primaryButton { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.buttonATouch"/> <see cref="PICO4TouchControllerProfile.buttonYTouch"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "ATouched", "XTouched", "ATouch", "XTouch", "buttonATouched", "buttonXTouched" }, usage = "PrimaryTouch")]
public ButtonControl primaryTouched { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.buttonB"/> <see cref="PICO4TouchControllerProfile.buttonY"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "B", "Y", "buttonB", "buttonY" }, usage = "SecondaryButton")]
public ButtonControl secondaryButton { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.buttonBTouch"/> <see cref="PICO4TouchControllerProfile.buttonYTouch"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "BTouched", "YTouched", "BTouch", "YTouch", "buttonBTouched", "buttonYTouched" }, usage = "SecondaryTouch")]
public ButtonControl secondaryTouched { get; private set; }
/// <summary>
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the <see cref="PICO4TouchControllerProfile.trigger"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(usage = "Trigger")]
public AxisControl trigger { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.triggerClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "indexButton", "indexTouched", "triggerbutton" }, usage = "TriggerButton")]
public ButtonControl triggerPressed { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.triggerTouch"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "indexTouch", "indexNearTouched" }, usage = "TriggerTouch")]
public ButtonControl triggerTouched { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.thumbstickClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "JoystickOrPadPressed", "thumbstickClick", "joystickClicked" }, usage = "Primary2DAxisClick")]
public ButtonControl thumbstickClicked { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4TouchControllerProfile.thumbstickTouch"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "JoystickOrPadTouched", "thumbstickTouch", "joystickTouched" }, usage = "Primary2DAxisTouch")]
public ButtonControl thumbstickTouched { get; private set; }
/// <summary>
/// A <see cref="PoseControl"/> that represents the <see cref="PICO4TouchControllerProfile.grip"/> OpenXR binding.
/// </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="PICO4TouchControllerProfile.aim"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(offset = 0, alias = "aimPose", usage = "Pointer")]
public PoseControl pointer { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) required for backwards compatibility with the XRSDK layouts. This represents the overall tracking state of the device. This value is equivalent to mapping devicePose/isTracked.
/// </summary>
[Preserve, InputControl(offset = 28, usage = "IsTracked")]
new public ButtonControl isTracked { get; private set; }
/// <summary>
/// A [IntegerControl](xref:UnityEngine.InputSystem.Controls.IntegerControl) required for backwards compatibility with the XRSDK layouts. This represents the bit flag set to indicate what data is valid. This value is equivalent to mapping devicePose/trackingState.
/// </summary>
[Preserve, InputControl(offset = 32, usage = "TrackingState")]
new public IntegerControl trackingState { get; private set; }
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the device position. For the PICO Touch device, this is both the grip and the pointer position. This value is equivalent to mapping devicePose/position.
/// </summary>
[Preserve, InputControl(offset = 36, noisy = true, alias = "gripPosition")]
new public Vector3Control devicePosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the device orientation. For the PICO Touch device, this is both the grip and the pointer rotation. This value is equivalent to mapping devicePose/rotation.
/// </summary>
[Preserve, InputControl(offset = 48, noisy = true, alias = "gripOrientation")]
new public QuaternionControl deviceRotation { get; private set; }
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for back compatibility with the XRSDK layouts. This is the pointer position. This value is equivalent to mapping pointerPose/position.
/// </summary>
[Preserve, InputControl(offset = 96)]
public Vector3Control pointerPosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the pointer rotation. This value is equivalent to mapping pointerPose/rotation.
/// </summary>
[Preserve, InputControl(offset = 108, alias = "pointerOrientation")]
public QuaternionControl pointerRotation { get; private set; }
/// <summary>
/// A <see cref="HapticControl"/> that represents the <see cref="PICO4TouchControllerProfile.haptic"/> binding.
/// </summary>
[Preserve, InputControl(usage = "Haptic")]
public HapticControl haptic { get; private set; }
[Preserve, InputControl(usage = "BatteryLevel")]
public AxisControl batteryLevel { get; private set; }
/// <summary>
/// Internal call used to assign controls to the the correct element.
/// </summary>
protected override void FinishSetup()
{
base.FinishSetup();
thumbstick = GetChildControl<Vector2Control>("thumbstick");
trigger = GetChildControl<AxisControl>("trigger");
triggerPressed = GetChildControl<ButtonControl>("triggerPressed");
triggerTouched = GetChildControl<ButtonControl>("triggerTouched");
grip = GetChildControl<AxisControl>("grip");
gripPressed = GetChildControl<ButtonControl>("gripPressed");
menu = GetChildControl<ButtonControl>("menu");
primaryButton = GetChildControl<ButtonControl>("primaryButton");
primaryTouched = GetChildControl<ButtonControl>("primaryTouched");
secondaryButton = GetChildControl<ButtonControl>("secondaryButton");
secondaryTouched = GetChildControl<ButtonControl>("secondaryTouched");
thumbstickClicked = GetChildControl<ButtonControl>("thumbstickClicked");
thumbstickTouched = GetChildControl<ButtonControl>("thumbstickTouched");
devicePose = GetChildControl<PoseControl>("devicePose");
pointer = GetChildControl<PoseControl>("pointer");
isTracked = GetChildControl<ButtonControl>("isTracked");
trackingState = GetChildControl<IntegerControl>("trackingState");
devicePosition = GetChildControl<Vector3Control>("devicePosition");
deviceRotation = GetChildControl<QuaternionControl>("deviceRotation");
pointerPosition = GetChildControl<Vector3Control>("pointerPosition");
pointerRotation = GetChildControl<QuaternionControl>("pointerRotation");
haptic = GetChildControl<HapticControl>("haptic");
batteryLevel = GetChildControl<AxisControl>("BatteryLevel");
}
}
public const string profile = "/interaction_profiles/bytedance/pico4_controller";
// Available Bindings
// Left Hand Only
/// <summary>
/// Constant for a boolean interaction binding '.../input/x/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonX = "/input/x/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/x/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonXTouch = "/input/x/touch";
/// <summary>
/// Constant for a boolean interaction binding '.../input/y/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonY = "/input/y/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/y/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonYTouch = "/input/y/touch";
// Right Hand Only
/// <summary>
/// Constant for a boolean interaction binding '.../input/a/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonA = "/input/a/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/a/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonATouch = "/input/a/touch";
/// <summary>
/// Constant for a boolean interaction binding '..."/input/b/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonB = "/input/b/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/b/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonBTouch = "/input/b/touch";
// Both Hands
/// <summary>
/// Constant for a boolean interaction binding '.../input/menu/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string menu = "/input/menu/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/system/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.(may not be available for application use)
/// </summary>
public const string system = "/input/system/click";
/// <summary>
/// Constant for a float interaction binding '.../input/trigger/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string triggerClick = "/input/trigger/click";
/// <summary>
/// Constant for a float interaction binding '.../input/trigger/value' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string trigger = "/input/trigger/value";
/// <summary>
/// Constant for a boolean interaction binding '.../input/trigger/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string triggerTouch = "/input/trigger/touch";
/// <summary>
/// Constant for a Vector2 interaction binding '.../input/thumbstick' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstick = "/input/thumbstick";
/// <summary>
/// Constant for a boolean interaction binding '.../input/thumbstick/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstickClick = "/input/thumbstick/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/thumbstick/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstickTouch = "/input/thumbstick/touch";
/// <summary>
/// Constant for a float interaction binding '.../input/squeeze/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string squeezeClick = "/input/squeeze/click";
/// <summary>
/// Constant for a float interaction binding '.../input/squeeze/value' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string squeezeValue = "/input/squeeze/value";
/// <summary>
/// Constant for a pose interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string grip = "/input/grip/pose";
/// <summary>
/// Constant for a pose interaction binding '.../input/aim/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string aim = "/input/aim/pose";
/// <summary>
/// Constant for a haptic interaction binding '.../output/haptic' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string haptic = "/output/haptic";
public const string batteryLevel = "/input/battery/value";
private const string kDeviceLocalizedName = "PICO4 Touch Controller OpenXR";
/// <summary>
/// The OpenXR Extension string. This extension defines the interaction profile for PICO Neo3 and PICO 4 Controllers.
/// /// </summary>
public const string extensionString = "XR_BD_controller_interaction";
/// <inheritdoc/>
protected override void RegisterDeviceLayout()
{
InputSystem.InputSystem.RegisterLayout(typeof(PICO4TouchController),
matches: new InputDeviceMatcher()
.WithInterface(XRUtilities.InterfaceMatchAnyVersion)
.WithProduct(kDeviceLocalizedName));
}
/// <inheritdoc/>
protected override void UnregisterDeviceLayout()
{
InputSystem.InputSystem.RemoveLayout(nameof(PICO4TouchController));
}
/// <inheritdoc/>
protected override void RegisterActionMapsWithRuntime()
{
ActionMapConfig actionMap = new ActionMapConfig()
{
name = "PICO4TouchController",
localizedName = kDeviceLocalizedName,
desiredInteractionProfile = profile,
manufacturer = "PICO",
serialNumber = "",
deviceInfos = new List<DeviceConfig>()
{
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Left),
userPath = UserPaths.leftHand
},
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right),
userPath = UserPaths.rightHand
}
},
actions = new List<ActionConfig>()
{
// Grip
new ActionConfig()
{
name = "grip",
localizedName = "Grip",
type = ActionType.Axis1D,
usages = new List<string>()
{
"Grip"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = squeezeValue,
interactionProfileName = profile,
}
}
},
// Grip Pressed
new ActionConfig()
{
name = "gripPressed",
localizedName = "Grip Pressed",
type = ActionType.Binary,
usages = new List<string>()
{
"GripButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = squeezeClick,
interactionProfileName = profile,
}
}
},
//A / X Press
new ActionConfig()
{
name = "primaryButton",
localizedName = "Primary Button",
type = ActionType.Binary,
usages = new List<string>()
{
"PrimaryButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonX,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonA,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
//A / X Touch
new ActionConfig()
{
name = "primaryTouched",
localizedName = "Primary Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"PrimaryTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonXTouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonATouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
//B / Y Press
new ActionConfig()
{
name = "secondaryButton",
localizedName = "Secondary Button",
type = ActionType.Binary,
usages = new List<string>()
{
"SecondaryButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonY,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonB,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
//B / Y Touch
new ActionConfig()
{
name = "secondaryTouched",
localizedName = "Secondary Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"SecondaryTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonYTouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonBTouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
// Menu
new ActionConfig()
{
name = "menu",
localizedName = "Menu",
type = ActionType.Binary,
usages = new List<string>()
{
"Menu"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = menu,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
}
}
},
// System
new ActionConfig()
{
name = "system",
localizedName = "system",
type = ActionType.Binary,
usages = new List<string>()
{
"System"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = system,
interactionProfileName = profile,
}
}
},
// Trigger
new ActionConfig()
{
name = "trigger",
localizedName = "Trigger",
type = ActionType.Axis1D,
usages = new List<string>()
{
"Trigger"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = trigger,
interactionProfileName = profile,
}
}
},
// Trigger Pressed
new ActionConfig()
{
name = "triggerPressed",
localizedName = "Trigger Pressed",
type = ActionType.Binary,
usages = new List<string>()
{
"TriggerButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = triggerClick,
interactionProfileName = profile,
}
}
},
//Trigger Touch
new ActionConfig()
{
name = "triggerTouched",
localizedName = "Trigger Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"TriggerTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = triggerTouch,
interactionProfileName = profile,
}
}
},
// Joystick
new ActionConfig()
{
name = "thumbstick",
localizedName = "Thumbstick",
type = ActionType.Axis2D,
usages = new List<string>()
{
"Primary2DAxis"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstick,
interactionProfileName = profile,
}
}
},
//Thumbstick Clicked
new ActionConfig()
{
name = "thumbstickClicked",
localizedName = "Thumbstick Clicked",
type = ActionType.Binary,
usages = new List<string>()
{
"Primary2DAxisClick"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstickClick,
interactionProfileName = profile,
}
}
},
//Thumbstick Touched
new ActionConfig()
{
name = "thumbstickTouched",
localizedName = "Thumbstick Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"Primary2DAxisTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstickTouch,
interactionProfileName = profile,
}
}
},
// Device Pose
new ActionConfig()
{
name = "devicePose",
localizedName = "Device Pose",
type = ActionType.Pose,
usages = new List<string>()
{
"Device"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = grip,
interactionProfileName = profile,
}
}
},
// Pointer Pose
new ActionConfig()
{
name = "pointer",
localizedName = "Pointer Pose",
type = ActionType.Pose,
usages = new List<string>()
{
"Pointer"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = aim,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "batteryLevel",
localizedName = "BatteryLevel",
type = ActionType.Axis1D,
usages = new List<string>()
{
"BatteryLevel"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = batteryLevel,
interactionProfileName = profile,
}
}
},
// Haptics
new ActionConfig()
{
name = "haptic",
localizedName = "Haptic Output",
type = ActionType.Vibrate,
usages = new List<string>() { "Haptic" },
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = haptic,
interactionProfileName = profile,
}
}
}
}
};
AddActionMap(actionMap);
}
protected override string GetDeviceLayoutName()
{
return nameof(PICO4TouchController);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,743 @@
#if PICO_OPENXR_SDK
using System.Collections.Generic;
using UnityEngine.Scripting;
using UnityEngine.XR.OpenXR.Input;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.XR;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if USE_INPUT_SYSTEM_POSE_CONTROL
using PoseControl = UnityEngine.InputSystem.XR.PoseControl;
#else
using PoseControl = UnityEngine.XR.OpenXR.Input.PoseControl;
#endif
namespace UnityEngine.XR.OpenXR.Features.Interactions
{
/// <summary>
/// This <see cref="OpenXRInteractionFeature"/> enables the use of PICO TouchControllers interaction profiles in OpenXR.
/// </summary>
#if UNITY_EDITOR
[UnityEditor.XR.OpenXR.Features.OpenXRFeature(UiName = "PICO4 Ultra Touch Controller Profile",
BuildTargetGroups = new[] { BuildTargetGroup.Android },
Company = "PICO",
Desc = "Allows for mapping input to the PICO4 Ultra Touch Controller interaction profile.",
OpenxrExtensionStrings = extensionString,
Version = "1.0.0",
Category = UnityEditor.XR.OpenXR.Features.FeatureCategory.Interaction,
FeatureId = featureId
)]
#endif
public class PICO4UltraControllerProfile : OpenXRInteractionFeature
{
/// <summary>
/// The feature id string. This is used to give the feature a well known id for reference.
/// </summary>
public const string featureId = "com.unity.openxr.feature.input.PICO4Ultratouch";
/// <summary>
/// An Input System device based on the hand interaction profile in the PICO Touch Controller</a>.
/// </summary>
[Preserve, InputControlLayout(displayName = "PICO4 Ultra Touch Controller (OpenXR)", commonUsages = new[] { "LeftHand", "RightHand" })]
public class PICO4UltraController : XRControllerWithRumble
{
/// <summary>
/// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control) that represents the <see cref="PICO4UltraControllerProfile.thumbstick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "Primary2DAxis", "Joystick" }, usage = "Primary2DAxis")]
public Vector2Control thumbstick { get; private set; }
/// <summary>
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the <see cref="PICO4UltraControllerProfile.squeezeValue"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "GripAxis", "squeeze" }, usage = "Grip")]
public AxisControl grip { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.squeezeClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "GripButton", "squeezeClicked" }, usage = "GripButton")]
public ButtonControl gripPressed { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.menu"/> OpenXR bindings.
/// </summary>
[Preserve, InputControl(aliases = new[] { "Primary", "menuButton" }, usage = "Menu")]
public ButtonControl menu { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.system"/> OpenXR bindings.
/// </summary>
[Preserve, InputControl(aliases = new[] { "systemButton" }, usage = "system")]
public ButtonControl system { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.buttonA"/> <see cref="PICO4UltraControllerProfile.buttonX"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "A", "X", "buttonA", "buttonX" }, usage = "PrimaryButton")]
public ButtonControl primaryButton { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.buttonATouch"/> <see cref="PICO4UltraControllerProfile.buttonYTouch"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "ATouched", "XTouched", "ATouch", "XTouch", "buttonATouched", "buttonXTouched" }, usage = "PrimaryTouch")]
public ButtonControl primaryTouched { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.buttonB"/> <see cref="PICO4UltraControllerProfile.buttonY"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "B", "Y", "buttonB", "buttonY" }, usage = "SecondaryButton")]
public ButtonControl secondaryButton { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.buttonBTouch"/> <see cref="PICO4UltraControllerProfile.buttonYTouch"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "BTouched", "YTouched", "BTouch", "YTouch", "buttonBTouched", "buttonYTouched" }, usage = "SecondaryTouch")]
public ButtonControl secondaryTouched { get; private set; }
/// <summary>
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the <see cref="PICO4UltraControllerProfile.trigger"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(usage = "Trigger")]
public AxisControl trigger { get; private set; }
[Preserve, InputControl(usage = "BatteryLevel")]
public AxisControl batteryLevel { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.triggerClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "indexButton", "indexTouched", "triggerbutton" }, usage = "TriggerButton")]
public ButtonControl triggerPressed { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.triggerTouch"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "indexTouch", "indexNearTouched" }, usage = "TriggerTouch")]
public ButtonControl triggerTouched { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.thumbstickClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "JoystickOrPadPressed", "thumbstickClick", "joystickClicked" }, usage = "Primary2DAxisClick")]
public ButtonControl thumbstickClicked { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICO4UltraControllerProfile.thumbstickTouch"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "JoystickOrPadTouched", "thumbstickTouch", "joystickTouched" }, usage = "Primary2DAxisTouch")]
public ButtonControl thumbstickTouched { get; private set; }
/// <summary>
/// A <see cref="PoseControl"/> that represents the <see cref="PICO4UltraControllerProfile.grip"/> OpenXR binding.
/// </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="PICO4UltraControllerProfile.aim"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(offset = 0, alias = "aimPose", usage = "Pointer")]
public PoseControl pointer { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) required for backwards compatibility with the XRSDK layouts. This represents the overall tracking state of the device. This value is equivalent to mapping devicePose/isTracked.
/// </summary>
[Preserve, InputControl(offset = 28, usage = "IsTracked")]
new public ButtonControl isTracked { get; private set; }
/// <summary>
/// A [IntegerControl](xref:UnityEngine.InputSystem.Controls.IntegerControl) required for backwards compatibility with the XRSDK layouts. This represents the bit flag set to indicate what data is valid. This value is equivalent to mapping devicePose/trackingState.
/// </summary>
[Preserve, InputControl(offset = 32, usage = "TrackingState")]
new public IntegerControl trackingState { get; private set; }
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the device position. For the PICO Touch device, this is both the grip and the pointer position. This value is equivalent to mapping devicePose/position.
/// </summary>
[Preserve, InputControl(offset = 36, noisy = true, alias = "gripPosition")]
new public Vector3Control devicePosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the device orientation. For the PICO Touch device, this is both the grip and the pointer rotation. This value is equivalent to mapping devicePose/rotation.
/// </summary>
[Preserve, InputControl(offset = 48, noisy = true, alias = "gripOrientation")]
new public QuaternionControl deviceRotation { get; private set; }
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for back compatibility with the XRSDK layouts. This is the pointer position. This value is equivalent to mapping pointerPose/position.
/// </summary>
[Preserve, InputControl(offset = 96)]
public Vector3Control pointerPosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the pointer rotation. This value is equivalent to mapping pointerPose/rotation.
/// </summary>
[Preserve, InputControl(offset = 108, alias = "pointerOrientation")]
public QuaternionControl pointerRotation { get; private set; }
/// <summary>
/// A <see cref="HapticControl"/> that represents the <see cref="PICO4UltraControllerProfile.haptic"/> binding.
/// </summary>
[Preserve, InputControl(usage = "Haptic")]
public HapticControl haptic { get; private set; }
/// <summary>
/// Internal call used to assign controls to the the correct element.
/// </summary>
protected override void FinishSetup()
{
base.FinishSetup();
thumbstick = GetChildControl<Vector2Control>("thumbstick");
trigger = GetChildControl<AxisControl>("trigger");
triggerPressed = GetChildControl<ButtonControl>("triggerPressed");
triggerTouched = GetChildControl<ButtonControl>("triggerTouched");
batteryLevel = GetChildControl<AxisControl>("BatteryLevel");
grip = GetChildControl<AxisControl>("grip");
gripPressed = GetChildControl<ButtonControl>("gripPressed");
menu = GetChildControl<ButtonControl>("menu");
primaryButton = GetChildControl<ButtonControl>("primaryButton");
primaryTouched = GetChildControl<ButtonControl>("primaryTouched");
secondaryButton = GetChildControl<ButtonControl>("secondaryButton");
secondaryTouched = GetChildControl<ButtonControl>("secondaryTouched");
thumbstickClicked = GetChildControl<ButtonControl>("thumbstickClicked");
thumbstickTouched = GetChildControl<ButtonControl>("thumbstickTouched");
devicePose = GetChildControl<PoseControl>("devicePose");
pointer = GetChildControl<PoseControl>("pointer");
isTracked = GetChildControl<ButtonControl>("isTracked");
trackingState = GetChildControl<IntegerControl>("trackingState");
devicePosition = GetChildControl<Vector3Control>("devicePosition");
deviceRotation = GetChildControl<QuaternionControl>("deviceRotation");
pointerPosition = GetChildControl<Vector3Control>("pointerPosition");
pointerRotation = GetChildControl<QuaternionControl>("pointerRotation");
haptic = GetChildControl<HapticControl>("haptic");
}
}
public const string profile = "/interaction_profiles/bytedance/pico4s_controller";
// Available Bindings
// Left Hand Only
/// <summary>
/// Constant for a boolean interaction binding '.../input/x/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonX = "/input/x/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/x/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonXTouch = "/input/x/touch";
/// <summary>
/// Constant for a boolean interaction binding '.../input/y/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonY = "/input/y/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/y/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonYTouch = "/input/y/touch";
// Right Hand Only
/// <summary>
/// Constant for a boolean interaction binding '.../input/a/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonA = "/input/a/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/a/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonATouch = "/input/a/touch";
/// <summary>
/// Constant for a boolean interaction binding '..."/input/b/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonB = "/input/b/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/b/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonBTouch = "/input/b/touch";
// Both Hands
/// <summary>
/// Constant for a boolean interaction binding '.../input/menu/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string menu = "/input/menu/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/system/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.(may not be available for application use)
/// </summary>
public const string system = "/input/system/click";
/// <summary>
/// Constant for a float interaction binding '.../input/trigger/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string triggerClick = "/input/trigger/click";
/// <summary>
/// Constant for a float interaction binding '.../input/trigger/value' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string trigger = "/input/trigger/value";
/// <summary>
/// Constant for a boolean interaction binding '.../input/trigger/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string triggerTouch = "/input/trigger/touch";
/// <summary>
/// Constant for a Vector2 interaction binding '.../input/thumbstick' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstick = "/input/thumbstick";
/// <summary>
/// Constant for a boolean interaction binding '.../input/thumbstick/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstickClick = "/input/thumbstick/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/thumbstick/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstickTouch = "/input/thumbstick/touch";
/// <summary>
/// Constant for a float interaction binding '.../input/squeeze/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string squeezeClick = "/input/squeeze/click";
/// <summary>
/// Constant for a float interaction binding '.../input/squeeze/value' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string squeezeValue = "/input/squeeze/value";
/// <summary>
/// Constant for a pose interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string grip = "/input/grip/pose";
/// <summary>
/// Constant for a pose interaction binding '.../input/aim/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string aim = "/input/aim/pose";
/// <summary>
/// Constant for a haptic interaction binding '.../output/haptic' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string haptic = "/output/haptic";
public const string batteryLevel = "/input/battery/value";
private const string kDeviceLocalizedName = "PICO4 Ultra Touch Controller OpenXR";
/// <summary>
/// The OpenXR Extension string. This extension defines the interaction profile for PICO Neo3 and PICO 4 Controllers.
/// /// </summary>
public const string extensionString = "XR_BD_controller_interaction";
/// <inheritdoc/>
protected override void RegisterDeviceLayout()
{
InputSystem.InputSystem.RegisterLayout(typeof(PICO4UltraController),
matches: new InputDeviceMatcher()
.WithInterface(XRUtilities.InterfaceMatchAnyVersion)
.WithProduct(kDeviceLocalizedName));
}
/// <inheritdoc/>
protected override void UnregisterDeviceLayout()
{
InputSystem.InputSystem.RemoveLayout(nameof(PICO4UltraController));
}
/// <inheritdoc/>
protected override void RegisterActionMapsWithRuntime()
{
ActionMapConfig actionMap = new ActionMapConfig()
{
name = "PICO4UltraController",
localizedName = kDeviceLocalizedName,
desiredInteractionProfile = profile,
manufacturer = "PICO",
serialNumber = "",
deviceInfos = new List<DeviceConfig>()
{
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Left),
userPath = UserPaths.leftHand
},
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right),
userPath = UserPaths.rightHand
}
},
actions = new List<ActionConfig>()
{
// Grip
new ActionConfig()
{
name = "grip",
localizedName = "Grip",
type = ActionType.Axis1D,
usages = new List<string>()
{
"Grip"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = squeezeValue,
interactionProfileName = profile,
}
}
},
// Grip Pressed
new ActionConfig()
{
name = "gripPressed",
localizedName = "Grip Pressed",
type = ActionType.Binary,
usages = new List<string>()
{
"GripButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = squeezeClick,
interactionProfileName = profile,
}
}
},
//A / X Press
new ActionConfig()
{
name = "primaryButton",
localizedName = "Primary Button",
type = ActionType.Binary,
usages = new List<string>()
{
"PrimaryButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonX,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonA,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
//A / X Touch
new ActionConfig()
{
name = "primaryTouched",
localizedName = "Primary Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"PrimaryTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonXTouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonATouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
//B / Y Press
new ActionConfig()
{
name = "secondaryButton",
localizedName = "Secondary Button",
type = ActionType.Binary,
usages = new List<string>()
{
"SecondaryButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonY,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonB,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
//B / Y Touch
new ActionConfig()
{
name = "secondaryTouched",
localizedName = "Secondary Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"SecondaryTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonYTouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonBTouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
// Menu
new ActionConfig()
{
name = "menu",
localizedName = "Menu",
type = ActionType.Binary,
usages = new List<string>()
{
"Menu"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = menu,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
}
}
},
// System
new ActionConfig()
{
name = "system",
localizedName = "system",
type = ActionType.Binary,
usages = new List<string>()
{
"System"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = system,
interactionProfileName = profile,
}
}
},
// Trigger
new ActionConfig()
{
name = "trigger",
localizedName = "Trigger",
type = ActionType.Axis1D,
usages = new List<string>()
{
"Trigger"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = trigger,
interactionProfileName = profile,
}
}
},
// Trigger Pressed
new ActionConfig()
{
name = "triggerPressed",
localizedName = "Trigger Pressed",
type = ActionType.Binary,
usages = new List<string>()
{
"TriggerButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = triggerClick,
interactionProfileName = profile,
}
}
},
//Trigger Touch
new ActionConfig()
{
name = "triggerTouched",
localizedName = "Trigger Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"TriggerTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = triggerTouch,
interactionProfileName = profile,
}
}
},
// Joystick
new ActionConfig()
{
name = "thumbstick",
localizedName = "Thumbstick",
type = ActionType.Axis2D,
usages = new List<string>()
{
"Primary2DAxis"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstick,
interactionProfileName = profile,
}
}
},
//Thumbstick Clicked
new ActionConfig()
{
name = "thumbstickClicked",
localizedName = "Thumbstick Clicked",
type = ActionType.Binary,
usages = new List<string>()
{
"Primary2DAxisClick"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstickClick,
interactionProfileName = profile,
}
}
},
//Thumbstick Touched
new ActionConfig()
{
name = "thumbstickTouched",
localizedName = "Thumbstick Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"Primary2DAxisTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstickTouch,
interactionProfileName = profile,
}
}
},
// Device Pose
new ActionConfig()
{
name = "devicePose",
localizedName = "Device Pose",
type = ActionType.Pose,
usages = new List<string>()
{
"Device"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = grip,
interactionProfileName = profile,
}
}
},
// Pointer Pose
new ActionConfig()
{
name = "pointer",
localizedName = "Pointer Pose",
type = ActionType.Pose,
usages = new List<string>()
{
"Pointer"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = aim,
interactionProfileName = profile,
}
}
},
// Trigger
new ActionConfig()
{
name = "batteryLevel",
localizedName = "BatteryLevel",
type = ActionType.Axis1D,
usages = new List<string>()
{
"BatteryLevel"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = batteryLevel,
interactionProfileName = profile,
}
}
},
// Haptics
new ActionConfig()
{
name = "haptic",
localizedName = "Haptic Output",
type = ActionType.Vibrate,
usages = new List<string>() { "Haptic" },
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = haptic,
interactionProfileName = profile,
}
}
}
}
};
AddActionMap(actionMap);
}
protected override string GetDeviceLayoutName()
{
return nameof(PICO4UltraController);
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4891747df4d5e714f9fec69b98639e2c
timeCreated: 1712037227

View File

@@ -0,0 +1,496 @@
#if PICO_OPENXR_SDK
using System.Collections.Generic;
using UnityEngine.Scripting;
using UnityEngine.XR.OpenXR.Input;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.XR;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if USE_INPUT_SYSTEM_POSE_CONTROL
using PoseControl = UnityEngine.InputSystem.XR.PoseControl;
#else
using PoseControl = UnityEngine.XR.OpenXR.Input.PoseControl;
#endif
namespace UnityEngine.XR.OpenXR.Features.Interactions
{
/// <summary>
/// This <see cref="OpenXRInteractionFeature"/> enables the use of PICO TouchControllers interaction profiles in OpenXR.
/// </summary>
#if UNITY_EDITOR
[UnityEditor.XR.OpenXR.Features.OpenXRFeature(UiName = "PICOG3 Touch Controller Profile",
BuildTargetGroups = new[] { BuildTargetGroup.Android },
Company = "PICO",
Desc = "Allows for mapping input to the PICOG3 Touch Controller interaction profile.",
OpenxrExtensionStrings = extensionString,
Version = "1.0.0",
Category = UnityEditor.XR.OpenXR.Features.FeatureCategory.Interaction,
FeatureId = featureId
)]
#endif
public class PICOG3ControllerProfile : OpenXRInteractionFeature
{
/// <summary>
/// The feature id string. This is used to give the feature a well known id for reference.
/// </summary>
public const string featureId = "com.unity.openxr.feature.input.PICOG3touch";
/// <summary>
/// An Input System device based on the hand interaction profile in the PICO Touch Controller</a>.
/// </summary>
[Preserve,
InputControlLayout(displayName = "PICOG3 Touch Controller (OpenXR)", commonUsages = new[] { "LeftHand", "RightHand" })]
public class PICOG3TouchController : XRControllerWithRumble
{
/// <summary>
/// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control) that represents the <see cref="PICOG3TouchControllerProfile.thumbstick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "Primary2DAxis", "Joystick" }, usage = "Primary2DAxis")]
public Vector2Control thumbstick { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICOG3TouchControllerProfile.menu"/> OpenXR bindings.
/// </summary>
[Preserve, InputControl(aliases = new[] { "Primary", "menuButton" }, usage = "Menu")]
public ButtonControl menu { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICOG3TouchControllerProfile.system"/> OpenXR bindings.
/// </summary>
[Preserve, InputControl(aliases = new[] { "systemButton" }, usage = "system")]
public ButtonControl system { get; private set; }
/// <summary>
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the <see cref="PICOG3TouchControllerProfile.trigger"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(usage = "Trigger")]
public AxisControl trigger { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICOG3TouchControllerProfile.triggerClick"/> OpenXR binding.
/// </summary>
[Preserve,
InputControl(aliases = new[] { "indexButton", "indexTouched", "triggerbutton" }, usage = "TriggerButton")]
public ButtonControl triggerPressed { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICOG3TouchControllerProfile.thumbstickClick"/> OpenXR binding.
/// </summary>
[Preserve,
InputControl(aliases = new[] { "JoystickOrPadPressed", "thumbstickClick", "joystickClicked" },
usage = "Primary2DAxisClick")]
public ButtonControl thumbstickClicked { get; private set; }
/// <summary>
/// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control) that represents information from the <see cref="HTCViveControllerProfile.trackpad"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "Primary2DAxis", "touchpadaxes", "touchpad" }, usage = "Primary2DAxis")]
public Vector2Control trackpad { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents information from the <see cref="HTCViveControllerProfile.trackpadClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "joystickorpadpressed", "touchpadpressed" }, usage = "Primary2DAxisClick")]
public ButtonControl trackpadClicked { get; private set; }
/// <summary>
/// A <see cref="PoseControl"/> that represents the <see cref="PICOG3TouchControllerProfile.grip"/> OpenXR binding.
/// </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="PICOG3TouchControllerProfile.aim"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(offset = 0, alias = "aimPose", usage = "Pointer")]
public PoseControl pointer { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) required for backwards compatibility with the XRSDK layouts. This represents the overall tracking state of the device. This value is equivalent to mapping devicePose/isTracked.
/// </summary>
[Preserve, InputControl(offset = 28, usage = "IsTracked")]
new public ButtonControl isTracked { get; private set; }
/// <summary>
/// A [IntegerControl](xref:UnityEngine.InputSystem.Controls.IntegerControl) required for backwards compatibility with the XRSDK layouts. This represents the bit flag set to indicate what data is valid. This value is equivalent to mapping devicePose/trackingState.
/// </summary>
[Preserve, InputControl(offset = 32, usage = "TrackingState")]
new public IntegerControl trackingState { get; private set; }
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the device position. For the PICO Touch device, this is both the grip and the pointer position. This value is equivalent to mapping devicePose/position.
/// </summary>
[Preserve, InputControl(offset = 36, noisy = true, alias = "gripPosition")]
new public Vector3Control devicePosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the device orientation. For the PICO Touch device, this is both the grip and the pointer rotation. This value is equivalent to mapping devicePose/rotation.
/// </summary>
[Preserve, InputControl(offset = 48, noisy = true, alias = "gripOrientation")]
new public QuaternionControl deviceRotation { get; private set; }
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for back compatibility with the XRSDK layouts. This is the pointer position. This value is equivalent to mapping pointerPose/position.
/// </summary>
[Preserve, InputControl(offset = 96)]
public Vector3Control pointerPosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the pointer rotation. This value is equivalent to mapping pointerPose/rotation.
/// </summary>
[Preserve, InputControl(offset = 108, alias = "pointerOrientation")]
public QuaternionControl pointerRotation { get; private set; }
[Preserve, InputControl(usage = "BatteryLevel")]
public AxisControl batteryLevel { get; private set; }
/// <summary>
/// Internal call used to assign controls to the the correct element.
/// </summary>
protected override void FinishSetup()
{
base.FinishSetup();
thumbstick = GetChildControl<Vector2Control>("thumbstick");
// trigger = GetChildControl<AxisControl>("trigger");
trigger = GetChildControl<AxisControl>("trigger");
triggerPressed = GetChildControl<ButtonControl>("triggerPressed");
trackpad = GetChildControl<Vector2Control>("trackpad");
trackpadClicked = GetChildControl<ButtonControl>("trackpadClicked");
menu = GetChildControl<ButtonControl>("menu");
thumbstickClicked = GetChildControl<ButtonControl>("thumbstickClicked");
devicePose = GetChildControl<PoseControl>("devicePose");
pointer = GetChildControl<PoseControl>("pointer");
isTracked = GetChildControl<ButtonControl>("isTracked");
trackingState = GetChildControl<IntegerControl>("trackingState");
devicePosition = GetChildControl<Vector3Control>("devicePosition");
deviceRotation = GetChildControl<QuaternionControl>("deviceRotation");
pointerPosition = GetChildControl<Vector3Control>("pointerPosition");
pointerRotation = GetChildControl<QuaternionControl>("pointerRotation");
batteryLevel = GetChildControl<AxisControl>("BatteryLevel");
}
}
public const string profile = "/interaction_profiles/bytedance/pico_g3_controller";
// Available Bindings
/// <summary>
/// Constant for a boolean interaction binding '.../input/thumbstick/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstickClick = "/input/thumbstick/click";
/// <summary>
/// Constant for a Vector2 interaction binding '.../input/thumbstick' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstick = "/input/thumbstick";
/// <summary>
/// Constant for a float interaction binding '.../input/trigger/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string triggerClick = "/input/trigger/click";
/// <summary>
/// Constant for a float interaction binding '.../input/trigger/value' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string trigger = "/input/trigger/value";
/// <summary>
/// Constant for a pose interaction binding '.../input/aim/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string aim = "/input/aim/pose";
/// <summary>
/// Constant for a boolean interaction binding '.../input/menu/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string menu = "/input/menu/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/system/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.(may not be available for application use)
/// </summary>
public const string system = "/input/system/click";
/// <summary>
/// Constant for a Vector2 interaction binding '.../input/trackpad' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string trackpad = "/input/trackpad";
/// <summary>
/// Constant for a boolean interaction binding '.../input/trackpad/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string trackpadClick = "/input/trackpad/click";
/// <summary>
/// Constant for a pose interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string grip = "/input/grip/pose";
public const string batteryLevel = "/input/battery/value";
private const string kDeviceLocalizedName = "PICOG3 Touch Controller OpenXR";
/// <summary>
/// The OpenXR Extension string. This extension defines the interaction profile for PICO Neo3 and PICO 4 Controllers.
/// /// </summary>
public const string extensionString = "XR_BD_controller_interaction";
/// <inheritdoc/>
protected override void RegisterDeviceLayout()
{
InputSystem.InputSystem.RegisterLayout(typeof(PICOG3TouchController),
matches: new InputDeviceMatcher()
.WithInterface(XRUtilities.InterfaceMatchAnyVersion)
.WithProduct(kDeviceLocalizedName));
}
/// <inheritdoc/>
protected override void UnregisterDeviceLayout()
{
InputSystem.InputSystem.RemoveLayout(nameof(PICOG3TouchController));
}
/// <inheritdoc/>
protected override void RegisterActionMapsWithRuntime()
{
ActionMapConfig actionMap = new ActionMapConfig()
{
name = "PICOG3TouchController",
localizedName = kDeviceLocalizedName,
desiredInteractionProfile = profile,
manufacturer = "PICO",
serialNumber = "",
deviceInfos = new List<DeviceConfig>()
{
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Left),
userPath = UserPaths.leftHand
},
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right),
userPath = UserPaths.rightHand
}
},
actions = new List<ActionConfig>()
{
new ActionConfig()
{
name = "trigger",
localizedName = "Trigger",
type = ActionType.Axis1D,
usages = new List<string>()
{
"Trigger"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = trigger,
interactionProfileName = profile,
}
}
},
// Menu
new ActionConfig()
{
name = "menu",
localizedName = "Menu",
type = ActionType.Binary,
usages = new List<string>()
{
"Menu"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = menu,
interactionProfileName = profile,
}
}
},
// System
new ActionConfig()
{
name = "system",
localizedName = "system",
type = ActionType.Binary,
usages = new List<string>()
{
"System"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = system,
interactionProfileName = profile,
}
}
},
// Trigger Pressed
new ActionConfig()
{
name = "triggerPressed",
localizedName = "Trigger Pressed",
type = ActionType.Binary,
usages = new List<string>()
{
"TriggerButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = triggerClick,
interactionProfileName = profile,
}
}
},
// Joystick
new ActionConfig()
{
name = "thumbstick",
localizedName = "Thumbstick",
type = ActionType.Axis2D,
usages = new List<string>()
{
"Primary2DAxis"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstick,
interactionProfileName = profile,
}
}
},
//Thumbstick Clicked
new ActionConfig()
{
name = "thumbstickClicked",
localizedName = "Thumbstick Clicked",
type = ActionType.Binary,
usages = new List<string>()
{
"Primary2DAxisClick"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstickClick,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "trackpad",
localizedName = "Trackpad",
type = ActionType.Axis2D,
usages = new List<string>()
{
"Primary2DAxis"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = trackpad,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "trackpadClicked",
localizedName = "Trackpad Clicked",
type = ActionType.Binary,
usages = new List<string>()
{
"Primary2DAxisClick"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = trackpadClick,
interactionProfileName = profile,
}
}
},
// Device Pose
new ActionConfig()
{
name = "devicePose",
localizedName = "Device Pose",
type = ActionType.Pose,
usages = new List<string>()
{
"Device"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = grip,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "batteryLevel",
localizedName = "BatteryLevel",
type = ActionType.Axis1D,
usages = new List<string>()
{
"BatteryLevel"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = batteryLevel,
interactionProfileName = profile,
}
}
},
// Pointer Pose
new ActionConfig()
{
name = "pointer",
localizedName = "Pointer Pose",
type = ActionType.Pose,
usages = new List<string>()
{
"Pointer"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = aim,
interactionProfileName = profile,
}
}
},
}
};
AddActionMap(actionMap);
}
protected override string GetDeviceLayoutName()
{
return nameof(PICOG3TouchController);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,738 @@
#if PICO_OPENXR_SDK
using System.Collections.Generic;
using UnityEngine.Scripting;
using UnityEngine.XR.OpenXR.Input;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.XR;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if USE_INPUT_SYSTEM_POSE_CONTROL
using PoseControl = UnityEngine.InputSystem.XR.PoseControl;
#else
using PoseControl = UnityEngine.XR.OpenXR.Input.PoseControl;
#endif
namespace UnityEngine.XR.OpenXR.Features.Interactions
{
/// <summary>
/// This <see cref="OpenXRInteractionFeature"/> enables the use of PICO TouchControllers interaction profiles in OpenXR.
/// </summary>
#if UNITY_EDITOR
[UnityEditor.XR.OpenXR.Features.OpenXRFeature(UiName = "PICO Neo3 Touch Controller Profile",
BuildTargetGroups = new[] { BuildTargetGroup.Android },
Company = "PICO",
Desc = "Allows for mapping input to the PICO Neo3 Touch Controller interaction profile.",
OpenxrExtensionStrings = extensionString,
Version = "1.0.0",
Category = UnityEditor.XR.OpenXR.Features.FeatureCategory.Interaction,
FeatureId = featureId
)]
#endif
public class PICONeo3ControllerProfile : OpenXRInteractionFeature
{
/// <summary>
/// The feature id string. This is used to give the feature a well known id for reference.
/// </summary>
public const string featureId = "com.unity.openxr.feature.input.PICONeo3touch";
/// <summary>
/// An Input System device based on the hand interaction profile in the PICO Touch Controller</a>.
/// </summary>
[Preserve, InputControlLayout(displayName = "PICO Neo3 Touch Controller (OpenXR)", commonUsages = new[] { "LeftHand", "RightHand" })]
public class PICONeo3Controller : XRControllerWithRumble
{
/// <summary>
/// A [Vector2Control](xref:UnityEngine.InputSystem.Controls.Vector2Control) that represents the <see cref="PICONeo3TouchControllerProfile.thumbstick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "Primary2DAxis", "Joystick" }, usage = "Primary2DAxis")]
public Vector2Control thumbstick { get; private set; }
/// <summary>
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the <see cref="PICONeo3TouchControllerProfile.squeezeValue"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "GripAxis", "squeeze" }, usage = "Grip")]
public AxisControl grip { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.squeezeClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "GripButton", "squeezeClicked" }, usage = "GripButton")]
public ButtonControl gripPressed { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.menu"/> OpenXR bindings.
/// </summary>
[Preserve, InputControl(aliases = new[] { "Primary", "menuButton" }, usage = "Menu")]
public ButtonControl menu { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.system"/> OpenXR bindings.
/// </summary>
[Preserve, InputControl(aliases = new[] { "systemButton" }, usage = "system")]
public ButtonControl system { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.buttonA"/> <see cref="PICONeo3TouchControllerProfile.buttonX"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "A", "X", "buttonA", "buttonX" }, usage = "PrimaryButton")]
public ButtonControl primaryButton { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.buttonATouch"/> <see cref="PICONeo3TouchControllerProfile.buttonYTouch"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "ATouched", "XTouched", "ATouch", "XTouch", "buttonATouched", "buttonXTouched" }, usage = "PrimaryTouch")]
public ButtonControl primaryTouched { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.buttonB"/> <see cref="PICONeo3TouchControllerProfile.buttonY"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "B", "Y", "buttonB", "buttonY" }, usage = "SecondaryButton")]
public ButtonControl secondaryButton { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.buttonBTouch"/> <see cref="PICONeo3TouchControllerProfile.buttonYTouch"/> OpenXR bindings, depending on handedness.
/// </summary>
[Preserve, InputControl(aliases = new[] { "BTouched", "YTouched", "BTouch", "YTouch", "buttonBTouched", "buttonYTouched" }, usage = "SecondaryTouch")]
public ButtonControl secondaryTouched { get; private set; }
/// <summary>
/// A [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl) that represents the <see cref="PICONeo3TouchControllerProfile.trigger"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(usage = "Trigger")]
public AxisControl trigger { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.triggerClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "indexButton", "indexTouched", "triggerbutton" }, usage = "TriggerButton")]
public ButtonControl triggerPressed { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.triggerTouch"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "indexTouch", "indexNearTouched" }, usage = "TriggerTouch")]
public ButtonControl triggerTouched { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.thumbstickClick"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "JoystickOrPadPressed", "thumbstickClick", "joystickClicked" }, usage = "Primary2DAxisClick")]
public ButtonControl thumbstickClicked { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) that represents the <see cref="PICONeo3TouchControllerProfile.thumbstickTouch"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(aliases = new[] { "JoystickOrPadTouched", "thumbstickTouch", "joystickTouched" }, usage = "Primary2DAxisTouch")]
public ButtonControl thumbstickTouched { get; private set; }
/// <summary>
/// A <see cref="PoseControl"/> that represents the <see cref="PICONeo3TouchControllerProfile.grip"/> OpenXR binding.
/// </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="PICONeo3TouchControllerProfile.aim"/> OpenXR binding.
/// </summary>
[Preserve, InputControl(offset = 0, alias = "aimPose", usage = "Pointer")]
public PoseControl pointer { get; private set; }
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl) required for backwards compatibility with the XRSDK layouts. This represents the overall tracking state of the device. This value is equivalent to mapping devicePose/isTracked.
/// </summary>
[Preserve, InputControl(offset = 28, usage = "IsTracked")]
new public ButtonControl isTracked { get; private set; }
/// <summary>
/// A [IntegerControl](xref:UnityEngine.InputSystem.Controls.IntegerControl) required for backwards compatibility with the XRSDK layouts. This represents the bit flag set to indicate what data is valid. This value is equivalent to mapping devicePose/trackingState.
/// </summary>
[Preserve, InputControl(offset = 32, usage = "TrackingState")]
new public IntegerControl trackingState { get; private set; }
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for backwards compatibility with the XRSDK layouts. This is the device position. For the PICO Touch device, this is both the grip and the pointer position. This value is equivalent to mapping devicePose/position.
/// </summary>
[Preserve, InputControl(offset = 36, noisy = true, alias = "gripPosition")]
new public Vector3Control devicePosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the device orientation. For the PICO Touch device, this is both the grip and the pointer rotation. This value is equivalent to mapping devicePose/rotation.
/// </summary>
[Preserve, InputControl(offset = 48, noisy = true, alias = "gripOrientation")]
new public QuaternionControl deviceRotation { get; private set; }
/// <summary>
/// A [Vector3Control](xref:UnityEngine.InputSystem.Controls.Vector3Control) required for back compatibility with the XRSDK layouts. This is the pointer position. This value is equivalent to mapping pointerPose/position.
/// </summary>
[Preserve, InputControl(offset = 96)]
public Vector3Control pointerPosition { get; private set; }
/// <summary>
/// A [QuaternionControl](xref:UnityEngine.InputSystem.Controls.QuaternionControl) required for backwards compatibility with the XRSDK layouts. This is the pointer rotation. This value is equivalent to mapping pointerPose/rotation.
/// </summary>
[Preserve, InputControl(offset = 108, alias = "pointerOrientation")]
public QuaternionControl pointerRotation { get; private set; }
/// <summary>
/// A <see cref="HapticControl"/> that represents the <see cref="PICONeo3TouchControllerProfile.haptic"/> binding.
/// </summary>
[Preserve, InputControl(usage = "Haptic")]
public HapticControl haptic { get; private set; }
[Preserve, InputControl(usage = "BatteryLevel")]
public AxisControl batteryLevel { get; private set; }
/// <summary>
/// Internal call used to assign controls to the the correct element.
/// </summary>
protected override void FinishSetup()
{
base.FinishSetup();
thumbstick = GetChildControl<Vector2Control>("thumbstick");
trigger = GetChildControl<AxisControl>("trigger");
triggerPressed = GetChildControl<ButtonControl>("triggerPressed");
triggerTouched = GetChildControl<ButtonControl>("triggerTouched");
grip = GetChildControl<AxisControl>("grip");
gripPressed = GetChildControl<ButtonControl>("gripPressed");
menu = GetChildControl<ButtonControl>("menu");
primaryButton = GetChildControl<ButtonControl>("primaryButton");
primaryTouched = GetChildControl<ButtonControl>("primaryTouched");
secondaryButton = GetChildControl<ButtonControl>("secondaryButton");
secondaryTouched = GetChildControl<ButtonControl>("secondaryTouched");
thumbstickClicked = GetChildControl<ButtonControl>("thumbstickClicked");
thumbstickTouched = GetChildControl<ButtonControl>("thumbstickTouched");
devicePose = GetChildControl<PoseControl>("devicePose");
pointer = GetChildControl<PoseControl>("pointer");
isTracked = GetChildControl<ButtonControl>("isTracked");
trackingState = GetChildControl<IntegerControl>("trackingState");
devicePosition = GetChildControl<Vector3Control>("devicePosition");
deviceRotation = GetChildControl<QuaternionControl>("deviceRotation");
pointerPosition = GetChildControl<Vector3Control>("pointerPosition");
pointerRotation = GetChildControl<QuaternionControl>("pointerRotation");
batteryLevel = GetChildControl<AxisControl>("BatteryLevel");
haptic = GetChildControl<HapticControl>("haptic");
}
}
public const string profile = "/interaction_profiles/bytedance/pico_neo3_controller";
// Available Bindings
// Left Hand Only
/// <summary>
/// Constant for a boolean interaction binding '.../input/x/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonX = "/input/x/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/x/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonXTouch = "/input/x/touch";
/// <summary>
/// Constant for a boolean interaction binding '.../input/y/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonY = "/input/y/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/y/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.leftHand"/> user path.
/// </summary>
public const string buttonYTouch = "/input/y/touch";
// Right Hand Only
/// <summary>
/// Constant for a boolean interaction binding '.../input/a/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonA = "/input/a/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/a/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonATouch = "/input/a/touch";
/// <summary>
/// Constant for a boolean interaction binding '..."/input/b/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonB = "/input/b/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/b/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs. This binding is only available for the <see cref="OpenXRInteractionFeature.UserPaths.rightHand"/> user path.
/// </summary>
public const string buttonBTouch = "/input/b/touch";
// Both Hands
/// <summary>
/// Constant for a boolean interaction binding '.../input/menu/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string menu = "/input/menu/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/system/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.(may not be available for application use)
/// </summary>
public const string system = "/input/system/click";
/// <summary>
/// Constant for a float interaction binding '.../input/trigger/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string triggerClick = "/input/trigger/click";
/// <summary>
/// Constant for a float interaction binding '.../input/trigger/value' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string trigger = "/input/trigger/value";
/// <summary>
/// Constant for a boolean interaction binding '.../input/trigger/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string triggerTouch = "/input/trigger/touch";
/// <summary>
/// Constant for a Vector2 interaction binding '.../input/thumbstick' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstick = "/input/thumbstick";
/// <summary>
/// Constant for a boolean interaction binding '.../input/thumbstick/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstickClick = "/input/thumbstick/click";
/// <summary>
/// Constant for a boolean interaction binding '.../input/thumbstick/touch' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string thumbstickTouch = "/input/thumbstick/touch";
/// <summary>
/// Constant for a float interaction binding '.../input/squeeze/click' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string squeezeClick = "/input/squeeze/click";
/// <summary>
/// Constant for a float interaction binding '.../input/squeeze/value' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string squeezeValue = "/input/squeeze/value";
/// <summary>
/// Constant for a pose interaction binding '.../input/grip/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string grip = "/input/grip/pose";
/// <summary>
/// Constant for a pose interaction binding '.../input/aim/pose' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string aim = "/input/aim/pose";
/// <summary>
/// Constant for a haptic interaction binding '.../output/haptic' OpenXR Input Binding. Used by input subsystem to bind actions to physical inputs.
/// </summary>
public const string haptic = "/output/haptic";
public const string batteryLevel = "/input/battery/value";
private const string kDeviceLocalizedName = "PICO Neo3 Touch Controller OpenXR";
/// <summary>
/// The OpenXR Extension string. This extension defines the interaction profile for PICO Neo3 and PICO 4 Controllers.
/// /// </summary>
public const string extensionString = "XR_BD_controller_interaction";
/// <inheritdoc/>
protected override void RegisterDeviceLayout()
{
InputSystem.InputSystem.RegisterLayout(typeof(PICONeo3Controller),
matches: new InputDeviceMatcher()
.WithInterface(XRUtilities.InterfaceMatchAnyVersion)
.WithProduct(kDeviceLocalizedName));
}
/// <inheritdoc/>
protected override void UnregisterDeviceLayout()
{
InputSystem.InputSystem.RemoveLayout(nameof(PICONeo3Controller));
}
/// <inheritdoc/>
protected override void RegisterActionMapsWithRuntime()
{
ActionMapConfig actionMap = new ActionMapConfig()
{
name = "PICONeo3controller",
localizedName = kDeviceLocalizedName,
desiredInteractionProfile = profile,
manufacturer = "PICO",
serialNumber = "",
deviceInfos = new List<DeviceConfig>()
{
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Left),
userPath = UserPaths.leftHand
},
new DeviceConfig()
{
characteristics = (InputDeviceCharacteristics)(InputDeviceCharacteristics.HeldInHand | InputDeviceCharacteristics.TrackedDevice | InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right),
userPath = UserPaths.rightHand
}
},
actions = new List<ActionConfig>()
{
// Grip
new ActionConfig()
{
name = "grip",
localizedName = "Grip",
type = ActionType.Axis1D,
usages = new List<string>()
{
"Grip"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = squeezeValue,
interactionProfileName = profile,
}
}
},
// Grip Pressed
new ActionConfig()
{
name = "gripPressed",
localizedName = "Grip Pressed",
type = ActionType.Binary,
usages = new List<string>()
{
"GripButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = squeezeClick,
interactionProfileName = profile,
}
}
},
//A / X Press
new ActionConfig()
{
name = "primaryButton",
localizedName = "Primary Button",
type = ActionType.Binary,
usages = new List<string>()
{
"PrimaryButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonX,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonA,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
//A / X Touch
new ActionConfig()
{
name = "primaryTouched",
localizedName = "Primary Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"PrimaryTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonXTouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonATouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
//B / Y Press
new ActionConfig()
{
name = "secondaryButton",
localizedName = "Secondary Button",
type = ActionType.Binary,
usages = new List<string>()
{
"SecondaryButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonY,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonB,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
//B / Y Touch
new ActionConfig()
{
name = "secondaryTouched",
localizedName = "Secondary Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"SecondaryTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = buttonYTouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.leftHand }
},
new ActionBinding()
{
interactionPath = buttonBTouch,
interactionProfileName = profile,
userPaths = new List<string>() { UserPaths.rightHand }
},
}
},
// Menu
new ActionConfig()
{
name = "menu",
localizedName = "Menu",
type = ActionType.Binary,
usages = new List<string>()
{
"Menu"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = menu,
interactionProfileName = profile,
}
}
},
// System
new ActionConfig()
{
name = "system",
localizedName = "system",
type = ActionType.Binary,
usages = new List<string>()
{
"System"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = system,
interactionProfileName = profile,
}
}
},
// Trigger
new ActionConfig()
{
name = "trigger",
localizedName = "Trigger",
type = ActionType.Axis1D,
usages = new List<string>()
{
"Trigger"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = trigger,
interactionProfileName = profile,
}
}
},
// Trigger Pressed
new ActionConfig()
{
name = "triggerPressed",
localizedName = "Trigger Pressed",
type = ActionType.Binary,
usages = new List<string>()
{
"TriggerButton"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = triggerClick,
interactionProfileName = profile,
}
}
},
//Trigger Touch
new ActionConfig()
{
name = "triggerTouched",
localizedName = "Trigger Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"TriggerTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = triggerTouch,
interactionProfileName = profile,
}
}
},
// Joystick
new ActionConfig()
{
name = "thumbstick",
localizedName = "Thumbstick",
type = ActionType.Axis2D,
usages = new List<string>()
{
"Primary2DAxis"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstick,
interactionProfileName = profile,
}
}
},
//Thumbstick Clicked
new ActionConfig()
{
name = "thumbstickClicked",
localizedName = "Thumbstick Clicked",
type = ActionType.Binary,
usages = new List<string>()
{
"Primary2DAxisClick"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstickClick,
interactionProfileName = profile,
}
}
},
//Thumbstick Touched
new ActionConfig()
{
name = "thumbstickTouched",
localizedName = "Thumbstick Touched",
type = ActionType.Binary,
usages = new List<string>()
{
"Primary2DAxisTouch"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = thumbstickTouch,
interactionProfileName = profile,
}
}
},
// Device Pose
new ActionConfig()
{
name = "devicePose",
localizedName = "Device Pose",
type = ActionType.Pose,
usages = new List<string>()
{
"Device"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = grip,
interactionProfileName = profile,
}
}
},
// Pointer Pose
new ActionConfig()
{
name = "pointer",
localizedName = "Pointer Pose",
type = ActionType.Pose,
usages = new List<string>()
{
"Pointer"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = aim,
interactionProfileName = profile,
}
}
},
new ActionConfig()
{
name = "batteryLevel",
localizedName = "BatteryLevel",
type = ActionType.Axis1D,
usages = new List<string>()
{
"BatteryLevel"
},
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = batteryLevel,
interactionProfileName = profile,
}
}
},
// Haptics
new ActionConfig()
{
name = "haptic",
localizedName = "Haptic Output",
type = ActionType.Vibrate,
usages = new List<string>() { "Haptic" },
bindings = new List<ActionBinding>()
{
new ActionBinding()
{
interactionPath = haptic,
interactionProfileName = profile,
}
}
}
}
};
AddActionMap(actionMap);
}
protected override string GetDeviceLayoutName()
{
return nameof(PICONeo3Controller);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,352 @@
#if PICO_OPENXR_SDK
using System.Collections.Generic;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using Object = System.Object;
using UnityEngine.XR.OpenXR.Features.Interactions;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using AOT;
using Unity.XR.PXR;
using UnityEngine.XR;
#if UNITY_EDITOR
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEditor;
using UnityEditor.XR.OpenXR.Features;
#endif
#if AR_FOUNDATION_5||AR_FOUNDATION_6
using UnityEngine.XR.ARSubsystems;
#endif
namespace Unity.XR.OpenXR.Features.PICOSupport
{
#if UNITY_EDITOR
public class ExtensionsConfig
{
public const string OpenXrExtensionList = "XR_FB_composition_layer_alpha_blend " +
"XR_FB_triangle_mesh " +
"XR_KHR_composition_layer_color_scale_bias " +
"XR_KHR_composition_layer_cylinder " +
"XR_KHR_composition_layer_equirect2 " +
"XR_KHR_composition_layer_cube " +
"XR_BD_composition_layer_eac " +
"XR_BD_composition_layer_fisheye " +
"XR_BD_composition_layer_blurred_quad " +
"XR_KHR_android_surface_swapchain " +
"XR_BD_composition_layer_color_matrix " +
"XR_BD_composition_layer_settings " +
"XR_KHR_composition_layer_depth ";
}
[OpenXRFeature(UiName = "PICO OpenXR Features",
Desc = "PICO XR Features for OpenXR.",
Company = "PICO",
Priority = 100,
Version = PXR_Constants.SDKVersion,
BuildTargetGroups = new[] { BuildTargetGroup.Android },
OpenxrExtensionStrings = ExtensionsConfig.OpenXrExtensionList,
FeatureId = featureId
)]
#endif
public class OpenXRExtensions : OpenXRFeature
{
public const string featureId = "com.unity.openxr.pico.features";
public const string PXR_PLATFORM_DLL = "PxrPlatform";
private static ulong xrInstance = 0ul;
private static ulong xrSession = 0ul;
public static event Action<ulong> SenseDataUpdated;
public static event Action SpatialAnchorDataUpdated;
public static event Action SceneAnchorDataUpdated;
public static event Action<PxrEventSenseDataProviderStateChanged> SenseDataProviderStateChanged;
public static event Action<List<PxrSpatialMeshInfo>> SpatialMeshDataUpdated;
static bool isCoroutineRunning = false;
protected override bool OnInstanceCreate(ulong instance)
{
Debug.Log($"[PICOOpenXRExtensions] OnInstanceCreate: {instance}");
xrInstance = instance;
xrSession = 0ul;
PICO_OnInstanceCreate(instance);
return true;
}
protected override void OnSessionCreate(ulong xrSessionId)
{
Debug.Log($"[PICOOpenXRExtensions] OnSessionCreate: {xrSessionId}");
xrSession = xrSessionId;
PICO_OnSessionCreate(xrSessionId);
PXR_Plugin.System.UPxr_SetXrEventDataBufferCallBack(XrEventDataBufferFunction);
}
public static int GetReferenceSpaceBoundsRect(XrReferenceSpaceType referenceSpace, ref XrExtent2Df extent2D)
{
return PICO_xrGetReferenceSpaceBoundsRect(
xrSession, referenceSpace, ref extent2D);
}
public static XrReferenceSpaceType[] EnumerateReferenceSpaces()
{
UInt32 Output = 0;
XrReferenceSpaceType[] outSpaces = null;
PICO_xrEnumerateReferenceSpaces(xrSession, 0, ref Output, outSpaces);
if (Output <= 0)
{
return null;
}
outSpaces = new XrReferenceSpaceType[Output];
PICO_xrEnumerateReferenceSpaces(xrSession, Output, ref Output, outSpaces);
return outSpaces;
}
[MonoPInvokeCallback(typeof(XrEventDataBufferCallBack))]
static void XrEventDataBufferFunction(ref XrEventDataBuffer eventDB)
{
int status, action;
Debug.Log($"XrEventDataBufferFunction eventType={eventDB.type}");
switch (eventDB.type)
{
case XrStructureType.XR_TYPE_EVENT_DATA_SENSE_DATA_PROVIDER_STATE_CHANGED:
{
if (SenseDataProviderStateChanged != null)
{
PxrEventSenseDataProviderStateChanged data = new PxrEventSenseDataProviderStateChanged()
{
providerHandle = BitConverter.ToUInt64(eventDB.data, 0),
newState = (PxrSenseDataProviderState)BitConverter.ToInt32(eventDB.data, 8),
};
SenseDataProviderStateChanged(data);
}
break;
}
case XrStructureType.XR_TYPE_EVENT_KEY_EVENT:
{
if (PXR_Plugin.System.RecenterSuccess != null)
{
PXR_Plugin.System.RecenterSuccess();
}
break;
}
case XrStructureType.XR_TYPE_EVENT_DATA_SENSE_DATA_UPDATED:
{
ulong providerHandle = BitConverter.ToUInt64(eventDB.data, 0);
PLog.i("EventDataFunction",$"providerHandle ={providerHandle}");
if (SenseDataUpdated != null)
{
SenseDataUpdated(providerHandle);
}
if (providerHandle == PXR_Plugin.MixedReality.UPxr_GetSenseDataProviderHandle(PxrSenseDataProviderType.SpatialAnchor))
{
if (SpatialAnchorDataUpdated != null)
{
SpatialAnchorDataUpdated();
}
}
if (providerHandle == PXR_Plugin.MixedReality.UPxr_GetSenseDataProviderHandle(PxrSenseDataProviderType.SceneCapture))
{
if (SceneAnchorDataUpdated != null)
{
SceneAnchorDataUpdated();
}
}
if (providerHandle == PXR_Plugin.MixedReality.UPxr_GetSpatialMeshProviderHandle())
{
if (!isCoroutineRunning)
{
QuerySpatialMeshAnchor();
}
}
break;
}
}
}
static async void QuerySpatialMeshAnchor()
{
isCoroutineRunning = true;
var task = await PXR_MixedReality.QueryMeshAnchorAsync();
isCoroutineRunning = false;
var (result, meshInfos) = task;
for (int i = 0; i < meshInfos.Count; i++)
{
switch (meshInfos[i].state)
{
case MeshChangeState.Added:
case MeshChangeState.Updated:
{
PXR_Plugin.MixedReality.UPxr_AddOrUpdateMesh(meshInfos[i]);
}
break;
case MeshChangeState.Removed:
{
PXR_Plugin.MixedReality.UPxr_RemoveMesh(meshInfos[i].uuid);
}
break;
case MeshChangeState.Unchanged:
{
break;
}
}
}
if (result == PxrResult.SUCCESS)
{
SpatialMeshDataUpdated?.Invoke(meshInfos);
}
}
protected override void OnInstanceDestroy(ulong xrInstance)
{
Debug.Log($"[PICOOpenXRExtensions] OnInstanceDestroy: {xrInstance}");
base.OnInstanceDestroy(xrInstance);
xrInstance = 0ul;
PICO_OnInstanceDestroy(xrInstance);
}
protected override IntPtr HookGetInstanceProcAddr(IntPtr func)
{
Debug.Log($"[PICOOpenXRExtensions] HookGetInstanceProcAddr: {func}");
return PICO_HookCreateInstance(func);
}
protected override void OnAppSpaceChange(ulong xrSpace)
{
Debug.Log($"[PICOOpenXRExtensions] OnAppSpaceChange: {xrSpace}");
PICO_OnAppSpaceChange(xrSpace);
}
protected override void OnSystemChange(ulong xrSystem)
{
Debug.Log($"[PICOOpenXRExtensions] OnSystemChange: {xrSystem}");
PICO_OnSystemChange(xrSystem);
}
protected override void OnSessionStateChange(int oldState, int newState)
{
Debug.Log($"[PICOOpenXRExtensions] OnSessionStateChange: {oldState} -> {newState}");
}
protected override void OnSessionBegin(ulong xrSessionId)
{
Debug.Log($"[PICOOpenXRExtensions] OnSessionBegin: {xrSessionId}");
}
protected override void OnSessionEnd(ulong xrSessionId)
{
Debug.Log($"[PICOOpenXRExtensions] OnSessionEnd: {xrSessionId}");
}
protected override void OnSessionExiting(ulong xrSessionId)
{
Debug.Log($"[PICOOpenXRExtensions] OnSessionExiting: {xrSessionId}");
}
protected override void OnSessionDestroy(ulong xrSessionId)
{
Debug.Log($"[PICOOpenXRExtensions] OnSessionDestroy: {xrSessionId}");
xrSession = 0ul;
PICO_OnSessionDestroy(xrSessionId);
}
public static float GetLocationHeight()
{
float height = 0;
PICO_GetLocationHeight( ref height);
return height;
}
#if AR_FOUNDATION_5||AR_FOUNDATION_6
public bool isSessionSubsystem=false;
private static List<XRSessionSubsystemDescriptor> sessionSubsystemDescriptors = new List<XRSessionSubsystemDescriptor>();
protected override void OnSubsystemCreate()
{
base.OnSubsystemCreate();
if (isSessionSubsystem)
{
CreateSubsystem<XRSessionSubsystemDescriptor, XRSessionSubsystem>(sessionSubsystemDescriptors, PXR_SessionSubsystem.k_SubsystemId);
}
}
protected override void OnSubsystemStart()
{
if (isSessionSubsystem)
{
StartSubsystem<XRSessionSubsystem>();
}
}
protected override void OnSubsystemStop()
{
if (isSessionSubsystem)
{
StopSubsystem<XRSessionSubsystem>();
}
}
protected override void OnSubsystemDestroy()
{
if (isSessionSubsystem)
{
DestroySubsystem<XRSessionSubsystem>();
}
}
#endif
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr PICO_HookCreateInstance(IntPtr func);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnInstanceCreate(UInt64 xrInstance);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnInstanceDestroy(UInt64 xrInstance);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnSessionCreate(UInt64 xrSession);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnAppSpaceChange(UInt64 xrSpace);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnSessionStateChange(int oldState, int newState);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnSessionBegin(UInt64 xrSession);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnSessionEnd(UInt64 xrSession);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnSessionExiting(UInt64 xrSession);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnSessionDestroy(UInt64 xrSession);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void PICO_OnSystemChange(UInt64 xrSystemId);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int PICO_xrEnumerateReferenceSpaces(ulong xrSession, UInt32 CountInput, ref UInt32 CountOutput,
XrReferenceSpaceType[] Spaces);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int PICO_xrGetReferenceSpaceBoundsRect(ulong xrSession, XrReferenceSpaceType referenceSpace,
ref XrExtent2Df extent2D);
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, EntryPoint = "PICO_SetMarkMode", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetMarkMode();
[DllImport(PXR_Plugin.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
private static extern int PICO_GetLocationHeight(ref float delaY);
}
}
#endif

View File

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

View File

@@ -0,0 +1,129 @@
#if PICO_OPENXR_SDK
using System.Collections.Generic;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using Object = System.Object;
using UnityEngine.XR.OpenXR.Features.Interactions;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using AOT;
using Unity.XR.PXR;
#if UNITY_EDITOR
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEditor;
using UnityEditor.XR.OpenXR.Features;
#endif
#if AR_FOUNDATION_5||AR_FOUNDATION_6
using UnityEngine.XR.ARSubsystems;
#endif
namespace Unity.XR.OpenXR.Features.PICOSupport
{
#if UNITY_EDITOR
[OpenXRFeature(UiName = "PICO XR Support",
Desc = "Necessary to deploy an PICO compatible app.",
Company = "PICO",
Version = PXR_Constants.SDKVersion,
BuildTargetGroups = new[] { BuildTargetGroup.Android },
CustomRuntimeLoaderBuildTargets = new[] { BuildTarget.Android },
OpenxrExtensionStrings = OpenXrExtensionList,
FeatureId = featureId
)]
#endif
public class PICOFeature : OpenXRFeature
{
/// <summary>
/// The feature id string. This is used to give the feature a well known id for reference.
/// </summary>
public const string featureId = "com.unity.openxr.feature.pico";
public const string OpenXrExtensionList = "XR_PICO_controller_interaction "+"XR_PICO_view_state";
public bool isPicoSupport = false;
public static Action<bool> onAppFocusedAction;
protected override void OnSessionStateChange(int oldState, int newState)
{
Debug.Log($"[PICOOpenXRExtensions] OnSessionStateChange: {oldState} -> {newState}");
if (onAppFocusedAction != null)
{
onAppFocusedAction(newState == 5);
}
}
#if UNITY_EDITOR
protected override void GetValidationChecks(List<ValidationRule> rules, BuildTargetGroup targetGroup)
{
OpenXRSettings settings = OpenXRSettings.GetSettingsForBuildTargetGroup(BuildTargetGroup.Android);
var AdditionalRules = new ValidationRule[]
{
new ValidationRule(this)
{
message = "Only the PICO Touch Interaction Profile is supported right now.",
checkPredicate = () =>
{
if (null == settings)
return false;
bool touchFeatureEnabled = false;
bool otherInteractionFeatureEnabled = false;
foreach (var feature in settings.GetFeatures<OpenXRInteractionFeature>())
{
if (feature.enabled)
{
if ((feature is PICONeo3ControllerProfile) ||
(feature is PICO4UltraControllerProfile) || (feature is PICO4ControllerProfile) ||
(feature is EyeGazeInteraction) || (feature is HandInteractionProfile) ||
(feature is PalmPoseInteraction) || (feature is PICOG3ControllerProfile))
touchFeatureEnabled = true;
else
otherInteractionFeatureEnabled = true;
}
}
return touchFeatureEnabled && !otherInteractionFeatureEnabled;
},
fixIt = () =>
{
if (null == settings)
return;
foreach (var feature in settings.GetFeatures<OpenXRInteractionFeature>())
{
feature.enabled = ((feature is PICO4UltraControllerProfile) || (feature is PICO4ControllerProfile));
}
},
error = true,
}
};
rules.AddRange(AdditionalRules);
}
internal class PICOFeatureEditorWindow : EditorWindow
{
private Object feature;
private Editor featureEditor;
public static EditorWindow Create(Object feature)
{
var window = EditorWindow.GetWindow<PICOFeatureEditorWindow>(true, "PICO Feature Configuration", true);
window.feature = feature;
window.featureEditor = Editor.CreateEditor((UnityEngine.Object)feature);
return window;
}
private void OnGUI()
{
featureEditor.OnInspectorGUI();
}
}
#endif
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f9b76292af5e4e389c642703b656f3b6
timeCreated: 1737536725