add unity doc.
This commit is contained in:
8
unity/XR_RM_PICO_UDP_Sender/Assets/Editor.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/Editor.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbe3a47119034546940d4a621f74e77b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
292
unity/XR_RM_PICO_UDP_Sender/Assets/Editor/XrRmUdpSenderProjectSetup.cs
Executable file
292
unity/XR_RM_PICO_UDP_Sender/Assets/Editor/XrRmUdpSenderProjectSetup.cs
Executable file
@ -0,0 +1,292 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEditor;
|
||||
using UnityEditor.XR.Management;
|
||||
using UnityEditor.XR.Management.Metadata;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.XR.Management;
|
||||
using Unity.XR.PXR;
|
||||
|
||||
public static class XrRmUdpSenderProjectSetup
|
||||
{
|
||||
private const string ScenePath = "Assets/Scenes/Main.unity";
|
||||
private const string PackageName = "com.local.xr_rm_udp_sender";
|
||||
private const string ProductName = "XR-RM-PICO-UDP-Sender";
|
||||
private const string DefaultTargetHost = "192.168.9.99";
|
||||
private const string TargetHostEnvVar = "XR_RM_UDP_TARGET_HOST";
|
||||
|
||||
[MenuItem("XR-RM/Apply UDP Sender Android Settings")]
|
||||
public static void ApplyAndroidSettings()
|
||||
{
|
||||
PlayerSettings.productName = ProductName;
|
||||
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, PackageName);
|
||||
PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel29;
|
||||
PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevelAuto;
|
||||
PlayerSettings.Android.forceInternetPermission = true;
|
||||
PlayerSettings.SetScriptingBackend(NamedBuildTarget.Android, ScriptingImplementation.IL2CPP);
|
||||
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64;
|
||||
PlayerSettings.SetGraphicsAPIs(BuildTarget.Android, new[] { GraphicsDeviceType.OpenGLES3 });
|
||||
|
||||
if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android)
|
||||
{
|
||||
bool switched = EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android);
|
||||
if (!switched)
|
||||
{
|
||||
Debug.LogWarning("Could not switch to Android. Install Unity Android Build Support, then run this menu item again.");
|
||||
}
|
||||
}
|
||||
|
||||
EditorUserBuildSettings.selectedBuildTargetGroup = BuildTargetGroup.Android;
|
||||
EnsurePicoSettings();
|
||||
EnablePicoLoader();
|
||||
CreateOrRefreshScene();
|
||||
EditorBuildSettings.scenes = new[] { new EditorBuildSettingsScene(ScenePath, true) };
|
||||
AssetDatabase.SaveAssets();
|
||||
Debug.Log("XR-RM UDP Sender Android settings applied.");
|
||||
}
|
||||
|
||||
[MenuItem("XR-RM/Create Or Refresh UDP Sender Scene")]
|
||||
public static void CreateOrRefreshScene()
|
||||
{
|
||||
Directory.CreateDirectory("Assets/Scenes");
|
||||
|
||||
Scene scene = File.Exists(ScenePath)
|
||||
? EditorSceneManager.OpenScene(ScenePath)
|
||||
: EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||||
|
||||
GameObject sender = GameObject.Find("PicoControllerUdpSender");
|
||||
if (sender == null)
|
||||
{
|
||||
sender = new GameObject("PicoControllerUdpSender");
|
||||
}
|
||||
|
||||
PicoControllerUdpSender component = sender.GetComponent<PicoControllerUdpSender>();
|
||||
if (component == null)
|
||||
{
|
||||
component = sender.AddComponent<PicoControllerUdpSender>();
|
||||
}
|
||||
|
||||
string targetHost = ResolveTargetHost();
|
||||
component.host = targetHost;
|
||||
component.port = 15000;
|
||||
component.sendHz = 60.0f;
|
||||
component.convertUnityToProjectCoordinates = true;
|
||||
component.sendOnStart = true;
|
||||
|
||||
PicoUdpConfigPanel panel = sender.GetComponent<PicoUdpConfigPanel>();
|
||||
if (panel == null)
|
||||
{
|
||||
panel = sender.AddComponent<PicoUdpConfigPanel>();
|
||||
}
|
||||
|
||||
panel.targetFrameRate = 90;
|
||||
panel.showOnStart = true;
|
||||
panel.togglePanelWithMenuButton = true;
|
||||
|
||||
PicoKeepAwake keepAwake = sender.GetComponent<PicoKeepAwake>();
|
||||
if (keepAwake == null)
|
||||
{
|
||||
keepAwake = sender.AddComponent<PicoKeepAwake>();
|
||||
}
|
||||
|
||||
keepAwake.keepAwake = true;
|
||||
keepAwake.applyWhenSendingOnly = true;
|
||||
keepAwake.usePicoEnterpriseApi = true;
|
||||
keepAwake.useAndroidWindowFlag = true;
|
||||
keepAwake.picoRefreshSeconds = 30.0f;
|
||||
|
||||
EditorSceneManager.SaveScene(scene, ScenePath);
|
||||
Debug.Log($"XR-RM UDP Sender scene refreshed. Target host: {targetHost}");
|
||||
}
|
||||
|
||||
private static void EnsurePicoSettings()
|
||||
{
|
||||
Directory.CreateDirectory("Assets/XR/Settings");
|
||||
|
||||
const string settingsPath = "Assets/XR/Settings/PXR_Settings.asset";
|
||||
PXR_Settings settings = AssetDatabase.LoadAssetAtPath<PXR_Settings>(settingsPath);
|
||||
if (settings == null)
|
||||
{
|
||||
settings = ScriptableObject.CreateInstance<PXR_Settings>();
|
||||
settings.stereoRenderingModeAndroid = PXR_Settings.StereoRenderingModeAndroid.MultiPass;
|
||||
AssetDatabase.CreateAsset(settings, settingsPath);
|
||||
}
|
||||
|
||||
EditorBuildSettings.AddConfigObject("Unity.XR.PXR.Settings", settings, true);
|
||||
EditorUtility.SetDirty(settings);
|
||||
}
|
||||
|
||||
[MenuItem("XR-RM/Build Android APK")]
|
||||
public static void BuildAndroidApk()
|
||||
{
|
||||
ApplyAndroidSettings();
|
||||
|
||||
Directory.CreateDirectory("Builds");
|
||||
BuildPlayerOptions options = new BuildPlayerOptions
|
||||
{
|
||||
scenes = new[] { ScenePath },
|
||||
locationPathName = "Builds/XR-RM-PICO-UDP-Sender.apk",
|
||||
target = BuildTarget.Android,
|
||||
targetGroup = BuildTargetGroup.Android,
|
||||
options = BuildOptions.None
|
||||
};
|
||||
|
||||
BuildReport report = BuildPipeline.BuildPlayer(options);
|
||||
BuildSummary summary = report.summary;
|
||||
if (summary.result != BuildResult.Succeeded)
|
||||
{
|
||||
throw new Exception($"Android APK build failed: {summary.result}");
|
||||
}
|
||||
|
||||
Debug.Log($"Android APK built: {options.locationPathName}");
|
||||
}
|
||||
|
||||
private static void EnablePicoLoader()
|
||||
{
|
||||
XRGeneralSettingsPerBuildTarget buildTargetSettings = AssetDatabase.FindAssets("t:XRGeneralSettingsPerBuildTarget")
|
||||
.Select(guid => AssetDatabase.LoadAssetAtPath<XRGeneralSettingsPerBuildTarget>(AssetDatabase.GUIDToAssetPath(guid)))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (buildTargetSettings == null)
|
||||
{
|
||||
buildTargetSettings = ScriptableObject.CreateInstance<XRGeneralSettingsPerBuildTarget>();
|
||||
AssetDatabase.CreateAsset(buildTargetSettings, "Assets/XRGeneralSettingsPerBuildTarget.asset");
|
||||
}
|
||||
|
||||
XRGeneralSettings generalSettings = buildTargetSettings.SettingsForBuildTarget(BuildTargetGroup.Android);
|
||||
if (generalSettings == null)
|
||||
{
|
||||
generalSettings = ScriptableObject.CreateInstance<XRGeneralSettings>();
|
||||
AssetDatabase.AddObjectToAsset(generalSettings, buildTargetSettings);
|
||||
buildTargetSettings.SetSettingsForBuildTarget(BuildTargetGroup.Android, generalSettings);
|
||||
}
|
||||
|
||||
if (generalSettings.Manager == null)
|
||||
{
|
||||
XRManagerSettings managerSettings = ScriptableObject.CreateInstance<XRManagerSettings>();
|
||||
AssetDatabase.AddObjectToAsset(managerSettings, buildTargetSettings);
|
||||
generalSettings.Manager = managerSettings;
|
||||
}
|
||||
|
||||
while (generalSettings.Manager.activeLoaders.Count > 0)
|
||||
{
|
||||
string loaderName = generalSettings.Manager.activeLoaders[0].GetType().FullName;
|
||||
XRPackageMetadataStore.RemoveLoader(generalSettings.Manager, loaderName, BuildTargetGroup.Android);
|
||||
}
|
||||
|
||||
bool success = XRPackageMetadataStore.AssignLoader(generalSettings.Manager, "PXR_Loader", BuildTargetGroup.Android);
|
||||
if (!success)
|
||||
{
|
||||
Debug.LogWarning("Could not assign PICO XR Loader. Check that the PICO Integration package is imported.");
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(generalSettings.Manager);
|
||||
EditorUtility.SetDirty(generalSettings);
|
||||
EditorUtility.SetDirty(buildTargetSettings);
|
||||
}
|
||||
|
||||
private static string ResolveTargetHost()
|
||||
{
|
||||
string envHost = Environment.GetEnvironmentVariable(TargetHostEnvVar);
|
||||
if (IsUsableTargetHost(envHost))
|
||||
{
|
||||
return envHost.Trim();
|
||||
}
|
||||
|
||||
string discoveredHost = GetPreferredLocalIPv4Address();
|
||||
return string.IsNullOrEmpty(discoveredHost) ? DefaultTargetHost : discoveredHost;
|
||||
}
|
||||
|
||||
private static string GetPreferredLocalIPv4Address()
|
||||
{
|
||||
List<string> candidates = new List<string>();
|
||||
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
if (networkInterface.OperationalStatus != OperationalStatus.Up)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Loopback ||
|
||||
networkInterface.NetworkInterfaceType == NetworkInterfaceType.Tunnel)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (UnicastIPAddressInformation addressInfo in networkInterface.GetIPProperties().UnicastAddresses)
|
||||
{
|
||||
string address = addressInfo.Address.ToString();
|
||||
if (IsUsableTargetHost(address))
|
||||
{
|
||||
candidates.Add(address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return candidates
|
||||
.OrderByDescending(GetAddressScore)
|
||||
.ThenBy(address => address, StringComparer.Ordinal)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
private static bool IsUsableTargetHost(string value)
|
||||
{
|
||||
string trimmed = value == null ? string.Empty : value.Trim();
|
||||
if (!IPAddress.TryParse(trimmed, out IPAddress address) ||
|
||||
address.AddressFamily != AddressFamily.InterNetwork)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] bytes = address.GetAddressBytes();
|
||||
bool loopback = bytes[0] == 127;
|
||||
bool linkLocal = bytes[0] == 169 && bytes[1] == 254;
|
||||
bool unspecified = address.Equals(IPAddress.Any);
|
||||
return !loopback && !linkLocal && !unspecified;
|
||||
}
|
||||
|
||||
private static int GetAddressScore(string address)
|
||||
{
|
||||
string[] parts = address.Split('.');
|
||||
if (parts.Length != 4 ||
|
||||
!int.TryParse(parts[0], out int first) ||
|
||||
!int.TryParse(parts[1], out int second))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (first == 192 && second == 168)
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
if (first == 10)
|
||||
{
|
||||
return 40;
|
||||
}
|
||||
|
||||
if (first == 172 && second >= 16 && second <= 31)
|
||||
{
|
||||
return 35;
|
||||
}
|
||||
|
||||
if (first == 198 && (second == 18 || second == 19))
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
unity/XR_RM_PICO_UDP_Sender/Assets/Editor/XrRmUdpSenderProjectSetup.cs.meta
Executable file
11
unity/XR_RM_PICO_UDP_Sender/Assets/Editor/XrRmUdpSenderProjectSetup.cs.meta
Executable file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7d6206b5dd744f0967d32f4f87461d1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/Resources.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/Resources.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25fc9e3c58c3ff84e8cbe943ce7900a9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
4106
unity/XR_RM_PICO_UDP_Sender/Assets/Resources/PXR_DebuggerPanel.prefab
Executable file
4106
unity/XR_RM_PICO_UDP_Sender/Assets/Resources/PXR_DebuggerPanel.prefab
Executable file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2397792c84896c346b1c9782d84b4b7b
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
61
unity/XR_RM_PICO_UDP_Sender/Assets/Resources/PXR_PICODebugger.prefab
Executable file
61
unity/XR_RM_PICO_UDP_Sender/Assets/Resources/PXR_PICODebugger.prefab
Executable file
@ -0,0 +1,61 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &5110496278330240476
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1730820333764801041}
|
||||
- component: {fileID: 2674595972798899402}
|
||||
- component: {fileID: 8854059141330627992}
|
||||
m_Layer: 0
|
||||
m_Name: PXR_PICODebugger
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1730820333764801041
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5110496278330240476}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 1.07, z: 3.09}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &2674595972798899402
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5110496278330240476}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 16f20e8e0453b4ff8a0517178b2117ea, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
config: {fileID: 0}
|
||||
uiController: {fileID: 0}
|
||||
--- !u!114 &8854059141330627992
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5110496278330240476}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d3a4e4bf576cc4998a8d2b5a8b5a3399, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae56b4152c065f545b90d4d8a15a5d90
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
19
unity/XR_RM_PICO_UDP_Sender/Assets/Resources/PXR_PlatformSetting.asset
Executable file
19
unity/XR_RM_PICO_UDP_Sender/Assets/Resources/PXR_PlatformSetting.asset
Executable file
@ -0,0 +1,19 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 508edb944d24e574595a91425051a8e4, type: 3}
|
||||
m_Name: PXR_PlatformSetting
|
||||
m_EditorClassIdentifier:
|
||||
entitlementCheckSimulation: 0
|
||||
startTimeEntitlementCheck: 0
|
||||
appID:
|
||||
useHighlight: 1
|
||||
deviceSN: []
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c14f862605e067e48a1812ecaeae6cc6
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
55
unity/XR_RM_PICO_UDP_Sender/Assets/Resources/PXR_ProjectSetting.asset
Executable file
55
unity/XR_RM_PICO_UDP_Sender/Assets/Resources/PXR_ProjectSetting.asset
Executable file
@ -0,0 +1,55 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 261e5777ad4ae374eb318821653de6aa, type: 3}
|
||||
m_Name: PXR_ProjectSetting
|
||||
m_EditorClassIdentifier:
|
||||
useContentProtect: 0
|
||||
handTracking: 0
|
||||
adaptiveHand: 0
|
||||
highFrequencyHand: 0
|
||||
openMRC: 1
|
||||
faceTracking: 0
|
||||
lipsyncTracking: 0
|
||||
eyeTracking: 0
|
||||
eyetrackingCalibration: 0
|
||||
enableETFR: 0
|
||||
foveationLevel: -1
|
||||
latelatching: 0
|
||||
latelatchingDebug: 0
|
||||
enableSubsampled: 0
|
||||
bodyTracking: 0
|
||||
adaptiveResolution: 0
|
||||
stageMode: 0
|
||||
videoSeeThrough: 0
|
||||
spatialAnchor: 0
|
||||
sceneCapture: 0
|
||||
sharedAnchor: 0
|
||||
spatialMesh: 0
|
||||
planeDetection: 0
|
||||
secureMR: 0
|
||||
meshLod: 0
|
||||
superResolution: 0
|
||||
normalSharpening: 0
|
||||
qualitySharpening: 0
|
||||
fixedFoveatedSharpening: 0
|
||||
selfAdaptiveSharpening: 0
|
||||
handTrackingSupportType: 0
|
||||
arFoundation: 0
|
||||
mrSafeguard: 0
|
||||
enableRecommendMSAA: 0
|
||||
recommendSubsamping: 0
|
||||
recommendMSAA: 0
|
||||
validationFFREnabled: 0
|
||||
validationETFREnabled: 0
|
||||
portalInited: 1
|
||||
isDataCollectionDisabled: 0
|
||||
portalFirstSelected: 0
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 452d3aa7f191564489e0b6bd1da20f22
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/Scenes.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/Scenes.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a106f6617ef14bc88f737d82559a136e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
212
unity/XR_RM_PICO_UDP_Sender/Assets/Scenes/Main.unity
Normal file
212
unity/XR_RM_PICO_UDP_Sender/Assets/Scenes/Main.unity
Normal file
@ -0,0 +1,212 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 3
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 0}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 12
|
||||
m_GIWorkflowMode: 1
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 0
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 40
|
||||
m_AtlasSize: 1024
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 0}
|
||||
m_LightingSettings: {fileID: 0}
|
||||
--- !u!196 &4
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 3
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
buildHeightMesh: 0
|
||||
maxJobWorkers: 0
|
||||
preserveTilesOutsideBounds: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &100000
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 100001}
|
||||
- component: {fileID: 100002}
|
||||
- component: {fileID: 100003}
|
||||
- component: {fileID: 100004}
|
||||
m_Layer: 0
|
||||
m_Name: PicoControllerUdpSender
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &100001
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 100000}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &100002
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 100000}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e4c7a11d85854eddb40a6a614bfb129c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
host: 192.168.9.99
|
||||
port: 15000
|
||||
sendHz: 60
|
||||
convertUnityToProjectCoordinates: 1
|
||||
sendOnStart: 1
|
||||
--- !u!114 &100003
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 100000}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6d53b4ec62e44220a350bfe97f87d681, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
targetFrameRate: 90
|
||||
showOnStart: 1
|
||||
togglePanelWithMenuButton: 1
|
||||
--- !u!114 &100004
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 100000}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 09740726046b89c1b89aad001e0caa83, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
keepAwake: 1
|
||||
applyWhenSendingOnly: 1
|
||||
usePicoEnterpriseApi: 1
|
||||
useAndroidWindowFlag: 1
|
||||
picoRefreshSeconds: 30
|
||||
--- !u!1660057539 &9223372036854775807
|
||||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Roots:
|
||||
- {fileID: 100001}
|
||||
7
unity/XR_RM_PICO_UDP_Sender/Assets/Scenes/Main.unity.meta
Executable file
7
unity/XR_RM_PICO_UDP_Sender/Assets/Scenes/Main.unity.meta
Executable file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f6f64df724c4cf3a040530c120c37d7
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f169e2b3773b4251a0eebc3dd88e1b7d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
374
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoControllerUdpSender.cs
Executable file
374
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoControllerUdpSender.cs
Executable file
@ -0,0 +1,374 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR;
|
||||
|
||||
public class PicoControllerUdpSender : MonoBehaviour
|
||||
{
|
||||
private const string HostPrefsKey = "xr_rm_udp_sender.host";
|
||||
private const string PortPrefsKey = "xr_rm_udp_sender.port";
|
||||
private const string SendHzPrefsKey = "xr_rm_udp_sender.send_hz";
|
||||
private const string ConvertPrefsKey = "xr_rm_udp_sender.convert_coordinates";
|
||||
|
||||
[Header("ROS UDP Target")]
|
||||
public string host = "192.168.9.99";
|
||||
public int port = 15000;
|
||||
|
||||
[Header("Send")]
|
||||
public float sendHz = 60.0f;
|
||||
public bool convertUnityToProjectCoordinates = true;
|
||||
public bool sendOnStart = true;
|
||||
|
||||
private UdpClient client;
|
||||
private IPEndPoint endPoint;
|
||||
private float nextSendTime;
|
||||
private bool sendEnabled;
|
||||
private readonly Packet packet = new Packet();
|
||||
private readonly List<InputDevice> deviceBuffer = new List<InputDevice>();
|
||||
|
||||
public bool SendEnabled => sendEnabled;
|
||||
public bool HasEndpoint => endPoint != null;
|
||||
public bool LeftDeviceValid { get; private set; }
|
||||
public bool RightDeviceValid { get; private set; }
|
||||
public bool LeftGripPressed { get; private set; }
|
||||
public bool RightGripPressed { get; private set; }
|
||||
public string LastError { get; private set; } = string.Empty;
|
||||
public double LastSendTime { get; private set; }
|
||||
public uint SentPackets { get; private set; }
|
||||
|
||||
[Serializable]
|
||||
private class Packet
|
||||
{
|
||||
public double t;
|
||||
public string frame_id = "xr_world";
|
||||
public Controllers controllers = new Controllers();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class Controllers
|
||||
{
|
||||
public ControllerPayload left = new ControllerPayload();
|
||||
public ControllerPayload right = new ControllerPayload();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class ControllerPayload
|
||||
{
|
||||
public bool grip;
|
||||
public float trigger;
|
||||
public float[] pos = new float[] { 0.0f, 1.0f, 0.0f };
|
||||
public float[] quat = new float[] { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
LoadConfig();
|
||||
ReopenClient();
|
||||
sendEnabled = sendOnStart;
|
||||
nextSendTime = 0.0f;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
SendSafeStopPacket();
|
||||
CloseClient();
|
||||
}
|
||||
|
||||
private void OnApplicationPause(bool pauseStatus)
|
||||
{
|
||||
if (pauseStatus)
|
||||
{
|
||||
SendSafeStopPacket();
|
||||
return;
|
||||
}
|
||||
|
||||
nextSendTime = 0.0f;
|
||||
}
|
||||
|
||||
private void OnApplicationFocus(bool hasFocus)
|
||||
{
|
||||
if (!hasFocus)
|
||||
{
|
||||
SendSafeStopPacket();
|
||||
return;
|
||||
}
|
||||
|
||||
nextSendTime = 0.0f;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!sendEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Time.unscaledTime < nextSendTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nextSendTime = Time.unscaledTime + 1.0f / Mathf.Max(sendHz, 1.0f);
|
||||
packet.t = Time.realtimeSinceStartupAsDouble;
|
||||
|
||||
FillController(XRNode.LeftHand, packet.controllers.left);
|
||||
FillController(XRNode.RightHand, packet.controllers.right);
|
||||
SendPacket();
|
||||
}
|
||||
|
||||
public bool ApplyConfig(string newHost, int newPort, float newSendHz, bool newConvertUnityToProjectCoordinates, bool save)
|
||||
{
|
||||
string trimmedHost = newHost == null ? string.Empty : newHost.Trim();
|
||||
if (!TryParseTargetAddress(trimmedHost, out IPAddress address))
|
||||
{
|
||||
LastError = $"Invalid IPv4 address: {newHost}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newPort < 1 || newPort > 65535)
|
||||
{
|
||||
LastError = $"Invalid UDP port: {newPort}";
|
||||
return false;
|
||||
}
|
||||
|
||||
host = trimmedHost;
|
||||
port = newPort;
|
||||
sendHz = Mathf.Clamp(newSendHz, 1.0f, 120.0f);
|
||||
convertUnityToProjectCoordinates = newConvertUnityToProjectCoordinates;
|
||||
ReopenClient(address);
|
||||
if (endPoint == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (save)
|
||||
{
|
||||
SaveConfig();
|
||||
}
|
||||
|
||||
LastError = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetSending(bool enabled)
|
||||
{
|
||||
if (!enabled && sendEnabled)
|
||||
{
|
||||
SendSafeStopPacket();
|
||||
}
|
||||
|
||||
sendEnabled = enabled;
|
||||
nextSendTime = 0.0f;
|
||||
}
|
||||
|
||||
private void LoadConfig()
|
||||
{
|
||||
string savedHost = PlayerPrefs.GetString(HostPrefsKey, host);
|
||||
if (TryParseTargetAddress(savedHost, out _))
|
||||
{
|
||||
host = savedHost.Trim();
|
||||
}
|
||||
|
||||
port = Mathf.Clamp(PlayerPrefs.GetInt(PortPrefsKey, port), 1, 65535);
|
||||
sendHz = Mathf.Clamp(PlayerPrefs.GetFloat(SendHzPrefsKey, sendHz), 1.0f, 120.0f);
|
||||
convertUnityToProjectCoordinates = PlayerPrefs.GetInt(ConvertPrefsKey, convertUnityToProjectCoordinates ? 1 : 0) != 0;
|
||||
}
|
||||
|
||||
private void SaveConfig()
|
||||
{
|
||||
PlayerPrefs.SetString(HostPrefsKey, host);
|
||||
PlayerPrefs.SetInt(PortPrefsKey, port);
|
||||
PlayerPrefs.SetFloat(SendHzPrefsKey, sendHz);
|
||||
PlayerPrefs.SetInt(ConvertPrefsKey, convertUnityToProjectCoordinates ? 1 : 0);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
private void ReopenClient()
|
||||
{
|
||||
if (TryParseTargetAddress(host, out IPAddress address))
|
||||
{
|
||||
ReopenClient(address);
|
||||
return;
|
||||
}
|
||||
|
||||
LastError = $"Invalid IPv4 address: {host}";
|
||||
CloseClient();
|
||||
endPoint = null;
|
||||
}
|
||||
|
||||
private void ReopenClient(IPAddress address)
|
||||
{
|
||||
try
|
||||
{
|
||||
CloseClient();
|
||||
client = new UdpClient();
|
||||
endPoint = new IPEndPoint(address, port);
|
||||
LastError = string.Empty;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LastError = exception.Message;
|
||||
CloseClient();
|
||||
endPoint = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void FillController(XRNode node, ControllerPayload payload)
|
||||
{
|
||||
InputDevice device = GetControllerDevice(node);
|
||||
bool isLeft = node == XRNode.LeftHand;
|
||||
if (isLeft)
|
||||
{
|
||||
LeftDeviceValid = device.isValid;
|
||||
}
|
||||
else
|
||||
{
|
||||
RightDeviceValid = device.isValid;
|
||||
}
|
||||
|
||||
if (!device.isValid)
|
||||
{
|
||||
payload.grip = false;
|
||||
payload.trigger = 0.0f;
|
||||
SetGripState(isLeft, false);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 position = Vector3.zero;
|
||||
Quaternion rotation = Quaternion.identity;
|
||||
float trigger = 0.0f;
|
||||
float gripValue = 0.0f;
|
||||
bool gripButton = false;
|
||||
|
||||
device.TryGetFeatureValue(CommonUsages.devicePosition, out position);
|
||||
device.TryGetFeatureValue(CommonUsages.deviceRotation, out rotation);
|
||||
device.TryGetFeatureValue(CommonUsages.trigger, out trigger);
|
||||
device.TryGetFeatureValue(CommonUsages.grip, out gripValue);
|
||||
device.TryGetFeatureValue(CommonUsages.gripButton, out gripButton);
|
||||
|
||||
payload.grip = gripButton || gripValue > 0.5f;
|
||||
SetGripState(isLeft, payload.grip);
|
||||
payload.trigger = Mathf.Clamp01(trigger);
|
||||
|
||||
if (convertUnityToProjectCoordinates)
|
||||
{
|
||||
payload.pos[0] = position.x;
|
||||
payload.pos[1] = position.y;
|
||||
payload.pos[2] = -position.z;
|
||||
|
||||
payload.quat[0] = -rotation.x;
|
||||
payload.quat[1] = -rotation.y;
|
||||
payload.quat[2] = rotation.z;
|
||||
payload.quat[3] = rotation.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
payload.pos[0] = position.x;
|
||||
payload.pos[1] = position.y;
|
||||
payload.pos[2] = position.z;
|
||||
|
||||
payload.quat[0] = rotation.x;
|
||||
payload.quat[1] = rotation.y;
|
||||
payload.quat[2] = rotation.z;
|
||||
payload.quat[3] = rotation.w;
|
||||
}
|
||||
}
|
||||
|
||||
private InputDevice GetControllerDevice(XRNode node)
|
||||
{
|
||||
InputDevice device = InputDevices.GetDeviceAtXRNode(node);
|
||||
if (device.isValid)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
|
||||
InputDeviceCharacteristics handedness = node == XRNode.LeftHand
|
||||
? InputDeviceCharacteristics.Left
|
||||
: InputDeviceCharacteristics.Right;
|
||||
|
||||
device = FindControllerByCharacteristics(
|
||||
InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.HeldInHand | handedness);
|
||||
if (device.isValid)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
|
||||
return FindControllerByCharacteristics(InputDeviceCharacteristics.Controller | handedness);
|
||||
}
|
||||
|
||||
private InputDevice FindControllerByCharacteristics(InputDeviceCharacteristics characteristics)
|
||||
{
|
||||
deviceBuffer.Clear();
|
||||
InputDevices.GetDevicesWithCharacteristics(characteristics, deviceBuffer);
|
||||
for (int i = 0; i < deviceBuffer.Count; i++)
|
||||
{
|
||||
if (deviceBuffer[i].isValid)
|
||||
{
|
||||
return deviceBuffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
private static bool TryParseTargetAddress(string value, out IPAddress address)
|
||||
{
|
||||
string trimmed = value == null ? string.Empty : value.Trim();
|
||||
return IPAddress.TryParse(trimmed, out address) && address.AddressFamily == AddressFamily.InterNetwork;
|
||||
}
|
||||
|
||||
private void SetGripState(bool isLeft, bool pressed)
|
||||
{
|
||||
if (isLeft)
|
||||
{
|
||||
LeftGripPressed = pressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
RightGripPressed = pressed;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendSafeStopPacket()
|
||||
{
|
||||
packet.t = Time.realtimeSinceStartupAsDouble;
|
||||
packet.controllers.left.grip = false;
|
||||
packet.controllers.left.trigger = 0.0f;
|
||||
packet.controllers.right.grip = false;
|
||||
packet.controllers.right.trigger = 0.0f;
|
||||
LeftGripPressed = false;
|
||||
RightGripPressed = false;
|
||||
SendPacket();
|
||||
}
|
||||
|
||||
private void SendPacket()
|
||||
{
|
||||
if (client == null || endPoint == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string json = JsonUtility.ToJson(packet);
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(json);
|
||||
try
|
||||
{
|
||||
client.Send(bytes, bytes.Length, endPoint);
|
||||
LastSendTime = Time.realtimeSinceStartupAsDouble;
|
||||
SentPackets++;
|
||||
LastError = string.Empty;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LastError = exception.Message;
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseClient()
|
||||
{
|
||||
client?.Close();
|
||||
client = null;
|
||||
}
|
||||
}
|
||||
11
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoControllerUdpSender.cs.meta
Executable file
11
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoControllerUdpSender.cs.meta
Executable file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4c7a11d85854eddb40a6a614bfb129c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
372
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoKeepAwake.cs
Normal file
372
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoKeepAwake.cs
Normal file
@ -0,0 +1,372 @@
|
||||
using System;
|
||||
using Unity.XR.PICO.TOBSupport;
|
||||
using UnityEngine;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public class PicoKeepAwake : MonoBehaviour
|
||||
{
|
||||
[Header("Policy")]
|
||||
public bool keepAwake = true;
|
||||
public bool applyWhenSendingOnly = true;
|
||||
|
||||
[Header("Backends")]
|
||||
public bool usePicoEnterpriseApi = true;
|
||||
public bool useAndroidWindowFlag = true;
|
||||
public float picoRefreshSeconds = 30.0f;
|
||||
|
||||
private const int AndroidFlagKeepScreenOn = 128;
|
||||
|
||||
private PicoControllerUdpSender sender;
|
||||
private bool enterpriseInitialized;
|
||||
private bool enterpriseBound;
|
||||
private bool enterpriseBindingRequested;
|
||||
private bool picoSettingsApplied;
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
private bool picoSystemDelaysCaptured;
|
||||
private SleepDelayTimeEnum previousSleepDelay;
|
||||
private ScreenOffDelayTimeEnum previousScreenOffDelay;
|
||||
#endif
|
||||
private float nextPicoRefreshTime;
|
||||
private int lastScreenOffDelayResult = int.MinValue;
|
||||
private string lastPicoError = string.Empty;
|
||||
|
||||
public bool KeepAwakeActive { get; private set; }
|
||||
public bool EnterpriseBound => enterpriseBound;
|
||||
public string StatusText { get; private set; } = "KeepAwake idle";
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
sender = GetComponent<PicoControllerUdpSender>();
|
||||
ApplyUnityKeepAwakeDefaults();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (usePicoEnterpriseApi)
|
||||
{
|
||||
EnsureEnterpriseBinding();
|
||||
}
|
||||
|
||||
RefreshDesiredState(true);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
RefreshDesiredState(false);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
DisableKeepAwake();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
DisableKeepAwake();
|
||||
}
|
||||
|
||||
private void OnApplicationPause(bool pauseStatus)
|
||||
{
|
||||
if (!pauseStatus)
|
||||
{
|
||||
nextPicoRefreshTime = 0.0f;
|
||||
RefreshDesiredState(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnApplicationFocus(bool hasFocus)
|
||||
{
|
||||
if (hasFocus)
|
||||
{
|
||||
nextPicoRefreshTime = 0.0f;
|
||||
RefreshDesiredState(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshDesiredState(bool force)
|
||||
{
|
||||
bool shouldKeepAwake = keepAwake && (!applyWhenSendingOnly || sender == null || sender.SendEnabled);
|
||||
if (!shouldKeepAwake)
|
||||
{
|
||||
if (KeepAwakeActive)
|
||||
{
|
||||
DisableKeepAwake();
|
||||
}
|
||||
else
|
||||
{
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!KeepAwakeActive)
|
||||
{
|
||||
EnableKeepAwake();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((force || Time.unscaledTime >= nextPicoRefreshTime) && usePicoEnterpriseApi)
|
||||
{
|
||||
ApplyPicoEnterpriseKeepAwake();
|
||||
}
|
||||
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
private void EnableKeepAwake()
|
||||
{
|
||||
ApplyUnityKeepAwakeDefaults();
|
||||
SetAndroidKeepScreenOn(true);
|
||||
|
||||
KeepAwakeActive = true;
|
||||
nextPicoRefreshTime = 0.0f;
|
||||
|
||||
if (usePicoEnterpriseApi)
|
||||
{
|
||||
EnsureEnterpriseBinding();
|
||||
ApplyPicoEnterpriseKeepAwake();
|
||||
}
|
||||
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
private void DisableKeepAwake()
|
||||
{
|
||||
if (!KeepAwakeActive)
|
||||
{
|
||||
RefreshStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (usePicoEnterpriseApi)
|
||||
{
|
||||
ReleasePicoEnterpriseWakeLock();
|
||||
}
|
||||
|
||||
SetAndroidKeepScreenOn(false);
|
||||
Screen.sleepTimeout = SleepTimeout.SystemSetting;
|
||||
KeepAwakeActive = false;
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
private static void ApplyUnityKeepAwakeDefaults()
|
||||
{
|
||||
Application.runInBackground = true;
|
||||
Screen.sleepTimeout = SleepTimeout.NeverSleep;
|
||||
}
|
||||
|
||||
private void EnsureEnterpriseBinding()
|
||||
{
|
||||
if (!usePicoEnterpriseApi || enterpriseBindingRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
enterpriseBindingRequested = true;
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
try
|
||||
{
|
||||
enterpriseInitialized = PXR_Enterprise.InitEnterpriseService(false);
|
||||
PXR_Enterprise.BindEnterpriseService(OnEnterpriseBound);
|
||||
lastPicoError = enterpriseInitialized ? string.Empty : "PICO enterprise init failed";
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
enterpriseInitialized = false;
|
||||
lastPicoError = exception.Message;
|
||||
}
|
||||
#else
|
||||
enterpriseInitialized = true;
|
||||
enterpriseBound = true;
|
||||
#endif
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
private void OnEnterpriseBound(bool success)
|
||||
{
|
||||
enterpriseBound = success;
|
||||
if (!success)
|
||||
{
|
||||
lastPicoError = "PICO enterprise bind failed";
|
||||
RefreshStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
lastPicoError = string.Empty;
|
||||
nextPicoRefreshTime = 0.0f;
|
||||
if (KeepAwakeActive)
|
||||
{
|
||||
ApplyPicoEnterpriseKeepAwake();
|
||||
}
|
||||
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
private void ApplyPicoEnterpriseKeepAwake()
|
||||
{
|
||||
nextPicoRefreshTime = Time.unscaledTime + Mathf.Max(5.0f, picoRefreshSeconds);
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
if (!enterpriseInitialized)
|
||||
{
|
||||
EnsureEnterpriseBinding();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CapturePicoSystemDelays();
|
||||
PXR_Enterprise.AcquireWakeLock();
|
||||
PXR_Enterprise.PropertySetSleepDelay(SleepDelayTimeEnum.NEVER);
|
||||
PXR_Enterprise.PropertySetScreenOffDelay(ScreenOffDelayTimeEnum.NEVER, OnScreenOffDelaySet);
|
||||
PXR_Enterprise.SwitchSystemFunction(SystemFunctionSwitchEnum.SFS_AUTOSLEEP, SwitchEnum.S_OFF);
|
||||
|
||||
picoSettingsApplied = true;
|
||||
lastPicoError = string.Empty;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
lastPicoError = exception.Message;
|
||||
}
|
||||
#else
|
||||
picoSettingsApplied = true;
|
||||
#endif
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
private void CapturePicoSystemDelays()
|
||||
{
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
if (picoSystemDelaysCaptured || !enterpriseBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
previousSleepDelay = PXR_Enterprise.GetSleepDelay();
|
||||
previousScreenOffDelay = PXR_Enterprise.GetScreenOffDelay();
|
||||
picoSystemDelaysCaptured = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnScreenOffDelaySet(int result)
|
||||
{
|
||||
lastScreenOffDelayResult = result;
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
private void ReleasePicoEnterpriseWakeLock()
|
||||
{
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
if (!enterpriseInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
PXR_Enterprise.ReleaseWakeLock();
|
||||
RestorePicoSystemDelays();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
lastPicoError = exception.Message;
|
||||
}
|
||||
#endif
|
||||
picoSettingsApplied = false;
|
||||
lastScreenOffDelayResult = int.MinValue;
|
||||
}
|
||||
|
||||
private void RestorePicoSystemDelays()
|
||||
{
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
if (!picoSystemDelaysCaptured)
|
||||
{
|
||||
PXR_Enterprise.SwitchSystemFunction(SystemFunctionSwitchEnum.SFS_AUTOSLEEP, SwitchEnum.S_ON);
|
||||
return;
|
||||
}
|
||||
|
||||
PXR_Enterprise.PropertySetSleepDelay(previousSleepDelay);
|
||||
PXR_Enterprise.PropertySetScreenOffDelay(previousScreenOffDelay, null);
|
||||
PXR_Enterprise.SwitchSystemFunction(SystemFunctionSwitchEnum.SFS_AUTOSLEEP, SwitchEnum.S_ON);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void RefreshStatus()
|
||||
{
|
||||
if (!keepAwake)
|
||||
{
|
||||
StatusText = "KeepAwake disabled";
|
||||
return;
|
||||
}
|
||||
|
||||
if (applyWhenSendingOnly && sender != null && !sender.SendEnabled)
|
||||
{
|
||||
StatusText = "KeepAwake waiting";
|
||||
return;
|
||||
}
|
||||
|
||||
string activeState = KeepAwakeActive ? "ON" : "OFF";
|
||||
string picoState = "PICO --";
|
||||
if (usePicoEnterpriseApi)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(lastPicoError))
|
||||
{
|
||||
picoState = "PICO error";
|
||||
}
|
||||
else if (enterpriseBindingRequested && !enterpriseInitialized)
|
||||
{
|
||||
picoState = "PICO init";
|
||||
}
|
||||
else if (enterpriseBound)
|
||||
{
|
||||
picoState = picoSettingsApplied ? "PICO applied" : "PICO bound";
|
||||
}
|
||||
else if (enterpriseBindingRequested)
|
||||
{
|
||||
picoState = "PICO binding";
|
||||
}
|
||||
}
|
||||
|
||||
string screenState = lastScreenOffDelayResult == int.MinValue
|
||||
? string.Empty
|
||||
: " screen " + lastScreenOffDelayResult.ToString();
|
||||
|
||||
StatusText = "KeepAwake " + activeState + " | " + picoState + screenState;
|
||||
}
|
||||
|
||||
private void SetAndroidKeepScreenOn(bool enabled)
|
||||
{
|
||||
if (!useAndroidWindowFlag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
try
|
||||
{
|
||||
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
|
||||
{
|
||||
AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
|
||||
activity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
|
||||
{
|
||||
AndroidJavaObject window = activity.Call<AndroidJavaObject>("getWindow");
|
||||
if (enabled)
|
||||
{
|
||||
window.Call("addFlags", AndroidFlagKeepScreenOn);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.Call("clearFlags", AndroidFlagKeepScreenOn);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
lastPicoError = exception.Message;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09740726046b89c1b89aad001e0caa83
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
638
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoUdpConfigPanel.cs
Executable file
638
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoUdpConfigPanel.cs
Executable file
@ -0,0 +1,638 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.XR;
|
||||
|
||||
public class PicoUdpConfigPanel : MonoBehaviour
|
||||
{
|
||||
private const int RowCount = 6;
|
||||
private const float AxisRepeatDelay = 0.22f;
|
||||
|
||||
public int targetFrameRate = 90;
|
||||
public bool showOnStart = true;
|
||||
public bool togglePanelWithMenuButton = true;
|
||||
|
||||
private readonly Text[] rowTexts = new Text[RowCount];
|
||||
private readonly Color normalColor = new Color(0.86f, 0.91f, 0.96f, 1.0f);
|
||||
private readonly Color selectedColor = new Color(0.35f, 0.82f, 1.0f, 1.0f);
|
||||
private readonly Color mutedColor = new Color(0.58f, 0.66f, 0.74f, 1.0f);
|
||||
|
||||
private PicoControllerUdpSender sender;
|
||||
private Canvas canvas;
|
||||
private GameObject configPanelObject;
|
||||
private GameObject runHudObject;
|
||||
private Text titleText;
|
||||
private Text statusText;
|
||||
private Text footerText;
|
||||
private Text hudTitleText;
|
||||
private Text hudStatusText;
|
||||
private Text hudDetailText;
|
||||
private Text hudHintText;
|
||||
private TouchScreenKeyboard keyboard;
|
||||
private KeyboardTarget keyboardTarget;
|
||||
private string hostDraft;
|
||||
private int portDraft;
|
||||
private float sendHzDraft;
|
||||
private bool convertDraft;
|
||||
private PicoKeepAwake keepAwake;
|
||||
private int selectedRow;
|
||||
private float nextAxisTime;
|
||||
private bool wasActivatePressed;
|
||||
private bool wasApplyPressed;
|
||||
private bool wasMenuPressed;
|
||||
private string panelMessage = "Ready";
|
||||
|
||||
private enum KeyboardTarget
|
||||
{
|
||||
None,
|
||||
Host,
|
||||
Port,
|
||||
SendHz
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
sender = GetComponent<PicoControllerUdpSender>();
|
||||
if (sender == null)
|
||||
{
|
||||
sender = gameObject.AddComponent<PicoControllerUdpSender>();
|
||||
}
|
||||
|
||||
keepAwake = GetComponent<PicoKeepAwake>();
|
||||
if (keepAwake == null)
|
||||
{
|
||||
keepAwake = gameObject.AddComponent<PicoKeepAwake>();
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
ApplyRuntimeDefaults();
|
||||
EnsurePanel();
|
||||
LoadDraftsFromSender();
|
||||
canvas.gameObject.SetActive(true);
|
||||
SetConfigPanelVisible(showOnStart, false);
|
||||
RefreshPanel();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
HandleKeyboard();
|
||||
HandleControllerInput();
|
||||
RefreshPanel();
|
||||
}
|
||||
|
||||
private void ApplyRuntimeDefaults()
|
||||
{
|
||||
Application.targetFrameRate = targetFrameRate;
|
||||
Application.runInBackground = true;
|
||||
QualitySettings.vSyncCount = 0;
|
||||
Screen.sleepTimeout = SleepTimeout.NeverSleep;
|
||||
XRSettings.eyeTextureResolutionScale = 1.0f;
|
||||
}
|
||||
|
||||
private void EnsurePanel()
|
||||
{
|
||||
Camera panelCamera = Camera.main;
|
||||
if (panelCamera == null)
|
||||
{
|
||||
GameObject cameraObject = new GameObject("XR-RM Main Camera");
|
||||
cameraObject.tag = "MainCamera";
|
||||
panelCamera = cameraObject.AddComponent<Camera>();
|
||||
panelCamera.nearClipPlane = 0.05f;
|
||||
panelCamera.farClipPlane = 100.0f;
|
||||
panelCamera.clearFlags = CameraClearFlags.SolidColor;
|
||||
panelCamera.backgroundColor = new Color(0.02f, 0.025f, 0.03f, 1.0f);
|
||||
|
||||
if (FindObjectOfType<AudioListener>() == null)
|
||||
{
|
||||
cameraObject.AddComponent<AudioListener>();
|
||||
}
|
||||
|
||||
AddTrackedPoseDriverIfAvailable(cameraObject);
|
||||
}
|
||||
|
||||
GameObject canvasObject = new GameObject("XR-RM UDP Config Canvas", typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler));
|
||||
canvasObject.transform.SetParent(panelCamera.transform, false);
|
||||
canvasObject.transform.localPosition = new Vector3(0.0f, 0.0f, 2.0f);
|
||||
canvasObject.transform.localRotation = Quaternion.identity;
|
||||
canvasObject.transform.localScale = Vector3.one * 0.0014f;
|
||||
|
||||
canvas = canvasObject.GetComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.WorldSpace;
|
||||
canvas.worldCamera = panelCamera;
|
||||
canvas.sortingOrder = 10;
|
||||
|
||||
RectTransform canvasRect = canvasObject.GetComponent<RectTransform>();
|
||||
canvasRect.sizeDelta = new Vector2(980.0f, 640.0f);
|
||||
|
||||
CanvasScaler scaler = canvasObject.GetComponent<CanvasScaler>();
|
||||
scaler.dynamicPixelsPerUnit = 12.0f;
|
||||
scaler.referencePixelsPerUnit = 100.0f;
|
||||
|
||||
configPanelObject = new GameObject("Config Panel", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image));
|
||||
configPanelObject.transform.SetParent(canvasObject.transform, false);
|
||||
RectTransform backgroundRect = configPanelObject.GetComponent<RectTransform>();
|
||||
backgroundRect.anchorMin = Vector2.zero;
|
||||
backgroundRect.anchorMax = Vector2.one;
|
||||
backgroundRect.offsetMin = Vector2.zero;
|
||||
backgroundRect.offsetMax = Vector2.zero;
|
||||
Image background = configPanelObject.GetComponent<Image>();
|
||||
background.color = new Color(0.045f, 0.06f, 0.075f, 0.94f);
|
||||
|
||||
titleText = CreateText("Title", configPanelObject.transform, 38, FontStyle.Bold, TextAnchor.MiddleLeft);
|
||||
SetRect(titleText.rectTransform, new Vector2(0.06f, 0.82f), new Vector2(0.94f, 0.96f), Vector2.zero, Vector2.zero);
|
||||
|
||||
statusText = CreateText("Status", configPanelObject.transform, 22, FontStyle.Normal, TextAnchor.MiddleLeft);
|
||||
statusText.color = mutedColor;
|
||||
SetRect(statusText.rectTransform, new Vector2(0.06f, 0.72f), new Vector2(0.94f, 0.82f), Vector2.zero, Vector2.zero);
|
||||
|
||||
for (int i = 0; i < RowCount; i++)
|
||||
{
|
||||
Text rowText = CreateText("Row " + i, configPanelObject.transform, 27, FontStyle.Normal, TextAnchor.MiddleLeft);
|
||||
float top = 0.68f - i * 0.09f;
|
||||
SetRect(rowText.rectTransform, new Vector2(0.08f, top - 0.075f), new Vector2(0.92f, top), Vector2.zero, Vector2.zero);
|
||||
rowTexts[i] = rowText;
|
||||
}
|
||||
|
||||
footerText = CreateText("Footer", configPanelObject.transform, 23, FontStyle.Normal, TextAnchor.MiddleCenter);
|
||||
footerText.color = normalColor;
|
||||
SetRect(footerText.rectTransform, new Vector2(0.05f, 0.025f), new Vector2(0.95f, 0.15f), Vector2.zero, Vector2.zero);
|
||||
|
||||
CreateRunHud(canvasObject.transform);
|
||||
}
|
||||
|
||||
private void CreateRunHud(Transform canvasParent)
|
||||
{
|
||||
runHudObject = new GameObject("Run HUD", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image));
|
||||
runHudObject.transform.SetParent(canvasParent, false);
|
||||
RectTransform hudRect = runHudObject.GetComponent<RectTransform>();
|
||||
hudRect.anchorMin = Vector2.zero;
|
||||
hudRect.anchorMax = Vector2.one;
|
||||
hudRect.offsetMin = Vector2.zero;
|
||||
hudRect.offsetMax = Vector2.zero;
|
||||
Image hudBackground = runHudObject.GetComponent<Image>();
|
||||
hudBackground.color = new Color(0.018f, 0.026f, 0.032f, 0.88f);
|
||||
|
||||
GameObject headerObject = CreateImage("HUD Header", runHudObject.transform, new Color(0.035f, 0.05f, 0.06f, 0.88f));
|
||||
SetRect(headerObject.GetComponent<RectTransform>(), new Vector2(0.05f, 0.70f), new Vector2(0.95f, 0.92f), Vector2.zero, Vector2.zero);
|
||||
|
||||
hudTitleText = CreateText("HUD Title", headerObject.transform, 34, FontStyle.Bold, TextAnchor.MiddleLeft);
|
||||
SetRect(hudTitleText.rectTransform, new Vector2(0.04f, 0.54f), new Vector2(0.96f, 0.95f), Vector2.zero, Vector2.zero);
|
||||
|
||||
hudStatusText = CreateText("HUD Status", headerObject.transform, 28, FontStyle.Bold, TextAnchor.MiddleLeft);
|
||||
hudStatusText.color = selectedColor;
|
||||
SetRect(hudStatusText.rectTransform, new Vector2(0.04f, 0.15f), new Vector2(0.96f, 0.56f), Vector2.zero, Vector2.zero);
|
||||
|
||||
hudDetailText = CreateText("HUD Detail", runHudObject.transform, 25, FontStyle.Normal, TextAnchor.MiddleCenter);
|
||||
SetRect(hudDetailText.rectTransform, new Vector2(0.07f, 0.36f), new Vector2(0.93f, 0.64f), Vector2.zero, Vector2.zero);
|
||||
|
||||
hudHintText = CreateText("HUD Hint", runHudObject.transform, 23, FontStyle.Normal, TextAnchor.MiddleCenter);
|
||||
hudHintText.color = mutedColor;
|
||||
SetRect(hudHintText.rectTransform, new Vector2(0.07f, 0.08f), new Vector2(0.93f, 0.20f), Vector2.zero, Vector2.zero);
|
||||
|
||||
GameObject verticalLine = CreateImage("HUD Vertical Reticle", runHudObject.transform, new Color(0.35f, 0.82f, 1.0f, 0.38f));
|
||||
SetRect(verticalLine.GetComponent<RectTransform>(), new Vector2(0.498f, 0.27f), new Vector2(0.502f, 0.36f), Vector2.zero, Vector2.zero);
|
||||
|
||||
GameObject horizontalLine = CreateImage("HUD Horizontal Reticle", runHudObject.transform, new Color(0.35f, 0.82f, 1.0f, 0.38f));
|
||||
SetRect(horizontalLine.GetComponent<RectTransform>(), new Vector2(0.47f, 0.313f), new Vector2(0.53f, 0.319f), Vector2.zero, Vector2.zero);
|
||||
}
|
||||
|
||||
private static void AddTrackedPoseDriverIfAvailable(GameObject cameraObject)
|
||||
{
|
||||
string[] typeNames =
|
||||
{
|
||||
"UnityEngine.SpatialTracking.TrackedPoseDriver, UnityEngine.SpatialTracking",
|
||||
"UnityEngine.InputSystem.XR.TrackedPoseDriver, Unity.InputSystem"
|
||||
};
|
||||
|
||||
for (int i = 0; i < typeNames.Length; i++)
|
||||
{
|
||||
Type driverType = Type.GetType(typeNames[i]);
|
||||
if (driverType != null && cameraObject.GetComponent(driverType) == null)
|
||||
{
|
||||
cameraObject.AddComponent(driverType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Text CreateText(string name, Transform parent, int fontSize, FontStyle fontStyle, TextAnchor alignment)
|
||||
{
|
||||
GameObject textObject = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(Text));
|
||||
textObject.transform.SetParent(parent, false);
|
||||
|
||||
Text text = textObject.GetComponent<Text>();
|
||||
text.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||||
text.fontSize = fontSize;
|
||||
text.fontStyle = fontStyle;
|
||||
text.alignment = alignment;
|
||||
text.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
text.verticalOverflow = VerticalWrapMode.Truncate;
|
||||
text.resizeTextForBestFit = true;
|
||||
text.resizeTextMinSize = Mathf.Max(12, fontSize - 8);
|
||||
text.resizeTextMaxSize = fontSize;
|
||||
text.color = normalColor;
|
||||
return text;
|
||||
}
|
||||
|
||||
private static void SetRect(RectTransform rectTransform, Vector2 anchorMin, Vector2 anchorMax, Vector2 offsetMin, Vector2 offsetMax)
|
||||
{
|
||||
rectTransform.anchorMin = anchorMin;
|
||||
rectTransform.anchorMax = anchorMax;
|
||||
rectTransform.offsetMin = offsetMin;
|
||||
rectTransform.offsetMax = offsetMax;
|
||||
}
|
||||
|
||||
private static GameObject CreateImage(string name, Transform parent, Color color)
|
||||
{
|
||||
GameObject imageObject = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(Image));
|
||||
imageObject.transform.SetParent(parent, false);
|
||||
Image image = imageObject.GetComponent<Image>();
|
||||
image.color = color;
|
||||
return imageObject;
|
||||
}
|
||||
|
||||
private void LoadDraftsFromSender()
|
||||
{
|
||||
hostDraft = sender.host;
|
||||
portDraft = sender.port;
|
||||
sendHzDraft = sender.sendHz;
|
||||
convertDraft = sender.convertUnityToProjectCoordinates;
|
||||
}
|
||||
|
||||
private void HandleKeyboard()
|
||||
{
|
||||
if (keyboard == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyboard.status == TouchScreenKeyboard.Status.Done || keyboard.status == TouchScreenKeyboard.Status.LostFocus)
|
||||
{
|
||||
CommitKeyboardText(keyboard.text);
|
||||
keyboard = null;
|
||||
keyboardTarget = KeyboardTarget.None;
|
||||
}
|
||||
else if (keyboard.status == TouchScreenKeyboard.Status.Canceled)
|
||||
{
|
||||
panelMessage = "Edit canceled";
|
||||
keyboard = null;
|
||||
keyboardTarget = KeyboardTarget.None;
|
||||
}
|
||||
}
|
||||
|
||||
private void CommitKeyboardText(string value)
|
||||
{
|
||||
string trimmed = value == null ? string.Empty : value.Trim();
|
||||
if (keyboardTarget == KeyboardTarget.Host)
|
||||
{
|
||||
hostDraft = trimmed;
|
||||
panelMessage = "Target IP edited";
|
||||
}
|
||||
else if (keyboardTarget == KeyboardTarget.Port)
|
||||
{
|
||||
if (int.TryParse(trimmed, out int parsedPort))
|
||||
{
|
||||
portDraft = Mathf.Clamp(parsedPort, 1, 65535);
|
||||
panelMessage = "Target port edited";
|
||||
}
|
||||
else
|
||||
{
|
||||
panelMessage = "Invalid port text";
|
||||
}
|
||||
}
|
||||
else if (keyboardTarget == KeyboardTarget.SendHz)
|
||||
{
|
||||
if (TryParseFloat(trimmed, out float parsedHz))
|
||||
{
|
||||
sendHzDraft = Mathf.Clamp(parsedHz, 1.0f, 120.0f);
|
||||
panelMessage = "Send rate edited";
|
||||
}
|
||||
else
|
||||
{
|
||||
panelMessage = "Invalid send rate text";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleControllerInput()
|
||||
{
|
||||
bool menuPressed = IsButtonPressed(CommonUsages.menuButton);
|
||||
if (togglePanelWithMenuButton && menuPressed && !wasMenuPressed)
|
||||
{
|
||||
SetConfigPanelVisible(!IsConfigPanelVisible(), true);
|
||||
}
|
||||
|
||||
wasMenuPressed = menuPressed;
|
||||
if (!IsConfigPanelVisible())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 axis = ReadPrimaryAxis();
|
||||
if (Time.unscaledTime >= nextAxisTime)
|
||||
{
|
||||
if (axis.y > 0.55f)
|
||||
{
|
||||
selectedRow = (selectedRow + RowCount - 1) % RowCount;
|
||||
nextAxisTime = Time.unscaledTime + AxisRepeatDelay;
|
||||
}
|
||||
else if (axis.y < -0.55f)
|
||||
{
|
||||
selectedRow = (selectedRow + 1) % RowCount;
|
||||
nextAxisTime = Time.unscaledTime + AxisRepeatDelay;
|
||||
}
|
||||
else if (axis.x > 0.65f)
|
||||
{
|
||||
AdjustSelectedValue(1);
|
||||
nextAxisTime = Time.unscaledTime + AxisRepeatDelay;
|
||||
}
|
||||
else if (axis.x < -0.65f)
|
||||
{
|
||||
AdjustSelectedValue(-1);
|
||||
nextAxisTime = Time.unscaledTime + AxisRepeatDelay;
|
||||
}
|
||||
}
|
||||
|
||||
bool activatePressed = IsActivatePressed();
|
||||
if (activatePressed && !wasActivatePressed)
|
||||
{
|
||||
ActivateSelectedRow();
|
||||
}
|
||||
|
||||
wasActivatePressed = activatePressed;
|
||||
|
||||
bool applyPressed = IsButtonPressed(CommonUsages.secondaryButton);
|
||||
if (applyPressed && !wasApplyPressed)
|
||||
{
|
||||
ApplyDrafts();
|
||||
}
|
||||
|
||||
wasApplyPressed = applyPressed;
|
||||
}
|
||||
|
||||
private void AdjustSelectedValue(int direction)
|
||||
{
|
||||
if (selectedRow == 1)
|
||||
{
|
||||
portDraft = Mathf.Clamp(portDraft + direction, 1, 65535);
|
||||
panelMessage = "Target port adjusted";
|
||||
}
|
||||
else if (selectedRow == 2)
|
||||
{
|
||||
sendHzDraft = Mathf.Clamp(sendHzDraft + direction * 5.0f, 1.0f, 120.0f);
|
||||
panelMessage = "Send rate adjusted";
|
||||
}
|
||||
else if (selectedRow == 3)
|
||||
{
|
||||
convertDraft = !convertDraft;
|
||||
panelMessage = "Coordinate mode toggled";
|
||||
}
|
||||
else if (selectedRow == 4)
|
||||
{
|
||||
ToggleSending();
|
||||
}
|
||||
}
|
||||
|
||||
private void ActivateSelectedRow()
|
||||
{
|
||||
if (selectedRow == 0)
|
||||
{
|
||||
OpenKeyboard(KeyboardTarget.Host, hostDraft, TouchScreenKeyboardType.URL);
|
||||
}
|
||||
else if (selectedRow == 1)
|
||||
{
|
||||
OpenKeyboard(KeyboardTarget.Port, portDraft.ToString(), TouchScreenKeyboardType.NumberPad);
|
||||
}
|
||||
else if (selectedRow == 2)
|
||||
{
|
||||
OpenKeyboard(KeyboardTarget.SendHz, Mathf.RoundToInt(sendHzDraft).ToString(), TouchScreenKeyboardType.NumberPad);
|
||||
}
|
||||
else if (selectedRow == 3)
|
||||
{
|
||||
convertDraft = !convertDraft;
|
||||
panelMessage = "Coordinate mode toggled";
|
||||
}
|
||||
else if (selectedRow == 4)
|
||||
{
|
||||
ToggleSending();
|
||||
}
|
||||
else if (selectedRow == 5)
|
||||
{
|
||||
ApplyDrafts();
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenKeyboard(KeyboardTarget target, string text, TouchScreenKeyboardType keyboardType)
|
||||
{
|
||||
keyboardTarget = target;
|
||||
keyboard = TouchScreenKeyboard.Open(text, keyboardType, false, false, false, false, "XR-RM UDP");
|
||||
panelMessage = "Editing " + target;
|
||||
}
|
||||
|
||||
private void ToggleSending()
|
||||
{
|
||||
sender.SetSending(!sender.SendEnabled);
|
||||
panelMessage = sender.SendEnabled ? "UDP sending enabled" : "UDP sending paused";
|
||||
}
|
||||
|
||||
private void ApplyDrafts()
|
||||
{
|
||||
bool applied = sender.ApplyConfig(hostDraft, portDraft, sendHzDraft, convertDraft, true);
|
||||
panelMessage = applied ? "Saved and applied" : sender.LastError;
|
||||
}
|
||||
|
||||
private bool IsActivatePressed()
|
||||
{
|
||||
return IsButtonPressed(CommonUsages.primaryButton) || IsButtonPressed(CommonUsages.triggerButton) || ReadTriggerValue() > 0.75f;
|
||||
}
|
||||
|
||||
private static Vector2 ReadPrimaryAxis()
|
||||
{
|
||||
if (TryReadPrimaryAxis(XRNode.RightHand, out Vector2 rightAxis))
|
||||
{
|
||||
return rightAxis;
|
||||
}
|
||||
|
||||
if (TryReadPrimaryAxis(XRNode.LeftHand, out Vector2 leftAxis))
|
||||
{
|
||||
return leftAxis;
|
||||
}
|
||||
|
||||
return Vector2.zero;
|
||||
}
|
||||
|
||||
private static bool TryReadPrimaryAxis(XRNode node, out Vector2 axis)
|
||||
{
|
||||
InputDevice device = InputDevices.GetDeviceAtXRNode(node);
|
||||
if (device.isValid && device.TryGetFeatureValue(CommonUsages.primary2DAxis, out axis))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
axis = Vector2.zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsButtonPressed(InputFeatureUsage<bool> usage)
|
||||
{
|
||||
return TryReadButton(XRNode.RightHand, usage) || TryReadButton(XRNode.LeftHand, usage);
|
||||
}
|
||||
|
||||
private static bool TryReadButton(XRNode node, InputFeatureUsage<bool> usage)
|
||||
{
|
||||
InputDevice device = InputDevices.GetDeviceAtXRNode(node);
|
||||
return device.isValid && device.TryGetFeatureValue(usage, out bool pressed) && pressed;
|
||||
}
|
||||
|
||||
private static float ReadTriggerValue()
|
||||
{
|
||||
float rightValue = TryReadTriggerValue(XRNode.RightHand);
|
||||
if (rightValue > 0.0f)
|
||||
{
|
||||
return rightValue;
|
||||
}
|
||||
|
||||
return TryReadTriggerValue(XRNode.LeftHand);
|
||||
}
|
||||
|
||||
private static float TryReadTriggerValue(XRNode node)
|
||||
{
|
||||
InputDevice device = InputDevices.GetDeviceAtXRNode(node);
|
||||
if (device.isValid && device.TryGetFeatureValue(CommonUsages.trigger, out float value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
private void RefreshPanel()
|
||||
{
|
||||
if (canvas == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshConfigPanel();
|
||||
RefreshRunHud();
|
||||
}
|
||||
|
||||
private void RefreshConfigPanel()
|
||||
{
|
||||
titleText.text = "XR-RM PICO UDP Sender";
|
||||
statusText.text = BuildConfigStatusText();
|
||||
|
||||
SetRow(0, "Target IP", hostDraft);
|
||||
SetRow(1, "Target Port", portDraft.ToString());
|
||||
SetRow(2, "Send Rate", Mathf.RoundToInt(sendHzDraft) + " Hz");
|
||||
SetRow(3, "Coordinates", convertDraft ? "Project (+Z forward)" : "Unity raw");
|
||||
SetRow(4, "UDP Sending", sender.SendEnabled ? "ON" : "OFF");
|
||||
SetRow(5, "Save & Apply", "press trigger");
|
||||
|
||||
footerText.text = "Stick: select / adjust Trigger, A or X: edit\nB or Y: save Menu: run view";
|
||||
}
|
||||
|
||||
private void RefreshRunHud()
|
||||
{
|
||||
if (runHudObject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hudTitleText.text = "XR-RM UDP Sender";
|
||||
hudStatusText.text = (sender.SendEnabled ? "SENDING" : "PAUSED") + " " + BuildEndpointText();
|
||||
hudDetailText.text = BuildTrackingStateText() + " " + BuildGripStateText() + "\n"
|
||||
+ BuildPacketStateText(false) + " " + BuildKeepAwakeStateText();
|
||||
hudHintText.text = "Menu: config panel";
|
||||
}
|
||||
|
||||
private string BuildConfigStatusText()
|
||||
{
|
||||
string endpointState = BuildEndpointText();
|
||||
string sendState = sender.SendEnabled ? "ON" : "OFF";
|
||||
string trackingState = BuildTrackingStateText();
|
||||
string packetState = BuildPacketStateText(true);
|
||||
string keepAwakeState = BuildKeepAwakeStateText();
|
||||
string error = string.IsNullOrEmpty(sender.LastError) ? panelMessage : sender.LastError;
|
||||
return endpointState + " | " + sendState + " | " + trackingState + " | " + packetState + " | " + keepAwakeState + " | " + error;
|
||||
}
|
||||
|
||||
private string BuildEndpointText()
|
||||
{
|
||||
return sender.HasEndpoint ? sender.host + ":" + sender.port : "not configured";
|
||||
}
|
||||
|
||||
private string BuildTrackingStateText()
|
||||
{
|
||||
return "L " + (sender.LeftDeviceValid ? "ok" : "--") + " / R " + (sender.RightDeviceValid ? "ok" : "--");
|
||||
}
|
||||
|
||||
private string BuildGripStateText()
|
||||
{
|
||||
return "Grip L " + (sender.LeftGripPressed ? "ON" : "--") + " / R " + (sender.RightGripPressed ? "ON" : "--");
|
||||
}
|
||||
|
||||
private string BuildPacketStateText(bool compact)
|
||||
{
|
||||
if (sender.SentPackets == 0)
|
||||
{
|
||||
return compact ? "0 pkts" : "Packets 0";
|
||||
}
|
||||
|
||||
double age = Math.Max(0.0, Time.realtimeSinceStartupAsDouble - sender.LastSendTime);
|
||||
string packetCount = sender.SentPackets.ToString(CultureInfo.InvariantCulture);
|
||||
string lastAge = age.ToString("0.0", CultureInfo.InvariantCulture) + "s";
|
||||
return compact ? packetCount + " pkts " + lastAge : "Packets " + packetCount + " Last " + lastAge;
|
||||
}
|
||||
|
||||
private string BuildKeepAwakeStateText()
|
||||
{
|
||||
if (keepAwake == null)
|
||||
{
|
||||
return "KeepAwake --";
|
||||
}
|
||||
|
||||
return keepAwake.StatusText;
|
||||
}
|
||||
|
||||
private void SetRow(int index, string label, string value)
|
||||
{
|
||||
Text rowText = rowTexts[index];
|
||||
bool selected = index == selectedRow;
|
||||
rowText.color = selected ? selectedColor : normalColor;
|
||||
rowText.fontStyle = selected ? FontStyle.Bold : FontStyle.Normal;
|
||||
rowText.text = (selected ? "> " : " ") + label.PadRight(14) + value;
|
||||
}
|
||||
|
||||
private static bool TryParseFloat(string value, out float parsedValue)
|
||||
{
|
||||
return float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out parsedValue)
|
||||
|| float.TryParse(value, out parsedValue);
|
||||
}
|
||||
|
||||
private bool IsConfigPanelVisible()
|
||||
{
|
||||
return configPanelObject != null && configPanelObject.activeSelf;
|
||||
}
|
||||
|
||||
private void SetConfigPanelVisible(bool visible, bool updateMessage)
|
||||
{
|
||||
if (configPanelObject != null)
|
||||
{
|
||||
configPanelObject.SetActive(visible);
|
||||
}
|
||||
|
||||
if (runHudObject != null)
|
||||
{
|
||||
runHudObject.SetActive(!visible);
|
||||
}
|
||||
|
||||
if (updateMessage)
|
||||
{
|
||||
panelMessage = visible ? "Config panel" : "Run view";
|
||||
}
|
||||
}
|
||||
}
|
||||
11
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoUdpConfigPanel.cs.meta
Executable file
11
unity/XR_RM_PICO_UDP_Sender/Assets/Scripts/PicoUdpConfigPanel.cs.meta
Executable file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d53b4ec62e44220a350bfe97f87d681
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13b2a357a18be354fa53f3b373988484
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Loaders.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Loaders.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee2817c3133c6884ab3c7f56bf39f12d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
14
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Loaders/PXR_Loader.asset
Executable file
14
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Loaders/PXR_Loader.asset
Executable file
@ -0,0 +1,14 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 563682312a45bbe4bbd8d243e5e14608, type: 3}
|
||||
m_Name: PXR_Loader
|
||||
m_EditorClassIdentifier:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Loaders/PXR_Loader.asset.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Loaders/PXR_Loader.asset.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a25d5a0e12be3664da944c68c3bbcd6b
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Settings.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Settings.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7451b163683d94f4b848b230514c7eda
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,19 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 1c52faa1787e89a4eaf8abdae2e6ae25, type: 3}
|
||||
m_Name: PXR_Settings
|
||||
m_EditorClassIdentifier:
|
||||
stereoRenderingModeAndroid: 0
|
||||
systemDisplayFrequency: 0
|
||||
optimizeBufferDiscards: 1
|
||||
enableAppSpaceWarp: 0
|
||||
systemSplashScreen: {fileID: 0}
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Settings/PXR_Settings.asset.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/XR/Settings/PXR_Settings.asset.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 059224c120ae442458f8d823f1a61cce
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,48 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d2dc886499c26824283350fa532d087d, type: 3}
|
||||
m_Name: XRGeneralSettingsPerBuildTarget
|
||||
m_EditorClassIdentifier:
|
||||
Keys: 07000000
|
||||
Values:
|
||||
- {fileID: 6605851554665993113}
|
||||
--- !u!114 &2102942924974739106
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4c3631f5e58749a59194e0cf6baf6d5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_RequiresSettingsUpdate: 0
|
||||
m_AutomaticLoading: 0
|
||||
m_AutomaticRunning: 0
|
||||
m_Loaders:
|
||||
- {fileID: 11400000, guid: a25d5a0e12be3664da944c68c3bbcd6b, type: 2}
|
||||
--- !u!114 &6605851554665993113
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d236b7d11115f2143951f1e14045df39, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_LoaderManagerInstance: {fileID: 2102942924974739106}
|
||||
m_InitManagerOnStart: 1
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c49ddd5c17188674cbc8a8202417d809
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/XRI.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/XRI.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4209dd8ed8b68e47bed72c57621dc31
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/XRI/Settings.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/XRI/Settings.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 899d7e70781ccdc4fb59d70722dadd8a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
unity/XR_RM_PICO_UDP_Sender/Assets/XRI/Settings/Resources.meta
Executable file
8
unity/XR_RM_PICO_UDP_Sender/Assets/XRI/Settings/Resources.meta
Executable file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b10eaead46d3ca344a76e7354c02a5a9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,47 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 191492db6e452eb468b95433ec162164, type: 3}
|
||||
m_Name: InteractionLayerSettings
|
||||
m_EditorClassIdentifier:
|
||||
m_LayerNames:
|
||||
- Default
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eb3833504bb18c45b28f88ac198d88e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,17 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 690929a59dc7a42da9030305190d391f, type: 3}
|
||||
m_Name: XRDeviceSimulatorSettings
|
||||
m_EditorClassIdentifier:
|
||||
m_AutomaticallyInstantiateSimulatorPrefab: 0
|
||||
m_AutomaticallyInstantiateInEditorOnly: 1
|
||||
m_SimulatorPrefab: {fileID: 0}
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59629bd48a2904f4dbf31e7642c990cc
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,16 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 2d38fb1463c5c804b8847c20e8873623, type: 3}
|
||||
m_Name: XRInteractionEditorSettings
|
||||
m_EditorClassIdentifier:
|
||||
m_InteractionLayerUpdaterShown: 1
|
||||
m_ShowOldInteractionLayerMaskInInspector: 0
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8503bf4d9a0202a40a1ff4c4676ccad4
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user