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,10 @@
fileFormatVersion: 2
guid: 0e81046a8890fab4e90491fbd3317812
folderAsset: yes
timeCreated: 1604287454
licenseType: Free
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,97 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
namespace Unity.XR.PXR
{
public class PXR_ControllerAnimator : MonoBehaviour
{
private Animator controllerAnimator;
public Transform primary2DAxisTran;
public Transform gripTran;
public Transform triggerTran;
public PXR_Input.Controller controller;
private InputDevice currentController;
private Vector2 axis2D = Vector2.zero;
private bool primaryButton;
private bool secondaryButton;
private bool menuButton;
private float grip;
private float trigger;
private Vector3 originalGrip;
private Vector3 originalTrigger;
private Vector3 originalJoystick;
public const string primary = "IsPrimaryDown";
public const string secondary = "IsSecondaryDown";
public const string media = "IsMediaDown";
public const string menu = "IsMenuDown";
void Start()
{
controllerAnimator = GetComponent<Animator>();
currentController = InputDevices.GetDeviceAtXRNode(controller == PXR_Input.Controller.LeftController
? XRNode.LeftHand
: XRNode.RightHand);
originalGrip = gripTran.localEulerAngles;
originalJoystick = primary2DAxisTran.localEulerAngles;
originalTrigger = triggerTran.localEulerAngles;
}
void Update()
{
currentController.TryGetFeatureValue(CommonUsages.primary2DAxis, out axis2D);
currentController.TryGetFeatureValue(CommonUsages.grip, out grip);
currentController.TryGetFeatureValue(CommonUsages.trigger, out trigger);
currentController.TryGetFeatureValue(CommonUsages.primaryButton, out primaryButton);
currentController.TryGetFeatureValue(CommonUsages.secondaryButton, out secondaryButton);
currentController.TryGetFeatureValue(CommonUsages.menuButton, out menuButton);
float x = Mathf.Clamp(axis2D.x * 10f, -10f, 10f);
float z = Mathf.Clamp(axis2D.y * 10f, -10f, 10f);
if (primary2DAxisTran != null)
{
if (controller == PXR_Input.Controller.LeftController)
{
primary2DAxisTran.localEulerAngles = new Vector3(-z, 0, x) + originalJoystick;
}
else
{
primary2DAxisTran.localEulerAngles = new Vector3(-z, 0, -x) + originalJoystick;
}
}
trigger *= -15;
if (triggerTran != null)
triggerTran.localEulerAngles = new Vector3(trigger, 0f, 0f) + originalTrigger;
grip *= 12;
if (gripTran != null)
gripTran.localEulerAngles = new Vector3(0f, grip, 0f) + originalGrip;
if (controllerAnimator != null)
{
controllerAnimator.SetBool(primary, primaryButton);
controllerAnimator.SetBool(secondary, secondaryButton);
if (controller == PXR_Input.Controller.LeftController)
controllerAnimator.SetBool(menu, menuButton);
else if(controller == PXR_Input.Controller.RightController)
controllerAnimator.SetBool(media, menuButton);
}
}
}
}

View File

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

View File

@@ -0,0 +1,78 @@
/*******************************************************************************
Copyright ? 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using UnityEngine;
using UnityEngine.XR;
namespace Unity.XR.PXR
{
public class PXR_ControllerG3Animator : MonoBehaviour
{
public Transform triggerTran;
public Transform menuTran;
public Transform touchPadTran;
public PXR_ControllerPower controllerPower;
private bool primaryAxisState = false;
private bool menuButtonState;
private float trigger;
private Vector3 menu;
private Vector3 originTrigger;
private Vector3 touchPadPos;
private InputDevice currentController;
private int handness;
void Start()
{
PXR_Plugin.Controller.UPxr_GetControllerHandness(ref handness);
XRNode hand = handness == 0? XRNode.RightHand : XRNode.LeftHand;
if (controllerPower != null)
{
controllerPower.hand = handness == 0 ? PXR_Input.Controller.RightController : PXR_Input.Controller.LeftController;
}
currentController = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
menu = menuTran.localPosition;
originTrigger = triggerTran.localEulerAngles;
touchPadPos = touchPadTran.localPosition;
}
void Update()
{
currentController.TryGetFeatureValue(CommonUsages.primary2DAxisClick, out primaryAxisState);
currentController.TryGetFeatureValue(CommonUsages.menuButton, out menuButtonState);
currentController.TryGetFeatureValue(CommonUsages.trigger, out trigger);
if (triggerTran != null)
{
trigger *= -9.0f;
triggerTran.localEulerAngles = new Vector3(0f, 0f, Mathf.Clamp(trigger, -9f, 0f)) + originTrigger;
}
if (touchPadTran != null)
{
if (primaryAxisState)
touchPadTran.localPosition = touchPadPos + new Vector3(0f, -0.0005f, 0f);
else
touchPadTran.localPosition = touchPadPos;
}
if (menuButtonState)
menuTran.localPosition = new Vector3(0f, -0.00021f, 0f) + menu;
else
menuTran.localPosition = menu;
}
}
}

View File

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

View File

@@ -0,0 +1,339 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.Collections;
using System.IO;
using LitJson;
using UnityEngine;
using UnityEngine.Rendering;
namespace Unity.XR.PXR
{
public class PXR_ControllerLoader : MonoBehaviour
{
[SerializeField]
private PXR_Input.Controller hand;
public GameObject neo3L;
public GameObject neo3R;
public GameObject PICO_4L;
public GameObject PICO_4R;
public GameObject G3;
public GameObject PICO_4U_L;
public GameObject PICO_4U_R;
public Material legacyMaterial;
private Texture2D modelTexture2D;
private int controllerType = -1;
private JsonData curControllerData = null;
private int systemOrLocal = 0;
private bool loadModelSuccess = false;
private string modelName = "";
private string texFormat = "";
private string prePath = "";
private string modelFilePath = "/system/media/pxrRes/controller/";
private bool leftControllerState = false;
private bool rightControllerState = false;
private enum ControllerSimulationType
{
None,
Neo3,
PICO4,
G3,
PICO4U
}
#if UNITY_EDITOR
[SerializeField]
private ControllerSimulationType controllerSimulation = ControllerSimulationType.None;
#endif
public PXR_ControllerLoader(PXR_Input.Controller controller)
{
hand = controller;
}
void Awake()
{
#if UNITY_EDITOR
switch (controllerSimulation)
{
case ControllerSimulationType.Neo3:
{
Instantiate(hand == PXR_Input.Controller.LeftController ? neo3L : neo3R, transform, false);
break;
}
case ControllerSimulationType.PICO4:
{
Instantiate(hand == PXR_Input.Controller.LeftController ? PICO_4L : PICO_4R, transform, false);
break;
}
case ControllerSimulationType.G3:
{
Instantiate(G3, transform, false);
break;
}
case ControllerSimulationType.PICO4U:
{
Instantiate(hand == PXR_Input.Controller.LeftController ? PICO_4U_L : PICO_4U_R, transform, false);
break;
}
}
#endif
}
void Start()
{
controllerType = PXR_Plugin.Controller.UPxr_GetControllerType();
#if UNITY_ANDROID && !UNITY_EDITOR
LoadResFromJson();
#endif
leftControllerState = PXR_Plugin.Controller.UPxr_IsControllerConnected(PXR_Input.Controller.LeftController);
rightControllerState = PXR_Plugin.Controller.UPxr_IsControllerConnected(PXR_Input.Controller.RightController);
if (hand == PXR_Input.Controller.LeftController)
RefreshController(PXR_Input.Controller.LeftController);
if (hand == PXR_Input.Controller.RightController)
RefreshController(PXR_Input.Controller.RightController);
}
void Update()
{
if (hand == PXR_Input.Controller.LeftController)
{
if (PXR_Plugin.Controller.UPxr_IsControllerConnected(PXR_Input.Controller.LeftController))
{
if (!leftControllerState)
{
controllerType = PXR_Plugin.Controller.UPxr_GetControllerType();
RefreshController(PXR_Input.Controller.LeftController);
leftControllerState = true;
}
}
else
{
if (leftControllerState)
{
DestroyLocalController();
leftControllerState = false;
}
}
}
if (hand == PXR_Input.Controller.RightController)
{
if (PXR_Plugin.Controller.UPxr_IsControllerConnected(PXR_Input.Controller.RightController))
{
if (!rightControllerState)
{
controllerType = PXR_Plugin.Controller.UPxr_GetControllerType();
RefreshController(PXR_Input.Controller.RightController);
rightControllerState = true;
}
}
else
{
if (rightControllerState)
{
DestroyLocalController();
rightControllerState = false;
}
}
}
}
private void RefreshController(PXR_Input.Controller hand)
{
if (PXR_Plugin.Controller.UPxr_IsControllerConnected(hand))
{
if (systemOrLocal == 0)
{
LoadControllerFromPrefab(hand);
if (!loadModelSuccess)
{
LoadControllerFromSystem((int)hand);
}
}
else
{
var isControllerExist = false;
foreach (Transform t in transform)
{
if (t.name == modelName)
{
isControllerExist = true;
}
}
if (!isControllerExist)
{
LoadControllerFromSystem((int)hand);
if (!loadModelSuccess)
{
LoadControllerFromPrefab(hand);
}
}
else
{
var currentController = transform.Find(modelName);
currentController.gameObject.SetActive(true);
}
}
}
}
private void LoadResFromJson()
{
string json = PXR_Plugin.System.UPxr_GetObjectOrArray("config.controller", (int)ResUtilsType.TypeObjectArray);
if (json != null)
{
JsonData jdata = JsonMapper.ToObject(json);
if (controllerType > 0)
{
if (jdata.Count >= controllerType)
{
curControllerData = jdata[controllerType - 1];
if (curControllerData != null)
{
modelFilePath = (string)curControllerData["base_path"];
modelName = (string)curControllerData["model_name"] + "_sys";
}
}
}
}
else
{
Debug.LogError("PXRLog LoadJsonFromSystem Error");
}
}
private void DestroyLocalController()
{
foreach (Transform t in transform)
{
Destroy(modelTexture2D);
Destroy(t.gameObject);
Resources.UnloadUnusedAssets();
loadModelSuccess = false;
}
}
private void LoadControllerFromPrefab(PXR_Input.Controller hand)
{
#if UNITY_6000_0_OR_NEWER && !URP
if (GraphicsDeviceType.OpenGLES3 == SystemInfo.graphicsDeviceType && QualitySettings.activeColorSpace == ColorSpace.Linear
&& PXR_Settings.GetSettings().stereoRenderingModeAndroid == PXR_Settings.StereoRenderingModeAndroid.Multiview)
{
loadModelSuccess = false;
return;
}
#endif
switch (controllerType)
{
case 5:
Instantiate(hand == PXR_Input.Controller.LeftController ? neo3L : neo3R, transform, false);
loadModelSuccess = true;
break;
case 6:
Instantiate(hand == PXR_Input.Controller.LeftController ? PICO_4L : PICO_4R, transform, false);
loadModelSuccess = true;
break;
case 7:
Instantiate(G3, transform, false);
loadModelSuccess = true;
break;
case 8:
Instantiate(hand == PXR_Input.Controller.LeftController ? PICO_4U_L : PICO_4U_R, transform, false);
loadModelSuccess = true;
break;
default:
loadModelSuccess = false;
break;
}
}
private void LoadControllerFromSystem(int id)
{
var sysControllerName = controllerType.ToString() + id.ToString() + ".obj";
var fullFilePath = modelFilePath + sysControllerName;
if (!File.Exists(fullFilePath))
{
Debug.Log("PXRLog Load Obj From Prefab");
}
else
{
GameObject go = new GameObject
{
name = modelName
};
MeshFilter meshFilter = go.AddComponent<MeshFilter>();
meshFilter.mesh = PXR_ObjImporter.Instance.ImportFile(fullFilePath);
go.transform.SetParent(transform);
go.transform.localPosition = Vector3.zero;
MeshRenderer meshRenderer = go.AddComponent<MeshRenderer>();
meshRenderer.material = legacyMaterial;
LoadTexture(meshRenderer, controllerType.ToString() + id.ToString(), false);
go.transform.localRotation = Quaternion.Euler(new Vector3(0, 180, 0));
go.transform.localScale = new Vector3(-0.01f, 0.01f, 0.01f);
loadModelSuccess = true;
}
}
private void LoadTexture(MeshRenderer mr,string controllerName, bool fromRes)
{
if (fromRes)
{
texFormat = "";
prePath = controllerName;
}
else
{
texFormat = "." + (string)curControllerData["tex_format"];
prePath = modelFilePath + controllerName;
}
var texturePath = prePath + "_idle" + texFormat;
mr.material.SetTexture("_MainTex", LoadOneTexture(texturePath, fromRes));
}
private Texture2D LoadOneTexture(string filepath, bool fromRes)
{
if (fromRes)
{
return Resources.Load<Texture2D>(filepath);
}
else
{
int tW = (int)curControllerData["tex_width"];
int tH = (int)curControllerData["tex_height"];
modelTexture2D = new Texture2D(tW, tH);
modelTexture2D.LoadImage(ReadPNG(filepath));
return modelTexture2D;
}
}
private byte[] ReadPNG(string path)
{
FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
fileStream.Seek(0, SeekOrigin.Begin);
byte[] binary = new byte[fileStream.Length];
fileStream.Read(binary, 0, (int)fileStream.Length);
fileStream.Close();
fileStream.Dispose();
return binary;
}
}
}

View File

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

View File

@@ -0,0 +1,128 @@
/*******************************************************************************
Copyright ? 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.Collections;
using System.Collections.Generic;
using Unity.XR.PXR;
using UnityEngine;
using UnityEngine.XR;
public class PXR_ControllerPower : MonoBehaviour
{
[SerializeField]
private Texture power1;
[SerializeField]
private Texture power2;
[SerializeField]
private Texture power3;
[SerializeField]
private Texture power4;
[SerializeField]
private Texture power5;
private Material powerMaterial;
private float interval = 2f;
public PXR_Input.Controller hand;
// Start is called before the first frame update
void Awake()
{
if (GetComponent<MeshRenderer>() != null)
{
powerMaterial = GetComponent<MeshRenderer>().material;
}
else
{
powerMaterial = GetComponent<SkinnedMeshRenderer>().material;
}
}
void OnEnable()
{
RefreshPower();
}
private void RefreshPower()
{
var curBattery = 0f;
switch (hand)
{
case PXR_Input.Controller.LeftController:
{
InputDevices.GetDeviceAtXRNode(XRNode.LeftHand).TryGetFeatureValue(CommonUsages.batteryLevel, out curBattery);
}
break;
case PXR_Input.Controller.RightController:
{
InputDevices.GetDeviceAtXRNode(XRNode.RightHand).TryGetFeatureValue(CommonUsages.batteryLevel, out curBattery);
}
break;
}
switch ((int)curBattery)
{
case 1:
{
powerMaterial.SetTexture("_MainTex", power1);
powerMaterial.SetTexture("_EmissionMap", power1);
}
break;
case 2:
{
powerMaterial.SetTexture("_MainTex", power2);
powerMaterial.SetTexture("_EmissionMap", power2);
}
break;
case 3:
{
powerMaterial.SetTexture("_MainTex", power3);
powerMaterial.SetTexture("_EmissionMap", power3);
}
break;
case 4:
{
powerMaterial.SetTexture("_MainTex", power4);
powerMaterial.SetTexture("_EmissionMap", power4);
}
break;
case 5:
{
powerMaterial.SetTexture("_MainTex", power5);
powerMaterial.SetTexture("_EmissionMap", power5);
}
break;
default:
{
powerMaterial.SetTexture("_MainTex", power1);
powerMaterial.SetTexture("_EmissionMap", power1);
}
break;
}
}
// Update is called once per frame
void Update()
{
interval -= Time.deltaTime;
if (interval > 0)
return;
interval = 2f;
RefreshPower();
}
}

View File

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

View File

@@ -0,0 +1,307 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using Unity.XR.PXR.Input;
namespace Unity.XR.PXR
{
public class PXR_ControllerWithHandAnimator : MonoBehaviour
{
public PXR_Input.Controller controller;
private Animator mAnimator;
private InputDevice mInputDevice;
private PXR_Controller mXRController;
private readonly float animation_time = 0.05f;
private float per_animation_step = 0.1f;
//trigger;
private readonly string trigger_Touch_LayerName = "trigger_touch";
private int trigger_Touch_LayerIndex;
private readonly string trigger_Value_LayerName = "trigger_press";
private int trigger_Value_LayerIndex;
private bool trigger_Touch;
private float trigger_Value;
private float trigger_Touch_Weight = 0f;
// A/X;
private readonly string X_A_Touch_LayerName = "X_A_touch";
private int X_A_Touch_LayerIndex;
private readonly string X_A_Press_LayerName = "X_A_press";
private int X_A_Press_LayerIndex;
private bool X_A_Press;
private bool X_A_Touch;
private float X_A_Touch_Weight = 0f;
// B/Y;
private readonly string Y_B_Touch_LayerName = "Y_B_touch";
private int Y_B_Touch_LayerIndex;
private readonly string Y_B_Press_LayerName = "Y_B_press";
private int Y_B_Press_LayerIndex;
private bool Y_B_Press;
private bool Y_B_Touch;
private float Y_B_Touch_Weight = 0f;
//Y/B or X/A
private readonly string X_A_Y_B_Press_LayerName = "X_A_Y_B_press";
private int X_A_Y_B_Press_LayerIndex;
//Y/B or X/A
private readonly string X_A_Y_B_Touch_LayerName = "X_A_Y_B_touch";
private int X_A_Y_B_Touch_LayerIndex;
private float X_A_Y_B_Touch_Weight = 0f;
//grip;
private readonly string grip_Value_LayerName = "grip_press";
private int grip_Value_LayerIndex;
private float grip_Value;
//rocker
private readonly string primary2DAxis_Touch_LayerName = "axis_touch";
private int primary2DAxis_Touch_LayerIndex;
private readonly string primary2DAxis_Vertical = "axis_vertical";
private int primary2DAxis_Vertical_Index;
private readonly string primary2DAxis_Horizontal = "axis_horizontal";
private int primary2DAxis_Horizontal_Index;
private Vector2 primary2DAxisVec2;
private bool primary2DAxis_Touch;
private float primary2DAxis_Touch_Weight = 0f;
//print screen
private readonly string menu_Press_LayerName = "thumbMenu";
private int menu_Press_LayerIndex;
private bool menu_Press;
private float menu_Press_Weight;
//home
private readonly string pico_Press_LayerName = "thumbPico";
private int pico_Press_LayerIndex;
private bool pico_Press;
private float pico_Press_Weight;
//thumb rest
private readonly string thumbstick_Touch_LayerName = "thumbstick_touch";
private int thumbstick_Touch_LayerIndex;
private bool thumbstick_Touch;
private float thumbstick_Touch_Weight;
// Start is called before the first frame update
void Start()
{
per_animation_step = 1.0f / animation_time;
mAnimator = GetComponent<Animator>();
mInputDevice = InputDevices.GetDeviceAtXRNode(controller == PXR_Input.Controller.LeftController ? XRNode.LeftHand : XRNode.RightHand);
mXRController = (controller == PXR_Input.Controller.LeftController ? PXR_Controller.leftHand : PXR_Controller.rightHand) as PXR_Controller;
if (mAnimator != null)
{
trigger_Touch_LayerIndex = mAnimator.GetLayerIndex(trigger_Touch_LayerName);
trigger_Value_LayerIndex = mAnimator.GetLayerIndex(trigger_Value_LayerName);
grip_Value_LayerIndex = mAnimator.GetLayerIndex(grip_Value_LayerName);
X_A_Touch_LayerIndex = mAnimator.GetLayerIndex(X_A_Touch_LayerName);
X_A_Press_LayerIndex = mAnimator.GetLayerIndex(X_A_Press_LayerName);
Y_B_Touch_LayerIndex = mAnimator.GetLayerIndex(Y_B_Touch_LayerName);
Y_B_Press_LayerIndex = mAnimator.GetLayerIndex(Y_B_Press_LayerName);
X_A_Y_B_Press_LayerIndex = mAnimator.GetLayerIndex(X_A_Y_B_Press_LayerName);
X_A_Y_B_Touch_LayerIndex = mAnimator.GetLayerIndex(X_A_Y_B_Touch_LayerName);
primary2DAxis_Touch_LayerIndex = mAnimator.GetLayerIndex(primary2DAxis_Touch_LayerName);
thumbstick_Touch_LayerIndex = mAnimator.GetLayerIndex(thumbstick_Touch_LayerName);
primary2DAxis_Vertical_Index = Animator.StringToHash(primary2DAxis_Vertical);
primary2DAxis_Horizontal_Index = Animator.StringToHash(primary2DAxis_Horizontal);
}
else
{
Debug.Log("Animator is null");
}
}
// Update is called once per frame
void Update()
{
mInputDevice.TryGetFeatureValue(CommonUsages.primaryButton, out X_A_Press);
mInputDevice.TryGetFeatureValue(CommonUsages.primaryTouch, out X_A_Touch);
mInputDevice.TryGetFeatureValue(CommonUsages.secondaryButton, out Y_B_Press);
mInputDevice.TryGetFeatureValue(CommonUsages.secondaryTouch, out Y_B_Touch);
mInputDevice.TryGetFeatureValue(CommonUsages.trigger, out trigger_Value);
mInputDevice.TryGetFeatureValue(PXR_Usages.triggerTouch, out trigger_Touch);
mInputDevice.TryGetFeatureValue(CommonUsages.grip, out grip_Value);
mInputDevice.TryGetFeatureValue(CommonUsages.primary2DAxis, out primary2DAxisVec2);
mInputDevice.TryGetFeatureValue(CommonUsages.primary2DAxisTouch, out primary2DAxis_Touch);
if (!primary2DAxis_Touch)
{
if (primary2DAxisVec2 != Vector2.zero)
primary2DAxis_Touch = true;
}
mInputDevice.TryGetFeatureValue(CommonUsages.menuButton, out menu_Press);
if (Y_B_Touch && primary2DAxisVec2 == Vector2.zero)
{
if (Y_B_Press)
{
Y_B_Touch_Weight = 1.0f;
mAnimator.SetLayerWeight(Y_B_Touch_LayerIndex, Y_B_Touch_Weight);
mAnimator.SetLayerWeight(Y_B_Press_LayerIndex, 1.0f);
mAnimator.SetLayerWeight(X_A_Y_B_Press_LayerIndex, X_A_Press ? 1.0f : 0.0f);
}
else
{
if (X_A_Touch)
{
if (X_A_Press)
{
X_A_Touch_Weight = 1.0f;
mAnimator.SetLayerWeight(X_A_Touch_LayerIndex, X_A_Touch_Weight);
}
else
{
if (X_A_Y_B_Touch_Weight < 0.9999f)
{
X_A_Y_B_Touch_Weight = Mathf.Min(mAnimator.GetLayerWeight(X_A_Y_B_Touch_LayerIndex) + Time.deltaTime * per_animation_step, 1.0f);
mAnimator.SetLayerWeight(X_A_Y_B_Touch_LayerIndex, X_A_Y_B_Touch_Weight);
}
}
mAnimator.SetLayerWeight(X_A_Press_LayerIndex, X_A_Press ? 1.0f : 0f);
}
else
{
if (Y_B_Touch_Weight < 0.9999f)
{
Y_B_Touch_Weight = Mathf.Min(mAnimator.GetLayerWeight(Y_B_Touch_LayerIndex) + Time.deltaTime * per_animation_step, 1.0f);
mAnimator.SetLayerWeight(Y_B_Touch_LayerIndex, Y_B_Touch_Weight);
}
if (X_A_Y_B_Touch_Weight > 0.0001f)
{
X_A_Y_B_Touch_Weight = Mathf.Max(mAnimator.GetLayerWeight(X_A_Y_B_Touch_LayerIndex) - Time.deltaTime * per_animation_step, 0.0f);
mAnimator.SetLayerWeight(X_A_Y_B_Touch_LayerIndex, X_A_Y_B_Touch_Weight);
}
if (X_A_Touch_Weight > 0.0001f)
{
X_A_Touch_Weight = Mathf.Max(mAnimator.GetLayerWeight(X_A_Touch_LayerIndex) - Time.deltaTime * per_animation_step, 0.0f);
mAnimator.SetLayerWeight(X_A_Touch_LayerIndex, X_A_Touch_Weight);
}
}
mAnimator.SetLayerWeight(Y_B_Press_LayerIndex, 0.0f);
mAnimator.SetLayerWeight(X_A_Y_B_Press_LayerIndex, 0.0f);
}
}
else
{
if (Y_B_Touch_Weight > 0.0001f)
{
Y_B_Touch_Weight = Mathf.Max(mAnimator.GetLayerWeight(Y_B_Touch_LayerIndex) - Time.deltaTime * per_animation_step, 0.0f);
mAnimator.SetLayerWeight(Y_B_Touch_LayerIndex, Y_B_Touch_Weight);
mAnimator.SetLayerWeight(Y_B_Press_LayerIndex, 0.0f);
mAnimator.SetLayerWeight(X_A_Y_B_Press_LayerIndex, 0.0f);
}
if (X_A_Y_B_Touch_Weight > 0.0001f)
{
X_A_Y_B_Touch_Weight = Mathf.Max(mAnimator.GetLayerWeight(X_A_Y_B_Touch_LayerIndex) - Time.deltaTime * per_animation_step, 0.0f);
mAnimator.SetLayerWeight(X_A_Y_B_Touch_LayerIndex, X_A_Y_B_Touch_Weight);
mAnimator.SetLayerWeight(Y_B_Press_LayerIndex, 0.0f);
mAnimator.SetLayerWeight(X_A_Y_B_Press_LayerIndex, 0.0f);
}
if (X_A_Touch && primary2DAxisVec2 == Vector2.zero)
{
if (X_A_Press)
{
X_A_Touch_Weight = 1.0f;
mAnimator.SetLayerWeight(X_A_Touch_LayerIndex, X_A_Touch_Weight);
}
else
{
if (X_A_Touch_Weight < 0.9999f)
{
X_A_Touch_Weight = Mathf.Min(mAnimator.GetLayerWeight(X_A_Touch_LayerIndex) + Time.deltaTime * per_animation_step, 1.0f);
mAnimator.SetLayerWeight(X_A_Touch_LayerIndex, X_A_Touch_Weight);
}
}
mAnimator.SetLayerWeight(X_A_Press_LayerIndex, X_A_Press ? 1.0f : 0f);
mAnimator.SetFloat(primary2DAxis_Vertical_Index, 0f);
mAnimator.SetFloat(primary2DAxis_Horizontal_Index, 0f);
}
else
{
if (X_A_Touch_Weight > 0.0001f)
{
X_A_Touch_Weight = Mathf.Max(mAnimator.GetLayerWeight(X_A_Touch_LayerIndex) - Time.deltaTime * per_animation_step, 0.0f);
mAnimator.SetLayerWeight(X_A_Touch_LayerIndex, X_A_Touch_Weight);
mAnimator.SetLayerWeight(X_A_Press_LayerIndex, 0f);
}
if (primary2DAxis_Touch)
{
if (primary2DAxis_Touch_Weight < 0.9999f)
{
primary2DAxis_Touch_Weight = Mathf.Min(mAnimator.GetLayerWeight(primary2DAxis_Touch_LayerIndex) + Time.deltaTime * per_animation_step, 1.0f);
mAnimator.SetLayerWeight(primary2DAxis_Touch_LayerIndex, primary2DAxis_Touch_Weight);
}
mAnimator.SetFloat(primary2DAxis_Vertical_Index, primary2DAxisVec2.y);
mAnimator.SetFloat(primary2DAxis_Horizontal_Index, primary2DAxisVec2.x);
}
else
{
if (primary2DAxis_Touch_Weight > 0.0001f)
{
primary2DAxis_Touch_Weight = Mathf.Max(mAnimator.GetLayerWeight(primary2DAxis_Touch_LayerIndex) - Time.deltaTime * per_animation_step, 0.0f);
mAnimator.SetLayerWeight(primary2DAxis_Touch_LayerIndex, primary2DAxis_Touch_Weight);
mAnimator.SetFloat(primary2DAxis_Vertical_Index, 0f);
mAnimator.SetFloat(primary2DAxis_Horizontal_Index, 0f);
}
if (thumbstick_Touch)
{
if (thumbstick_Touch_Weight < 0.9999f)
{
thumbstick_Touch_Weight = Mathf.Min(mAnimator.GetLayerWeight(thumbstick_Touch_LayerIndex) + Time.deltaTime * per_animation_step, 1.0f);
mAnimator.SetLayerWeight(thumbstick_Touch_LayerIndex, thumbstick_Touch_Weight);
}
}
else
{
if (thumbstick_Touch_Weight > 0.0001f)
{
thumbstick_Touch_Weight = Mathf.Max(mAnimator.GetLayerWeight(thumbstick_Touch_LayerIndex) - Time.deltaTime * per_animation_step, 0.0f);
mAnimator.SetLayerWeight(thumbstick_Touch_LayerIndex, thumbstick_Touch_Weight);
}
}
}
}
}
if (trigger_Touch)
{
if (trigger_Touch_Weight < 0.9999f)
{
trigger_Touch_Weight = Mathf.Min(mAnimator.GetLayerWeight(trigger_Touch_LayerIndex) + Time.deltaTime * per_animation_step, 1.0f);
mAnimator.SetLayerWeight(trigger_Touch_LayerIndex, trigger_Touch_Weight);
}
mAnimator.SetLayerWeight(trigger_Value_LayerIndex, trigger_Value);
}
else
{
if (trigger_Touch_Weight > 0.0001f)
{
trigger_Touch_Weight = Mathf.Max(mAnimator.GetLayerWeight(trigger_Touch_LayerIndex) - Time.deltaTime * per_animation_step, 0.0f);
mAnimator.SetLayerWeight(trigger_Touch_LayerIndex, trigger_Touch_Weight);
}
}
mAnimator.SetLayerWeight(grip_Value_LayerIndex, grip_Value);
}
}
}

View File

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

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: ba33a065da87db540a48c95b1795a99f
folderAsset: yes
timeCreated: 1593498988
licenseType: Free
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,186 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using UnityEngine;
namespace Unity.XR.PXR
{
public class PXR_Boundary
{
/// <summary>
/// Sets the boundary as visible or invisible. Note: The setting defined in this function can be overridden by system settings (e.g., proximity trigger) or user settings (e.g., disabling the boundary system).
/// </summary>
/// <param name="value">Whether to set the boundary as visible or invisble:
/// - `true`: visible
/// - `false`: invisible</param>
public static void SetVisible(bool value)
{
PXR_Plugin.Boundary.UPxr_SetBoundaryVisiable(value);
}
/// <summary>
/// Gets whether the boundary is visible.
/// </summary>
/// <returns>
/// - `true`: visible
/// - `false`: invisible</returns>
public static bool GetVisible()
{
return PXR_Plugin.Boundary.UPxr_GetBoundaryVisiable();
}
/// <summary>
/// Checks whether the boundary is configured. Boundary-related functions are available for use only if the boundary is configured.
/// </summary>
/// <returns>
/// - `true`: configured
/// - `false`: not configured</returns>
public static bool GetConfigured()
{
return PXR_Plugin.Boundary.UPxr_GetBoundaryConfigured();
}
/// <summary>
/// Checks whether the boundary is enabled.
/// </summary>
/// <returns>
/// - `true`: enabled
/// - `false`: not enabled</returns>
public static bool GetEnabled()
{
return PXR_Plugin.Boundary.UPxr_GetBoundaryEnabled();
}
/// <summary>
/// Checks whether a tracked node (Left hand, Right hand, Head) will trigger the boundary.
/// </summary>
/// <param name="node">The node to track: HandLeft-left controller; HandRight-right controller; Head-HMD.</param>
/// <param name="boundaryType">The boundary type: `OuterBoundary`-boundary (custom boundary or in-site fast boundary); `PlayArea`-the maximum rectangle in the custom boundary (no such a rectangle in the in-site fast boundary).</param>
/// <returns>
/// A struct that contains the following details:
/// - `IsTriggering`: bool, whether the boundary is triggered;
/// - `ClosestDistance`: float, the minimum distance between the tracked node and the boundary;
/// - `ClosestPoint`: vector3, the closest point between the tracked node and the boundary;
/// - `ClosestPointNormal`: vector3, the normal line of the closest point;
/// - `valid`: bool, whether the result returned is valid.
/// </returns>
public static PxrBoundaryTriggerInfo TestNode(BoundaryTrackingNode node, BoundaryType boundaryType)
{
return PXR_Plugin.Boundary.UPxr_TestNodeIsInBoundary(node, boundaryType);
}
/// <summary>
/// Checks whether a tracked point will trigger the boundary.
/// </summary>
/// <param name="point">The coordinate of the point.</param>
/// <param name="boundaryType">The boundary type: `OuterBoundary`-boundary (custom boundary or in-site fast boundary); `PlayArea`-customize the maximum rectangle in the custom boundary (no such rectangle for in-site fast boundary).</param>
/// <returns>
/// A struct that contains the following details:
/// - `IsTriggering`: bool, whether the boundary is triggered;
/// - `ClosestDistance`: float, the minimum distance between the tracked node and the boundary;
/// - `ClosestPoint`: vector3, the closest point between the tracked node and the boundary;
/// - `ClosestPointNormal`: vector3, the normal line of the closest point;
/// - `valid`: bool, whether the result returned is valid.
/// </returns>
public static PxrBoundaryTriggerInfo TestPoint(PxrVector3f point, BoundaryType boundaryType)
{
return PXR_Plugin.Boundary.UPxr_TestPointIsInBoundary(point, boundaryType);
}
/// <summary>
/// Gets the collection of boundary points.
/// </summary>
/// <param name="boundaryType">The boundary type:
/// - `OuterBoundary`: custom boundary or in-site fast boundary.
/// - `PlayArea`: customize the maximum rectangle in the custom boundary (no such rectangle for in-site fast boundary).</param>
/// <returns>A collection of boundary points.
/// - If you pass `OuterBoundary`, the actual calibrated vertex array of the boundary will be returned.
/// - If you pass `PlayArea`, the boundary points array of the maximum rectangle within the calibrated play area will be returned. The boundary points array is calculated by the algorithm.
/// For stationary boundary, passing `PlayArea` returns nothing.
/// </returns>
public static Vector3[] GetGeometry(BoundaryType boundaryType)
{
return PXR_Plugin.Boundary.UPxr_GetBoundaryGeometry(boundaryType);
}
/// <summary>
/// Gets the size of the play area for the custom boundary.
/// </summary>
/// <param name="boundaryType">You can only pass `PlayArea` (customize the maximum rectangle in the custom boundary). **Note**: There is no such rectangle for stationary boundary.</param>
/// <returns>The lengths of the X and Z axis of the maximum rectangle within the custom calibrated play area. The lengths are calculated by the algorithm. The length of the Y axis is always 1.
/// If the current user calibrates the stationary boundary, (0,1,0) will be returned.
/// </returns>
public static Vector3 GetDimensions(BoundaryType boundaryType)
{
return PXR_Plugin.Boundary.UPxr_GetBoundaryDimensions(boundaryType);
}
/// <summary>
/// Gets the camera image of the device and use it as the environmental background. Before calling this function, make sure you have set the clear flags of the camera to solid color and have set the background color of the camera to 0 for the alpha channel.
/// @note If the app is paused, this function will cease. Therefore, you need to call this function again after the app has been resumed.
/// </summary>
/// <param name="value">Whether to enable SeeThrough: `true`-enable; `false`-do not enable.</param>
/// <see cref="PXR_Manager.EnableVideoSeeThrough"/> is preferred over this method.
[Obsolete("Deprecated.Please use PXR_Manager.EnableVideoSeeThrough instead", true)]
public static void EnableSeeThroughManual(bool value)
{
}
/// <summary>
/// Gets the current status of seethrough tracking.
/// </summary>
/// <returns>Returns `PxrTrackingState`. Below are the enumerations:
/// * `LostNoReason`: no reason
/// * `LostCamera`: camera calibration data error
/// * `LostHighLight`: environment lighting too bright
/// * `LostLowLight`: environment lighting too dark
/// * `LostLowFeatureCount`: few environmental features
/// * `LostReLocation`: relocation in progress
/// * `LostInitialization`: initialization in progress
/// * `LostNoCamera`: camera data error
/// * `LostNoIMU`: IMU data error
/// * `LostIMUJitter`: IMU data jitter
/// * `LostUnknown`: unknown error
/// </returns>
[Obsolete("SeeThroughTracking State is not supported.", true)]
public static PxrTrackingState GetSeeThroughTrackingState() {
return PxrTrackingState.LostUnknown;
}
/// <summary>
/// disable or enable boundary
/// </summary>
/// <param name="value"></param>
public static void SetGuardianSystemDisable(bool value)
{
PXR_Plugin.Boundary.UPxr_SetGuardianSystemDisable(value);
}
/// <summary>
/// Uses the global pose.
/// </summary>
/// <param name="value">Specifies whether to use the global pose.
/// * `true`: use
/// * `false`: do not use
/// </param>
[Obsolete("Global Pose is not supported.", true)]
public static void UseGlobalPose(bool value)
{
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,863 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.XR;
namespace Unity.XR.PXR
{
public class PXR_CompositionLayer : MonoBehaviour, IComparable<PXR_CompositionLayer>
{
private const string TAG = "[PXR_CompositionLayer]";
public static List<PXR_CompositionLayer> Instances = new List<PXR_CompositionLayer>();
public static int overlayID = 0;
[NonSerialized]
public int overlayIndex;
public int layerDepth;
public int imageIndex = 0;
public OverlayType overlayType = OverlayType.Overlay;
public OverlayShape overlayShape = OverlayShape.Quad;
public TextureType textureType = TextureType.ExternalSurface;
public Transform overlayTransform;
public Camera xrRig;
public Texture[] layerTextures = new Texture[2] { null, null };
public bool useTextureAlphaBlending = true;
public bool usePremultipliedAlpha = false;
public bool isDynamic = false;
public int[] overlayTextureIds = new int[2];
public Matrix4x4[] mvMatrixs = new Matrix4x4[2];
public Vector3[] modelScales = new Vector3[2];
public Quaternion[] modelRotations = new Quaternion[2];
public Vector3[] modelTranslations = new Vector3[2];
public Quaternion[] cameraRotations = new Quaternion[2];
public Vector3[] cameraTranslations = new Vector3[2];
public Camera[] overlayEyeCamera = new Camera[2];
public bool overrideColorScaleAndOffset = false;
public Vector4 colorScale = Vector4.one;
public Vector4 colorOffset = Vector4.zero;
// Eac
public Vector3 offsetPosLeft = Vector3.zero;
public Vector3 offsetPosRight = Vector3.zero;
public Vector4 offsetRotLeft = new Vector4(0, 0, 0, 1);
public Vector4 offsetRotRight = new Vector4(0, 0, 0, 1);
public EACModelType eacModelType = EACModelType.Eac360;
public float overlapFactor = 1.0f;
public ulong timestamp = 0;
private Vector4 overlayLayerColorScaleDefault = Vector4.one;
private Vector4 overlayLayerColorOffsetDefault = Vector4.zero;
public bool isExternalAndroidSurface = false;
public bool isExternalAndroidSurfaceDRM = false;
public Surface3DType externalAndroidSurface3DType = Surface3DType.Single;
#region Blurred Quad
public BlurredQuadMode blurredQuadMode = BlurredQuadMode.SmallWindow;
public float blurredQuadScale = 0.5f;
public float blurredQuadShift = 0.01f;
public float blurredQuadFOV = 61.05f;
public float blurredQuadIPD = 0.064f;
#endregion
public IntPtr externalAndroidSurfaceObject = IntPtr.Zero;
public delegate void ExternalAndroidSurfaceObjectCreated();
public ExternalAndroidSurfaceObjectCreated externalAndroidSurfaceObjectCreated = null;
// 360
public float radius = 0; // >0
// ImageRect
public bool useImageRect = false;
public TextureRect textureRect = TextureRect.StereoScopic;
public DestinationRect destinationRect = DestinationRect.Default;
public Rect srcRectLeft = new Rect(0, 0, 1, 1);
public Rect srcRectRight = new Rect(0, 0, 1, 1);
public Rect dstRectLeft = new Rect(0, 0, 1, 1);
public Rect dstRectRight = new Rect(0, 0, 1, 1);
public PxrRecti imageRectLeft;
public PxrRecti imageRectRight;
// LayerBlend
public bool useLayerBlend = false;
public PxrBlendFactor srcColor = PxrBlendFactor.PxrBlendFactorOne;
public PxrBlendFactor dstColor = PxrBlendFactor.PxrBlendFactorOne;
public PxrBlendFactor srcAlpha = PxrBlendFactor.PxrBlendFactorOne;
public PxrBlendFactor dstAlpha = PxrBlendFactor.PxrBlendFactorOne;
public float[] colorMatrix = new float[18] {
1,0,0, // left
0,1,0,
0,0,1,
1,0,0, // right
0,1,0,
0,0,1,
};
public bool isClones = false;
public bool isClonesToNew = false;
public bool enableSubmitLayer = true;
public PXR_CompositionLayer originalOverLay;
public IntPtr layerSubmitPtr = IntPtr.Zero;
[HideInInspector]
public SuperSamplingMode supersamplingMode = SuperSamplingMode.None;
[HideInInspector]
public SuperSamplingEnhance supersamplingEnhance = SuperSamplingEnhance.None;
[HideInInspector]
public SharpeningMode sharpeningMode = SharpeningMode.None;
[HideInInspector]
public SharpeningEnhance sharpeningEnhance = SharpeningEnhance.None;
//Super Resolution
public bool superResolution;
public bool normalSupersampling;
public bool qualitySupersampling;
public bool fixedFoveatedSupersampling;
public bool normalSharpening;
public bool qualitySharpening;
public bool fixedFoveatedSharpening;
public bool selfAdaptiveSharpening;
private bool toCreateSwapChain = false;
private bool toCopyRT = false;
private bool copiedRT = false;
private int eyeCount = 2;
private UInt32 imageCounts = 0;
private PxrLayerParam overlayParam = new PxrLayerParam();
private struct NativeTexture
{
public Texture[] textures;
};
private NativeTexture[] nativeTextures;
private static Material cubeM;
private IntPtr leftPtr = IntPtr.Zero;
private IntPtr rightPtr = IntPtr.Zero;
private static Material textureM;
public HDRFlags hdr = HDRFlags.None;
public int CompareTo(PXR_CompositionLayer other)
{
return layerDepth.CompareTo(other.layerDepth);
}
protected void Awake()
{
xrRig = Camera.main;
Instances.Add(this);
if (null == xrRig.gameObject.GetComponent<PXR_CompositionLayerManager>())
{
xrRig.gameObject.AddComponent<PXR_CompositionLayerManager>();
}
overlayEyeCamera[0] = xrRig;
overlayEyeCamera[1] = xrRig;
overlayTransform = GetComponent<Transform>();
#if UNITY_ANDROID && !UNITY_EDITOR
if (overlayTransform != null)
{
MeshRenderer render = overlayTransform.GetComponent<MeshRenderer>();
if (render != null)
{
render.enabled = false;
}
}
#endif
if (!isClones)
{
InitializeBuffer();
}
PXR_Plugin.Sensor.UPxr_HMDUpdateSwitch(false);
}
private void Start()
{
if (isClones)
{
InitializeBuffer();
}
if (PXR_Manager.Instance == null)
{
return;
}
Camera[] cam = PXR_Manager.Instance.GetEyeCamera();
if (cam[0] != null && cam[0].enabled)
{
RefreshCamera(cam[0], cam[0]);
}
else if (cam[1] != null && cam[2] != null)
{
RefreshCamera(cam[1], cam[2]);
}
}
public void RefreshCamera(Camera leftCamera, Camera rightCamera)
{
overlayEyeCamera[0] = leftCamera;
overlayEyeCamera[1] = rightCamera;
}
private void InitializeBuffer()
{
if (!isExternalAndroidSurface && !isClones)
{
if (null == layerTextures[0] && null == layerTextures[1])
{
PLog.e(TAG, " The left and right images are all empty!");
return;
}
else if (null == layerTextures[0] && null != layerTextures[1])
{
layerTextures[0] = layerTextures[1];
}
else if (null != layerTextures[0] && null == layerTextures[1])
{
layerTextures[1] = layerTextures[0];
}
overlayParam.width = (uint)layerTextures[1].width;
overlayParam.height = (uint)layerTextures[1].height;
}
else
{
overlayParam.width = 1024;
overlayParam.height = 1024;
}
overlayID++;
overlayIndex = overlayID;
overlayParam.layerId = overlayIndex;
overlayParam.layerShape = overlayShape == 0 ? OverlayShape.Quad : overlayShape;
overlayParam.layerType = overlayType;
overlayParam.arraySize = 1;
overlayParam.mipmapCount = 1;
overlayParam.sampleCount = 1;
overlayParam.layerFlags = 0;
if (OverlayShape.Cubemap == overlayShape)
{
overlayParam.faceCount = 6;
if (cubeM == null)
cubeM = new Material(Shader.Find("PXR_SDK/PXR_CubemapBlit"));
}
else
{
overlayParam.faceCount = 1;
if (textureM == null)
textureM = new Material(Shader.Find("PXR_SDK/PXR_Texture2DBlit"));
}
if (GraphicsDeviceType.Vulkan == SystemInfo.graphicsDeviceType)
{
if (ColorSpace.Linear == QualitySettings.activeColorSpace)
{
overlayParam.format = (UInt64)ColorForamt.VK_FORMAT_R8G8B8A8_SRGB;
}
else
{
overlayParam.format = (UInt64)ColorForamt.VK_FORMAT_R8G8B8A8_UNORM;
if (OverlayShape.Cubemap == overlayShape)
{
cubeM.SetFloat("_Gamma", 2.2f);
}
else
{
textureM.SetFloat("_Gamma", 2.2f);
}
}
}
else
{
overlayParam.format = (UInt64)ColorForamt.GL_SRGB8_ALPHA8;
}
if (isClones)
{
if (null != originalOverLay)
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlagSharedImagesBetweenLayers;
leftPtr = Marshal.AllocHGlobal(Marshal.SizeOf(originalOverLay.overlayIndex));
rightPtr = Marshal.AllocHGlobal(Marshal.SizeOf(originalOverLay.overlayIndex));
Marshal.WriteInt64(leftPtr, originalOverLay.overlayIndex);
Marshal.WriteInt64(rightPtr, originalOverLay.overlayIndex);
overlayParam.leftExternalImages = leftPtr;
overlayParam.rightExternalImages = rightPtr;
isExternalAndroidSurface = originalOverLay.isExternalAndroidSurface;
isDynamic = originalOverLay.isDynamic;
overlayParam.width = (UInt32)Mathf.Min(overlayParam.width, originalOverLay.overlayParam.width);
overlayParam.height = (UInt32)Mathf.Min(overlayParam.height, originalOverLay.overlayParam.height);
}
else
{
PLog.e(TAG, "In clone state, originalOverLay cannot be empty!");
}
}
if (isExternalAndroidSurface)
{
if (isExternalAndroidSurfaceDRM)
{
overlayParam.layerFlags |= (UInt32)(PxrLayerCreateFlags.PxrLayerFlagAndroidSurface | PxrLayerCreateFlags.PxrLayerFlagProtectedContent);
}
else
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlagAndroidSurface;
}
if (Surface3DType.LeftRight == externalAndroidSurface3DType)
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlag3DLeftRightSurface;
}
else if (Surface3DType.TopBottom == externalAndroidSurface3DType)
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlag3DTopBottomSurface;
}
overlayParam.layerLayout = LayerLayout.Mono;
}
else
{
if (!isDynamic)
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlagStaticImage;
}
if ((layerTextures[0] != null && layerTextures[1] != null && layerTextures[0] == layerTextures[1]) || null == layerTextures[1])
{
eyeCount = 1;
overlayParam.layerLayout = LayerLayout.Mono;
}
else
{
eyeCount = 2;
overlayParam.layerLayout = LayerLayout.Stereo;
}
toCreateSwapChain = true;
}
PLog.i(TAG, $"UPxr_CreateLayer() overlayParam.layerId={overlayParam.layerId}, layerShape={overlayParam.layerShape}, layerType={overlayParam.layerType}, width={overlayParam.width}, height={overlayParam.height}, layerFlags={overlayParam.layerFlags}, format={overlayParam.format}, layerLayout={overlayParam.layerLayout}.");
PXR_Plugin.Render.UPxr_CreateLayerParam(overlayParam);
}
public void CreateExternalSurface(PXR_CompositionLayer overlayInstance)
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (IntPtr.Zero != overlayInstance.externalAndroidSurfaceObject)
{
return;
}
PXR_Plugin.Render.UPxr_GetLayerAndroidSurface(overlayInstance.overlayIndex, 0, ref overlayInstance.externalAndroidSurfaceObject);
PLog.i(TAG, string.Format("CreateExternalSurface: Overlay Type:{0}, LayerDepth:{1}, SurfaceObject:{2}", overlayInstance.overlayType, overlayInstance.overlayIndex, overlayInstance.externalAndroidSurfaceObject));
if (IntPtr.Zero == overlayInstance.externalAndroidSurfaceObject || null == overlayInstance.externalAndroidSurfaceObjectCreated)
{
return;
}
overlayInstance.externalAndroidSurfaceObjectCreated();
#endif
}
public void UpdateCoords()
{
if (null == overlayTransform || !overlayTransform.gameObject.activeSelf || null == overlayEyeCamera[0] || null == overlayEyeCamera[1])
{
return;
}
for (int i = 0; i < mvMatrixs.Length; i++)
{
mvMatrixs[i] = overlayEyeCamera[i].worldToCameraMatrix * overlayTransform.localToWorldMatrix;
if (overlayTransform is RectTransform uiTransform)
{
var rect = uiTransform.rect;
var lossyScale = overlayTransform.lossyScale;
modelScales[i] = new Vector3(rect.width * lossyScale.x,
rect.height * lossyScale.y, 1);
modelTranslations[i] = uiTransform.TransformPoint(rect.center);
}
else
{
modelScales[i] = overlayTransform.lossyScale;
modelTranslations[i] = overlayTransform.position;
}
modelRotations[i] = overlayTransform.rotation;
cameraRotations[i] = overlayEyeCamera[i].transform.rotation;
cameraTranslations[i] = overlayEyeCamera[i].transform.position;
}
}
public bool CreateTexture()
{
if (!toCreateSwapChain)
{
return false;
}
if (null == nativeTextures)
nativeTextures = new NativeTexture[eyeCount];
for (int i = 0; i < eyeCount; i++)
{
int ret = PXR_Plugin.Render.UPxr_GetLayerImageCount(overlayIndex, (EyeType)i, ref imageCounts);
if (ret != 0 || imageCounts < 1)
{
return false;
}
if (null == nativeTextures[i].textures)
{
nativeTextures[i].textures = new Texture[imageCounts];
}
for (int j = 0; j < imageCounts; j++)
{
IntPtr ptr = IntPtr.Zero;
PXR_Plugin.Render.UPxr_GetLayerImagePtr(overlayIndex, (EyeType)i, j, ref ptr);
if (IntPtr.Zero == ptr)
{
return false;
}
Texture texture;
if (OverlayShape.Cubemap == overlayShape)
{
texture = Cubemap.CreateExternalTexture((int)overlayParam.width, TextureFormat.RGBA32, false, ptr);
}
else
{
texture = Texture2D.CreateExternalTexture((int)overlayParam.width, (int)overlayParam.height, TextureFormat.RGBA32, false, true, ptr);
}
if (null == texture)
{
return false;
}
nativeTextures[i].textures[j] = texture;
}
}
toCreateSwapChain = false;
toCopyRT = true;
copiedRT = false;
FreePtr();
return true;
}
public bool CopyRT()
{
if (isClones)
{
return true;
}
if (!toCopyRT)
{
return copiedRT;
}
if (!isDynamic && copiedRT)
{
return copiedRT;
}
if (null == nativeTextures)
{
return false;
}
if (enableSubmitLayer)
{
PXR_Plugin.Render.UPxr_GetLayerNextImageIndexByRender(overlayIndex, ref imageIndex);
}
for (int i = 0; i < eyeCount; i++)
{
Texture nativeTexture = nativeTextures[i].textures[imageIndex];
if (null == nativeTexture || null == layerTextures[i])
continue;
RenderTexture texture = layerTextures[i] as RenderTexture;
if (OverlayShape.Cubemap == overlayShape && null == layerTextures[i] as Cubemap)
{
return false;
}
for (int f = 0; f < (int)overlayParam.faceCount; f++)
{
if (QualitySettings.activeColorSpace == ColorSpace.Gamma && texture != null && texture.format == RenderTextureFormat.ARGB32)
{
Graphics.CopyTexture(layerTextures[i], f, 0, nativeTexture, f, 0);
}
else
{
RenderTextureDescriptor rtDes = new RenderTextureDescriptor((int)overlayParam.width, (int)overlayParam.height, RenderTextureFormat.ARGB32, 0);
rtDes.msaaSamples = (int)overlayParam.sampleCount;
rtDes.useMipMap = true;
rtDes.autoGenerateMips = false;
rtDes.sRGB = true;
RenderTexture renderTexture = RenderTexture.GetTemporary(rtDes);
if (!renderTexture.IsCreated())
{
renderTexture.Create();
}
renderTexture.DiscardContents();
if (OverlayShape.Cubemap == overlayShape)
{
cubeM.SetInt("_d", f);
Graphics.Blit(layerTextures[i], renderTexture, cubeM);
}
else
{
textureM.mainTexture = texture;
textureM.SetPass(0);
textureM.SetInt("_premultiply", usePremultipliedAlpha ? 1 : 0);
Graphics.Blit(layerTextures[i], renderTexture, textureM);
}
Graphics.CopyTexture(renderTexture, 0, 0, nativeTexture, f, 0);
RenderTexture.ReleaseTemporary(renderTexture);
}
}
copiedRT = true;
}
return copiedRT;
}
public void SetTexture(Texture texture, bool dynamic)
{
if (isExternalAndroidSurface)
{
PLog.w(TAG, "Not support setTexture !");
return;
}
if (isClones)
{
return;
}
else
{
foreach (PXR_CompositionLayer overlay in PXR_CompositionLayer.Instances)
{
if (overlay.isClones && null != overlay.originalOverLay && overlay.originalOverLay.overlayIndex == overlayIndex)
{
overlay.DestroyLayer();
overlay.isClonesToNew = true;
}
}
}
toCopyRT = false;
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overlayIndex);
ClearTexture();
for (int i = 0; i < layerTextures.Length; i++)
{
layerTextures[i] = texture;
}
isDynamic = dynamic;
InitializeBuffer();
if (!isClones)
{
foreach (PXR_CompositionLayer overlay in PXR_CompositionLayer.Instances)
{
if (overlay.isClones && overlay.isClonesToNew)
{
overlay.originalOverLay = this;
overlay.InitializeBuffer();
overlay.isClonesToNew = false;
}
}
}
}
private void FreePtr()
{
if (leftPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(leftPtr);
leftPtr = IntPtr.Zero;
}
if (rightPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(rightPtr);
rightPtr = IntPtr.Zero;
}
if (layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(layerSubmitPtr);
layerSubmitPtr = IntPtr.Zero;
}
}
public void OnDestroy()
{
DestroyLayer();
Instances.Remove(this);
}
public void DestroyLayer()
{
if (isExternalAndroidSurface)
{
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overlayIndex);
externalAndroidSurfaceObject = IntPtr.Zero;
ClearTexture();
return;
}
if (!isClones)
{
List<PXR_CompositionLayer> toDestroyClones = new List<PXR_CompositionLayer>();
foreach (PXR_CompositionLayer overlay in Instances)
{
if (overlay.isClones && null != overlay.originalOverLay && overlay.originalOverLay.overlayIndex == overlayIndex)
{
toDestroyClones.Add(overlay);
}
}
foreach (PXR_CompositionLayer overLay in toDestroyClones)
{
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overLay.overlayIndex);
ClearTexture();
}
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overlayIndex);
}
else
{
if (null != originalOverLay && Instances.Contains(originalOverLay))
{
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overlayIndex);
}
}
ClearTexture();
}
private void ClearTexture()
{
FreePtr();
if (isExternalAndroidSurface || null == nativeTextures || isClones)
{
return;
}
for (int i = 0; i < eyeCount; i++)
{
if (null == nativeTextures[i].textures)
{
continue;
}
for (int j = 0; j < imageCounts; j++)
DestroyImmediate(nativeTextures[i].textures[j]);
}
nativeTextures = null;
}
public void SetLayerColorScaleAndOffset(Vector4 scale, Vector4 offset)
{
colorScale = scale;
colorOffset = offset;
}
public void SetEACOffsetPosAndRot(Vector3 leftPos, Vector3 rightPos, Vector4 leftRot, Vector4 rightRot)
{
offsetPosLeft = leftPos;
offsetPosRight = rightPos;
offsetRotLeft = leftRot;
offsetRotRight = rightRot;
}
public void SetEACFactor(float factor)
{
overlapFactor = factor;
}
public Vector4 GetLayerColorScale()
{
if (!overrideColorScaleAndOffset)
{
return overlayLayerColorScaleDefault;
}
return colorScale;
}
public Vector4 GetLayerColorOffset()
{
if (!overrideColorScaleAndOffset)
{
return overlayLayerColorOffsetDefault;
}
return colorOffset;
}
public PxrRecti getPxrRectiLeft(bool left)
{
if (left)
{
imageRectLeft.x = (int)(overlayParam.width * srcRectLeft.x);
imageRectLeft.y = (int)(overlayParam.height * srcRectLeft.y);
imageRectLeft.width = (int)(overlayParam.width * Mathf.Min(srcRectLeft.width, 1 - srcRectLeft.x));
imageRectLeft.height = (int)(overlayParam.height * Mathf.Min(srcRectLeft.height, 1 - srcRectLeft.y));
return imageRectLeft;
}
else
{
imageRectRight.x = (int)(overlayParam.width * srcRectRight.x);
imageRectRight.y = (int)(overlayParam.height * srcRectRight.y);
imageRectRight.width = (int)(overlayParam.width * Mathf.Min(srcRectRight.width, 1 - srcRectRight.x));
imageRectRight.height = (int)(overlayParam.height * Mathf.Min(srcRectRight.height, 1 - srcRectRight.y));
return imageRectRight;
}
}
public UInt32 getHDRFlags()
{
UInt32 hdrFlags = 0;
if (!isExternalAndroidSurface)
{
return hdrFlags;
}
switch (hdr)
{
case HDRFlags.HdrPQ:
hdrFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagColorSpaceHdrPQ;
break;
case HDRFlags.HdrHLG:
hdrFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagColorSpaceHdrHLG;
break;
default:
break;
}
return hdrFlags;
}
public enum HDRFlags
{
None,
HdrPQ,
HdrHLG,
}
public enum OverlayShape
{
Quad = 1,
Cylinder = 2,
Equirect = 4,
Cubemap = 5,
Eac = 6,
Fisheye = 7,
BlurredQuad = 9
}
public enum OverlayType
{
Overlay = 0,
Underlay = 1
}
public enum TextureType
{
ExternalSurface,
DynamicTexture,
StaticTexture
}
public enum LayerLayout
{
Stereo = 0,
DoubleWide = 1,
Array = 2,
Mono = 3
}
public enum Surface3DType
{
Single = 0,
LeftRight,
TopBottom
}
public enum TextureRect
{
MonoScopic,
StereoScopic,
Custom
}
public enum DestinationRect
{
Default,
Custom
}
public enum EACModelType
{
Eac360 = 0,
Eac360ViewPort = 1,
Eac180 = 4,
Eac180ViewPort = 5,
}
public enum ColorForamt
{
VK_FORMAT_R8G8B8A8_UNORM = 37,
VK_FORMAT_R8G8B8A8_SRGB = 43,
GL_SRGB8_ALPHA8 = 0x8c43,
GL_RGBA8 = 0x8058
}
public enum BlurredQuadMode
{
SmallWindow,
Immersion
}
}
}

View File

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

View File

@@ -0,0 +1,428 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
namespace Unity.XR.PXR
{
public class PXR_EyeTracking
{
/// <summary>
/// Gets the PosMatrix of the head.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="matrix">A Matrix4x4 value returned by the result.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetHeadPosMatrix(out Matrix4x4 matrix)
{
matrix = Matrix4x4.identity;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
Vector3 headPos = Vector3.zero;
if (!device.TryGetFeatureValue(CommonUsages.devicePosition, out headPos))
{
Debug.LogError("PXRLog Failed at GetHeadPosMatrix Pos");
return false;
}
Quaternion headRot = Quaternion.identity;
if (!device.TryGetFeatureValue(CommonUsages.deviceRotation, out headRot))
{
Debug.LogError("PXRLog Failed at GetHeadPosMatrix Rot");
return false;
}
matrix = Matrix4x4.TRS(headPos, headRot, Vector3.one);
return true;
}
static InputDevice curDevice;
/// <summary>
/// Gets the input device for eye tracking data.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="device">The input device returned by the result.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
static bool GetEyeTrackingDevice(out InputDevice device)
{
if (curDevice!= null&& curDevice.isValid)
{
device = curDevice;
return true;
}
device = default;
if (!PXR_Manager.Instance.eyeTracking)
return false;
List<InputDevice> devices = new List<InputDevice>();
InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.EyeTracking | InputDeviceCharacteristics.HeadMounted, devices);
if (devices.Count == 0)
{
Debug.LogError("PXRLog Failed at GetEyeTrackingDevice devices.Count");
return false;
}
device = devices[0];
curDevice = device;
if (!device.isValid)
{
Debug.LogError("PXRLog Failed at GetEyeTrackingDevice device.isValid");
}
return device.isValid;
}
/// <summary>
/// Gets the position of the center of the eyes in the Unity camera coordinate system (unit: meter).
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="point">Returns a vector3 value which is divided by 1000. To get the original value, multiply the returned value by 1000. Unit: millimeter.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetCombineEyeGazePoint(out Vector3 point)
{
point = Vector3.zero;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.combineEyePoint, out point))
{
Debug.Log("PXRLog Failed at GetCombineEyeGazePoint point");
return false;
}
return true;
}
/// <summary>
/// Gets the direction of binocular combined gaze in the Unity camera coordinate system.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="vector">Returns a vector3 value which is divided by 1000. To get the original value, multiply the returned value by 1000. Unit: millimeter.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetCombineEyeGazeVector(out Vector3 vector)
{
vector = Vector3.zero;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.combineEyeVector, out vector))
{
Debug.LogError("PXRLog Failed at GetCombineEyeGazeVector vector");
return false;
}
return true;
}
/// <summary>
/// Gets the openness/closeness of the left eye.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="openness">A float value returned by the result. The value ranges from `0.0` to `1.0`. `0.0` incicates completely closed, `1.0` indicates completely open.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetLeftEyeGazeOpenness(out float openness)
{
openness = 0;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.leftEyeOpenness, out openness))
{
Debug.LogError("PXRLog Failed at GetLeftEyeGazeOpenness openness");
return false;
}
return true;
}
/// <summary>
/// Gets the openness/closeness of the right eye.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="openness">A float value returned by the result. The value ranges from `0.0` to `1.0`. `0.0` indicates completely closed, `1.0` indicates completely open.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetRightEyeGazeOpenness(out float openness)
{
openness = 0;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.rightEyeOpenness, out openness))
{
Debug.LogError("PXRLog Failed at GetRightEyeGazeOpenness openness");
return false;
}
return true;
}
/// <summary>
/// Gets whether the data of the current left eye is available.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="status">An int value returned by the result. Below are the `EyePoseStatus` enumerations:
/// - GazePointValid = (1 << 0),
/// - GazeVectorValid = (1 << 1),
/// - EyeOpennessValid = (1 << 2),
/// - EyePupilDilationValid = (1 << 3),
/// - EyePositionGuideValid = (1 << 4),
/// - EyePupilPositionValid = (1 << 5),
/// - EyeConvergenceDistanceValid = (1 << 6),
/// - EyeGazePointValid = (1 << 7),
/// - EyeGazeVectorValid = (1 << 8),
/// - PupilDistanceValid = (1 << 9),
/// - ConvergenceDistanceValid = (1 << 10),
/// - PupilDiameterValid = (1 << 11),
/// </param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetLeftEyePoseStatus(out uint status)
{
status = 0;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.leftEyePoseStatus, out status))
{
Debug.LogError("PXRLog Failed at GetLeftEyePoseStatus status");
return false;
}
return true;
}
/// <summary>
/// Gets whether the data of the current right eye is available.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="status">An int value returned by the result. Below are the `EyePoseStatus` enumerations:
/// - GazePointValid = (1 << 0),
/// - GazeVectorValid = (1 << 1),
/// - EyeOpennessValid = (1 << 2),
/// - EyePupilDilationValid = (1 << 3),
/// - EyePositionGuideValid = (1 << 4),
/// - EyePupilPositionValid = (1 << 5),
/// - EyeConvergenceDistanceValid = (1 << 6),
/// - EyeGazePointValid = (1 << 7),
/// - EyeGazeVectorValid = (1 << 8),
/// - PupilDistanceValid = (1 << 9),
/// - ConvergenceDistanceValid = (1 << 10),
/// - PupilDiameterValid = (1 << 11),
/// </param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetRightEyePoseStatus(out uint status)
{
status = 0;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.rightEyePoseStatus, out status))
{
Debug.LogError("PXRLog Failed at GetRightEyePoseStatus status");
return false;
}
return true;
}
/// <summary>
/// Gets whether the data of the combined eye is available.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="status">An int value returned by the result:
/// `0`: not available
/// `1`: available
/// </param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetCombinedEyePoseStatus(out uint status)
{
status = 0;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.combinedEyePoseStatus, out status))
{
Debug.LogError("PXRLog Failed at GetCombinedEyePoseStatus status");
return false;
}
return true;
}
/// <summary>
/// Gets the position of the left eye in a coordinate system. The upper-right point of the sensor is taken as the origin (0, 0) and the lower-left point is taken as (1, 1).
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="position">A vector3 value returned by the result.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetLeftEyePositionGuide(out Vector3 position)
{
position = Vector3.zero;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.leftEyePositionGuide, out position))
{
Debug.LogError("PXRLog Failed at GetLeftEyePositionGuide pos");
return false;
}
return true;
}
/// <summary>
/// Gets the position of the right eye in a coordinate system. The upper-right point of the sensor is taken as the origin (0, 0) and the lower-left point is taken as (1, 1).
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="position">A vector3 value returned by the result.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetRightEyePositionGuide(out Vector3 position)
{
position = Vector3.zero;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.rightEyePositionGuide, out position))
{
Debug.LogError("PXRLog Failed at GetRightEyePositionGuide pos");
return false;
}
return true;
}
/// <summary>
/// Gets the foveated gaze direction (i.e., the central point of fixed foveated rendering).
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="direction">A vector3 value returned by the result.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetFoveatedGazeDirection(out Vector3 direction)
{
direction = Vector3.zero;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.foveatedGazeDirection, out direction))
{
Debug.LogError("PXRLog Failed at GetFoveatedGazeDirection direction");
return false;
}
return true;
}
/// <summary>
/// Gets whether the current foveated gaze tracking data is available.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="status">An int value returned by the result:
/// * `0`: not available
/// * `1`: available
/// </param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetFoveatedGazeTrackingState(out uint state)
{
state = 0;
if (!PXR_Manager.Instance.eyeTracking)
return false;
if (!GetEyeTrackingDevice(out InputDevice device))
return false;
if (!device.TryGetFeatureValue(PXR_Usages.foveatedGazeTrackingState, out state))
{
Debug.LogError("PXRLog Failed at GetFoveatedGazeTrackingState state");
return false;
}
return true;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,93 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using UnityEngine;
namespace Unity.XR.PXR
{
public class PXR_FoveationRendering
{
private static PXR_FoveationRendering instance = null;
public static PXR_FoveationRendering Instance
{
get
{
if (instance == null)
{
instance = new PXR_FoveationRendering();
}
return instance;
}
}
/// <summary>
/// Sets a foveated rendering level.
/// </summary>
/// <param name="level">Select a foveated rendering level:
/// * `None`: disable foveated rendering
/// * `Low`
/// * `Med`
/// * `High`
/// * `TopHigh`
/// </param>
/// <param name="isETFR">
/// Describe if the foveated rendering mode is eye tracked foveated rendering (ETFR):
/// * `true`: ETFR
/// * `false`: not ETFR
/// </param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool SetFoveationLevel(FoveationLevel level, bool isETFR)
{
if (isETFR)
{
return PXR_Plugin.Render.UPxr_SetEyeFoveationLevel(level);
}
else
{
return PXR_Plugin.Render.UPxr_SetFoveationLevel(level);
}
}
/// <summary>
/// Gets the current foveated rendering level.
/// </summary>
/// <returns>The current foveated rendering level:
/// * `None` (`-1`): foveated rendering disabled
/// * `Low`
/// * `Med`
/// * `High`
/// * `TopHigh`
/// </returns>
public static FoveationLevel GetFoveationLevel()
{
return PXR_Plugin.Render.UPxr_GetFoveationLevel();
}
/// <summary>
/// Sets foveated rendering parameters.
/// </summary>
/// <param name="foveationGainX">Set the reduction rate of peripheral pixels in the X-axis direction. Value range: [1.0, 10.0], the greater the value, the higher the reduction rate.</param>
/// <param name="foveationGainY">Set the reduction rate of peripheral pixels in the Y-axis direction. Value range: [1.0, 10.0], the greater the value, the higher the reduction rate.</param>
/// <param name="foveationArea">Set the range of foveated area whose resolution is not to be reduced. Value range: [0.0, 4.0], the higher the value, the bigger the high-quality central area.</param>
/// <param name="foveationMinimum">Set the minimum pixel density. Recommended values: 1/32, 1/16, 1/8, 1/4, 1/2. The actual pixel density will be greater than or equal to the value set here.</param>
[Obsolete("SetFoveationParameters is not supported.", true)]
public static void SetFoveationParameters(float foveationGainX, float foveationGainY, float foveationArea, float foveationMinimum)
{}
}
}
#endif

View File

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

View File

@@ -0,0 +1,119 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Runtime.InteropServices;
using UnityEngine;
#if PICO_LIVE_PREVIEW && UNITY_EDITOR
using Unity.XR.PICO.LivePreview;
#endif
namespace Unity.XR.PXR
{
public static class PXR_HandTracking
{
/// <summary>Gets whether hand tracking is enabled or disabled.</summary>
/// <returns>
/// * `true`: enabled
/// * `false`: disabled
/// </returns>
///interface has been deprecated
[Obsolete("interface has been deprecated", true)]
public static bool GetSettingState()
{
return false;
}
/// <summary>Gets the current active input device.</summary>
/// <returns>The current active input device:
/// * `HeadActive`: HMD
/// * `ControllerActive`: controllers
/// * `HandTrackingActive`: hands
/// </returns>
public static ActiveInputDevice GetActiveInputDevice()
{
return PXR_Plugin.HandTracking.UPxr_GetHandTrackerActiveInputType();
}
/// <summary>Gets the data about the pose of a specified hand, including the status of the ray and fingers, the strength of finger pinch and ray touch.</summary>
/// <param name="hand">The hand to get data for:
/// * `HandLeft`: left hand
/// * `HandRight`: right hand
/// </param>
/// <param name="aimState">`HandAimState` contains the data about the poses of ray and fingers.
/// If you use PICO hand prefabs without changing any of their default settings, you will get the following data:
/// ```csharp
/// public class PXR_Hand
/// {
/// // Whether the data is valid.
/// public bool Computed { get; private set; }
/// // The ray pose.
/// public Posef RayPose { get; private set; }
/// // Whether the ray was displayed.
/// public bool RayValid { get; private set; }
/// // Whether the ray pinched.
/// public bool Pinch { get; private set; }
/// // The strength of ray pinch.
/// public float PinchStrength { get; private set; }
/// ```
/// </param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetAimState(HandType hand, ref HandAimState aimState)
{
if (!PXR_ProjectSetting.GetProjectConfig().handTracking)
return false;
return PXR_Plugin.HandTracking.UPxr_GetHandTrackerAimState(hand, ref aimState);
}
/// <summary>Gets the locations of joints for a specified hand.</summary>
/// <param name="hand">The hand to get joint locations for:
/// * `HandLeft`: left hand
/// * `HandRight`: right hand
/// </param>
/// <param name="jointLocations">Contains data about the locations of the joints in the specified hand.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetJointLocations(HandType hand, ref HandJointLocations jointLocations)
{
if (!PXR_ProjectSetting.GetProjectConfig().handTracking)
return false;
return PXR_Plugin.HandTracking.UPxr_GetHandTrackerJointLocations(hand, ref jointLocations);
}
/// <summary>
/// Gets the scaling ratio of the hand model.
/// </summary>
/// <param name="hand">Specifies the hand to get scaling ratio for:
/// * `HandLeft`: left hand
/// * `HandRight`: right hand
/// </param>
/// <param name="scale">Returns the scaling ratio for the specified hand.</param>
/// <returns>
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool GetHandScale(HandType hand,ref float scale)
{
return PXR_Plugin.HandTracking.UPxr_GetHandScale((int)hand, ref scale);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,952 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using LitJson;
using System;
using UnityEngine;
using UnityEngine.XR;
namespace Unity.XR.PXR
{
public static partial class PXR_Input
{
/// <summary>Gets the status of the specified controller.</summary>
/// <param name="controller">Specifies the controller to get status for: `LeftController` or `RightController`.</param>
/// <returns>The status of the specified controller:
/// - `static`: the controller is static
/// - `SixDof`: the controller is in 6DoF tracking mode
/// - `ThreeDof`: the controller is in 3DoF tracking mode
/// - `Sleep`: the controller remains static for a long time and is now in sleep mode
/// - `CollidedIn3Dof`: the controller collided with something else during 3DoF tracking
/// - `CollidedIn6Dof`: the controller collided with something else during 6DoF tracking
/// </returns>
public static ControllerStatus GetControllerStatus(Controller controller)
{
PxrControllerTracking pxrControllerTracking = new PxrControllerTracking();
PXR_Plugin.Controller.UPxr_GetControllerTrackingState((uint)controller, PXR_Plugin.System.UPxr_GetPredictedDisplayTime(), ref pxrControllerTracking);
return (ControllerStatus)pxrControllerTracking.localControllerPose.status;
}
/// <summary>A callback that indicates the input source (hand poses/controllers) has changed.</summary>
public static Action<ActiveInputDevice> InputDeviceChanged;
/// <summary>
/// Gets the current dominant controller.
/// </summary>
/// <returns>The current dominant controller: `LeftController`; `RightController`.</returns>
[Obsolete("GetDominantHand is not supported", true)]
public static Controller GetDominantHand()
{
return Controller.LeftController;
}
/// <summary>
/// Sets a controller as the dominant controller.
/// </summary>
/// <param name="controller">The controller to be set as the dominant controller: `0`-left controller; `1`-right controller.</param>
[Obsolete("SetDominantHand is not supported", true)]
public static void SetDominantHand(Controller controller)
{}
/// <summary>
/// Sets controller vibration, including vibration amplitude and duration.
/// @note The `SendHapticImpulse` method offered by UnityXR is also supported. Click [here](https://docs.unity3d.com/ScriptReference/XR.InputDevice.SendHapticImpulse.html) for more information.
/// </summary>
/// <param name="strength">Vibration amplitude. The valid value ranges from `0` to `1`. The greater the value, the stronger the vibration amplitude. To stop controller vibration, call this function again and set this parameter to `0`.</param>
/// <param name="time">Vibration duration. The valid value ranges from `0` to `65535` ms.</param>
/// <param name="controller">The controller to set vibration for:
/// * `0`: left controller
/// * `1`: right controller
/// </param>
[Obsolete("Please use SendHapticImpulse instead", true)]
public static void SetControllerVibration(float strength, int time, Controller controller)
{}
/// <summary>
/// Gets the device model.
/// </summary>
/// <returns>The device model. Enumerations: `G2`, `Neo2`, `Neo3`, `NewController`, `PICO_4`.</returns>
public static ControllerDevice GetControllerDeviceType()
{
return (ControllerDevice)PXR_Plugin.Controller.UPxr_GetControllerType();
}
/// <summary>
/// Gets the connection status for a specified controller.
/// </summary>
/// <param name="controller">The controller to get connection status for:
/// * `0`: left controller
/// * `1`: right controller
/// </param>
/// <returns>The connection status of the specified controller:
/// * `true`: connected
/// * `false`: not connected
/// </returns>
public static bool IsControllerConnected(Controller controller)
{
return PXR_Plugin.Controller.UPxr_IsControllerConnected(controller);
}
/// <summary>
/// Sets the offset of the controller's display position to its real position.
/// </summary>
/// <param name="hand">The controller to set an offset for:
/// * `0`: left controller
/// * `1`: right controller
/// </param>
/// <param name="offset">The offset (in meters).</param>
public static void SetControllerOriginOffset(Controller controller, Vector3 offset)
{
PXR_Plugin.Controller.UPxr_SetControllerOriginOffset((int)controller, offset);
}
/// <summary>
/// Gets the predicted orientation of a specified controller after a specified time.
/// </summary>
/// <param name="hand">The controller to get the predicted rotation for:
/// * `0`: left controller
/// * `1`: right controller
/// </param>
/// <param name="predictTime">The time for prediction (in milliseconds).</param>
/// <returns>The predicted orientation.</returns>
public static Quaternion GetControllerPredictRotation(Controller controller, double predictTime)
{
PxrControllerTracking pxrControllerTracking = new PxrControllerTracking();
PXR_Plugin.Controller.UPxr_GetControllerTrackingState((uint)controller, predictTime, ref pxrControllerTracking);
return new Quaternion(
pxrControllerTracking.localControllerPose.pose.orientation.x,
pxrControllerTracking.localControllerPose.pose.orientation.y,
pxrControllerTracking.localControllerPose.pose.orientation.z,
pxrControllerTracking.localControllerPose.pose.orientation.w);
}
/// <summary>
/// Gets the predicted position of a specified controller after a specified time.
/// </summary>
/// <param name="hand">The controller to get the predicted position for:
/// * `0`: left controller
/// * `1`: right controller
/// </param>
/// <param name="predictTime">The time for prediction (in milliseconds).</param>
/// <returns>The predicted position.</returns>
public static Vector3 GetControllerPredictPosition(Controller controller, double predictTime)
{
PxrControllerTracking pxrControllerTracking = new PxrControllerTracking();
PXR_Plugin.Controller.UPxr_GetControllerTrackingState((uint)controller, predictTime, ref pxrControllerTracking);
return new Vector3(
pxrControllerTracking.localControllerPose.pose.position.x,
pxrControllerTracking.localControllerPose.pose.position.y,
pxrControllerTracking.localControllerPose.pose.position.z);
}
/// @deprecated Use \ref SendHapticImpulse instead.
/// <summary>
/// Sets event-triggered vibration for a specified controller.
/// </summary>
/// <param name="hand">The controller to enable vibration for:
/// * `0`: left controller
/// * `1`: right controller
/// </param>
/// <param name="frequency">Vibration frequency, which ranges from `50` to `500` Hz.</param>
/// <param name="strength">Vibration amplitude. Its valid value ranges from `0` to `1`. The higher the value, the stronger the vibration amplitude.</param>
/// <param name="time">Vibration duration, which ranges from `0` to `65535` ms.</param>
[Obsolete("Please use SendHapticImpulse instead", true)]
public static int SetControllerVibrationEvent(UInt32 hand, int frequency, float strength, int time)
{
return -1;
}
/// @deprecated Use \ref StopHapticBuffer(int sourceId, bool clearCache) instead.
/// <summary>
/// Stops audio-triggered vibration.
/// </summary>
/// <param name="id">A reserved parameter, set it to the source ID returned by `StartVibrateBySharem` or `SaveVibrateByCache` to stop the corresponding vibration,
/// or set it to `0` to stop all vibrations.</param>
[Obsolete("Please use StopHapticBuffer instead", true)]
public static int StopControllerVCMotor(int sourceId)
{
return -1;
}
/// @deprecated Deprecated.
/// <summary>
/// Starts audio-triggered vibration for specified controller(s). The audio data come from an audio file.
/// </summary>
/// <param name="file">The path to the audio file.</param>
/// <param name="vibrateType">The controller(s) to enable vibration for:
/// * `0`: none
/// * `1`: left controller
/// * `2`: right controller
/// * `3`: left and right controllers
/// </param>
[Obsolete("StartControllerVCMotor is not supported", true)]
public static int StartControllerVCMotor(string file, VibrateType vibrateType)
{
return -1;
}
/// @deprecated Deprecated.
/// <summary>
/// Sets the amplitude for audio-triggered vibration. Support changing the vibration amplitude during audio playback.
/// </summary>
/// <param name="mode">Vibration amplitude level:
/// * `0`: no vibration
/// * `1`: standard amplitude
/// * `2`: 2×standard amplitude
/// * `3`: 3×standard amplitude
/// * `4`: 4×standard amplitude
/// @note "3×standard amplitude" and "4×standard amplitude" are NOT recommended as they will cause serious loss of vibration details.
/// </param>
[Obsolete("SetControllerAmp is not supported", true)]
public static int SetControllerAmp(float mode)
{
return -1;
}
/// @deprecated Use \ref SendHapticBuffer(VibrateType vibrateType, AudioClip audioClip, ChannelFlip channelFlip, ref int sourceId, CacheType cacheType) instead.
/// <summary>
/// Starts audio-triggered vibration for specified controller(s). The audio data come from an audio clip passed to the Unity Engine.
/// </summary>
/// <param name="audioClip">The path to the audio clip.</param>
/// <param name="vibrateType">The controller(s) to enable vibration for:
/// * `0`: none
/// * `1`: left controller
/// * `2`: right controller
/// * `3`: left and right controllers
/// </param>
/// <param nname="channelFlip">Whether to enable audio channel inversion:
/// * `Yes`: enable
/// * `No`: disable
/// Once audio channel inversion is enabled, the left controller vibrates with the audio data from the right channel, and vice versa.
/// </param>
/// <param nname="sourceId">Returns the unique ID for controlling the corresponding vibration,
/// which will be used in `StartVibrateByCache`, `ClearVibrateByCache` or `StopControllerVCMotor`.</param>
[Obsolete("Please use SendHapticBuffer instead", true)]
public static int StartVibrateBySharem(AudioClip audioClip, VibrateType vibrateType, ChannelFlip channelFlip, ref int sourceId)
{
return -1;
}
/**
* @deprecated Use \ref SendHapticBuffer(VibrateType vibrateType, float[] pcmData, int buffersize, int frequency, int channelMask, ChannelFlip channelFlip, ref int sourceId, CacheType cacheType) instead.
*/
/// <summary>
/// Starts audio-triggered vibration for specified controller(s). This function is the overloaded version.
/// </summary>
/// <param name="data">The PCM data.</param>
/// <param name="vibrateType">The controller(s) to enable vibration for:
/// * `0`: none
/// * `1`: left controller
/// * `2`: right controller
/// * `3`: left and right controllers
/// </param>
/// <param name="buffersize">The length of PCM data. Formula: (audioClip.samples)×(audioClip.channels).</param>
/// <param name="frequency">Audio sampling rate.</param>
/// <param name="channelMask">The number of channels.</param>
/// <param name="channelFlip">Whether to enable audio channel inversion:
/// * `Yes`: enable
/// * `No`: disable
/// Once audio channel inversion is enabled, the left controller vibrates with the audio data from the right channel, and vice versa.
/// </param>
/// <param name="sourceId">Returns the unique ID for controlling the corresponding vibration,
/// which will be used in `StartVibrateByCache`, `ClearVibrateByCache` or `StopControllerVCMotor`.</param>
[Obsolete("Please use SendHapticBuffer instead", true)]
public static int StartVibrateBySharem(float[] data, VibrateType vibrateType, int buffersize, int frequency, int channelMask, ChannelFlip channelFlip, ref int sourceId)
{
return -1;
}
/// @deprecated Use \ref SendHapticBuffer(VibrateType vibrateType, AudioClip audioClip, ChannelFlip channelFlip, ref int sourceId, CacheType cacheType) instead.
/// <summary>
/// Caches audio-triggered vibration data for specified controller(s).
/// @note The cached data can be extracted from the cache directory and then transmitted, which reduces resource consumption and improves service performance.
/// </summary>
/// <param name="audioClip">The path to the audio clip.</param>
/// <param name="vibrateType">The controller(s) to cache data for:
/// * `0`: none
/// * `1`: left controller
/// * `2`: right controller
/// * `3`: left and right controllers</param>
/// <param name="channelFlip">Whether to enable audio channel inversion:
/// * `Yes`: enable
/// * `No`: disable
/// Once audio channel inversion is enabled, the left controller vibrates with the audio data from the right channel, and vice versa.
/// </param>
/// <param name="cacheConfig">Whether to keep the controller vibrating while caching audio-based vibration data:
/// * `CacheAndVibrate`: cache and keep vibrating
/// * `CacheNoVibrate`: cache and stop vibrating
/// </param>
/// <param name="sourceId">Returns the unique ID for controlling the corresponding vibration,
/// which will be used in `StartVibrateByCache`, `ClearVibrateByCache` or `StopControllerVCMotor`.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
[Obsolete("Please use SendHapticBuffer instead", true)]
public static int SaveVibrateByCache(AudioClip audioClip, VibrateType vibrateType, ChannelFlip channelFlip, CacheConfig cacheConfig, ref int sourceId)
{
return -1;
}
/// @deprecated Use \ref SendHapticBuffer(VibrateType vibrateType, float[] pcmData, int buffersize, int frequency, int channelMask, ChannelFlip channelFlip, ref int sourceId, CacheType cacheType)
/// <summary>
/// Caches audio-triggered vibration data for specified controller(s). This function is the overloaded version.
/// @note The cached data can be extracted from the cache directory and then transmitted, which reduces resource consumption and improves service performance.
/// </summary>
/// <param name="data">The PCM data.</param>
/// <param name="vibrateType">The controller(s) to cache data for:
/// * `0`: none
/// * `1`: left controller
/// * `2`: right controller
/// * `3`: left and right controllers
/// </param>
/// <param name="buffersize">The length of PCM data. Formula: (audioClip.samples)×(audioClip.channels)</param>
/// <param name="frequency">Audio sampling rate.</param>
/// <param name="channelMask">The number of channels.</param>
/// <param name="channelFlip">Whether to enable audio channel inversion:
/// * `Yes`: enable
/// * `No`: disable
/// Once audio channel inversion is enabled, the left controller vibrates with the audio data from the right channel, and vice versa.
/// </param>
/// <param name="cacheConfig">Whether to keep the controller vibrating while caching audio-based vibration data:
/// * `CacheAndVibrate`: cache and keep vibrating
/// * `CacheNoVibrate`: cache and stop vibrating
/// </param>
/// <param name="sourceId">Returns the unique ID for controlling the corresponding vibration,
/// which will be used in `StartVibrateByCache`, `ClearVibrateByCache` or `StopControllerVCMotor`.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
[Obsolete("Please use SendHapticBuffer instead", true)]
public static int SaveVibrateByCache(float[] data, VibrateType vibrateType, int buffersize, int frequency, int channelMask, ChannelFlip channelFlip, CacheConfig cacheConfig, ref int sourceId)
{
return -1;
}
/// @deprecated Use \ref StartHapticBuffer instead.
/// <summary>
/// Plays cached audio-triggered vibration data.
/// </summary>
/// <param name="sourceId">The source ID returned by `StartVibrateBySharem` or `SaveVibrateByCache`.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
[Obsolete("Please use StartHapticBuffer instead", true)]
public static int StartVibrateByCache(int sourceId)
{
return -1;
}
/// @deprecated Use \ref StopHapticBuffer(clearCache) instead.
/// <summary>
/// Clears cached audio-triggered vibration data.
/// </summary>
/// <param name="sourceId">The source ID returned by `StartVibrateBySharem` or `SaveVibrateByCache`.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
[Obsolete("Please use StopHapticBuffer(clearCache) instead", true)]
public static int ClearVibrateByCache(int sourceId)
{
return -1;
}
public static int SetControllerEnableKey(bool isEnable, PxrControllerKeyMap Key)
{
return PXR_Plugin.Controller.UPxr_SetControllerEnableKey(isEnable, Key);
}
/// @deprecated Use \ref SendHapticBuffer(VibrateType vibrateType, TextAsset phfText, ChannelFlip channelFlip, float amplitudeScale, ref int sourceId) instead.
/// <summary>
/// Starts PHF-triggered vibration for specified controller(s). PHF stands for PICO haptic file.
/// </summary>
/// <param name="phfText">The path to the PHF file.</param>
/// <param name="sourceId">The source ID returned by `StartVibrateBySharem` or `SaveVibrateByCache`.</param>
/// <param name="vibrateType">The controller(s) to enable vibration for:
/// * `0`: none
/// * `1`: left controller
/// * `2`: right controller
/// * `3`: left and right controllers
/// </param>
/// <param name="channelFlip">Whether to enable audio channel inversion:
/// * `Yes`: enable
/// * `No`: disable
/// Once audio channel inversion is enabled, the left controller vibrates with the audio data from the right channel, and vice versa.</param>
/// <param name="amp">The vibration gain, the valid value range from `0` to `2`:
/// * `0`: no vibration
/// * `1`: standard amplitude
/// * `2`: 2×standard amplitude</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
[Obsolete("Please use SendHapticBuffer instead", true)]
public static int StartVibrateByPHF(TextAsset phfText, ref int sourceId, VibrateType vibrateType, ChannelFlip channelFlip, float amp)
{
return -1;
}
/// @deprecated Use \ref PauseHapticBuffer instead.
/// <summary>
/// Pauses PHF-triggered vibration.
/// </summary>
/// <param name="sourceId">The source ID returned by `StartVibrateBySharem` or `SaveVibrateByCache`.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
[Obsolete("Please use PauseHapticBuffer instead", true)]
public static int PauseVibrate(int sourceId)
{
return -1;
}
/// @deprecated Use \ref ResumeHapticBuffer instead.
/// <summary>
/// Resumes PHF-triggered vibration.
/// </summary>
/// <param name="sourceId">The source ID returned by `StartVibrateBySharem` or `SaveVibrateByCache`.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
[Obsolete("Please use ResumeHapticBuffer instead", true)]
public static int ResumeVibrate(int sourceId)
{
return -1;
}
/// @deprecated Use \ref UpdateHapticBuffer instead.
/// <summary>
/// Dynamically updates PHF and AudioClip vibration data.
/// </summary>
/// <param name="sourceId">The source ID returned by `StartVibrateBySharem` or `SaveVibrateByCache`.</param>
/// <param name="vibrateType">The controller(s) to update PHF and AudioClip vibration data for:
/// * `0`: none
/// * `1`: left controller
/// * `2`: right controller
/// * `3`: left and right controllers
/// </param>
/// <param name="channelFlip">Whether to enable audio channel inversion:
/// * `Yes`: enable
/// * `No`: disable
/// Once audio channel inversion is enabled, the left controller vibrates with the audio data from the right channel, and vice versa.</param>
/// <param name="amp">The vibration gain, the valid value range from `0` to `2`:
/// * `0`: no vibration
/// * `1`: standard amplitude
/// * `2`: 2×standard amplitude</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
[Obsolete("Please use UpdateHapticBuffer instead", true)]
public static int UpdateVibrateParams(int sourceId, VibrateType vibrateType, ChannelFlip channelFlip, float amp)
{
return -1;
}
/// <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 instead", true)]
public static int GetBodyTrackingPose(double predictTime, ref BodyTrackerResult bodyTrackerResult)
{
return -1;
}
/// <summary>
/// Gets the number of PICO Motion Trackers currently connected and their IDs.
/// </summary>
/// <param name="state">The number and IDs of connected PICO Motion Trackers.</param>
[Obsolete("Please use GetMotionTrackerConnectStateWithSN instead", true)]
public static int GetMotionTrackerConnectStateWithID(ref PxrMotionTracker1ConnectState state)
{
return -1;
}
/// <summary>
/// Gets the battery of a specified PICO Motion Traker.
/// </summary>
/// <param name="trackerId">The ID of the motion tracker to get battery for.</param>
/// <param name="battery">The motion tracker's battery. Value range: [0,5]. The smaller the value, the lower the battery level.</param>
[Obsolete("Please use GetMotionTrackerBatteryWithSN instead", true)]
public static int GetMotionTrackerBattery(int trackerId, ref int battery)
{
return 0;
}
/// <summary>
/// Gets whether the PICO Motion Tracker has completed calibration.
/// </summary>
/// <param name="calibrated">Indicates the calibration status:
/// `0`: calibration uncompleted
/// `1`: calibration completed
/// </param>
[Obsolete("Please use GetBodyTrackingState instead", true)]
public static int GetMotionTrackerCalibState(ref int calibrated)
{
return -1;
}
/// <summary>
/// Sets a body tracking mode for PICO Motion Tracker. If this API is not called, the mode defaults to leg tracking.
/// @note If you want to set the mode to full-body tracking, you must call this API before calling `OpenMotionTrackerCalibrationAPP`.
/// </summary>
/// <param name="mode">Selects a body tracking mode from the following:
/// * Motion Tracker 1.0 `0`: leg tracking, nodes numbered 0 to 15 in `BodyTrackerRole` enum will return data.
/// * Motion Tracker 1.0 `1`: full-body tracking, nodes numbered 0 to 23 in `BodyTrackerRole` enum will return data.
/// * Motion Tracker 2.0 `0`: full-body tracking, nodes numbered 0 to 23 in `BodyTrackerRole` enum will return data. Low latency.
/// * Motion Tracker 2.0 `1`: full-body tracking, nodes numbered 0 to 23 in `BodyTrackerRole` enum will return data. High latency.
/// </param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("Please use StartBodyTracking instead", true)]
public static int SetBodyTrackingMode(BodyTrackingMode mode)
{
return 1;
}
/// <summary>
/// Sets bone lengths for different parts of the avatar. The data will be sent to PICO'S algorithm to make the avatar's poses more accurate.
/// </summary>
/// <param name="boneLength">Sets the bone lengths for different parts of the avatar. See the `BodyTrackingBoneLength` for details.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("Please use StartBodyTracking instead", true)]
public static int SetBodyTrackingBoneLength(BodyTrackingBoneLength boneLength)
{
return 1;
}
/// <summary>
/// Sends a haptic impulse to specified controller(s) to trigger vibration.
/// @note To stop vibration, call this API again and set both `amplitude` and `duration` to `0`.
/// </summary>
/// <param name="vibrateType">The controller(s) to send the haptic impulse to:
/// * `None`
/// * `LeftController`
/// * `RightController`
/// * `BothController`
/// </param>
/// <param name="amplitude">Vibration amplitude, which ranges from `0` to `1`. The higher the value, the stronger the vibration amplitude.</param>
/// <param name="duration">Vibration duration, which ranges from `0` to `65535` ms.</param>
/// <param name="frequency">Vibration frequency, which ranges from `50` to `500` Hz.</param>
public static void SendHapticImpulse(VibrateType vibrateType, float amplitude, int duration, int frequency = 150)
{
switch (vibrateType)
{
case VibrateType.None:
break;
case VibrateType.LeftController:
PXR_Plugin.Controller.UPxr_SetControllerVibrationEvent(0, frequency, amplitude, duration);
break;
case VibrateType.RightController:
PXR_Plugin.Controller.UPxr_SetControllerVibrationEvent(1, frequency, amplitude, duration);
break;
case VibrateType.BothController:
PXR_Plugin.Controller.UPxr_SetControllerVibrationEvent(0, frequency, amplitude, duration);
PXR_Plugin.Controller.UPxr_SetControllerVibrationEvent(1, frequency, amplitude, duration);
break;
default:
break;
}
}
/// <summary>
/// Sends a buffer of haptic data to specified controller(s) to trigger vibration.
/// </summary>
/// <param name="vibrateType">The controller(s) to send the haptic data to:
/// * `None`
/// * `LeftController`
/// * `RightController`
/// * `BothController`
/// </param>
/// <param name="audioClip">The audio data pulled from the audio file stored in the AudioClip component is used as the haptic data.</param>
/// <param name="channelFlip">Determines whether to enable audio channel inversion. Once enabled, the left controller vibrates with the audio data from the right channel, and vice versa.
/// * `Yes`: enable
/// * `No`: disable
/// </param>
/// <param name="sourceId">Returns the unique ID for controlling the corresponding buffered haptic,
/// which will be used in `PauseHapticBuffer`, `ResumeHapticBuffer`, `UpdateHapticBuffer`, or `StopHapticBuffer`.</param>
/// <param name="cacheType">Whether to keep the controller vibrating while caching haptic data:
/// * `DontCache`: don't cache.
/// * `CacheAndVibrate`: cache and keep vibrating.
/// * `CacheNoVibrate`: cache and stop vibrating. Call `StartHapticBuffer` to start haptic after caching the data.
/// @note If not defined, `DontCache` will be passed by default.
/// </param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
/**
* \overload int SendHapticBuffer(VibrateType vibrateType, AudioClip audioClip, ChannelFlip channelFlip, ref int sourceId, CacheType cacheType)
*/
public static int SendHapticBuffer(VibrateType vibrateType, AudioClip audioClip, ChannelFlip channelFlip, ref int sourceId, CacheType cacheType = CacheType.DontCache)
{
if (audioClip == null)
{
return 0;
}
float[] data = new float[audioClip.samples * audioClip.channels];
int buffersize = audioClip.samples * audioClip.channels;
audioClip.GetData(data, 0);
int sampleRate = audioClip.frequency;
int channelMask = audioClip.channels;
if (cacheType == CacheType.DontCache)
{
return PXR_Plugin.Controller.UPxr_StartVibrateBySharem(data, (int)vibrateType, buffersize, sampleRate, channelMask, 32, (int)channelFlip, ref sourceId);
}
else
{
return PXR_Plugin.Controller.UPxr_SaveVibrateByCache(data, (int)vibrateType, buffersize, sampleRate, channelMask, 32, (int)channelFlip, (int)cacheType, ref sourceId);
}
}
/// <summary>
/// Sends a buffer of haptic data to specified controller(s) to trigger vibration.
/// </summary>
/// <param name="vibrateType">The controller(s) to send the haptic data to:
/// * `None`
/// * `LeftController`
/// * `RightController`
/// * `BothController`
/// </param>
/// <param name="pcmData">The PCM data is converted from the audio file stored in the AudioClip component in the Unity Engine.</param>
/// <param name="buffersize">The length of PCM data. Calculation formula: (audioClip.samples)×(audioClip.channels). Sample refers to the data in each channel.</param>
/// <param name="frequency">Sample rate. The higher the sample rate, the closer the recorded signal is to the original.</param>
/// <param name="channelMask">The number of channels that play the haptic data.</param>
/// <param name="channelFlip">Determines whether to enable audio channel inversion. Once enabled, the left controller vibrates with the audio data from the right channel, and vice versa.
/// * `Yes`: enable
/// * `No`: disable
/// </param>
/// <param name="sourceId">Returns the unique ID for controlling the corresponding buffered haptic,
/// which will be used in `PauseHapticBuffer`, `ResumeHapticBuffer`, `UpdateHapticBuffer`, or `StopHapticBuffer`.</param>
/// <param name="cacheType">Whether to keep the controller vibrating while caching haptic data:
/// * `DontCache`: don't cache.
/// * `CacheAndVibrate`: cache and keep vibrating.
/// * `CacheNoVibrate`: cache and stop vibrating. Call `StartHapticBuffer` to start vibration after caching the data.
/// @note If not defined, `DontCache` will be passed by default.
/// </param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
/**
* \overload int SendHapticBuffer(VibrateType vibrateType, float[] pcmData, int buffersize, int frequency, int channelMask, ChannelFlip channelFlip, ref int sourceId, CacheType cacheType)
*/
public static int SendHapticBuffer(VibrateType vibrateType, float[] pcmData, int buffersize, int frequency, int channelMask, ChannelFlip channelFlip, ref int sourceId, CacheType cacheType = CacheType.DontCache)
{
if (cacheType == CacheType.DontCache)
{
return PXR_Plugin.Controller.UPxr_StartVibrateBySharem(pcmData, (int)vibrateType, buffersize, frequency, channelMask, 32, (int)channelFlip, ref sourceId);
}
else
{
return PXR_Plugin.Controller.UPxr_SaveVibrateByCache(pcmData, (int)vibrateType, buffersize, frequency, channelMask, 32, (int)channelFlip, (int)cacheType, ref sourceId);
}
}
/// <summary>
/// Sends a buffer of haptic data to specified controller(s) to trigger vibration.
/// </summary>
/// <param name="vibrateType">The controller(s) to send the haptic data to:
/// * `None`
/// * `LeftController`
/// * `RightController`
/// * `BothController`
/// </param>
/// <param name="phfText">The PHF file (.json) that contains haptic data.</param>
/// <param name="channelFlip">Determines whether to enable audio channel inversion. Once enabled, the left controller vibrates with the audio data from the right channel, and vice versa.
/// * `Yes`: enable
/// * `No`: disable
/// <param name="amplitudeScale">Vibration amplitude, the higher the amplitude, the stronger the haptic effect. The valid value range from `0` to `2`:
/// * `0`: no vibration
/// * `1`: standard amplitude
/// * `2`: 2×standard amplitude
/// </param>
/// <param name="sourceId">Returns the unique ID for controlling the corresponding buffered haptic,
/// which will be used in `PauseHapticBuffer`, `ResumeHapticBuffer`, `UpdateHapticBuffer`, or `StopHapticBuffer`.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
public static int SendHapticBuffer(VibrateType vibrateType, TextAsset phfText, ChannelFlip channelFlip, float amplitudeScale, ref int sourceId)
{
return PXR_Plugin.Controller.UPxr_StartVibrateByPHF(phfText.text, phfText.text.Length, ref sourceId, (int)vibrateType, (int)channelFlip, amplitudeScale);
}
/// <summary>
/// Stops a specified buffered haptic.
/// </summary>
/// <param name="sourceId">The source ID returned by `SendHapticBuffer`. Set it to the target source ID to stop a specific buffered haptic,
/// or set it to `0` to stop all buffered haptics. If not defined, `0` will be passed to stop all buffered haptics by default.</param>
/// <param name="clearCache">Determines whether to clear the cached data of the specified haptic.
/// If not defined, `false` will be passed to keep the cached data by default.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
public static int StopHapticBuffer(int sourceId = 0, bool clearCache = false)
{
if (clearCache)
{
PXR_Plugin.Controller.UPxr_ClearVibrateByCache(sourceId);
}
return PXR_Plugin.Controller.UPxr_StopControllerVCMotor(sourceId);
}
/// <summary>
/// Pauses a specified buffered haptic.
/// </summary>
/// <param name="sourceId">The source ID returned by `SendHapticBuffer`.
/// Set it to the target source ID to stop a specific buffered haptic.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
public static int PauseHapticBuffer(int sourceId)
{
return PXR_Plugin.Controller.UPxr_PauseVibrate(sourceId);
}
/// <summary>
/// Resumes a paused buffered haptic.
/// </summary>
/// <param name="sourceId">The source ID returned by `SendHapticBuffer`.
/// Set it to the target source ID to resume a specific buffered haptic.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
public static int ResumeHapticBuffer(int sourceId)
{
return PXR_Plugin.Controller.UPxr_ResumeVibrate(sourceId);
}
/// <summary>
/// Starts a specified buffered haptic.
/// @note If you pass `CacheNoVibrate` in `SendHapticBuffer`, call this API if you want to start haptic after caching the data.
/// </summary>
/// <param name="sourceId">The source ID returned by `SendHapticBuffer` when there is cached data for the haptic.</param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
public static int StartHapticBuffer(int sourceId)
{
return PXR_Plugin.Controller.UPxr_StartVibrateByCache(sourceId);
}
/// <summary>
/// Updates the settings for a specified buffered haptic.
/// </summary>
/// <param name="sourceId">The source ID returned by `SendHapticBuffer`.
/// Set it to the target source ID to update a specific buffered haptic.</param>
/// <param name="vibrateType">The controller(s) that the vibration is applied to:
/// * `None`
/// * `LeftController`
/// * `RightController`
/// * `BothController`
/// </param>
/// <param name="channelFlip">Determines whether to enable audio channel inversion. Once enabled, the left controller vibrates with the audio data from the right channel, and vice versa.
/// * `Yes`: enable
/// * `No`: disable
/// <param name="amplitudeScale">Vibration amplitude, the higher the amplitude, the stronger the haptic effect. The valid value range from `0` to `2`:
/// * `0`: no vibration
/// * `1`: standard amplitude
/// * `2`: 2×standard amplitude
/// </param>
/// <returns>
/// * `0`: success
/// * `-1`: failure
/// </returns>
public static int UpdateHapticBuffer(int sourceId, VibrateType vibrateType, ChannelFlip channelFlip, float amplitudeScale)
{
return PXR_Plugin.Controller.UPxr_UpdateVibrateParams(sourceId, (int)vibrateType, (int)channelFlip, amplitudeScale);
}
/// <summary>Creates a haptic stream.</summary>
/// <param name="phfVersion">The version of the PICO haptic file (PHF) that the stream uses.</param>
/// <param name="frameDurationMs">Interframe space, which is the amount of time in milliseconds existing between the transmissions of frames.</param>
/// <param name="hapticInfo">The information about this haptic stream you create.</param>
/// <param name="speed">The streaming speed.</param>
/// <param name="id">Returns the ID of the stream.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("CreateHapticStream is not supported", true)]
public static int CreateHapticStream(string phfVersion, UInt32 frameDurationMs, ref VibrateInfo hapticInfo, float speed, ref int id)
{
return 1;
}
/// <summary>
/// Writes haptic data to a specified stream.
/// </summary>
/// <param name="id">The ID of the target stream.</param>
/// <param name="frames">The data contained in the PICO haptic file (PHF).</param>
/// <param name="numFrames">The number of frames.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("WriteHapticStream is not supported", true)]
public static int WriteHapticStream(int id, ref PxrPhfParamsNum frames, UInt32 numFrames)
{
return 1;
}
/// <summary>
/// Sets a transmission speed for a specified haptic stream.
/// </summary>
/// <param name="id">The ID of the stream.</param>
/// <param name="speed">The transmission speed to set for the stream.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("SetHapticStreamSpeed is not supported", true)]
public static int SetHapticStreamSpeed(int id, float speed)
{
return 1;
}
/// <summary>
/// Gets the transmission speed of a specified haptic stream.
/// </summary>
/// <param name="id">The ID of the stream.</param>
/// <param name="speed">Returns the stream's transmission speed.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("GetHapticStreamSpeed is not supported", true)]
public static int GetHapticStreamSpeed(int id, ref float speed)
{
return 1;
}
/// <summary>
/// Gets the No. of the frame that the controller currently plays.
/// </summary>
/// <param name="id">The ID of the haptic stream that triggers the vibration.</param>
/// <param name="frameSequence">Returns the current frame's sequence No.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("GetHapticStreamCurrentFrameSequence is not supported", true)]
public static int GetHapticStreamCurrentFrameSequence(int id, ref UInt64 frameSequence)
{
return 1;
}
/// <summary>
/// Starts the transmission of a specified haptic stream.
/// </summary>
/// <param name="source_id">The ID of the haptic stream.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("StartHapticStream is not supported", true)]
public static int StartHapticStream(int source_id)
{
return 1;
}
/// <summary>
/// Stops the transmission of a specified haptic stream.
/// </summary>
/// <param name="source_id">The ID of the haptic stream.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("StopHapticStream is not supported", true)]
public static int StopHapticStream(int source_id)
{
return 1;
}
/// <summary>
/// Removes a specified haptic stream.
/// </summary>
/// <param name="source_id">The ID of the stream.</param>
/// <returns>
/// * `0`: successGetMotionTrackerCalibState
/// * `1`: failure
/// </returns>
[Obsolete("RemoveHapticStream is not supported", true)]
public static int RemoveHapticStream(int source_id)
{
return 1;
}
/// <summary>
/// Parses the haptic data in a specified PICO haptic file (PHF).
/// </summary>
/// <param name="phfText">The PICO haptic file (.json) to parse.</param>
[Obsolete("AnalysisHapticStreamPHF is not supported", true)]
public static PxrPhfFile AnalysisHapticStreamPHF(TextAsset phfText)
{
String str = phfText.text;
return JsonMapper.ToObject<PxrPhfFile>(str);
}
/// <summary>
/// Recenters the controller on PICO G3.
/// </summary>
[Obsolete("ResetController is not supported", true)]
public static void ResetController()
{}
/// <summary>
/// Sets arm model parameters on PICO G3.
/// </summary>
/// <param name="gazetype">Gaze type, which is used to define the way of getting the HMD data.</param>
/// <param name="armmodeltype">Arm model type</param>
/// <param name="elbowHeight">The elbow's height, which changes the arm's length.Value range: (0.0f, 0.2f). The default value is 0.0f.</param>
/// <param name="elbowDepth">The elbow's depth, which changes the arm's position.Value range: (0.0f, 0.2f). The default value is 0.0f.</param>
/// <param name="pointerTiltAngle">The ray's tilt angle. Value range: (0.0f, 30.0f). The default value is 0.0f.</param>
[Obsolete("SetArmModelParameters is not supported", true)]
public static void SetArmModelParameters(PxrGazeType gazetype, PxrArmModelType armmodeltype, float elbowHeight, float elbowDepth, float pointerTiltAngle)
{ }
/// <summary>
/// Gets the current user's dominant hand in the system on PICO G3.
/// </summary>
/// <param name="deviceID"></param>
public static void GetControllerHandness(ref int deviceID)
{
PXR_Plugin.Controller.UPxr_GetControllerHandness(ref deviceID);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,95 @@
#if !PICO_OPENXR_SDK
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR;
namespace Unity.XR.PXR
{
[Serializable]
public class PXR_LateLatching : MonoBehaviour
{
#if UNITY_2020_3_OR_NEWER
private Camera m_LateLatchingCamera;
static XRDisplaySubsystem s_DisplaySubsystem = null;
static List<XRDisplaySubsystem> s_DisplaySubsystems = new List<XRDisplaySubsystem>();
private void Awake()
{
m_LateLatchingCamera = GetComponent<Camera>();
}
private void OnEnable()
{
List<XRDisplaySubsystem> displaySubsystems = new List<XRDisplaySubsystem>();
#if UNITY_6000_0_OR_NEWER
SubsystemManager.GetSubsystems(displaySubsystems);
#else
SubsystemManager.GetInstances(displaySubsystems);
#endif
Debug.Log("PXR_U OnEnable() displaySubsystems.Count = " + displaySubsystems.Count);
for (int i = 0; i < displaySubsystems.Count; i++)
{
s_DisplaySubsystem = displaySubsystems[i];
}
}
private void OnDisable()
{
}
void Update()
{
if (s_DisplaySubsystem == null)
{
List<XRDisplaySubsystem> displaySubsystems = new List<XRDisplaySubsystem>();
#if UNITY_6000_0_OR_NEWER
SubsystemManager.GetSubsystems(displaySubsystems);
#else
SubsystemManager.GetInstances(displaySubsystems);
#endif
if (displaySubsystems.Count > 0)
{
s_DisplaySubsystem = displaySubsystems[0];
}
}
if (null == s_DisplaySubsystem)
return;
s_DisplaySubsystem.MarkTransformLateLatched(m_LateLatchingCamera.transform, XRDisplaySubsystem.LateLatchNode.Head);
}
#if !UNITY_EDITOR && UNITY_2021_2_OR_NEWER
private void OnPreRender()
{
s_DisplaySubsystem.BeginRecordingIfLateLatched(m_LateLatchingCamera);
}
private void OnPostRender()
{
s_DisplaySubsystem.EndRecordingIfLateLatched(m_LateLatchingCamera);
}
#endif
private void FixedUpdate()
{
}
private void LateUpdate()
{
}
#endif
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,762 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
namespace Unity.XR.PXR
{
public class PXR_MotionTracking
{
#region Eye Tracking
//Eye Tracking
public const int PXR_EYE_TRACKING_API_VERSION = 1;
/// <summary>
/// Wants eye tracking service for the current app.
/// </summary>
/// <returns>Returns `0` for success and other values for failure.</returns>
[Obsolete("WantEyeTrackingService is not supported..", true)]
public static int WantEyeTrackingService()
{
return -1;
}
/// <summary>
/// Gets whether the current device supports eye tracking.
/// </summary>
/// <param name="supported">
/// Returns a bool indicating whether eye tracking is supported:
/// * `true`: supported
/// * `false`: not supported
/// </param>
/// <param name="supportedModesCount">
/// Returns the number of eye tracking modes supported by the current device.
/// </param>
/// <param name="supportedModes">
/// Returns the eye tracking modes supported by the current device.
/// </param>
/// <returns>Returns `0` for success and other values for failure.</returns>
public static int GetEyeTrackingSupported(ref bool supported, ref int supportedModesCount, ref EyeTrackingMode[] supportedModes)
{
return PXR_Plugin.MotionTracking.UPxr_GetEyeTrackingSupported(ref supported, ref supportedModesCount, ref supportedModes);
}
/// <summary>
/// Starts eye tracking.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="startInfo">Passes the information for starting eye tracking.
/// </param>
/// <returns>Returns `0` for success and other values for failure.</returns>
public static int StartEyeTracking(ref EyeTrackingStartInfo startInfo)
{
startInfo.SetVersion(PXR_EYE_TRACKING_API_VERSION);
return PXR_Plugin.MotionTracking.UPxr_StartEyeTracking1(ref startInfo);
}
/// <summary>
/// Stops eye tracking.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="stopInfo">Passes the information for stopping eye tracking. Currently, you do not need to pass anything.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
public static int StopEyeTracking(ref EyeTrackingStopInfo stopInfo)
{
stopInfo.SetVersion(PXR_EYE_TRACKING_API_VERSION);
return PXR_Plugin.MotionTracking.UPxr_StopEyeTracking1(ref stopInfo);
}
/// <summary>
/// Gets the state of eye tracking.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="isTracking">Returns a bool that indicates whether eye tracking is working:
/// * `true`: eye tracking is working
/// * `false`: eye tracking has been stopped
/// </param>
/// <param name="state">Returns the eye tracking state information, including the eye tracking mode and eye tracking state code.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
public static int GetEyeTrackingState(ref bool isTracking, ref EyeTrackingState state)
{
state.SetVersion(PXR_EYE_TRACKING_API_VERSION);
return PXR_Plugin.MotionTracking.UPxr_GetEyeTrackingState(ref isTracking, ref state);
}
/// <summary>
/// Gets eye tracking data.
/// @note Only supported by PICO Neo3 Pro Eye, PICO 4 Pro, and PICO 4 Enterprise.
/// </summary>
/// <param name="getInfo">Specifies the eye tracking data you want.</param>
/// <param name="data">Returns the desired eye tracking data.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
public static int GetEyeTrackingData(ref EyeTrackingDataGetInfo getInfo, ref EyeTrackingData data)
{
getInfo.SetVersion(PXR_EYE_TRACKING_API_VERSION);
data.SetVersion(PXR_EYE_TRACKING_API_VERSION);
return PXR_Plugin.MotionTracking.UPxr_GetEyeTrackingData1(ref getInfo, ref data);
}
//PICO4E
/// <summary>
/// Gets the opennesses of the left and right eyes.
/// @note
/// - Only supported by PICO 4 Enterprise.
/// - To use this API, you need to add `<meta-data android:name="pvr.app.et_tob_advance" android:value="true"/>` to the app's AndroidManifest.xml file.
/// </summary>
/// <param name="leftEyeOpenness">The openness of the left eye, which is a float value ranges from `0.0` to `1.0`. `0.0` indicates completely closed, `1.0` indicates completely open.</param>
/// <param name="rightEyeOpenness">The openness of the right eye, which is a float value ranges from `0.0` to `1.0`. `0.0` indicates completely closed, `1.0` indicates completely open.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
public static int GetEyeOpenness(ref float leftEyeOpenness, ref float rightEyeOpenness)
{
return PXR_Plugin.MotionTracking.UPxr_GetEyeOpenness(ref leftEyeOpenness, ref rightEyeOpenness);
}
/// <summary>
/// Gets the information about the pupils of both eyes.
/// @note
/// - Only supported by PICO 4 Enterprise.
/// - To use this API, you need to add `<meta-data android:name="pvr.app.et_tob_advance" android:value="true"/>` to the app's AndroidManifest.xml file.
/// </summary>
/// <param name="eyePupilPosition">Returns the diameters and positions of both pupils.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
public static int GetEyePupilInfo(ref EyePupilInfo eyePupilPosition)
{
return PXR_Plugin.MotionTracking.UPxr_GetEyePupilInfo(ref eyePupilPosition);
}
/// <summary>
/// Gets the pose of the left and right eyes.
/// @note
/// - Only supported by PICO 4 Enterprise.
/// - To use this API, you need to add `<meta-data android:name="pvr.app.et_tob_advance" android:value="true"/>` to the app's AndroidManifest.xml file.
/// </summary>
/// <param name="timestamp">Returns the timestamp (unit: nanosecond) of the eye pose information.</param>
/// <param name="leftEyePose">Returns the position and rotation of the left eye.</param>
/// <param name="rightPose">Returns the position and rotation of the right eye.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
public static int GetPerEyePose(ref long timestamp, ref Posef leftEyePose, ref Posef rightPose)
{
return PXR_Plugin.MotionTracking.UPxr_GetPerEyePose(ref timestamp, ref leftEyePose, ref rightPose);
}
/// <summary>
/// Gets whether the left and right eyes blinked.
/// @note
/// - Only supported by PICO 4 Enterprise.
/// - To use this API, you need to add `<meta-data android:name="pvr.app.et_tob_advance" android:value="true"/>` to the app's AndroidManifest.xml file.
/// </summary>
/// <param name="timestamp">Returns the timestamp (in nanoseconds) of the eye blink information.</param>
/// <param name="isLeftBlink">Returns whether the left eye blinked:
/// - `true`: blinked (the user's left eye is closed, which will usually open again immediately to generate a blink event)
/// - `false`: didn't blink (the user's left eye is open)
/// </param>
/// <param name="isRightBlink">Returns whether the right eye blined:
/// - `true`: blinked (the user's right eye is closed, which will usually open again immediately to generate a blink event)
/// - `false`: didn't blink (the user's right eye is open)
/// </param>
/// <returns>Returns `0` for success and other values for failure.</returns>
public static int GetEyeBlink(ref long timestamp, ref bool isLeftBlink, ref bool isRightBlink)
{
return PXR_Plugin.MotionTracking.UPxr_GetEyeBlink(ref timestamp, ref isLeftBlink, ref isRightBlink);
}
#endregion
#region Face Tracking
//Face Tracking
public const int PXR_FACE_TRACKING_API_VERSION = 1;
/// <summary>
/// Wants face tracking service for the current app.
/// </summary>
/// <returns>Returns `0` for success and other values for failure.</returns>
[Obsolete("WantFaceTrackingService is not supported..", true)]
public static int WantFaceTrackingService()
{
return -1;
}
/// <summary>
/// Gets whether the current device supports face tracking.
/// </summary>
/// <param name="supported">Indicates whether the device supports face tracking:
/// * `true`: support
/// * `false`: not support
/// </param>
/// <param name="supportedModesCount">Returns the total number of face tracking modes supported by the device.</param>
/// <param name="supportedModes">Returns the specific face tracking modes supported by the device.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
[Obsolete("GetFaceTrackingSupported is not supported..", true)]
public static unsafe int GetFaceTrackingSupported(ref bool supported, ref int supportedModesCount, ref FaceTrackingMode[] supportedModes)
{
// return PXR_Plugin.MotionTracking.UPxr_GetFaceTrackingSupported(ref supported, ref supportedModesCount, ref supportedModes);
return -1;
}
/// <summary>
/// Starts face tracking.
/// @note Supported by PICO 4 Pro and PICO 4 Enterprise.
/// </summary>
/// <param name="startInfo">Passes the information for starting face tracking.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
[Obsolete("StartFaceTracking is not supported..", true)]
public static int StartFaceTracking(ref FaceTrackingStartInfo startInfo)
{
// startInfo.SetVersion(PXR_FACE_TRACKING_API_VERSION);
// return PXR_Plugin.MotionTracking.UPxr_StartFaceTracking(ref startInfo);
return -1;
}
/// <summary>
/// Stops face tracking.
/// @note Supported by PICO 4 Pro and PICO 4 Enterprise.
/// </summary>
/// <param name="stopInfo">Passes the information for stopping face tracking.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
[Obsolete("StopFaceTracking is not supported..", true)]
public static int StopFaceTracking(ref FaceTrackingStopInfo stopInfo)
{
// stopInfo.SetVersion(PXR_FACE_TRACKING_API_VERSION);
// return PXR_Plugin.MotionTracking.UPxr_StopFaceTracking(ref stopInfo);
return -1;
}
/// <summary>
/// Gets the state of face tracking.
/// @note Supported by PICO 4 Pro and PICO 4 Enterprise.
/// </summary>
/// <param name="isTracking">Returns a bool indicating whether face tracking is working:
/// * `true`: face tracking is working
/// * `false`: face tracking has been stopped
/// </param>
/// <param name="state">Returns the state of face tracking, including the face tracking mode and face tracking state code.
/// </param>
/// <returns>Returns `0` for success and other values for failure.</returns>
[Obsolete("GetFaceTrackingState is not supported..", true)]
public static int GetFaceTrackingState(ref bool isTracking, ref FaceTrackingState state)
{
// state.SetVersion(PXR_FACE_TRACKING_API_VERSION);
// return PXR_Plugin.MotionTracking.UPxr_GetFaceTrackingState(ref isTracking, ref state);
return -1;
}
/// <summary>
/// Gets face tracking data.
/// @note Supported by PICO 4 Pro and PICO 4 Enterprise.
/// </summary>
/// <param name="getInfo">Specifies the face tracking data you want.</param>
/// <param name="data">Returns the desired face tracking data.</param>
/// <returns>Returns `0` for success and other values for failure.</returns>
[Obsolete("GetFaceTrackingData is not supported..", true)]
public static int GetFaceTrackingData(ref FaceTrackingDataGetInfo getInfo, ref FaceTrackingData data)
{
// getInfo.SetVersion(PXR_FACE_TRACKING_API_VERSION);
// data.SetVersion(PXR_FACE_TRACKING_API_VERSION);
// return PXR_Plugin.MotionTracking.UPxr_GetFaceTrackingData1(ref getInfo, ref data);
return -1;
}
#endregion
#region Body Tracking
/// <summary>
/// A callback function that notifies calibration exceptions.
/// The user then needs to recalibrate with PICO Motion Tracker.
/// </summary>
[Obsolete("BodyTrackingAbnormalCalibrationData is not supported..", true)]
public static Action<int, int> BodyTrackingAbnormalCalibrationData;
/// <summary>You can use this callback function to receive the status code and error code for body tracking.</summary>
/// <returns>
/// - `BodyTrackingStatusCode`: The status code.
/// - `BodyTrackingErrorCode`: The error code.
/// </returns>
[Obsolete("BodyTrackingStateError is not supported..", true)]
public static Action<BodyTrackingStatusCode, BodyTrackingErrorCode> BodyTrackingStateError;
/// <summary>You can use this callback function to get notified when the action status of a tracked bone node changes.</summary>
/// <returns>
/// - `int`: Returns the bone No., and only `7` (`LEFT_ANKLE`) and `8` (`RIGHT_ANKLE`) are available currently. You can use the change of the status of the left and right ankles to get the foot-down action of the left and right feet.
/// - `BodyActionList`: Receiving the `PxrFootDownAction` event indicates that the left and/or right foot has stepped on the floor.
/// </returns>
[Obsolete("BodyTrackingAction is not supported..", true)]
public static Action<int, BodyActionList> BodyTrackingAction;
/// <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()
{
return PXR_Plugin.MotionTracking.UPxr_StartMotionTrackerCalibApp();
}
/// <summary>Gets whether the current device supports body tracking.</summary>
/// <param name="supported">Returns whether the current device supports body tracking:
/// - `true`: support
/// - `false`: not support
/// </param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int GetBodyTrackingSupported(ref bool supported)
{
return PXR_Plugin.MotionTracking.UPxr_GetBodyTrackingSupported(ref supported);
}
/// <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>
[Obsolete("Please use StartBodyTracking(BodyJointSet JointSet, BodyTrackingBoneLength boneLength)")]
public static int StartBodyTracking(BodyTrackingMode mode, BodyTrackingBoneLength boneLength)
{
return StartBodyTracking(BodyJointSet.BODY_JOINT_SET_BODY_FULL_START,boneLength);
}
/// <summary>
/// >Starts body tracking.
/// </summary>
/// <param name="JointSet">Specifies the set of body joints to be tracked.</param>
/// <param name="boneLength">Specifies lengths (unit: cm) for the bones of the avatar. 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)
{
return PXR_Plugin.MotionTracking.UPxr_StartBodyTracking(JointSet,boneLength);
}
/// <summary>Stops body tracking.</summary>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int StopBodyTracking()
{
return PXR_Plugin.MotionTracking.UPxr_StopBodyTracking();
}
/// <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>
[Obsolete("Please use GetBodyTrackingState(ref bool isTracking, ref BodyTrackingStatus state)")]
public static int GetBodyTrackingState(ref bool isTracking, ref BodyTrackingState state)
{
BodyTrackingStatus bs2 = new BodyTrackingStatus();
int ret = GetBodyTrackingState(ref isTracking, ref bs2);
state.stateCode=bs2.stateCode;
state.errorCode=(BodyTrackingErrorCode)bs2.message;
return ret;
}
/// <summary>
/// >Gets the state of body tracking.
/// </summary>
/// <param name="isTracking">Indicates whether the PICO Motion Tracker is tracking the body normally:
/// - `true`: is tracking
/// - `false`: tracking lost
/// </param>
/// <param name="state">Returns the current status of body tracking.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int GetBodyTrackingState(ref bool isTracking, ref BodyTrackingStatus state)
{
return PXR_Plugin.MotionTracking.UPxr_GetBodyTrackingState(ref isTracking, ref state);
}
/// <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 static int GetBodyTrackingData(ref BodyTrackingGetDataInfo getInfo, ref BodyTrackingData data)
{
return PXR_Plugin.MotionTracking.UPxr_GetBodyTrackingData(ref getInfo, ref data);
}
#endregion
#region Motion Tracker
//Motion Tracker
/// <summary>
/// You can use this callback function to get notified when the connection state of PICO Motion Tracker changes.
/// For connection status, `0` indicates "disconnected" and `1` indicates "connected".
/// </summary>
[Obsolete("Deprecated",true)]
public static Action<int, int> MotionTrackerNumberOfConnections;
/// <summary>
/// You can use this callback function to get notified when the battery level of PICO Motion Tracker changes.
/// </summary>
/// <Returns>
/// The ID and battery level of the PICO Motion Tracker.
/// - For PICO Motion Tracker (Beta), the value range of battery level is [0,5].
/// `0` indicates a low battery, which can affect the tracking accuracy.
/// </returns>
[Obsolete("Deprecated",true)]
public static Action<int, int> MotionTrackerBatteryLevel;
/// <summary>
/// You can use this callback function to get the key actions of the motion tracker.
/// </summary>
[Obsolete("Deprecated",true)]
public static Action<MotionTrackerEventData> MotionTrackerKeyAction;
/// <summary>
/// You can use this callback function to get notified if the tracking mode changes.
/// - `0`: body tracking
/// - `1`: object tracking
/// </summary>
[Obsolete("Deprecated",true)]
public static Action<MotionTrackerMode> MotionTrackingModeChangedAction;
/// <summary>
/// You can use the callback function to whether if PICO Motion Trackers are successfully connected to your PICO headset.
/// </summary>
public static Action<RequestMotionTrackerCompleteEventData> RequestMotionTrackerCompleteAction;
/// <summary>
/// You can use this callback function to be notified when the connection state of PICO Motion Tracker changes.
/// </summary>
public static Action<long, int> MotionTrackerConnectionAction;
/// <summary>
/// You can use this callback function to receive events for the Power key of PICO Motion Trackers.
/// </summary>
public static Action<long, bool> MotionTrackerPowerKeyAction;
/// <summary>Gets the number of trackers currently connected and their serial numbers.</summary>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
[Obsolete("Deprecated.Please use MotionTrackerConnectionAction instead", true)]
public static int GetMotionTrackerConnectStateWithSN(ref MotionTrackerConnectState connectState)
{
return -1;
}
/// <summary>Gets the type of the PICO Motion Tracker connected.</summary>
/// <returns>The type of the motion tracker (beta or official).</summary>
[Obsolete("Deprecated",true)]
public static MotionTrackerType GetMotionTrackerDeviceType()
{
return MotionTrackerType.MT_2;
}
/// <summary>Checks whether the current tracking mode and the number of motion trackers connected are as wanted.
/// If not, a panel will appear to let the user switch the tracking mode and perform calibration accordingly.</summary>
/// <param name="mode">Specifies the wanted tracking mode.</summary>
/// <param name="number">Specifies the expected number of motion trackers. Value range: [0,3].
/// - If you set `mode` to `BodyTracking`, you do not need to set this parameter as it will not work even if you set it.
/// - If you set `mode` to `MotionTracking`, the default value of this parameter will be 0, and you can select a value from range [0,3].</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
[Obsolete("Deprecated.Please use CheckMotionTrackerNumber instead")]
public static int CheckMotionTrackerModeAndNumber(MotionTrackerMode mode, MotionTrackerNum number = MotionTrackerNum.ONE)
{
return CheckMotionTrackerNumber(number);
}
/// <summary>
/// Checks whether the current tracking mode and the number of motion trackers connected are as expected.
/// If not, a panel will appear to let the user switch the tracking mode and perform calibration accordingly.
/// </summary>
/// <param name="number">Specifies the expected number of motion trackers. Value range: [0,3]. You can get the result from callback `RequestMotionTrackerCompleteAction`.
/// </param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int CheckMotionTrackerNumber(MotionTrackerNum number)
{
return PXR_Plugin.MotionTracking.UPxr_CheckMotionTrackerNumber((int)number);
}
/// <summary>Gets the current tracking mode of the PICO Motion Tracker connected.</summary>
/// <returns>The current tracking mode.</summary>
[Obsolete("Deprecated")]
public static MotionTrackerMode GetMotionTrackerMode()
{
return MotionTrackerMode.MotionTracking;
}
/// <summary>Gets the location of a PICO Motion Tracker which is set to the "motion tracking" mode.</summary>
/// <param name="trackerSN">Specifies the serial number of the motion tracker to get position for. You can pass only one serial number in one request.</param>
/// <param name="locations">Returns the location of the specified motion tracker.</param>
/// <param name="confidence">Returns the confidence of the returned data.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
[Obsolete("Deprecated.Please use GetMotionTrackerLocation instead",true)]
public static int GetMotionTrackerLocations(TrackerSN trackerSN, ref MotionTrackerLocations locations, ref MotionTrackerConfidence confidence, double predictTime = 0)
{
return -1;
}
/// <summary>
/// Gets the location of a PICO Motion Tracker which is set to the "motion tracking" mode.
/// </summary>
/// <param name="trackerid">Specifies the serial number of the motion tracker to get position for. You can pass only one serial number in one request.</param>
/// <param name="location">Returns the location of the specified motion tracker.</param>
/// <param name="isValidPose">Whether the returned pose data is valid:
/// - `true`: valid
/// - `false`: invalid
/// </param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int GetMotionTrackerLocation(long trackerid,ref MotionTrackerLocation location,ref bool isValidPose)
{
return PXR_Plugin.MotionTracking.UPxr_GetMotionTrackerLocation(trackerid, ref location, ref isValidPose);
}
/// <summary>
/// Gets the battery of a PICO Motion Tracker.
/// </summary>
/// <param name="trackerid">Specifies the serial number of the motion tracker to get battery for.</param>
/// <param name="battery">Returns the battery of the motion tracker. Value range: [0,1]. The higher the value, the higher the current battery.</param>
/// <param name="charger">Returns the charging status of the motion tracker.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int GetMotionTrackerBattery(long trackerid,ref float battery, ref XrBatteryChargingState charger)
{
return PXR_Plugin.MotionTracking.UPxr_GetMotionTrackerBatteryState(trackerid, ref battery, ref charger);
}
#endregion
#region Motion Tracker For External Device
/// <summary>You can use this callback function to get notified when the connection state of the external device changes.</summary>
/// <returns>The connection state of the external device.</returns>
[Obsolete("Deprecated.Please use ExpandDeviceConnectionAction instead",true)]
public static Action<ExtDevConnectEventData> ExtDevConnectAction;
/// <summary>You can use this callback function to get notified when the battery level and charging status of the external device changes.</summary>
/// <returns>The current better level and charging status of the external device.</returns>
[Obsolete("Deprecated.Please use ExpandDeviceBatteryAction instead",true)]
public static Action<ExtDevBatteryEventData> ExtDevBatteryAction;
/// <summary>
/// You need to listen for this event to call the `GetExtDevTrackerByPassData` API:
/// - When receiving `1`, it is necessary to call the `PXR_GetExtDevTrackerByPassData` API to obtain the data passed through.
/// - When receiving `0`, stop obtaining the data passed through.
/// </summary>
public static Action<int> ExtDevPassDataAction;
/// <summary>You can use this callback function to get notified when the state of the connection between the PICO Motion Tracker and an external device changes.</summary>
/// <returns>The series number of the motion tracker connected to the external device and the connection state (`0`: disconnected; `1`: connected).</returns>
public static Action<long, int> ExpandDeviceConnectionAction;
/// <summary>You can use this callback function to get notified when the battery level and charging status of the external device changes.</summary>
/// <returns>The current better level and charging status of the external device.</returns>
public static Action<ExpandDeviceBatteryEventData> ExpandDeviceBatteryAction;
/// <summary>Gets the connection state of the external device.</summary>
/// <param name="connectState">Returns the connection state of the external device.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
[Obsolete("Deprecated.Please use ExpandDeviceConnectionAction instead",true)]
public static int GetExtDevTrackerConnectState(ref ExtDevTrackerConnectState connectState)
{
return -1;
}
/// <summary>Sets vibration for the external device.</summary>
/// <param name="motorVibrate">Specifies vibration settings.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
[Obsolete("Deprecated.Please use SetExpandDeviceVibrate instead",true)]
public static int SetExtDevTrackerMotorVibrate(ref ExtDevTrackerMotorVibrate motorVibrate)
{
return -1;
}
/// <summary>Sets the state for data passthrough-related APIs.</summary>
/// <param name="state">Specifies the state of data passthrough-related APIs according to actual needs:
/// Before calling `SetExpandDeviceCustomData` and `GetExpandDeviceCustomData`, set `state` to `true` to enable these APIs, or set `state` to `false` to disable these APIs.
/// </param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int SetExtDevTrackerPassDataState(bool state)
{
return PXR_Plugin.MotionTracking.UPxr_SetExpandDeviceCustomDataCapability(state);
}
/// <summary>Sets data passthrough for the external device. The protocol is defined by yourself according to your own hardware.
/// There is no correspondence between the `set` and `get`-related methods themselves.</summary>
/// <param name="passData">When PICO SDK's APIs are unable to meet your needs, you can define custom protocols and place them in the `passData` parameter.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
[Obsolete("Deprecated.Please use SetExpandDeviceCustomData instead",true)]
public static int SetExtDevTrackerByPassData(ref ExtDevTrackerPassData passData)
{
return -1;
}
/// <summary>Gets the data passed through for an external device.</summary>
/// <param name="passData">Returns the details of the data passed through.</param>
/// <param name="realLength">Returns the number of `passData` arrays filled by the underlying layer.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
[Obsolete("Deprecated.Please use GetExpandDeviceCustomData instead",true)]
public static int GetExtDevTrackerByPassData(ref ExtDevTrackerPassDataArray passData, ref int realLength)
{
return -1;
}
/// <summary>Gets the battery level of the external device.</summary>
/// <param name="trackerSN">Specifies the serial number of the external device the get battery level for.</param>
/// <param name="battery">Returns the current battery level of the external device. Value range: [0,10].</param>
/// <param name="charger">Returns whether the external device is charging:
/// - `0`: not charging
/// - `1`: charging
/// </param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
[Obsolete("Deprecated.Please use GetExpandDeviceBattery instead",true)]
public static int GetExtDevTrackerBattery(ref TrackerSN trackerSN, ref int battery, ref int charger)
{
return -1;
}
/// <summary>Gets the key values of the external device.</summary>
/// <param name="trackerSN">Specifies the serial number of the external device to get key values for.</param>
/// <param name="keyData">Returns the key values of the specified external device.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
[Obsolete("Deprecated",true)]
public static int GetExtDevTrackerKeyData(ref TrackerSN trackerSN, ref ExtDevTrackerKeyData keyData)
{
return -1;
}
/// <summary>
/// Sets vibration for the external device. The vibration command is passed to the external device via the PICO Motion Tracker connected to it.
/// </summary>
/// <param name="deviceid">Specifies the serial number of the external device.</param>
/// <param name="motorVibrate">Specifies vibration settings.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int SetExpandDeviceVibrate(long deviceid, ExpandDeviceVibrate motorVibrate)
{
return PXR_Plugin.MotionTracking.UPxr_SetExpandDeviceVibrate(deviceid, motorVibrate);
}
/// <summary>
/// Gets the array of serial numbers of the external devices connected to PICO Motion Trackers.
/// </summary>
/// <param name="deviceArray">Returns the array of serial numbers.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int GetExpandDevice(out long[] deviceArray)
{
return PXR_Plugin.MotionTracking.UPxr_GetExpandDevice(out deviceArray);
}
/// <summary>
/// Gets the battery level of the external device.
/// </summary>
/// <param name="deviceid">Specifies the serial number of the external device to get battery level for.</param>
/// <param name="battery">Returns the current battery level of the external device. Value range: [0,1]. The higher the value, the higher the battery.</param>
/// <param name="charger">Returns the charging status of the external device.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int GetExpandDeviceBattery(long deviceid, ref float battery, ref XrBatteryChargingState charger)
{
return PXR_Plugin.MotionTracking.UPxr_GetExpandDeviceBattery(deviceid, ref battery, ref charger);
}
/// <summary>
/// Gets the data passed from external devices.
/// </summary>
/// <param name="dataArray">Returns the array of data passed from external devices.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int GetExpandDeviceCustomData(out List<ExpandDevicesCustomData> dataArray)
{
return PXR_Plugin.MotionTracking.UPxr_GetExpandDeviceCustomData(out dataArray);
}
/// <summary>
/// Sets the data to be passed to external devices. The protocol is defined by yourself according to your own hardware.
/// </summary>
/// <param name="dataArray">Specifies the array of data to be passed to external devices.</param>
/// <returns>
/// - `0`: success
/// - `1`: failure
/// </returns>
public static int SetExpandDeviceCustomData(ref ExpandDevicesCustomData[] dataArray)
{
return PXR_Plugin.MotionTracking.UPxr_SetExpandDeviceCustomData(ref dataArray);
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,861 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.XR;
namespace Unity.XR.PXR
{
[Obsolete("PXR_OverLay is obsolete and will be removed in the next version. Please use PXR_CompositionLayer instead.", false)]
public class PXR_OverLay : MonoBehaviour, IComparable<PXR_OverLay>
{
private const string TAG = "[PXR_CompositeLayers]";
public static List<PXR_OverLay> Instances = new List<PXR_OverLay>();
[NonSerialized]
public int overlayIndex;
public int layerDepth;
public int imageIndex = 0;
public OverlayType overlayType = OverlayType.Overlay;
public OverlayShape overlayShape = OverlayShape.Quad;
public TextureType textureType = TextureType.ExternalSurface;
public Transform overlayTransform;
public Camera xrRig;
public Texture[] layerTextures = new Texture[2] { null, null };
public bool isPremultipliedAlpha = false;
public bool isDynamic = false;
public int[] overlayTextureIds = new int[2];
public Matrix4x4[] mvMatrixs = new Matrix4x4[2];
public Vector3[] modelScales = new Vector3[2];
public Quaternion[] modelRotations = new Quaternion[2];
public Vector3[] modelTranslations = new Vector3[2];
public Quaternion[] cameraRotations = new Quaternion[2];
public Vector3[] cameraTranslations = new Vector3[2];
public Camera[] overlayEyeCamera = new Camera[2];
public bool overrideColorScaleAndOffset = false;
public Vector4 colorScale = Vector4.one;
public Vector4 colorOffset = Vector4.zero;
// Eac
public Vector3 offsetPosLeft = Vector3.zero;
public Vector3 offsetPosRight = Vector3.zero;
public Vector4 offsetRotLeft = new Vector4(0, 0, 0, 1);
public Vector4 offsetRotRight = new Vector4(0, 0, 0, 1);
public EACModelType eacModelType = EACModelType.Eac360;
public float overlapFactor = 1.0f;
public ulong timestamp = 0;
private Vector4 overlayLayerColorScaleDefault = Vector4.one;
private Vector4 overlayLayerColorOffsetDefault = Vector4.zero;
public bool isExternalAndroidSurface = false;
public bool isExternalAndroidSurfaceDRM = false;
public Surface3DType externalAndroidSurface3DType = Surface3DType.Single;
#region Blurred Quad
public BlurredQuadMode blurredQuadMode = BlurredQuadMode.SmallWindow;
public float blurredQuadScale = 0.5f;
public float blurredQuadShift = 0.01f;
public float blurredQuadFOV = 61.05f;
public float blurredQuadIPD = 0.064f;
#endregion
public IntPtr externalAndroidSurfaceObject = IntPtr.Zero;
public delegate void ExternalAndroidSurfaceObjectCreated();
public ExternalAndroidSurfaceObjectCreated externalAndroidSurfaceObjectCreated = null;
// 360
public float radius = 0; // >0
// ImageRect
public bool useImageRect = false;
public TextureRect textureRect = TextureRect.StereoScopic;
public DestinationRect destinationRect = DestinationRect.Default;
public Rect srcRectLeft = new Rect(0, 0, 1, 1);
public Rect srcRectRight = new Rect(0, 0, 1, 1);
public Rect dstRectLeft = new Rect(0, 0, 1, 1);
public Rect dstRectRight = new Rect(0, 0, 1, 1);
public PxrRecti imageRectLeft;
public PxrRecti imageRectRight;
// LayerBlend
public bool useLayerBlend = false;
public PxrBlendFactor srcColor = PxrBlendFactor.PxrBlendFactorOne;
public PxrBlendFactor dstColor = PxrBlendFactor.PxrBlendFactorOne;
public PxrBlendFactor srcAlpha = PxrBlendFactor.PxrBlendFactorOne;
public PxrBlendFactor dstAlpha = PxrBlendFactor.PxrBlendFactorOne;
public float[] colorMatrix = new float[18] {
1,0,0, // left
0,1,0,
0,0,1,
1,0,0, // right
0,1,0,
0,0,1,
};
public bool isClones = false;
public bool isClonesToNew = false;
public bool enableSubmitLayer = true;
public PXR_OverLay originalOverLay;
public IntPtr layerSubmitPtr = IntPtr.Zero;
[HideInInspector]
public SuperSamplingMode supersamplingMode = SuperSamplingMode.None;
[HideInInspector]
public SuperSamplingEnhance supersamplingEnhance = SuperSamplingEnhance.None;
[HideInInspector]
public SharpeningMode sharpeningMode = SharpeningMode.None;
[HideInInspector]
public SharpeningEnhance sharpeningEnhance = SharpeningEnhance.None;
//Super Resolution
public bool superResolution;
public bool normalSupersampling;
public bool qualitySupersampling;
public bool fixedFoveatedSupersampling;
public bool normalSharpening;
public bool qualitySharpening;
public bool fixedFoveatedSharpening;
public bool selfAdaptiveSharpening;
private bool toCreateSwapChain = false;
private bool toCopyRT = false;
private bool copiedRT = false;
private int eyeCount = 2;
private UInt32 imageCounts = 0;
private PxrLayerParam overlayParam = new PxrLayerParam();
private struct NativeTexture
{
public Texture[] textures;
};
private NativeTexture[] nativeTextures;
private static Material cubeM;
private IntPtr leftPtr = IntPtr.Zero;
private IntPtr rightPtr = IntPtr.Zero;
private static Material textureM;
public HDRFlags hdr = HDRFlags.None;
public int CompareTo(PXR_OverLay other)
{
return layerDepth.CompareTo(other.layerDepth);
}
protected void Awake()
{
xrRig = Camera.main;
Instances.Add(this);
if (null == xrRig.gameObject.GetComponent<PXR_OverlayManager>())
{
xrRig.gameObject.AddComponent<PXR_OverlayManager>();
}
overlayEyeCamera[0] = xrRig;
overlayEyeCamera[1] = xrRig;
overlayTransform = GetComponent<Transform>();
#if UNITY_ANDROID && !UNITY_EDITOR
if (overlayTransform != null)
{
MeshRenderer render = overlayTransform.GetComponent<MeshRenderer>();
if (render != null)
{
render.enabled = false;
}
}
#endif
if (!isClones)
{
InitializeBuffer();
}
}
private void Start()
{
if (isClones)
{
InitializeBuffer();
}
if (PXR_Manager.Instance == null)
{
return;
}
Camera[] cam = PXR_Manager.Instance.GetEyeCamera();
if (cam[0] != null && cam[0].enabled)
{
RefreshCamera(cam[0], cam[0]);
}
else if (cam[1] != null && cam[2] != null)
{
RefreshCamera(cam[1], cam[2]);
}
}
public void RefreshCamera(Camera leftCamera, Camera rightCamera)
{
overlayEyeCamera[0] = leftCamera;
overlayEyeCamera[1] = rightCamera;
}
private void InitializeBuffer()
{
if (!isExternalAndroidSurface && !isClones)
{
if (null == layerTextures[0] && null == layerTextures[1])
{
PLog.e(TAG, " The left and right images are all empty!");
return;
}
else if (null == layerTextures[0] && null != layerTextures[1])
{
layerTextures[0] = layerTextures[1];
}
else if (null != layerTextures[0] && null == layerTextures[1])
{
layerTextures[1] = layerTextures[0];
}
overlayParam.width = (uint)layerTextures[1].width;
overlayParam.height = (uint)layerTextures[1].height;
}
else
{
overlayParam.width = 1024;
overlayParam.height = 1024;
}
PXR_CompositionLayer.overlayID++;
overlayIndex = PXR_CompositionLayer.overlayID;
overlayParam.layerId = overlayIndex;
overlayParam.layerShape = (PXR_CompositionLayer.OverlayShape)(overlayShape == 0 ? OverlayShape.Quad : overlayShape);
overlayParam.layerType = (PXR_CompositionLayer.OverlayType)overlayType;
overlayParam.arraySize = 1;
overlayParam.mipmapCount = 1;
overlayParam.sampleCount = 1;
overlayParam.layerFlags = 0;
if (OverlayShape.Cubemap == overlayShape)
{
overlayParam.faceCount = 6;
if (cubeM == null)
cubeM = new Material(Shader.Find("PXR_SDK/PXR_CubemapBlit"));
}
else
{
overlayParam.faceCount = 1;
if (textureM == null)
textureM = new Material(Shader.Find("PXR_SDK/PXR_Texture2DBlit"));
}
if (GraphicsDeviceType.Vulkan == SystemInfo.graphicsDeviceType)
{
if (ColorSpace.Linear == QualitySettings.activeColorSpace)
{
overlayParam.format = (UInt64)ColorForamt.VK_FORMAT_R8G8B8A8_SRGB;
}
else
{
overlayParam.format = (UInt64)ColorForamt.VK_FORMAT_R8G8B8A8_UNORM;
if (OverlayShape.Cubemap == overlayShape)
{
cubeM.SetFloat("_Gamma", 2.2f);
}
else
{
textureM.SetFloat("_Gamma", 2.2f);
}
}
}
else
{
overlayParam.format = (UInt64)ColorForamt.GL_SRGB8_ALPHA8;
}
if (isClones)
{
if (null != originalOverLay)
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlagSharedImagesBetweenLayers;
leftPtr = Marshal.AllocHGlobal(Marshal.SizeOf(originalOverLay.overlayIndex));
rightPtr = Marshal.AllocHGlobal(Marshal.SizeOf(originalOverLay.overlayIndex));
Marshal.WriteInt64(leftPtr, originalOverLay.overlayIndex);
Marshal.WriteInt64(rightPtr, originalOverLay.overlayIndex);
overlayParam.leftExternalImages = leftPtr;
overlayParam.rightExternalImages = rightPtr;
isExternalAndroidSurface = originalOverLay.isExternalAndroidSurface;
isDynamic = originalOverLay.isDynamic;
overlayParam.width = (UInt32)Mathf.Min(overlayParam.width, originalOverLay.overlayParam.width);
overlayParam.height = (UInt32)Mathf.Min(overlayParam.height, originalOverLay.overlayParam.height);
}
else
{
PLog.e(TAG, "In clone state, originalOverLay cannot be empty!");
}
}
if (isExternalAndroidSurface)
{
if (isExternalAndroidSurfaceDRM)
{
overlayParam.layerFlags |= (UInt32)(PxrLayerCreateFlags.PxrLayerFlagAndroidSurface | PxrLayerCreateFlags.PxrLayerFlagProtectedContent);
}
else
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlagAndroidSurface;
}
if (Surface3DType.LeftRight == externalAndroidSurface3DType)
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlag3DLeftRightSurface;
}
else if (Surface3DType.TopBottom == externalAndroidSurface3DType)
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlag3DTopBottomSurface;
}
overlayParam.layerLayout = (PXR_CompositionLayer.LayerLayout)LayerLayout.Mono;
}
else
{
if (!isDynamic)
{
overlayParam.layerFlags |= (UInt32)PxrLayerCreateFlags.PxrLayerFlagStaticImage;
}
if ((layerTextures[0] != null && layerTextures[1] != null && layerTextures[0] == layerTextures[1]) || null == layerTextures[1])
{
eyeCount = 1;
overlayParam.layerLayout = (PXR_CompositionLayer.LayerLayout)LayerLayout.Mono;
}
else
{
eyeCount = 2;
overlayParam.layerLayout = (PXR_CompositionLayer.LayerLayout)LayerLayout.Stereo;
}
toCreateSwapChain = true;
}
PLog.i(TAG, $"UPxr_CreateLayer() overlayParam.layerId={overlayParam.layerId}, layerShape={overlayParam.layerShape}, layerType={overlayParam.layerType}, width={overlayParam.width}, height={overlayParam.height}, layerFlags={overlayParam.layerFlags}, format={overlayParam.format}, layerLayout={overlayParam.layerLayout}.");
PXR_Plugin.Render.UPxr_CreateLayerParam(overlayParam);
}
public void CreateExternalSurface(PXR_OverLay overlayInstance)
{
#if UNITY_ANDROID && !UNITY_EDITOR
if (IntPtr.Zero != overlayInstance.externalAndroidSurfaceObject)
{
return;
}
PXR_Plugin.Render.UPxr_GetLayerAndroidSurface(overlayInstance.overlayIndex, 0, ref overlayInstance.externalAndroidSurfaceObject);
PLog.i(TAG, string.Format("CreateExternalSurface: Overlay Type:{0}, LayerDepth:{1}, SurfaceObject:{2}", overlayInstance.overlayType, overlayInstance.overlayIndex, overlayInstance.externalAndroidSurfaceObject));
if (IntPtr.Zero == overlayInstance.externalAndroidSurfaceObject || null == overlayInstance.externalAndroidSurfaceObjectCreated)
{
return;
}
overlayInstance.externalAndroidSurfaceObjectCreated();
#endif
}
public void UpdateCoords()
{
if (null == overlayTransform || !overlayTransform.gameObject.activeSelf || null == overlayEyeCamera[0] || null == overlayEyeCamera[1])
{
return;
}
for (int i = 0; i < mvMatrixs.Length; i++)
{
mvMatrixs[i] = overlayEyeCamera[i].worldToCameraMatrix * overlayTransform.localToWorldMatrix;
if (overlayTransform is RectTransform uiTransform)
{
var rect = uiTransform.rect;
var lossyScale = overlayTransform.lossyScale;
modelScales[i] = new Vector3(rect.width * lossyScale.x,
rect.height * lossyScale.y, 1);
modelTranslations[i] = uiTransform.TransformPoint(rect.center);
}
else
{
modelScales[i] = overlayTransform.lossyScale;
modelTranslations[i] = overlayTransform.position;
}
modelRotations[i] = overlayTransform.rotation;
cameraRotations[i] = overlayEyeCamera[i].transform.rotation;
cameraTranslations[i] = overlayEyeCamera[i].transform.position;
}
}
public bool CreateTexture()
{
if (!toCreateSwapChain)
{
return false;
}
if (null == nativeTextures)
nativeTextures = new NativeTexture[eyeCount];
for (int i = 0; i < eyeCount; i++)
{
int ret = PXR_Plugin.Render.UPxr_GetLayerImageCount(overlayIndex, (EyeType)i, ref imageCounts);
if (ret != 0 || imageCounts < 1)
{
return false;
}
if (null == nativeTextures[i].textures)
{
nativeTextures[i].textures = new Texture[imageCounts];
}
for (int j = 0; j < imageCounts; j++)
{
IntPtr ptr = IntPtr.Zero;
PXR_Plugin.Render.UPxr_GetLayerImagePtr(overlayIndex, (EyeType)i, j, ref ptr);
if (IntPtr.Zero == ptr)
{
return false;
}
Texture texture;
if (OverlayShape.Cubemap == overlayShape)
{
texture = Cubemap.CreateExternalTexture((int)overlayParam.width, TextureFormat.RGBA32, false, ptr);
}
else
{
texture = Texture2D.CreateExternalTexture((int)overlayParam.width, (int)overlayParam.height, TextureFormat.RGBA32, false, true, ptr);
}
if (null == texture)
{
return false;
}
nativeTextures[i].textures[j] = texture;
}
}
toCreateSwapChain = false;
toCopyRT = true;
copiedRT = false;
FreePtr();
return true;
}
public bool CopyRT()
{
if (isClones)
{
return true;
}
if (!toCopyRT)
{
return copiedRT;
}
if (!isDynamic && copiedRT)
{
return copiedRT;
}
if (null == nativeTextures)
{
return false;
}
if (enableSubmitLayer)
{
PXR_Plugin.Render.UPxr_GetLayerNextImageIndexByRender(overlayIndex, ref imageIndex);
}
for (int i = 0; i < eyeCount; i++)
{
Texture nativeTexture = nativeTextures[i].textures[imageIndex];
if (null == nativeTexture || null == layerTextures[i])
continue;
RenderTexture texture = layerTextures[i] as RenderTexture;
if (OverlayShape.Cubemap == overlayShape && null == layerTextures[i] as Cubemap)
{
return false;
}
for (int f = 0; f < (int)overlayParam.faceCount; f++)
{
if (QualitySettings.activeColorSpace == ColorSpace.Gamma && texture != null && texture.format == RenderTextureFormat.ARGB32)
{
Graphics.CopyTexture(layerTextures[i], f, 0, nativeTexture, f, 0);
}
else
{
RenderTextureDescriptor rtDes = new RenderTextureDescriptor((int)overlayParam.width, (int)overlayParam.height, RenderTextureFormat.ARGB32, 0);
rtDes.msaaSamples = (int)overlayParam.sampleCount;
rtDes.useMipMap = true;
rtDes.autoGenerateMips = false;
rtDes.sRGB = true;
RenderTexture renderTexture = RenderTexture.GetTemporary(rtDes);
if (!renderTexture.IsCreated())
{
renderTexture.Create();
}
renderTexture.DiscardContents();
if (OverlayShape.Cubemap == overlayShape)
{
cubeM.SetInt("_d", f);
Graphics.Blit(layerTextures[i], renderTexture, cubeM);
}
else
{
textureM.mainTexture = texture;
textureM.SetPass(0);
textureM.SetInt("_premultiply", isPremultipliedAlpha ? 1 : 0);
Graphics.Blit(layerTextures[i], renderTexture, textureM);
}
Graphics.CopyTexture(renderTexture, 0, 0, nativeTexture, f, 0);
RenderTexture.ReleaseTemporary(renderTexture);
}
}
copiedRT = true;
}
return copiedRT;
}
public void SetTexture(Texture texture, bool dynamic)
{
if (isExternalAndroidSurface)
{
PLog.w(TAG, "Not support setTexture !");
return;
}
if (isClones)
{
return;
}
else
{
foreach (PXR_OverLay overlay in PXR_OverLay.Instances)
{
if (overlay.isClones && null != overlay.originalOverLay && overlay.originalOverLay.overlayIndex == overlayIndex)
{
overlay.DestroyLayer();
overlay.isClonesToNew = true;
}
}
}
toCopyRT = false;
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overlayIndex);
ClearTexture();
for (int i = 0; i < layerTextures.Length; i++)
{
layerTextures[i] = texture;
}
isDynamic = dynamic;
InitializeBuffer();
if (!isClones)
{
foreach (PXR_OverLay overlay in PXR_OverLay.Instances)
{
if (overlay.isClones && overlay.isClonesToNew)
{
overlay.originalOverLay = this;
overlay.InitializeBuffer();
overlay.isClonesToNew = false;
}
}
}
}
private void FreePtr()
{
if (leftPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(leftPtr);
leftPtr = IntPtr.Zero;
}
if (rightPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(rightPtr);
rightPtr = IntPtr.Zero;
}
if (layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(layerSubmitPtr);
layerSubmitPtr = IntPtr.Zero;
}
}
public void OnDestroy()
{
DestroyLayer();
Instances.Remove(this);
}
public void DestroyLayer()
{
if (isExternalAndroidSurface)
{
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overlayIndex);
externalAndroidSurfaceObject = IntPtr.Zero;
ClearTexture();
return;
}
if (!isClones)
{
List<PXR_OverLay> toDestroyClones = new List<PXR_OverLay>();
foreach (PXR_OverLay overlay in Instances)
{
if (overlay.isClones && null != overlay.originalOverLay && overlay.originalOverLay.overlayIndex == overlayIndex)
{
toDestroyClones.Add(overlay);
}
}
foreach (PXR_OverLay overLay in toDestroyClones)
{
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overLay.overlayIndex);
ClearTexture();
}
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overlayIndex);
}
else
{
if (null != originalOverLay && Instances.Contains(originalOverLay))
{
PXR_Plugin.Render.UPxr_DestroyLayerByRender(overlayIndex);
}
}
ClearTexture();
}
private void ClearTexture()
{
FreePtr();
if (isExternalAndroidSurface || null == nativeTextures || isClones)
{
return;
}
for (int i = 0; i < eyeCount; i++)
{
if (null == nativeTextures[i].textures)
{
continue;
}
for (int j = 0; j < imageCounts; j++)
DestroyImmediate(nativeTextures[i].textures[j]);
}
nativeTextures = null;
}
public void SetLayerColorScaleAndOffset(Vector4 scale, Vector4 offset)
{
colorScale = scale;
colorOffset = offset;
}
public void SetEACOffsetPosAndRot(Vector3 leftPos, Vector3 rightPos, Vector4 leftRot, Vector4 rightRot)
{
offsetPosLeft = leftPos;
offsetPosRight = rightPos;
offsetRotLeft = leftRot;
offsetRotRight = rightRot;
}
public void SetEACFactor(float factor)
{
overlapFactor = factor;
}
public Vector4 GetLayerColorScale()
{
if (!overrideColorScaleAndOffset)
{
return overlayLayerColorScaleDefault;
}
return colorScale;
}
public Vector4 GetLayerColorOffset()
{
if (!overrideColorScaleAndOffset)
{
return overlayLayerColorOffsetDefault;
}
return colorOffset;
}
public PxrRecti getPxrRectiLeft(bool left)
{
if (left)
{
imageRectLeft.x = (int)(overlayParam.width * srcRectLeft.x);
imageRectLeft.y = (int)(overlayParam.height * srcRectLeft.y);
imageRectLeft.width = (int)(overlayParam.width * Mathf.Min(srcRectLeft.width, 1 - srcRectLeft.x));
imageRectLeft.height = (int)(overlayParam.height * Mathf.Min(srcRectLeft.height, 1 - srcRectLeft.y));
return imageRectLeft;
}
else
{
imageRectRight.x = (int)(overlayParam.width * srcRectRight.x);
imageRectRight.y = (int)(overlayParam.height * srcRectRight.y);
imageRectRight.width = (int)(overlayParam.width * Mathf.Min(srcRectRight.width, 1 - srcRectRight.x));
imageRectRight.height = (int)(overlayParam.height * Mathf.Min(srcRectRight.height, 1 - srcRectRight.y));
return imageRectRight;
}
}
public UInt32 getHDRFlags()
{
UInt32 hdrFlags = 0;
if (!isExternalAndroidSurface)
{
return hdrFlags;
}
switch (hdr)
{
case HDRFlags.HdrPQ:
hdrFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagColorSpaceHdrPQ;
break;
case HDRFlags.HdrHLG:
hdrFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagColorSpaceHdrHLG;
break;
default:
break;
}
return hdrFlags;
}
public enum HDRFlags
{
None,
HdrPQ,
HdrHLG,
}
public enum OverlayShape
{
Quad = 1,
Cylinder = 2,
Equirect = 4,
Cubemap = 5,
Eac = 6,
Fisheye = 7,
BlurredQuad = 9
}
public enum OverlayType
{
Overlay = 0,
Underlay = 1
}
public enum TextureType
{
ExternalSurface,
DynamicTexture,
StaticTexture
}
public enum LayerLayout
{
Stereo = 0,
DoubleWide = 1,
Array = 2,
Mono = 3
}
public enum Surface3DType
{
Single = 0,
LeftRight,
TopBottom
}
public enum TextureRect
{
MonoScopic,
StereoScopic,
Custom
}
public enum DestinationRect
{
Default,
Custom
}
public enum EACModelType
{
Eac360 = 0,
Eac360ViewPort = 1,
Eac180 = 4,
Eac180ViewPort = 5,
}
public enum ColorForamt
{
VK_FORMAT_R8G8B8A8_UNORM = 37,
VK_FORMAT_R8G8B8A8_SRGB = 43,
GL_SRGB8_ALPHA8 = 0x8c43,
GL_RGBA8 = 0x8058
}
public enum BlurredQuadMode
{
SmallWindow,
Immersion
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: daeec670ce18c8d488f9f5b2e51c817b
timeCreated: 1590405833
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,214 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.XR.PXR
{
public class PXR_ScreenFade : MonoBehaviour
{
[Tooltip("The gradient of time.")]
public float gradientTime = 5.0f;
[Tooltip("Basic color.")]
public Color fadeColor = new Color(0.0f, 0.0f, 0.0f, 1.0f);
[Tooltip("The default value is 4000.")]
private int renderQueue = 4000;
private MeshRenderer gradientMeshRenderer;
private MeshFilter gradientMeshFilter;
private Material gradientMaterial = null;
private bool isGradient = false;
private float currentAlpha;
private float nowFadeAlpha;
private List<Vector3> verts;
private List<int> indices;
private int N = 5;
void Awake()
{
CreateFadeMesh();
SetCurrentAlpha(0);
}
void OnEnable()
{
StartCoroutine(ScreenFade());
}
void OnDestroy()
{
DestoryGradientMesh();
}
private void CreateFadeMesh()
{
verts = new List<Vector3>();
indices = new List<int>();
gradientMaterial = new Material(Shader.Find("PXR_SDK/PXR_Fade"));
gradientMeshFilter = gameObject.AddComponent<MeshFilter>();
gradientMeshRenderer = gameObject.AddComponent<MeshRenderer>();
CreateModel();
}
public void SetCurrentAlpha(float alpha)
{
currentAlpha = alpha;
SetAlpha();
}
IEnumerator ScreenFade()
{
float nowTime = 0.0f;
while (nowTime < gradientTime)
{
nowTime += Time.deltaTime;
nowFadeAlpha = Mathf.Lerp(1.0f, 0, Mathf.Clamp01(nowTime / gradientTime));
SetAlpha();
yield return null;
}
}
private void SetAlpha()
{
Color color = fadeColor;
color.a = Mathf.Max(currentAlpha, nowFadeAlpha);
isGradient = color.a > 0;
if (gradientMaterial != null)
{
gradientMaterial.color = color;
gradientMaterial.renderQueue = renderQueue;
gradientMeshRenderer.material = gradientMaterial;
gradientMeshRenderer.enabled = isGradient;
}
}
void CreateModel()
{
for (float i = -N / 2f; i <= N / 2f; i++)
{
for (float j = -N / 2f; j <= N / 2f; j++)
{
verts.Add(new Vector3(i, j, -N / 2f));
}
}
for (float i = -N / 2f; i <= N / 2f; i++)
{
for (float j = -N / 2f; j <= N / 2f; j++)
{
verts.Add(new Vector3(N / 2f, j, i));
}
}
for (float i = -N / 2f; i <= N / 2f; i++)
{
for (float j = -N / 2f; j <= N / 2f; j++)
{
verts.Add(new Vector3(i, N / 2f, j));
}
}
for (float i = -N / 2f; i <= N / 2f; i++)
{
for (float j = -N / 2f; j <= N / 2f; j++)
{
verts.Add(new Vector3(-N / 2f, j, i));
}
}
for (float i = -N / 2f; i <= N / 2f; i++)
{
for (float j = -N / 2f; j <= N / 2f; j++)
{
verts.Add(new Vector3(i, j, N / 2f));
}
}
for (float i = -N / 2f; i <= N / 2f; i++)
{
for (float j = -N / 2f; j <= N / 2f; j++)
{
verts.Add(new Vector3(i, -N / 2f, j));
}
}
for (int i = 0; i < verts.Count; i++)
{
verts[i] = verts[i].normalized * 0.7f;
}
CreateMakePos(0);
CreateMakePos(1);
CreateMakePos(2);
OtherMakePos(3);
OtherMakePos(4);
OtherMakePos(5);
Mesh mesh = new Mesh();
mesh.vertices = verts.ToArray();
mesh.triangles = indices.ToArray();
mesh.RecalculateNormals();
mesh.RecalculateBounds();
Vector3[] normals = mesh.normals;
for (int i = 0; i < normals.Length; i++)
{
normals[i] = -normals[i];
}
mesh.normals = normals;
int[] triangles = mesh.triangles;
for (int i = 0; i < triangles.Length; i += 3)
{
int t = triangles[i];
triangles[i] = triangles[i + 2];
triangles[i + 2] = t;
}
mesh.triangles = triangles;
gradientMeshFilter.mesh = mesh;
}
public void CreateMakePos(int num)
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
int index = j * (N + 1) + (N + 1) * (N + 1) * num + i;
int up = (j + 1) * (N + 1) + (N + 1) * (N + 1) * num + i;
indices.AddRange(new int[] { index, index + 1, up + 1 });
indices.AddRange(new int[] { index, up + 1, up });
}
}
}
public void OtherMakePos(int num)
{
for (int i = 0; i < N + 1; i++)
{
for (int j = 0; j < N + 1; j++)
{
if (i != N && j != N)
{
int index = j * (N + 1) + (N + 1) * (N + 1) * num + i;
int up = (j + 1) * (N + 1) + (N + 1) * (N + 1) * num + i;
indices.AddRange(new int[] { index, up + 1, index + 1 });
indices.AddRange(new int[] { index, up, up + 1 });
}
}
}
}
private void DestoryGradientMesh()
{
if (gradientMeshRenderer != null)
Destroy(gradientMeshRenderer);
if (gradientMaterial != null)
Destroy(gradientMaterial);
if (gradientMeshFilter != null)
Destroy(gradientMeshFilter);
}
}
}

View File

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

View File

@@ -0,0 +1,440 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.XR.PXR
{
public class PXR_System
{
/// <summary>
/// Gets the SDK version.
/// </summary>
/// <returns>The SDK version.</returns>
public static string GetSDKVersion()
{
return PXR_Plugin.System.UPxr_GetSDKVersion();
}
/// <summary>
/// Gets the predicted time a frame will be displayed after being rendered.
/// </summary>
/// <returns>The predicted time (in miliseconds).</returns>
public static double GetPredictedDisplayTime()
{
return PXR_Plugin.System.UPxr_GetPredictedDisplayTime();
}
/// <summary>
/// Sets the extra latency mode. Note: Call this function once only.
/// </summary>
/// <param name="mode">The latency mode:
/// * `0`: ExtraLatencyModeOff (Disable ExtraLatencyMode mode. This option will display the latest rendered frame for display)
/// * `1`: ExtraLatencyModeOn (Enable ExtraLatencyMode mode. This option will display one frame prior to the latest rendered frame)
/// * `2`: ExtraLatencyModeDynamic (Use system default setup)
/// </param>
/// <returns>Whether the extra latency mode has been set:
/// * `true`: success
/// * `false`: failure
/// </returns>
[Obsolete("SetExtraLatencyMode has been deprecated", true)]
public static bool SetExtraLatencyMode(int mode)
{
return false;
}
/// <summary>
/// Gets the sensor's status.
/// </summary>
/// <returns>The sensor's status:
/// * `0`: null
/// * `1`: 3DoF
/// * `3`: 6DoF
/// </returns>
public static int GetSensorStatus()
{
return PXR_Plugin.System.UPxr_GetSensorStatus();
}
/// <summary>
/// Sets the system display frequency rate.
/// </summary>
/// <param name="rate">The frequency rate: `72`; `90`; `120`. Other values are invalid.</param>
public static void SetSystemDisplayFrequency(float rate)
{
PXR_Plugin.System.UPxr_SetSystemDisplayFrequency(rate);
}
/// <summary>
/// Gets the system display frequency rate.
/// </summary>
/// <returns>The system display frequency rate.</returns>
public static float GetSystemDisplayFrequency()
{
return PXR_Plugin.System.UPxr_GetSystemDisplayFrequency();
}
/// <summary>
/// Gets the available display refresh rates.
/// </summary>
/// <returns>
/// The available refresh rates (in Hz).
/// </returns>
public static float[] GetDisplayFrequenciesAvailable()
{
return PXR_Plugin.System.UPxr_GetDisplayFrequenciesAvailable();
}
/// <summary>
/// Gets the predicted status of the sensor.
/// </summary>
/// <param name="sensorState">Sensor's coordinate:
/// * `pose`: in-app coordinate
/// * `globalPose`: global coordinate
/// </param>
/// <param name="sensorFrameIndex">Sensor frame index.</param>
/// <returns>The predicted status of the sensor.</returns>
public static int GetPredictedMainSensorStateNew(ref PxrSensorState2 sensorState, ref int sensorFrameIndex) {
return PXR_Plugin.System.UPxr_GetPredictedMainSensorStateNew(ref sensorState, ref sensorFrameIndex);
}
/// <summary>
/// Enables/disables content protection.
/// </summary>
/// <param name="data">Specifies whether to enable/disable content protection:
/// * `0`: disable
/// * `1`: enable
/// </param>
/// <returns>Whether content protection is successfully enabled/disabled:
/// * `0`: success
/// * `1`: failure
/// </returns>
public static int ContentProtect(int data) {
return PXR_Plugin.System.UPxr_ContentProtect(data);
}
/// <summary>
/// Enables/disables face tracking.
/// @note Only supported by PICO 4 Pro and PICO 4 Enterprise.
/// </summary>
/// <param name="enable">Whether to enable/disable face tracking:
/// * `true`: enable
/// * `false`: disable
/// </param>
[Obsolete("EnableFaceTracking has been deprecated", true)]
public static void EnableFaceTracking(bool enable)
{
}
/// <summary>
/// Enables/disables lipsync.
/// @note Only supported by PICO 4 Pro and PICO 4 Enterprise.
/// </summary>
/// <param name="enable">Whether to enable/disable lipsync:
/// * `true`: enable
/// * `false`: disable
/// </param>
[Obsolete("EnableLipSync has been deprecated", true)]
public static void EnableLipSync(bool enable)
{
}
/// <summary>
/// Gets face tracking data.
/// @note Only supported by PICO 4 Pro and PICO 4 Enterprise.
/// </summary>
/// <param name="ts">(Optional) A reserved parameter, pass `0`.</param>
/// <param name="flags">The face tracking mode to retrieve data for. Enumertions:
/// * `PXR_GET_FACE_DATA_DEFAULT` (invalid, only for making it compatible with older SDK version)
/// * `PXR_GET_FACE_DATA`: face only
/// * `PXR_GET_LIP_DATA`: lipsync only
/// * `PXR_GET_FACELIP_DATA`: hybrid (both face and lipsync)
/// </param>
/// <param name="faceTrackingInfo">Returns the `PxrFaceTrackingInfo` struct that contains the following face tracking data:
/// * `timestamp`: Int64, reserved field
/// * `blendShapeWeight`: float[], pass `0`.
/// * `videoInputValid`: float[], the input validity of the upper and lower parts of the face.
/// * `laughingProb`: float[], the coefficient of laughter.
/// * `emotionProb`: float[], the emotion factor.
/// * `reserved`: float[], reserved field.
/// </param>
[Obsolete("GetFaceTrackingData has been deprecated", true)]
public static void GetFaceTrackingData(Int64 ts, GetDataType flags, ref PxrFaceTrackingInfo faceTrackingInfo)
{
}
/// <summary>Sets a GPU or CPU level for the device.</summary>
/// <param name="which">Choose to set a GPU or CPU level:
/// * `CPU`
/// * `GPU`
/// </param>
/// <param name="level">Select a level from the following:
/// * `POWER_SAVINGS`: power-saving level
/// * `SUSTAINED_LOW`: low level
/// * `SUSTAINED_HIGH`: high level
/// * `BOOST`: top-high level, be careful to use this level
/// </param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
public static int SetPerformanceLevels(PxrPerfSettings which, PxrSettingsLevel level)
{
return PXR_Plugin.System.UPxr_SetPerformanceLevels(which, level);
}
/// <summary>Gets the device's GPU or CPU level.</summary>
/// <param name="which">Choose to get GPU or CPU level:
/// * `CPU`
/// * `GPU`
/// </param>
/// <returns>
/// Returns one of the following levels:
/// * `POWER_SAVINGS`: power-saving level
/// * `SUSTAINED_LOW`: low level
/// * `SUSTAINED_HIGH`: high level
/// * `BOOST`: top-high level, be careful to use this level
/// </returns>
public static PxrSettingsLevel GetPerformanceLevels(PxrPerfSettings which)
{
return PXR_Plugin.System.UPxr_GetPerformanceLevels(which);
}
/// <summary>Sets FOV in four directions (left, right, up, and down) for specified eye(s).</summary>
/// <param name="eye">The eye to set FOV for:
/// * `LeftEye`
/// * `RightEye`
/// * `BothEye`
/// </param>
/// <param name="fovLeft">The horizontal FOV (in degrees) for the left part of the eye, for example, `47.5`.</param>
/// <param name="fovRight">The horizontal FOV (in degrees) for the right part of the eye..</param>
/// <param name="fovUp">The vertical FOV (in degrees) for the upper part of the eye.</param>
/// <param name="fovDown">The vertical FOV (in degrees) for the lower part of the eye.</param>
/// <returns>
/// * `0`: success
/// * `1`: failure
/// </returns>
[Obsolete("SetEyeFOV has been deprecated", true)]
public static int SetEyeFOV(EyeType eye, float fovLeft, float fovRight, float fovUp, float fovDown)
{
return 1;
}
/// <summary>
/// Switches the face tracking mode.
/// @note Only supported by PICO 4 Pro and PICO 4 Enterprise.
/// </summary>
/// <param name="value">
/// `STOP_FT`: to stop the "Face Only" mode.
/// `STOP_LIPSYNC`: to stop the "Lipsync Only" mode.
/// `START_FT`: to start the "Face Only" mode.
/// `START_LIPSYNC`: to start the "Lipsync Only" mode.
/// </param>
/// <returns>
/// `0`: success
/// `1`: failure
/// </returns>
[Obsolete("SetFaceTrackingStatus has been deprecated", true)]
public static int SetFaceTrackingStatus(PxrFtLipsyncValue value) {
return 1;
}
/// <summary>
/// Sets a tracking origin mode for the app.
/// When the user moves in the virtual scene, the system tracks and calculates the user's positional changes based on the origin.
/// </summary>
/// <param name="originMode">Selects a tracking origin mode from the following:
/// * `TrackingOriginModeFlags.Device`: Device mode. The system sets the device's initial position as the origin. The device's height from the floor is not calculated.
/// * `TrackingOriginModeFlags.Floor`: Floor mode. The system sets an origin based on the device's original position and the device's height from the floor.
/// </param>
public static void SetTrackingOrigin(PxrTrackingOrigin originMode)
{
PXR_Plugin.System.UPxr_SetTrackingOrigin(originMode);
}
/// <summary>
/// Gets the tracking origin mode of the app.
/// </summary>
/// <param name="originMode">Returns the app's tracking origin mode:
/// * `TrackingOriginModeFlags.Device`: Device mode
/// * `TrackingOriginModeFlags.Floor`: Floor mode
/// For the description of each mode, refer to `SetTrackingOrigin`.
/// </param>
public static void GetTrackingOrigin(out PxrTrackingOrigin originMode)
{
originMode = PxrTrackingOrigin.Eye;
PXR_Plugin.System.UPxr_GetTrackingOrigin(ref originMode);
}
/// <summary>
/// Turns on the power service for a specified object.
/// </summary>
/// <param name="objName">The name of the object to turn on the power service for.</param>
/// <returns>Whether the power service has been turned on:
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool StartBatteryReceiver(string objName)
{
return PXR_Plugin.System.UPxr_StartBatteryReceiver(objName);
}
/// <summary>
/// Turns off the power service.
/// </summary>
/// <returns>Whether the power service has been turned off:
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool StopBatteryReceiver()
{
return PXR_Plugin.System.UPxr_StopBatteryReceiver();
}
/// <summary>
/// Sets the brightness for the current HMD.
/// </summary>
/// <param name="brightness">Target brightness. Value range: [0,255].</param>
/// <returns>Whether the brightness has been set successfully:
/// * `true`: success
/// * `false`: failure
/// </returns>
[Obsolete("SetCommonBrightness has been deprecated", true)]
public static bool SetCommonBrightness(int brightness)
{
return false;
}
/// <summary>
/// Gets the brightness of the current HMD.
/// </summary>
/// <returns>An int value that indicates the brightness. Value range: [0,255].</returns>
[Obsolete("GetCommonBrightness has been deprecated", true)]
public static int GetCommonBrightness()
{
return -1;
}
/// <summary>
/// Gets the brightness level of the current screen.
/// </summary>
/// <returns>An int array. The first bit is the total brightness level supported, the second bit is the current brightness level, and it is the interval value of the brightness level from the third bit to the end bit.</returns>
[Obsolete("GetScreenBrightnessLevel has been deprecated", true)]
public static int[] GetScreenBrightnessLevel()
{
return null;
}
/// <summary>
/// Sets a brightness level for the current screen.
/// </summary>
/// <param name="brightness">Brightness mode:
/// * `0`: system default brightness setting.
/// * `1`: custom brightness setting, you can then set param `level`.
/// </param>
/// <param name="level">Brightness level. Value range: [1,255].</param>
[Obsolete("GetScreenBrightnessLevel has been deprecated", true)]
public static void SetScreenBrightnessLevel(int brightness, int level)
{
}
/// <summary>
/// Turns on the volume service for a specified object.
/// </summary>
/// <param name="objName">The name of the object to turn on the volume service for.</param>
/// <returns>Whether the volume service has been turned on:
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool StartAudioReceiver(string objName)
{
return PXR_Plugin.System.UPxr_StartAudioReceiver(objName);
}
/// <summary>
/// Turns off the volume service.
/// </summary>
/// <returns>Whether the volume service has been turned off:
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool StopAudioReceiver()
{
return PXR_Plugin.System.UPxr_StopAudioReceiver();
}
/// <summary>
/// Gets the maximum volume.
/// </summary>
/// <returns>An int value that indicates the maximum volume.</returns>
public static int GetMaxVolumeNumber()
{
return PXR_Plugin.System.UPxr_GetMaxVolumeNumber();
}
/// <summary>
/// Gets the current volume.
/// </summary>
/// <returns>An int value that indicates the current volume. Value range: [0,15].</returns>
public static int GetCurrentVolumeNumber()
{
return PXR_Plugin.System.UPxr_GetCurrentVolumeNumber();
}
/// <summary>
/// Increases the volume.
/// </summary>
/// <returns>Whether the volume has been increased:
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool VolumeUp()
{
return PXR_Plugin.System.UPxr_VolumeUp();
}
/// <summary>
/// Decreases the volume.
/// </summary>
/// <returns>Whether the volume has been decreased:
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool VolumeDown()
{
return PXR_Plugin.System.UPxr_VolumeDown();
}
/// <summary>
/// Sets a volume.
/// </summary>
/// <param name="volume">The target volume. Value range: [0,15].</param>
/// <returns>Whether the target volume has been set:
/// * `true`: success
/// * `false`: failure
/// </returns>
public static bool SetVolumeNum(int volume)
{
return PXR_Plugin.System.UPxr_SetVolumeNum(volume);
}
public static string GetProductName()
{
return PXR_Plugin.System.ProductName;
}
}
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,156 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.Collections.Generic;
using UnityEngine;
using Unity.XR.PXR;
public class PXR_Hand : MonoBehaviour
{
public HandType handType;
public Transform Basemesh;
[HideInInspector]
public List<Transform> handJoints = new List<Transform>(new Transform[(int)HandJoint.JointMax]);
public bool Computed { get; private set; }
public Posef RayPose { get; private set; }
public bool RayValid { get; private set; }
public bool Pinch { get; private set; }
public float PinchStrength { get; private set; }
private HandJointLocations handJointLocations = new HandJointLocations();
private HandAimState aimState = new HandAimState();
[SerializeField]
private Transform rayPose;
[SerializeField]
private GameObject defaultRay;
private SkinnedMeshRenderer[] touchRenders;
private bool isaAdaptiveScales = false;
PXR_VstModelPosCheck mOffsetPos=null;
private void Awake()
{
mOffsetPos= GetComponent<PXR_VstModelPosCheck>();
}
private void Start()
{
isaAdaptiveScales = PXR_ProjectSetting.GetProjectConfig().adaptiveHand;
if (defaultRay != null)
{
touchRenders = defaultRay.GetComponentsInChildren<SkinnedMeshRenderer>();
}
}
protected void OnEnable() => Application.onBeforeRender += OnBeforeRender;
protected void OnDisable() => Application.onBeforeRender -= OnBeforeRender;
private void OnBeforeRender()
{
UpdateHandJoints();
UpdateAimState();
UpdateRayPose();
}
private void UpdateHandJoints()
{
if (PXR_HandTracking.GetJointLocations(handType, ref handJointLocations))
{
if (isaAdaptiveScales)
{
float scale = 0;
PXR_HandTracking.GetHandScale(handType,ref scale);
Basemesh.localScale = Vector3.one*scale;
}
for (int i = 0; i < handJoints.Count; ++i)
{
if (handJoints[i] == null) continue;
if (i == (int)HandJoint.JointWrist)
{
handJoints[i].localPosition = handJointLocations.jointLocations[i].pose.Position.ToVector3();
handJoints[i].localRotation = handJointLocations.jointLocations[i].pose.Orientation.ToQuat();
}
else
{
Pose parentPose = Pose.identity;
if (i == (int)HandJoint.JointPalm ||
i == (int)HandJoint.JointThumbMetacarpal ||
i == (int)HandJoint.JointIndexMetacarpal ||
i == (int)HandJoint.JointMiddleMetacarpal ||
i == (int)HandJoint.JointRingMetacarpal ||
i == (int)HandJoint.JointLittleMetacarpal)
{
parentPose = new Pose(handJointLocations.jointLocations[1].pose.Position.ToVector3(), handJointLocations.jointLocations[1].pose.Orientation.ToQuat());
}
else
{
parentPose = new Pose(handJointLocations.jointLocations[i-1].pose.Position.ToVector3(), handJointLocations.jointLocations[i-1].pose.Orientation.ToQuat());
}
var inverseParentRotation = Quaternion.Inverse(parentPose.rotation);
handJoints[i].localRotation = inverseParentRotation * handJointLocations.jointLocations[i].pose.Orientation.ToQuat();
}
}
if (mOffsetPos)
{
Basemesh.localPosition = handJointLocations.jointLocations[(int)Unity.XR.PXR.HandJoint.JointWrist].pose.Position.ToVector3()+ mOffsetPos.GetHandPosOffset();
}
}
}
private void UpdateAimState()
{
if (PXR_HandTracking.GetAimState(handType, ref aimState))
{
Computed = (aimState.aimStatus&HandAimStatus.AimComputed) != 0;
RayPose = aimState.aimRayPose;
RayValid = (aimState.aimStatus&HandAimStatus.AimRayValid) != 0;
Pinch = (aimState.aimStatus&HandAimStatus.AimRayTouched) != 0;
PinchStrength = aimState.touchStrengthRay;
}
}
private void UpdateRayPose()
{
if (rayPose == null) return;
if (RayValid)
{
rayPose.gameObject.SetActive(true);
rayPose.localPosition = RayPose.Position.ToVector3();
rayPose.localRotation = RayPose.Orientation.ToQuat();
if (defaultRay != null)
{
foreach (var touchRender in touchRenders)
{
touchRender.SetBlendShapeWeight(0, aimState.touchStrengthRay*100);
}
}
}
else
{
rayPose.gameObject.SetActive(false);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,570 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System;
using UnityEngine.XR;
namespace Unity.XR.PXR
{
public class PXR_HandPose : MonoBehaviour
{
public TrackType trackType;
public PXR_HandPoseConfig config;
public UnityEvent handPoseStart;
public UpdateEvent handPoseUpdate;
public UnityEvent handPoseEnd;
private List<Vector3> leftJointPos = new List<Vector3>(new Vector3[(int)HandJoint.JointMax]);
private List<Vector3> rightJointPos = new List<Vector3>(new Vector3[(int)HandJoint.JointMax]);
private HandJointLocations leftHandJointLocations = new HandJointLocations();
private HandJointLocations rightHandJointLocations = new HandJointLocations();
private bool poseStateHold;
private bool poseStateActive;
private float poseStateHoldTime;
public enum TrackType
{
Any,
Left,
Right
}
private void HandPoseEventCheck()
{
switch (trackType)
{
case TrackType.Any:
poseStateActive = (leftShapesActive && leftBonesActive && leftTransActive) || (rightShapesActive && rightBonesActive && rightTransActive);
break;
case TrackType.Left:
poseStateActive = leftShapesActive && leftBonesActive && leftTransActive;
break;
case TrackType.Right:
poseStateActive = rightShapesActive && rightBonesActive && rightTransActive;
break;
default:
break;
}
if (poseStateHold != poseStateActive)
{
poseStateHold = poseStateActive;
if (poseStateHold)
{
poseStateActive = true;
if (handPoseStart != null)
{
handPoseStart.Invoke();
}
}
else
{
poseStateActive = false;
if (handPoseStart != null)
{
handPoseEnd.Invoke();
}
}
poseStateHoldTime = 0f;
}
else
{
if (poseStateHold)
{
poseStateHoldTime += Time.deltaTime;
handPoseUpdate.Invoke(poseStateHoldTime);
}
}
}
private bool HoldCheck(bool holdState, float holdDuration, bool resultState, ref float holdTime)
{
if (resultState != holdState)
{
holdTime += Time.deltaTime;
if (holdTime >= holdDuration)
{
resultState = holdState;
}
}
else
{
holdTime = 0;
}
return resultState;
}
private void Start()
{
shapesHoldDuration = config.shapesRecognizer.holdDuration;
bones = config.bonesRecognizer.Bones;
bonesHoldDuration = config.bonesRecognizer.holdDuration;
transTrackAxis = config.transRecognizer.trackAxis;
transSpaceType = config.transRecognizer.spaceType;
transTrackTarget = config.transRecognizer.trackTarget;
transHoldDuration = config.transRecognizer.holdDuration;
transAngleThreshold = config.transRecognizer.angleThreshold;
transThresholdWidth = config.transRecognizer.thresholdWidth;
}
private void Update()
{
if (config == null) return;
InputDevices.GetDeviceAtXRNode(XRNode.Head).TryGetFeatureValue(CommonUsages.devicePosition, out HMDpose);
if (trackType == TrackType.Right || trackType == TrackType.Any)
{
PXR_HandTracking.GetJointLocations(HandType.HandRight, ref rightHandJointLocations);
for (int i = 0; i < rightJointPos.Count; ++i)
{
if (rightHandJointLocations.jointLocations == null) break;
rightJointPos[i] = rightHandJointLocations.jointLocations[i].pose.Position.ToVector3();
if (i == (int)HandJoint.JointWrist)
{
rightWirstPos = rightHandJointLocations.jointLocations[i].pose.Position.ToVector3();
rightWirstRot = rightHandJointLocations.jointLocations[i].pose.Orientation.ToQuat();
}
}
rightShapesHold = ShapesRecognizerCheck(rightJointPos, rightWirstRot * Vector3.left, rightWirstRot * Vector3.back);
rightShapesActive = HoldCheck(rightShapesHold, shapesHoldDuration, rightShapesActive, ref rightShapesHoldTime);
rightBonesHold = BonesCheck(HandType.HandRight);
rightBonesActive = HoldCheck(rightBonesHold, bonesHoldDuration, rightBonesActive, ref rightBonesHoldTime);
rightTransHold = TransCheck(TrackType.Right, rightWirstPos, rightWirstRot, HMDpose, rightTransHold);
rightTransActive = HoldCheck(rightTransHold, transHoldDuration, rightTransActive, ref rightTransHoldTime);
}
if (trackType == TrackType.Left || trackType == TrackType.Any)
{
PXR_HandTracking.GetJointLocations(HandType.HandLeft, ref leftHandJointLocations);
for (int i = 0; i < leftJointPos.Count; ++i)
{
if (leftHandJointLocations.jointLocations == null) break;
leftJointPos[i] = leftHandJointLocations.jointLocations[i].pose.Position.ToVector3();
if (i == (int)HandJoint.JointWrist)
{
leftWirstPos = leftHandJointLocations.jointLocations[i].pose.Position.ToVector3();
leftWirstRot = leftHandJointLocations.jointLocations[i].pose.Orientation.ToQuat();
}
}
leftShapesHold = ShapesRecognizerCheck(leftJointPos, leftWirstRot * Vector3.right, leftWirstRot * Vector3.forward, -1);
leftShapesActive = HoldCheck(leftShapesHold, shapesHoldDuration, leftShapesActive, ref leftShapesHoldTime);
leftBonesHold = BonesCheck(HandType.HandLeft);
leftBonesActive = HoldCheck(leftBonesHold, bonesHoldDuration, leftBonesActive, ref leftBonesHoldTime);
leftTransHold = TransCheck(TrackType.Left, leftWirstPos, leftWirstRot, HMDpose, leftTransHold);
leftTransActive = HoldCheck(leftTransHold, transHoldDuration, leftTransActive, ref leftTransHoldTime);
}
HandPoseEventCheck();
}
#region ShapesRecognizer
private float shapesHoldDuration = 0.09f;
private bool leftShapesHold;
private bool leftShapesActive;
private float leftShapesHoldTime;
private bool rightShapesActive;
private bool rightShapesHold;
private float rightShapesHoldTime;
private bool angleCheckValid = false;
private bool abducCheckOpen = false;
private Vector3 leftWirstPos;
private Vector3 rightWirstPos;
private Quaternion leftWirstRot;
private Quaternion rightWirstRot;
private Vector3 thumb0, thumb1, thumb2, thumb3;
private Vector3 index0, index1, index2, index3;
private Vector3 middle0, middle1, middle2, middle3;
private Vector3 ring0, ring1, ring2, ring3;
private Vector3 pinky0, pinky1, pinky2, pinky3;
private bool thumbFlex, indexFlex, middleFlex, ringFlex, pinkyFlex;
private bool thumbCurl, indexCurl, middleCurl, ringCurl, pinkyCurl;
private bool thumbAbduc, indexAbduc, middleAbduc, ringAbduc, pinkyAbduc;
private bool ShapesRecognizerCheck(List<Vector3> jointPos, Vector3 wirstRight, Vector3 wirstForward, int wirstDirect = 1)
{
thumb0 = jointPos[(int)HandJoint.JointThumbTip];
thumb1 = jointPos[(int)HandJoint.JointThumbDistal];
thumb2 = jointPos[(int)HandJoint.JointThumbProximal];
thumb3 = jointPos[(int)HandJoint.JointThumbMetacarpal];
index0 = jointPos[(int)HandJoint.JointIndexTip];
index1 = jointPos[(int)HandJoint.JointIndexDistal];
index2 = jointPos[(int)HandJoint.JointIndexIntermediate];
index3 = jointPos[(int)HandJoint.JointIndexProximal];
middle0 = jointPos[(int)HandJoint.JointMiddleTip];
middle1 = jointPos[(int)HandJoint.JointMiddleDistal];
middle2 = jointPos[(int)HandJoint.JointMiddleIntermediate];
middle3 = jointPos[(int)HandJoint.JointMiddleProximal];
ring0 = jointPos[(int)HandJoint.JointRingTip];
ring1 = jointPos[(int)HandJoint.JointRingDistal];
ring2 = jointPos[(int)HandJoint.JointRingIntermediate];
ring3 = jointPos[(int)HandJoint.JointRingProximal];
pinky0 = jointPos[(int)HandJoint.JointLittleTip];
pinky1 = jointPos[(int)HandJoint.JointLittleDistal];
pinky2 = jointPos[(int)HandJoint.JointLittleIntermediate];
pinky3 = jointPos[(int)HandJoint.JointLittleProximal];
thumbFlex = FlexionCheck(config.shapesRecognizer.thumb, wirstDirect * wirstRight, wirstDirect * wirstForward);
indexFlex = FlexionCheck(config.shapesRecognizer.index, wirstRight, wirstForward);
middleFlex = FlexionCheck(config.shapesRecognizer.middle, wirstRight, wirstForward);
ringFlex = FlexionCheck(config.shapesRecognizer.ring, wirstRight, wirstForward);
pinkyFlex = FlexionCheck(config.shapesRecognizer.pinky, wirstRight, wirstForward);
thumbCurl = CurlCheck(config.shapesRecognizer.thumb);
indexCurl = CurlCheck(config.shapesRecognizer.index);
middleCurl = CurlCheck(config.shapesRecognizer.middle);
ringCurl = CurlCheck(config.shapesRecognizer.ring);
pinkyCurl = CurlCheck(config.shapesRecognizer.pinky);
thumbAbduc = AbductionCheck(config.shapesRecognizer.thumb);
indexAbduc = AbductionCheck(config.shapesRecognizer.index);
middleAbduc = AbductionCheck(config.shapesRecognizer.middle);
ringAbduc = AbductionCheck(config.shapesRecognizer.ring);
pinkyAbduc = AbductionCheck(config.shapesRecognizer.pinky);
return thumbFlex && indexFlex && middleFlex && ringFlex && pinkyFlex
&& thumbCurl && indexCurl && middleCurl && ringCurl && pinkyCurl
&& thumbAbduc && indexAbduc && middleAbduc && ringAbduc && pinkyAbduc;
}
private bool FlexionCheck(ShapesRecognizer.Finger finger, Vector3 wirstRight, Vector3 wirstForward)
{
if (finger.flexion == ShapesRecognizer.Flexion.Any) return true;
else
{
float flexAngle = 0;
switch (finger.handFinger)
{
case HandFinger.Thumb:
Vector3 thumb23 = (thumb2 - thumb3);
Vector3 thumb23_project = Vector3.ProjectOnPlane(thumb23, wirstRight);
flexAngle = Vector3.Angle(thumb23_project, wirstForward);
break;
case HandFinger.Index:
Vector3 index23 = (index2 - index3);
Vector3 index_project = Vector3.ProjectOnPlane(index23, wirstForward);
flexAngle = Vector3.Angle(index_project, wirstRight);
break;
case HandFinger.Middle:
Vector3 middle23 = (middle2 - middle3);
Vector3 middle_project = Vector3.ProjectOnPlane(middle23, wirstForward);
flexAngle = Vector3.Angle(middle_project, wirstRight);
break;
case HandFinger.Ring:
Vector3 ring23 = (ring2 - ring3);
Vector3 ring_project = Vector3.ProjectOnPlane(ring23, wirstForward);
flexAngle = Vector3.Angle(ring_project, wirstRight);
break;
case HandFinger.Pinky:
Vector3 pinky23 = (pinky2 - pinky3);
Vector3 pinky_project = Vector3.ProjectOnPlane(pinky23, wirstForward);
flexAngle = Vector3.Angle(pinky_project, wirstRight);
break;
default:
break;
}
return AngleCheck(flexAngle, finger.fingerConfigs.flexionConfigs.min, finger.fingerConfigs.flexionConfigs.max, finger.fingerConfigs.flexionConfigs.width,
ShapesRecognizer.flexionMin, ShapesRecognizer.flexionMax);
}
}
private bool CurlCheck(ShapesRecognizer.Finger finger)
{
if (finger.curl == ShapesRecognizer.Curl.Any) return true;
else
{
float curlAngle = 0;
switch (finger.handFinger)
{
case HandFinger.Thumb:
Vector3 thumb01 = (thumb0 - thumb1);
Vector3 thumb32 = (thumb3 - thumb2);
curlAngle = Vector3.Angle(thumb01, thumb32);
break;
case HandFinger.Index:
Vector3 index01 = (index0 - index1);
Vector3 index32 = (index3 - index2);
curlAngle = Vector3.Angle(index32, index01);
break;
case HandFinger.Middle:
Vector3 middle01 = (middle0 - middle1);
Vector3 middle32 = (middle3 - middle2);
curlAngle = Vector3.Angle(middle32, middle01);
break;
case HandFinger.Ring:
Vector3 ring01 = (ring0 - ring1);
Vector3 ring32 = (ring3 - ring2);
curlAngle = Vector3.Angle(ring32, ring01);
break;
case HandFinger.Pinky:
Vector3 pinky01 = (pinky0 - pinky1);
Vector3 pinky32 = (pinky3 - pinky2);
curlAngle = Vector3.Angle(pinky32, pinky01);
break;
default:
break;
}
return AngleCheck(curlAngle, finger.fingerConfigs.curlConfigs.min, finger.fingerConfigs.curlConfigs.max, finger.fingerConfigs.curlConfigs.width,
ShapesRecognizer.curlMin, ShapesRecognizer.curlMax);
}
}
private bool AbductionCheck(ShapesRecognizer.Finger finger)
{
if (finger.abduction == ShapesRecognizer.Abduction.Any) return true;
else
{
float abducAngle = 0;
Vector3 thumb12 = (thumb1 - thumb2);
Vector3 index23 = (index2 - index3);
Vector3 middle23 = (middle2 - middle3);
Vector3 ring23 = (ring2 - ring3);
Vector3 pinky23 = (pinky2 - pinky3);
switch (finger.handFinger)
{
case HandFinger.Thumb:
abducAngle = Vector3.Angle(thumb12, index23);
break;
case HandFinger.Index:
abducAngle = Vector3.Angle(index23, middle23);
break;
case HandFinger.Middle:
abducAngle = Vector3.Angle(middle23, ring23);
break;
case HandFinger.Ring:
abducAngle = Vector3.Angle(ring23, pinky23);
break;
case HandFinger.Pinky:
abducAngle = Vector3.Angle(pinky23, ring23);
break;
default:
break;
}
bool result = false;
if (finger.abduction == ShapesRecognizer.Abduction.Open)
{
result = AbducCheck(abducAngle, finger.fingerConfigs.abductionConfigs.mid, finger.fingerConfigs.abductionConfigs.width); ;
}
else if (finger.abduction == ShapesRecognizer.Abduction.Close)
{
result = !AbducCheck(abducAngle, finger.fingerConfigs.abductionConfigs.mid, finger.fingerConfigs.abductionConfigs.width); ;
}
return result;
}
}
private bool AngleCheck(float angle, float min, float max, float width, float rangeMin, float rangeMax)
{
if (angle > min && angle < max)
{
angleCheckValid = true;
}
if (min - rangeMin <= 1f)
{
angleCheckValid = angle < max;
}
else if (angle < (min - width))
{
angleCheckValid = false;
}
if (rangeMax - max <= 1f)
{
angleCheckValid = angle > min;
}
else if ((angle > (max + width)))
{
angleCheckValid = false;
}
return angleCheckValid;
}
private bool AbducCheck(float angle, float mid, float width)
{
if (angle > mid + width / 2)
{
abducCheckOpen = true;
}
if (angle < mid - width / 2)
{
abducCheckOpen = false;
}
return abducCheckOpen;
}
#endregion
#region BonesRecognizer
private List<BonesRecognizer.BonesGroup> bones;
private bool leftBonesHold;
private bool leftBonesActive;
private float leftBonesHoldTime;
private bool rightBonesHold;
private bool rightBonesActive;
private float rightBonesHoldTime;
private float bonesHoldDuration;
private bool BonesCheck(HandType handType)
{
for (int i = 0; i < bones.Count; i++)
{
float distance = Vector3.Distance(GetHandJoint(handType, bones[i].bone1), GetHandJoint(handType, bones[i].bone2));
if (distance < bones[i].distance - bones[i].thresholdWidth / 2)
{
bones[i].activeState = true;
}
else if (distance > bones[i].distance + bones[i].thresholdWidth / 2)
{
bones[i].activeState = false;
}
if (!bones[i].activeState)
{
return false;
}
}
return true;
}
private Vector3 GetHandJoint(HandType hand, BonesRecognizer.HandBones bone)
{
if (hand == HandType.HandLeft)
{
return leftHandJointLocations.jointLocations[(int)bone].pose.Position.ToVector3();
}
else
{
return rightHandJointLocations.jointLocations[(int)bone].pose.Position.ToVector3();
}
}
#endregion
#region TransRecognizer
private bool leftTransHold;
private bool leftTransActive;
private float leftTransHoldTime;
private bool rightTransHold;
private bool rightTransActive;
private float rightTransHoldTime;
private TransRecognizer.TrackAxis transTrackAxis;
private TransRecognizer.SpaceType transSpaceType;
private TransRecognizer.TrackTarget transTrackTarget;
private float transAngleThreshold;
private float transThresholdWidth;
private float transHoldDuration;
private Vector3 HMDpose;
private Vector3 palmPos;
private Vector3 palmAxis;
private Vector3 targetPos;
private bool TransCheck(TrackType trackType, Vector3 wristPos, Quaternion wristRot, Vector3 headPose, bool holdState)
{
GetTrackAxis(trackType, wristRot);
GetProjectedTarget(headPose, wristRot, wristPos);
float errorAngle = Vector3.Angle(palmAxis, targetPos);
if (errorAngle < transAngleThreshold - transThresholdWidth / 2)
{
holdState = true;
}
if (errorAngle > transAngleThreshold + transThresholdWidth / 2)
{
holdState = false;
}
return holdState;
}
private Vector3 GetTrackAxis(TrackType trackType, Quaternion wristRot)
{
switch (transTrackAxis)
{
case TransRecognizer.TrackAxis.Fingers:
palmAxis = wristRot * Vector3.forward;
break;
case TransRecognizer.TrackAxis.Palm:
palmAxis = wristRot * Vector3.down;
break;
case TransRecognizer.TrackAxis.Thumb:
palmAxis = trackType == TrackType.Right ? wristRot * Vector3.left : wristRot * Vector3.right;
break;
}
return palmAxis;
}
private Vector3 GetProjectedTarget(Vector3 headPose, Quaternion wristRot, Vector3 wristPos)
{
palmPos = wristRot * (trackType == TrackType.Right ? new Vector3(0.08f, 0, 0) : new Vector3(-0.08f, 0, 0)) + wristPos;
switch (transTrackTarget)
{
case TransRecognizer.TrackTarget.TowardsFace:
targetPos = headPose;
break;
case TransRecognizer.TrackTarget.AwayFromFace:
targetPos = palmPos * 2 - headPose;
break;
case TransRecognizer.TrackTarget.WorldUp:
targetPos = palmPos + Vector3.up;
break;
case TransRecognizer.TrackTarget.WorldDown:
targetPos = palmPos + Vector3.down;
break;
}
targetPos -= palmPos;
switch (transSpaceType)
{
case TransRecognizer.SpaceType.WorldSpace:
break;
case TransRecognizer.SpaceType.LocalXY:
targetPos = Vector3.ProjectOnPlane(targetPos, wristRot * Vector3.forward);
break;
case TransRecognizer.SpaceType.LocalXZ:
targetPos = Vector3.ProjectOnPlane(targetPos, wristRot * Vector3.up);
break;
case TransRecognizer.SpaceType.LocalYZ:
targetPos = Vector3.ProjectOnPlane(targetPos, wristRot * Vector3.right);
break;
}
return targetPos;
}
#endregion
[Serializable]
public class UpdateEvent : UnityEvent<float> { }
}
}
#endif

View File

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

View File

@@ -0,0 +1,275 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.XR.PXR
{
[Serializable]
public class PXR_HandPoseConfig : ScriptableObject
{
[DisplayOnly]
public ShapesRecognizer shapesRecognizer;
[DisplayOnly]
public BonesRecognizer bonesRecognizer;
[DisplayOnly]
public TransRecognizer transRecognizer;
}
[Serializable]
public class ShapesRecognizer
{
public Finger thumb = new Finger(HandFinger.Thumb);
public Finger index = new Finger(HandFinger.Index);
public Finger middle = new Finger(HandFinger.Middle);
public Finger ring = new Finger(HandFinger.Ring);
public Finger pinky = new Finger(HandFinger.Pinky);
public float holdDuration = 0.09f;
[Serializable]
public class Finger
{
[HideInInspector]
public HandFinger handFinger;
public Flexion flexion;
public Curl curl;
public Abduction abduction;
public FingerConfigs fingerConfigs;
public Finger(HandFinger finger)
{
handFinger = finger;
flexion = Flexion.Any;
curl = Curl.Any;
abduction = Abduction.Any;
fingerConfigs = new FingerConfigs(finger);
}
}
[Serializable]
public class FingerConfigs
{
public RangeConfigs flexionConfigs;
public RangeConfigs curlConfigs;
public RangeConfigsAbduction abductionConfigs;
public FingerConfigs(HandFinger finger)
{
flexionConfigs = new RangeConfigs(flexionMin, flexionMax, defaultFlexionWidth);
if (finger == HandFinger.Thumb)
{
curlConfigs = new RangeConfigs(curlThumbMin, curlThumbMax, defaultCurlWidth);
abductionConfigs = new RangeConfigsAbduction(abductionThumbMid, abductionThumbWidth);
}
else
{
curlConfigs = new RangeConfigs(curlMin, curlMax, defaultCurlWidth);
abductionConfigs = new RangeConfigsAbduction(abductionMid, abductionWidth);
}
}
}
public enum ShapeType
{
flexion,
curl,
abduction
}
public enum Flexion
{
Any,
Open,
Close,
//Custom
}
public enum Curl
{
Any,
Open,
Close,
//Custom
}
public enum Abduction
{
Any,
Open,
Close,
}
[Serializable]
public class RangeConfigs
{
public float min;
public float max;
public float width;
public RangeConfigs(float n, float m, float w)
{
min = n;
max = m;
width =w;
}
}
[Serializable]
public class RangeConfigsAbduction
{
public float mid;
public float width;
public RangeConfigsAbduction(float m, float w)
{
mid = m;
width = w;
}
}
public const float defaultFlexionWidth = 10f;
public const float flexionThumbOpenMin = 155f;
public const float flexionThumbOpenMax = 180f;
public const float flexionThumbCloseMin = 90f;
public const float flexionThumbCloseMax = 120f;
public const float flexionOpenMin = 144f;
public const float flexionOpenMax = 180f;
public const float flexionCloseMin = 90f;
public const float flexionCloseMax = 126f;
public const float flexionMin = 90f;
public const float flexionMax = 180f;
public const float defaultCurlWidth = 20f;
public const float curlThumbOpenMin = 90f;
public const float curlThumbOpenMax = 180f;
public const float curlThumbCloseMin = 45f;
public const float curlThumbCloseMax = 90f;
public const float curlThumbMin = 45f;
public const float curlThumbMax = 180f;
public const float curlOpenMin = 107f;
public const float curlOpenMax = 180f;
public const float curlCloseMin = 0f;
public const float curlCloseMax = 73f;
public const float curlMin = 0f;
public const float curlMax = 180f;
public const float abductionThumbMid = 13f;
public const float abductionThumbWidth = 6f;
public const float abductionMid = 10f;
public const float abductionWidth = 6f;
public const float abductionMin = 0f;
public const float abductionMax = 90f;
}
[Serializable]
public class BonesRecognizer
{
public List<BonesGroup> Bones = new List<BonesGroup>();
public float holdDuration = 0.022f;
[Serializable]
public class BonesGroup
{
[LabelAttribute("Joint 1")]
public HandBones bone1 = HandBones.Wrist;
[LabelAttribute("Joint 2")]
public HandBones bone2 = HandBones.Wrist;
public float distance = 0.025f;
[LabelAttribute("Margin")]
public float thresholdWidth = 0.003f;
[HideInInspector]
public bool activeState;
}
public enum HandBones
{
Palm = 0,
Wrist = 1,
Thumb_Metacarpal = 2,
Thumb_Proximal = 3,
Thumb_Distal = 4,
Thumb_Tip = 5,
Index_Metacarpal = 6,
Index_Proximal = 7,
Index_Intermediate = 8,
Index_Distal = 9,
Index_Tip = 10,
Middle_Metacarpal = 11,
Middle_Proximal = 12,
Middle_Intermediate = 13,
Middle_Distal = 14,
Middle_Tip = 15,
Ring_Metacarpal = 16,
Ring_Proximal = 17,
Ring_Intermediate = 18,
Ring_Distal = 19,
Ring_Tip = 20,
Little_Metacarpal = 21,
Little_Proximal = 22,
Little_Intermediate = 23,
Little_Distal = 24,
Little_Tip = 25
}
}
[Serializable]
public class TransRecognizer
{
public TrackAxis trackAxis;
public SpaceType spaceType;
public TrackTarget trackTarget;
public enum SpaceType
{
WorldSpace,
LocalXY,
LocalYZ,
LocalXZ
}
public enum TrackAxis
{
Fingers, Palm, Thumb
}
public enum TrackTarget
{
TowardsFace,
AwayFromFace,
WorldUp,
WorldDown,
}
public float angleThreshold = 35f;
public float thresholdWidth = 10f;
public float holdDuration = 0.022f;
}
public class DisplayOnly : PropertyAttribute { }
public class LabelAttribute : PropertyAttribute
{
public string name;
public LabelAttribute(string name)
{
this.name = name;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,49 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.Collections.Generic;
using UnityEngine;
namespace Unity.XR.PXR
{
public class PXR_HandPoseGenerator : MonoBehaviour
{
public PXR_HandPoseConfig config;
public PXR_HandPosePreview preview;
//Shapes
public ShapesRecognizer.Finger thumb = new ShapesRecognizer.Finger(HandFinger.Thumb);
public ShapesRecognizer.Finger index = new ShapesRecognizer.Finger(HandFinger.Index);
public ShapesRecognizer.Finger middle = new ShapesRecognizer.Finger(HandFinger.Middle);
public ShapesRecognizer.Finger ring = new ShapesRecognizer.Finger(HandFinger.Ring);
public ShapesRecognizer.Finger pinky = new ShapesRecognizer.Finger(HandFinger.Pinky);
public float shapesholdDuration = 0.09f;
//Bones
public List<BonesRecognizer.BonesGroup> Bones = new List<BonesRecognizer.BonesGroup>();
public float bonesHoldDuration = 0.022f;
//Trans
public TransRecognizer.TrackAxis trackAxis;
public TransRecognizer.SpaceType spaceType;
public TransRecognizer.TrackTarget trackTarget;
public float angleThreshold = 35f;
public float thresholdWidth = 10f;
public float transHoldDuration = 0.022f;
}
}
#endif

View File

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

View File

@@ -0,0 +1,363 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.Collections.Generic;
using UnityEngine;
using Unity.XR.PXR;
using System;
[ExecuteInEditMode]
public class PXR_HandPosePreview : MonoBehaviour
{
[HideInInspector]public List<Transform> handJoints = new List<Transform>(new Transform[(int)HandJoint.JointMax]);
[HideInInspector] public Vector3[] jointAngles = new Vector3[(int)HandJoint.JointMax];
[HideInInspector] public Transform posePreviewX;
[HideInInspector] public Transform posePreviewY;
[HideInInspector] public Transform handModel;
[HideInInspector] public SkinnedMeshRenderer handAxis;
[HideInInspector] public Transform headModel;
[HideInInspector] public Transform handShadow;
[HideInInspector] public ModelFinger modelThumb = new ModelFinger(ModelFinger.FingerType.thumb);
[HideInInspector] public ModelFinger modelIndex = new ModelFinger(ModelFinger.FingerType.index);
[HideInInspector] public ModelFinger modelMiddle = new ModelFinger(ModelFinger.FingerType.middle);
[HideInInspector] public ModelFinger modelRing = new ModelFinger(ModelFinger.FingerType.ring);
[HideInInspector] public ModelFinger modelLittle = new ModelFinger(ModelFinger.FingerType.little);
[HideInInspector] public Material openMaterial;
[HideInInspector] public Material anyMaterial;
[HideInInspector] public Material openFadeMaterial;
[HideInInspector] public Material anyFadeMaterial;
[HideInInspector] public Material highLightMaterial;
private Vector4 highLightBlendPower;
private int blendPower = Shader.PropertyToID("_BlendPower");
public void UpdateShapeState(ShapesRecognizer shapesConfig)
{
var thumb = shapesConfig.thumb;
var index = shapesConfig.index;
var middle = shapesConfig.middle;
var ring = shapesConfig.ring;
var little = shapesConfig.pinky;
int joint = 0;
Vector3 angle = Vector3.zero;
//thumb
joint = (int)HandJoint.JointThumbProximal;
angle =
thumb.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(52f, -37, -8) :
thumb.abduction == ShapesRecognizer.Abduction.Close ? new Vector3(58f, 16, 1) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
joint = (int)HandJoint.JointThumbDistal;
angle =
thumb.curl == ShapesRecognizer.Curl.Close ? new Vector3(36, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
modelThumb.HighlightModelJoints(this,thumb.flexion, thumb.curl);
//index
joint = (int)HandJoint.JointIndexProximal;
angle =
index.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(jointAngles[joint].x + 68, jointAngles[joint].y, jointAngles[joint].z) :
index.abduction == ShapesRecognizer.Abduction.Close ? new Vector3(jointAngles[joint].x, 18, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
joint = (int)HandJoint.JointIndexIntermediate;
angle = index.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 60, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
joint = (int)HandJoint.JointIndexDistal;
angle = index.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 65, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
modelIndex.HighlightModelJoints(this, index.flexion, index.curl);
//middle
joint = (int)HandJoint.JointMiddleProximal;
angle =
middle.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(jointAngles[joint].x + 68, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
joint = (int)HandJoint.JointMiddleIntermediate;
angle = middle.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 60, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
joint = (int)HandJoint.JointMiddleDistal;
angle = middle.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 65, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
modelMiddle.HighlightModelJoints(this, middle.flexion, middle.curl);
//ring
joint = (int)HandJoint.JointRingProximal;
angle =
ring.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(jointAngles[joint].x + 68, jointAngles[joint].y, jointAngles[joint].z) :
middle.abduction == ShapesRecognizer.Abduction.Close ? new Vector3(jointAngles[joint].x, -18, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
joint = (int)HandJoint.JointRingIntermediate;
angle = ring.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 60, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
joint = (int)HandJoint.JointRingDistal;
angle = ring.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 65, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
modelRing.HighlightModelJoints(this, ring.flexion, ring.curl);
//little
joint = (int)HandJoint.JointLittleProximal;
angle =
little.flexion == ShapesRecognizer.Flexion.Close ? new Vector3(jointAngles[joint].x + 68, jointAngles[joint].y, jointAngles[joint].z) :
ring.abduction == ShapesRecognizer.Abduction.Close ? new Vector3(jointAngles[joint].x, -18, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
joint = (int)HandJoint.JointLittleIntermediate;
angle = little.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 60, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
joint = (int)HandJoint.JointLittleDistal;
angle = little.curl == ShapesRecognizer.Curl.Close ? new Vector3(jointAngles[joint].x + 65, jointAngles[joint].y, jointAngles[joint].z) : jointAngles[joint];
handJoints[joint].localEulerAngles = angle;
modelLittle.HighlightModelJoints(this, little.flexion, little.curl);
//abduction highlight
highLightBlendPower.w = thumb.abduction == ShapesRecognizer.Abduction.Any ? 0 : 1;
highLightBlendPower.x = index.abduction == ShapesRecognizer.Abduction.Any ? 0 : 1;
highLightBlendPower.y = middle.abduction == ShapesRecognizer.Abduction.Any ? 0 : 1;
highLightBlendPower.z = ring.abduction == ShapesRecognizer.Abduction.Any ? 0 : 1;
highLightMaterial.SetVector(blendPower, highLightBlendPower);
}
public void ResetShapeState()
{
for (int i = 0; i < handJoints.Count; i++)
{
handJoints[i].localEulerAngles = jointAngles[i];
}
modelThumb.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
modelIndex.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
modelMiddle.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
modelRing.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
modelLittle.HighlightModelJoints(this, ShapesRecognizer.Flexion.Any, ShapesRecognizer.Curl.Any);
highLightMaterial.SetVector(blendPower, Vector4.zero);
}
public void ResetTransformState()
{
headModel.gameObject.SetActive(false);
handAxis.gameObject.SetActive(false);
handModel.localEulerAngles = new Vector3(-90, 180, 0);
}
public void UpdateTransformState(TransRecognizer transRecognizer)
{
handAxis.gameObject.SetActive(true);
switch (transRecognizer.trackAxis)
{
case TransRecognizer.TrackAxis.Fingers:
handAxis.SetBlendShapeWeight(0, 100);
handAxis.SetBlendShapeWeight(1, 0);
handAxis.SetBlendShapeWeight(2, 0);
break;
case TransRecognizer.TrackAxis.Palm:
handAxis.SetBlendShapeWeight(0, 0);
handAxis.SetBlendShapeWeight(1, 0);
handAxis.SetBlendShapeWeight(2, 100);
break;
case TransRecognizer.TrackAxis.Thumb:
handAxis.SetBlendShapeWeight(0, 0);
handAxis.SetBlendShapeWeight(1, 100);
handAxis.SetBlendShapeWeight(2, 0);
break;
default:
break;
}
switch (transRecognizer.trackTarget)
{
case TransRecognizer.TrackTarget.TowardsFace:
headModel.gameObject.SetActive(true);
headModel.localPosition = new Vector3(0, 0.05f, -0.24f);
headModel.localEulerAngles = Vector3.zero;
handModel.localEulerAngles =
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Fingers ? new Vector3(0, 180, 0) :
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Palm ? new Vector3(-90, 180, 0) : new Vector3(-90, 0, -90);
break;
case TransRecognizer.TrackTarget.AwayFromFace:
headModel.gameObject.SetActive(true);
headModel.localPosition = new Vector3(0, 0.05f, 0.24f);
headModel.localEulerAngles = new Vector3(0, 180, 0);
handModel.localEulerAngles =
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Fingers ? new Vector3(0, 180, 0) :
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Palm ? new Vector3(-90, 180, 0) : new Vector3(-90, 0, -90);
break;
case TransRecognizer.TrackTarget.WorldUp:
headModel.gameObject.SetActive(false);
handModel.localEulerAngles =
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Fingers ? new Vector3(-90, 0, 0) :
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Palm ? new Vector3(0, 0, 180) : new Vector3(0, 0, -90);
break;
case TransRecognizer.TrackTarget.WorldDown:
headModel.gameObject.SetActive(false);
handModel.localEulerAngles =
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Fingers ? new Vector3(90, 0, 0) :
transRecognizer.trackAxis == TransRecognizer.TrackAxis.Palm ? Vector3.zero : new Vector3(0, 0, 90);
break;
default:
break;
}
if (handModel.localEulerAngles.x == 0)
{
handShadow.GetChild(0).gameObject.SetActive(false);
handShadow.GetChild(1).gameObject.SetActive(true);
}
else
{
handShadow.GetChild(0).gameObject.SetActive(true);
handShadow.GetChild(1).gameObject.SetActive(false);
}
}
[Serializable]
public class ModelFinger
{
public FingerType Type;
public List<Transform> flexionTransforms = new List<Transform>();
public List<MeshRenderer> flexionMeshRenderers = new List<MeshRenderer>();
public List<Transform> curlTransforms = new List<Transform>();
public List<MeshRenderer> curlMeshRenderers = new List<MeshRenderer>();
public enum ModelJoint
{
metacarpal = 0,
proximal = 1,
intermediate = 2,
distal = 3,
tip = 4
}
public enum FingerType
{
thumb,
index,
middle,
ring,
little
}
public ModelFinger(FingerType type)
{
Type = type;
}
public void RefreshModelJoints(Transform transform)
{
if (flexionTransforms.Count == 0 || curlTransforms.Count == 0)
{
flexionTransforms.Clear();
curlTransforms.Clear();
flexionMeshRenderers.Clear();
curlMeshRenderers.Clear();
var baseTransform = transform.GetChild(1);
for (int i = 0; i < baseTransform.childCount; i++)
{
if (baseTransform.GetChild(i).name.EndsWith($"{Type}_{ModelJoint.metacarpal}"))
{
baseTransform = baseTransform.GetChild(i);
break;
}
}
flexionTransforms.Add(GetModelJoint(baseTransform, ModelJoint.proximal));
curlTransforms.Add(GetModelJoint(baseTransform, ModelJoint.intermediate));
if (Type != FingerType.thumb)
{
curlTransforms.Add(GetModelJoint(baseTransform, ModelJoint.distal));
}
foreach (var flexionTransform in flexionTransforms)
{
flexionMeshRenderers.Add(flexionTransform.Find("Bone").GetComponent<MeshRenderer>());
flexionMeshRenderers.Add(flexionTransform.Find("Pointer").GetComponent<MeshRenderer>());
flexionMeshRenderers.Add(flexionTransform.parent.Find("Bone").GetComponent<MeshRenderer>());
}
foreach (var curlTransform in curlTransforms)
{
var mesh = curlTransform.Find("Bone").GetComponent<MeshRenderer>();
if (!curlMeshRenderers.Contains(mesh)) curlMeshRenderers.Add(mesh);
mesh = curlTransform.Find("Pointer").GetComponent<MeshRenderer>();
if (!curlMeshRenderers.Contains(mesh)) curlMeshRenderers.Add(mesh);
mesh = curlTransform.parent.Find("Bone").GetComponent<MeshRenderer>();
if (!curlMeshRenderers.Contains(mesh)) curlMeshRenderers.Add(mesh);
}
if (Type != FingerType.thumb)
{
var m = GetModelJoint(baseTransform, ModelJoint.tip).Find("Pointer")
.GetComponent<MeshRenderer>();
if (!curlMeshRenderers.Contains(m)) curlMeshRenderers.Add(m);
}
else
{
var m = GetModelJoint(baseTransform, ModelJoint.distal).Find("Pointer")
.GetComponent<MeshRenderer>();
if (!curlMeshRenderers.Contains(m)) curlMeshRenderers.Add(m);
}
}
}
public void HighlightModelJoints(PXR_HandPosePreview handPosePreview, ShapesRecognizer.Flexion flexion, ShapesRecognizer.Curl curl)
{
foreach (var mesh in flexionMeshRenderers)
{
mesh.material = flexion != ShapesRecognizer.Flexion.Any ? handPosePreview.openMaterial : handPosePreview.anyMaterial;
}
foreach (var mesh in curlMeshRenderers)
{
mesh.material = curl != ShapesRecognizer.Curl.Any ? handPosePreview.openMaterial : handPosePreview.anyMaterial;
}
flexionMeshRenderers[2].material = flexion != ShapesRecognizer.Flexion.Any ? handPosePreview.openFadeMaterial : handPosePreview.anyFadeMaterial;
}
private Transform GetModelJoint(Transform tran, ModelJoint type)
{
for (int i = 0; i < (int)type; i++)
{
tran = tran.GetChild(2);
}
return tran;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,622 @@
#if !PICO_OPENXR_SDK
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using Unity.Collections;
using UnityEngine;
using UnityEngine.Scripting;
using System.Runtime.CompilerServices;
using UnityEngine.XR.Management;
using UnityEngine.InputSystem;
using UnityEngine.XR;
using System.Collections.Generic;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.XR;
#if XR_HANDS
using UnityEngine.XR.Hands;
using UnityEngine.XR.Hands.ProviderImplementation;
namespace Unity.XR.PXR
{
[Preserve]
/// <summary>
/// Implement Unity XRHandSubSystem
/// Reference: https://docs.unity3d.com/Packages/com.unity.xr.hands@1.1/manual/implement-a-provider.html
/// </summary>
public class PXR_HandSubSystem : XRHandSubsystem
{
XRHandProviderUtility.SubsystemUpdater m_Updater;
// This method registers the subsystem descriptor with the SubsystemManager
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void RegisterDescriptor()
{
var handsSubsystemCinfo = new XRHandSubsystemDescriptor.Cinfo
{
id = "PICO Hands",
providerType = typeof(PXRHandSubsystemProvider),
subsystemTypeOverride = typeof(PXR_HandSubSystem)
};
XRHandSubsystemDescriptor.Register(handsSubsystemCinfo);
}
protected override void OnCreate()
{
base.OnCreate();
m_Updater = new XRHandProviderUtility.SubsystemUpdater(this);
}
protected override void OnStart()
{
Debug.Log("PXR_HandSubSystem Start");
m_Updater.Start();
base.OnStart();
}
protected override void OnStop()
{
m_Updater.Stop();
base.OnStop();
}
protected override void OnDestroy()
{
m_Updater.Destroy();
m_Updater = null;
base.OnDestroy();
}
class PXRHandSubsystemProvider : XRHandSubsystemProvider
{
HandJointLocations jointLocations = new HandJointLocations();
readonly HandLocationStatus AllStatus = HandLocationStatus.PositionTracked | HandLocationStatus.PositionValid |
HandLocationStatus.OrientationTracked | HandLocationStatus.OrientationValid;
bool isValid = false;
public override void Start()
{
CreateHands();
}
public override void Stop()
{
DestroyHands();
}
public override void Destroy()
{
}
/// <summary>
/// Mapping the PICO Joint Index To Unity Joint Index
/// </summary>
static int[] pxrJointIndexToUnityJointIndexMapping;
static void Initialize()
{
if (pxrJointIndexToUnityJointIndexMapping == null)
{
pxrJointIndexToUnityJointIndexMapping = new int[(int)HandJoint.JointMax];
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointPalm] = XRHandJointID.Palm.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointWrist] = XRHandJointID.Wrist.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbMetacarpal] = XRHandJointID.ThumbMetacarpal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbProximal] = XRHandJointID.ThumbProximal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbDistal] = XRHandJointID.ThumbDistal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointThumbTip] = XRHandJointID.ThumbTip.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexMetacarpal] = XRHandJointID.IndexMetacarpal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexProximal] = XRHandJointID.IndexProximal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexIntermediate] = XRHandJointID.IndexIntermediate.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexDistal] = XRHandJointID.IndexDistal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointIndexTip] = XRHandJointID.IndexTip.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleMetacarpal] = XRHandJointID.MiddleMetacarpal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleProximal] = XRHandJointID.MiddleProximal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleIntermediate] = XRHandJointID.MiddleIntermediate.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleDistal] = XRHandJointID.MiddleDistal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointMiddleTip] = XRHandJointID.MiddleTip.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingMetacarpal] = XRHandJointID.RingMetacarpal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingProximal] = XRHandJointID.RingProximal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingIntermediate] = XRHandJointID.RingIntermediate.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingDistal] = XRHandJointID.RingDistal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointRingTip] = XRHandJointID.RingTip.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleMetacarpal] = XRHandJointID.LittleMetacarpal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleProximal] = XRHandJointID.LittleProximal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleIntermediate] = XRHandJointID.LittleIntermediate.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleDistal] = XRHandJointID.LittleDistal.ToIndex();
pxrJointIndexToUnityJointIndexMapping[(int)HandJoint.JointLittleTip] = XRHandJointID.LittleTip.ToIndex();
}
}
/// <summary>
/// Gets the layout of hand joints for this provider, by having the
/// provider mark each index corresponding to a <see cref="XRHandJointID"/>
/// get marked as <see langword="true"/> if the provider attempts to track
/// that joint.
/// </summary>
/// <remarks>
/// Called once on creation so that before the subsystem is even started,
/// so the user can immediately create a valid hierarchical structure as
/// soon as they get a reference to the subsystem without even needing to
/// start it.
/// </remarks>
/// <param name="handJointsInLayout">
/// Each index corresponds to a <see cref="XRHandJointID"/>. For each
/// joint that the provider will attempt to track, mark that spot as
/// <see langword="true"/> by calling <c>.ToIndex()</c> on that ID.
/// </param>
public override void GetHandLayout(NativeArray<bool> handJointsInLayout)
{
Initialize();
handJointsInLayout[XRHandJointID.Palm.ToIndex()] = true;
handJointsInLayout[XRHandJointID.Wrist.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.ThumbTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.IndexTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.MiddleTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.RingTip.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleMetacarpal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleProximal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleIntermediate.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleDistal.ToIndex()] = true;
handJointsInLayout[XRHandJointID.LittleTip.ToIndex()] = true;
isValid = true;
}
/// <summary>
/// Attempts to retrieve current hand-tracking data from the provider.
/// </summary>
public override UpdateSuccessFlags TryUpdateHands(
UpdateType updateType,
ref Pose leftHandRootPose,
NativeArray<XRHandJoint> leftHandJoints,
ref Pose rightHandRootPose,
NativeArray<XRHandJoint> rightHandJoints)
{
if (!isValid)
return UpdateSuccessFlags.None;
UpdateSuccessFlags ret = UpdateSuccessFlags.None;
const int handRootIndex = (int)HandJoint.JointWrist;
if (PXR_HandTracking.GetJointLocations(HandType.HandLeft, ref jointLocations))
{
if (jointLocations.isActive != 0U)
{
for (int index = 0, jointCount = (int)jointLocations.jointCount; index < jointCount; ++index)
{
ref HandJointLocation joint = ref jointLocations.jointLocations[index];
int unityHandJointIndex = pxrJointIndexToUnityJointIndexMapping[index];
leftHandJoints[unityHandJointIndex] = CreateXRHandJoint(Handedness.Left, unityHandJointIndex, joint);
if (index == handRootIndex)
{
leftHandRootPose = PXRPosefToUnityPose(joint.pose);
ret |= UpdateSuccessFlags.LeftHandRootPose;
}
}
#if UNITY_EDITOR
ret |= UpdateSuccessFlags.LeftHandJoints;
#else
if (PicoAimHand.left.UpdateHand(HandType.HandLeft, (ret & UpdateSuccessFlags.LeftHandRootPose) != 0))
{
ret |= UpdateSuccessFlags.LeftHandJoints;
}
#endif
}
}
if (PXR_HandTracking.GetJointLocations(HandType.HandRight, ref jointLocations))
{
if (jointLocations.isActive != 0U)
{
for (int index = 0, jointCount = (int)jointLocations.jointCount; index < jointCount; ++index)
{
ref HandJointLocation joint = ref jointLocations.jointLocations[index];
int unityHandJointIndex = pxrJointIndexToUnityJointIndexMapping[index];
rightHandJoints[unityHandJointIndex] = CreateXRHandJoint(Handedness.Right, unityHandJointIndex, joint);
if (index == handRootIndex)
{
rightHandRootPose = PXRPosefToUnityPose(joint.pose);
ret |= UpdateSuccessFlags.RightHandRootPose;
}
}
#if UNITY_EDITOR
ret |= UpdateSuccessFlags.RightHandJoints;
#else
if (PicoAimHand.right.UpdateHand(HandType.HandRight, (ret & UpdateSuccessFlags.RightHandRootPose) != 0))
{
ret |= UpdateSuccessFlags.RightHandJoints;
}
#endif
}
}
return ret;
}
void CreateHands()
{
if (PicoAimHand.left == null)
PicoAimHand.left = PicoAimHand.CreateHand(InputDeviceCharacteristics.Left);
if (PicoAimHand.right == null)
PicoAimHand.right = PicoAimHand.CreateHand(InputDeviceCharacteristics.Right);
}
void DestroyHands()
{
if (PicoAimHand.left != null)
{
InputSystem.RemoveDevice(PicoAimHand.left);
PicoAimHand.left = null;
}
if (PicoAimHand.right != null)
{
InputSystem.RemoveDevice(PicoAimHand.right);
PicoAimHand.right = null;
}
}
/// <summary>
/// Create Unity XRHandJoint From PXR HandJointLocation
/// </summary>
/// <param name="handedness"></param>
/// <param name="unityHandJointIndex"></param>
/// <param name="joint"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
XRHandJoint CreateXRHandJoint(Handedness handedness, int unityHandJointIndex, in HandJointLocation joint)
{
Pose pose = Pose.identity;
XRHandJointTrackingState state = XRHandJointTrackingState.None;
if ((joint.locationStatus & AllStatus) == AllStatus)
{
state = (XRHandJointTrackingState.Pose | XRHandJointTrackingState.Radius);
pose = PXRPosefToUnityPose(joint.pose);
}
return XRHandProviderUtility.CreateJoint(handedness,
state,
XRHandJointIDUtility.FromIndex(unityHandJointIndex),
pose, joint.radius
);
}
/// <summary>
/// PXR's Posef to Unity'Pose
/// </summary>
/// <param name="pxrPose"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Pose PXRPosefToUnityPose(in Posef pxrPose)
{
Vector3 position = pxrPose.Position.ToVector3();
Quaternion orientation = pxrPose.Orientation.ToQuat();
return new Pose(position, orientation);
}
}
}
/// <remarks>
/// The <see cref="TrackedDevice.devicePosition"/> and
/// <see cref="TrackedDevice.deviceRotation"/> inherited from <see cref="TrackedDevice"/>
/// represent the aim pose. You can use these values to discover the target for pinch gestures,
/// when appropriate.
///
/// Use the [XROrigin](xref:Unity.XR.CoreUtils.XROrigin) in the scene to position and orient
/// the device properly. If you are using this data to set the Transform of a GameObject in
/// the scene hierarchy, you can set the local position and rotation of the Transform and make
/// it a child of the <c>CameraOffset</c> object below the <c>XROrigin</c>. Otherwise, you can use the
/// Transform of the <c>CameraOffset</c> to transform the data into world space.
/// </remarks>
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoad]
#endif
[Preserve, InputControlLayout(displayName = "Pico Aim Hand", commonUsages = new[] { "LeftHand", "RightHand" })]
public partial class PicoAimHand : TrackedDevice
{
/// <summary>
/// The left-hand <see cref="InputDevice"/> that contains
/// <see cref="InputControl"/>s that surface data in the Pico Hand
/// Tracking Aim extension.
/// </summary>
/// <remarks>
/// It is recommended that you treat this as read-only, and do not set
/// it yourself. It will be set for you if hand-tracking has been
/// enabled and if you are running with either the OpenXR or Oculus
/// plug-in.
/// </remarks>
public static PicoAimHand left { get; set; }
/// <summary>
/// The right-hand <see cref="InputDevice"/> that contains
/// <see cref="InputControl"/>s that surface data in the Pico Hand
/// Tracking Aim extension.
/// </summary>
/// <remarks>
/// It is recommended that you treat this as read-only, and do not set
/// it yourself. It will be set for you if hand-tracking has been
/// enabled and if you are running with either the OpenXR or Oculus
/// plug-in.
/// </remarks>
public static PicoAimHand right { get; set; }
/// <summary>
/// The pinch amount required to register as being pressed for the
/// purposes of <see cref="indexPressed"/>, <see cref="middlePressed"/>,
/// <see cref="ringPressed"/>, and <see cref="littlePressed"/>.
/// </summary>
public const float pressThreshold = 0.8f;
/// <summary>
/// A [ButtonControl](xref:UnityEngine.InputSystem.Controls.ButtonControl)
/// that represents whether the pinch between the index finger and
/// the thumb is mostly pressed (greater than a threshold of <c>0.8</c>
/// contained in <see cref="pressThreshold"/>).
/// </summary>
[Preserve, InputControl(offset = 0)]
public ButtonControl indexPressed { get; private set; }
/// <summary>
/// Cast the result of reading this to <see cref="PicoAimFlags"/> to examine the value.
/// </summary>
[Preserve, InputControl]
public IntegerControl aimFlags { get; private set; }
/// <summary>
/// An [AxisControl](xref:UnityEngine.InputSystem.Controls.AxisControl)
/// that represents the pinch strength between the index finger and
/// the thumb.
/// </summary>
/// <remarks>
/// A value of <c>0</c> denotes no pinch at all, while a value of
/// <c>1</c> denotes a full pinch.
/// </remarks>
[Preserve, InputControl]
public AxisControl pinchStrengthIndex { get; private set; }
/// <summary>
/// Perform final initialization tasks after the control hierarchy has been put into place.
/// </summary>
protected override void FinishSetup()
{
base.FinishSetup();
indexPressed = GetChildControl<ButtonControl>(nameof(indexPressed));
aimFlags = GetChildControl<IntegerControl>(nameof(aimFlags));
pinchStrengthIndex = GetChildControl<AxisControl>(nameof(pinchStrengthIndex));
var deviceDescriptor = XRDeviceDescriptor.FromJson(description.capabilities);
if (deviceDescriptor != null)
{
if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Left) != 0)
InputSystem.SetDeviceUsage(this, UnityEngine.InputSystem.CommonUsages.LeftHand);
else if ((deviceDescriptor.characteristics & InputDeviceCharacteristics.Right) != 0)
InputSystem.SetDeviceUsage(this, UnityEngine.InputSystem.CommonUsages.RightHand);
}
PXR_Plugin.System.FocusStateAcquired += OnFocusStateAcquired;
}
private void OnFocusStateAcquired()
{
m_WasTracked = false;
}
protected override void OnRemoved()
{
PXR_Plugin.System.FocusStateAcquired -= OnFocusStateAcquired;
base.OnRemoved();
}
/// <summary>
/// Creates a <see cref="PicoAimHand"/> and adds it to the Input System.
/// </summary>
/// <param name="extraCharacteristics">
/// Additional characteristics to build the hand device with besides
/// <see cref="InputDeviceCharacteristics.HandTracking"/> and <see cref="InputDeviceCharacteristics.TrackedDevice"/>.
/// </param>
/// <returns>
/// A <see cref="PicoAimHand"/> retrieved from
/// <see cref="InputSystem.AddDevice(InputDeviceDescription)"/>.
/// </returns>
/// <remarks>
/// It is recommended that you do not call this yourself. It will be
/// called for you at the appropriate time if hand-tracking has been
/// enabled and if you are running with either the OpenXR or Oculus
/// plug-in.
/// </remarks>
public static PicoAimHand CreateHand(InputDeviceCharacteristics extraCharacteristics)
{
var desc = new InputDeviceDescription
{
product = k_PicoAimHandDeviceProductName,
capabilities = new XRDeviceDescriptor
{
characteristics = InputDeviceCharacteristics.HandTracking | InputDeviceCharacteristics.TrackedDevice | extraCharacteristics,
inputFeatures = new List<XRFeatureDescriptor>
{
new XRFeatureDescriptor
{
name = "index_pressed",
featureType = FeatureType.Binary
},
new XRFeatureDescriptor
{
name = "aim_flags",
featureType = FeatureType.DiscreteStates
},
new XRFeatureDescriptor
{
name = "aim_pose_position",
featureType = FeatureType.Axis3D
},
new XRFeatureDescriptor
{
name = "aim_pose_rotation",
featureType = FeatureType.Rotation
},
new XRFeatureDescriptor
{
name = "pinch_strength_index",
featureType = FeatureType.Axis1D
}
}
}.ToJson()
};
return InputSystem.AddDevice(desc) as PicoAimHand;
}
/// <summary>
/// Queues update events in the Input System based on the supplied hand.
/// It is not recommended that you call this directly. This will be called
/// for you when appropriate.
/// </summary>
/// <param name="isHandRootTracked">
/// Whether the hand root pose is valid.
/// </param>
/// <param name="aimFlags">
/// The aim flags to update in the Input System.
/// </param>
/// <param name="aimPose">
/// The aim pose to update in the Input System. Used if the hand root is tracked.
/// </param>
/// <param name="pinchIndex">
/// The pinch strength for the index finger to update in the Input System.
/// </param>
public void UpdateHand(bool isHandRootTracked, HandAimStatus aimFlags, Posef aimPose, float pinchIndex)
{
if (aimFlags != m_PreviousFlags)
{
InputSystem.QueueDeltaStateEvent(this.aimFlags, (int)aimFlags);
m_PreviousFlags = aimFlags;
}
bool isIndexPressed = pinchIndex > pressThreshold;
if (isIndexPressed != m_WasIndexPressed)
{
InputSystem.QueueDeltaStateEvent(indexPressed, isIndexPressed);
m_WasIndexPressed = isIndexPressed;
}
InputSystem.QueueDeltaStateEvent(pinchStrengthIndex, pinchIndex);
if ((aimFlags & HandAimStatus.AimComputed) == 0)
{
if (m_WasTracked)
{
InputSystem.QueueDeltaStateEvent(isTracked, false);
InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.None);
m_WasTracked = false;
}
return;
}
if (isHandRootTracked)
{
InputSystem.QueueDeltaStateEvent(devicePosition, aimPose.Position.ToVector3());
InputSystem.QueueDeltaStateEvent(deviceRotation, aimPose.Orientation.ToQuat());
if (!m_WasTracked)
{
InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.Position | InputTrackingState.Rotation);
InputSystem.QueueDeltaStateEvent(isTracked, true);
}
m_WasTracked = true;
}
else if (m_WasTracked)
{
InputSystem.QueueDeltaStateEvent(trackingState, InputTrackingState.None);
InputSystem.QueueDeltaStateEvent(isTracked, false);
m_WasTracked = false;
}
}
internal bool UpdateHand(HandType handType, bool isHandRootTracked)
{
HandAimState handAimState = new HandAimState();
PXR_HandTracking.GetAimState(handType, ref handAimState);
UpdateHand(
isHandRootTracked,
handAimState.aimStatus,
handAimState.aimRayPose,
handAimState.touchStrengthRay);
return (handAimState.aimStatus&HandAimStatus.AimComputed) != 0;
}
#if UNITY_EDITOR
static PicoAimHand() => RegisterLayout();
#endif
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void RegisterLayout()
{
InputSystem.RegisterLayout<PicoAimHand>(
matches: new InputDeviceMatcher()
.WithProduct(k_PicoAimHandDeviceProductName));
}
const string k_PicoAimHandDeviceProductName = "Pico Aim Hand Tracking";
HandAimStatus m_PreviousFlags;
bool m_WasTracked;
bool m_WasIndexPressed;
}
}
#endif //XR_HANDS
#endif

View File

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

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0d02828fb7cb42f399ff5ba545b8ca23
timeCreated: 1737536276

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

View File

@@ -0,0 +1,534 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Rendering;
namespace Unity.XR.PXR
{
public class PXR_CompositionLayerManager : MonoBehaviour
{
bool isURP = false;
private void OnEnable()
{
#if UNITY_6000_0_OR_NEWER
if (GraphicsSettings.currentRenderPipeline != null)
#else
if (GraphicsSettings.renderPipelineAsset != null)
#endif
{
#if UNITY_2023_3_OR_NEWER
RenderPipelineManager.beginContextRendering += BeginRendering;
#else
RenderPipelineManager.beginFrameRendering += BeginRendering;
#endif
isURP = true;
}
else
{
Camera.onPreRender += OnPreRenderCallBack;
isURP = false;
}
}
private void OnDisable()
{
#if UNITY_6000_0_OR_NEWER
if (GraphicsSettings.currentRenderPipeline != null)
#else
if (GraphicsSettings.renderPipelineAsset != null)
#endif
{
#if UNITY_2023_3_OR_NEWER
RenderPipelineManager.beginContextRendering -= BeginRendering;
#else
RenderPipelineManager.beginFrameRendering -= BeginRendering;
#endif
}
else
{
Camera.onPreRender -= OnPreRenderCallBack;
}
}
private void Start()
{
// external surface
if (PXR_CompositionLayer.Instances.Count > 0)
{
foreach (var overlay in PXR_CompositionLayer.Instances)
{
if (overlay.isExternalAndroidSurface)
{
overlay.CreateExternalSurface(overlay);
}
}
}
}
#if UNITY_2023_3_OR_NEWER
private void BeginRendering(ScriptableRenderContext arg1, List<Camera> arg2)
#else
private void BeginRendering(ScriptableRenderContext arg1, Camera[] arg2)
#endif
{
foreach (Camera cam in arg2)
{
if (cam != null && Camera.main == cam)
{
OnPreRenderCallBack(cam);
}
}
}
private void OnPreRenderCallBack(Camera cam)
{
// There is only one XR main camera in the scene.
if (null == Camera.main) return;
if (cam == null || cam != Camera.main || cam.stereoActiveEye == Camera.MonoOrStereoscopicEye.Right) return;
//CompositeLayers
int boundaryState = PXR_Plugin.Boundary.seeThroughState;
if (null == PXR_CompositionLayer.Instances) return;
if (PXR_CompositionLayer.Instances.Count > 0 && boundaryState != 2)
{
foreach (var overlay in PXR_CompositionLayer.Instances)
{
if (!overlay.isActiveAndEnabled) continue;
if (null == overlay.layerTextures) continue;
if (overlay.isExternalAndroidSurface)
{
overlay.CreateExternalSurface(overlay);
continue;
}
if (!overlay.isClones && overlay.layerTextures[0] == null && overlay.layerTextures[1] == null && !overlay.isExternalAndroidSurface) continue;
if (overlay.overlayTransform != null && !overlay.overlayTransform.gameObject.activeSelf) continue;
overlay.CreateTexture();
}
}
Submitlayers();
}
void Submitlayers()
{
int boundaryState = PXR_Plugin.Boundary.seeThroughState;
if (null == PXR_CompositionLayer.Instances) return;
if (PXR_CompositionLayer.Instances.Count > 0 && boundaryState != 2)
{
PXR_CompositionLayer.Instances.Sort();
foreach (var compositeLayer in PXR_CompositionLayer.Instances)
{
if (null == compositeLayer) continue;
compositeLayer.UpdateCoords();
if (!compositeLayer.isActiveAndEnabled) continue;
if (null == compositeLayer.layerTextures) continue;
if (!compositeLayer.isClones && compositeLayer.layerTextures[0] == null && compositeLayer.layerTextures[1] == null && !compositeLayer.isExternalAndroidSurface) continue;
if (compositeLayer.overlayTransform != null && null == compositeLayer.overlayTransform.gameObject) continue;
if (compositeLayer.overlayTransform != null && !compositeLayer.overlayTransform.gameObject.activeSelf) continue;
Vector4 colorScale = compositeLayer.GetLayerColorScale();
Vector4 colorBias = compositeLayer.GetLayerColorOffset();
bool isHeadLocked = false;
if (compositeLayer.overlayTransform != null && compositeLayer.overlayTransform.parent == transform)
{
isHeadLocked = true;
}
if (!compositeLayer.isExternalAndroidSurface && !compositeLayer.CopyRT()) continue;
if (null == compositeLayer.cameraRotations || null == compositeLayer.modelScales || null == compositeLayer.modelTranslations) continue;
PxrLayerHeader2 header = new PxrLayerHeader2();
PxrPosef poseLeft = new PxrPosef();
PxrPosef poseRight = new PxrPosef();
header.layerId = compositeLayer.overlayIndex;
header.colorScaleX = colorScale.x;
header.colorScaleY = colorScale.y;
header.colorScaleZ = colorScale.z;
header.colorScaleW = colorScale.w;
header.colorBiasX = colorBias.x;
header.colorBiasY = colorBias.y;
header.colorBiasZ = colorBias.z;
header.colorBiasW = colorBias.w;
header.compositionDepth = compositeLayer.layerDepth;
header.headPose.orientation.x = compositeLayer.cameraRotations[0].x;
header.headPose.orientation.y = compositeLayer.cameraRotations[0].y;
header.headPose.orientation.z = -compositeLayer.cameraRotations[0].z;
header.headPose.orientation.w = -compositeLayer.cameraRotations[0].w;
header.headPose.position.x = (compositeLayer.cameraTranslations[0].x + compositeLayer.cameraTranslations[1].x) / 2;
header.headPose.position.y = (compositeLayer.cameraTranslations[0].y + compositeLayer.cameraTranslations[1].y) / 2;
header.headPose.position.z = -(compositeLayer.cameraTranslations[0].z + compositeLayer.cameraTranslations[1].z) / 2;
header.layerShape = compositeLayer.overlayShape;
header.useLayerBlend = (UInt32)(compositeLayer.useLayerBlend ? 1 : 0);
header.layerBlend.srcColor = compositeLayer.srcColor;
header.layerBlend.dstColor = compositeLayer.dstColor;
header.layerBlend.srcAlpha = compositeLayer.srcAlpha;
header.layerBlend.dstAlpha = compositeLayer.dstAlpha;
header.useImageRect = (UInt32)(compositeLayer.useImageRect ? 1 : 0);
header.imageRectLeft = compositeLayer.getPxrRectiLeft(true);
header.imageRectRight = compositeLayer.getPxrRectiLeft(false);
header.colorMatrix = compositeLayer.colorMatrix;
if (isHeadLocked)
{
poseLeft.orientation.x = compositeLayer.overlayTransform.localRotation.x;
poseLeft.orientation.y = compositeLayer.overlayTransform.localRotation.y;
poseLeft.orientation.z = -compositeLayer.overlayTransform.localRotation.z;
poseLeft.orientation.w = -compositeLayer.overlayTransform.localRotation.w;
poseLeft.position.x = compositeLayer.overlayTransform.localPosition.x;
poseLeft.position.y = compositeLayer.overlayTransform.localPosition.y;
poseLeft.position.z = -compositeLayer.overlayTransform.localPosition.z;
poseRight.orientation.x = compositeLayer.overlayTransform.localRotation.x;
poseRight.orientation.y = compositeLayer.overlayTransform.localRotation.y;
poseRight.orientation.z = -compositeLayer.overlayTransform.localRotation.z;
poseRight.orientation.w = -compositeLayer.overlayTransform.localRotation.w;
poseRight.position.x = compositeLayer.overlayTransform.localPosition.x;
poseRight.position.y = compositeLayer.overlayTransform.localPosition.y;
poseRight.position.z = -compositeLayer.overlayTransform.localPosition.z;
header.layerFlags = (UInt32)(
PxrLayerSubmitFlags.PxrLayerFlagLayerPoseNotInTrackingSpace |
PxrLayerSubmitFlags.PxrLayerFlagHeadLocked);
}
else
{
poseLeft.orientation.x = compositeLayer.modelRotations[0].x;
poseLeft.orientation.y = compositeLayer.modelRotations[0].y;
poseLeft.orientation.z = -compositeLayer.modelRotations[0].z;
poseLeft.orientation.w = -compositeLayer.modelRotations[0].w;
poseLeft.position.x = compositeLayer.modelTranslations[0].x;
poseLeft.position.y = compositeLayer.modelTranslations[0].y;
poseLeft.position.z = -compositeLayer.modelTranslations[0].z;
poseRight.orientation.x = compositeLayer.modelRotations[0].x;
poseRight.orientation.y = compositeLayer.modelRotations[0].y;
poseRight.orientation.z = -compositeLayer.modelRotations[0].z;
poseRight.orientation.w = -compositeLayer.modelRotations[0].w;
poseRight.position.x = compositeLayer.modelTranslations[0].x;
poseRight.position.y = compositeLayer.modelTranslations[0].y;
poseRight.position.z = -compositeLayer.modelTranslations[0].z;
header.layerFlags = (UInt32)(
PxrLayerSubmitFlags.PxrLayerFlagUseExternalHeadPose |
PxrLayerSubmitFlags.PxrLayerFlagLayerPoseNotInTrackingSpace);
}
header.layerFlags |= compositeLayer.getHDRFlags();
if (compositeLayer.useTextureAlphaBlending)
{
header.layerFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagSourceAlpha_1_0;
}
if (compositeLayer.usePremultipliedAlpha)
{
header.layerFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagPremultipliedAlpha;
}
if (!compositeLayer.enableSubmitLayer)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagFixLayer);
}
if (compositeLayer.superResolution)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableSuperResolution);
}
if (compositeLayer.normalSupersampling)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableNormalSupersampling);
}
if (compositeLayer.qualitySupersampling)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableQualitySupersampling);
}
if (compositeLayer.fixedFoveatedSupersampling)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableFixedFoveatedSupersampling);
}
if (compositeLayer.normalSharpening)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableNormalSharpening);
}
if (compositeLayer.qualitySharpening)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableQualitySharpening);
}
if (compositeLayer.fixedFoveatedSharpening)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableFixedFoveatedSharpening);
}
if (compositeLayer.selfAdaptiveSharpening)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableSelfAdaptiveSharpening);
}
if (compositeLayer.overlayShape == PXR_CompositionLayer.OverlayShape.Quad)
{
PxrLayerQuad2 layerSubmit2 = new PxrLayerQuad2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
layerSubmit2.sizeLeft.x = compositeLayer.modelScales[0].x;
layerSubmit2.sizeLeft.y = compositeLayer.modelScales[0].y;
layerSubmit2.sizeRight.x = compositeLayer.modelScales[0].x;
layerSubmit2.sizeRight.y = compositeLayer.modelScales[0].y;
if (compositeLayer.useImageRect)
{
Vector3 lPos = new Vector3();
Vector3 rPos = new Vector3();
Quaternion quaternion = new Quaternion(compositeLayer.modelRotations[0].x, compositeLayer.modelRotations[0].y, -compositeLayer.modelRotations[0].z, -compositeLayer.modelRotations[0].w);
lPos.x = compositeLayer.modelScales[0].x * (-0.5f + compositeLayer.dstRectLeft.x + 0.5f * Mathf.Min(compositeLayer.dstRectLeft.width, 1 - compositeLayer.dstRectLeft.x));
lPos.y = compositeLayer.modelScales[0].y * (-0.5f + compositeLayer.dstRectLeft.y + 0.5f * Mathf.Min(compositeLayer.dstRectLeft.height, 1 - compositeLayer.dstRectLeft.y));
lPos.z = 0;
lPos = quaternion * lPos;
layerSubmit2.poseLeft.position.x += lPos.x;
layerSubmit2.poseLeft.position.y += lPos.y;
layerSubmit2.poseLeft.position.z += lPos.z;
rPos.x = compositeLayer.modelScales[0].x * (-0.5f + compositeLayer.dstRectRight.x + 0.5f * Mathf.Min(compositeLayer.dstRectRight.width, 1 - compositeLayer.dstRectRight.x));
rPos.y = compositeLayer.modelScales[0].y * (-0.5f + compositeLayer.dstRectRight.y + 0.5f * Mathf.Min(compositeLayer.dstRectRight.height, 1 - compositeLayer.dstRectRight.y));
rPos.z = 0;
rPos = quaternion * rPos;
layerSubmit2.poseRight.position.x += rPos.x;
layerSubmit2.poseRight.position.y += rPos.y;
layerSubmit2.poseRight.position.z += rPos.z;
layerSubmit2.sizeLeft.x = compositeLayer.modelScales[0].x * Mathf.Min(compositeLayer.dstRectLeft.width, 1 - compositeLayer.dstRectLeft.x);
layerSubmit2.sizeLeft.y = compositeLayer.modelScales[0].y * Mathf.Min(compositeLayer.dstRectLeft.height, 1 - compositeLayer.dstRectLeft.y);
layerSubmit2.sizeRight.x = compositeLayer.modelScales[0].x * Mathf.Min(compositeLayer.dstRectRight.width, 1 - compositeLayer.dstRectRight.x);
layerSubmit2.sizeRight.y = compositeLayer.modelScales[0].y * Mathf.Min(compositeLayer.dstRectRight.height, 1 - compositeLayer.dstRectRight.y);
}
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerQuad2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_CompositionLayer.OverlayShape.Cylinder)
{
PxrLayerCylinder2 layerSubmit2 = new PxrLayerCylinder2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
if (compositeLayer.modelScales[0].z != 0)
{
layerSubmit2.centralAngleLeft = compositeLayer.modelScales[0].x / compositeLayer.modelScales[0].z;
layerSubmit2.centralAngleRight = compositeLayer.modelScales[0].x / compositeLayer.modelScales[0].z;
}
else
{
Debug.LogError("PXRLog scale.z is 0");
}
layerSubmit2.heightLeft = compositeLayer.modelScales[0].y;
layerSubmit2.heightRight = compositeLayer.modelScales[0].y;
layerSubmit2.radiusLeft = compositeLayer.modelScales[0].z;
layerSubmit2.radiusRight = compositeLayer.modelScales[0].z;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerCylinder2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_CompositionLayer.OverlayShape.Equirect)
{
PxrLayerEquirect2 layerSubmit2 = new PxrLayerEquirect2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
layerSubmit2.header.layerShape = PXR_CompositionLayer.OverlayShape.Equirect;
layerSubmit2.radiusLeft = compositeLayer.radius;
layerSubmit2.radiusRight = compositeLayer.radius;
layerSubmit2.centralHorizontalAngleLeft = compositeLayer.dstRectLeft.width * 2 * Mathf.PI;
layerSubmit2.centralHorizontalAngleRight = compositeLayer.dstRectRight.width * 2 * Mathf.PI;
layerSubmit2.upperVerticalAngleLeft = (compositeLayer.dstRectLeft.height + compositeLayer.dstRectLeft.y - 0.5f) * Mathf.PI;
layerSubmit2.upperVerticalAngleRight = (compositeLayer.dstRectRight.height + compositeLayer.dstRectRight.y - 0.5f) * Mathf.PI;
layerSubmit2.lowerVerticalAngleLeft = (compositeLayer.dstRectLeft.y - 0.5f) * Mathf.PI;
layerSubmit2.lowerVerticalAngleRight = (compositeLayer.dstRectRight.y - 0.5f) * Mathf.PI;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerEquirect2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_CompositionLayer.OverlayShape.Cubemap)
{
PxrLayerCube2 layerSubmit2 = new PxrLayerCube2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerCube2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_CompositionLayer.OverlayShape.Eac)
{
PxrLayerEac2 layerSubmit2 = new PxrLayerEac2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
layerSubmit2.offsetPosLeft.x = compositeLayer.offsetPosLeft.x;
layerSubmit2.offsetPosLeft.y = compositeLayer.offsetPosLeft.y;
layerSubmit2.offsetPosLeft.z = compositeLayer.offsetPosLeft.z;
layerSubmit2.offsetPosRight.x = compositeLayer.offsetPosRight.x;
layerSubmit2.offsetPosRight.y = compositeLayer.offsetPosRight.y;
layerSubmit2.offsetPosRight.z = compositeLayer.offsetPosRight.z;
layerSubmit2.offsetRotLeft.x = compositeLayer.offsetRotLeft.x;
layerSubmit2.offsetRotLeft.y = compositeLayer.offsetRotLeft.y;
layerSubmit2.offsetRotLeft.z = compositeLayer.offsetRotLeft.z;
layerSubmit2.offsetRotLeft.w = compositeLayer.offsetRotLeft.w;
layerSubmit2.offsetRotRight.x = compositeLayer.offsetRotRight.x;
layerSubmit2.offsetRotRight.y = compositeLayer.offsetRotRight.y;
layerSubmit2.offsetRotRight.z = compositeLayer.offsetRotRight.z;
layerSubmit2.offsetRotRight.w = compositeLayer.offsetRotRight.w;
layerSubmit2.degreeType = (uint)compositeLayer.eacModelType;
layerSubmit2.overlapFactor = compositeLayer.overlapFactor;
layerSubmit2.timestamp = compositeLayer.timestamp;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerEac2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_CompositionLayer.OverlayShape.Fisheye)
{
PxrLayerFisheye layerSubmit = new PxrLayerFisheye();
layerSubmit.header = header;
layerSubmit.poseLeft = poseLeft;
layerSubmit.poseRight = poseRight;
layerSubmit.header.layerShape = PXR_CompositionLayer.OverlayShape.Fisheye;
layerSubmit.radiusLeft = compositeLayer.radius;
layerSubmit.radiusRight = compositeLayer.radius;
layerSubmit.scaleXLeft = 1 / compositeLayer.dstRectLeft.width;
layerSubmit.scaleXRight = 1 / compositeLayer.dstRectRight.width;
layerSubmit.scaleYLeft = 1 / compositeLayer.dstRectLeft.height;
layerSubmit.scaleYRight = 1 / compositeLayer.dstRectRight.height;
layerSubmit.biasXLeft = -compositeLayer.dstRectLeft.x / compositeLayer.dstRectLeft.width;
layerSubmit.biasXRight = -compositeLayer.dstRectRight.x / compositeLayer.dstRectRight.width;
layerSubmit.biasYLeft = 1 + (compositeLayer.dstRectLeft.y - 1) / compositeLayer.dstRectLeft.height;
layerSubmit.biasYRight = 1 + (compositeLayer.dstRectRight.y - 1) / compositeLayer.dstRectRight.height;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit));
Marshal.StructureToPtr(layerSubmit, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerFisheyeByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_CompositionLayer.OverlayShape.BlurredQuad)
{
PxrLayerQuad2 layerSubmit2 = new PxrLayerQuad2();
if (PXR_CompositionLayer.BlurredQuadMode.SmallWindow == compositeLayer.blurredQuadMode)
{
header.layerFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagBlurredQuadModeSmallWindow;
}
else if (PXR_CompositionLayer.BlurredQuadMode.Immersion == compositeLayer.blurredQuadMode)
{
header.layerFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagBlurredQuadModeImmersion;
}
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
layerSubmit2.sizeLeft.x = compositeLayer.modelScales[0].x;
layerSubmit2.sizeLeft.y = compositeLayer.modelScales[0].y;
layerSubmit2.sizeRight.x = compositeLayer.modelScales[0].x;
layerSubmit2.sizeRight.y = compositeLayer.modelScales[0].y;
if (compositeLayer.useImageRect)
{
Vector3 lPos = new Vector3();
Vector3 rPos = new Vector3();
Quaternion quaternion = new Quaternion(compositeLayer.modelRotations[0].x, compositeLayer.modelRotations[0].y, -compositeLayer.modelRotations[0].z, -compositeLayer.modelRotations[0].w);
lPos.x = compositeLayer.modelScales[0].x * (-0.5f + compositeLayer.dstRectLeft.x + 0.5f * Mathf.Min(compositeLayer.dstRectLeft.width, 1 - compositeLayer.dstRectLeft.x));
lPos.y = compositeLayer.modelScales[0].y * (-0.5f + compositeLayer.dstRectLeft.y + 0.5f * Mathf.Min(compositeLayer.dstRectLeft.height, 1 - compositeLayer.dstRectLeft.y));
lPos.z = 0;
lPos = quaternion * lPos;
layerSubmit2.poseLeft.position.x += lPos.x;
layerSubmit2.poseLeft.position.y += lPos.y;
layerSubmit2.poseLeft.position.z += lPos.z;
rPos.x = compositeLayer.modelScales[0].x * (-0.5f + compositeLayer.dstRectRight.x + 0.5f * Mathf.Min(compositeLayer.dstRectRight.width, 1 - compositeLayer.dstRectRight.x));
rPos.y = compositeLayer.modelScales[0].y * (-0.5f + compositeLayer.dstRectRight.y + 0.5f * Mathf.Min(compositeLayer.dstRectRight.height, 1 - compositeLayer.dstRectRight.y));
rPos.z = 0;
rPos = quaternion * rPos;
layerSubmit2.poseRight.position.x += rPos.x;
layerSubmit2.poseRight.position.y += rPos.y;
layerSubmit2.poseRight.position.z += rPos.z;
layerSubmit2.sizeLeft.x = compositeLayer.modelScales[0].x * Mathf.Min(compositeLayer.dstRectLeft.width, 1 - compositeLayer.dstRectLeft.x);
layerSubmit2.sizeLeft.y = compositeLayer.modelScales[0].y * Mathf.Min(compositeLayer.dstRectLeft.height, 1 - compositeLayer.dstRectLeft.y);
layerSubmit2.sizeRight.x = compositeLayer.modelScales[0].x * Mathf.Min(compositeLayer.dstRectRight.width, 1 - compositeLayer.dstRectRight.x);
layerSubmit2.sizeRight.y = compositeLayer.modelScales[0].y * Mathf.Min(compositeLayer.dstRectRight.height, 1 - compositeLayer.dstRectRight.y);
}
layerSubmit2.blurredQuadScale = compositeLayer.blurredQuadScale;
layerSubmit2.blurredQuadShift = compositeLayer.blurredQuadShift;
layerSubmit2.blurredQuadFOV = compositeLayer.blurredQuadFOV;
layerSubmit2.blurredQuadIPD = compositeLayer.blurredQuadIPD;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerQuad2ByRender(compositeLayer.layerSubmitPtr);
}
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,680 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Management;
using UnityEngine.XR;
using AOT;
#if UNITY_INPUT_SYSTEM
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.XR;
using Unity.XR.PXR.Input;
using System.Linq;
#if XR_COMPOSITION_LAYERS
using Unity.XR.CompositionLayers.Services;
#endif
#endif
#if UNITY_EDITOR
using UnityEditor;
#endif
#if AR_FOUNDATION_5 || AR_FOUNDATION_6
using UnityEngine.XR.ARSubsystems;
#endif
#if XR_HANDS
using UnityEngine.XR.Hands;
#endif
namespace Unity.XR.PXR
{
#if UNITY_INPUT_SYSTEM
#if UNITY_EDITOR
[InitializeOnLoad]
#endif
static class InputLayoutLoader
{
static InputLayoutLoader()
{
RegisterInputLayouts();
}
public static void RegisterInputLayouts()
{
InputSystem.RegisterLayout<PXR_HMD>(matches: new InputDeviceMatcher().WithInterface(XRUtilities.InterfaceMatchAnyVersion).WithProduct(@"^(PICO HMD)|^(PICO Neo)|^(PICO G)"));
InputSystem.RegisterLayout<PXR_Controller>(matches: new InputDeviceMatcher().WithInterface(XRUtilities.InterfaceMatchAnyVersion).WithProduct(@"^(PICO Controller)"));
}
}
#endif
public class PXR_Loader : XRLoaderHelper
#if UNITY_EDITOR
, IXRLoaderPreInit
#endif
{
private const string TAG = "PXR_Loader";
private static List<XRDisplaySubsystemDescriptor> displaySubsystemDescriptors = new List<XRDisplaySubsystemDescriptor>();
private static List<XRInputSubsystemDescriptor> inputSubsystemDescriptors = new List<XRInputSubsystemDescriptor>();
private static List<XRMeshSubsystemDescriptor> meshSubsystemDescriptors = new List<XRMeshSubsystemDescriptor>();
#if XR_HANDS
private static List<XRHandSubsystemDescriptor> handSubsystemDescriptors = new List<XRHandSubsystemDescriptor>();
#endif
#if AR_FOUNDATION_5 || AR_FOUNDATION_6
private static List<XRSessionSubsystemDescriptor> sessionSubsystemDescriptors = new List<XRSessionSubsystemDescriptor>();
private static List<XRCameraSubsystemDescriptor> cameraSubsystemDescriptors = new List<XRCameraSubsystemDescriptor>();
private static List<XRFaceSubsystemDescriptor> faceSubsystemDescriptors = new List<XRFaceSubsystemDescriptor>();
private static List<XRHumanBodySubsystemDescriptor> humanBodySubsystemDescriptors = new List<XRHumanBodySubsystemDescriptor>();
private static List<XRAnchorSubsystemDescriptor> anchorSubsystemDescriptors = new List<XRAnchorSubsystemDescriptor>();
#endif
public delegate Quaternion ConvertRotationWith2VectorDelegate(Vector3 from, Vector3 to);
public XRDisplaySubsystem displaySubsystem
{
get
{
return GetLoadedSubsystem<XRDisplaySubsystem>();
}
}
public XRInputSubsystem inputSubsystem
{
get
{
return GetLoadedSubsystem<XRInputSubsystem>();
}
}
public XRMeshSubsystem meshSubsystem
{
get
{
return GetLoadedSubsystem<XRMeshSubsystem>();
}
}
internal enum LoaderState
{
Uninitialized,
InitializeAttempted,
Initialized,
StartAttempted,
Started,
StopAttempted,
Stopped,
DeinitializeAttempted
}
internal LoaderState currentLoaderState { get; private set; } = LoaderState.Uninitialized;
List<LoaderState> validLoaderInitStates = new List<LoaderState> { LoaderState.Uninitialized, LoaderState.InitializeAttempted };
List<LoaderState> validLoaderStartStates = new List<LoaderState> { LoaderState.Initialized, LoaderState.StartAttempted, LoaderState.Stopped };
List<LoaderState> validLoaderStopStates = new List<LoaderState> { LoaderState.StartAttempted, LoaderState.Started, LoaderState.StopAttempted };
List<LoaderState> validLoaderDeinitStates = new List<LoaderState> { LoaderState.InitializeAttempted, LoaderState.Initialized, LoaderState.Stopped, LoaderState.DeinitializeAttempted };
List<LoaderState> runningStates = new List<LoaderState>()
{
LoaderState.Initialized,
LoaderState.StartAttempted,
LoaderState.Started
};
public override bool Initialize()
{
Debug.Log($"{TAG} Initialize() currentLoaderState={currentLoaderState}");
#if UNITY_INPUT_SYSTEM
InputLayoutLoader.RegisterInputLayouts();
#endif
// #if UNITY_ANDROID
PXR_Settings settings = GetSettings();
if (settings != null)
{
UserDefinedSettings userDefinedSettings = new UserDefinedSettings
{
stereoRenderingMode = settings.GetStereoRenderingMode(),
colorSpace = (ushort)((QualitySettings.activeColorSpace == ColorSpace.Linear) ? 1 : 0),
useContentProtect = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().useContentProtect),
systemDisplayFrequency = settings.GetSystemDisplayFrequency(),
optimizeBufferDiscards = settings.GetOptimizeBufferDiscards(),
enableAppSpaceWarp = Convert.ToUInt16(settings.enableAppSpaceWarp),
enableSubsampled = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().enableSubsampled),
lateLatchingDebug = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().latelatchingDebug),
enableStageMode = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().stageMode),
enableSuperResolution = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().superResolution),
normalSharpening = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().normalSharpening),
qualitySharpening = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().qualitySharpening),
fixedFoveatedSharpening = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().fixedFoveatedSharpening),
selfAdaptiveSharpening = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().selfAdaptiveSharpening),
enableETFR = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().enableETFR),
foveationLevel = Convert.ToUInt16((int)PXR_ProjectSetting.GetProjectConfig().foveationLevel + 1),
spatialMeshLod = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().meshLod),
enableEyeTracking = Convert.ToUInt16(PXR_ProjectSetting.GetProjectConfig().eyeTracking),
dynamicFoveation =1,
};
PXR_Plugin.System.UPxr_SetUserDefinedSettings(userDefinedSettings);
}
PXR_Plugin.System.UPxr_SetXrEventDataBufferCallBack(XrEventDataBufferFunction);
// #endif
PXR_Plugin.System.ProductName = PXR_Plugin.System.UPxr_GetProductName();
if (currentLoaderState == LoaderState.Initialized)
return true;
if (!validLoaderInitStates.Contains(currentLoaderState))
return false;
if (displaySubsystem == null)
{
CreateSubsystem<XRDisplaySubsystemDescriptor, XRDisplaySubsystem>(displaySubsystemDescriptors, "PICO Display");
if (displaySubsystem == null)
return false;
}
if (inputSubsystem == null)
{
CreateSubsystem<XRInputSubsystemDescriptor, XRInputSubsystem>(inputSubsystemDescriptors, "PICO Input");
if (inputSubsystem == null)
return false;
}
if (PXR_ProjectSetting.GetProjectConfig().spatialMesh)
{
CreateSubsystem<XRMeshSubsystemDescriptor, XRMeshSubsystem>(meshSubsystemDescriptors, "PICO Mesh");
}
#if XR_HANDS
CreateSubsystem<XRHandSubsystemDescriptor, XRHandSubsystem>(handSubsystemDescriptors, "PICO Hands");
#endif
#if AR_FOUNDATION_5 || AR_FOUNDATION_6
if (PXR_ProjectSetting.GetProjectConfig().arFoundation)
{
CreateSubsystem<XRSessionSubsystemDescriptor, XRSessionSubsystem>(sessionSubsystemDescriptors, PXR_SessionSubsystem.k_SubsystemId);
CreateSubsystem<XRCameraSubsystemDescriptor, XRCameraSubsystem>(cameraSubsystemDescriptors, PXR_CameraSubsystem.k_SubsystemId);
if (PXR_ProjectSetting.GetProjectConfig().faceTracking)
{
CreateSubsystem<XRFaceSubsystemDescriptor, XRFaceSubsystem>(faceSubsystemDescriptors, PXR_FaceSubsystem.k_SubsystemId);
}
if (PXR_ProjectSetting.GetProjectConfig().bodyTracking)
{
CreateSubsystem<XRHumanBodySubsystemDescriptor, XRHumanBodySubsystem>(humanBodySubsystemDescriptors, PXR_HumanBodySubsystem.k_SubsystemId);
}
if (PXR_ProjectSetting.GetProjectConfig().spatialAnchor)
{
CreateSubsystem<XRAnchorSubsystemDescriptor, XRAnchorSubsystem>(anchorSubsystemDescriptors, PXR_AnchorSubsystem.k_SubsystemId);
}
}
#endif
if (displaySubsystem == null && inputSubsystem == null)
{
Debug.LogError("PXRLog Unable to start PICO Plugin.");
}
else if (displaySubsystem == null)
{
Debug.LogError("PXRLog Failed to load display subsystem.");
}
else if (inputSubsystem == null)
{
Debug.LogError("PXRLog Failed to load input subsystem.");
}
else
{
PXR_Plugin.System.UPxr_InitializeFocusCallback();
}
#if XR_HANDS
var handSubSystem = GetLoadedSubsystem<XRHandSubsystem>();
if (handSubSystem == null)
{
Debug.LogError("PXRLog Failed to load XRHandSubsystem.");
}
#endif
if (PXR_ProjectSetting.GetProjectConfig().spatialAnchor)
{
PXR_Plugin.MixedReality.UPxr_CreateSpatialAnchorSenseDataProvider();
}
if (PXR_ProjectSetting.GetProjectConfig().sceneCapture)
{
PXR_Plugin.MixedReality.UPxr_CreateSceneCaptureSenseDataProvider();
}
currentLoaderState = LoaderState.Initialized;
return displaySubsystem != null;
}
public override bool Start()
{
Debug.Log($"{TAG} Start() currentLoaderState={currentLoaderState}");
if (currentLoaderState == LoaderState.Started)
return true;
if (!validLoaderStartStates.Contains(currentLoaderState))
return false;
currentLoaderState = LoaderState.StartAttempted;
StartSubsystem<XRDisplaySubsystem>();
StartSubsystem<XRInputSubsystem>();
#if XR_HANDS
StartSubsystem<XRHandSubsystem>();
#endif
#if AR_FOUNDATION_5 || AR_FOUNDATION_6
if (PXR_ProjectSetting.GetProjectConfig().arFoundation)
{
StartSubsystem<XRCameraSubsystem>();
if (PXR_ProjectSetting.GetProjectConfig().bodyTracking)
{
StartSubsystem<XRHumanBodySubsystem>();
}
if (PXR_ProjectSetting.GetProjectConfig().faceTracking)
{
StartSubsystem<XRFaceSubsystem>();
}
}
if (PXR_ProjectSetting.GetProjectConfig().spatialAnchor)
{
StartSubsystem<XRAnchorSubsystem>();
}
#endif
if (!displaySubsystem?.running ?? false)
{
StartSubsystem<XRDisplaySubsystem>();
}
if (!inputSubsystem?.running ?? false)
{
StartSubsystem<XRInputSubsystem>();
}
currentLoaderState = LoaderState.Started;
return true;
}
public override bool Stop()
{
Debug.Log($"{TAG} Stop() currentLoaderState={currentLoaderState}");
if (currentLoaderState == LoaderState.Stopped)
return true;
if (!validLoaderStopStates.Contains(currentLoaderState))
return false;
currentLoaderState = LoaderState.StopAttempted;
var inputRunning = inputSubsystem?.running ?? false;
var displayRunning = displaySubsystem?.running ?? false;
if (inputRunning)
{
StopSubsystem<XRInputSubsystem>();
}
if (displayRunning)
{
StopSubsystem<XRDisplaySubsystem>();
}
#if XR_HANDS
StopSubsystem<XRHandSubsystem>();
#endif
#if AR_FOUNDATION_5 || AR_FOUNDATION_6
if (PXR_ProjectSetting.GetProjectConfig().arFoundation)
{
StopSubsystem<XRCameraSubsystem>();
if (PXR_ProjectSetting.GetProjectConfig().bodyTracking)
{
StopSubsystem<XRHumanBodySubsystem>();
}
if (PXR_ProjectSetting.GetProjectConfig().faceTracking)
{
StopSubsystem<XRFaceSubsystem>();
}
}
if (PXR_ProjectSetting.GetProjectConfig().spatialAnchor)
{
StopSubsystem<XRAnchorSubsystem>();
}
#endif
currentLoaderState = LoaderState.Stopped;
return true;
}
public override bool Deinitialize()
{
Debug.Log($"{TAG} Deinitialize() currentLoaderState={currentLoaderState}");
if (PXR_Plugin.System.IsOpenXRLoaderActive())
{
return false;
}
if (currentLoaderState == LoaderState.Uninitialized)
return true;
if (!validLoaderDeinitStates.Contains(currentLoaderState))
{
return false;
}
currentLoaderState = LoaderState.DeinitializeAttempted;
DestroySubsystem<XRDisplaySubsystem>();
DestroySubsystem<XRInputSubsystem>();
if (PXR_ProjectSetting.GetProjectConfig().spatialMesh)
{
if (meshSubsystem.running)
{
StopSubsystem<XRMeshSubsystem>();
}
PXR_Plugin.MixedReality.UPxr_DisposeMesh();
DestroySubsystem<XRMeshSubsystem>();
}
#if XR_HANDS
DestroySubsystem<XRHandSubsystem>();
#endif
#if AR_FOUNDATION_5 || AR_FOUNDATION_6
if (PXR_ProjectSetting.GetProjectConfig().arFoundation)
{
DestroySubsystem<XRCameraSubsystem>();
if (PXR_ProjectSetting.GetProjectConfig().bodyTracking)
{
DestroySubsystem<XRHumanBodySubsystem>();
}
if (PXR_ProjectSetting.GetProjectConfig().faceTracking)
{
DestroySubsystem<XRFaceSubsystem>();
}
}
#endif
PXR_Plugin.System.UPxr_DeinitializeFocusCallback();
if (PXR_ProjectSetting.GetProjectConfig().spatialAnchor)
{
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));
}
if (PXR_ProjectSetting.GetProjectConfig().sceneCapture)
{
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));
}
currentLoaderState = LoaderState.Uninitialized;
return true;
}
[MonoPInvokeCallback(typeof(ConvertRotationWith2VectorDelegate))]
static Quaternion ConvertRotationWith2Vector(Vector3 from, Vector3 to)
{
return Quaternion.FromToRotation(from, to);
}
[MonoPInvokeCallback(typeof(XrEventDataBufferCallBack))]
static void XrEventDataBufferFunction(ref XrEventDataBuffer eventDB)
{
int status, action;
PLog.d("PxrUnity",$"XrEventDataBufferFunction eventType={eventDB.type}",false);
switch (eventDB.type)
{
case XrStructureType.XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
int sessionstate = BitConverter.ToInt32(eventDB.data, 8);
Debug.Log($"XrEventDataBufferFunction sessionstate={sessionstate}");
if (PXR_Plugin.System.SessionStateChanged != null)
{
PXR_Plugin.System.SessionStateChanged((XrSessionState)sessionstate);
}
#if AR_FOUNDATION_5 || AR_FOUNDATION_6
PXR_SessionSubsystem.instance?.OnSessionStateChange((XrSessionState)sessionstate);
#endif
#if XR_COMPOSITION_LAYERS
OnSessionStateChanged((XrSessionState)sessionstate);
#endif
break;
case XrStructureType.XR_TYPE_EVENT_CONTROLLER_STATE_CHANGED_PICO:
XrDeviceEventType eventType = (XrDeviceEventType)eventDB.data[0];
status = eventDB.data[5];
action = eventDB.data[6];
PLog.i(TAG, $"Controller eventType={eventType}, status={status}, action={action}", false);
switch (eventType)
{
case XrDeviceEventType.XR_DEVICE_INPUTDEVICE_CHANGED:
if (PXR_Plugin.System.InputDeviceChanged != null)
{
PXR_Plugin.System.InputDeviceChanged(status);
}
break;
}
break;
case XrStructureType.XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB:
float drRate = BitConverter.ToSingle(eventDB.data, 4);
if (PXR_Plugin.System.DisplayRefreshRateChangedAction != null)
{
PXR_Plugin.System.DisplayRefreshRateChangedAction(drRate);
}
PLog.i(TAG, $"RefreshRateChanged value ={drRate}", false);
break;
case XrStructureType.XR_TYPE_EVENT_SEETHROUGH_STATE_CHANGED:
status = BitConverter.ToInt32(eventDB.data, 0);
PXR_Plugin.Boundary.seeThroughState = status;
if (PXR_Plugin.Boundary.SeethroughStateChangedAction != null)
{
PXR_Plugin.Boundary.SeethroughStateChangedAction(status);
}
PLog.i(TAG, $"SeethroughStateChanged status ={status}", false);
break;
case XrStructureType.XR_TYPE_EVENT_DATA_MRC_STATUS_CHANGED_PICO:
status = BitConverter.ToInt32(eventDB.data, 0);
PLog.i(TAG, $"XR_TYPE_EVENT_DATA_MRC_STATUS_CHANGED_PICO status ={status}", false);
PXR_Plugin.System.enableMRC = status == 1;
if (PXR_Plugin.System.MRCStateChangedAction != null)
{
PXR_Plugin.System.MRCStateChangedAction(status == 1);
}
break;
case XrStructureType.XR_TYPE_EVENT_LOG_LEVEL_CHANGE:
status = BitConverter.ToInt32(eventDB.data, 4);
PLog.logLevel = (PLog.LogLevel)status;
PLog.i(TAG, $"SDKLoglevelChanged logLevel ={status}", false);
break;
case XrStructureType.XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT:
bool isUserPresent = BitConverter.ToBoolean(eventDB.data, 8);
if (PXR_Plugin.System.UserPresenceChangedAction != null)
{
PXR_Plugin.System.UserPresenceChangedAction(isUserPresent);
}
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_ENVIRONMENT_BLEND_MODE_CHANGED_EXT:
if (PXR_Manager.VstDisplayStatusChanged != null)
{
int status_ = BitConverter.ToInt32(eventDB.data, 8);
PXR_Manager.VstDisplayStatusChanged(status_==1?PxrVstStatus.Disabled:PxrVstStatus.Enabled);
}
break;
case XrStructureType.XR_TYPE_EVENT_DATA_SENSE_DATA_PROVIDER_STATE_CHANGED:
case XrStructureType.XR_TYPE_EVENT_DATA_SENSE_DATA_UPDATED:
case XrStructureType.XR_TYPE_EVENT_DATA_AUTO_SCENE_CAPTURE_UPDATE_PICO:
{
PXR_Manager.Instance.PollEvent(eventDB);
break;
}
case XrStructureType.XR_TYPE_EVENT_DATA_REQUEST_MOTION_TRACKER_COMPLETE:
#if PICO_OPENXR_SDK
#else
if (PXR_MotionTracking.RequestMotionTrackerCompleteAction != null)
{
RequestMotionTrackerCompleteEventData requestMotionTrackerCompleteEventData = new RequestMotionTrackerCompleteEventData();
requestMotionTrackerCompleteEventData.trackerCount = BitConverter.ToUInt32(eventDB.data, 0);
requestMotionTrackerCompleteEventData.trackerIds = new long[requestMotionTrackerCompleteEventData.trackerCount];
for (int i = 0; i < requestMotionTrackerCompleteEventData.trackerCount; i++)
{
requestMotionTrackerCompleteEventData.trackerIds[i] = BitConverter.ToInt16(eventDB.data, 8+ 8 * i);
}
requestMotionTrackerCompleteEventData.result =
(PxrResult)BitConverter.ToInt32(eventDB.data, 4 + 8 * (int)requestMotionTrackerCompleteEventData.trackerCount);
PXR_MotionTracking.RequestMotionTrackerCompleteAction(requestMotionTrackerCompleteEventData);
}
#endif
break;
case XrStructureType.XR_TYPE_EVENT_DATA_MOTION_TRACKER_CONNECTION_STATE_CHANGED:
#if PICO_OPENXR_SDK
#else
if (PXR_MotionTracking.MotionTrackerConnectionAction != null)
{
Int64 trackerId = BitConverter.ToInt64(eventDB.data, 0);
int state = BitConverter.ToInt32(eventDB.data, 8);
PXR_MotionTracking.MotionTrackerConnectionAction(trackerId, state);
}
#endif
break;
case XrStructureType.XR_TYPE_EVENT_DATA_MOTION_TRACKER_POWER_KEY_EVENT:
#if PICO_OPENXR_SDK
#else
if (PXR_MotionTracking.MotionTrackerPowerKeyAction != null)
{
Int64 trackerId = BitConverter.ToInt64(eventDB.data, 0);
bool state = BitConverter.ToBoolean(eventDB.data, 8);
PXR_MotionTracking.MotionTrackerPowerKeyAction(trackerId, state);
}
#endif
break;
case XrStructureType.XR_TYPE_EVENT_DATA_EXPAND_DEVICE_CONNECTION_STATE_CHANGED:
#if PICO_OPENXR_SDK
#else
if (PXR_MotionTracking.ExpandDeviceConnectionAction != null)
{
UInt64 trackerId = BitConverter.ToUInt64(eventDB.data, 0);
int state = BitConverter.ToInt32(eventDB.data, 8);
PXR_MotionTracking.ExpandDeviceConnectionAction((long)trackerId, state);
}
#endif
break;
case XrStructureType.XR_TYPE_EVENT_DATA_EXPAND_DEVICE_BATTERY_STATE_CHANGED:
#if PICO_OPENXR_SDK
#else
if (PXR_MotionTracking.ExpandDeviceBatteryAction != null)
{
ExpandDeviceBatteryEventData expandDevice = new ExpandDeviceBatteryEventData();
expandDevice.deviceId = BitConverter.ToUInt64(eventDB.data, 0);
expandDevice.batteryLevel = BitConverter.ToSingle(eventDB.data, 8);
expandDevice.chargingState = (XrBatteryChargingState)BitConverter.ToInt32(eventDB.data, 12);
PXR_MotionTracking.ExpandDeviceBatteryAction(expandDevice);
}
#endif
break;
case XrStructureType.XR_TYPE_EVENT_DATA_EXPAND_DEVICE_CUSTOM_DATA_STATE_CHANGED:
#if PICO_OPENXR_SDK
#else
if (PXR_MotionTracking.ExtDevPassDataAction != null)
{
status = BitConverter.ToInt32(eventDB.data, 0);
PXR_MotionTracking.ExtDevPassDataAction(status);
}
#endif
break;
}
}
public PXR_Settings GetSettings()
{
PXR_Settings settings = null;
#if UNITY_EDITOR
UnityEditor.EditorBuildSettings.TryGetConfigObject<PXR_Settings>("Unity.XR.PXR.Settings", out settings);
#endif
#if UNITY_ANDROID && !UNITY_EDITOR
settings = PXR_Settings.settings;
#endif
return settings;
}
#if UNITY_EDITOR
public string GetPreInitLibraryName(BuildTarget buildTarget, BuildTargetGroup buildTargetGroup)
{
return "PxrPlatform";
}
#endif
#if UNITY_ANDROID && !UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
static void RuntimeLoadPicoPlugin()
{
string version = "UnityXR_" + PXR_Plugin.System.UPxr_GetSDKVersion() + "_" + Application.unityVersion;
PXR_Plugin.System.UPxr_SetConfigString( ConfigType.EngineVersion, version );
}
#endif
private static bool _isSessionActive = false;
public static void OnSessionStateChanged(XrSessionState state)
{
PLog.i(TAG, $"OnSessionStateChanged Session state changed to: {state}");
#if XR_COMPOSITION_LAYERS
if (state == XrSessionState.Focused && !_isSessionActive)
{
if (CompositionLayerManager.Instance != null)
{
PLog.i(TAG, $"OnSessionBegin OpenXRLayerProvider");
CompositionLayerManager.Instance.LayerProvider ??= new PXR_LayerProvider();
_isSessionActive = true;
}
}
else if (state == XrSessionState.Stopping && _isSessionActive)
{
if (CompositionLayerManager.Instance?.LayerProvider is PXR_LayerProvider)
{
PLog.i(TAG, $"OnSessionEnd OpenXRLayerProvider");
((PXR_LayerProvider)CompositionLayerManager.Instance.LayerProvider).Dispose();
CompositionLayerManager.Instance.LayerProvider = null;
_isSessionActive = false;
}
}
#endif
}
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,93 @@
#if PICO_OPENXR_SDK
using System.IO;
using Unity.XR.PXR;
using UnityEditor;
using UnityEngine;
namespace Unity.XR.OpenXR.Features.PICOSupport
{
[System.Serializable]
public class PXR_OpenXRProjectSetting: ScriptableObject
{
public bool useContentProtect;
public bool isEyeTracking;
public bool MRSafeguard;
public bool isHandTracking;
public bool isEyeTrackingCalibration;
public bool highFrequencyHand;
public SystemDisplayFrequency displayFrequency;
public SecureContentFlag contentProtectFlags ;
public bool foveationEnable;
public FoveationFeature.FoveatedRenderingMode foveatedRenderingMode;
public FoveationFeature.FoveatedRenderingLevel foveatedRenderingLevel;
public bool isSubsampledEnabled;
public HandTrackingSupport handTrackingSupportType;
[SerializeField, Tooltip("Set the system splash screen picture in PNG format.")]
public Texture2D systemSplashScreen;
private string splashPath = string.Empty;
public static PXR_OpenXRProjectSetting GetProjectConfig()
{
PXR_OpenXRProjectSetting projectConfig = Resources.Load<PXR_OpenXRProjectSetting>("PICOProjectSetting");
#if UNITY_EDITOR
if (projectConfig == null)
{
projectConfig = CreateInstance<PXR_OpenXRProjectSetting>();
projectConfig.useContentProtect = false;
projectConfig.contentProtectFlags = SecureContentFlag.SECURE_CONTENT_OFF;
projectConfig.isEyeTracking = false;
projectConfig.isEyeTrackingCalibration = false;
projectConfig.handTrackingSupportType = HandTrackingSupport.ControllersAndHands;
projectConfig.isHandTracking = false;
projectConfig.MRSafeguard = false;
projectConfig.highFrequencyHand = false;
projectConfig.displayFrequency = SystemDisplayFrequency.Default;
projectConfig.foveationEnable = false;
projectConfig.foveatedRenderingMode = FoveationFeature.FoveatedRenderingMode.FixedFoveatedRendering;
projectConfig.foveatedRenderingLevel = FoveationFeature.FoveatedRenderingLevel.Off;
projectConfig.isSubsampledEnabled = false;
string path = Application.dataPath + "/Resources";
if (!Directory.Exists(path))
{
UnityEditor.AssetDatabase.CreateFolder("Assets", "Resources");
UnityEditor.AssetDatabase.CreateAsset(projectConfig, "Assets/Resources/PICOProjectSetting.asset");
}
else
{
UnityEditor.AssetDatabase.CreateAsset(projectConfig, "Assets/Resources/PICOProjectSetting.asset");
}
}
#endif
return projectConfig;
}
#if UNITY_EDITOR
private void OnValidate()
{
if (systemSplashScreen != null)
{
splashPath = AssetDatabase.GetAssetPath(systemSplashScreen);
if (Path.GetExtension(splashPath).ToLower() != ".png")
{
systemSplashScreen = null;
Debug.LogError("Invalid file format of System Splash Screen, only PNG format is supported. The asset path: " + splashPath);
splashPath = string.Empty;
}
}
}
public string GetSystemSplashScreen(string path)
{
if (systemSplashScreen == null || splashPath == string.Empty)
{
return "0";
}
string targetPath = Path.Combine(path, "src/main/assets/pico_splash.png");
FileUtil.ReplaceFile(splashPath, targetPath);
return "1";
}
#endif
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3ea462bb563b4defae668dc5d8cb1144
timeCreated: 1738740935

View File

@@ -0,0 +1,530 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Rendering;
namespace Unity.XR.PXR
{
[Obsolete("PXR_OverlayManager is obsolete and will be removed in the next version. Please use PXR_CompositionLayerManager instead.", false)]
public class PXR_OverlayManager : MonoBehaviour
{
bool isURP = false;
private void OnEnable()
{
#if UNITY_6000_0_OR_NEWER
if (GraphicsSettings.currentRenderPipeline != null)
#else
if (GraphicsSettings.renderPipelineAsset != null)
#endif
{
#if UNITY_2023_3_OR_NEWER
RenderPipelineManager.beginContextRendering += BeginRendering;
#else
RenderPipelineManager.beginFrameRendering += BeginRendering;
#endif
isURP = true;
}
else
{
Camera.onPreRender += OnPreRenderCallBack;
isURP = false;
}
}
private void OnDisable()
{
#if UNITY_6000_0_OR_NEWER
if (GraphicsSettings.currentRenderPipeline != null)
#else
if (GraphicsSettings.renderPipelineAsset != null)
#endif
{
#if UNITY_2023_3_OR_NEWER
RenderPipelineManager.beginContextRendering -= BeginRendering;
#else
RenderPipelineManager.beginFrameRendering -= BeginRendering;
#endif
}
else
{
Camera.onPreRender -= OnPreRenderCallBack;
}
}
private void Start()
{
// external surface
if (PXR_OverLay.Instances.Count > 0)
{
foreach (var overlay in PXR_OverLay.Instances)
{
if (overlay.isExternalAndroidSurface)
{
overlay.CreateExternalSurface(overlay);
}
}
}
}
#if UNITY_2023_3_OR_NEWER
private void BeginRendering(ScriptableRenderContext arg1, List<Camera> arg2)
#else
private void BeginRendering(ScriptableRenderContext arg1, Camera[] arg2)
#endif
{
foreach (Camera cam in arg2)
{
if (cam != null && Camera.main == cam)
{
OnPreRenderCallBack(cam);
}
}
}
private void OnPreRenderCallBack(Camera cam)
{
// There is only one XR main camera in the scene.
if (null == Camera.main) return;
if (cam == null || cam != Camera.main || cam.stereoActiveEye == Camera.MonoOrStereoscopicEye.Right) return;
//CompositeLayers
int boundaryState = PXR_Plugin.Boundary.seeThroughState;
if (null == PXR_OverLay.Instances) return;
if (PXR_OverLay.Instances.Count > 0 && boundaryState != 2)
{
foreach (var overlay in PXR_OverLay.Instances)
{
if (!overlay.isActiveAndEnabled) continue;
if (null == overlay.layerTextures) continue;
if (overlay.isExternalAndroidSurface)
{
overlay.CreateExternalSurface(overlay);
continue;
}
if (!overlay.isClones && overlay.layerTextures[0] == null && overlay.layerTextures[1] == null && !overlay.isExternalAndroidSurface) continue;
if (overlay.overlayTransform != null && !overlay.overlayTransform.gameObject.activeSelf) continue;
overlay.CreateTexture();
}
}
Submitlayers();
}
void Submitlayers()
{
int boundaryState = PXR_Plugin.Boundary.seeThroughState;
if (null == PXR_OverLay.Instances) return;
if (PXR_OverLay.Instances.Count > 0 && boundaryState != 2)
{
PXR_OverLay.Instances.Sort();
foreach (var compositeLayer in PXR_OverLay.Instances)
{
if (null == compositeLayer) continue;
compositeLayer.UpdateCoords();
if (!compositeLayer.isActiveAndEnabled) continue;
if (null == compositeLayer.layerTextures) continue;
if (!compositeLayer.isClones && compositeLayer.layerTextures[0] == null && compositeLayer.layerTextures[1] == null && !compositeLayer.isExternalAndroidSurface) continue;
if (compositeLayer.overlayTransform != null && null == compositeLayer.overlayTransform.gameObject) continue;
if (compositeLayer.overlayTransform != null && !compositeLayer.overlayTransform.gameObject.activeSelf) continue;
Vector4 colorScale = compositeLayer.GetLayerColorScale();
Vector4 colorBias = compositeLayer.GetLayerColorOffset();
bool isHeadLocked = false;
if (compositeLayer.overlayTransform != null && compositeLayer.overlayTransform.parent == transform)
{
isHeadLocked = true;
}
if (!compositeLayer.isExternalAndroidSurface && !compositeLayer.CopyRT()) continue;
if (null == compositeLayer.cameraRotations || null == compositeLayer.modelScales || null == compositeLayer.modelTranslations) continue;
PxrLayerHeader2 header = new PxrLayerHeader2();
PxrPosef poseLeft = new PxrPosef();
PxrPosef poseRight = new PxrPosef();
header.layerId = compositeLayer.overlayIndex;
header.colorScaleX = colorScale.x;
header.colorScaleY = colorScale.y;
header.colorScaleZ = colorScale.z;
header.colorScaleW = colorScale.w;
header.colorBiasX = colorBias.x;
header.colorBiasY = colorBias.y;
header.colorBiasZ = colorBias.z;
header.colorBiasW = colorBias.w;
header.compositionDepth = compositeLayer.layerDepth;
header.headPose.orientation.x = compositeLayer.cameraRotations[0].x;
header.headPose.orientation.y = compositeLayer.cameraRotations[0].y;
header.headPose.orientation.z = -compositeLayer.cameraRotations[0].z;
header.headPose.orientation.w = -compositeLayer.cameraRotations[0].w;
header.headPose.position.x = (compositeLayer.cameraTranslations[0].x + compositeLayer.cameraTranslations[1].x) / 2;
header.headPose.position.y = (compositeLayer.cameraTranslations[0].y + compositeLayer.cameraTranslations[1].y) / 2;
header.headPose.position.z = -(compositeLayer.cameraTranslations[0].z + compositeLayer.cameraTranslations[1].z) / 2;
header.layerShape = (PXR_CompositionLayer.OverlayShape)compositeLayer.overlayShape;
header.useLayerBlend = (UInt32)(compositeLayer.useLayerBlend ? 1 : 0);
header.layerBlend.srcColor = compositeLayer.srcColor;
header.layerBlend.dstColor = compositeLayer.dstColor;
header.layerBlend.srcAlpha = compositeLayer.srcAlpha;
header.layerBlend.dstAlpha = compositeLayer.dstAlpha;
header.useImageRect = (UInt32)(compositeLayer.useImageRect ? 1 : 0);
header.imageRectLeft = compositeLayer.getPxrRectiLeft(true);
header.imageRectRight = compositeLayer.getPxrRectiLeft(false);
header.colorMatrix = compositeLayer.colorMatrix;
if (isHeadLocked)
{
poseLeft.orientation.x = compositeLayer.overlayTransform.localRotation.x;
poseLeft.orientation.y = compositeLayer.overlayTransform.localRotation.y;
poseLeft.orientation.z = -compositeLayer.overlayTransform.localRotation.z;
poseLeft.orientation.w = -compositeLayer.overlayTransform.localRotation.w;
poseLeft.position.x = compositeLayer.overlayTransform.localPosition.x;
poseLeft.position.y = compositeLayer.overlayTransform.localPosition.y;
poseLeft.position.z = -compositeLayer.overlayTransform.localPosition.z;
poseRight.orientation.x = compositeLayer.overlayTransform.localRotation.x;
poseRight.orientation.y = compositeLayer.overlayTransform.localRotation.y;
poseRight.orientation.z = -compositeLayer.overlayTransform.localRotation.z;
poseRight.orientation.w = -compositeLayer.overlayTransform.localRotation.w;
poseRight.position.x = compositeLayer.overlayTransform.localPosition.x;
poseRight.position.y = compositeLayer.overlayTransform.localPosition.y;
poseRight.position.z = -compositeLayer.overlayTransform.localPosition.z;
header.layerFlags = (UInt32)(
PxrLayerSubmitFlags.PxrLayerFlagLayerPoseNotInTrackingSpace |
PxrLayerSubmitFlags.PxrLayerFlagHeadLocked);
}
else
{
poseLeft.orientation.x = compositeLayer.modelRotations[0].x;
poseLeft.orientation.y = compositeLayer.modelRotations[0].y;
poseLeft.orientation.z = -compositeLayer.modelRotations[0].z;
poseLeft.orientation.w = -compositeLayer.modelRotations[0].w;
poseLeft.position.x = compositeLayer.modelTranslations[0].x;
poseLeft.position.y = compositeLayer.modelTranslations[0].y;
poseLeft.position.z = -compositeLayer.modelTranslations[0].z;
poseRight.orientation.x = compositeLayer.modelRotations[0].x;
poseRight.orientation.y = compositeLayer.modelRotations[0].y;
poseRight.orientation.z = -compositeLayer.modelRotations[0].z;
poseRight.orientation.w = -compositeLayer.modelRotations[0].w;
poseRight.position.x = compositeLayer.modelTranslations[0].x;
poseRight.position.y = compositeLayer.modelTranslations[0].y;
poseRight.position.z = -compositeLayer.modelTranslations[0].z;
header.layerFlags = (UInt32)(
PxrLayerSubmitFlags.PxrLayerFlagUseExternalHeadPose |
PxrLayerSubmitFlags.PxrLayerFlagLayerPoseNotInTrackingSpace);
}
header.layerFlags |= compositeLayer.getHDRFlags();
if (compositeLayer.isPremultipliedAlpha)
{
header.layerFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagPremultipliedAlpha;
}
if (!compositeLayer.enableSubmitLayer)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagFixLayer);
}
if (compositeLayer.superResolution)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableSuperResolution);
}
if (compositeLayer.normalSupersampling)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableNormalSupersampling);
}
if (compositeLayer.qualitySupersampling)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableQualitySupersampling);
}
if (compositeLayer.fixedFoveatedSupersampling)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableFixedFoveatedSupersampling);
}
if (compositeLayer.normalSharpening)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableNormalSharpening);
}
if (compositeLayer.qualitySharpening)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableQualitySharpening);
}
if (compositeLayer.fixedFoveatedSharpening)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableFixedFoveatedSharpening);
}
if (compositeLayer.selfAdaptiveSharpening)
{
header.layerFlags |= (UInt32)(PxrLayerSubmitFlags.PxrLayerFlagEnableSelfAdaptiveSharpening);
}
if (compositeLayer.overlayShape == PXR_OverLay.OverlayShape.Quad)
{
PxrLayerQuad2 layerSubmit2 = new PxrLayerQuad2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
layerSubmit2.sizeLeft.x = compositeLayer.modelScales[0].x;
layerSubmit2.sizeLeft.y = compositeLayer.modelScales[0].y;
layerSubmit2.sizeRight.x = compositeLayer.modelScales[0].x;
layerSubmit2.sizeRight.y = compositeLayer.modelScales[0].y;
if (compositeLayer.useImageRect)
{
Vector3 lPos = new Vector3();
Vector3 rPos = new Vector3();
Quaternion quaternion = new Quaternion(compositeLayer.modelRotations[0].x, compositeLayer.modelRotations[0].y, -compositeLayer.modelRotations[0].z, -compositeLayer.modelRotations[0].w);
lPos.x = compositeLayer.modelScales[0].x * (-0.5f + compositeLayer.dstRectLeft.x + 0.5f * Mathf.Min(compositeLayer.dstRectLeft.width, 1 - compositeLayer.dstRectLeft.x));
lPos.y = compositeLayer.modelScales[0].y * (-0.5f + compositeLayer.dstRectLeft.y + 0.5f * Mathf.Min(compositeLayer.dstRectLeft.height, 1 - compositeLayer.dstRectLeft.y));
lPos.z = 0;
lPos = quaternion * lPos;
layerSubmit2.poseLeft.position.x += lPos.x;
layerSubmit2.poseLeft.position.y += lPos.y;
layerSubmit2.poseLeft.position.z += lPos.z;
rPos.x = compositeLayer.modelScales[0].x * (-0.5f + compositeLayer.dstRectRight.x + 0.5f * Mathf.Min(compositeLayer.dstRectRight.width, 1 - compositeLayer.dstRectRight.x));
rPos.y = compositeLayer.modelScales[0].y * (-0.5f + compositeLayer.dstRectRight.y + 0.5f * Mathf.Min(compositeLayer.dstRectRight.height, 1 - compositeLayer.dstRectRight.y));
rPos.z = 0;
rPos = quaternion * rPos;
layerSubmit2.poseRight.position.x += rPos.x;
layerSubmit2.poseRight.position.y += rPos.y;
layerSubmit2.poseRight.position.z += rPos.z;
layerSubmit2.sizeLeft.x = compositeLayer.modelScales[0].x * Mathf.Min(compositeLayer.dstRectLeft.width, 1 - compositeLayer.dstRectLeft.x);
layerSubmit2.sizeLeft.y = compositeLayer.modelScales[0].y * Mathf.Min(compositeLayer.dstRectLeft.height, 1 - compositeLayer.dstRectLeft.y);
layerSubmit2.sizeRight.x = compositeLayer.modelScales[0].x * Mathf.Min(compositeLayer.dstRectRight.width, 1 - compositeLayer.dstRectRight.x);
layerSubmit2.sizeRight.y = compositeLayer.modelScales[0].y * Mathf.Min(compositeLayer.dstRectRight.height, 1 - compositeLayer.dstRectRight.y);
}
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerQuad2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_OverLay.OverlayShape.Cylinder)
{
PxrLayerCylinder2 layerSubmit2 = new PxrLayerCylinder2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
if (compositeLayer.modelScales[0].z != 0)
{
layerSubmit2.centralAngleLeft = compositeLayer.modelScales[0].x / compositeLayer.modelScales[0].z;
layerSubmit2.centralAngleRight = compositeLayer.modelScales[0].x / compositeLayer.modelScales[0].z;
}
else
{
Debug.LogError("PXRLog scale.z is 0");
}
layerSubmit2.heightLeft = compositeLayer.modelScales[0].y;
layerSubmit2.heightRight = compositeLayer.modelScales[0].y;
layerSubmit2.radiusLeft = compositeLayer.modelScales[0].z;
layerSubmit2.radiusRight = compositeLayer.modelScales[0].z;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerCylinder2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_OverLay.OverlayShape.Equirect)
{
PxrLayerEquirect2 layerSubmit2 = new PxrLayerEquirect2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
layerSubmit2.header.layerShape = (PXR_CompositionLayer.OverlayShape)PXR_OverLay.OverlayShape.Equirect;
layerSubmit2.radiusLeft = compositeLayer.radius;
layerSubmit2.radiusRight = compositeLayer.radius;
layerSubmit2.centralHorizontalAngleLeft = compositeLayer.dstRectLeft.width * 2 * Mathf.PI;
layerSubmit2.centralHorizontalAngleRight = compositeLayer.dstRectRight.width * 2 * Mathf.PI;
layerSubmit2.upperVerticalAngleLeft = (compositeLayer.dstRectLeft.height + compositeLayer.dstRectLeft.y - 0.5f) * Mathf.PI;
layerSubmit2.upperVerticalAngleRight = (compositeLayer.dstRectRight.height + compositeLayer.dstRectRight.y - 0.5f) * Mathf.PI;
layerSubmit2.lowerVerticalAngleLeft = (compositeLayer.dstRectLeft.y - 0.5f) * Mathf.PI;
layerSubmit2.lowerVerticalAngleRight = (compositeLayer.dstRectRight.y - 0.5f) * Mathf.PI;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerEquirect2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_OverLay.OverlayShape.Cubemap)
{
PxrLayerCube2 layerSubmit2 = new PxrLayerCube2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerCube2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_OverLay.OverlayShape.Eac)
{
PxrLayerEac2 layerSubmit2 = new PxrLayerEac2();
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
layerSubmit2.offsetPosLeft.x = compositeLayer.offsetPosLeft.x;
layerSubmit2.offsetPosLeft.y = compositeLayer.offsetPosLeft.y;
layerSubmit2.offsetPosLeft.z = compositeLayer.offsetPosLeft.z;
layerSubmit2.offsetPosRight.x = compositeLayer.offsetPosRight.x;
layerSubmit2.offsetPosRight.y = compositeLayer.offsetPosRight.y;
layerSubmit2.offsetPosRight.z = compositeLayer.offsetPosRight.z;
layerSubmit2.offsetRotLeft.x = compositeLayer.offsetRotLeft.x;
layerSubmit2.offsetRotLeft.y = compositeLayer.offsetRotLeft.y;
layerSubmit2.offsetRotLeft.z = compositeLayer.offsetRotLeft.z;
layerSubmit2.offsetRotLeft.w = compositeLayer.offsetRotLeft.w;
layerSubmit2.offsetRotRight.x = compositeLayer.offsetRotRight.x;
layerSubmit2.offsetRotRight.y = compositeLayer.offsetRotRight.y;
layerSubmit2.offsetRotRight.z = compositeLayer.offsetRotRight.z;
layerSubmit2.offsetRotRight.w = compositeLayer.offsetRotRight.w;
layerSubmit2.degreeType = (uint)compositeLayer.eacModelType;
layerSubmit2.overlapFactor = compositeLayer.overlapFactor;
layerSubmit2.timestamp = compositeLayer.timestamp;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerEac2ByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_OverLay.OverlayShape.Fisheye)
{
PxrLayerFisheye layerSubmit = new PxrLayerFisheye();
layerSubmit.header = header;
layerSubmit.poseLeft = poseLeft;
layerSubmit.poseRight = poseRight;
layerSubmit.header.layerShape = (PXR_CompositionLayer.OverlayShape)PXR_OverLay.OverlayShape.Fisheye;
layerSubmit.radiusLeft = compositeLayer.radius;
layerSubmit.radiusRight = compositeLayer.radius;
layerSubmit.scaleXLeft = 1 / compositeLayer.dstRectLeft.width;
layerSubmit.scaleXRight = 1 / compositeLayer.dstRectRight.width;
layerSubmit.scaleYLeft = 1 / compositeLayer.dstRectLeft.height;
layerSubmit.scaleYRight = 1 / compositeLayer.dstRectRight.height;
layerSubmit.biasXLeft = -compositeLayer.dstRectLeft.x / compositeLayer.dstRectLeft.width;
layerSubmit.biasXRight = -compositeLayer.dstRectRight.x / compositeLayer.dstRectRight.width;
layerSubmit.biasYLeft = 1 + (compositeLayer.dstRectLeft.y - 1) / compositeLayer.dstRectLeft.height;
layerSubmit.biasYRight = 1 + (compositeLayer.dstRectRight.y - 1) / compositeLayer.dstRectRight.height;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit));
Marshal.StructureToPtr(layerSubmit, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerFisheyeByRender(compositeLayer.layerSubmitPtr);
}
else if (compositeLayer.overlayShape == PXR_OverLay.OverlayShape.BlurredQuad)
{
PxrLayerQuad2 layerSubmit2 = new PxrLayerQuad2();
if (PXR_OverLay.BlurredQuadMode.SmallWindow == compositeLayer.blurredQuadMode)
{
header.layerFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagBlurredQuadModeSmallWindow;
}
else if (PXR_OverLay.BlurredQuadMode.Immersion == compositeLayer.blurredQuadMode)
{
header.layerFlags |= (UInt32)PxrLayerSubmitFlags.PxrLayerFlagBlurredQuadModeImmersion;
}
layerSubmit2.header = header;
layerSubmit2.poseLeft = poseLeft;
layerSubmit2.poseRight = poseRight;
layerSubmit2.sizeLeft.x = compositeLayer.modelScales[0].x;
layerSubmit2.sizeLeft.y = compositeLayer.modelScales[0].y;
layerSubmit2.sizeRight.x = compositeLayer.modelScales[0].x;
layerSubmit2.sizeRight.y = compositeLayer.modelScales[0].y;
if (compositeLayer.useImageRect)
{
Vector3 lPos = new Vector3();
Vector3 rPos = new Vector3();
Quaternion quaternion = new Quaternion(compositeLayer.modelRotations[0].x, compositeLayer.modelRotations[0].y, -compositeLayer.modelRotations[0].z, -compositeLayer.modelRotations[0].w);
lPos.x = compositeLayer.modelScales[0].x * (-0.5f + compositeLayer.dstRectLeft.x + 0.5f * Mathf.Min(compositeLayer.dstRectLeft.width, 1 - compositeLayer.dstRectLeft.x));
lPos.y = compositeLayer.modelScales[0].y * (-0.5f + compositeLayer.dstRectLeft.y + 0.5f * Mathf.Min(compositeLayer.dstRectLeft.height, 1 - compositeLayer.dstRectLeft.y));
lPos.z = 0;
lPos = quaternion * lPos;
layerSubmit2.poseLeft.position.x += lPos.x;
layerSubmit2.poseLeft.position.y += lPos.y;
layerSubmit2.poseLeft.position.z += lPos.z;
rPos.x = compositeLayer.modelScales[0].x * (-0.5f + compositeLayer.dstRectRight.x + 0.5f * Mathf.Min(compositeLayer.dstRectRight.width, 1 - compositeLayer.dstRectRight.x));
rPos.y = compositeLayer.modelScales[0].y * (-0.5f + compositeLayer.dstRectRight.y + 0.5f * Mathf.Min(compositeLayer.dstRectRight.height, 1 - compositeLayer.dstRectRight.y));
rPos.z = 0;
rPos = quaternion * rPos;
layerSubmit2.poseRight.position.x += rPos.x;
layerSubmit2.poseRight.position.y += rPos.y;
layerSubmit2.poseRight.position.z += rPos.z;
layerSubmit2.sizeLeft.x = compositeLayer.modelScales[0].x * Mathf.Min(compositeLayer.dstRectLeft.width, 1 - compositeLayer.dstRectLeft.x);
layerSubmit2.sizeLeft.y = compositeLayer.modelScales[0].y * Mathf.Min(compositeLayer.dstRectLeft.height, 1 - compositeLayer.dstRectLeft.y);
layerSubmit2.sizeRight.x = compositeLayer.modelScales[0].x * Mathf.Min(compositeLayer.dstRectRight.width, 1 - compositeLayer.dstRectRight.x);
layerSubmit2.sizeRight.y = compositeLayer.modelScales[0].y * Mathf.Min(compositeLayer.dstRectRight.height, 1 - compositeLayer.dstRectRight.y);
}
layerSubmit2.blurredQuadScale = compositeLayer.blurredQuadScale;
layerSubmit2.blurredQuadShift = compositeLayer.blurredQuadShift;
layerSubmit2.blurredQuadFOV = compositeLayer.blurredQuadFOV;
layerSubmit2.blurredQuadIPD = compositeLayer.blurredQuadIPD;
if (compositeLayer.layerSubmitPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(compositeLayer.layerSubmitPtr);
compositeLayer.layerSubmitPtr = IntPtr.Zero;
}
compositeLayer.layerSubmitPtr = Marshal.AllocHGlobal(Marshal.SizeOf(layerSubmit2));
Marshal.StructureToPtr(layerSubmit2, compositeLayer.layerSubmitPtr, false);
PXR_Plugin.Render.UPxr_SubmitLayerQuad2ByRender(compositeLayer.layerSubmitPtr);
}
}
}
}
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: e46169b3ebf1d5e45aa4a01a9ac54017
timeCreated: 1590461192
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,139 @@
/*******************************************************************************
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
NOTICEAll information contained herein is, and remains the property of
PICO Technology Co., Ltd. The intellectual and technical concepts
contained herein are proprietary to PICO Technology Co., Ltd. and may be
covered by patents, patents in process, and are protected by trade secret or
copyright law. Dissemination of this information or reproduction of this
material is strictly forbidden unless prior written permission is obtained from
PICO Technology Co., Ltd.
*******************************************************************************/
using System.IO;
using UnityEditor;
using UnityEngine;
namespace Unity.XR.PXR
{
[System.Serializable]
public class PXR_ProjectSetting : ScriptableObject
{
public bool useContentProtect;
public bool handTracking;
public bool adaptiveHand;
public bool highFrequencyHand;
public bool openMRC;
public bool faceTracking;
public bool lipsyncTracking;
public bool eyeTracking;
public bool eyetrackingCalibration;
public bool enableETFR;
public FoveationLevel foveationLevel;
public bool latelatching;
public bool latelatchingDebug;
public bool enableSubsampled;
public bool bodyTracking;
public bool adaptiveResolution;
public bool stageMode;
public bool videoSeeThrough;
public bool spatialAnchor;
public bool sceneCapture;
public bool sharedAnchor;
public bool spatialMesh;
public bool secureMR;
public PxrMeshLod meshLod;
public bool superResolution;
public bool normalSharpening;
public bool qualitySharpening;
public bool fixedFoveatedSharpening;
public bool selfAdaptiveSharpening;
public HandTrackingSupport handTrackingSupportType;
#region Project Validation
public bool arFoundation;
public bool mrSafeguard;
public bool enableRecommendMSAA;
public bool recommendSubsamping;
public bool recommendMSAA;
public bool validationFFREnabled;
public bool validationETFREnabled;
#endregion
#region portal
public bool portalInited;
public bool isDataCollectionDisabled;
public int portalFirstSelected;
#endregion
public static PXR_ProjectSetting GetProjectConfig()
{
PXR_ProjectSetting projectConfig = Resources.Load<PXR_ProjectSetting>("PXR_ProjectSetting");
#if UNITY_EDITOR
if (projectConfig == null)
{
projectConfig = CreateInstance<PXR_ProjectSetting>();
projectConfig.useContentProtect = false;
projectConfig.handTracking = false;
projectConfig.handTrackingSupportType = HandTrackingSupport.ControllersAndHands;
projectConfig.adaptiveHand = false;
projectConfig.highFrequencyHand = false;
projectConfig.openMRC = true;
projectConfig.faceTracking = false;
projectConfig.lipsyncTracking = false;
projectConfig.eyeTracking = false;
projectConfig.eyetrackingCalibration = false;
projectConfig.enableETFR = false;
projectConfig.latelatching = false;
projectConfig.latelatchingDebug = false;
projectConfig.enableSubsampled = false;
projectConfig.bodyTracking = false;
projectConfig.adaptiveResolution = false;
projectConfig.stageMode = false;
projectConfig.videoSeeThrough = false;
projectConfig.spatialAnchor = false;
projectConfig.sceneCapture = false;
projectConfig.sharedAnchor = false;
projectConfig.spatialMesh = false;
projectConfig.superResolution = false;
projectConfig.normalSharpening = false;
projectConfig.qualitySharpening = false;
projectConfig.fixedFoveatedSharpening = false;
projectConfig.selfAdaptiveSharpening = false;
projectConfig.arFoundation = false;
projectConfig.mrSafeguard = false;
projectConfig.enableRecommendMSAA = false;
projectConfig.recommendSubsamping = false;
projectConfig.recommendMSAA = false;
projectConfig.foveationLevel = FoveationLevel.None;
projectConfig.validationFFREnabled = false;
projectConfig.validationETFREnabled = false;
projectConfig.portalInited = false;
projectConfig.isDataCollectionDisabled = false;
projectConfig.portalFirstSelected = 0;
projectConfig.meshLod = PxrMeshLod.Low;
projectConfig.secureMR = false;
string path = Application.dataPath + "/Resources";
if (!Directory.Exists(path))
{
UnityEditor.AssetDatabase.CreateFolder("Assets", "Resources");
UnityEditor.AssetDatabase.CreateAsset(projectConfig, "Assets/Resources/PXR_ProjectSetting.asset");
}
else
{
UnityEditor.AssetDatabase.CreateAsset(projectConfig, "Assets/Resources/PXR_ProjectSetting.asset");
}
}
#endif
return projectConfig;
}
#if UNITY_EDITOR
public static void SaveAssets()
{
EditorUtility.SetDirty(GetProjectConfig());
UnityEditor.AssetDatabase.SaveAssets();
}
#endif
}
}

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