Init
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Collections;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.NativeTypes;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
public enum SystemDisplayFrequency
|
||||
{
|
||||
Default,
|
||||
RefreshRate72 = 72,
|
||||
RefreshRate90 = 90,
|
||||
RefreshRate120 = 120,
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "OpenXR Display Refresh Rate",
|
||||
Hidden = false,
|
||||
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
|
||||
Company = "PICO",
|
||||
OpenxrExtensionStrings = extensionString,
|
||||
Version = PXR_Constants.SDKVersion,
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
public class DisplayRefreshRateFeature : OpenXRFeatureBase
|
||||
{
|
||||
public const string featureId = "com.pico.openxr.feature.refreshrate";
|
||||
public const string extensionString = "XR_FB_display_refresh_rate";
|
||||
public static bool isExtensionEnable => OpenXRRuntime.IsExtensionEnabled(extensionString);
|
||||
|
||||
public override string GetExtensionString()
|
||||
{
|
||||
return extensionString;
|
||||
}
|
||||
|
||||
public override void SessionCreate(ulong xrSessionId)
|
||||
{
|
||||
PXR_OpenXRProjectSetting projectConfig = PXR_OpenXRProjectSetting.GetProjectConfig();
|
||||
if (projectConfig.displayFrequency != SystemDisplayFrequency.Default)
|
||||
{
|
||||
SetDisplayRefreshRate(projectConfig.displayFrequency);
|
||||
}
|
||||
}
|
||||
public static bool SetDisplayRefreshRate(SystemDisplayFrequency DisplayFrequency)
|
||||
{
|
||||
PLog.e(extensionString,$"SetDisplayRefreshRate:{DisplayFrequency}");
|
||||
float rate = 0;
|
||||
switch (DisplayFrequency)
|
||||
{
|
||||
case SystemDisplayFrequency.Default:
|
||||
return true;
|
||||
case SystemDisplayFrequency.RefreshRate72:
|
||||
rate = 72;
|
||||
break;
|
||||
case SystemDisplayFrequency.RefreshRate90:
|
||||
rate = 90;
|
||||
break;
|
||||
case SystemDisplayFrequency.RefreshRate120:
|
||||
rate = 120;
|
||||
break;
|
||||
}
|
||||
|
||||
return SetDisplayRefreshRate(rate);
|
||||
}
|
||||
|
||||
public static bool GetDisplayRefreshRate(ref float displayRefreshRate)
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Pxr_GetDisplayRefreshRate(ref displayRefreshRate) == (int)XrResult.Success;
|
||||
}
|
||||
|
||||
public static bool SetDisplayRefreshRate(float displayRefreshRate)
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Pxr_SetDisplayRefreshRate(displayRefreshRate) == (int)XrResult.Success;
|
||||
}
|
||||
[Obsolete("Please use GetDisplayFrequenciesAvailable")]
|
||||
public static int GetDisplayRefreshRateCount()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
[Obsolete("Please use GetDisplayFrequenciesAvailable")]
|
||||
public static bool TryGetSupportedDisplayRefreshRates(
|
||||
Allocator allocator, out NativeArray<float> refreshRates)
|
||||
{
|
||||
refreshRates = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static float[] GetDisplayFrequenciesAvailable()
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
float[] configArray = { 0 };
|
||||
int configCount = 0;
|
||||
IntPtr configHandle = IntPtr.Zero;
|
||||
bool ret = false;
|
||||
ret = Pxr_GetDisplayRefreshRatesAvailable(ref configCount, ref configHandle);
|
||||
if (ret)
|
||||
{
|
||||
configArray = new float[configCount];
|
||||
Marshal.Copy(configHandle, configArray, 0, configCount);
|
||||
}
|
||||
|
||||
return configArray;
|
||||
}
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int Pxr_GetDisplayRefreshRate(ref float displayRefreshRate);
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int Pxr_SetDisplayRefreshRate(float refreshRate);
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool Pxr_GetDisplayRefreshRatesAvailable(ref int configCount, ref IntPtr configArray);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f13a1b00c8524d6495757293c2324596
|
||||
timeCreated: 1738739475
|
||||
@@ -0,0 +1,156 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using UnityEditor;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
using Unity.XR.OpenXR.Features.PICOSupport;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
|
||||
[OpenXRFeature(UiName = "OpenXR Foveation",
|
||||
BuildTargetGroups = new[] { BuildTargetGroup.Android },
|
||||
OpenxrExtensionStrings = extensionList,
|
||||
Company = "PICO",
|
||||
Version = PXR_Constants.SDKVersion,
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
|
||||
|
||||
public class FoveationFeature : OpenXRFeatureBase
|
||||
{
|
||||
public const string extensionList = "XR_FB_foveation " +
|
||||
"XR_FB_foveation_configuration " +
|
||||
"XR_FB_foveation_vulkan " +
|
||||
"XR_META_foveation_eye_tracked " +
|
||||
"XR_META_vulkan_swapchain_create_info " +
|
||||
"XR_FB_swapchain_update_state ";
|
||||
|
||||
public const string featureId = "com.pico.openxr.feature.foveation";
|
||||
private static string TAG = "FoveationFeature";
|
||||
public enum FoveatedRenderingLevel
|
||||
{
|
||||
Off = 0,
|
||||
Low = 1,
|
||||
Medium = 2,
|
||||
High = 3
|
||||
}
|
||||
public enum FoveatedRenderingMode
|
||||
{
|
||||
FixedFoveatedRendering = 0,
|
||||
EyeTrackedFoveatedRendering = 1
|
||||
}
|
||||
|
||||
private static UInt32 _foveatedRenderingLevel = 0;
|
||||
private static UInt32 _useDynamicFoveation = 0;
|
||||
public static bool isExtensionEnable => OpenXRRuntime.IsExtensionEnabled("XR_FB_foveation");
|
||||
public override string GetExtensionString()
|
||||
{
|
||||
return extensionList;
|
||||
}
|
||||
|
||||
public override void SessionCreate(ulong xrSessionId)
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
PXR_OpenXRProjectSetting projectConfig = PXR_OpenXRProjectSetting.GetProjectConfig();
|
||||
if (projectConfig.foveationEnable)
|
||||
{
|
||||
PICO_setFoveationEyeTracked(projectConfig.foveatedRenderingMode ==
|
||||
FoveatedRenderingMode.EyeTrackedFoveatedRendering);
|
||||
foveatedRenderingLevel = projectConfig.foveatedRenderingLevel;
|
||||
}
|
||||
}
|
||||
public static FoveatedRenderingLevel foveatedRenderingLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return FoveatedRenderingLevel.Off;
|
||||
}
|
||||
UInt32 level;
|
||||
FBGetFoveationLevel(out level);
|
||||
PLog.i(TAG,$" foveatedRenderingLevel get if level= {level}");
|
||||
return (FoveatedRenderingLevel)level;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
PLog.e(TAG,$" foveatedRenderingLevel set if value= {value}");
|
||||
_foveatedRenderingLevel = (UInt32)value;
|
||||
FBSetFoveationLevel(xrSession, _foveatedRenderingLevel, 0.0f, _useDynamicFoveation);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool useDynamicFoveatedRendering
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
UInt32 dynamic;
|
||||
FBGetFoveationLevel(out dynamic);
|
||||
return dynamic != 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
if (value)
|
||||
_useDynamicFoveation = 1;
|
||||
else
|
||||
_useDynamicFoveation = 0;
|
||||
FBSetFoveationLevel(xrSession, _foveatedRenderingLevel, 0.0f, _useDynamicFoveation);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool supportsFoveationEyeTracked
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool supported=false;
|
||||
Pxr_GetEyeTrackingFoveationRenderingSupported(ref supported);
|
||||
return supported;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region OpenXR Plugin DLL Imports
|
||||
|
||||
[DllImport("UnityOpenXR", EntryPoint = "FBSetFoveationLevel")]
|
||||
private static extern void FBSetFoveationLevel(UInt64 session, UInt32 level, float verticalOffset, UInt32 dynamic);
|
||||
|
||||
[DllImport("UnityOpenXR", EntryPoint = "FBGetFoveationLevel")]
|
||||
private static extern void FBGetFoveationLevel(out UInt32 level);
|
||||
|
||||
[DllImport("UnityOpenXR", EntryPoint = "FBGetFoveationDynamic")]
|
||||
private static extern void FBGetFoveationDynamic(out UInt32 dynamic);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool Pxr_GetEyeTrackingFoveationRenderingSupported(ref bool supported);
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void PICO_setFoveationEyeTracked(bool value);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7137a47eb739c7a4485f1395871a6d68
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,128 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.XR.CoreUtils;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
public class LayerBase : MonoBehaviour
|
||||
{
|
||||
public static int ID = 0;
|
||||
private Transform overlayTransform;
|
||||
private Camera xrRig;
|
||||
|
||||
private Vector3 modelTranslations;
|
||||
private Quaternion modelRotations;
|
||||
private Vector3 modelScales ;
|
||||
private XROrigin cameraRig;
|
||||
private XROrigin lastcameraRig;
|
||||
public bool isXROriginChange = false;
|
||||
private float offsetY = 0;
|
||||
bool isUpdateOffsetY= false;
|
||||
private Vector3 cameraPosOri;
|
||||
private TrackingOriginModeFlags lastTrackingOriginMod = TrackingOriginModeFlags.Unknown;
|
||||
public void Awake()
|
||||
{
|
||||
ID++;
|
||||
lastcameraRig=cameraRig=FindActiveXROrigin();
|
||||
overlayTransform = GetComponent<Transform>();
|
||||
PXR_Plugin.System.RecenterSuccess+=()=>
|
||||
{
|
||||
isUpdateOffsetY = true;
|
||||
};
|
||||
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
if (overlayTransform != null)
|
||||
{
|
||||
MeshRenderer render = overlayTransform.GetComponent<MeshRenderer>();
|
||||
if (render != null)
|
||||
{
|
||||
render.enabled = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
XROrigin FindActiveXROrigin()
|
||||
{
|
||||
XROrigin[] xrOrigins = FindObjectsOfType<XROrigin>();
|
||||
foreach (XROrigin xrOrigin in xrOrigins)
|
||||
{
|
||||
if (xrOrigin.gameObject.activeInHierarchy)
|
||||
{
|
||||
return xrOrigin;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
ID--;
|
||||
}
|
||||
|
||||
public void UpdateCoords(bool isCreate = false)
|
||||
{
|
||||
if (isXROriginChange)
|
||||
{
|
||||
cameraRig=FindActiveXROrigin();
|
||||
isUpdateOffsetY=cameraRig!= lastcameraRig;
|
||||
lastcameraRig = cameraRig;
|
||||
}
|
||||
|
||||
if (isCreate)
|
||||
{
|
||||
cameraPosOri=cameraRig.transform.position;
|
||||
}
|
||||
if (isCreate||cameraRig.CurrentTrackingOriginMode != lastTrackingOriginMod ||isUpdateOffsetY)
|
||||
{
|
||||
|
||||
if (cameraRig.CurrentTrackingOriginMode == TrackingOriginModeFlags.Floor)
|
||||
{
|
||||
offsetY= cameraRig.Camera.transform.position.y;
|
||||
}
|
||||
Debug.Log("CurrentTrackingOriginMode:"+cameraRig.CurrentTrackingOriginMode+" offsetY:"+offsetY);
|
||||
isUpdateOffsetY=false;
|
||||
lastTrackingOriginMod = cameraRig.CurrentTrackingOriginMode;
|
||||
}
|
||||
|
||||
|
||||
var worldInsightModel = GetTransformMatrixForPassthrough(overlayTransform.localToWorldMatrix);
|
||||
modelTranslations=worldInsightModel.GetPosition();
|
||||
modelRotations = worldInsightModel.rotation;
|
||||
modelScales = overlayTransform.lossyScale;
|
||||
}
|
||||
|
||||
private Matrix4x4 GetTransformMatrixForPassthrough(Matrix4x4 worldFromObj)
|
||||
{
|
||||
Matrix4x4 trackingSpaceFromWorld =
|
||||
(cameraRig != null) ? cameraRig.CameraFloorOffsetObject.transform.worldToLocalMatrix : Matrix4x4.identity;
|
||||
|
||||
return trackingSpaceFromWorld * worldFromObj;
|
||||
}
|
||||
public void GetCurrentTransform(ref GeometryInstanceTransform geometryInstanceTransform)
|
||||
{
|
||||
geometryInstanceTransform.pose.position.x = modelTranslations.x;
|
||||
geometryInstanceTransform.pose.position.y = modelTranslations.y-offsetY+ (cameraRig.CurrentTrackingOriginMode == TrackingOriginModeFlags.Floor
|
||||
? (cameraRig.transform.position.y - cameraPosOri.y)
|
||||
: 0);
|
||||
geometryInstanceTransform.pose.position.z = -modelTranslations.z;
|
||||
geometryInstanceTransform.pose.orientation.x = -modelRotations.x;
|
||||
geometryInstanceTransform.pose.orientation.y = -modelRotations.y;
|
||||
geometryInstanceTransform.pose.orientation.z = modelRotations.z;
|
||||
geometryInstanceTransform.pose.orientation.w = modelRotations.w;
|
||||
|
||||
geometryInstanceTransform.scale.x = modelScales.x;
|
||||
geometryInstanceTransform.scale.y = modelScales.y;
|
||||
geometryInstanceTransform.scale.z = 1;
|
||||
|
||||
geometryInstanceTransform.isFloor = cameraRig.CurrentTrackingOriginMode == TrackingOriginModeFlags.Floor;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d95410458cc9bf46a74d78dcba2294f
|
||||
timeCreated: 1695197751
|
||||
@@ -0,0 +1,54 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "OpenXR Composition Layer Secure Content",
|
||||
Hidden = false,
|
||||
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
|
||||
Company = "PICO",
|
||||
OpenxrExtensionStrings = extensionString,
|
||||
Version = PXR_Constants.SDKVersion,
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
public class LayerSecureContentFeature : OpenXRFeatureBase
|
||||
{
|
||||
public const string featureId = "com.pico.openxr.feature.LayerSecureContent";
|
||||
public const string extensionString = "XR_FB_composition_layer_secure_content";
|
||||
|
||||
public static bool isExtensionEnable => OpenXRRuntime.IsExtensionEnabled(extensionString);
|
||||
|
||||
public override string GetExtensionString()
|
||||
{
|
||||
return extensionString;
|
||||
}
|
||||
public override void SessionCreate(ulong xrSessionId)
|
||||
{
|
||||
PXR_OpenXRProjectSetting projectConfig = PXR_OpenXRProjectSetting.GetProjectConfig();
|
||||
if (projectConfig.useContentProtect)
|
||||
{
|
||||
SetSecureContentFlag(projectConfig.contentProtectFlags);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetSecureContentFlag(SecureContentFlag flag)
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SetSecureContentFlag((int)flag);
|
||||
}
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void SetSecureContentFlag(int state);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9496d215cb181c64c9cde2f724356e20
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,96 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
public abstract class OpenXRFeatureBase : OpenXRFeature
|
||||
{
|
||||
protected static ulong xrInstance = 0ul;
|
||||
protected static ulong xrSession = 0ul;
|
||||
protected override bool OnInstanceCreate(ulong instance)
|
||||
{
|
||||
xrInstance = instance;
|
||||
xrSession = 0ul;
|
||||
InstanceCreate(instance);
|
||||
return true;
|
||||
}
|
||||
protected override void OnSessionCreate(ulong xrSessionId)
|
||||
{
|
||||
xrSession = xrSessionId;
|
||||
base.OnSessionCreate(xrSessionId);
|
||||
SessionCreate(xrSessionId);
|
||||
}
|
||||
public bool isExtensionEnabled(string extensionUrl)
|
||||
{
|
||||
string[] exts = extensionUrl.Split(' ');
|
||||
if (exts.Length > 0)
|
||||
{
|
||||
foreach (var _ext in exts)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_ext) && !OpenXRRuntime.IsExtensionEnabled(_ext))
|
||||
{
|
||||
PLog.e("OpenXRFeatureBase", _ext + " is not enabled");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(extensionUrl) && !OpenXRRuntime.IsExtensionEnabled(extensionUrl))
|
||||
{
|
||||
PLog.e("OpenXRFeatureBase", extensionUrl + " is not enabled");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void InstanceCreate(ulong instance) {}
|
||||
|
||||
public virtual void SessionCreate(ulong xrSessionId) {}
|
||||
public abstract string GetExtensionString();
|
||||
#if UNITY_EDITOR
|
||||
protected override void GetValidationChecks(List<ValidationRule> rules, BuildTargetGroup targetGroup)
|
||||
{
|
||||
var settings = OpenXRSettings.GetSettingsForBuildTargetGroup(targetGroup);
|
||||
rules.Add(new ValidationRule(this)
|
||||
{
|
||||
message = "No PICO OpenXR Features selected.",
|
||||
checkPredicate = () =>
|
||||
{
|
||||
if (null == settings)
|
||||
return false;
|
||||
|
||||
foreach (var feature in settings.GetFeatures<OpenXRFeature>())
|
||||
{
|
||||
if (feature is OpenXRExtensions)
|
||||
{
|
||||
return feature.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
fixIt = () =>
|
||||
{
|
||||
if (null == settings)
|
||||
return ;
|
||||
var openXRExtensions = settings.GetFeature<OpenXRExtensions>();
|
||||
if (openXRExtensions != null)
|
||||
{
|
||||
openXRExtensions.enabled = true;
|
||||
}
|
||||
},
|
||||
error = true
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03de18223d234dd4914b78bf7b2ad088
|
||||
timeCreated: 1738739629
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7a3b25af74c35240b11ce66fc7614ef
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,251 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
#if AR_FOUNDATION_5||AR_FOUNDATION_6
|
||||
using UnityEngine.XR.ARSubsystems;
|
||||
#endif
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
public enum XrBodyJointSetBD
|
||||
{
|
||||
XR_BODY_JOINT_SET_DEFAULT_BD = 0, //default joint set XR_BODY_JOINT_SET_BODY_STAR_WITHOUT_ARM_BD
|
||||
XR_BODY_JOINT_SET_BODY_START_WITHOUT_ARM_BD = 1,
|
||||
XR_BODY_JOINT_SET_BODY_FULL_STAR_BD = 2
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "PICO Body Tracking",
|
||||
Hidden = false,
|
||||
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
|
||||
Company = "PICO",
|
||||
OpenxrExtensionStrings = extensionString,
|
||||
Version = PXR_Constants.SDKVersion,
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
|
||||
public class BodyTrackingFeature : OpenXRFeatureBase
|
||||
{
|
||||
public const string featureId = "com.pico.openxr.feature.PICO_BodyTracking";
|
||||
public const string extensionString = "XR_BD_body_tracking XR_PICO_body_tracking2";
|
||||
|
||||
public static bool isEnable => OpenXRRuntime.IsExtensionEnabled("XR_BD_body_tracking");
|
||||
|
||||
public override string GetExtensionString()
|
||||
{
|
||||
return extensionString;
|
||||
}
|
||||
|
||||
[Obsolete("Please use StartBodyTracking(BodyJointSet JointSet, BodyTrackingBoneLength boneLength)")]
|
||||
public static bool StartBodyTracking(XrBodyJointSetBD Mode)
|
||||
{
|
||||
if (!isEnable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BodyTrackingBoneLength boneLength=new BodyTrackingBoneLength();
|
||||
|
||||
return StartBodyTracking((BodyJointSet)Mode, boneLength)==0;
|
||||
}
|
||||
/// <summary>Starts body tracking.</summary>
|
||||
/// <param name="mode">Specifies the body tracking mode (default or high-accuracy).</param>
|
||||
/// <param name="boneLength">Specifies lengths (unit: cm) for the bones of the avatar, which is only available for the `BTM_FULL_BODY_HIGH` mode.
|
||||
/// Bones that are not set lengths for will use the default values.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// - `0`: success
|
||||
/// - `1`: failure
|
||||
/// </returns>
|
||||
public static int StartBodyTracking(BodyJointSet JointSet, BodyTrackingBoneLength boneLength)
|
||||
{
|
||||
if (!isEnable)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
BodyTrackingStartInfo startInfo = new BodyTrackingStartInfo();
|
||||
startInfo.jointSet = JointSet;
|
||||
startInfo.BoneLength = boneLength;
|
||||
|
||||
return Pxr_StartBodyTracking(ref startInfo);
|
||||
}
|
||||
/// <summary>Launches the PICO Motion Tracker app to perform calibration.
|
||||
/// - For PICO Motion Tracker (Beta), the user needs to follow the instructions on the home of the PICO Motion Tracker app to complete calibration.
|
||||
/// - For PICO Motion Tracker (Official), "single-glance calibration" will be performed. When a user has a glance at the PICO Motion Tracker on their lower legs, calibration is completed.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// - `0`: success
|
||||
/// - `1`: failure
|
||||
/// </returns>
|
||||
public static int StartMotionTrackerCalibApp()
|
||||
{
|
||||
if (!isEnable)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return Pxr_StartBodyTrackingCalibApp();
|
||||
}
|
||||
|
||||
public static bool IsBodyTrackingSupported()
|
||||
{
|
||||
if (!isEnable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool supported=false;
|
||||
Pxr_GetBodyTrackingSupported(ref supported);
|
||||
return supported;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data about the poses of body joints.
|
||||
/// </summary>
|
||||
/// <param name="predictTime">Reserved parameter, pass `0`.</param>
|
||||
/// <param name="bodyTrackerResult">Contains the data about the poses of body joints, including position, action, and more.</param>
|
||||
[Obsolete("Please use GetBodyTrackingData",true)]
|
||||
public static bool GetBodyTrackingPose(ref BodyTrackerResult bodyTrackerResult)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/// <summary>Stops body tracking.</summary>
|
||||
/// <returns>
|
||||
/// - `0`: success
|
||||
/// - `1`: failure
|
||||
/// </returns>
|
||||
public static int StopBodyTracking()
|
||||
{
|
||||
return Pxr_StopBodyTracking();
|
||||
}
|
||||
[Obsolete("Please use StopBodyTracking")]
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (!isEnable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StopBodyTracking();
|
||||
}
|
||||
|
||||
[Obsolete("Please use StartMotionTrackerCalibApp")]
|
||||
public static void OpenFitnessBandCalibrationAPP()
|
||||
{
|
||||
StartMotionTrackerCalibApp();
|
||||
}
|
||||
|
||||
/// <summary>Gets body tracking data.</summary>
|
||||
/// <param name="getInfo"> Specifies the display time and the data filtering flags.
|
||||
/// For the display time, for example, when it is set to 0.1 second, it means predicting the pose of the tracked node 0.1 seconds ahead.
|
||||
/// </param>
|
||||
/// <param name="data">Returns the array of data for all tracked nodes.</param>
|
||||
/// <returns>
|
||||
/// - `0`: success
|
||||
/// - `1`: failure
|
||||
/// </returns>
|
||||
public unsafe static int GetBodyTrackingData(ref BodyTrackingGetDataInfo getInfo, ref BodyTrackingData data)
|
||||
{
|
||||
if (!isEnable)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int val = -1;
|
||||
{
|
||||
val = Pxr_GetBodyTrackingData(ref getInfo, ref data);
|
||||
for (int i = 0; i < (int)BodyTrackerRole.ROLE_NUM; i++)
|
||||
{
|
||||
data.roleDatas[i].localPose.PosZ = -data.roleDatas[i].localPose.PosZ;
|
||||
data.roleDatas[i].localPose.RotQz = -data.roleDatas[i].localPose.RotQz;
|
||||
data.roleDatas[i].localPose.RotQw = -data.roleDatas[i].localPose.RotQw;
|
||||
data.roleDatas[i].velo[3] = -data.roleDatas[i].velo[3];
|
||||
data.roleDatas[i].acce[3] = -data.roleDatas[i].acce[3];
|
||||
data.roleDatas[i].wvelo[3] = -data.roleDatas[i].wvelo[3];
|
||||
data.roleDatas[i].wacce[3] = -data.roleDatas[i].wacce[3];
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
/// <summary>Gets the state of PICO Motion Tracker and, if any, the reason for an exception.</summary>
|
||||
/// <param name="isTracking">Indicates whether the PICO Motion Tracker is tracking normally:
|
||||
/// - `true`: is tracking
|
||||
/// - `false`: tracking lost
|
||||
/// </param>
|
||||
/// <param name="state">Returns the information about body tracking state.</param>
|
||||
/// <returns>
|
||||
/// - `0`: success
|
||||
/// - `1`: failure
|
||||
/// </returns>
|
||||
public static int GetBodyTrackingState(ref bool isTracking, ref BodyTrackingStatus state)
|
||||
{
|
||||
int val = -1;
|
||||
{
|
||||
val = Pxr_GetBodyTrackingState(ref isTracking, ref state);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
#if AR_FOUNDATION_5||AR_FOUNDATION_6
|
||||
public bool isBodyTracking=false;
|
||||
static List<XRHumanBodySubsystemDescriptor> s_HumanBodyDescriptors = new List<XRHumanBodySubsystemDescriptor>();
|
||||
protected override void OnSubsystemCreate()
|
||||
{
|
||||
base.OnSubsystemCreate();
|
||||
if (isBodyTracking)
|
||||
{
|
||||
CreateSubsystem<XRHumanBodySubsystemDescriptor, XRHumanBodySubsystem>(
|
||||
s_HumanBodyDescriptors,
|
||||
PXR_HumanBodySubsystem.k_SubsystemId);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
protected override void OnSubsystemStart()
|
||||
{
|
||||
if (isBodyTracking)
|
||||
{
|
||||
StartSubsystem<XRHumanBodySubsystem>();
|
||||
}
|
||||
}
|
||||
protected override void OnSubsystemStop()
|
||||
{
|
||||
if (isBodyTracking)
|
||||
{
|
||||
StopSubsystem<XRHumanBodySubsystem>();
|
||||
}
|
||||
}
|
||||
protected override void OnSubsystemDestroy()
|
||||
{
|
||||
if (isBodyTracking)
|
||||
{
|
||||
DestroySubsystem<XRHumanBodySubsystem>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int Pxr_StartBodyTrackingCalibApp();
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int Pxr_GetBodyTrackingSupported(ref bool supported);
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int Pxr_StartBodyTracking(ref BodyTrackingStartInfo startInfo);
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int Pxr_StopBodyTracking();
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int Pxr_GetBodyTrackingState(ref bool isTracking, ref BodyTrackingStatus state);
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int Pxr_GetBodyTrackingData(ref BodyTrackingGetDataInfo getInfo, ref BodyTrackingData data);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa772d31a64f93d49bd62d49064fee41
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "PICO Scene Capture",
|
||||
Hidden = false,
|
||||
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
|
||||
Company = "PICO",
|
||||
OpenxrExtensionStrings = extensionString,
|
||||
Version = "1.0.0",
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
public class PICOSceneCapture: OpenXRFeature
|
||||
{
|
||||
public const string featureId = "com.pico.openxr.feature.scenecapture";
|
||||
public const string extensionString = "XR_PICO_scene_capture XR_PICO_spatial_sensing XR_EXT_future";
|
||||
public static bool isEnable => OpenXRRuntime.IsExtensionEnabled("XR_PICO_scene_capture");
|
||||
protected override void OnSessionCreate(ulong xrSession)
|
||||
{
|
||||
base.OnSessionCreate(xrSession);
|
||||
PXR_Plugin.MixedReality.UPxr_CreateSceneCaptureSenseDataProvider();
|
||||
}
|
||||
|
||||
protected override void OnSessionExiting(ulong xrSession)
|
||||
{
|
||||
PXR_MixedReality.GetSenseDataProviderState(PxrSenseDataProviderType.SceneCapture, out var providerState);
|
||||
if (providerState == PxrSenseDataProviderState.Running)
|
||||
{
|
||||
PXR_MixedReality.StopSenseDataProvider(PxrSenseDataProviderType.SceneCapture);
|
||||
}
|
||||
|
||||
PXR_Plugin.MixedReality.UPxr_DestroySenseDataProvider(
|
||||
PXR_Plugin.MixedReality.UPxr_GetSenseDataProviderHandle(PxrSenseDataProviderType.SceneCapture));
|
||||
|
||||
base.OnSessionExiting(xrSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a0b5403262c64d5888bf5672e1e1f3bb
|
||||
timeCreated: 1721806849
|
||||
@@ -0,0 +1,96 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#if AR_FOUNDATION_5||AR_FOUNDATION_6
|
||||
using UnityEngine.XR.ARSubsystems;
|
||||
#endif
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "PICO Spatial Anchor",
|
||||
Hidden = false,
|
||||
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
|
||||
Company = "PICO",
|
||||
OpenxrExtensionStrings = extensionString,
|
||||
Version = "1.0.0",
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
public class PICOSpatialAnchor: OpenXRFeature
|
||||
{
|
||||
public const string featureId = "com.pico.openxr.feature.spatialanchor";
|
||||
public const string extensionString = "XR_PICO_spatial_anchor XR_PICO_spatial_sensing XR_EXT_future";
|
||||
|
||||
public static bool isEnable => OpenXRRuntime.IsExtensionEnabled("XR_PICO_spatial_anchor");
|
||||
|
||||
protected override void OnSessionCreate(ulong xrSession)
|
||||
{
|
||||
base.OnSessionCreate(xrSession);
|
||||
PXR_Plugin.MixedReality.UPxr_CreateSpatialAnchorSenseDataProvider();
|
||||
}
|
||||
protected override void OnSessionExiting(ulong xrSession)
|
||||
{
|
||||
PXR_MixedReality.GetSenseDataProviderState(PxrSenseDataProviderType.SpatialAnchor, out var providerState);
|
||||
if (providerState == PxrSenseDataProviderState.Running)
|
||||
{
|
||||
PXR_MixedReality.StopSenseDataProvider(PxrSenseDataProviderType.SpatialAnchor);
|
||||
}
|
||||
|
||||
PXR_Plugin.MixedReality.UPxr_DestroySenseDataProvider(
|
||||
PXR_Plugin.MixedReality.UPxr_GetSenseDataProviderHandle(PxrSenseDataProviderType.SpatialAnchor));
|
||||
|
||||
base.OnSessionExiting(xrSession);
|
||||
}
|
||||
|
||||
#if AR_FOUNDATION_5||AR_FOUNDATION_6
|
||||
public bool isAnchorSubsystem=false;
|
||||
static List<XRAnchorSubsystemDescriptor> anchorSubsystemDescriptors = new List<XRAnchorSubsystemDescriptor>();
|
||||
protected override void OnSubsystemCreate()
|
||||
{
|
||||
base.OnSubsystemCreate();
|
||||
if (isAnchorSubsystem)
|
||||
{
|
||||
CreateSubsystem<XRAnchorSubsystemDescriptor, XRAnchorSubsystem>(
|
||||
anchorSubsystemDescriptors,
|
||||
PXR_AnchorSubsystem.k_SubsystemId);
|
||||
}
|
||||
|
||||
}
|
||||
protected override void OnSubsystemStart()
|
||||
{
|
||||
if (isAnchorSubsystem)
|
||||
{
|
||||
StartSubsystem<XRAnchorSubsystem>();
|
||||
}
|
||||
}
|
||||
protected override void OnSubsystemStop()
|
||||
{
|
||||
if (isAnchorSubsystem)
|
||||
{
|
||||
StopSubsystem<XRAnchorSubsystem>();
|
||||
}
|
||||
}
|
||||
protected override void OnSubsystemDestroy()
|
||||
{
|
||||
if (isAnchorSubsystem)
|
||||
{
|
||||
DestroySubsystem<XRAnchorSubsystem>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8b7731b990240c0b289e41fb880787b
|
||||
timeCreated: 1721806849
|
||||
@@ -0,0 +1,72 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
// using Unity.XR.CoreUtils;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "PICO Spatial Mesh",
|
||||
Hidden = false,
|
||||
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
|
||||
Company = "PICO",
|
||||
OpenxrExtensionStrings = extensionString,
|
||||
Version = "1.0.0",
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
public class PICOSpatialMesh: OpenXRFeature
|
||||
{
|
||||
public const string featureId = "com.pico.openxr.feature.spatialmesh";
|
||||
public const string extensionString = "XR_PICO_spatial_mesh XR_PICO_spatial_sensing XR_EXT_future";
|
||||
private static List<XRMeshSubsystemDescriptor> meshSubsystemDescriptors = new List<XRMeshSubsystemDescriptor>();
|
||||
|
||||
public PxrMeshLod LOD;
|
||||
|
||||
private XRMeshSubsystem subsystem;
|
||||
public static bool isEnable => OpenXRRuntime.IsExtensionEnabled("XR_PICO_spatial_mesh");
|
||||
protected override void OnSubsystemCreate()
|
||||
{
|
||||
base.OnSubsystemCreate();
|
||||
PXR_Plugin.Pxr_SetMeshLOD(Convert.ToUInt16(LOD));
|
||||
|
||||
}
|
||||
|
||||
protected override void OnSessionCreate(ulong xrSession)
|
||||
{
|
||||
base.OnSessionCreate(xrSession);
|
||||
CreateSubsystem<XRMeshSubsystemDescriptor, XRMeshSubsystem>(meshSubsystemDescriptors, "PICO Mesh");
|
||||
}
|
||||
|
||||
protected override void OnSubsystemStop()
|
||||
{
|
||||
base.OnSubsystemStop();
|
||||
StopSubsystem<XRMeshSubsystem>();
|
||||
|
||||
}
|
||||
|
||||
protected override void OnSubsystemDestroy()
|
||||
{
|
||||
base.OnSubsystemDestroy();
|
||||
PXR_Plugin.MixedReality.UPxr_DisposeMesh();
|
||||
DestroySubsystem<XRMeshSubsystem>();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1248416ce414cd0a788c5240bec5766
|
||||
timeCreated: 1721806849
|
||||
@@ -0,0 +1,541 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Unity.XR.CoreUtils;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
#if AR_FOUNDATION_5||AR_FOUNDATION_6
|
||||
using UnityEngine.XR.ARSubsystems;
|
||||
#endif
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using UnityEngine.XR.OpenXR.Features;
|
||||
using UnityEngine.XR.OpenXR.NativeTypes;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor.XR.OpenXR.Features;
|
||||
#endif
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[OpenXRFeature(UiName = "OpenXR Passthrough",
|
||||
Hidden = false,
|
||||
BuildTargetGroups = new[] { UnityEditor.BuildTargetGroup.Android },
|
||||
Company = "PICO",
|
||||
OpenxrExtensionStrings = extensionString,
|
||||
Version = PXR_Constants.SDKVersion,
|
||||
FeatureId = featureId)]
|
||||
#endif
|
||||
public class PassthroughFeature : OpenXRFeatureBase
|
||||
{
|
||||
public const string featureId = "com.pico.openxr.feature.passthrough";
|
||||
public const string extensionString = "XR_FB_passthrough";
|
||||
public const int XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB = 256;
|
||||
private static byte[] colorData;
|
||||
private static uint Size = 0;
|
||||
private static bool isInit = false;
|
||||
private static bool isPause = false;
|
||||
private static int _enableVideoSeeThrough=-1;
|
||||
public static event Action<bool> EnableVideoSeeThroughAction;
|
||||
private static bool isRefreshRecenterSpace = false;
|
||||
public static bool isExtensionEnable => OpenXRRuntime.IsExtensionEnabled(extensionString);
|
||||
[HideInInspector]
|
||||
public static bool EnableVideoSeeThrough
|
||||
{
|
||||
get => _enableVideoSeeThrough==1;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
if (_enableVideoSeeThrough != 1)
|
||||
{
|
||||
_enableVideoSeeThrough = 1;
|
||||
EnableSeeThroughManual(value);
|
||||
|
||||
if (EnableVideoSeeThroughAction != null)
|
||||
{
|
||||
EnableVideoSeeThroughAction(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_enableVideoSeeThrough == 1)
|
||||
{
|
||||
_enableVideoSeeThrough = 0;
|
||||
EnableSeeThroughManual(value);
|
||||
|
||||
if (EnableVideoSeeThroughAction != null)
|
||||
{
|
||||
EnableVideoSeeThroughAction(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void OnSessionBegin(ulong xrSessionId)
|
||||
{
|
||||
if (!isRefreshRecenterSpace)
|
||||
{
|
||||
OpenXRSettings.RefreshRecenterSpace();
|
||||
isRefreshRecenterSpace = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetExtensionString()
|
||||
{
|
||||
return extensionString;
|
||||
}
|
||||
|
||||
public static void PassthroughStart()
|
||||
{
|
||||
passthroughStart();
|
||||
isPause = false;
|
||||
}
|
||||
|
||||
public static void PassthroughPause()
|
||||
{
|
||||
passthroughPause();
|
||||
isPause = true;
|
||||
}
|
||||
|
||||
//This interface has been changed to a private interface.
|
||||
//Please use the EnableVideoSeeThrough .
|
||||
private static bool EnableSeeThroughManual(bool value)
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isInit)
|
||||
{
|
||||
isInit = initializePassthrough();
|
||||
}
|
||||
|
||||
if (value)
|
||||
{
|
||||
createFullScreenLayer();
|
||||
if (!isPause)
|
||||
{
|
||||
passthroughStart();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
passthroughPause();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void Destroy()
|
||||
{
|
||||
if (!isExtensionEnable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Passthrough_Destroy();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
private static void AllocateColorMapData(uint size)
|
||||
{
|
||||
if (colorData != null && size != colorData.Length)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
if (colorData == null)
|
||||
{
|
||||
colorData = new byte[size];
|
||||
}
|
||||
}
|
||||
|
||||
private static void Clear()
|
||||
{
|
||||
if (colorData != null)
|
||||
{
|
||||
colorData = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteVector3ToColorMap(int colorIndex, ref Vector3 color)
|
||||
{
|
||||
for (int c = 0; c < 3; c++)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(color[c]);
|
||||
Buffer.BlockCopy(bytes, 0, colorData, colorIndex * 12 + c * 4, 4);
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteFloatToColorMap(int index, float value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
Buffer.BlockCopy(bytes, 0, colorData, index * sizeof(float), sizeof(float));
|
||||
}
|
||||
|
||||
private static void WriteColorToColorMap(int colorIndex, ref Color color)
|
||||
{
|
||||
for (int c = 0; c < 4; c++)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(color[c]);
|
||||
Buffer.BlockCopy(bytes, 0, colorData, colorIndex * 16 + c * 4, 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static unsafe void SetBrightnessContrastSaturation(ref PassthroughStyle style, float brightness = 0.0f,
|
||||
float contrast = 0.0f, float saturation = 0.0f)
|
||||
{
|
||||
style.enableColorMap = true;
|
||||
style.TextureColorMapType = PassthroughColorMapType.BrightnessContrastSaturation;
|
||||
Size = 3 * sizeof(float);
|
||||
AllocateColorMapData(Size);
|
||||
WriteFloatToColorMap(0, brightness);
|
||||
|
||||
WriteFloatToColorMap(1, contrast);
|
||||
|
||||
WriteFloatToColorMap(2, saturation);
|
||||
fixed (byte* p = colorData)
|
||||
{
|
||||
style.TextureColorMapData = (IntPtr)p;
|
||||
}
|
||||
|
||||
style.TextureColorMapDataSize = Size;
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (int i = 0; i < Size; i++)
|
||||
{
|
||||
str.Append(colorData[i]);
|
||||
}
|
||||
|
||||
Debug.Log("SetPassthroughStyle SetBrightnessContrastSaturation colorData:" + str);
|
||||
}
|
||||
|
||||
public static unsafe void SetColorMapbyMonoToMono(ref PassthroughStyle style, int[] values)
|
||||
{
|
||||
if (values.Length != XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB)
|
||||
throw new ArgumentException("Must provide exactly 256 values");
|
||||
style.enableColorMap = true;
|
||||
style.TextureColorMapType = PassthroughColorMapType.MonoToMono;
|
||||
Size = XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB * 4;
|
||||
AllocateColorMapData(Size);
|
||||
Buffer.BlockCopy(values, 0, colorData, 0, (int)Size);
|
||||
|
||||
fixed (byte* p = colorData)
|
||||
{
|
||||
style.TextureColorMapData = (IntPtr)p;
|
||||
}
|
||||
|
||||
style.TextureColorMapDataSize = Size;
|
||||
}
|
||||
|
||||
public static unsafe void SetColorMapbyMonoToRgba(ref PassthroughStyle style, Color[] values)
|
||||
{
|
||||
if (values.Length != XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB)
|
||||
throw new ArgumentException("Must provide exactly 256 colors");
|
||||
|
||||
style.TextureColorMapType = PassthroughColorMapType.MonoToRgba;
|
||||
style.enableColorMap = true;
|
||||
Size = XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB * 4 * 4;
|
||||
|
||||
AllocateColorMapData(Size);
|
||||
|
||||
for (int i = 0; i < XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB; i++)
|
||||
{
|
||||
WriteColorToColorMap(i, ref values[i]);
|
||||
}
|
||||
|
||||
fixed (byte* p = colorData)
|
||||
{
|
||||
style.TextureColorMapData = (IntPtr)p;
|
||||
}
|
||||
|
||||
style.TextureColorMapDataSize = Size;
|
||||
}
|
||||
|
||||
public static _PassthroughStyle ToPassthroughStyle(PassthroughStyle c)
|
||||
{
|
||||
_PassthroughStyle mPassthroughStyle = new _PassthroughStyle();
|
||||
mPassthroughStyle.enableEdgeColor = (uint)(c.enableEdgeColor ? 1 : 0);
|
||||
mPassthroughStyle.enableColorMap = (uint)(c.enableColorMap ? 1 : 0);
|
||||
mPassthroughStyle.TextureOpacityFactor = c.TextureOpacityFactor;
|
||||
mPassthroughStyle.TextureColorMapType = c.TextureColorMapType;
|
||||
mPassthroughStyle.TextureColorMapDataSize = c.TextureColorMapDataSize;
|
||||
mPassthroughStyle.TextureColorMapData = c.TextureColorMapData;
|
||||
mPassthroughStyle.EdgeColor = new Colorf()
|
||||
{ r = c.EdgeColor.r, g = c.EdgeColor.g, b = c.EdgeColor.b, a = c.EdgeColor.a };
|
||||
return mPassthroughStyle;
|
||||
}
|
||||
|
||||
public static void SetPassthroughStyle(PassthroughStyle style)
|
||||
{
|
||||
setPassthroughStyle(ToPassthroughStyle(style));
|
||||
}
|
||||
|
||||
public static bool IsPassthroughSupported()
|
||||
{
|
||||
return isPassthroughSupported();
|
||||
}
|
||||
|
||||
|
||||
public static unsafe bool CreateTriangleMesh(int id, Vector3[] vertices, int[] triangles,
|
||||
GeometryInstanceTransform transform)
|
||||
{
|
||||
if (vertices == null || triangles == null || vertices.Length == 0 || triangles.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isInit)
|
||||
{
|
||||
isInit = initializePassthrough();
|
||||
}
|
||||
|
||||
int vertexCount = vertices.Length;
|
||||
int triangleCount = triangles.Length;
|
||||
|
||||
Size = (uint)vertexCount * 3 * 4;
|
||||
|
||||
AllocateColorMapData(Size);
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
WriteVector3ToColorMap(i, ref vertices[i]);
|
||||
}
|
||||
|
||||
IntPtr vertexDataPtr = IntPtr.Zero;
|
||||
|
||||
fixed (byte* p = colorData)
|
||||
{
|
||||
vertexDataPtr = (IntPtr)p;
|
||||
}
|
||||
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (int i = 0; i < 3 * 4; i++)
|
||||
{
|
||||
str.Append(colorData[i]);
|
||||
}
|
||||
|
||||
Debug.Log("CreateTriangleMesh vertexDataPtr colorData:" + str);
|
||||
str.Clear();
|
||||
|
||||
Size = (uint)triangleCount * 4;
|
||||
AllocateColorMapData(Size);
|
||||
Buffer.BlockCopy(triangles, 0, colorData, 0, (int)Size);
|
||||
IntPtr triangleDataPtr = IntPtr.Zero;
|
||||
fixed (byte* p = colorData)
|
||||
{
|
||||
triangleDataPtr = (IntPtr)p;
|
||||
}
|
||||
|
||||
for (int i = 0; i < colorData.Length; i++)
|
||||
{
|
||||
str.Append(colorData[i]);
|
||||
}
|
||||
|
||||
// Debug.Log("CreateTriangleMesh triangleDataPtr colorData:" + str);
|
||||
//
|
||||
// Debug.Log("CreateTriangleMesh vertexDataPtr=" + vertexDataPtr + " vertexCount=" + vertexCount);
|
||||
// Debug.Log("CreateTriangleMesh triangleDataPtr=" + triangleDataPtr + " triangleCount=" + triangleCount);
|
||||
|
||||
XrResult result =
|
||||
createTriangleMesh(id, vertexDataPtr, vertexCount, triangleDataPtr, triangleCount, transform);
|
||||
Clear();
|
||||
if (result == XrResult.Success)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void UpdateMeshTransform(int id, GeometryInstanceTransform transform)
|
||||
{
|
||||
updatePassthroughMeshTransform(id, transform);
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Validation Rules for ARCameraFeature.
|
||||
/// </summary>
|
||||
protected override void GetValidationChecks(List<ValidationRule> rules, BuildTargetGroup targetGroup)
|
||||
{
|
||||
var AdditionalRules = new ValidationRule[]
|
||||
{
|
||||
new ValidationRule(this)
|
||||
{
|
||||
message = "Passthrough requires Camera clear flags set to solid color with alpha value zero.",
|
||||
checkPredicate = () =>
|
||||
{
|
||||
|
||||
var xrOrigin = FindObjectsOfType<XROrigin>();
|
||||
|
||||
if (xrOrigin != null && xrOrigin.Length > 0)
|
||||
{
|
||||
if (!xrOrigin[0].enabled) return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var camera = xrOrigin[0].Camera;
|
||||
if (camera == null) return true;
|
||||
|
||||
return camera.clearFlags == CameraClearFlags.SolidColor && Mathf.Approximately(camera.backgroundColor.a, 0);
|
||||
},
|
||||
fixItAutomatic = true,
|
||||
fixItMessage = "Set your XR Origin camera's Clear Flags to solid color with alpha value zero.",
|
||||
fixIt = () =>
|
||||
{
|
||||
var xrOrigin = FindObjectsOfType<XROrigin>();
|
||||
if (xrOrigin!=null&&xrOrigin.Length>0)
|
||||
{
|
||||
if (xrOrigin[0].enabled)
|
||||
{
|
||||
var camera = xrOrigin[0].Camera;
|
||||
if (camera != null )
|
||||
{
|
||||
camera.clearFlags = CameraClearFlags.SolidColor;
|
||||
Color clearColor = camera.backgroundColor;
|
||||
clearColor.a = 0;
|
||||
camera.backgroundColor = clearColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
error = false
|
||||
}
|
||||
};
|
||||
|
||||
rules.AddRange(AdditionalRules);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if AR_FOUNDATION_5||AR_FOUNDATION_6
|
||||
public bool isCameraSubsystem=false;
|
||||
static List<XRCameraSubsystemDescriptor> s_CameraDescriptors = new List<XRCameraSubsystemDescriptor>();
|
||||
protected override void OnSubsystemCreate()
|
||||
{
|
||||
base.OnSubsystemCreate();
|
||||
if (isCameraSubsystem)
|
||||
{
|
||||
CreateSubsystem<XRCameraSubsystemDescriptor, XRCameraSubsystem>(
|
||||
s_CameraDescriptors,
|
||||
PXR_CameraSubsystem.k_SubsystemId);
|
||||
}
|
||||
|
||||
}
|
||||
protected override void OnSubsystemStart()
|
||||
{
|
||||
if (isCameraSubsystem)
|
||||
{
|
||||
StartSubsystem<XRCameraSubsystem>();
|
||||
}
|
||||
}
|
||||
protected override void OnSubsystemStop()
|
||||
{
|
||||
if (isCameraSubsystem)
|
||||
{
|
||||
StopSubsystem<XRCameraSubsystem>();
|
||||
}
|
||||
}
|
||||
protected override void OnSubsystemDestroy()
|
||||
{
|
||||
if (isCameraSubsystem)
|
||||
{
|
||||
DestroySubsystem<XRCameraSubsystem>();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
protected override void OnSessionStateChange(int oldState, int newState)
|
||||
{
|
||||
base.OnSessionStateChange(oldState, newState);
|
||||
if (newState == 1)
|
||||
{
|
||||
#if AR_FOUNDATION_5||AR_FOUNDATION_6
|
||||
if (isCameraSubsystem)
|
||||
{
|
||||
StopSubsystem<XRCameraSubsystem>();
|
||||
}else{
|
||||
if (_enableVideoSeeThrough!=-1)
|
||||
{
|
||||
EnableSeeThroughManual(false);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (_enableVideoSeeThrough!=-1)
|
||||
{
|
||||
EnableSeeThroughManual(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (newState == 5)
|
||||
{
|
||||
#if AR_FOUNDATION_5||AR_FOUNDATION_6
|
||||
if (isCameraSubsystem)
|
||||
{
|
||||
StartSubsystem<XRCameraSubsystem>();
|
||||
}else{
|
||||
if (_enableVideoSeeThrough!=-1)
|
||||
{
|
||||
EnableSeeThroughManual(EnableVideoSeeThrough);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (_enableVideoSeeThrough!=-1)
|
||||
{
|
||||
EnableSeeThroughManual(EnableVideoSeeThrough);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_InitializePassthrough", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool initializePassthrough();
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_CreateFullScreenLayer", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool createFullScreenLayer();
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_PassthroughStart", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void passthroughStart();
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_PassthroughPause", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void passthroughPause();
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_SetPassthroughStyle", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void setPassthroughStyle(_PassthroughStyle style);
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_IsPassthroughSupported", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool isPassthroughSupported();
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_Passthrough_Destroy", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void Passthrough_Destroy();
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_CreateTriangleMesh", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern XrResult createTriangleMesh(int id, IntPtr vertices, int vertexCount, IntPtr triangles,
|
||||
int triangleCount, GeometryInstanceTransform transform);
|
||||
|
||||
[DllImport(OpenXRExtensions.PXR_PLATFORM_DLL, EntryPoint = "PICO_UpdatePassthroughMeshTransform",
|
||||
CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void updatePassthroughMeshTransform(int id, GeometryInstanceTransform transform);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25fd7afe1de6d1545bfb5621a8e3aad5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,86 @@
|
||||
#if PICO_OPENXR_SDK
|
||||
using System;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.OpenXR.Features.PICOSupport
|
||||
{
|
||||
public class PassthroughLayerFeature : LayerBase
|
||||
{
|
||||
private int id = 0;
|
||||
private Vector3[] vertices;
|
||||
private int[] triangles;
|
||||
private Mesh mesh;
|
||||
private bool isPassthroughSupported = false;
|
||||
private bool isCreateTriangleMesh = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
id = ID;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
MeshFilter meshFilter = this.gameObject.GetComponent<MeshFilter>();
|
||||
if (meshFilter == null)
|
||||
{
|
||||
Debug.LogError("Passthrough GameObject does not have a mesh component.");
|
||||
return;
|
||||
}
|
||||
|
||||
mesh = meshFilter.sharedMesh;
|
||||
vertices = mesh.vertices;
|
||||
triangles = mesh.triangles;
|
||||
isPassthroughSupported = PassthroughFeature.IsPassthroughSupported();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (isPassthroughSupported && !isCreateTriangleMesh)
|
||||
{
|
||||
GeometryInstanceTransform Transform = new GeometryInstanceTransform();
|
||||
UpdateCoords(true);
|
||||
GetCurrentTransform(ref Transform);
|
||||
isCreateTriangleMesh = PassthroughFeature.CreateTriangleMesh(id, vertices, triangles, Transform);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
Camera.onPostRender += OnPostRenderCallBack;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
Camera.onPostRender -= OnPostRenderCallBack;
|
||||
}
|
||||
|
||||
|
||||
private void OnPostRenderCallBack(Camera cam)
|
||||
{
|
||||
GeometryInstanceTransform Transform = new GeometryInstanceTransform();
|
||||
UpdateCoords();
|
||||
GetCurrentTransform(ref Transform);
|
||||
PassthroughFeature.UpdateMeshTransform(id, Transform);
|
||||
}
|
||||
|
||||
void OnApplicationPause(bool pause)
|
||||
{
|
||||
if (isCreateTriangleMesh)
|
||||
{
|
||||
if (pause)
|
||||
{
|
||||
PassthroughFeature.PassthroughPause();
|
||||
}
|
||||
else
|
||||
{
|
||||
PassthroughFeature.PassthroughStart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d56a853c0545c25418b6e768fdff0d71
|
||||
timeCreated: 1694522562
|
||||
Reference in New Issue
Block a user