Init
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1f88856b31e5b048b260670c0dd2ab2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 687edb8814fe64d438f49fadb4fe7849
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 3
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
Android:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
Editor:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6948a18f1c6415b42a41bb1ffd98095c
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 3
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
Android:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
Editor:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50f8077c12618da40a431db72f014562
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,105 @@
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.XR.Interaction.Toolkit;
|
||||
|
||||
public class PXRSample_SpatialAnchor : MonoBehaviour
|
||||
{
|
||||
[HideInInspector]
|
||||
public ulong anchorHandle;
|
||||
[SerializeField]
|
||||
private Text anchorID;
|
||||
[SerializeField]
|
||||
private GameObject savedIcon;
|
||||
[SerializeField]
|
||||
private GameObject uiCanvas;
|
||||
|
||||
[SerializeField] private Button btnPersist;
|
||||
[SerializeField] private Button btnDestroyAnchor;
|
||||
[SerializeField] private Button btnDeleteAnchor;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
//uiCanvas.SetActive(false);
|
||||
uiCanvas.SetActive(true);
|
||||
uiCanvas.GetComponent<Canvas>().worldCamera = Camera.main;
|
||||
|
||||
btnPersist.onClick.AddListener(OnBtnPressedPersist);
|
||||
btnDestroyAnchor.onClick.AddListener(OnBtnPressedDestroy);
|
||||
btnDeleteAnchor.onClick.AddListener(OnBtnPressedUnPersist);
|
||||
}
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
}
|
||||
|
||||
protected void OnDisable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (uiCanvas.activeSelf)
|
||||
{
|
||||
uiCanvas.transform.LookAt(new Vector3(uiCanvas.transform.position.x * 2 - Camera.main.transform.position.x, uiCanvas.transform.position.y * 2 - Camera.main.transform.position.y, uiCanvas.transform.position.z * 2 - Camera.main.transform.position.z), Vector3.up);
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
var result = PXR_MixedReality.LocateAnchor(anchorHandle, out var position, out var rotation);
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
transform.position = position;
|
||||
transform.rotation = rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
PXRSample_SpatialAnchorManager.Instance.SetLogInfo("LocateSpatialAnchor:" + result.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnBtnPressedPersist()
|
||||
{
|
||||
var result = await PXR_MixedReality.PersistSpatialAnchorAsync(anchorHandle);
|
||||
PXRSample_SpatialAnchorManager.Instance.SetLogInfo("PersistSpatialAnchorAsync:" + result.ToString());
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
ShowSaveIcon();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBtnPressedDestroy()
|
||||
{
|
||||
PXRSample_SpatialAnchorManager.Instance.DestroySpatialAnchor(anchorHandle);
|
||||
}
|
||||
|
||||
private async void OnBtnPressedUnPersist()
|
||||
{
|
||||
var result = await PXR_MixedReality.UnPersistSpatialAnchorAsync(anchorHandle);
|
||||
PXRSample_SpatialAnchorManager.Instance.SetLogInfo("UnPersistSpatialAnchorAsync:" + result.ToString());
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
OnBtnPressedDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAnchorHandle(ulong handle)
|
||||
{
|
||||
anchorHandle = handle;
|
||||
anchorID.text = "ID: " + anchorHandle;
|
||||
}
|
||||
|
||||
public void ShowSaveIcon()
|
||||
{
|
||||
savedIcon.SetActive(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da98fba3f19feaf4c8a0e0bdd00191b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,198 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.XR;
|
||||
|
||||
public class PXRSample_SpatialAnchorManager : MonoBehaviour
|
||||
{
|
||||
private static PXRSample_SpatialAnchorManager instance = null;
|
||||
public static PXRSample_SpatialAnchorManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = FindObjectOfType<PXRSample_SpatialAnchorManager>();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject anchorPrefab;
|
||||
private bool isCreateAnchorMode = false;
|
||||
public Dictionary<ulong, PXRSample_SpatialAnchor> anchorList = new Dictionary<ulong, PXRSample_SpatialAnchor>();
|
||||
public Dictionary<ulong, ulong> persistTaskList = new Dictionary<ulong, ulong>();
|
||||
public Dictionary<ulong, ulong> unPersistTaskList = new Dictionary<ulong, ulong>();
|
||||
private InputDevice rightController;
|
||||
public GameObject anchorPreview;
|
||||
[SerializeField] private GameObject menuPanel;
|
||||
[SerializeField] private Button btnCreateAnchor;
|
||||
[SerializeField] private Button btnLoadAnchors;
|
||||
|
||||
|
||||
private bool btnAClick = false;
|
||||
private bool aLock = false;
|
||||
private bool btnAState = false;
|
||||
private bool gripButton = false;
|
||||
|
||||
|
||||
public Text tipsText;
|
||||
private int maxLogCount = 5;
|
||||
private Queue<string> logQueue = new Queue<string>();
|
||||
void Start()
|
||||
{
|
||||
PXR_Manager.EnableVideoSeeThrough = true;
|
||||
|
||||
StartSpatialAnchorProvider();
|
||||
|
||||
btnCreateAnchor.onClick.AddListener(OnBtnPressedCreateAnchor);
|
||||
btnLoadAnchors.onClick.AddListener(OnBtnPressedLoadAllAnchors);
|
||||
|
||||
btnCreateAnchor.gameObject.SetActive(true);
|
||||
btnLoadAnchors.gameObject.SetActive(true);
|
||||
|
||||
rightController = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
|
||||
}
|
||||
|
||||
private async void StartSpatialAnchorProvider()
|
||||
{
|
||||
var result = await PXR_MixedReality.StartSenseDataProvider(PxrSenseDataProviderType.SpatialAnchor);
|
||||
SetLogInfo("StartSenseDataProvider:" + result);
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
PXR_Manager.SpatialAnchorDataUpdated += SpatialAnchorDataUpdated;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
PXR_Manager.SpatialAnchorDataUpdated -= SpatialAnchorDataUpdated;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
ProcessKeyEvent();
|
||||
|
||||
menuPanel.SetActive(gripButton);
|
||||
|
||||
if (isCreateAnchorMode && btnAClick)
|
||||
{
|
||||
CreateSpatialAnchor(anchorPreview.transform);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessKeyEvent()
|
||||
{
|
||||
rightController.TryGetFeatureValue(CommonUsages.primaryButton, out btnAState);
|
||||
if (btnAState && !aLock)
|
||||
{
|
||||
btnAClick = true;
|
||||
aLock = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
btnAClick = false;
|
||||
}
|
||||
if (!btnAState)
|
||||
{
|
||||
btnAClick = false;
|
||||
aLock = false;
|
||||
}
|
||||
|
||||
InputDevices.GetDeviceAtXRNode(XRNode.LeftHand).TryGetFeatureValue(CommonUsages.gripButton, out gripButton);
|
||||
}
|
||||
|
||||
private void SpatialAnchorDataUpdated()
|
||||
{
|
||||
SetLogInfo("SpatialAnchorDataUpdated:");
|
||||
OnBtnPressedLoadAllAnchors();
|
||||
}
|
||||
|
||||
private void OnBtnPressedCreateAnchor()
|
||||
{
|
||||
isCreateAnchorMode = !isCreateAnchorMode;
|
||||
if (isCreateAnchorMode)
|
||||
{
|
||||
btnCreateAnchor.transform.Find("Text").GetComponent<Text>().text = "CancelCreate";
|
||||
anchorPreview.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
btnCreateAnchor.transform.Find("Text").GetComponent<Text>().text = "CreateAnchor";
|
||||
anchorPreview.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnBtnPressedLoadAllAnchors()
|
||||
{
|
||||
var result = await PXR_MixedReality.QuerySpatialAnchorAsync();
|
||||
SetLogInfo("LoadSpatialAnchorAsync:" + result.result.ToString());
|
||||
if (result.result == PxrResult.SUCCESS)
|
||||
{
|
||||
foreach (var key in result.anchorHandleList)
|
||||
{
|
||||
if (!anchorList.ContainsKey(key))
|
||||
{
|
||||
GameObject anchorObject = Instantiate(anchorPrefab);
|
||||
PXRSample_SpatialAnchor anchor = anchorObject.GetComponent<PXRSample_SpatialAnchor>();
|
||||
anchor.SetAnchorHandle(key);
|
||||
|
||||
PXR_MixedReality.LocateAnchor(key, out var position, out var orientation);
|
||||
anchor.transform.position = position;
|
||||
anchor.transform.rotation = orientation;
|
||||
anchorList.Add(key, anchor);
|
||||
anchorList[key].ShowSaveIcon();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void CreateSpatialAnchor(Transform transform)
|
||||
{
|
||||
var result = await PXR_MixedReality.CreateSpatialAnchorAsync(transform.position, transform.rotation);
|
||||
SetLogInfo("CreateSpatialAnchorAsync:" + result.ToString());
|
||||
if (result.result == PxrResult.SUCCESS)
|
||||
{
|
||||
GameObject anchorObject = Instantiate(anchorPrefab);
|
||||
PXRSample_SpatialAnchor anchor = anchorObject.GetComponent<PXRSample_SpatialAnchor>();
|
||||
if (anchor == null)
|
||||
{
|
||||
anchor = anchorObject.AddComponent<PXRSample_SpatialAnchor>();
|
||||
}
|
||||
anchor.SetAnchorHandle(result.anchorHandle);
|
||||
|
||||
anchorList.Add(result.anchorHandle, anchor);
|
||||
|
||||
var result1 = PXR_MixedReality.GetAnchorUuid(result.anchorHandle, out var uuid);
|
||||
SetLogInfo("GetUuid:" + result1.ToString() + " " + (result.uuid.Equals(uuid)) + "Uuid:" + uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public void DestroySpatialAnchor(ulong anchorHandle)
|
||||
{
|
||||
var result = PXR_MixedReality.DestroyAnchor(anchorHandle);
|
||||
SetLogInfo("DestroySpatialAnchor:" + result.ToString());
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
if (anchorList.ContainsKey(anchorHandle))
|
||||
{
|
||||
Destroy(anchorList[anchorHandle].gameObject);
|
||||
anchorList.Remove(anchorHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLogInfo(string log)
|
||||
{
|
||||
if (logQueue.Count >= maxLogCount)
|
||||
{
|
||||
logQueue.Dequeue();
|
||||
}
|
||||
logQueue.Enqueue(log);
|
||||
|
||||
tipsText.text = string.Join("\n", logQueue.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fed85861409e824a953639daefaacd6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,185 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine.UI;
|
||||
using System;
|
||||
#if PICO_OPENXR_SDK
|
||||
using Unity.XR.OpenXR.Features.PICOSupport;
|
||||
#endif
|
||||
|
||||
public class PXR_BodyTrackingBlock : MonoBehaviour
|
||||
{
|
||||
public Transform skeletonJoints;
|
||||
public bool showCube = true;
|
||||
public float zDistance = 0;
|
||||
|
||||
private bool supportedBT = false;
|
||||
private bool updateBT = true;
|
||||
|
||||
private BodyTrackingGetDataInfo bdi = new BodyTrackingGetDataInfo();
|
||||
private BodyTrackingData bd = new BodyTrackingData();
|
||||
private Transform[] boneMapping = new Transform[(int)BodyTrackerRole.ROLE_NUM];
|
||||
BodyTrackingStatus bs = new BodyTrackingStatus();
|
||||
|
||||
bool istracking = false;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
skeletonJoints.transform.localPosition += new Vector3(0, 0, zDistance);
|
||||
InitializeSkeletonJoints();
|
||||
StartBodyTracking();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
// Update bodytracking pose.
|
||||
if (updateBT)
|
||||
{
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
BodyTrackingFeature.GetBodyTrackingState(ref istracking, ref bs);
|
||||
#else
|
||||
PXR_MotionTracking.GetBodyTrackingState(ref istracking, ref bs);
|
||||
#endif
|
||||
// If not calibrated, invoked system motion tracker app for calibration.
|
||||
if (bs.stateCode != BodyTrackingStatusCode.BT_VALID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Get the position and orientation data of each body node.
|
||||
int ret = -1;
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
ret = BodyTrackingFeature.GetBodyTrackingData(ref bdi, ref bd);
|
||||
#else
|
||||
ret = PXR_MotionTracking.GetBodyTrackingData(ref bdi, ref bd);
|
||||
#endif
|
||||
|
||||
// if the return is successful
|
||||
if (ret == 0)
|
||||
{
|
||||
for (int i = 0; i < (int)BodyTrackerRole.ROLE_NUM; i++)
|
||||
{
|
||||
var bone = boneMapping[i];
|
||||
if (bone != null)
|
||||
{
|
||||
bone.transform.localPosition = new Vector3((float)bd.roleDatas[i].localPose.PosX, (float)bd.roleDatas[i].localPose.PosY,
|
||||
(float)bd.roleDatas[i].localPose.PosZ);
|
||||
bone.transform.localRotation = new Quaternion((float)bd.roleDatas[i].localPose.RotQx, (float)bd.roleDatas[i].localPose.RotQy,
|
||||
(float)bd.roleDatas[i].localPose.RotQz, (float)bd.roleDatas[i].localPose.RotQw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public void StartBodyTracking()
|
||||
{
|
||||
// Query whether the current device supports human body tracking.
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
supportedBT = BodyTrackingFeature.IsBodyTrackingSupported();
|
||||
#else
|
||||
PXR_MotionTracking.GetBodyTrackingSupported(ref supportedBT);
|
||||
#endif
|
||||
|
||||
if (!supportedBT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BodyTrackingBoneLength bones = new BodyTrackingBoneLength();
|
||||
|
||||
// Start BodyTracking
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
BodyTrackingFeature.StartBodyTracking(BodyJointSet.BODY_JOINT_SET_BODY_FULL_START, bones);
|
||||
BodyTrackingFeature.GetBodyTrackingState(ref istracking, ref bs);
|
||||
#else
|
||||
PXR_MotionTracking.StartBodyTracking(BodyJointSet.BODY_JOINT_SET_BODY_FULL_START, bones);
|
||||
PXR_MotionTracking.GetBodyTrackingState(ref istracking, ref bs);
|
||||
#endif
|
||||
|
||||
|
||||
// If not calibrated, invoked system motion tracker app for calibration.
|
||||
if (bs.stateCode != BodyTrackingStatusCode.BT_VALID)
|
||||
{
|
||||
if (bs.message == BodyTrackingMessage.BT_MESSAGE_TRACKER_NOT_CALIBRATED || bs.message == BodyTrackingMessage.BT_MESSAGE_UNKNOWN)
|
||||
{
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
BodyTrackingFeature.StartMotionTrackerCalibApp();
|
||||
#else
|
||||
PXR_MotionTracking.StartMotionTrackerCalibApp();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
skeletonJoints.gameObject.SetActive(true);
|
||||
updateBT = true;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
int ret = BodyTrackingFeature.StopBodyTracking();
|
||||
#else
|
||||
int ret = PXR_MotionTracking.StopBodyTracking();
|
||||
#endif
|
||||
updateBT = false;
|
||||
}
|
||||
|
||||
public void InitializeSkeletonJoints()
|
||||
{
|
||||
Queue<Transform> nodes = new Queue<Transform>();
|
||||
nodes.Enqueue(skeletonJoints);
|
||||
while (nodes.Count > 0)
|
||||
{
|
||||
Transform next = nodes.Dequeue();
|
||||
for (int i = 0; i < next.childCount; ++i)
|
||||
{
|
||||
nodes.Enqueue(next.GetChild(i));
|
||||
}
|
||||
|
||||
ProcessJoint(next);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessJoint(Transform joint)
|
||||
{
|
||||
int index = GetJointIndex(joint.name);
|
||||
if (index >= 0 && index < (int)BodyTrackerRole.ROLE_NUM)
|
||||
{
|
||||
boneMapping[index] = joint;
|
||||
Transform cubeT = joint.Find("Cube");
|
||||
if (cubeT)
|
||||
{
|
||||
cubeT.gameObject.SetActive(showCube);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"{joint.name} was not found.");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the integer value corresponding to the JointIndices enum value
|
||||
// passed in as a string.
|
||||
int GetJointIndex(string jointName)
|
||||
{
|
||||
BodyTrackerRole val;
|
||||
if (Enum.TryParse(jointName, out val))
|
||||
{
|
||||
return (int)val;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 097fbbaba53a01d42936fa80fff2d8ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,257 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine.UI;
|
||||
using System;
|
||||
using static UnityEngine.UI.Dropdown;
|
||||
#if PICO_OPENXR_SDK
|
||||
using Unity.XR.OpenXR.Features.PICOSupport;
|
||||
#endif
|
||||
public class PXR_BodyTrackingDebugBlock : MonoBehaviour
|
||||
{
|
||||
public Transform skeletonJoints;
|
||||
public bool showCube = true;
|
||||
public float zDistance = 0;
|
||||
|
||||
public Dropdown dropdown;
|
||||
public Text changeJointTittle;
|
||||
|
||||
|
||||
private bool supportedBT = false;
|
||||
private bool updateBT = true;
|
||||
private Transform changeJointT;
|
||||
|
||||
private BodyTrackingGetDataInfo bdi = new BodyTrackingGetDataInfo();
|
||||
private BodyTrackingData bd = new BodyTrackingData();
|
||||
private Transform[] boneMapping = new Transform[(int)BodyTrackerRole.ROLE_NUM];
|
||||
private Transform[] targetMapping = new Transform[(int)BodyTrackerRole.ROLE_NUM];
|
||||
BodyTrackingStatus bs = new BodyTrackingStatus();
|
||||
bool istracking = false;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
dropdown.ClearOptions();
|
||||
skeletonJoints.transform.localPosition += new Vector3(0, 0, zDistance);
|
||||
InitializeSkeletonJoints();
|
||||
StartBodyTracking();
|
||||
dropdown.RefreshShownValue();
|
||||
dropdown.onValueChanged.AddListener(delegate
|
||||
{
|
||||
DropdownValueChanged(dropdown);
|
||||
});
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
#if UNITY_ANDROID
|
||||
// Update bodytracking pose.
|
||||
if (updateBT)
|
||||
{
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
BodyTrackingFeature.GetBodyTrackingState(ref istracking, ref bs);
|
||||
#else
|
||||
PXR_MotionTracking.GetBodyTrackingState(ref istracking, ref bs);
|
||||
#endif
|
||||
// If not calibrated, invoked system motion tracker app for calibration.
|
||||
if (bs.stateCode!=BodyTrackingStatusCode.BT_VALID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Get the position and orientation data of each body node.
|
||||
int ret = -1;
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
ret = BodyTrackingFeature.GetBodyTrackingData(ref bdi, ref bd);
|
||||
#else
|
||||
ret = PXR_MotionTracking.GetBodyTrackingData(ref bdi, ref bd);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// if the return is successful
|
||||
if (ret == 0)
|
||||
{
|
||||
for (int i = 0; i < (int)BodyTrackerRole.ROLE_NUM; i++)
|
||||
{
|
||||
var bone = boneMapping[i];
|
||||
if (bone != null)
|
||||
{
|
||||
bone.transform.localPosition = new Vector3((float)bd.roleDatas[i].localPose.PosX, (float)bd.roleDatas[i].localPose.PosY, (float)bd.roleDatas[i].localPose.PosZ);
|
||||
bone.transform.localRotation = new Quaternion((float)bd.roleDatas[i].localPose.RotQx, (float)bd.roleDatas[i].localPose.RotQy, (float)bd.roleDatas[i].localPose.RotQz, (float)bd.roleDatas[i].localPose.RotQw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public void StartBodyTracking()
|
||||
{
|
||||
// Query whether the current device supports human body tracking.
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
supportedBT= BodyTrackingFeature.IsBodyTrackingSupported();
|
||||
#else
|
||||
PXR_MotionTracking.GetBodyTrackingSupported(ref supportedBT);
|
||||
#endif
|
||||
|
||||
if (!supportedBT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BodyTrackingBoneLength bones = new BodyTrackingBoneLength();
|
||||
|
||||
// Start BodyTracking
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
BodyTrackingFeature.StartBodyTracking(BodyJointSet.BODY_JOINT_SET_BODY_FULL_START, bones);
|
||||
BodyTrackingFeature.GetBodyTrackingState(ref istracking, ref bs);
|
||||
#else
|
||||
PXR_MotionTracking.StartBodyTracking(BodyJointSet.BODY_JOINT_SET_BODY_FULL_START, bones);
|
||||
PXR_MotionTracking.GetBodyTrackingState(ref istracking, ref bs);
|
||||
#endif
|
||||
|
||||
|
||||
// If not calibrated, invoked system motion tracker app for calibration.
|
||||
if (bs.stateCode!=BodyTrackingStatusCode.BT_VALID)
|
||||
{
|
||||
if (bs.message==BodyTrackingMessage.BT_MESSAGE_TRACKER_NOT_CALIBRATED||bs.message==BodyTrackingMessage.BT_MESSAGE_UNKNOWN)
|
||||
{
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
BodyTrackingFeature.StartMotionTrackerCalibApp();
|
||||
#else
|
||||
PXR_MotionTracking.StartMotionTrackerCalibApp();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
skeletonJoints.gameObject.SetActive(true);
|
||||
updateBT = true;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
int ret = BodyTrackingFeature.StopBodyTracking();
|
||||
#else
|
||||
int ret = PXR_MotionTracking.StopBodyTracking();
|
||||
#endif
|
||||
|
||||
updateBT = false;
|
||||
}
|
||||
|
||||
public void InitializeSkeletonJoints()
|
||||
{
|
||||
Queue<Transform> nodes = new Queue<Transform>();
|
||||
nodes.Enqueue(skeletonJoints);
|
||||
while (nodes.Count > 0)
|
||||
{
|
||||
Transform next = nodes.Dequeue();
|
||||
for (int i = 0; i < next.childCount; ++i)
|
||||
{
|
||||
nodes.Enqueue(next.GetChild(i));
|
||||
}
|
||||
|
||||
ProcessJoint(next);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessJoint(Transform joint)
|
||||
{
|
||||
int index = GetJointIndex(joint.name);
|
||||
if (index >= 0 && index < (int)BodyTrackerRole.ROLE_NUM)
|
||||
{
|
||||
boneMapping[index] = joint;
|
||||
Transform cubeT = joint.Find("Cube");
|
||||
if (cubeT)
|
||||
{
|
||||
cubeT.gameObject.SetActive(showCube);
|
||||
}
|
||||
OptionData optionData = new OptionData();
|
||||
optionData.text = joint.name;
|
||||
dropdown.options.Add(optionData);
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
changeJointT = cubeT;
|
||||
var cubeRenderer = changeJointT.GetComponent<Renderer>();
|
||||
cubeRenderer.material.SetColor("_Color", Color.green);
|
||||
if (changeJointTittle)
|
||||
{
|
||||
changeJointTittle.text = "Joint Rotation : " + joint.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"{joint.name} was not found.");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the integer value corresponding to the JointIndices enum value
|
||||
// passed in as a string.
|
||||
int GetJointIndex(string jointName)
|
||||
{
|
||||
BodyTrackerRole val;
|
||||
if (Enum.TryParse(jointName, out val))
|
||||
{
|
||||
return (int)val;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DropdownValueChanged(Dropdown change)
|
||||
{
|
||||
if (changeJointTittle)
|
||||
{
|
||||
changeJointTittle.text = "Joint Rotation : " + change.options[change.value].text;
|
||||
}
|
||||
|
||||
foreach (var b in boneMapping)
|
||||
{
|
||||
changeJointT = b.Find("Cube");
|
||||
var cubeRenderer = changeJointT.GetComponent<Renderer>();
|
||||
cubeRenderer.material.SetColor("_Color", Color.white);
|
||||
}
|
||||
|
||||
var bone = boneMapping[change.value];
|
||||
if (bone)
|
||||
{
|
||||
changeJointT = bone.Find("Cube");
|
||||
var cubeRenderer = changeJointT.GetComponent<Renderer>();
|
||||
cubeRenderer.material.SetColor("_Color", Color.green);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRotationX(float x)
|
||||
{
|
||||
if (changeJointT)
|
||||
{
|
||||
changeJointT.localRotation = Quaternion.AngleAxis(x, Vector3.right);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRotationY(float y)
|
||||
{
|
||||
if (changeJointT)
|
||||
{
|
||||
changeJointT.localRotation = Quaternion.AngleAxis(y, Vector3.up);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRotationZ(float z)
|
||||
{
|
||||
if (changeJointT)
|
||||
{
|
||||
changeJointT.localRotation = Quaternion.AngleAxis(z, Vector3.forward);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 942b30517cab85247a53f9e13863762b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,196 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
#if PICO_OPENXR_SDK
|
||||
using Unity.XR.OpenXR.Features.PICOSupport;
|
||||
#endif
|
||||
|
||||
public class PXR_CameraEffectBlock : MonoBehaviour
|
||||
{
|
||||
public Texture2D lutTex;
|
||||
|
||||
private int row = 0;
|
||||
private int col = 0;
|
||||
|
||||
private float brightness = 0;
|
||||
private float contrast = 0;
|
||||
private float saturation = 0;
|
||||
private PassthroughStyle passthroughStyle = new()
|
||||
{
|
||||
enableColorMap = true,
|
||||
enableEdgeColor = true,
|
||||
TextureOpacityFactor = 1.0f
|
||||
};
|
||||
|
||||
private float r = 0;
|
||||
private float g = 0;
|
||||
private float b = 0;
|
||||
private float a = 0;
|
||||
private Color[] values;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
#if PICO_OPENXR_SDK
|
||||
PassthroughFeature.EnableVideoSeeThrough = true;
|
||||
values = new Color[PassthroughFeature.XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB];
|
||||
#else
|
||||
PXR_Manager.EnableVideoSeeThrough = true;
|
||||
PXR_MixedReality.EnableVideoSeeThroughEffect(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetColortemp(float x)
|
||||
{
|
||||
#if PICO_OPENXR_SDK
|
||||
#else
|
||||
PXR_MixedReality.EnableVideoSeeThroughEffect(true);
|
||||
PXR_MixedReality.SetVideoSeeThroughEffect(PxrLayerEffect.Colortemp, x, 0);
|
||||
#endif
|
||||
}
|
||||
public void SetBrightness(float x)
|
||||
{
|
||||
#if PICO_OPENXR_SDK
|
||||
brightness = x;
|
||||
PassthroughFeature.SetBrightnessContrastSaturation(ref passthroughStyle, brightness, contrast, saturation);
|
||||
PassthroughFeature.SetPassthroughStyle(passthroughStyle);
|
||||
#else
|
||||
PXR_MixedReality.EnableVideoSeeThroughEffect(true);
|
||||
PXR_MixedReality.SetVideoSeeThroughEffect(PxrLayerEffect.Brightness, x, 0);
|
||||
#endif
|
||||
}
|
||||
public void SetSaturation(float x)
|
||||
{
|
||||
#if PICO_OPENXR_SDK
|
||||
saturation = x;
|
||||
PassthroughFeature.SetBrightnessContrastSaturation(ref passthroughStyle, brightness, contrast, saturation);
|
||||
PassthroughFeature.SetPassthroughStyle(passthroughStyle);
|
||||
#else
|
||||
PXR_MixedReality.EnableVideoSeeThroughEffect(true);
|
||||
PXR_MixedReality.SetVideoSeeThroughEffect(PxrLayerEffect.Saturation, x, 0);
|
||||
#endif
|
||||
}
|
||||
public void SetContrast(float x)
|
||||
{
|
||||
#if PICO_OPENXR_SDK
|
||||
contrast = x;
|
||||
PassthroughFeature.SetBrightnessContrastSaturation(ref passthroughStyle, brightness, contrast, saturation);
|
||||
PassthroughFeature.SetPassthroughStyle(passthroughStyle);
|
||||
#else
|
||||
PXR_MixedReality.EnableVideoSeeThroughEffect(true);
|
||||
PXR_MixedReality.SetVideoSeeThroughEffect(PxrLayerEffect.Contrast, x, 0);
|
||||
#endif
|
||||
}
|
||||
public void SetLut()
|
||||
{
|
||||
if (lutTex)
|
||||
{
|
||||
#if PICO_OPENXR_SDK
|
||||
#else
|
||||
PXR_MixedReality.EnableVideoSeeThroughEffect(true);
|
||||
PXR_MixedReality.SetVideoSeeThroughLut(lutTex, 8, 8);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
public void ClearAll()
|
||||
{
|
||||
#if PICO_OPENXR_SDK
|
||||
passthroughStyle = new()
|
||||
{
|
||||
enableColorMap = true,
|
||||
enableEdgeColor = true,
|
||||
TextureOpacityFactor = 1.0f
|
||||
};
|
||||
PassthroughFeature.SetPassthroughStyle(passthroughStyle);
|
||||
#else
|
||||
PXR_MixedReality.EnableVideoSeeThroughEffect(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if PICO_OPENXR_SDK
|
||||
public void MonoToMono()
|
||||
{
|
||||
var monOvalues = new int[PassthroughFeature.XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB];
|
||||
for (int i = 0; i < PassthroughFeature.XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB; ++i)
|
||||
{
|
||||
monOvalues[i] = i;
|
||||
}
|
||||
PassthroughFeature.SetColorMapbyMonoToMono(ref passthroughStyle, monOvalues);
|
||||
PassthroughFeature.SetPassthroughStyle(passthroughStyle);
|
||||
}
|
||||
|
||||
public void SetEdgeColorToR(float x)
|
||||
{
|
||||
r = x;
|
||||
SetEdgeColorRGBA();
|
||||
}
|
||||
|
||||
public void SetEdgeColorToG(float x)
|
||||
{
|
||||
g = x;
|
||||
SetEdgeColorRGBA();
|
||||
}
|
||||
|
||||
public void SetEdgeColorToB(float x)
|
||||
{
|
||||
b = x;
|
||||
SetEdgeColorRGBA();
|
||||
}
|
||||
|
||||
public void SetEdgeColorToA(float x)
|
||||
{
|
||||
a = x;
|
||||
SetEdgeColorRGBA();
|
||||
}
|
||||
|
||||
public void SetEdgeColorRGBA()
|
||||
{
|
||||
passthroughStyle.EdgeColor = new Color(r, g, b, a);
|
||||
PassthroughFeature.SetPassthroughStyle(passthroughStyle);
|
||||
}
|
||||
|
||||
public void SetColorMapR()
|
||||
{
|
||||
var values = new Color[PassthroughFeature.XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB];
|
||||
for (int i = 0; i < PassthroughFeature.XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB; ++i)
|
||||
{
|
||||
float colorValue = i / 255.0f;
|
||||
values[i] = new Color(colorValue, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
PassthroughFeature.SetColorMapbyMonoToRgba(ref passthroughStyle, values);
|
||||
PassthroughFeature.SetPassthroughStyle(passthroughStyle);
|
||||
}
|
||||
public void SetColorMapG()
|
||||
{
|
||||
var values = new Color[PassthroughFeature.XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB];
|
||||
for (int i = 0; i < PassthroughFeature.XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB; ++i)
|
||||
{
|
||||
float colorValue = i / 255.0f;
|
||||
values[i] = new Color(0.0f, colorValue, 0.0f, 1.0f);
|
||||
}
|
||||
PassthroughFeature.SetColorMapbyMonoToRgba(ref passthroughStyle, values);
|
||||
PassthroughFeature.SetPassthroughStyle(passthroughStyle);
|
||||
}
|
||||
|
||||
public void SetColorMapB()
|
||||
{
|
||||
var values = new Color[PassthroughFeature.XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB];
|
||||
for (int i = 0; i < PassthroughFeature.XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB; ++i)
|
||||
{
|
||||
float colorValue = i / 255.0f;
|
||||
values[i] = new Color(0.0f, 0.0f, colorValue, 1.0f);
|
||||
}
|
||||
PassthroughFeature.SetColorMapbyMonoToRgba(ref passthroughStyle, values);
|
||||
PassthroughFeature.SetPassthroughStyle(passthroughStyle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41e24597e86cd0642a0a2d98622a50c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,103 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
public class PXR_ObjectTrackingBlock : MonoBehaviour
|
||||
{
|
||||
private Transform objectTrackers;
|
||||
private bool updateOT = true;
|
||||
private int objectTrackersMaxNum = 3;
|
||||
int DeviceCount = 1;
|
||||
List<long> trackerIds = new List<long>();
|
||||
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
objectTrackers = transform;
|
||||
for (int i = 0; i < objectTrackersMaxNum; i++)
|
||||
{
|
||||
GameObject ga = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
ga.transform.parent = objectTrackers;
|
||||
ga.transform.localScale = Vector3.one * 0f;
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
if (GraphicsSettings.defaultRenderPipeline != null)
|
||||
#else
|
||||
if (GraphicsSettings.renderPipelineAsset != null)
|
||||
#endif
|
||||
{
|
||||
Material material = new Material(Shader.Find("Universal Render Pipeline/Lit"));
|
||||
Renderer renderer = ga.GetComponent<Renderer>();
|
||||
if (renderer != null)
|
||||
{
|
||||
renderer.sharedMaterial = material;
|
||||
}
|
||||
}
|
||||
}
|
||||
int res = -1;
|
||||
#if PICO_OPENXR_SDK
|
||||
#else
|
||||
PXR_MotionTracking.RequestMotionTrackerCompleteAction += RequestMotionTrackerComplete;
|
||||
res = PXR_MotionTracking.CheckMotionTrackerNumber(MotionTrackerNum.TWO);
|
||||
#endif
|
||||
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
objectTrackers.gameObject.SetActive(true);
|
||||
|
||||
}
|
||||
}
|
||||
private void RequestMotionTrackerComplete(RequestMotionTrackerCompleteEventData obj)
|
||||
{
|
||||
DeviceCount = (int)obj.trackerCount;
|
||||
for (int i = 0; i < DeviceCount; i++)
|
||||
{
|
||||
trackerIds.Add(obj.trackerIds[i]);
|
||||
}
|
||||
|
||||
updateOT = true;
|
||||
}
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
|
||||
for (int i = 0; i < objectTrackersMaxNum; i++)
|
||||
{
|
||||
var child = objectTrackers.GetChild(i);
|
||||
if (child)
|
||||
{
|
||||
child.localScale = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
// Update motiontrackers pose.
|
||||
if (updateOT )
|
||||
{
|
||||
MotionTrackerLocation location = new MotionTrackerLocation();
|
||||
for (int i = 0; i < trackerIds.Count; i++)
|
||||
{
|
||||
bool isValidPose = false;
|
||||
int result = -1;
|
||||
#if PICO_OPENXR_SDK
|
||||
#else
|
||||
result = PXR_MotionTracking.GetMotionTrackerLocation(trackerIds[i], ref location, ref isValidPose);
|
||||
#endif
|
||||
// if the return is successful
|
||||
if (result == 0)
|
||||
{
|
||||
var child = objectTrackers.GetChild(i);
|
||||
if (child)
|
||||
{
|
||||
child.localPosition = location.pose.Position.ToVector3();
|
||||
child.localRotation = location.pose.Orientation.ToQuat();
|
||||
child.localScale = Vector3.one * 0.1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebf5cf49b568aa24db3dbf4a942dee24
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class SliderText : MonoBehaviour
|
||||
{
|
||||
public Text text;
|
||||
private Slider m_Slider;//Slider<65><72><EFBFBD><EFBFBD>
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
m_Slider = GetComponent<Slider>();
|
||||
m_Slider.onValueChanged.AddListener(delegate {ValueChangeCheck(); });
|
||||
}
|
||||
|
||||
private void ValueChangeCheck()
|
||||
{
|
||||
text.text = m_Slider.value.ToString();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2685195f56c9cfc4c8822476cbe32045
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bec33959f7da2ab48afb4551f620ee26
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,84 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using System.Collections.Generic;
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
internal class PXR_CubeLayer : PXR_CustomLayerHandler<XrCompositionLayerCubeKHR>
|
||||
{
|
||||
protected override unsafe bool CreateSwapchain(CompositionLayerManager.LayerInfo layerInfo, out SwapchainCreateInfo swapchainCreateInfo)
|
||||
{
|
||||
TexturesExtension texture = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texture == null || texture.enabled == false || texture.LeftTexture == null)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
swapchainCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = PXR_LayerUtility.GetDefaultColorFormat(),
|
||||
SampleCount = 1,
|
||||
Width = (uint)(texture.LeftTexture.width),
|
||||
Height = (uint)(texture.LeftTexture.height),
|
||||
FaceCount = 6,
|
||||
ArraySize = 1,
|
||||
MipCount = (uint)texture.LeftTexture.mipmapCount,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override unsafe bool CreateNativeLayer(CompositionLayerManager.LayerInfo layerInfo, SwapchainCreatedOutput swapchainOutput, out XrCompositionLayerCubeKHR nativeLayer)
|
||||
{
|
||||
var data = layerInfo.Layer.LayerData as CubeProjectionLayerData;
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
|
||||
nativeLayer = new XrCompositionLayerCubeKHR()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_COMPOSITION_LAYER_CUBE_KHR,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer),
|
||||
LayerFlags = data.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha,
|
||||
Space = PXR_LayerUtility.GetCurrentAppSpace(),
|
||||
EyeVisibility = 0,
|
||||
Swapchain = swapchainOutput.handle,
|
||||
ImageArrayIndex = 0,
|
||||
Orientation = new XrQuaternionf(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation)
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerCubeKHR nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false || texturesExtension.LeftTexture == null)
|
||||
return false;
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
nativeLayer.Orientation = new XrQuaternionf(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerCubeKHR nativeLayer)
|
||||
{
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
return base.ActiveNativeLayer(layerInfo, ref nativeLayer);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f76b65d70a4bf240be9fa70a4d5d87e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,491 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
#if UNITY_VIDEO
|
||||
using UnityEngine.Video;
|
||||
#endif
|
||||
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base implementation for the <see cref="PXR_LayerProvider.ILayerHandler"/> interface.
|
||||
/// You can implement the required methods of this abstract class to create a concrete layer handler.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <see cref="PXR_LayerProvider.ILayerHandler"/> methods that this class implements handle adding
|
||||
/// and removing composition layers from native arrays, swap chain creation dispatching and other tasks
|
||||
/// required by the Unity side of the API.
|
||||
///
|
||||
/// The abstract methods that you must implement handle the custom aspects of your layer. These methods include:
|
||||
///
|
||||
/// * <see cref="CreateSwapchain(CompositionLayerManager.LayerInfo, out SwapchainCreateInfo)"/>
|
||||
/// * <see cref="CreateNativeLayer(CompositionLayerManager.LayerInfo, PXR_CustomLayerHandler{T}.SwapchainCreatedOutput, out T)"/>
|
||||
/// * <see cref="ModifyNativeLayer(CompositionLayerManager.LayerInfo, ref T)"/>
|
||||
///
|
||||
/// You are not required to implement a custom layer handler based on this abstract class, but doing so should be
|
||||
/// easier than implementing the <see cref="PXR_LayerProvider.ILayerHandler"/> interface in its entirety.
|
||||
///
|
||||
/// You must register your concrete layer handler object with
|
||||
/// <see cref="PXR_LayerProvider.RegisterLayerHandler(Type, PXR_LayerProvider.ILayerHandler)"/>.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">The native PXR_ structure of the composition layer to handle.</typeparam>
|
||||
public abstract class PXR_CustomLayerHandler<T> : PXR_LayerProvider.ILayerHandler, IDisposable where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Container for swapchain related information that may be needed during the creation of the native PXR_ composition layer struct.
|
||||
/// </summary>
|
||||
protected struct SwapchainCreateInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Native structure for the swapchain creation info.
|
||||
/// </summary>
|
||||
public XrSwapchainCreateInfo nativeStruct;
|
||||
|
||||
/// <summary>
|
||||
/// Tells if swapchain is using an external surface.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool isExternalSurface;
|
||||
|
||||
/// <summary>
|
||||
/// Tells if swapchain should be stereo.
|
||||
/// </summary>
|
||||
public bool isStereo;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes and returns an instance of SwapchainCreateInfo with the provided parameters.
|
||||
/// </summary>
|
||||
/// <param name="xrSwapchainCreateInfo">Native structure for the swapchain creation info.</param>
|
||||
/// <param name="isExternalSurface">Tells if swapchain is using an external surface.</param>
|
||||
/// <param name="isStereo">Tells if swapchain should be stereo.</param>
|
||||
public SwapchainCreateInfo(XrSwapchainCreateInfo xrSwapchainCreateInfo, bool isExternalSurface = false, bool isStereo = false)
|
||||
{
|
||||
this.nativeStruct = xrSwapchainCreateInfo;
|
||||
this.isExternalSurface = isExternalSurface;
|
||||
this.isStereo = isStereo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion with just a native XrSwapchainCreateInfo struct.
|
||||
/// </summary>
|
||||
/// <param name="createInfo">The native struct to convert.</param>
|
||||
public static implicit operator SwapchainCreateInfo(XrSwapchainCreateInfo createInfo) => new SwapchainCreateInfo(createInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Container for swapchain related information that may be needed during the creation of the native PXR_ composition layer struct.
|
||||
/// </summary>
|
||||
protected struct SwapchainCreatedOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// The handle of the created swapchain.
|
||||
/// Can be used to initialize the swapchain member of a native PXR_ composition layer struct.
|
||||
/// </summary>
|
||||
public ulong handle;
|
||||
|
||||
/// <summary>
|
||||
/// The second handle of the created stereo swapchain.
|
||||
/// Can be used to initialize the swapchain member of a native PXR_ composition layer struct.
|
||||
/// </summary>
|
||||
public ulong secondStereoHandle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Container for grouping render information for each compostion layer.
|
||||
/// </summary>
|
||||
class LayerRenderInfo
|
||||
{
|
||||
public Texture RenderTexture;
|
||||
public Texture Texture;
|
||||
#if UNITY_VIDEO
|
||||
public VideoPlayer videoPlayer;
|
||||
#endif
|
||||
public MeshCollider meshCollider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes and returns an instance of this <c>PXR_CustomLayerHandler<T></c> while also setting the singleton instance member.
|
||||
/// </summary>
|
||||
protected PXR_CustomLayerHandler() => Instance = this;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton instance of this specific handler.
|
||||
/// </summary>
|
||||
protected static PXR_CustomLayerHandler<T> Instance;
|
||||
|
||||
/// <summary>
|
||||
/// Deinitializes this instance of c>PXR_CustomLayerHandler<T></c>.
|
||||
/// </summary>
|
||||
~PXR_CustomLayerHandler() => Dispose(false);
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to create the <see cref="XrSwapchainCreateInfo"/> struct that is passed to PXR_
|
||||
/// to create a swapchain.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To add extensions when constructing the <see cref="XrSwapchainCreateInfo"/> struct, initialize
|
||||
/// the <c>Next</c> pointer with
|
||||
/// <see cref="PXR_LayerUtility.GetExtensionsChain(CompositionLayerManager.LayerInfo, Unity.XR.CompositionLayers.CompositionLayerExtension.ExtensionTarget)"/>.
|
||||
/// </remarks>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// that was just created.</param>
|
||||
/// <param name="swapchainCreateInfo"> An <c>XrSwapchainCreateInfo</c> object created and initialized by the concrete implementation of this method.</returns>
|
||||
/// <returns> A bool indicating success or failure.</returns>
|
||||
|
||||
protected abstract bool CreateSwapchain(CompositionLayerManager.LayerInfo layerInfo, out SwapchainCreateInfo swapchainCreateInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to create the native composition layer struct of type T that is passed to PXR_.
|
||||
/// A swapchain info struct is provided so your layer handler has access to any needed swapchain information.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To add extensions when constructing the <see cref="XrSwapchainCreateInfo"/> struct, initialize
|
||||
/// the <c>Next</c> pointer with <see cref="PXR_LayerUtility.GetExtensionsChain(CompositionLayerManager.LayerInfo, Unity.XR.CompositionLayers.CompositionLayerExtension.ExtensionTarget)"/>.
|
||||
///
|
||||
/// If your struct needs any XrSpace relative info you can use <see cref="PXR_LayerUtility.GetCurrentAppSpace"/>
|
||||
/// to get the current app space.
|
||||
/// </remarks>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// that was just created.</param>
|
||||
/// <param name="swapchainOutput"> Information regarding the swapchain that was created for this layer,
|
||||
/// such as the associated swapchain handle.</param>
|
||||
/// <param name="nativeLayer"> An object of type T that is created and initialized by the concrete implementation of this method.</returns>
|
||||
/// <returns> A bool indicating success or failure.</returns>
|
||||
|
||||
protected abstract bool CreateNativeLayer(CompositionLayerManager.LayerInfo layerInfo, SwapchainCreatedOutput swapchainOutput, out T nativeLayer);
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to modify a native composition layer struct in response to changes on the associated
|
||||
/// <see cref="Unity.XR.CompositionLayers.Layers.LayerData"/> object or any extension components on the
|
||||
/// <see cref="Unity.XR.CompositionLayers.CompositionLayer"/> GameObject.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You must reinitialize the Next pointer with <see cref="PXR_LayerUtility.GetExtensionsChain(CompositionLayerManager.LayerInfo, Unity.XR.CompositionLayers.CompositionLayerExtension.ExtensionTarget)"/>
|
||||
/// to get any potential updates from extension components.
|
||||
/// </remarks>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition
|
||||
/// layer that was modified.</param>
|
||||
/// <param name="nativeLayer"> A reference to the native PXR_ structure of the composition layer that was modified.
|
||||
/// The concrete implementation of this method should update the values of the structure as appropriate.</param>
|
||||
/// <returns> A bool indicating success or failure.</returns>
|
||||
protected abstract bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref T nativeLayer);
|
||||
|
||||
/// <summary>
|
||||
/// Mapping of instance ids and native layer structs to help determine what layers are currently set to be active.
|
||||
/// </summary>
|
||||
protected Dictionary<int, T> m_nativeLayers = new Dictionary<int, T>();
|
||||
|
||||
/// <summary>
|
||||
/// Thread safe queue used to dispatch callbacks that may come from other threads such as the swapchain creation
|
||||
/// on the graphics thread.
|
||||
/// </summary>
|
||||
protected ConcurrentQueue<Action> actionsForMainThread = new ConcurrentQueue<Action>();
|
||||
|
||||
Dictionary<int, LayerRenderInfo> m_renderInfos = new Dictionary<int, LayerRenderInfo>();
|
||||
Dictionary<int, CompositionLayerManager.LayerInfo> m_layerInfos = new Dictionary<int, CompositionLayerManager.LayerInfo>();
|
||||
NativeArray<T> m_ActiveNativeLayers;
|
||||
NativeArray<int> m_ActiveNativeLayerOrders;
|
||||
int m_ActiveNativeLayerCount;
|
||||
|
||||
/// <summary>
|
||||
/// Implements the <see cref="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> during the Unity update loop.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This implementation carries out two tasks. It dequeues actions for the main thread like dispatch when
|
||||
/// the swapchain has been
|
||||
/// created and it adds all the active layers to the <c>endFrameInfo</c> struct in the native UnityPXR_ lib.
|
||||
/// </remarks>
|
||||
public virtual void OnUpdate()
|
||||
{
|
||||
while (actionsForMainThread.Count > 0)
|
||||
{
|
||||
if (actionsForMainThread.TryDequeue(out Action action))
|
||||
action();
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
if (m_ActiveNativeLayerCount > 0)
|
||||
PXR_LayerUtility.AddActiveLayersToEndFrame(m_ActiveNativeLayers.GetUnsafePtr(), m_ActiveNativeLayerOrders.GetUnsafePtr(), m_ActiveNativeLayerCount, UnsafeUtility.SizeOf<T>());
|
||||
}
|
||||
|
||||
m_ActiveNativeLayerCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the <see cref="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> when a new layer has been created.
|
||||
/// This implementation triggers the creation of a swapchain before the actual native layer struct is created.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// being created.</param>
|
||||
public void CreateLayer(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
CreateSwapchainAsync(layerInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the <see cref="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> when a layer or attached extension has been modified.
|
||||
/// This implementation asks the subclass for any changes that must be made to the layer via
|
||||
/// <see cref="ModifyNativeLayer(CompositionLayerManager.LayerInfo, ref T)"/>
|
||||
/// by sending a reference to the native layer struct.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// that was modified.</param>
|
||||
public virtual void ModifyLayer(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
|
||||
if (!m_nativeLayers.TryGetValue(layerInfo.Id, out var nativeLayer))
|
||||
{
|
||||
if (texturesExtension != null && texturesExtension.TextureAdded)
|
||||
{
|
||||
texturesExtension.TextureAdded = false;
|
||||
CreateLayer(layerInfo);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var success = ModifyNativeLayer(layerInfo, ref nativeLayer);
|
||||
if (success)
|
||||
m_nativeLayers[layerInfo.Id] = nativeLayer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the <see cref="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> when a layer is destroyed or disabled.
|
||||
/// </summary>
|
||||
/// <param name="removedLayerId"> The instance id of the CompositionLayer component that was removed.</param>
|
||||
public virtual void RemoveLayer(int removedLayerId)
|
||||
{
|
||||
PXR_LayerUtility.ReleaseSwapchain(removedLayerId);
|
||||
m_nativeLayers.Remove(removedLayerId);
|
||||
m_layerInfos.Remove(removedLayerId);
|
||||
m_renderInfos.Remove(removedLayerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the <see cref="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> when a layer is considered to be currently active.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// being set to active.</param>
|
||||
public virtual void SetActiveLayer(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
if (!m_nativeLayers.TryGetValue(layerInfo.Id, out var nativeLayer))
|
||||
return;
|
||||
var success = ActiveNativeLayer(layerInfo, ref nativeLayer);
|
||||
if (!success)
|
||||
return;
|
||||
m_nativeLayers[layerInfo.Id] = nativeLayer;
|
||||
ResizeNativeArrays();
|
||||
m_ActiveNativeLayers[m_ActiveNativeLayerCount] = m_nativeLayers[layerInfo.Id];
|
||||
m_ActiveNativeLayerOrders[m_ActiveNativeLayerCount] = layerInfo.Layer.Order;
|
||||
++m_ActiveNativeLayerCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements method from <see cref="IDisposable"/> that is called by the <see cref="PXR_LayerProvider"/>
|
||||
/// when this custom layer handler instance is disposed.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all maps and disposes any created native arrays.
|
||||
/// </summary>
|
||||
/// <param name="disposing">Determines if this method was called from the Dispose() method or the finalizer.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
m_layerInfos.Clear();
|
||||
m_nativeLayers.Clear();
|
||||
m_renderInfos.Clear();
|
||||
}
|
||||
|
||||
if (m_ActiveNativeLayers.IsCreated)
|
||||
m_ActiveNativeLayers.Dispose();
|
||||
if (m_ActiveNativeLayerOrders.IsCreated)
|
||||
m_ActiveNativeLayerOrders.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls <see cref="CreateSwapchain(CompositionLayerManager.LayerInfo, out SwapchainCreateInfo)"/> to create a
|
||||
/// <see cref="SwapchainCreateInfo"/> struct that is then passed to the
|
||||
/// UnityPXR_ lib to actually create the swapchain on the graphics thread.
|
||||
/// The static <see cref="OnCreatedSwapchainCallback(int, ulong)"/> method is passed as a callback and invoked when
|
||||
/// the swapchain has been created.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// that was just created.</param>
|
||||
protected virtual void CreateSwapchainAsync(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
m_layerInfos[layerInfo.Id] = layerInfo;
|
||||
var success = CreateSwapchain(layerInfo, out var swapChainInfo);
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
if (swapChainInfo.isStereo)
|
||||
PXR_LayerUtility.CreateStereoSwapchain(layerInfo.Id, swapChainInfo.nativeStruct, OnCreatedStereoSwapchainCallback);
|
||||
else
|
||||
PXR_LayerUtility.CreateSwapchain(layerInfo.Id, swapChainInfo.nativeStruct, swapChainInfo.isExternalSurface, OnCreatedSwapchainCallback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is dispatched to the main thread inside <see cref="OnCreatedSwapchainCallback(int, ulong)"/>
|
||||
/// and asks this subclass to create the native layer struct by invoking
|
||||
/// <see cref="CreateNativeLayer(CompositionLayerManager.LayerInfo, SwapchainCreatedOutput, out T)"/>.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// that was just created.</param>
|
||||
/// <param name="swapchainOutput"> Information regarding the swapchain that was created for this layer, such as
|
||||
/// the associated swapchain handle.</param>
|
||||
protected virtual void OnCreatedSwapchain(CompositionLayerManager.LayerInfo layerInfo, SwapchainCreatedOutput swapchainOutput)
|
||||
{
|
||||
var success = CreateNativeLayer(layerInfo, swapchainOutput, out var nativeLayer);
|
||||
if (success){
|
||||
|
||||
m_nativeLayers[layerInfo.Id] = nativeLayer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the native arrays are of the same size as the m_nativeLayers map.
|
||||
/// </summary>
|
||||
protected virtual void ResizeNativeArrays()
|
||||
{
|
||||
if (!m_ActiveNativeLayers.IsCreated && !m_ActiveNativeLayerOrders.IsCreated)
|
||||
{
|
||||
m_ActiveNativeLayers = new NativeArray<T>(m_nativeLayers.Count, Allocator.Persistent);
|
||||
m_ActiveNativeLayerOrders = new NativeArray<int>(m_nativeLayers.Count, Allocator.Persistent);
|
||||
return;
|
||||
}
|
||||
|
||||
UnityEngine.Assertions.Assert.AreEqual(m_ActiveNativeLayers.Length, m_ActiveNativeLayerOrders.Length);
|
||||
|
||||
if (m_ActiveNativeLayers.Length < m_nativeLayers.Count)
|
||||
{
|
||||
var newLayerArray = new NativeArray<T>(m_nativeLayers.Count, Allocator.Persistent);
|
||||
NativeArray<T>.Copy(m_ActiveNativeLayers, newLayerArray, m_ActiveNativeLayers.Length);
|
||||
m_ActiveNativeLayers.Dispose();
|
||||
m_ActiveNativeLayers = newLayerArray;
|
||||
|
||||
var newOrderArray = new NativeArray<int>(m_nativeLayers.Count, Allocator.Persistent);
|
||||
NativeArray<int>.Copy(m_ActiveNativeLayerOrders, newOrderArray, m_ActiveNativeLayerOrders.Length);
|
||||
m_ActiveNativeLayerOrders.Dispose();
|
||||
m_ActiveNativeLayerOrders = newOrderArray;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to modify a native composition layer struct in response to when it is active.
|
||||
/// An active compositon layer will invoke this every frame.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition
|
||||
/// layer that is active.</param>
|
||||
/// <param name="nativeLayer"> A reference to the native PXR_ structure of the composition layer that is active.</param>
|
||||
/// <returns>Bool indicating success or failure. A failure case will result in the native composition layer struct not being added into the final XrFrameEndInfo struct.</returns>
|
||||
protected virtual bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref T nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.LeftTexture == null || texturesExtension.sourceTexture == TexturesExtension.SourceTextureEnum.AndroidSurface)
|
||||
return true;
|
||||
|
||||
if (m_renderInfos.TryGetValue(layerInfo.Id, out var container))
|
||||
{
|
||||
PXR_LayerUtility.WriteToRenderTexture(layerInfo.Id, container.Texture, container.RenderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
bool isNewTexture = container.Texture != texturesExtension.LeftTexture;
|
||||
|
||||
if (isNewTexture)
|
||||
{
|
||||
// If we have a new texture with different dimensions then we need to release the current swapchain and create another.
|
||||
// This is an async procedure that also creates a new native layer object.
|
||||
if (container.Texture.width != texturesExtension.LeftTexture.width || container.Texture.height != texturesExtension.LeftTexture.height)
|
||||
{
|
||||
RemoveLayer(layerInfo.Id);
|
||||
CreateSwapchainAsync(layerInfo);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
container.Texture = texturesExtension.LeftTexture;
|
||||
|
||||
#if UNITY_VIDEO
|
||||
container.videoPlayer = layerInfo.Layer.GetComponent<VideoPlayer>();
|
||||
#endif
|
||||
container.meshCollider = layerInfo.Layer.GetComponent<MeshCollider>();
|
||||
}
|
||||
|
||||
bool isVideo = false;
|
||||
#if UNITY_VIDEO
|
||||
isVideo = container.videoPlayer != null && container.videoPlayer.enabled;
|
||||
#endif
|
||||
bool isUI = container.meshCollider != null && container.meshCollider.enabled;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Layers with a video or ui component in editor may have multiple native render textures associated with the layer id so we must find them.
|
||||
if (isVideo || isUI){
|
||||
PXR_LayerUtility.FindAndWriteToRenderTexture(layerInfo, container.Texture, out container.RenderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
}
|
||||
else if (isNewTexture){
|
||||
PXR_LayerUtility.WriteToRenderTexture(layerInfo.Id, container.Texture, container.RenderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
}
|
||||
#else
|
||||
// We only need to write continuously to the native render texture if our texture is changing.
|
||||
if (isVideo || isUI || isNewTexture)
|
||||
PXR_LayerUtility.WriteToRenderTexture(layerInfo.Id, container.Texture, container.RenderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isRenderTextureWritten = PXR_LayerUtility.FindAndWriteToRenderTexture(layerInfo, texturesExtension.LeftTexture, out Texture renderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
if (isRenderTextureWritten)
|
||||
{
|
||||
var layerRenderInfo = new LayerRenderInfo()
|
||||
{ Texture = texturesExtension.LeftTexture, RenderTexture = renderTexture,
|
||||
#if UNITY_VIDEO
|
||||
videoPlayer = layerInfo.Layer.GetComponent<VideoPlayer>(),
|
||||
#endif
|
||||
meshCollider = layerInfo.Layer.GetComponent<MeshCollider>() };
|
||||
|
||||
m_renderInfos.Add(layerInfo.Id, layerRenderInfo);
|
||||
};
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[AOT.MonoPInvokeCallback(typeof(PXR_LayerUtility.SwapchainCallbackDelegate))]
|
||||
static void OnCreatedSwapchainCallback(int layerId, ulong swapchainHandle)
|
||||
{
|
||||
if (Instance == null)
|
||||
return;
|
||||
|
||||
Instance.actionsForMainThread.Enqueue(() => { Instance.OnCreatedSwapchain(Instance.m_layerInfos[layerId], new SwapchainCreatedOutput { handle = swapchainHandle });});
|
||||
}
|
||||
|
||||
[AOT.MonoPInvokeCallback(typeof(PXR_LayerUtility.StereoSwapchainCallbackDelegate))]
|
||||
static void OnCreatedStereoSwapchainCallback(int layerId, ulong swapchainHandleLeft, ulong swapchainHandleRight)
|
||||
{
|
||||
if (Instance == null)
|
||||
return;
|
||||
|
||||
Instance.actionsForMainThread.Enqueue(() => { Instance.OnCreatedSwapchain(Instance.m_layerInfos[layerId], new SwapchainCreatedOutput { handle = swapchainHandleLeft, secondStereoHandle = swapchainHandleRight}); });
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c975401c3bdf0db46afd0591e8ce6a27
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,314 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
internal class PXR_CylinderLayer : PXR_CustomLayerHandler<XrCompositionLayerCylinderKHR>
|
||||
{
|
||||
float savedDelta;
|
||||
bool layerDataChanged = false;
|
||||
|
||||
struct CylinderLayerSize
|
||||
{
|
||||
public float radius;
|
||||
public float centralAngle;
|
||||
public float aspectRatio;
|
||||
|
||||
public static implicit operator CylinderLayerSize(Vector3 v) => new CylinderLayerSize
|
||||
{
|
||||
radius = v.x,
|
||||
centralAngle = v.y,
|
||||
aspectRatio = v.z
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool CreateSwapchain(CompositionLayerManager.LayerInfo layer, out SwapchainCreateInfo swapchainCreateInfo)
|
||||
{
|
||||
if (layer.Layer == null)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
var texturesExtension = layer.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture == null)
|
||||
goto default;
|
||||
|
||||
var xrCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = PXR_LayerUtility.GetDefaultColorFormat(),
|
||||
SampleCount = 1,
|
||||
Width = (uint)texturesExtension.LeftTexture.width,
|
||||
Height = (uint)texturesExtension.LeftTexture.height,
|
||||
FaceCount = 1,
|
||||
ArraySize = 1,
|
||||
MipCount = (uint)texturesExtension.LeftTexture.mipmapCount,
|
||||
};
|
||||
|
||||
swapchainCreateInfo = new SwapchainCreateInfo(xrCreateInfo, isExternalSurface: false);
|
||||
return true;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
var xrCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = 0,
|
||||
SampleCount = 0,
|
||||
Width = (uint)texturesExtension.Resolution.x,
|
||||
Height = (uint)texturesExtension.Resolution.y,
|
||||
FaceCount = 0,
|
||||
ArraySize = 0,
|
||||
MipCount = 0,
|
||||
};
|
||||
swapchainCreateInfo = new SwapchainCreateInfo(xrCreateInfo, isExternalSurface: true);
|
||||
return true;
|
||||
#else
|
||||
goto default;
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool CreateNativeLayer(CompositionLayerManager.LayerInfo layer, SwapchainCreatedOutput swapchainOutput, out XrCompositionLayerCylinderKHR nativeLayer)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var data = layer.Layer.LayerData as CylinderLayerData;
|
||||
var transform = layer.Layer.GetComponent<Transform>();
|
||||
var texturesExtension = layer.Layer.GetComponent<TexturesExtension>();
|
||||
int subImageWidth = 0;
|
||||
int subImageHeight = 0;
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
subImageWidth = texturesExtension.LeftTexture.width;
|
||||
subImageHeight = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
subImageWidth = (int)texturesExtension.Resolution.x;
|
||||
subImageHeight = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CylinderLayerSize scaledSize = data.GetScaledSize(transform.lossyScale);
|
||||
if (texturesExtension.CropToAspect)
|
||||
{
|
||||
scaledSize = FixAspectRatio(data, scaledSize, subImageWidth, subImageHeight);
|
||||
}
|
||||
|
||||
nativeLayer = new XrCompositionLayerCylinderKHR()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Layer),
|
||||
LayerFlags = data.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha,
|
||||
Space = PXR_LayerUtility.GetCurrentAppSpace(),
|
||||
EyeVisibility = 0,
|
||||
SubImage = new XrSwapchainSubImage()
|
||||
{
|
||||
Swapchain = swapchainOutput.handle,
|
||||
ImageRect = new XrRect2Di()
|
||||
{
|
||||
Offset = new XrOffset2Di() { X = 0, Y = 0 },
|
||||
Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = subImageWidth,
|
||||
Height = subImageHeight
|
||||
}
|
||||
},
|
||||
ImageArrayIndex = 0
|
||||
},
|
||||
Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation),
|
||||
Radius = data.ApplyTransformScale ? scaledSize.radius : data.Radius,
|
||||
CentralAngle = data.ApplyTransformScale ? scaledSize.centralAngle : data.CentralAngle,
|
||||
AspectRatio = data.ApplyTransformScale ? scaledSize.aspectRatio : data.AspectRatio,
|
||||
};
|
||||
layerDataChanged = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerCylinderKHR nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
return false;
|
||||
|
||||
var data = layerInfo.Layer.LayerData as CylinderLayerData;
|
||||
GetSubImageDimensions(out int subImageWidth, out int subImageHeight, texturesExtension);
|
||||
nativeLayer.SubImage.ImageRect.Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = subImageWidth,
|
||||
Height = subImageHeight
|
||||
};
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
CylinderLayerSize scaledSize = data.GetScaledSize(transform.lossyScale);
|
||||
if (texturesExtension.CropToAspect)
|
||||
{
|
||||
scaledSize = FixAspectRatio(data, scaledSize, subImageWidth, subImageHeight);
|
||||
}
|
||||
nativeLayer.Radius = data.ApplyTransformScale ? scaledSize.radius : data.Radius;
|
||||
nativeLayer.CentralAngle = data.ApplyTransformScale ? scaledSize.centralAngle : data.CentralAngle;
|
||||
nativeLayer.AspectRatio = data.ApplyTransformScale ? scaledSize.aspectRatio : data.AspectRatio;
|
||||
|
||||
unsafe
|
||||
{
|
||||
nativeLayer.Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer);
|
||||
}
|
||||
layerDataChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerCylinderKHR nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
return false;
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
|
||||
// Special treatment for cylinder type based on destination rects.
|
||||
if (texturesExtension != null && texturesExtension.CustomRects)
|
||||
{
|
||||
var cylinderLayer = layerInfo.Layer.LayerData as CylinderLayerData;
|
||||
float rotationDelta = (texturesExtension.LeftEyeDestinationRect.x + (0.5f * texturesExtension.LeftEyeDestinationRect.width) - 0.5f) * cylinderLayer.CentralAngle / (float)System.Math.PI * 180.0f;
|
||||
|
||||
if (rotationDelta != savedDelta)
|
||||
{
|
||||
Quaternion savedDeltaQuaternion = Quaternion.AngleAxis(savedDelta, Vector3.up);
|
||||
Quaternion deltaQuaternion = Quaternion.AngleAxis(rotationDelta, Vector3.up);
|
||||
Quaternion difference = deltaQuaternion * Quaternion.Inverse(savedDeltaQuaternion);
|
||||
|
||||
savedDelta = rotationDelta;
|
||||
transform.rotation *= difference;
|
||||
}
|
||||
}
|
||||
|
||||
nativeLayer.Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
|
||||
if (texturesExtension.CustomRects && layerDataChanged)
|
||||
{
|
||||
GetSubImageDimensions(out int subImageWidth, out int subImageHeight, texturesExtension);
|
||||
|
||||
nativeLayer.SubImage.ImageRect = new XrRect2Di()
|
||||
{
|
||||
Offset = new XrOffset2Di()
|
||||
{
|
||||
X = (int)(subImageWidth * texturesExtension.LeftEyeSourceRect.x),
|
||||
Y = (int)(subImageHeight * texturesExtension.LeftEyeSourceRect.y)
|
||||
},
|
||||
|
||||
Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = (int)(subImageWidth * texturesExtension.LeftEyeSourceRect.width),
|
||||
Height = (int)(subImageHeight * texturesExtension.LeftEyeSourceRect.height)
|
||||
}
|
||||
};
|
||||
|
||||
var currentPosition = PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position;
|
||||
float cylinderHeight = nativeLayer.Radius * nativeLayer.CentralAngle / nativeLayer.AspectRatio;
|
||||
float transformedY = currentPosition.y + (((texturesExtension.LeftEyeDestinationRect.y + (0.5f * texturesExtension.LeftEyeDestinationRect.height) - 0.5f)) * (-1.0f * cylinderHeight));
|
||||
nativeLayer.Pose = new XrPosef(new Vector3(currentPosition.x, transformedY, currentPosition.z), PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
|
||||
nativeLayer.CentralAngle = nativeLayer.CentralAngle * texturesExtension.LeftEyeDestinationRect.width;
|
||||
nativeLayer.AspectRatio = nativeLayer.AspectRatio * texturesExtension.LeftEyeDestinationRect.width / texturesExtension.LeftEyeDestinationRect.height;
|
||||
layerDataChanged = false;
|
||||
}
|
||||
|
||||
return base.ActiveNativeLayer(layerInfo, ref nativeLayer);
|
||||
}
|
||||
|
||||
static CylinderLayerSize FixAspectRatio(CylinderLayerData data, CylinderLayerSize scaledSize, int texWidth, int texHeight)
|
||||
{
|
||||
// because we're cropping and trying to maintain the same other parameters, we don't
|
||||
// need to consider data.MaintainAspectRatio here. That's mostly an editor concern, anyway.
|
||||
float texRatio = (float)texWidth / (float)texHeight;
|
||||
if (scaledSize.aspectRatio > texRatio)
|
||||
{
|
||||
// too wide
|
||||
float width = scaledSize.radius * scaledSize.centralAngle;
|
||||
float height = width / scaledSize.aspectRatio;
|
||||
scaledSize.centralAngle = height * texRatio / scaledSize.radius;
|
||||
scaledSize.aspectRatio = texRatio;
|
||||
}
|
||||
else if (scaledSize.aspectRatio < texRatio)
|
||||
{
|
||||
// too narrow
|
||||
scaledSize.aspectRatio = texRatio;
|
||||
}
|
||||
|
||||
return scaledSize;
|
||||
}
|
||||
|
||||
static void GetSubImageDimensions(out int width, out int height, TexturesExtension texturesExtension)
|
||||
{
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
width = texturesExtension.LeftTexture.width;
|
||||
height = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
width = (int)texturesExtension.Resolution.x;
|
||||
height = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47eec2213f606e6469915b08b46fe725
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
internal class PXR_DefaultLayer : PXR_LayerProvider.ILayerHandler
|
||||
{
|
||||
unsafe void SetDefaultLayerAttributes(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
var extensions = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer);
|
||||
PXR_LayerUtility.SetDefaultSceneLayerExtensions(extensions);
|
||||
|
||||
var flags = layerInfo.Layer.LayerData.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha;
|
||||
PXR_LayerUtility.SetDefaultLayerFlags(flags);
|
||||
}
|
||||
|
||||
public void CreateLayer(CompositionLayerManager.LayerInfo layerInfo) => SetDefaultLayerAttributes(layerInfo);
|
||||
|
||||
public void ModifyLayer(CompositionLayerManager.LayerInfo layerInfo) => SetDefaultLayerAttributes(layerInfo);
|
||||
|
||||
public void OnUpdate()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void RemoveLayer(int id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void SetActiveLayer(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0074c6f14de152e4ca8c07c4bb7601b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,120 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using System;
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
internal class PXR_Equirect2Layer : PXR_CustomLayerHandler<XrCompositionLayerEquirect2KHR>
|
||||
{
|
||||
protected override unsafe bool CreateSwapchain(CompositionLayerManager.LayerInfo layerInfo, out SwapchainCreateInfo swapchainCreateInfo)
|
||||
{
|
||||
TexturesExtension texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false || texturesExtension.LeftTexture == null)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
swapchainCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = PXR_LayerUtility.GetDefaultColorFormat(),
|
||||
SampleCount = 1,
|
||||
Width = (uint)(texturesExtension.LeftTexture.width),
|
||||
Height = (uint)(texturesExtension.LeftTexture.height),
|
||||
FaceCount = 1,
|
||||
ArraySize = 1,
|
||||
MipCount = (uint)texturesExtension.LeftTexture.mipmapCount,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override unsafe bool CreateNativeLayer(CompositionLayerManager.LayerInfo layerInfo, SwapchainCreatedOutput swapchainOutput, out XrCompositionLayerEquirect2KHR nativeLayer)
|
||||
{
|
||||
TexturesExtension texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false || texturesExtension.LeftTexture == null)
|
||||
{
|
||||
nativeLayer = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
var data = layerInfo.Layer.LayerData as EquirectMeshLayerData;
|
||||
Vector2 scaleCalculated = CalculateScale(data.CentralHorizontalAngle, data.UpperVerticalAngle, data.LowerVerticalAngle);
|
||||
|
||||
nativeLayer = new XrCompositionLayerEquirect2KHR()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer),
|
||||
LayerFlags = data.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha,
|
||||
Space = PXR_LayerUtility.GetCurrentAppSpace(),
|
||||
EyeVisibility = 0,
|
||||
SubImage = new XrSwapchainSubImage()
|
||||
{
|
||||
Swapchain = swapchainOutput.handle,
|
||||
ImageRect = new XrRect2Di()
|
||||
{
|
||||
Offset = new XrOffset2Di() { X = 0, Y = 0 },
|
||||
Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = texturesExtension.LeftTexture.width,
|
||||
Height = texturesExtension.LeftTexture.height
|
||||
}
|
||||
},
|
||||
ImageArrayIndex = 0
|
||||
},
|
||||
Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation),
|
||||
Radius = data.Radius,
|
||||
CentralHorizontalAngle = data.CentralHorizontalAngle,
|
||||
UpperVerticalAngle = data.UpperVerticalAngle,
|
||||
LowerVerticalAngle = -data.LowerVerticalAngle
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override unsafe bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerEquirect2KHR nativeLayer)
|
||||
{
|
||||
TexturesExtension texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false || texturesExtension.LeftTexture == null)
|
||||
return false;
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
var data = layerInfo.Layer.LayerData as EquirectMeshLayerData;
|
||||
Vector2 scaleCalculated = CalculateScale(data.CentralHorizontalAngle, data.UpperVerticalAngle, data.LowerVerticalAngle);
|
||||
|
||||
nativeLayer.SubImage.ImageRect.Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = texturesExtension.LeftTexture.width,
|
||||
Height = texturesExtension.LeftTexture.height
|
||||
};
|
||||
nativeLayer.Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
nativeLayer.Radius = data.Radius;
|
||||
nativeLayer.CentralHorizontalAngle = data.CentralHorizontalAngle;
|
||||
nativeLayer.UpperVerticalAngle = data.UpperVerticalAngle;
|
||||
nativeLayer.LowerVerticalAngle = -data.LowerVerticalAngle;
|
||||
|
||||
nativeLayer.Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerEquirect2KHR nativeLayer)
|
||||
{
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
return base.ActiveNativeLayer(layerInfo, ref nativeLayer);
|
||||
}
|
||||
|
||||
Vector2 CalculateScale(float centralHorizontalAngle, float upperVerticalAngle, float lowerVerticalAngle)
|
||||
{
|
||||
return new Vector2((2.0f * (float)Math.PI) / centralHorizontalAngle, (float)Math.PI / (upperVerticalAngle - lowerVerticalAngle));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2e2d51ed59c3174c8104de10442fb25
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,300 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
using Unity.Profiling;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Provider;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages communication of changes between an application and the UnityPXR_ lib for all
|
||||
/// <see cref="Unity.XR.CompositionLayers.Layers.LayerData"/> objects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// PXR_ providers or extensions that create custom composition layer types or that override how the built-in
|
||||
/// layer types are handled, must implement the <see cref="ILayerProvider"/> interface and register instances of
|
||||
/// these implementations with the <c>PXR_LayerProvider</c> via <see cref="RegisterLayerHandler(Type, PXR_LayerProvider.ILayerHandler)"/>.
|
||||
/// </remarks>
|
||||
public class PXR_LayerProvider : ILayerProvider, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface used by the <see cref="PXR_LayerProvider"/> to communicate layer data changes to
|
||||
/// registered layer handlers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <c>ILayerHandler</c> instances must register themselves via
|
||||
/// <see cref="PXR_LayerProvider.RegisterLayerHandler(Type, PXR_LayerProvider.ILayerHandler)"/>
|
||||
/// to specify the <see cref="LayerData"/> type to handle.
|
||||
/// If more than one object registers itself as a handler for a specific <see cref="LayerData"/>
|
||||
/// type, the last registered handler is used.
|
||||
///
|
||||
/// The <see cref="PXR_CustomLayerHandler{T}"/> class provides a partial, base implementation of this interface that you can
|
||||
/// use to create custom layer handlers.
|
||||
/// </remarks>
|
||||
public interface ILayerHandler
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="PXR_LayerProvider"/> during the Unity Update loop.
|
||||
/// All implementations must call <see cref="PXR_LayerUtility.AddActiveLayersToEndFrame(void*,void*,int,int)"/> every frame
|
||||
/// to add their native layer structs to the <c>endFrameInfo</c> struct inside the UnityPXR_ lib.
|
||||
/// </summary>
|
||||
public void OnUpdate();
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="PXR_LayerProvider"/> when a new <see cref="LayerData"/>
|
||||
/// object of the type registered to this <c>ILayerHandler</c> instance has been created.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// that was just created.</param>
|
||||
public void CreateLayer(CompositionLayerManager.LayerInfo layerInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="PXR_LayerProvider"/> when a <see cref="LayerData"/> object
|
||||
/// of the type registered to this <c>ILayerHandler</c> instance has been destroyed or disabled.
|
||||
/// </summary>
|
||||
/// <param name="removedLayerId"> The instance id of the CompositionLayer component that was removed.</param>
|
||||
public void RemoveLayer(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="PXR_LayerProvider"/> when a <see cref="LayerData"/> object
|
||||
/// or any attached extension components have had a member modified.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// that was modified.</param>
|
||||
public void ModifyLayer(CompositionLayerManager.LayerInfo layerInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Called every frame by the <see cref="PXR_LayerProvider"/> for all currently active <see cref="LayerData"/> objects
|
||||
/// of the type registered to this <c>ILayerHandler</c> instance.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// being set to active.</param>
|
||||
public void SetActiveLayer(CompositionLayerManager.LayerInfo layerInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes and returns an instance of <c>PXR_LayerProvider</c>.
|
||||
/// Initializes and registers all the default, built-in layer handlers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <c>PXR_LayerProvider</c> is created and disposed by the <see cref="Management.XRLoader"/>.
|
||||
/// You do not need to create an instance of <c>PXR_LayerProvider</c> yourself. Layer handlers
|
||||
/// should only use the static methods and properties of this class
|
||||
/// </remarks>
|
||||
public PXR_LayerProvider() => InitializeAndRegisterBuiltInHandlers();
|
||||
|
||||
/// <summary>
|
||||
/// Calls the methods in its invocation list when the <c>PXR_LayerProvider</c> has started and registered it's built-in layer handlers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You can use this event to wait for the <c>PXR_LayerProvider</c> to finish registering its built-in layer handlers
|
||||
/// so that you can override them with your own custom layer handlers.
|
||||
/// </remarks>
|
||||
public static event Action Started;
|
||||
|
||||
/// <summary>
|
||||
/// Calls the methods in its invocation list when the <c>PXR_LayerProvider</c> has stopped and is disposed.
|
||||
/// </summary>
|
||||
public static event Action Stopped;
|
||||
|
||||
/// <summary>
|
||||
/// Reports whether the <c>PXR_LayerProvider</c> has already been created and started.
|
||||
/// </summary>
|
||||
public static bool isStarted { get; set; }
|
||||
|
||||
static Dictionary<Type, ILayerHandler> LayerHandlers = new Dictionary<Type, ILayerHandler>();
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderCreate = new ProfilerMarker("PXR_LayerProvider.Create");
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderRemove = new ProfilerMarker("PXR_LayerProvider.Remove");
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderModify = new ProfilerMarker("PXR_LayerProvider.Modify");
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderActive = new ProfilerMarker("PXR_LayerProvider.Active");
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderUpdate = new ProfilerMarker("PXR_LayerProvider.Update");
|
||||
|
||||
/// <summary>
|
||||
/// Registers a concrete <see cref="ILayerHandler"/> object as the handler for all layers of a specific
|
||||
/// <see cref="LayerData"/> subclass.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If more than one object registers itself as a handler for a specific <see cref="LayerData"/>
|
||||
/// type, the last registered handler is used.
|
||||
///
|
||||
/// The <c>PXR_LayerProvider</c> invokes the registered layer handler's <see cref="ILayerHandler"/> methods
|
||||
/// when any object of the associated <see cref="LayerData"/> type is updated in some way.
|
||||
/// </remarks>
|
||||
/// <param name="layerDataType">The <see cref="LayerData"/> subclass to handle.</param>
|
||||
/// <param name="handler">The concrete <c>ILayerHandler</c> instance> to register.</param>
|
||||
public static void RegisterLayerHandler(Type layerDataType, ILayerHandler handler)
|
||||
{
|
||||
if (handler == null)
|
||||
{
|
||||
LayerHandlers.Remove(layerDataType);
|
||||
return;
|
||||
}
|
||||
|
||||
LayerHandlers[layerDataType] = handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the layer provider state on first assignment to the <see cref="CompositionLayerManager" />.
|
||||
/// </summary>
|
||||
/// <param name="layers">The list of all currently known <see cref="CompositionLayer"/> instances, regardless of active state.</param>
|
||||
public void SetInitialState(List<CompositionLayerManager.LayerInfo> layers)
|
||||
{
|
||||
UpdateLayers(layers, null, null, null);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="CompositionLayerManager" /> to tell the instance of <see cref="ILayerProvider" /> about
|
||||
/// the current state of layers it is managing.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="createdLayers">The list of layers that were just created. Any layer in
|
||||
/// this list may be in the <paramref name="activeLayers" /> list if it is activated in the same frame.
|
||||
/// Any layer in this list should not be in <paramref name="modifiedLayers" /> or <paramref name="removedLayers" />.
|
||||
/// This list is ephemeral and cleared after each call.</param>
|
||||
///
|
||||
/// <param name="removedLayers">The list of layers that are no longer being managed. Any layer in
|
||||
/// this list should not be in the <paramref name="createdLayers" />, <paramref name="modifiedLayers" />, or
|
||||
/// <paramref name="activeLayers" /> lists.
|
||||
/// This list is ephemeral and cleared after each call.</param>
|
||||
///
|
||||
/// <param name="modifiedLayers">The list of layers that have been recently modified. Any layer in
|
||||
/// this list may also be in the <paramref name="activeLayers" /> list. Any layer in this list should not
|
||||
/// be in <paramref name="createdLayers" /> or <paramref name="removedLayers" />.
|
||||
/// This list is ephemeral and cleared after each call.</param>
|
||||
///
|
||||
/// <param name="activeLayers">The list of layers currently active within the scene.
|
||||
/// Layers in this list may also be in the <paramref name="createdLayers" /> or <paramref name="modifiedLayers" /> lists
|
||||
/// if they became active in the same frame.</param>
|
||||
public void UpdateLayers(List<CompositionLayerManager.LayerInfo> createdLayers, List<int> removedLayers, List<CompositionLayerManager.LayerInfo> modifiedLayers, List<CompositionLayerManager.LayerInfo> activeLayers)
|
||||
{
|
||||
if (removedLayers != null && removedLayers.Count != 0)
|
||||
{
|
||||
foreach (var handler in LayerHandlers.Values)
|
||||
{
|
||||
foreach (var removed in removedLayers)
|
||||
{
|
||||
s_PXR_LayerProviderRemove.Begin();
|
||||
handler?.RemoveLayer(removed);
|
||||
s_PXR_LayerProviderRemove.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (createdLayers != null && createdLayers.Count != 0)
|
||||
{
|
||||
foreach (var created in createdLayers)
|
||||
{
|
||||
if (created.Layer == null)
|
||||
continue;
|
||||
|
||||
var layerDataType = created.Layer.LayerData.GetType();
|
||||
if (LayerHandlers.TryGetValue(layerDataType, out ILayerHandler handler))
|
||||
{
|
||||
s_PXR_LayerProviderCreate.Begin();
|
||||
handler?.CreateLayer(created);
|
||||
s_PXR_LayerProviderCreate.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modifiedLayers != null && modifiedLayers.Count != 0)
|
||||
{
|
||||
foreach (var modified in modifiedLayers)
|
||||
{
|
||||
if (modified.Layer == null)
|
||||
continue;
|
||||
|
||||
var layerDataType = modified.Layer.LayerData.GetType();
|
||||
|
||||
if (LayerHandlers.TryGetValue(layerDataType, out ILayerHandler handler))
|
||||
{
|
||||
s_PXR_LayerProviderModify.Begin();
|
||||
handler?.ModifyLayer(modified);
|
||||
s_PXR_LayerProviderModify.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activeLayers != null && activeLayers.Count != 0)
|
||||
{
|
||||
foreach (var active in activeLayers)
|
||||
{
|
||||
if (active.Layer == null)
|
||||
continue;
|
||||
|
||||
var layerDataType = active.Layer.LayerData.GetType();
|
||||
if (LayerHandlers.TryGetValue(layerDataType, out ILayerHandler handler))
|
||||
{
|
||||
s_PXR_LayerProviderActive.Begin();
|
||||
handler?.SetActiveLayer(active);
|
||||
s_PXR_LayerProviderActive.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var handler in LayerHandlers.Values)
|
||||
{
|
||||
s_PXR_LayerProviderUpdate.Begin();
|
||||
handler?.OnUpdate();
|
||||
s_PXR_LayerProviderUpdate.End();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for cleanup and to call Dispose() on registered layer handlers.
|
||||
/// </summary>
|
||||
/// <remarks>This is called by the PXR_Loader class when StopInternal() is invoked.</remarks>
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var handler in LayerHandlers.Values)
|
||||
{
|
||||
if (handler is IDisposable)
|
||||
{
|
||||
((IDisposable)handler)?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
LayerHandlers.Clear();
|
||||
isStarted = false;
|
||||
Stopped?.Invoke();
|
||||
}
|
||||
|
||||
public void CleanupState()
|
||||
{
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
}
|
||||
|
||||
void InitializeAndRegisterBuiltInHandlers()
|
||||
{
|
||||
// var defaultLayerHandler = new PXR_DefaultLayer();
|
||||
var quadLayerHandler = new PXR_QuadLayer();
|
||||
//var projectionLayerHandler = new PXR_ProjectionLayer();
|
||||
var cylinderLayerHandler = new PXR_CylinderLayer();
|
||||
var cubeLayerHandler = new PXR_CubeLayer() ;
|
||||
ILayerHandler equirectLayerHandler = new PXR_Equirect2Layer() ;
|
||||
|
||||
// RegisterLayerHandler(typeof(DefaultLayerData), defaultLayerHandler);
|
||||
RegisterLayerHandler(typeof(QuadLayerData), quadLayerHandler);
|
||||
RegisterLayerHandler(typeof(CylinderLayerData), cylinderLayerHandler);
|
||||
//RegisterLayerHandler(typeof(ProjectionLayerData), projectionLayerHandler);
|
||||
//RegisterLayerHandler(typeof(ProjectionLayerRigData), projectionLayerHandler);
|
||||
RegisterLayerHandler(typeof(CubeProjectionLayerData), cubeLayerHandler);
|
||||
RegisterLayerHandler(typeof(EquirectMeshLayerData), equirectLayerHandler);
|
||||
|
||||
isStarted = true;
|
||||
Started?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8aed7bd439ad8c4196f22bd4fa60d1b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,420 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using static Unity.XR.CompositionLayers.CompositionLayersRuntimeSettings;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
/// <summary>
|
||||
/// A general-purpose helper class for composition layer support.
|
||||
/// </summary>
|
||||
public static class PXR_LayerUtility
|
||||
{
|
||||
internal unsafe delegate void LayerCallbackDelegate(int layerId, XrCompositionLayerBaseHeader* layer);
|
||||
|
||||
private static Material textureM;
|
||||
private static Material cubeM;
|
||||
static Dictionary<UInt32, Texture> _textureMap = new Dictionary<UInt32, Texture>();
|
||||
static Dictionary<ValueTuple<int, int>, Texture> _textureCache = new Dictionary<ValueTuple<int, int>, Texture>();
|
||||
|
||||
/// <summary>
|
||||
/// Calls the methods in its invocation list when a swapchain is created on the graphics thread inside the UnityPXR_ lib.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <param name="swapchainHandle">The handle to the native swapchain that was just created.</param>
|
||||
public unsafe delegate void SwapchainCallbackDelegate(int layerId, ulong swapchainHandle);
|
||||
|
||||
/// <summary>
|
||||
/// Calls the methods in its invocation list when a stereo swapchain is created on the graphics thread inside the UnityPXR_ lib.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <param name="swapchainHandleLeft">The handle to one of the stereo swapchains that was just created.</param>
|
||||
/// <param name="swapchainHandleRight">The handle to one of the stereo swapchains that was just created.</param>
|
||||
public unsafe delegate void StereoSwapchainCallbackDelegate(int layerId, ulong swapchainHandleLeft, ulong swapchainHandleRight);
|
||||
|
||||
/// <summary>
|
||||
/// Helper method used to gather the extension components attached to a CompositionLayer GameObject.
|
||||
/// This method chains the native extension struct pointers of those extension components to initialize an PXR_ native object's Next pointer struct chain.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer.</param>
|
||||
/// <param name="extensionTarget"> Represents what part of the composition layer to retrieve extensions for.</param>
|
||||
/// <returns>A pointer to the head of an array of native extension objects that will be associated with a composition layer.</returns>
|
||||
public static unsafe void* GetExtensionsChain(CompositionLayerManager.LayerInfo layerInfo, CompositionLayerExtension.ExtensionTarget extensionTarget)
|
||||
{
|
||||
void* extensionsChainHead = null;
|
||||
void* extensionsChain = null;
|
||||
|
||||
foreach (var extension in layerInfo.Layer.Extensions)
|
||||
{
|
||||
// Skip extension if not enabled or not the intended target.
|
||||
if (!extension.enabled || extension.Target != extensionTarget)
|
||||
continue;
|
||||
|
||||
var extensionNativeStructPtr = extension.GetNativeStructPtr();
|
||||
|
||||
// Skip extension if no native pointer is provided.
|
||||
if (extensionNativeStructPtr == null)
|
||||
continue;
|
||||
|
||||
// Initialize pointer chain if head has not been set.
|
||||
if (extensionsChainHead == null)
|
||||
{
|
||||
extensionsChainHead = extensionNativeStructPtr;
|
||||
extensionsChain = extensionsChainHead;
|
||||
}
|
||||
// Chain pointer if head has been initialized.
|
||||
else
|
||||
{
|
||||
((XrBaseInStructure*)extensionsChain)->Next = extensionNativeStructPtr;
|
||||
extensionsChain = extensionNativeStructPtr;
|
||||
}
|
||||
}
|
||||
|
||||
return extensionsChainHead;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method used get the current app space for any native composition layer structs that may require an associated XrSpace.
|
||||
/// </summary>
|
||||
/// <returns>A handle to the current app space.</returns>
|
||||
/// <remarks>Normally used when creating native composition layers.</remarks>
|
||||
//public static ulong GetCurrentAppSpace() => Features.PXR_Feature.Internal_GetAppSpace(out ulong appSpaceId) ? appSpaceId : 0; // TODO
|
||||
public static ulong GetCurrentAppSpace() => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Helper method used get the XR session handle for any native composition layer structs that may require an associated XrSession.
|
||||
/// </summary>
|
||||
/// <returns>A handle to the current xr session.</returns>
|
||||
//public static ulong GetXRSession() => Features.PXR_Feature.Internal_GetXRSession(out ulong xrSessionHandle) ? xrSessionHandle : 0; // TODO
|
||||
public static ulong GetXRSession() => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Create the <see cref="XrSwapchainCreateInfo"/> struct that is passed to PXR_ SDK to create a swapchain.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <param name="createInfo">The struct used to create the swapchain.</param>
|
||||
/// <param name="isExternalSurface"> Optional parameter that can be used when an external surface will be used, like when using the Android Surface feature.</param>
|
||||
/// <param name="callback"> Optional parameter that can be used if your composition layer needs to know the handle after swapchain creation.</param>
|
||||
public static void CreateSwapchain(int layerId, XrSwapchainCreateInfo createInfo, bool isExternalSurface = false, SwapchainCallbackDelegate callback = null)
|
||||
{
|
||||
Pxr_CompositorLayersCreateSwapchain(layerId, createInfo, isExternalSurface, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the <see cref="XrSwapchainCreateInfo"/> struct that is passed to PXR_ SDK to create a swapchain for stereo projection, like Projection layer type.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <param name="createInfo">The struct used to create the swapchain.</param>
|
||||
/// <param name="callback"> Optional parameter that can be used if your composition layer needs to know the handles after swapchain creation.</param>
|
||||
public static void CreateStereoSwapchain(int layerId, XrSwapchainCreateInfo createInfo, StereoSwapchainCallbackDelegate callback = null)
|
||||
{
|
||||
Pxr_CompositorLayersCreateStereoSwapchain(layerId, createInfo, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release swapchain according to the id provided.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
public static void ReleaseSwapchain(int layerId)
|
||||
{
|
||||
Pxr_CompositorLayersReleaseSwapchain(layerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return swapchain supported color format.
|
||||
/// </summary>
|
||||
/// <returns>The color format the swapchains will be using.</returns>
|
||||
public static Int64 GetDefaultColorFormat()
|
||||
{
|
||||
if (GraphicsDeviceType.Vulkan == SystemInfo.graphicsDeviceType)
|
||||
{
|
||||
return (long)PXR_CompositionLayer.ColorForamt.VK_FORMAT_R8G8B8A8_SRGB;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (long)PXR_CompositionLayer.ColorForamt.GL_SRGB8_ALPHA8;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the render texture of the give texture id.
|
||||
/// </summary>
|
||||
/// <param name="texId">The id of the render texture to find.</param>
|
||||
/// <returns>The render texture with the provided id or null if no render textrue with that id was found.</returns>
|
||||
public static Texture FindRenderTexture(int id, UInt32 texId)
|
||||
{
|
||||
// texId will be 0 if swapchain has no images.
|
||||
if (texId == 0)
|
||||
return null;
|
||||
|
||||
if (!_textureMap.TryGetValue(texId, out var renderTexture))
|
||||
{
|
||||
var objs = Resources.FindObjectsOfTypeAll<RenderTexture>();
|
||||
var name = $"XR Texture [{texId}]";
|
||||
// for (int i = 0; i < objs.Length; i++)
|
||||
// {
|
||||
// Debug.Log($"FindRenderTexture 2 objs[i]={objs[i].name}");
|
||||
|
||||
// }
|
||||
bool found = false;
|
||||
foreach (var rt in objs)
|
||||
{
|
||||
if (rt.name == name)
|
||||
{
|
||||
renderTexture = rt;
|
||||
_textureMap[texId] = rt;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderTexture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the render texture of the layer id.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer.</param>
|
||||
/// <returns>The render texture with the provided id or null if no render textrue with that id was found.</returns>
|
||||
public static Texture FindRenderTexture(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
UInt32 texId = Pxr_CompositorLayersCreateOrGetRenderTextureId(layerInfo.Id);
|
||||
return FindRenderTexture(layerInfo.Id, texId);
|
||||
}
|
||||
|
||||
public static Texture CreateExternalTexture(int id, int width, int height, bool isCube)
|
||||
{
|
||||
int imageIndex = 0;
|
||||
PXR_Plugin.Render.UPxr_GetLayerNextImageIndexByRender(id, ref imageIndex);
|
||||
|
||||
var cacheKey = ValueTuple.Create(id, imageIndex);
|
||||
if (_textureCache.TryGetValue(cacheKey, out var cachedTexture))
|
||||
{
|
||||
return cachedTexture;
|
||||
}
|
||||
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
PXR_Plugin.Render.UPxr_GetLayerImagePtr(id, (EyeType)0, imageIndex, ref ptr);
|
||||
if (IntPtr.Zero == ptr)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture id={id}, _textureMap, imageIndex={imageIndex}, IntPtr.Zero == ptr");
|
||||
return null;
|
||||
}
|
||||
|
||||
Texture nativeTexture;
|
||||
|
||||
if (isCube)
|
||||
{
|
||||
nativeTexture = Cubemap.CreateExternalTexture(width, TextureFormat.RGBA32, false, ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
nativeTexture = Texture2D.CreateExternalTexture(width, height, TextureFormat.RGBA32, false, true, ptr);
|
||||
}
|
||||
if (nativeTexture == null)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture id={id}, _textureMap, imageIndex={imageIndex}, nativeTexture == null");
|
||||
}
|
||||
if (nativeTexture != null)
|
||||
{
|
||||
nativeTexture.name = $"{id}+{imageIndex}";
|
||||
_textureCache[cacheKey] = nativeTexture;
|
||||
}
|
||||
Debug.Log($"WriteToRenderTexture id={id}, imageIndex={imageIndex}, cacheKey={cacheKey}, ptr={ptr}");
|
||||
return nativeTexture;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handles transfering texture data to a render texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The source texture that will be written into the provided render texture.</param>
|
||||
/// <param name="renderTexture">The render texture that will be written to.</param>
|
||||
public static void WriteToRenderTexture(int id, Texture sourceTextures, Texture nativeTexture, bool isCube)
|
||||
{
|
||||
if (sourceTextures == null)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture sourceTextures == null!");
|
||||
return;
|
||||
}
|
||||
|
||||
nativeTexture = CreateExternalTexture(id, sourceTextures.width, sourceTextures.height, isCube);
|
||||
if (nativeTexture == null)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture 11 id={id} nativeTexture == null");
|
||||
return;
|
||||
}
|
||||
int eyeCount = 1;
|
||||
for (int i = 0; i < eyeCount; i++)
|
||||
{
|
||||
if (isCube && null == sourceTextures as Cubemap)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture 11 id={id} isCube && null == sourceTextures as Cubemap");
|
||||
return;
|
||||
}
|
||||
|
||||
int faceCount = isCube ? 6:1;
|
||||
for (int f = 0; f < faceCount; f++)
|
||||
{
|
||||
if (QualitySettings.activeColorSpace == ColorSpace.Gamma && sourceTextures != null)
|
||||
{
|
||||
Graphics.CopyTexture(sourceTextures, f, 0, nativeTexture, f, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderTextureDescriptor rtDes = new RenderTextureDescriptor((int)sourceTextures.width, (int)sourceTextures.height, RenderTextureFormat.ARGB32, 0);
|
||||
rtDes.msaaSamples = 1;
|
||||
rtDes.useMipMap = true;
|
||||
rtDes.autoGenerateMips = false;
|
||||
rtDes.sRGB = true;
|
||||
|
||||
RenderTexture renderTexture = RenderTexture.GetTemporary(rtDes);
|
||||
|
||||
if (!renderTexture.IsCreated())
|
||||
{
|
||||
renderTexture.Create();
|
||||
}
|
||||
renderTexture.DiscardContents();
|
||||
|
||||
if (isCube)
|
||||
{
|
||||
if (cubeM == null)
|
||||
{
|
||||
Debug.Log($"WriteToRenderTexture id={id}, cubeM , f={f}, cubeM == null");
|
||||
cubeM = new Material(Shader.Find("PXR_SDK/PXR_CubemapBlit"));
|
||||
}
|
||||
cubeM.SetInt("_d", f);
|
||||
Graphics.Blit(sourceTextures, renderTexture, cubeM);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (textureM == null)
|
||||
{
|
||||
Debug.Log($"WriteToRenderTexture id={id}, textureM, textureM == null");
|
||||
textureM = new Material(Shader.Find("PXR_SDK/PXR_Texture2DBlit"));
|
||||
}
|
||||
textureM.mainTexture = renderTexture;
|
||||
textureM.SetPass(0);
|
||||
//textureM.SetInt("_premultiply", isPremultipliedAlpha ? 1 : 0);
|
||||
Graphics.Blit(sourceTextures, renderTexture);
|
||||
}
|
||||
Graphics.CopyTexture(renderTexture, 0, 0, nativeTexture, f, 0);
|
||||
RenderTexture.ReleaseTemporary(renderTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the correct XR Textures for rendering and blit the layer textures.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer.</param>
|
||||
/// <param name="texture">The source texture that will be written into the provided render texture.</param>
|
||||
/// <param name="renderTexture">The render texture that will be searched for and written to.
|
||||
/// Will be null if no render texture can be found for the provided layerInfo object.</param>
|
||||
/// <returns>True if a render texture was found and written to, false if the provided texture is null or if no render texture was found for the provided layerInfo object.</returns>
|
||||
public static bool FindAndWriteToRenderTexture(CompositionLayerManager.LayerInfo layerInfo, Texture texture, out Texture renderTexture, bool isCube)
|
||||
{
|
||||
if (texture == null)
|
||||
{
|
||||
Debug.Log($"FindAndWriteToRenderTexture texture == null");
|
||||
renderTexture = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
renderTexture = FindRenderTexture(layerInfo);
|
||||
WriteToRenderTexture(layerInfo.Id, texture, renderTexture, isCube);
|
||||
return renderTexture != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add native layer structs to the <c>endFrameInfo</c> struct inside the UnityPXR_ lib - for custom layer type support
|
||||
/// </summary>
|
||||
/// <param name="layers">Pointer to the native array of currently active composition layers.</param>
|
||||
/// <param name="orders">Pointer to the native array of order values for the currently active composition layers.</param>
|
||||
/// <param name="count">Indicates the size of the layers and orders arrays.</param>
|
||||
/// <param name="layerByteSize">Indicates the size in bytes of a single element of the given array of composition layers.</param>
|
||||
/// <remarks>Layers sent must all be of the same type.Demonstrated in the PXR_CustomLayerHandler class.</remarks>
|
||||
public static unsafe void AddActiveLayersToEndFrame(void* layers, void* orders, int count, int layerByteSize)
|
||||
{
|
||||
IntPtr ptrLayers = new IntPtr(layers);
|
||||
IntPtr ptrOrders = new IntPtr(orders);
|
||||
Pxr_CompositorLayersAddActiveLayers(layers, orders, count, layerByteSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the Surface object for Android External Surface support (Android only).
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <returns>Pointer to the android surface object.</returns>
|
||||
public static System.IntPtr GetLayerAndroidSurfaceObject(int layerId)
|
||||
{
|
||||
IntPtr surfaceObject = IntPtr.Zero;
|
||||
if (Pxr_CompositorLayersGetLayerAndroidSurfaceObject(layerId, ref surfaceObject))
|
||||
{
|
||||
return surfaceObject;
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an array of extensions to be attached to the native default compostion layer.
|
||||
/// </summary>
|
||||
/// <param name="extensions">Pointer to the array of extensions to attach to the default compostion layer.</param>
|
||||
/// <remarks>Currently only called by the PXR_DefautLayer class.</remarks>
|
||||
public static unsafe void SetDefaultSceneLayerExtensions(void* extensions)
|
||||
{
|
||||
// IntPtr ptr = new IntPtr(extensions);
|
||||
// ext_composition_layers_SetDefaultSceneLayerExtensions(extensions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends what flags are to be added to the native default compostion layer.
|
||||
/// </summary>
|
||||
/// <param name="flags">Flags to be added to the native default compostion layer.</param>
|
||||
/// <remarks>Currently only called by the PXR_DefautLayer class.</remarks>
|
||||
public static unsafe void SetDefaultLayerFlags(XrCompositionLayerFlags flags)
|
||||
{
|
||||
// ext_composition_layers_SetDefaultSceneLayerFlags(flags);
|
||||
}
|
||||
|
||||
const string LibraryName = "PxrPlatform";
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern UInt32 Pxr_CompositorLayersCreateOrGetRenderTextureId(int id); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static extern bool Pxr_CompositorLayersCreateOrGetStereoRenderTextureIds(int id, out UInt32 leftId, out UInt32 rightId); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void Pxr_CompositorLayersCreateSwapchain(int id, XrSwapchainCreateInfo createInfo, [MarshalAs(UnmanagedType.I1)]bool isExternalSurface = false, SwapchainCallbackDelegate callback = null); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void Pxr_CompositorLayersCreateStereoSwapchain(int id, XrSwapchainCreateInfo createInfo, StereoSwapchainCallbackDelegate callback = null); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void Pxr_CompositorLayersReleaseSwapchain(int id); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern unsafe void Pxr_CompositorLayersAddActiveLayers(void* layers, void* orders, int count, int size); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static extern bool Pxr_CompositorLayersGetLayerAndroidSurfaceObject(int layerId, ref IntPtr surfaceObject); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern unsafe void ext_composition_layers_SetDefaultSceneLayerExtensions(void* extensions);
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void ext_composition_layers_SetDefaultSceneLayerFlags(XrCompositionLayerFlags flags);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50cb351d62257144eabbecc94c61adef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,300 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
//Default PXR_ Composition Layer - Quad Layer support
|
||||
internal class PXR_QuadLayer : PXR_CustomLayerHandler<XrCompositionLayerQuad>
|
||||
{
|
||||
protected override bool CreateSwapchain(CompositionLayerManager.LayerInfo layer, out SwapchainCreateInfo swapchainCreateInfo)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var texturesExtension = layer.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture == null)
|
||||
goto default;
|
||||
|
||||
var xrCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = PXR_LayerUtility.GetDefaultColorFormat(),
|
||||
SampleCount = 1,
|
||||
Width = (uint)texturesExtension.LeftTexture.width,
|
||||
Height = (uint)texturesExtension.LeftTexture.height,
|
||||
FaceCount = 1,
|
||||
ArraySize = 1,
|
||||
MipCount = (uint)texturesExtension.LeftTexture.mipmapCount,
|
||||
};
|
||||
|
||||
swapchainCreateInfo = new SwapchainCreateInfo(xrCreateInfo, isExternalSurface: false);
|
||||
return true;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
var xrCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = 0,
|
||||
SampleCount = 0,
|
||||
Width = (uint)texturesExtension.Resolution.x,
|
||||
Height = (uint)texturesExtension.Resolution.y,
|
||||
FaceCount = 0,
|
||||
ArraySize = 0,
|
||||
MipCount = 0,
|
||||
};
|
||||
|
||||
swapchainCreateInfo = new SwapchainCreateInfo(xrCreateInfo, isExternalSurface: true);
|
||||
return true;
|
||||
#else
|
||||
goto default;
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool CreateNativeLayer(CompositionLayerManager.LayerInfo layer, SwapchainCreatedOutput swapchainOutput, out XrCompositionLayerQuad nativeLayer)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var texturesExtension = layer.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
{
|
||||
nativeLayer = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = layer.Layer.LayerData as QuadLayerData;
|
||||
var transform = layer.Layer.GetComponent<Transform>();
|
||||
int subImageWidth = 0;
|
||||
int subImageHeight = 0;
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
subImageWidth = texturesExtension.LeftTexture.width;
|
||||
subImageHeight = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
subImageWidth = (int)texturesExtension.Resolution.x;
|
||||
subImageHeight = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var correctedSize = texturesExtension.CropToAspect ?
|
||||
FixAspectRatio(data, transform, subImageWidth, subImageHeight) :
|
||||
data.GetScaledSize(transform.lossyScale);
|
||||
|
||||
nativeLayer = new XrCompositionLayerQuad()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_COMPOSITION_LAYER_QUAD,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Layer),
|
||||
LayerFlags = data.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha,
|
||||
Space = PXR_LayerUtility.GetCurrentAppSpace(),
|
||||
EyeVisibility = 0,
|
||||
SubImage = new XrSwapchainSubImage()
|
||||
{
|
||||
Swapchain = swapchainOutput.handle,
|
||||
ImageRect = new XrRect2Di()
|
||||
{
|
||||
Offset = new XrOffset2Di() { X = 0, Y = 0 },
|
||||
Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = subImageWidth,
|
||||
Height = subImageHeight
|
||||
}
|
||||
},
|
||||
ImageArrayIndex = 0
|
||||
},
|
||||
Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation),
|
||||
Size = new XrExtent2Df()
|
||||
{
|
||||
width = correctedSize.x,
|
||||
height = correctedSize.y
|
||||
}
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerQuad nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
return false;
|
||||
|
||||
var data = layerInfo.Layer.LayerData as QuadLayerData;
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
nativeLayer.Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
|
||||
int subImageWidth = 0;
|
||||
int subImageHeight = 0;
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
subImageWidth = texturesExtension.LeftTexture.width;
|
||||
subImageHeight = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
subImageWidth = (int)texturesExtension.Resolution.x;
|
||||
subImageHeight = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nativeLayer.SubImage.ImageRect.Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = subImageWidth,
|
||||
Height = subImageHeight
|
||||
};
|
||||
|
||||
var correctedSize = texturesExtension.CropToAspect ?
|
||||
FixAspectRatio(data, transform, subImageWidth, subImageHeight) :
|
||||
data.GetScaledSize(transform.lossyScale);
|
||||
nativeLayer.Size = new XrExtent2Df()
|
||||
{
|
||||
width = correctedSize.x,
|
||||
height = correctedSize.y
|
||||
};
|
||||
|
||||
unsafe
|
||||
{
|
||||
nativeLayer.Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerQuad nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
return false;
|
||||
|
||||
var data = layerInfo.Layer.LayerData as QuadLayerData;
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
nativeLayer.Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
|
||||
if (texturesExtension.CustomRects)
|
||||
{
|
||||
int subImageWidth = 0;
|
||||
int subImageHeight = 0;
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
subImageWidth = texturesExtension.LeftTexture.width;
|
||||
subImageHeight = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
subImageWidth = (int)texturesExtension.Resolution.x;
|
||||
subImageHeight = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nativeLayer.SubImage.ImageRect = new XrRect2Di()
|
||||
{
|
||||
Offset = new XrOffset2Di()
|
||||
{
|
||||
X = (int)(subImageWidth * texturesExtension.LeftEyeSourceRect.x),
|
||||
Y = (int)(subImageHeight * texturesExtension.LeftEyeSourceRect.y)
|
||||
},
|
||||
|
||||
Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = (int)(subImageWidth * texturesExtension.LeftEyeSourceRect.width),
|
||||
Height = (int)(subImageHeight * texturesExtension.LeftEyeSourceRect.height)
|
||||
}
|
||||
};
|
||||
|
||||
var currentPosition = PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position;
|
||||
var correctedSize = texturesExtension.CropToAspect ?
|
||||
FixAspectRatio(data, transform, subImageWidth, subImageHeight) :
|
||||
data.GetScaledSize(transform.lossyScale);
|
||||
|
||||
float transformedX = currentPosition.x + (((texturesExtension.LeftEyeDestinationRect.x + (0.5f * texturesExtension.LeftEyeDestinationRect.width) - 0.5f)) * correctedSize.x);
|
||||
float transformedY = currentPosition.y + (((texturesExtension.LeftEyeDestinationRect.y + (0.5f * texturesExtension.LeftEyeDestinationRect.height) - 0.5f)) * (-1.0f * correctedSize.y));
|
||||
nativeLayer.Pose = new XrPosef(new Vector3(transformedX, transformedY, currentPosition.z), PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
nativeLayer.Size = new XrExtent2Df()
|
||||
{
|
||||
width = correctedSize.x * texturesExtension.LeftEyeDestinationRect.width,
|
||||
height = correctedSize.y * texturesExtension.LeftEyeDestinationRect.height
|
||||
};
|
||||
}
|
||||
|
||||
return base.ActiveNativeLayer(layerInfo, ref nativeLayer);
|
||||
}
|
||||
|
||||
static Vector2 FixAspectRatio(QuadLayerData data, Transform transform, int texWidth, int texHeight)
|
||||
{
|
||||
var requestedSize = data.GetScaledSize(transform.lossyScale);
|
||||
float reqSizeRatio = (float)requestedSize.x / (float)requestedSize.y;
|
||||
float texRatio = (float)texWidth / (float)texHeight;
|
||||
if (reqSizeRatio > texRatio)
|
||||
{
|
||||
// too wide
|
||||
requestedSize.x = requestedSize.y * texRatio;
|
||||
}
|
||||
else if (reqSizeRatio < texRatio)
|
||||
{
|
||||
// too narrow
|
||||
requestedSize.y = requestedSize.x / texRatio;
|
||||
}
|
||||
return requestedSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5e1a0709a0c74345b2e0408bec5348c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
/// <summary>
|
||||
/// PXR_ Utility Class contains helper methods that any script can use.
|
||||
/// </summary>
|
||||
public static class PXR_Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes the inverse of the given pose.
|
||||
/// </summary>
|
||||
private static Pose Inverse(Pose p)
|
||||
{
|
||||
Pose ret;
|
||||
ret.rotation = Quaternion.Inverse(p.rotation);
|
||||
ret.position = ret.rotation * -p.position;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recalculate object position and rotation from tracking-space to world-space, for use cases like teleporting.
|
||||
/// </summary>
|
||||
/// <param name="t">original transform of the object in the scene, typically obtained by gameObject.transform</param>
|
||||
/// <param name="camera">camera the calculation is based on, normally it is the main camera</param>
|
||||
/// <returns>the recalculated pose <see cref="UnityEngine.Pose"/> in world-space.</returns>
|
||||
public static Pose ComputePoseToWorldSpace(Transform t, Camera camera)
|
||||
{
|
||||
if (camera == null)
|
||||
return default;
|
||||
|
||||
Transform cameraTransform = camera.transform;
|
||||
Pose headPose = new Pose(cameraTransform.localPosition, cameraTransform.localRotation);
|
||||
Pose camPose = new Pose(cameraTransform.position, cameraTransform.rotation);
|
||||
Pose transformPose = new Pose(t.position, t.rotation);
|
||||
|
||||
Pose headSpacePose = transformPose.GetTransformedBy(Inverse(camPose));
|
||||
return headSpacePose.GetTransformedBy(headPose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the current session is in the focused state.
|
||||
/// See <a href="https://registry.khronos.org/PXR_/specs/1.0/html/xrspec.html#session-states">XR_SESSION_STATE_FOCUSED.</a> for reference.
|
||||
/// </summary>
|
||||
public static bool IsSessionFocused => Internal_IsSessionFocused();
|
||||
/// <summary>
|
||||
/// Returns the change of user presence, such as when the user has taken off or put on an XR headset.
|
||||
/// If the system does not support user presence sensing, runtime assumes that the user is always present and IsUserPresent always returns True.
|
||||
/// If the system supports the sensing of user presence, returns true when detected the presence of a user and returns false when detected the absence of a user.
|
||||
/// See <a href="https://registry.khronos.org/PXR_/specs/1.0/html/xrspec.html#XR_EXT_user_presence">XR_EXT_user_presence.</a> for reference.
|
||||
/// </summary>
|
||||
public static bool IsUserPresent => Internal_GetUserPresence();
|
||||
|
||||
private const string LibraryName = "PxrPlatform";
|
||||
|
||||
[DllImport(LibraryName, EntryPoint = "NativeConfig_IsSessionFocused")]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static extern bool Internal_IsSessionFocused();
|
||||
|
||||
[DllImport(LibraryName, EntryPoint = "NativeConfig_GetUserPresence")]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static extern bool Internal_GetUserPresence();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5fe75684f72312e4187498fd4db6f5ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebb628dede9d3e54ab6eb81df63d0495
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db96a9bfa8f934f8f8ca1cc2c403131c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.
|
||||
*******************************************************************************/
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public interface IPXR_PanelManager
|
||||
{
|
||||
public void Init();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51ecdd7b01226401883e934738179aca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22ec8844704ed4d4b87cb33d0962fcc4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c33f4710ca73400aa4ead29cfe05d8c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,125 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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;
|
||||
using System;
|
||||
// using UnityEngine.InputSystem.XR;
|
||||
using UnityEngine.XR.Interaction.Toolkit;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_DeviceManager : MonoBehaviour
|
||||
{
|
||||
public static PXR_DeviceManager Instance { get; private set; }
|
||||
private InputDevice rightHandDevice;
|
||||
private InputDevice leftHandDevice;
|
||||
private XRController rightHandController;
|
||||
private XRController leftHandController;
|
||||
public Transform RightHand => rightHandController.transform;
|
||||
public Transform LeftHand => leftHandController.transform;
|
||||
|
||||
public Action OnAButtonPress;
|
||||
public Action OnBButtonPress;
|
||||
public Action OnXButtonPress;
|
||||
public Action OnYButtonPress;
|
||||
public Action OnAButtonRelease;
|
||||
public Action OnBButtonRelease;
|
||||
public Action OnXButtonRelease;
|
||||
public Action OnYButtonRelease;
|
||||
public Action OnLeftGripButtonPress;
|
||||
public Action OnLeftTriggerButtonPress;
|
||||
public Action OnRightGripButtonPress;
|
||||
public Action OnRightTriggerButtonPress;
|
||||
public Action OnLeftGripButtonRelease;
|
||||
public Action OnLeftTriggerButtonRelease;
|
||||
public Action OnRightGripButtonRelease;
|
||||
public Action OnRightTriggerButtonRelease;
|
||||
private bool previousRightPrimaryButtonPress;
|
||||
private bool previousLeftPrimaryButtonPress;
|
||||
private bool previousRightSecondaryButtonPress;
|
||||
private bool previousLeftSecondaryButtonPress;
|
||||
private bool previousRightGripButtonPress;
|
||||
private bool previousLeftGripButtonPress;
|
||||
private bool previousRightTriggerButtonPress;
|
||||
private bool previousLeftTriggerButtonPress;
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null)
|
||||
{
|
||||
Debug.LogError($"The singleton has multiple instances!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(Instance);
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
void Start()
|
||||
{
|
||||
leftHandDevice = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
|
||||
rightHandDevice = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
|
||||
XRController[] xrControllers = FindObjectsOfType<XRController>();
|
||||
foreach (XRController controller in xrControllers){
|
||||
if (controller.controllerNode == XRNode.LeftHand){
|
||||
leftHandController = controller;
|
||||
}
|
||||
if (controller.controllerNode == XRNode.RightHand){
|
||||
rightHandController = controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleRightController(bool state){
|
||||
rightHandController.modelParent.gameObject.SetActive(state);
|
||||
}
|
||||
private void ButtonHandler(bool currentState,ref bool previousState,in Action OnPressed,in Action OnReleased)
|
||||
{
|
||||
if (currentState && !previousState)
|
||||
{
|
||||
OnPressed?.Invoke();
|
||||
}
|
||||
if (!currentState && previousState)
|
||||
{
|
||||
OnReleased?.Invoke();
|
||||
}
|
||||
previousState = currentState;
|
||||
}
|
||||
void Update()
|
||||
{
|
||||
|
||||
rightHandDevice.TryGetFeatureValue(CommonUsages.primaryButton, out bool isRightPrimaryButtonPress);
|
||||
ButtonHandler(isRightPrimaryButtonPress,ref previousRightPrimaryButtonPress, OnAButtonPress, OnAButtonRelease);
|
||||
|
||||
rightHandDevice.TryGetFeatureValue(CommonUsages.secondaryButton, out bool isRightSecondaryButtonPress);
|
||||
ButtonHandler(isRightSecondaryButtonPress,ref previousRightSecondaryButtonPress, OnBButtonPress, OnBButtonRelease);
|
||||
|
||||
rightHandDevice.TryGetFeatureValue(CommonUsages.gripButton, out bool isRightGripButtonPress);
|
||||
ButtonHandler(isRightGripButtonPress,ref previousRightGripButtonPress, OnRightGripButtonPress, OnRightGripButtonRelease);
|
||||
|
||||
rightHandDevice.TryGetFeatureValue(CommonUsages.triggerButton, out bool isRightTriggerButtonPress);
|
||||
ButtonHandler(isRightTriggerButtonPress,ref previousRightTriggerButtonPress, OnRightTriggerButtonPress, OnRightTriggerButtonRelease);
|
||||
|
||||
leftHandDevice.TryGetFeatureValue(CommonUsages.primaryButton, out bool isLeftPrimaryButtonPress);
|
||||
ButtonHandler(isLeftPrimaryButtonPress,ref previousLeftPrimaryButtonPress, OnXButtonPress, OnXButtonRelease);
|
||||
|
||||
leftHandDevice.TryGetFeatureValue(CommonUsages.secondaryButton, out bool isLeftSecondaryButtonPress);
|
||||
ButtonHandler(isLeftSecondaryButtonPress,ref previousLeftSecondaryButtonPress, OnYButtonPress, OnYButtonRelease);
|
||||
|
||||
leftHandDevice.TryGetFeatureValue(CommonUsages.gripButton, out bool isLeftGripButtonPress);
|
||||
ButtonHandler(isLeftGripButtonPress,ref previousLeftGripButtonPress, OnLeftGripButtonPress, OnLeftGripButtonRelease);
|
||||
|
||||
leftHandDevice.TryGetFeatureValue(CommonUsages.triggerButton, out bool isLeftTriggerButtonPress);
|
||||
ButtonHandler(isLeftTriggerButtonPress,ref previousLeftTriggerButtonPress, OnLeftTriggerButtonPress, OnLeftTriggerButtonRelease);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d3a4e4bf576cc4998a8d2b5a8b5a3399
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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 UnityEditor;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_PicoDebuggerManager : MonoBehaviour
|
||||
{
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void OnBeforeSceneLoadRuntimeMethod()
|
||||
{
|
||||
var config = Resources.Load<PXR_PicoDebuggerSO>("PXR_PicoDebuggerSO");
|
||||
if(config.isOpen){
|
||||
AddPrefab();
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddPrefab()
|
||||
{
|
||||
GameObject prefab = Resources.Load<GameObject>("PXR_PICODebugger");
|
||||
if (prefab != null)
|
||||
{
|
||||
Instantiate(prefab, Vector3.zero, Quaternion.identity);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Prefab not found in Resources folder.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d17c5f4e4f16443f6958bd26b26f24c5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ab97bca604e54c99a2273f6e8533286
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,100 @@
|
||||
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
|
||||
[CreateAssetMenu(fileName = "MainConfig", menuName = "ScriptableObjects / PXR_PicoDebuggerSO", order = 1)]
|
||||
public class PXR_PicoDebuggerSO : ScriptableObject
|
||||
{
|
||||
private static PXR_PicoDebuggerSO _instance;
|
||||
public static PXR_PicoDebuggerSO Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
GetAsset(out PXR_PicoDebuggerSO picoDebuggerSO, "PXR_PicoDebuggerSO");
|
||||
_instance = picoDebuggerSO;
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
[Header("default")]
|
||||
public bool isOpen;
|
||||
public LauncherButton debuggerLauncherButton;
|
||||
public StartPosiion startPosition;
|
||||
[Header("console")]
|
||||
[Range(500,1000)]public int maxInfoCount;
|
||||
[Header("tools")]
|
||||
public LauncherButton rulerClearButton;
|
||||
internal static void GetAsset<T>(out T asset, string name) where T : PXR_PicoDebuggerSO
|
||||
{
|
||||
asset = null;
|
||||
#if UNITY_EDITOR
|
||||
string path = GetPath(name);
|
||||
asset = AssetDatabase.LoadAssetAtPath(path, typeof(T)) as T;
|
||||
|
||||
if (asset == null )
|
||||
{
|
||||
asset = ScriptableObject.CreateInstance<T>();
|
||||
AssetDatabase.CreateAsset(asset, path);
|
||||
}
|
||||
#else
|
||||
asset = Resources.Load<T>(name);
|
||||
#endif
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
internal static string GetPath(string name)
|
||||
{
|
||||
string resourcesPath = Path.Combine(Application.dataPath, "Resources");
|
||||
if (!Directory.Exists(resourcesPath))
|
||||
{
|
||||
Directory.CreateDirectory(resourcesPath);
|
||||
}
|
||||
string assetPath = Path.GetRelativePath(Application.dataPath, Path.GetFullPath(Path.Combine(resourcesPath, $"{name}.asset")));
|
||||
// Unity's AssetDatabase path requires a slash before "Assets"
|
||||
return "Assets/" + assetPath.Replace('\\', '/');
|
||||
}
|
||||
|
||||
public void AddToPreloadedAssets()
|
||||
{
|
||||
var preloadedAssets = PlayerSettings.GetPreloadedAssets().ToList();
|
||||
|
||||
if (!preloadedAssets.Contains(this))
|
||||
{
|
||||
preloadedAssets.Add(this);
|
||||
PlayerSettings.SetPreloadedAssets(preloadedAssets.ToArray());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if UNITY_EDITOR
|
||||
public static PXR_PicoDebuggerSO GetSerializedObject(string path)
|
||||
{
|
||||
var config = AssetDatabase.LoadAssetAtPath<PXR_PicoDebuggerSO>(path);
|
||||
if (config == null)
|
||||
{
|
||||
Debug.LogError("Failed to load PXR_PicoDebuggerSO at path: " + path);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d84923cab4d03452a8a3b80e3386b9b4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0b5ff6f3ba0942d79f41538d7d76c76
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.EventSystems;
|
||||
using UnityEngine.Events;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_CloseButton : MonoBehaviour, IPointerDownHandler
|
||||
{
|
||||
public UnityEvent onButtonCLick;
|
||||
// Called when the button is selected
|
||||
public void OnPointerDown(PointerEventData args)
|
||||
{
|
||||
onButtonCLick?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fdd7d43df6054d408dc941060858139
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,105 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_DefaultButton : MonoBehaviour, IPointerDownHandler, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
bool isButtonPress = false;
|
||||
bool isButtonHover = false;
|
||||
private float hoverSpeed = 0.8f;
|
||||
[SerializeField] private Color defaultColor;
|
||||
[SerializeField] private Color hoverColor;
|
||||
[SerializeField] private GameObject panelGO;
|
||||
[SerializeField] private GameObject[] panelList;
|
||||
[SerializeField] private PXR_DefaultButton[] buttonList;
|
||||
[SerializeField] private MeshRenderer bg;
|
||||
[SerializeField] private MeshRenderer border;
|
||||
[SerializeField] private Sprite sprite;
|
||||
private float borderAlpha;
|
||||
private void Start()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
private void OnValidate()
|
||||
{
|
||||
transform.GetChild(0).GetComponent<Image>().sprite = sprite;
|
||||
}
|
||||
// Called when the button is selected
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
if (!isButtonPress)
|
||||
{
|
||||
border.material.color = hoverColor;
|
||||
bg.material.color = defaultColor;
|
||||
isButtonHover = false;
|
||||
isButtonPress = true;
|
||||
OpenPanel();
|
||||
}
|
||||
}
|
||||
private void Update()
|
||||
{
|
||||
if (isButtonHover)
|
||||
{
|
||||
bg.material.color = Color.Lerp(bg.material.color, hoverColor, hoverSpeed * Time.deltaTime);
|
||||
var borderColor = Color.Lerp(border.material.color, hoverColor, hoverSpeed * Time.deltaTime);
|
||||
borderAlpha += hoverSpeed * Time.deltaTime;
|
||||
borderColor.a = borderAlpha;
|
||||
border.material.color = borderColor;
|
||||
}
|
||||
}
|
||||
private void OpenPanel(){
|
||||
for (var i = 0; i < panelList.Length; i++)
|
||||
{
|
||||
panelList[i].SetActive(false);
|
||||
}
|
||||
for (var i = 0; i<buttonList.Length; i++){
|
||||
buttonList[i].Reset();
|
||||
}
|
||||
panelGO.SetActive(true);
|
||||
if(panelGO.TryGetComponent(out IPXR_PanelManager manager)){
|
||||
manager.Init();
|
||||
}
|
||||
}
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
if (!isButtonPress)
|
||||
{
|
||||
border.material.color = new Color(0, 0, 0, 0);
|
||||
borderAlpha = 0f;
|
||||
isButtonHover = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
if (!isButtonPress)
|
||||
{
|
||||
isButtonHover = false;
|
||||
border.material.color = new Color(0, 0, 0, 0);
|
||||
bg.material.color = defaultColor;
|
||||
}
|
||||
}
|
||||
public void Reset()
|
||||
{
|
||||
bg.material.color = defaultColor;
|
||||
border.material.color = new Color(0, 0, 0, 0);
|
||||
isButtonPress = false;
|
||||
isButtonHover = false;
|
||||
panelGO.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40cb8883085df4ffa8cca5f3a0072dfa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_DragButton : MonoBehaviour, IBeginDragHandler, IDragHandler,IEndDragHandler
|
||||
{
|
||||
private Image image;
|
||||
private Transform _camera;
|
||||
public PXR_UIController uiController;
|
||||
private Vector3 origin; // Center of a sphere
|
||||
private float radius = 5f; // Radius of a sphere
|
||||
public Transform container;
|
||||
[SerializeField]private Color defaultColor;
|
||||
[SerializeField]private Color hoverColor;
|
||||
private void Start()
|
||||
{
|
||||
_camera = Camera.main.transform;
|
||||
image = GetComponent<Image>();
|
||||
}
|
||||
private void UpdateTransformPosition(PointerEventData eventData)
|
||||
{
|
||||
// Gets the position and direction of the controller
|
||||
Vector3 controllerPosition = eventData.pointerCurrentRaycast.worldPosition;
|
||||
|
||||
// Calculate the point at which the ray intersects the sphere
|
||||
Vector3 sphereCenterToController = controllerPosition - origin;
|
||||
Vector3 intersectionPoint = origin + sphereCenterToController.normalized * radius;
|
||||
Vector3 intersectionDirection = (intersectionPoint - origin).normalized;
|
||||
float angle = Vector3.Angle(intersectionDirection, Vector3.up);
|
||||
if (angle < 45 || angle > 135)return;
|
||||
var forward = container.position - _camera.position;
|
||||
forward.y = 0;
|
||||
image.color = Color.Lerp(image.color,hoverColor,Time.deltaTime);
|
||||
container.forward = forward;
|
||||
container.position = intersectionPoint;
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.pointerCurrentRaycast.gameObject != gameObject) return;
|
||||
origin = uiController.origin;
|
||||
radius = uiController.GetDistance();
|
||||
// Update the position when you start dragging
|
||||
UpdateTransformPosition(eventData);
|
||||
}
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.pointerCurrentRaycast.gameObject != gameObject) return;
|
||||
image.color = defaultColor;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.pointerCurrentRaycast.gameObject != gameObject) return;
|
||||
// Update position while dragging
|
||||
UpdateTransformPosition(eventData);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b3c9f458c1e945d7b07755d7c90f336
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_FolderButton : MonoBehaviour, IPointerDownHandler, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
private Image image;
|
||||
public GameObject content;
|
||||
private bool isShowContent = false;
|
||||
private float hoverSpeed = 0.5f;
|
||||
[SerializeField] private Color defaultColor = new(184, 235, 255);
|
||||
bool isButtonHover = false;
|
||||
private void Start()
|
||||
{
|
||||
image = GetComponent<Image>();
|
||||
image.color = defaultColor;
|
||||
}
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
// text.color = Color.red;
|
||||
isShowContent = !isShowContent;
|
||||
content.SetActive(isShowContent);
|
||||
image.transform.Rotate(0, 0, 180);
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(content.transform.parent.gameObject.GetComponent<RectTransform>());
|
||||
}
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
isButtonHover = true;
|
||||
}
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
isButtonHover = false;
|
||||
image.color = defaultColor;
|
||||
}
|
||||
private void Update()
|
||||
{
|
||||
if (isButtonHover)
|
||||
{
|
||||
image.color = Color.Lerp(image.color, Color.white, hoverSpeed * Time.deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac9571667b43a4f9aabba6f70428aa17
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_LogButton : MonoBehaviour, IPointerDownHandler
|
||||
{
|
||||
public LogType type;
|
||||
[SerializeField]private Color defaultColor;
|
||||
[SerializeField]private PXR_LogManager logManager;
|
||||
[SerializeField]private Image icon;
|
||||
[SerializeField]private Text text;
|
||||
private bool isFilter = true;
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
isFilter = !isFilter;
|
||||
logManager.FilterLogs(type,isFilter);
|
||||
icon.color = isFilter?defaultColor:Color.gray;
|
||||
text.color = isFilter?defaultColor:Color.gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f54a5e3c6193443d894c8d0fffe39d3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Events;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_ToolButton : MonoBehaviour, IPointerDownHandler, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
private bool isButtonPress = false;
|
||||
private bool isButtonHover = false;
|
||||
// private float hoverSpeed = 0.8f;
|
||||
[SerializeField] private Color defaultColor;
|
||||
[SerializeField] private Color hoverColor;
|
||||
[SerializeField] private Image icon;
|
||||
public UnityEvent onButtonPressed;
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
if (!isButtonPress)
|
||||
{
|
||||
onButtonPressed?.Invoke();
|
||||
icon.color = hoverColor;
|
||||
isButtonHover = false;
|
||||
isButtonPress = true;
|
||||
}
|
||||
}
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
if (!isButtonPress)
|
||||
{
|
||||
icon.color = hoverColor;
|
||||
isButtonHover = true;
|
||||
}
|
||||
}
|
||||
public void Reset(){
|
||||
icon.color = defaultColor;
|
||||
isButtonHover = false;
|
||||
isButtonPress = false;
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
if (!isButtonPress)
|
||||
{
|
||||
isButtonHover = false;
|
||||
icon.color = defaultColor;
|
||||
}
|
||||
}
|
||||
public void CreateTool(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7bbd53e7b18d40e5a7adfa6cbd2cdab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7b0a5fb3a9ea4428b7d1096863a9bb2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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;
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class Ball : MonoBehaviour
|
||||
{
|
||||
void Update()
|
||||
{
|
||||
transform.position = Vector3.up*Mathf.Sin(Time.time)+Vector3.forward*0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3ed915b6efe14022bd4218f481ad615
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,170 @@
|
||||
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
using UnityEditor;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_Tool_Ruler : MonoBehaviour
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
[SerializeField] Material mal;
|
||||
[SerializeField] private GameObject rulerPrefab;
|
||||
[SerializeField] private Transform exitPosition;
|
||||
private Vector3 startPosition;
|
||||
private float size = 0.02f;
|
||||
private bool isStart = false;
|
||||
private GameObject ruler;
|
||||
private Text text;
|
||||
private Transform container;
|
||||
private List<GameObject> rulers = new();
|
||||
|
||||
void Start()
|
||||
{
|
||||
PXR_DeviceManager.Instance.OnRightGripButtonPress += StartMeasure;
|
||||
PXR_DeviceManager.Instance.OnRightGripButtonRelease += StopMeasure;
|
||||
var config = Resources.Load<PXR_PicoDebuggerSO>("PXR_PicoDebuggerSO");
|
||||
if(config.isOpen)
|
||||
{
|
||||
switch (config.rulerClearButton)
|
||||
{
|
||||
case LauncherButton.PressA:
|
||||
PXR_DeviceManager.Instance.OnAButtonPress += OnClearButtonPress;
|
||||
break;
|
||||
case LauncherButton.PressB:
|
||||
PXR_DeviceManager.Instance.OnBButtonPress += OnClearButtonPress;
|
||||
break;
|
||||
case LauncherButton.PressX:
|
||||
PXR_DeviceManager.Instance.OnXButtonPress += OnClearButtonPress;
|
||||
break;
|
||||
case LauncherButton.PressY:
|
||||
PXR_DeviceManager.Instance.OnYButtonPress += OnClearButtonPress;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (isStart)
|
||||
{
|
||||
GenerateRoundedRectMesh();
|
||||
}
|
||||
}
|
||||
void OnDestroy() {
|
||||
PXR_DeviceManager.Instance.OnRightGripButtonPress -= StartMeasure;
|
||||
PXR_DeviceManager.Instance.OnRightGripButtonRelease -= StopMeasure;
|
||||
var config = Resources.Load<PXR_PicoDebuggerSO>("PXR_PicoDebuggerSO");
|
||||
if(config.isOpen)
|
||||
{
|
||||
switch (config.rulerClearButton)
|
||||
{
|
||||
case LauncherButton.PressA:
|
||||
PXR_DeviceManager.Instance.OnAButtonPress -= OnClearButtonPress;
|
||||
break;
|
||||
case LauncherButton.PressB:
|
||||
PXR_DeviceManager.Instance.OnBButtonPress -= OnClearButtonPress;
|
||||
break;
|
||||
case LauncherButton.PressX:
|
||||
PXR_DeviceManager.Instance.OnXButtonPress -= OnClearButtonPress;
|
||||
break;
|
||||
case LauncherButton.PressY:
|
||||
PXR_DeviceManager.Instance.OnYButtonPress -= OnClearButtonPress;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void StartMeasure()
|
||||
{
|
||||
startPosition = exitPosition.position;
|
||||
ruler = Instantiate(rulerPrefab);
|
||||
text = ruler.GetComponentInChildren<Text>();
|
||||
container = ruler.transform.Find("Container");
|
||||
ruler.SetActive(true);
|
||||
isStart = true;
|
||||
rulers.Add(ruler);
|
||||
}
|
||||
private void StopMeasure()
|
||||
{
|
||||
isStart = false;
|
||||
}
|
||||
private void OnClearButtonPress(){
|
||||
StopMeasure();
|
||||
for (var i = 0; i < rulers.Count; i++)
|
||||
{
|
||||
Destroy(rulers[i]);
|
||||
}
|
||||
}
|
||||
private void GenerateRoundedRectMesh()
|
||||
{
|
||||
var meshFilter = ruler.GetComponent<MeshFilter>();
|
||||
meshFilter.GetComponent<MeshRenderer>().material = mal;
|
||||
Mesh mesh = new();
|
||||
meshFilter.mesh = mesh;
|
||||
List<Vector3> vertices = new();
|
||||
List<Vector2> uvs = new();
|
||||
List<int> triangles = new();
|
||||
|
||||
var dir = exitPosition.position-startPosition;
|
||||
var p0 = startPosition + exitPosition.forward * size;
|
||||
var p2 = startPosition - exitPosition.forward * size;
|
||||
var p1 = exitPosition.position + exitPosition.forward * size;
|
||||
var p3 = exitPosition.position - exitPosition.forward * size;
|
||||
|
||||
|
||||
vertices.Add(p0);
|
||||
uvs.Add(new Vector2(0, 0));
|
||||
vertices.Add(p2);
|
||||
uvs.Add(new Vector2(0, 1));
|
||||
triangles.Add(0);
|
||||
triangles.Add(2);
|
||||
triangles.Add(1);
|
||||
triangles.Add(0);
|
||||
triangles.Add(1);
|
||||
triangles.Add(2);
|
||||
|
||||
vertices.Add(p1);
|
||||
uvs.Add(new Vector2(1, 0));
|
||||
vertices.Add(p3);
|
||||
uvs.Add(new Vector2(1, 1));
|
||||
triangles.Add(1);
|
||||
triangles.Add(2);
|
||||
triangles.Add(3);
|
||||
triangles.Add(2);
|
||||
triangles.Add(1);
|
||||
triangles.Add(3);
|
||||
text.text = string.Format("{0:0.000}", dir.magnitude);
|
||||
|
||||
|
||||
mesh.SetVertices(vertices);
|
||||
mesh.SetUVs(0,uvs);
|
||||
mesh.SetIndices(triangles, MeshTopology.Triangles, 0);
|
||||
|
||||
mesh.RecalculateBounds();
|
||||
mesh.RecalculateNormals();
|
||||
|
||||
var normal = Vector3.Cross(p2 - p0, p1 - p0);
|
||||
|
||||
container.transform.position = startPosition+ dir*0.5f +(exitPosition.forward - normal) * size;
|
||||
container.transform.forward = normal;
|
||||
meshFilter.GetComponent<MeshRenderer>().material.SetFloat("_MeshLength", dir.magnitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8170ef5f852c443dd99dabc390a11a7c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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 UnityEngine;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_Tool_TimerController : MonoBehaviour
|
||||
{
|
||||
private readonly float delayTime = 0.17f;
|
||||
[SerializeField] private Animator anim;
|
||||
private bool isTurnOn = false;
|
||||
private bool isLock = true;
|
||||
|
||||
void Start()
|
||||
{
|
||||
PXR_DeviceManager.Instance.OnRightGripButtonPress += CutDown;
|
||||
StartCoroutine(Delay(Open));
|
||||
}
|
||||
void OnDestroy()
|
||||
{
|
||||
PXR_DeviceManager.Instance.OnRightGripButtonPress -= CutDown;
|
||||
}
|
||||
private void CutDown()
|
||||
{
|
||||
if (isLock) return;
|
||||
isTurnOn = !isTurnOn;
|
||||
anim.SetBool("TurnOn", isTurnOn);
|
||||
StartCoroutine(Delay(Open));
|
||||
if (isTurnOn)
|
||||
{
|
||||
StartCoroutine(Delay(TimePause));
|
||||
}
|
||||
else
|
||||
{
|
||||
Time.timeScale = 1f;
|
||||
}
|
||||
isLock = true;
|
||||
}
|
||||
private IEnumerator Delay(Action action)
|
||||
{
|
||||
yield return new WaitForSeconds(delayTime);
|
||||
action();
|
||||
}
|
||||
private void Open()
|
||||
{
|
||||
isLock = false;
|
||||
}
|
||||
private void TimePause()
|
||||
{
|
||||
Time.timeScale = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfd6818b7d6a84c20ae13afbdc7c1af9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10fdeff64c0134bbe95d1939a54eea37
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d08d4a0636fd64c698e3b13b89847379
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_UIController : MonoBehaviour
|
||||
{
|
||||
public static PXR_UIController Instance { get; private set; }
|
||||
public PXR_PicoDebuggerSO config;
|
||||
[HideInInspector] public Vector3 origin;
|
||||
private Transform _camera;
|
||||
private float distance;
|
||||
private StartPosiion state;
|
||||
public void Awake()
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
config = Resources.Load<PXR_PicoDebuggerSO>("PXR_PicoDebuggerSO");
|
||||
}
|
||||
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
Init();
|
||||
}
|
||||
private void Init()
|
||||
{
|
||||
_camera = Camera.main.transform;
|
||||
state = config.startPosition;
|
||||
distance = GetDistance();
|
||||
}
|
||||
public float GetDistance()
|
||||
{
|
||||
return state switch
|
||||
{
|
||||
StartPosiion.Far => 3f,
|
||||
StartPosiion.Medium => 2f,
|
||||
StartPosiion.Near => 1f,
|
||||
_ => 2f,
|
||||
};
|
||||
}
|
||||
private void OnEnable()
|
||||
{
|
||||
ResetTransform();
|
||||
}
|
||||
// Update is called once per frame
|
||||
private void ResetTransform()
|
||||
{
|
||||
origin = _camera.position;
|
||||
transform.position = origin + distance * _camera.transform.forward ;
|
||||
transform.forward = transform.position - origin;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 442a798e1fcc34e479becec159b8aaf7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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 UnityEditor;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_UIManager : MonoBehaviour
|
||||
{
|
||||
public PXR_PicoDebuggerSO config;
|
||||
public PXR_UIController uiController;
|
||||
private GameObject _controller = null;
|
||||
private void Start()
|
||||
{
|
||||
config = Resources.Load<PXR_PicoDebuggerSO>("PXR_PicoDebuggerSO");
|
||||
uiController = Resources.Load<GameObject>("PXR_DebuggerPanel").GetComponent<PXR_UIController>();
|
||||
if(config.isOpen)
|
||||
{
|
||||
switch (config.debuggerLauncherButton)
|
||||
{
|
||||
case LauncherButton.PressA:
|
||||
PXR_DeviceManager.Instance.OnAButtonPress += OnStartButtonPress;
|
||||
break;
|
||||
case LauncherButton.PressB:
|
||||
PXR_DeviceManager.Instance.OnBButtonPress += OnStartButtonPress;
|
||||
break;
|
||||
case LauncherButton.PressX:
|
||||
PXR_DeviceManager.Instance.OnXButtonPress += OnStartButtonPress;
|
||||
break;
|
||||
case LauncherButton.PressY:
|
||||
PXR_DeviceManager.Instance.OnYButtonPress += OnStartButtonPress;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void OnStartButtonPress(){
|
||||
ToggleController();
|
||||
}
|
||||
private void ToggleController(){
|
||||
if(_controller == null){
|
||||
_controller = Instantiate(uiController.gameObject);
|
||||
}else{
|
||||
_controller.SetActive(!_controller.gameObject.activeSelf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16f20e8e0453b4ff8a0517178b2117ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f68a863322194d27a20f7360a9deb30
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,77 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_InspectorItem : MonoBehaviour, IPointerDownHandler
|
||||
{
|
||||
public Text text;
|
||||
private bool isShowChildren = false;
|
||||
private bool hasChild = false;
|
||||
private string icon => hasChild?(isShowChildren?"- ":"+ "):"";
|
||||
private string nodeName;
|
||||
private GameObject target;
|
||||
public void SetTitle(){
|
||||
text.text = icon + nodeName;
|
||||
}
|
||||
public void Init(Transform item)
|
||||
{
|
||||
target = item.gameObject;
|
||||
nodeName = item.name;
|
||||
if(item.childCount > 0){
|
||||
hasChild = true;
|
||||
TraverseChild(item);
|
||||
}
|
||||
SetTitle();
|
||||
}
|
||||
public void AddItem(Transform item)
|
||||
{
|
||||
var go = Instantiate(PXR_InspectorManager.Instance.inspectItem, transform);
|
||||
if (go.TryGetComponent(out PXR_InspectorItem inspectItem))
|
||||
{
|
||||
inspectItem.Init(item);
|
||||
inspectItem.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
public void TraverseChild(Transform current)
|
||||
{
|
||||
for (int i = 0; i < current.childCount; i++)
|
||||
{
|
||||
// Debug.Log($"TraverseChild: {current.GetChild(i).name}");
|
||||
AddItem(current.GetChild(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
isShowChildren = !isShowChildren;
|
||||
// LayoutRebuilder.ForceRebuildLayoutImmediate(gameObject.GetComponent<RectTransform>());
|
||||
for (int i = 0; i < transform.childCount; i++)
|
||||
{
|
||||
// Debug.Log($"TraverseChild: {transform.GetChild(i).name}");
|
||||
transform.GetChild(i).gameObject.SetActive(isShowChildren);
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(transform.GetChild(i).GetComponent<RectTransform>());
|
||||
}
|
||||
var root = transform;
|
||||
while(root.TryGetComponent(out PXR_InspectorItem _)){
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(root.GetComponent<RectTransform>());
|
||||
root = root.parent;
|
||||
}
|
||||
SetTitle();
|
||||
PXR_InspectorManager.Instance.SetTransformInfo(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb8065e0c6c0d426490ad712bc1ce594
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,90 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_InspectorManager : MonoBehaviour, IPXR_PanelManager
|
||||
{
|
||||
public static PXR_InspectorManager Instance;
|
||||
private void Awake(){
|
||||
if(Instance == null){
|
||||
Instance = this;
|
||||
}
|
||||
}
|
||||
public GameObject inspectItem;
|
||||
public Transform content;
|
||||
public Text positionText;
|
||||
public Text rotationText;
|
||||
public Text scaleText;
|
||||
public GameObject transformInfoNode;
|
||||
private Transform target;
|
||||
void Update(){
|
||||
ShowTransformInfo();
|
||||
}
|
||||
private void ClearAllChildren(){
|
||||
int childCount = content.childCount;
|
||||
for (int i = childCount - 1; i >= 0; i--)
|
||||
{
|
||||
DestroyImmediate(content.GetChild(i).gameObject);
|
||||
}
|
||||
}
|
||||
public void CreateInspector()
|
||||
{
|
||||
GenerateInspectorTree();
|
||||
}
|
||||
public void Init(){
|
||||
CreateInspector();
|
||||
}
|
||||
public void Reset(){
|
||||
for (int i = 0; i < content.childCount; i++)
|
||||
{
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(content.GetChild(i).GetComponent<RectTransform>());
|
||||
}
|
||||
}
|
||||
public void SetTransformInfo(GameObject target){
|
||||
this.target = target.transform;
|
||||
transformInfoNode.SetActive(true);
|
||||
ShowTransformInfo();
|
||||
}
|
||||
public void Refresh(){
|
||||
ClearAllChildren();
|
||||
GenerateInspectorTree();
|
||||
}
|
||||
private void GenerateInspectorTree(){
|
||||
GameObject[] rootObjects = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
|
||||
// 遍历所有根GameObject
|
||||
foreach (GameObject obj in rootObjects)
|
||||
{
|
||||
if(!obj.TryGetComponent<PXR_UIController>(out _) && !obj.TryGetComponent<PXR_UIManager>(out _) && obj.activeSelf){
|
||||
var go = Instantiate(inspectItem, content);
|
||||
if(go.TryGetComponent(out PXR_InspectorItem item)){
|
||||
item.Init(obj.transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reset();
|
||||
}
|
||||
private void ShowTransformInfo(){
|
||||
if(target != null){
|
||||
positionText.text = $"x:{target.position.x} y:{target.position.y} z:{target.position.z}";
|
||||
rotationText.text = $"x:{target.eulerAngles.x} y:{target.eulerAngles.y} z:{target.eulerAngles.z} ";
|
||||
scaleText.text = $"x:{target.localScale.x} y:{target.localScale.y} z:{target.localScale.z}";
|
||||
}else{
|
||||
transformInfoNode.SetActive(false);
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11c28c50e274e400ababdc4ef40ca441
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e6248719bac74cbd9b183852eea9d1b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,124 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_LogManager : MonoBehaviour, IPXR_PanelManager
|
||||
{
|
||||
public List<GameObject> infoList = new();
|
||||
public List<GameObject> warningList = new();
|
||||
public List<GameObject> errorList = new();
|
||||
public GameObject errorMessage;
|
||||
public GameObject warningMessage;
|
||||
public GameObject infoMessage;
|
||||
public Text infoText;
|
||||
public Text warningText;
|
||||
public Text errorText;
|
||||
public Transform messageContainer;
|
||||
private int ListCount => infoList.Count + warningList.Count + errorList.Count;
|
||||
private void AddMessage(string title, string content, LogType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LogType.Error:
|
||||
CreateMessage(title, content, type, errorList, errorMessage);
|
||||
break;
|
||||
case LogType.Assert:
|
||||
break;
|
||||
case LogType.Warning:
|
||||
CreateMessage(title, content, type, warningList, warningMessage);
|
||||
break;
|
||||
case LogType.Log:
|
||||
CreateMessage(title, content, type, infoList, infoMessage);
|
||||
break;
|
||||
case LogType.Exception:
|
||||
break;
|
||||
}
|
||||
RecaculateLogCount();
|
||||
}
|
||||
private void CreateMessage(string title, string content, in LogType type, in List<GameObject> list, in GameObject template)
|
||||
{
|
||||
var msg = Instantiate(template, messageContainer).GetComponent<PXR_MessageController>();
|
||||
msg.Init(title, content);
|
||||
list.Add(msg.gameObject);
|
||||
}
|
||||
private void RecaculateLogCount()
|
||||
{
|
||||
infoText.text = infoList.Count.ToString();
|
||||
warningText.text = warningList.Count.ToString();
|
||||
errorText.text = errorList.Count.ToString();
|
||||
}
|
||||
public void FilterLogs(LogType type, bool isFilter)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LogType.Error:
|
||||
ToggleLogs(errorList, isFilter);
|
||||
break;
|
||||
case LogType.Assert:
|
||||
break;
|
||||
case LogType.Warning:
|
||||
ToggleLogs(warningList, isFilter);
|
||||
break;
|
||||
case LogType.Log:
|
||||
ToggleLogs(infoList, isFilter);
|
||||
break;
|
||||
case LogType.Exception:
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void ToggleLogs(in List<GameObject> list, bool status)
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
item.SetActive(status);
|
||||
}
|
||||
}
|
||||
void Start()
|
||||
{
|
||||
Application.logMessageReceived += OnLogMessageReceived;
|
||||
}
|
||||
private void OnLogMessageReceived(string logString, string stackTrace, LogType type)
|
||||
{
|
||||
if (PXR_UIController.Instance.config.maxInfoCount > ListCount)
|
||||
{
|
||||
AddMessage(logString, stackTrace, type);
|
||||
}
|
||||
}
|
||||
void OnEnable()
|
||||
{
|
||||
foreach (var item in infoList)
|
||||
{
|
||||
item.GetComponent<PXR_MessageController>().Reset();
|
||||
}
|
||||
foreach (var item in warningList)
|
||||
{
|
||||
item.GetComponent<PXR_MessageController>().Reset();
|
||||
}
|
||||
foreach (var item in errorList)
|
||||
{
|
||||
item.GetComponent<PXR_MessageController>().Reset();
|
||||
}
|
||||
}
|
||||
public void Init(){
|
||||
|
||||
}
|
||||
void OnDestroy()
|
||||
{
|
||||
Application.logMessageReceived -= OnLogMessageReceived;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37649a96b60c841e08f9e20ab7f59dfd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_MessageController : MonoBehaviour
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
public Text title;
|
||||
public Text content;
|
||||
private readonly string widthMark = "------------------------------------------------------------------";
|
||||
private readonly int maxLength = 47;
|
||||
public void Init(string title, string content)
|
||||
{
|
||||
string timestamp = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
string finalTitle = $"{timestamp}: {title}";
|
||||
|
||||
TextGenerator generator = new();
|
||||
var settings = this.title.GetGenerationSettings(this.title.gameObject.GetComponent<RectTransform>().rect.size);
|
||||
var targetWidth = generator.GetPreferredWidth(widthMark, settings);
|
||||
var currentWidth = generator.GetPreferredWidth(finalTitle, settings);
|
||||
if (targetWidth < currentWidth)
|
||||
{
|
||||
finalTitle = title[..(maxLength - 3)];
|
||||
currentWidth = generator.GetPreferredWidth(finalTitle, settings);
|
||||
while (targetWidth < currentWidth)
|
||||
{
|
||||
finalTitle = title[..(title.Length - 1)];
|
||||
currentWidth = generator.GetPreferredWidth(finalTitle, settings);
|
||||
}
|
||||
finalTitle += "...";
|
||||
}
|
||||
|
||||
this.title.text = finalTitle;
|
||||
this.content.text = $"{title}\n{content}";
|
||||
Reset();
|
||||
}
|
||||
public void Reset()
|
||||
{
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(gameObject.GetComponent<RectTransform>());
|
||||
}
|
||||
public void ToggleContent()
|
||||
{
|
||||
content.gameObject.SetActive(!content.gameObject.activeSelf);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 291fd7bf1abf04b508dbc7b5609dfe15
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_BGWithTouch : MonoBehaviour, IPointerMoveHandler, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
private Material material;
|
||||
private Vector4 v;
|
||||
private void Start()
|
||||
{
|
||||
var rect = GetComponent<RectTransform>().rect;
|
||||
material = new Material(GetComponent<Image>().material);
|
||||
v.z = rect.width;
|
||||
v.w = rect.height;
|
||||
material.SetVector("_TouchPos",v);
|
||||
GetComponent<Image>().material = material;
|
||||
}
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
}
|
||||
private void Update()
|
||||
{
|
||||
|
||||
}
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnPointerMove(PointerEventData eventData)
|
||||
{
|
||||
Vector3 offset = eventData.pointerCurrentRaycast.worldPosition-transform.position;
|
||||
v.x= offset.x/v.z;
|
||||
v.y= offset.y/v.w;
|
||||
material.SetVector("_TouchPos", v);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd02573a0bbc5408986e781f77a6ba20
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.
|
||||
*******************************************************************************/
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_DebuggerConst{
|
||||
public static string sdkPackageName = "Packages/com.unity.xr.picoxr/";
|
||||
public static string sdkRootName = "com.unity.xr.picoxr/";
|
||||
}
|
||||
public enum LauncherButton
|
||||
{
|
||||
PressA,
|
||||
PressB,
|
||||
PressX,
|
||||
PressY,
|
||||
}
|
||||
public enum StartPosiion
|
||||
{
|
||||
Far,
|
||||
Near ,
|
||||
Medium,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa10506b4fc074aeb944e1bbed5f5632
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 680b341d8fe6a4b7582f09429fefc6ef
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.UI;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
public class PXR_ToolManager : MonoBehaviour
|
||||
{
|
||||
private GameObject currentTool;
|
||||
public PXR_ToolButton[] toolButtons;
|
||||
public void CreateTool(GameObject tool){
|
||||
ResetButtons();
|
||||
if(currentTool != null){
|
||||
Destroy(currentTool);
|
||||
}
|
||||
currentTool = Instantiate(tool,PXR_DeviceManager.Instance.RightHand);
|
||||
PXR_DeviceManager.Instance.ToggleRightController(false);
|
||||
}
|
||||
private void ResetButtons(){
|
||||
foreach (var button in toolButtons){
|
||||
button.Reset();
|
||||
}
|
||||
PXR_DeviceManager.Instance.ToggleRightController(true);
|
||||
}
|
||||
public void DeleteTool(){
|
||||
ResetButtons();
|
||||
Destroy(currentTool);
|
||||
currentTool = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34aff3ee7450748cba11e0267142e5ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 992f1fd0351f3469cb00e97521173d91
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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;
|
||||
using UnityEditor;
|
||||
using System.IO;
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
namespace Unity.XR.PXR.Debugger
|
||||
{
|
||||
[RequireComponent(typeof(MeshFilter))]
|
||||
[RequireComponent(typeof(MeshRenderer))]
|
||||
public class RoundedRectMesh : MonoBehaviour
|
||||
{
|
||||
[SerializeField]public float width = 1f;
|
||||
[SerializeField]public float height = 1f;
|
||||
[SerializeField]public float depth = 1f;
|
||||
[SerializeField]public float cornerRadius = 0.2f;
|
||||
[SerializeField]public bool[] corner = { true, true, true, true };
|
||||
|
||||
[SerializeField]public int cornerSegments = 10; // The number of subdivisions of rounded corners
|
||||
[SerializeField]public string saveName = "CustomMesh"; // Customize the save name
|
||||
private MeshFilter meshFilter;
|
||||
private bool isInit = false;
|
||||
void OnValidate()
|
||||
{
|
||||
Init();
|
||||
GenerateRoundedRectMesh();
|
||||
}
|
||||
private void Init(){
|
||||
if(!isInit){
|
||||
meshFilter = GetComponent<MeshFilter>();
|
||||
isInit = true;
|
||||
}
|
||||
}
|
||||
public static List<Vector3> CreateRoundedRectPath(Vector3 center, float width, float height, float radius, bool[] corners, int cornerSegments)
|
||||
{
|
||||
List<Vector3> path = new();
|
||||
var halfWidth = width *0.5f;
|
||||
var halfHeight = height *0.5f;
|
||||
// Check whether the radius of the fillet is reasonable
|
||||
radius = Mathf.Min(radius, width *0.5f, height *0.5f);
|
||||
|
||||
// Define the fillet subdivision Angle
|
||||
float angleStep = 90f / (float)cornerSegments;
|
||||
|
||||
Vector2[] cornerCentersOffset = new Vector2[]
|
||||
{
|
||||
new(-1,1), // 左上 Left Top
|
||||
new (1, 1), // 右上 Right Top
|
||||
new (1, -1), // 右下 Right Bottom
|
||||
new (-1, -1) // 左下 Left Bottom
|
||||
};
|
||||
|
||||
// Generate the path of the rounded rectangle
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
bool isCorner = corners[i];
|
||||
var delta = isCorner ? radius : 0;
|
||||
Vector3 currentCornerCenter = center + new Vector3((halfWidth - delta) * cornerCentersOffset[i].x, (halfHeight - delta) * cornerCentersOffset[i].y, 0);
|
||||
|
||||
if (isCorner)
|
||||
{
|
||||
// Add arcs
|
||||
for (int j = 0; j <= cornerSegments; j++)
|
||||
{
|
||||
float angle = (i * 90 + angleStep * j) * Mathf.Deg2Rad;
|
||||
path.Add(currentCornerCenter + new Vector3(-Mathf.Cos(angle) * radius, Mathf.Sin(angle) * radius, 0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add a right Angle
|
||||
path.Add(currentCornerCenter);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private void GenerateRoundedRectMesh()
|
||||
{
|
||||
Mesh mesh = new();
|
||||
meshFilter.mesh = mesh;
|
||||
cornerRadius = Mathf.Clamp(cornerRadius, 0, Mathf.Min(width, height) *0.5f);
|
||||
|
||||
List<Vector3> path = CreateRoundedRectPath(transform.position, width, height, cornerRadius, corner, cornerSegments);
|
||||
List<Vector3> vertices = new();
|
||||
List<int> triangles = new();
|
||||
var count = path.Count;
|
||||
var doubleCount = count * 2;
|
||||
var firstIndex = 0;
|
||||
for (var j = 0; j < count; j++)
|
||||
{
|
||||
vertices.Add(path[j]);
|
||||
vertices.Add(path[j] + Vector3.forward * depth);
|
||||
triangles.Add(firstIndex);
|
||||
triangles.Add((firstIndex + 2) % doubleCount );
|
||||
triangles.Add(doubleCount);
|
||||
|
||||
triangles.Add((firstIndex + 1) % doubleCount);
|
||||
triangles.Add(doubleCount + 1);
|
||||
triangles.Add((firstIndex + 3) % doubleCount );
|
||||
firstIndex += 2;
|
||||
}
|
||||
vertices.Add(transform.position);
|
||||
vertices.Add(transform.position + Vector3.forward * depth);
|
||||
var currentCount = vertices.Count;
|
||||
firstIndex = 0;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
vertices.Add(path[i]);
|
||||
vertices.Add(path[i] + Vector3.forward * depth);
|
||||
triangles.Add(firstIndex + currentCount);
|
||||
triangles.Add((firstIndex + 1) % doubleCount + currentCount);
|
||||
triangles.Add((firstIndex + 3) % doubleCount + currentCount);
|
||||
triangles.Add(firstIndex + currentCount);
|
||||
triangles.Add((firstIndex + 3) % doubleCount + currentCount);
|
||||
triangles.Add((firstIndex + 2) % doubleCount + currentCount);
|
||||
firstIndex += 2;
|
||||
}
|
||||
|
||||
|
||||
mesh.SetVertices(vertices);
|
||||
mesh.SetIndices(triangles, MeshTopology.Triangles, 0);
|
||||
|
||||
mesh.RecalculateBounds();
|
||||
mesh.RecalculateNormals();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 075c06be15abc425cac804ea189da615
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f15fcfc3734242f4c84983e6956fd7e5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,252 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#if UNITY_INPUT_SYSTEM
|
||||
using UnityEngine.Scripting;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.XR;
|
||||
using UnityEngine.InputSystem.Controls;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
|
||||
namespace Unity.XR.PXR.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// A PICO Headset
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
[InputControlLayout(displayName = "PICO HMD")]
|
||||
public class PXR_HMD : XRHMD
|
||||
{
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public ButtonControl userPresence { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "devicetrackingstate" })]
|
||||
public new IntegerControl trackingState { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "deviceistracked" })]
|
||||
public new ButtonControl isTracked { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public new Vector3Control devicePosition { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public new QuaternionControl deviceRotation { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control deviceVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control deviceAngularVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control deviceAcceleration { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control deviceAngularAcceleration { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public new Vector3Control leftEyePosition { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public new QuaternionControl leftEyeRotation { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control leftEyeVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control leftEyeAngularVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control leftEyeAcceleration { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control leftEyeAngularAcceleration { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public new Vector3Control rightEyePosition { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public new QuaternionControl rightEyeRotation { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control rightEyeVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control rightEyeAngularVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control rightEyeAcceleration { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control rightEyeAngularAcceleration { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public new Vector3Control centerEyePosition { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public new QuaternionControl centerEyeRotation { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control centerEyeVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control centerEyeAngularVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control centerEyeAcceleration { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public Vector3Control centerEyeAngularAcceleration { get; private set; }
|
||||
|
||||
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
|
||||
userPresence = GetChildControl<ButtonControl>("userPresence");
|
||||
trackingState = GetChildControl<IntegerControl>("trackingState");
|
||||
isTracked = GetChildControl<ButtonControl>("isTracked");
|
||||
devicePosition = GetChildControl<Vector3Control>("devicePosition");
|
||||
deviceRotation = GetChildControl<QuaternionControl>("deviceRotation");
|
||||
deviceVelocity = GetChildControl<Vector3Control>("deviceVelocity");
|
||||
deviceAngularVelocity = GetChildControl<Vector3Control>("deviceAngularVelocity");
|
||||
deviceAcceleration = GetChildControl<Vector3Control>("deviceAcceleration");
|
||||
deviceAngularAcceleration = GetChildControl<Vector3Control>("deviceAngularAcceleration");
|
||||
leftEyePosition = GetChildControl<Vector3Control>("leftEyePosition");
|
||||
leftEyeRotation = GetChildControl<QuaternionControl>("leftEyeRotation");
|
||||
leftEyeVelocity = GetChildControl<Vector3Control>("leftEyeVelocity");
|
||||
leftEyeAngularVelocity = GetChildControl<Vector3Control>("leftEyeAngularVelocity");
|
||||
leftEyeAcceleration = GetChildControl<Vector3Control>("leftEyeAcceleration");
|
||||
leftEyeAngularAcceleration = GetChildControl<Vector3Control>("leftEyeAngularAcceleration");
|
||||
rightEyePosition = GetChildControl<Vector3Control>("rightEyePosition");
|
||||
rightEyeRotation = GetChildControl<QuaternionControl>("rightEyeRotation");
|
||||
rightEyeVelocity = GetChildControl<Vector3Control>("rightEyeVelocity");
|
||||
rightEyeAngularVelocity = GetChildControl<Vector3Control>("rightEyeAngularVelocity");
|
||||
rightEyeAcceleration = GetChildControl<Vector3Control>("rightEyeAcceleration");
|
||||
rightEyeAngularAcceleration = GetChildControl<Vector3Control>("rightEyeAngularAcceleration");
|
||||
centerEyePosition = GetChildControl<Vector3Control>("centerEyePosition");
|
||||
centerEyeRotation = GetChildControl<QuaternionControl>("centerEyeRotation");
|
||||
centerEyeVelocity = GetChildControl<Vector3Control>("centerEyeVelocity");
|
||||
centerEyeAngularVelocity = GetChildControl<Vector3Control>("centerEyeAngularVelocity");
|
||||
centerEyeAcceleration = GetChildControl<Vector3Control>("centerEyeAcceleration");
|
||||
centerEyeAngularAcceleration = GetChildControl<Vector3Control>("centerEyeAngularAcceleration");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A PICO Controller
|
||||
/// </summary>
|
||||
[Preserve]
|
||||
[InputControlLayout(displayName = "PICO Controller", commonUsages = new[] { "LeftHand", "RightHand" })]
|
||||
public class PXR_Controller : XRControllerWithRumble
|
||||
{
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "Primary2DAxis", "Thumbstick" })]
|
||||
public Vector2Control thumbstick { get; private set; }
|
||||
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public AxisControl trigger { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl]
|
||||
public AxisControl grip { get; private set; }
|
||||
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "A", "X" })]
|
||||
public ButtonControl primaryButton { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "B", "Y" })]
|
||||
public ButtonControl secondaryButton { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "GripButton", "GripPress" })]
|
||||
public ButtonControl gripPressed { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "Primary2DAxisClick", "ThumbstickPress" })]
|
||||
public ButtonControl thumbstickClicked { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "ATouch", "XTouch" })]
|
||||
public ButtonControl primaryTouched { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "BTouch", "YTouch" })]
|
||||
public ButtonControl secondaryTouched { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "TriggerTouch" })]
|
||||
public ButtonControl triggerTouched { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "TriggerPress" })]
|
||||
public ButtonControl triggerPressed { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "Menu" })]
|
||||
public ButtonControl menu { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "ThumbstickTouch" })]
|
||||
public ButtonControl thumbstickTouched { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "ThumbRestTouch" })]
|
||||
public ButtonControl thumbRestTouched { get; private set; }
|
||||
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "controllerTrackingState" })]
|
||||
public new IntegerControl trackingState { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "ControllerIsTracked" })]
|
||||
public new ButtonControl isTracked { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "controllerPosition" })]
|
||||
public new Vector3Control devicePosition { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "controllerRotation" })]
|
||||
public new QuaternionControl deviceRotation { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "controllerVelocity" })]
|
||||
public Vector3Control deviceVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "controllerAngularVelocity" })]
|
||||
public Vector3Control deviceAngularVelocity { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "controllerAcceleration" })]
|
||||
public Vector3Control deviceAcceleration { get; private set; }
|
||||
[Preserve]
|
||||
[InputControl(aliases = new[] { "controllerAngularAcceleration" })]
|
||||
public Vector3Control deviceAngularAcceleration { get; private set; }
|
||||
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
|
||||
thumbstick = GetChildControl<Vector2Control>("thumbstick");
|
||||
trigger = GetChildControl<AxisControl>("trigger");
|
||||
triggerTouched = GetChildControl<ButtonControl>("triggerTouched");
|
||||
grip = GetChildControl<AxisControl>("grip");
|
||||
|
||||
primaryButton = GetChildControl<ButtonControl>("primaryButton");
|
||||
secondaryButton = GetChildControl<ButtonControl>("secondaryButton");
|
||||
gripPressed = GetChildControl<ButtonControl>("gripPressed");
|
||||
thumbstickClicked = GetChildControl<ButtonControl>("thumbstickClicked");
|
||||
primaryTouched = GetChildControl<ButtonControl>("primaryTouched");
|
||||
secondaryTouched = GetChildControl<ButtonControl>("secondaryTouched");
|
||||
thumbstickTouched = GetChildControl<ButtonControl>("thumbstickTouched");
|
||||
triggerPressed = GetChildControl<ButtonControl>("triggerPressed");
|
||||
|
||||
trackingState = GetChildControl<IntegerControl>("trackingState");
|
||||
isTracked = GetChildControl<ButtonControl>("isTracked");
|
||||
devicePosition = GetChildControl<Vector3Control>("devicePosition");
|
||||
deviceRotation = GetChildControl<QuaternionControl>("deviceRotation");
|
||||
deviceVelocity = GetChildControl<Vector3Control>("deviceVelocity");
|
||||
deviceAngularVelocity = GetChildControl<Vector3Control>("deviceAngularVelocity");
|
||||
deviceAcceleration = GetChildControl<Vector3Control>("deviceAcceleration");
|
||||
deviceAngularAcceleration = GetChildControl<Vector3Control>("deviceAngularAcceleration");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user