123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- //======= Copyright (c) Stereolabs Corporation, All rights reserved. ===============
- using UnityEngine;
- using System.IO;
- #if UNITY_EDITOR
- using UnityEditor;
- #endif
- /// <summary>
- /// Saves and loads the pose of this object relative to its parent.
- /// Used primarily when mounting the ZED to a tracked object (like a VR controller) for 3rd person mixed reality.
- /// This way, you can calibrate its position/rotation to line up the real/virtual worlds, and hit Save.
- /// It will automatically load a calibration in the future if it's found.
- /// Note that if you used our beta tool for SteamVR calibration, this script will load that calibration automatically.
- /// </summary>
- public class ZEDOffsetController : MonoBehaviour
- {
- /// <summary>
- /// ZED offset file name.
- /// </summary>
- [SerializeField]
- public static string ZEDOffsetFile = "ZED_Position_Offset.conf";
- /// <summary>
- /// Where to save the ZED offset file.
- /// </summary>
- private string path = @"Stereolabs\steamvr";
- /// <summary>
- /// The ZEDControllerTracker object in the scene from which we're offset.
- /// This script checks this object, its parents and its children (in that order) for such a component.
- /// </summary>
- public ZEDControllerTracker controllerTracker;
- /// <summary>
- /// If the object is instantiated and ready to save/load an offset file.
- /// Used by the custom Inspector editor to know if the Save/Load buttons should be pressable.
- /// </summary>
- public bool isReady = false;
- /// <summary>
- /// Save the local position/rotation of the ZED into an offset file.
- /// </summary>
- public void SaveZEDPos()
- {
- using (System.IO.StreamWriter file = new System.IO.StreamWriter(path))
- {
- string tx = "x=" + transform.localPosition.x.ToString() + " //Translation x";
- string ty = "y=" + transform.localPosition.y.ToString() + " //Translation y";
- string tz = "z=" + transform.localPosition.z.ToString() + " //Translation z";
- string rx = "rx=" + transform.localRotation.eulerAngles.x.ToString() + " //Rotation x";
- string ry = "ry=" + transform.localRotation.eulerAngles.y.ToString() + " //Rotation y";
- string rz = "rz=" + transform.localRotation.eulerAngles.z.ToString() + " //Rotation z";
- //Write those values into the file.
- file.WriteLine(tx);
- file.WriteLine(ty);
- file.WriteLine(tz);
- file.WriteLine(rx);
- file.WriteLine(ry);
- file.WriteLine(rz);
- #if ZED_STEAM_VR
- if (TrackerComponentExist())
- {
- //If using SteamVR, get the serial number of the tracked device, or write "NONE" to indicate we checked but couldn't find it.
- string result = "indexController = ";
- if (controllerTracker.index > 0)
- {
- var snerror = Valve.VR.ETrackedPropertyError.TrackedProp_Success;
- var snresult = new System.Text.StringBuilder((int)64);
- result += Valve.VR.OpenVR.System.GetStringTrackedDeviceProperty((uint)controllerTracker.index, Valve.VR.ETrackedDeviceProperty.Prop_SerialNumber_String, snresult, 64, ref snerror);
- //OpenVR.System.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_SerialNumber_String, snresult, 64, ref snerror);
- }
- else
- {
- result += "NONE";
- }
- file.WriteLine(result);
- }
- #endif
- file.Close(); //Finalize the new file.
- }
- }
- /// <summary>
- /// Whether there is a referenced ZEDControllerTracker object in this object, a parent, or a child.
- /// </summary>
- /// <returns>True if such a component exists and is used to handle the offset.</returns>
- public bool TrackerComponentExist()
- {
- if (controllerTracker != null)
- return true;
- else
- return false;
- }
- private void OnEnable()
- {
- LoadTrackerComponent();
- }
- /// <summary>
- /// Searched for a ZEDControllerTracker component in this object, its parents, and its children.
- /// Sets the controllerTracker value to the first one it finds.
- /// </summary>
- private void LoadTrackerComponent()
- {
- ZEDControllerTracker zct = GetComponent<ZEDControllerTracker>();
- if (zct == null)
- zct = GetComponentInParent<ZEDControllerTracker>();
- if (zct == null)
- zct = GetComponentInChildren<ZEDControllerTracker>();
- if (zct != null)
- controllerTracker = zct;
- }
- /// <summary>
- /// Tries to find the relevant ZEDControllerTracker object, and loads the existing
- /// offset file if there is one.
- /// </summary>
- void Awake()
- {
- LoadTrackerComponent();
- string folder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
- string specificFolder = Path.Combine(folder, @"Stereolabs\steamvr");
- path = Path.Combine(specificFolder, ZEDOffsetFile);
- // Check if folder exists and if not, create it
- if (!Directory.Exists(specificFolder))
- Directory.CreateDirectory(specificFolder);
- LoadZEDPos();
- CreateFileWatcher(specificFolder);
- isReady = true;
- }
- private void Update()
- {
- if (isReady)
- LoadZEDPos();
- }
- /// <summary>
- /// Loads the offset file and sets the local position/rotation to the loaded values.
- /// </summary>
- public void LoadZEDPos()
- {
- if (!System.IO.File.Exists(path)) return;
- string[] lines = null;
- try
- {
- lines = System.IO.File.ReadAllLines(path);
- }
- catch (System.Exception)
- {
- controllerTracker.SNHolder = "NONE";
- }
- if (lines == null)
- {
- controllerTracker.SNHolder = "NONE";
- return;
- }
- if (lines == null) return;
- Vector3 position = new Vector3(0, 0, 0);
- Vector3 eulerRotation = new Vector3(0, 0, 0);
- foreach (string line in lines)
- {
- string[] splittedLine = line.Split('=');
- if (splittedLine != null && splittedLine.Length >= 2)
- {
- string key = splittedLine[0];
- string field = splittedLine[1].Split(' ')[0];
- if (key == "x")
- {
- position.x = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture);
- }
- else if (key == "y")
- {
- position.y = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture);
- }
- else if (key == "z")
- {
- position.z = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture);
- }
- else if (key == "rx")
- {
- eulerRotation.x = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture);
- }
- else if (key == "ry")
- {
- eulerRotation.y = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture);
- }
- else if (key == "rz")
- {
- eulerRotation.z = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture);
- }
- else if (key == "indexController")
- {
- LoadTrackerComponent();
- if (TrackerComponentExist())
- {
- controllerTracker.SNHolder = field;
- }
- }
- }
- }
- transform.localPosition = position;
- transform.localRotation = Quaternion.Euler(eulerRotation.x, eulerRotation.y, eulerRotation.z);
- }
- /// <summary>
- /// Creates a FileSystemWatcher that keeps track of the offset file, in case it
- /// changes or moves.
- /// </summary>
- /// <param name="path"></param>
- public void CreateFileWatcher(string path)
- {
- // Create a new FileSystemWatcher and set its properties.
- FileSystemWatcher watcher = new FileSystemWatcher();
- watcher.Path = path;
- /* Watch for changes in LastAccess and LastWrite times, and
- the renaming of files or directories. */
- watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
- | NotifyFilters.FileName | NotifyFilters.DirectoryName;
- // Only watch text files.
- watcher.Filter = ZEDOffsetFile;
- // Add event handlers.
- watcher.Changed += new FileSystemEventHandler(OnChanged);
- // Begin watching.
- watcher.EnableRaisingEvents = true;
- }
- /// <summary>
- /// Event handler for when the offset file changes or moves.
- /// Called by the FileSystemWatcher created in CreateFileWatcher().
- /// </summary>
- /// <param name="source"></param>
- /// <param name="e"></param>
- private void OnChanged(object source, FileSystemEventArgs e)
- {
- if (TrackerComponentExist())
- {
- LoadZEDPos();
- }
- }
- }
- #if UNITY_EDITOR
- /// <summary>
- /// Custom editor for ZEDOffsetController, to define its Inspector layout.
- /// Specifically, it doesn't draw public fields like normal but instead places Save/Load buttons
- /// for the offset file that are only pressable during runtime.
- /// </summary>
- [CustomEditor(typeof(ZEDOffsetController))]
- public class ZEDPositionEditor : Editor
- {
- private ZEDOffsetController positionManager;
- public void OnEnable()
- {
- positionManager = (ZEDOffsetController)target;
- }
- public override void OnInspectorGUI() //Called when the Inspector GUI becomes visible, or changes at all.
- {
- GUILayout.Space(5);
- EditorGUILayout.BeginHorizontal();
- EditorGUILayout.EndHorizontal();
- EditorGUILayout.BeginHorizontal();
- GUI.enabled = positionManager.isReady;
- GUIContent savecontent = new GUIContent("Save Offset", "Saves the object's local position/rotation to a text file to be loaded anytime in the future.");
- if (GUILayout.Button(savecontent))
- {
- positionManager.SaveZEDPos();
- }
- GUIContent loadcontent = new GUIContent("Load Offset", "Loads local position/rotation from an offset file previously saved, or created by the beta ZED calibration tool.");
- if (GUILayout.Button(loadcontent))
- {
- positionManager.LoadZEDPos();
- }
- EditorGUILayout.EndHorizontal();
- }
- }
- #endif
|