Tanoda
LeapRigUpgrader.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
9using Leap.Unity.Query;
10using System;
11using System.Collections.Generic;
12using System.Text;
13using UnityEditor;
14using UnityEditor.SceneManagement;
15using UnityEngine;
16using UnityEngine.SceneManagement;
17
18namespace Leap.Unity {
19
20 using UnityObject = UnityEngine.Object;
21
27 [InitializeOnLoad]
28 public static class LeapRigUpgrader {
29
30 #region Events
31
32 public enum SceneScanStatus { NotScanned, ContainsOldRigs, NoOldRigsFound }
33 private static SceneScanStatus _currentSceneScanStatus = SceneScanStatus.NotScanned;
34 public static SceneScanStatus currentSceneScanStatus {
35 get {
36 return _currentSceneScanStatus;
37 }
38 }
39
40 [InitializeOnLoadMethod]
41 private static void Init() {
42 EditorSceneManager.sceneOpened -= onSceneOpened;
43 EditorSceneManager.sceneOpened += onSceneOpened;
44
45 #if UNITY_2018_1_OR_NEWER
46 EditorApplication.hierarchyChanged -= onHierarchyChanged;
47 EditorApplication.hierarchyChanged += onHierarchyChanged;
48 #else
49 EditorApplication.hierarchyWindowChanged -= onHierarchyChanged;
50 EditorApplication.hierarchyWindowChanged += onHierarchyChanged;
51 #endif
52
53 _currentSceneScanStatus = SceneScanStatus.NotScanned;
54 }
55
56 private static void onSceneOpened(Scene scene, OpenSceneMode openSceneMode) {
57 _currentSceneScanStatus = SceneScanStatus.NotScanned;
58 ClearScanData();
59 }
60 private static void onHierarchyChanged() {
61 _currentSceneScanStatus = SceneScanStatus.NotScanned;
62 ClearScanData();
63 }
64
65 #endregion
66
67 #region GUI Drawing
68
69 #region Convenience Properties
70
71 public static GUIStyle boldLabel {
72 get { return EditorStyles.boldLabel; }
73 }
74
75 private static GUIStyle _backingWrapLabel;
76 public static GUIStyle wrapLabel {
77 get {
78 if (_backingWrapLabel == null) {
79 _backingWrapLabel = new GUIStyle(EditorStyles.label);
80 _backingWrapLabel.wordWrap = true;
81 }
82 return _backingWrapLabel;
83 }
84 }
85
86 #endregion
87
88 #region Project Check GUI
89
94 [LeapProjectCheck("Core", 0)]
95 private static bool drawRigUpgraderCheckGUI() {
96 EditorGUILayout.LabelField("Leap Rig Upgrader", boldLabel);
97
98 EditorGUILayout.LabelField(
99 "If you have upgraded from Core version 4.3.4 or earlier to Core version 4.4 or "
100 + "later, you can check the currently-open scene for out-of-date rigs. Instances of "
101 + "older Leap Rig prefabs can be automatically upgraded to match the updated rig, "
102 + "which is much simpler.",
103 wrapLabel);
104
105 EditorGUILayout.Space();
106
107 drawScanCurrentSceneButtonAndStatus();
108
109 EditorGUILayout.Space();
110
111 return true;
112 }
113
114 private static void drawScanCurrentSceneButtonAndStatus() {
115
116 using (new EditorGUILayout.HorizontalScope()) {
117 if (GUILayout.Button(new GUIContent("Scan Current Scene"),
118 GUILayout.MaxWidth(200f))) {
119 var oldRigsDetected = ScanCurrentSceneForOldLeapRigs();
120 if (oldRigsDetected) {
121 _currentSceneScanStatus = SceneScanStatus.ContainsOldRigs;
122 if (LeapUnityWindow.isWindowOpen) {
123 LeapUnityWindow.ShowTab(1);
124 }
125 }
126 else {
127 _currentSceneScanStatus = SceneScanStatus.NoOldRigsFound;
128 }
129 }
130
131 string scanText;
132 switch (_currentSceneScanStatus) {
133 case SceneScanStatus.ContainsOldRigs:
134 scanText = "Scene contained old Leap rigs as of the last scan.";
135 break;
136 case SceneScanStatus.NoOldRigsFound:
137 scanText = "Scene contained no old Leap rigs as of the last scan.";
138 break;
139 case SceneScanStatus.NotScanned:
140 default:
141 scanText = "Scene not yet scanned.";
142 break;
143 }
144 EditorGUILayout.LabelField(scanText);
145 }
146 }
147
148 #endregion
149
150 #region Upgrader GUI
151
152 private static Vector2 _scrollPosition = Vector2.zero;
153 private static Dictionary<OldRigHierarchy, bool> _rigFoldoutStates
154 = new Dictionary<OldRigHierarchy, bool>();
155 private static OldRigHierarchy.UpgradeOptions _upgradeOptions
156 = new OldRigHierarchy.UpgradeOptions();
157
158 public static void DrawUpgraderGUI() {
159 var origIndent = EditorGUI.indentLevel;
160 EditorGUI.indentLevel = 0;
161
162 using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
163 drawRigUpgraderCheckGUI();
164 }
165
166 EditorGUILayout.Space();
167 EditorGUILayout.Space();
168
169 drawRigScanResultsGUI();
170
171 var splitterStyle = new GUIStyle(LeapUnityWindow.windowSkin.box);
172 splitterStyle.fixedHeight = 1f;
173 splitterStyle.stretchWidth = true;
174 splitterStyle.margin = new RectOffset(0, 0, 0, 0);
175 GUILayout.Box("", splitterStyle);
176
177 _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition,
178 GUILayout.ExpandWidth(true));
179
180 foreach (var oldRig in _oldRigs) {
181 EditorGUILayout.Space();
182 drawOldRigUpgradeGUI(oldRig);
183 }
184
185 EditorGUILayout.EndScrollView();
186
187 EditorGUI.indentLevel = origIndent;
188 }
189
190 private static void drawRigScanResultsGUI() {
191 var safetyWarning = "To be safe, you should make sure you've backed up your scene "
192 + "before upgrading.";
193 EditorGUILayout.LabelField(safetyWarning, wrapLabel);
194
195 var singleRig = _oldRigs.Count == 1;
196 EditorGUILayout.LabelField(
197 "Detected " + _oldRigs.Count + " old rig"
198 + (singleRig ? "" : "s") + ". "
199 , wrapLabel);
200 }
201
202 private static void drawOldRigUpgradeGUI(OldRigHierarchy oldRig) {
203 using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
204
205 var rigDescFoldoutState = false;
206 if (!_rigFoldoutStates.TryGetValue(oldRig, out rigDescFoldoutState)) {
207 _rigFoldoutStates[oldRig] = false;
208 }
209 string foldoutName = getName(oldRig.rigTransform);
210 if (!rigDescFoldoutState) {
211 foldoutName += " (click to expand upgrade details)";
212 }
213 else {
214 foldoutName += " (click to hide upgrade details)";
215 }
216 using (new EditorGUILayout.HorizontalScope()) {
217 _rigFoldoutStates[oldRig] = EditorGUILayout.Foldout(_rigFoldoutStates[oldRig],
218 foldoutName, toggleOnLabelClick: true);
219
220 EditorGUI.BeginDisabledGroup(true);
221 EditorGUILayout.ObjectField(oldRig.rigTransform, typeof(Transform), true,
222 GUILayout.ExpandWidth(false));
223 EditorGUI.EndDisabledGroup();
224 }
225
226 if (_rigFoldoutStates[oldRig]) {
227 EditorGUILayout.Space();
228
229 drawOldRigCameraGUI(oldRig);
230
231 drawOldRigLeapSpaceGUI(oldRig);
232
233 drawOldRigLHCGUI(oldRig);
234 }
235
236 if (GUILayout.Button("Update Rig")) {
237 oldRig.Upgrade(_upgradeOptions);
238
239 EditorApplication.delayCall += () => {
240 ScanCurrentSceneForOldLeapRigs();
241 };
242 }
243 }
244 }
245
246 #region Old Rig Component Drawing
247
248 private static void drawOldRigCameraGUI(OldRigHierarchy oldRig) {
249 EditorGUI.indentLevel = 1;
250 drawRigItem("Rig Camera", oldRig.cameraData.cameraComponent,
251 typeof(Camera));
252 EditorGUI.indentLevel = 2;
253
254 var camera_enableDepthBuffer = oldRig.cameraData.enableDepthBuffer;
255 if (camera_enableDepthBuffer != null) {
256 EditorGUILayout.Space();
257 drawRigItem("Remove Enable Depth Buffer", camera_enableDepthBuffer,
258 typeof(EnableDepthBuffer));
259 EditorGUILayout.LabelField(
260 "The EnableDepthBuffer script used to be a part of Leap camera rigs by "
261 + "default but can cause shader issues in certain situations. If you're "
262 + "not sure you need this component, you should remove it.",
263 wrapLabel);
264 drawYesNoToggle(
265 yesOption: "Remove the EnableDepthBuffer script from the camera.",
266 noOption: "Don't remove the EnableDepthBuffer script, I'm using it for "
267 + "something.",
268 yesOptionFlag: ref _upgradeOptions.camera_removeEnableDepthBufferScript
269 );
270 }
271
272
273 if (oldRig.isImageRig) {
274 EditorGUILayout.Space();
275 var rightEyeCamera = oldRig.imageRigData.rightEyeCamData.cameraComponent;
276 if (rightEyeCamera != null) {
277 drawRigItem("Remove Right Eye Camera", rightEyeCamera, typeof(Camera));
278 EditorGUILayout.LabelField(
279 "Separate cameras for the left and right eyes are no longer necessary "
280 + "for IR viewer rigs.",
281 wrapLabel
282 );
283 drawYesNoToggle(
284 yesOption: "Remove this camera object.",
285 noOption: "Don't remove this camera, I'm using it for something else.",
286 yesOptionFlag: ref _upgradeOptions.camera_removeRightEyeCamera
287 );
288 }
289 }
290 else {
291 EditorGUILayout.Space();
292 var primaryLeapEyeDislocator = oldRig.cameraData.leapEyeDislocator;
293 if (primaryLeapEyeDislocator != null) {
294 drawRigItem("Remove Leap Eye Dislocator", primaryLeapEyeDislocator,
295 typeof(LeapEyeDislocator));
296 EditorGUILayout.LabelField(
297 "LeapEyeDislocator was found on this object, but it was not detected "
298 + "to be an IR viewer rig. LeapEyeDislocator is not necessary "
299 + "on non-IR viewer rigs.",
300 wrapLabel
301 );
302 drawYesNoToggle(
303 yesOption: "Remove the LeapEyeDislocator script from the camera.",
304 noOption: "Don't remove LeapEyeDislocator.",
305 yesOptionFlag: ref _upgradeOptions.camera_removeLeapEyeDislocator
306 );
307 }
308 }
309
310 EditorGUILayout.Space();
311 }
312
313 private static void drawOldRigLeapSpaceGUI(OldRigHierarchy oldRig) {
314 EditorGUILayout.Space();
315 EditorGUI.indentLevel = 1;
316 drawRigItem("LeapSpace Transform (to be deleted.)",
317 oldRig.leapSpaceData.leapSpaceTransform, typeof(Transform));
318 EditorGUI.indentLevel = 2;
319 EditorGUILayout.LabelField(
320 "The LeapSpace transform and its temporal warping functionality have been "
321 + "migrated into the LeapXRServiceProvider for XR rigs. As a part of this upgrade, "
322 + "this transform (including any components on it) will be deleted.",
323 wrapLabel);
324
325 var leapSpace_nonLHCChildren
326 = oldRig.leapSpaceData.nonLHCChildTransforms;
327 if (leapSpace_nonLHCChildren.Count > 0) {
328 EditorGUILayout.Space();
329 drawMergeUpwardsSetting(
330 originalTransformName: "LeapSpace",
331 numExtraChildren: leapSpace_nonLHCChildren.Count,
332 mergeExtraChildrenUpwardFlag:
333 ref _upgradeOptions.leapSpace_mergeExtraChildrenUpward
334 );
335 }
336
337 EditorGUILayout.Space();
338 }
339
340 private static void drawOldRigLHCGUI(OldRigHierarchy oldRig) {
341 EditorGUILayout.Space();
342 EditorGUI.indentLevel = 1;
343 drawRigItem("LeapHandController Transform (to be deleted.)",
344 oldRig.lhcData.leapServiceProvider, typeof(Transform));
345 EditorGUI.indentLevel = 2;
346 EditorGUILayout.LabelField(
347 "The LeapHandController transform and its LeapHandController, "
348 + "LeapServiceProvider, and HandPool components have been simplified.",
349 wrapLabel);
350
351 EditorGUILayout.LabelField(
352 "The LeapServiceProvider will be removed. In its place, a "
353 + "LeapXRServiceProvider will be added directly to the Camera. The "
354 + "LeapXRServiceProvider handles temporal warping (latency correction) "
355 + "automatically for XR rigs. Applicable settings will be transferred to "
356 + "the LeapXRServiceProvider.", wrapLabel);
357
358 EditorGUILayout.LabelField(
359 "The HandPool and HandController objects have been combined into a single "
360 + "HandModelManager script, which should be moved to the parent transform of the "
361 + "hand models. This clarifies its separation from the hand data pipeline "
362 + "as one of (potentially many) consumers of hand data from a device.",
363 wrapLabel);
364
365 var handModelParent = oldRig.handModelParentTransform;
366 var handModelManager = oldRig.lhcData.handModelManager;
367 if (handModelParent != null && handModelManager != null) {
368 EditorGUILayout.Space();
369 drawRigItem("Move the HandModelManager...", handModelManager, typeof(HandModelManager));
370 drawRigItem("...to the hand model parent transform", handModelParent, typeof(Transform));
371 EditorGUILayout.LabelField(
372 "The HandModelManager will be moved to the " + handModelParent.name
373 + " transform because it is the parent transform of the hand models.",
374 wrapLabel);
375 }
376 else {
377 // decided against adding a HandModelManager if none already exists.
378 }
379
380 var lhc_extraComponents = oldRig.lhcData.extraComponents;
381 if (lhc_extraComponents != null && lhc_extraComponents.Count > 0) {
382 EditorGUILayout.Space();
383 drawRigItem("Extra Components Detected", null, null);
384
385 var sb = new StringBuilder();
386 sb.Append("The ");
387 for (int i = 0; i < lhc_extraComponents.Count; i++) {
388 var component = lhc_extraComponents[i];
389 sb.Append(component.GetType().Name);
390 if (i != lhc_extraComponents.Count - 1) sb.Append(", ");
391 if (i == lhc_extraComponents.Count - 2) sb.Append("and ");
392 }
393 var isPlural = lhc_extraComponents.Count != 1;
394 if (isPlural) {
395 sb.Append(" components (and references to them) will be migrated to the camera "
396 + "transform.");
397 }
398 else {
399 sb.Append(" component (and references to it) will be migrated to the camera "
400 + "transform.");
401 }
402
403 EditorGUILayout.LabelField(
404 sb.ToString(),
405 wrapLabel);
406 }
407
408 var lhc_extraChildren = oldRig.lhcData.extraChildTransforms;
409 if (lhc_extraChildren.Count > 0) {
410 EditorGUILayout.Space();
411 drawMergeUpwardsSetting(
412 originalTransformName: "LeapHandController",
413 numExtraChildren: lhc_extraChildren.Count,
414 mergeExtraChildrenUpwardFlag: ref _upgradeOptions.lhc_mergeExtraChildrenUpward
415 );
416 }
417 }
418
419 #endregion
420
421 #region Drawing Helper Methods
422
423 private static void drawRigItem(string label, UnityObject obj, Type objType) {
424 using (new EditorGUILayout.HorizontalScope()) {
425 EditorGUILayout.LabelField(label, GUILayout.ExpandWidth(true));
426 if (obj != null) {
427 EditorGUI.BeginDisabledGroup(true);
428 EditorGUILayout.ObjectField(obj, objType, true, GUILayout.ExpandWidth(false));
429 EditorGUI.EndDisabledGroup();
430 }
431 }
432 }
433
434 private static void drawMergeUpwardsSetting(string originalTransformName,
435 int numExtraChildren,
436 ref bool mergeExtraChildrenUpwardFlag) {
437 var isPlural = numExtraChildren == 1;
438 EditorGUILayout.LabelField(
439 numExtraChildren
440 + (isPlural ? " transforms are attached as children "
441 : " transform is attached as a child")
442 + " to the " + originalTransformName + " transform, which is deprecated and will be "
443 + "removed.",
444 wrapLabel);
445 drawYesNoToggle(
446 yesOption: "Move these objects to be children of the camera.",
447 noOption: "Remove these objects.",
448 yesOptionFlag: ref mergeExtraChildrenUpwardFlag
449 );
450 }
451
452 private static void drawYesNoToggle(string yesOption, string noOption,
453 ref bool yesOptionFlag) {
454 yesOptionFlag = EditorGUILayout.ToggleLeft(yesOption, yesOptionFlag);
455
456 bool temp = EditorGUILayout.ToggleLeft(noOption, !yesOptionFlag);
457 yesOptionFlag = !temp;
458 }
459
460 private static void drawObjField(UnityObject obj, Type objType) {
461 EditorGUI.BeginDisabledGroup(true);
462 EditorGUILayout.ObjectField(obj, objType, true);
463 EditorGUI.EndDisabledGroup();
464 }
465
466 private static string getName(Transform t) {
467 if (t == null) return "";
468 return t.name;
469 }
470
471 #endregion
472
473 #endregion
474
475 #endregion
476
477 #region Upgrader Memory
478
479 private static List<Transform> _backingTransformsBuffer = null;
480 private static List<Transform> _transformsBuffer {
481 get {
482 if (_backingTransformsBuffer == null)
483 _backingTransformsBuffer = new List<Transform>();
484 return _backingTransformsBuffer;
485 }
486 }
487
488 private static List<OldRigHierarchy> _backingOldRigs = null;
489 private static List<OldRigHierarchy> _oldRigs {
490 get {
491 if (_backingOldRigs == null) {
492 _backingOldRigs = new List<OldRigHierarchy>();
493 }
494 return _backingOldRigs;
495 }
496 }
497
498 #endregion
499
500 #region Scan Methods
501
505 public static void ClearScanData() {
506 _oldRigs.Clear();
507 }
508
514 public static bool ScanCurrentSceneForOldLeapRigs() {
515 ClearScanData();
516
517 var currentScene = SceneManager.GetActiveScene();
518 var rootObjs = currentScene.GetRootGameObjects();
519 foreach (var rootObj in rootObjs) {
520 rootObj.transform.GetComponentsInChildren(_transformsBuffer);
521 foreach (var transform in _transformsBuffer) {
522 var oldRig = OldRigHierarchy.DetectFor(transform);
523 if (oldRig != null) {
524 _oldRigs.Add(oldRig);
525 }
526 }
527 _transformsBuffer.Clear();
528 }
529
530 return _oldRigs.Count > 0;
531 }
532
533 #endregion
534
535 }
536
592 public class OldRigHierarchy {
593
594 #region Status State
595
599 public bool isUpgradeableOldRig = false;
600
605 public bool detectedAsPotentialRig = false;
606
612 = "Rig data has not been collected. Call OldRigHierarchy.DetectFor(transform) to "
613 + "scan.";
614
615 #endregion
616
617 #region Scanned Rig Data
618
620 public Transform rigTransform;
621
625 public Transform handModelParentTransform;
626
627 #region Rig Camera Data
628
634 public class OldCameraData {
635 public Transform cameraTransform;
638 public Camera cameraComponent;
639
640 public bool containsCameraComponent { get { return cameraComponent != null; } }
641 }
647
648 #endregion
649
650 #region Other Rig Data
651
652 public class OldLeapSpaceData {
653 public Transform leapSpaceTransform;
654
660 public List<Transform> nonLHCChildTransforms;
661 }
663
665 public Transform lhcTransform;
668 public List<Transform> extraChildTransforms;
669 public List<Component> extraComponents;
670 }
672
673 public class ImageRigData {
675 }
677 public bool isImageRig { get { return imageRigData != null; } }
678
679 #endregion
680
681 #endregion
682
683 #region Scanning
684
690 public static bool DetectFor(Transform transform, OldRigHierarchy toFill) {
691 if (transform == null) return false;
692
693 var didDetectOldRig = false;
694 var scannedRig = toFill;
695 scannedRig.rigTransform = transform;
696
697 // Scan for the camera transform in immediate children.
698 var camDataBuffer = new List<OldCameraData>();
699 camDataBuffer.Clear();
700 detectPotentialOldRigCameras(transform, camDataBuffer);
701
702 if (camDataBuffer.Count == 0) {
703 // No cameras found; this is not an upgradeable old rig.
704 return false;
705 }
706 else {
707 // We have a list of children that contain Camera components and potentially
708 // other Leap rig-related data, but the check was intentionally loose.
709
710 // Some practical cases to consider, if there was only one camera found:
711 // (1) It could be a standard non-image rig, and so is upgradeable!
712 // (2) It could be an image rig but with one eye removed (weird).
713 // (2a) If the left eye was removed, the rig is non-upgradeable.
714 // (2b) If the right eye was removed, this rig will look identical to a
715 // non-image rig as in (1) and be upgradeable.
716 // (3) It could just be an object with a Camera component beneath it, and be
717 // unrelated to a Leap VR rig. (Looks similar to 2a but with fewer
718 // Leap-related or Missing components.)
719 //
720 // To confirm it is NOT (3) or (2a), we need to check its children to
721 // find the LeapSpace and LeapHandController.
722
723 // Alternatively, if there were two potential cameras found:
724 // (1) Optimistically, this could indicate it's an old image rig with a left
725 // and right eye.
726 // (2) It could be a stranger construction, like the rig for a custom VR
727 // integration.
728 // (3) It could be a standard single-camera non-image rig with another Camera
729 // utilized for some other, distinct purpose.
730 // (4) It could just be a transform with two cameras as children and not be
731 // Leap-related!
732
733 // To be an upgradeable Leap Rig, image or otherwise, one of the cameras we've
734 // found must have a LeapServiceProvider two transforms down (we don't actually
735 // care what transforms are named, since someone could change them without
736 // really affecting the structure of the rig):
737 //
738 // (Camera)
739 // |
740 // `- LeapSpace - Missing Component // optional, formerly LeapVRTemporalWarping
741 // |
742 // `- LeapHandController - LeapServiceProvider // required
743 // HandModelManager // optional
744 //
745 // If there is no LeapServiceProvider two-transforms-down, the rig has been
746 // modified too heavily and is no longer auto-upgradeable.
747 //
748 // Importantly, this condition will hold true if the rig is a non-image rig OR
749 // an image rig, and false if we are going to refuse the upgrade. What's more,
750 // if this condition holds true, we will be able to collect all the information
751 // we need from the rig after scanning through each camera.
752
753 var primaryCamData = (OldCameraData)null;
754 var firstLeapSpaceData = (OldLeapSpaceData)null;
755 var firstLHCData = (OldLeapHandControllerData)null;
756
757 // "Secondary" cameras in the rig are the cameras that don't have LeapSpace or
758 // LeapHandController objects (or weren't searched for these if we already
759 // found a primary camera).
760 // These need to be searched after we find the primary camera to find the
761 // right -eye camera in the image rig case.
762 var secondaryCamDatas = new List<OldCameraData>();
763
764 for (int i = 0; i < camDataBuffer.Count; i++) {
765 var camData = camDataBuffer[i];
766 var expectingFirstLeapSpaceData = firstLeapSpaceData == null;
767
768 var camTransform = camData.cameraTransform;
769 foreach (var child in camTransform.GetChildren()) {
770 var expectingFirstLHCData = firstLHCData == null;
771
772 // We're looking for the child that is the LeapSpace transform, only
773 // known implicitly by looking at _its_ children.
774 foreach (var grandchild in child.GetChildren()) {
775 var leapServiceProvider = grandchild.GetComponent<LeapServiceProvider>();
776
777 // We're going to assume the first LeapServiceProvider we find is
778 // indicative of an old, upgradeable rig, and construct out the
779 // definition from there.
780 if (leapServiceProvider != null) {
781 firstLHCData = new OldLeapHandControllerData();
782 firstLHCData.lhcTransform = grandchild;
783 firstLHCData.leapServiceProvider = leapServiceProvider;
784
785 firstLHCData.extraChildTransforms = new List<Transform>();
786 foreach (var greatGrandchild in grandchild.GetChildren()) {
787 firstLHCData.extraChildTransforms.Add(greatGrandchild);
788 }
789
790 firstLHCData.handModelManager
791 = grandchild.GetComponent<HandModelManager>();
792
793 var components = grandchild.GetComponents<Component>();
794 foreach (var component in components) {
795 if (component == null) continue; // ignore "Missing Script"
796 if (component == firstLHCData.lhcTransform) continue;
797 if (component == firstLHCData.leapServiceProvider) continue;
798 if (component == firstLHCData.handModelManager) continue;
799
800 if (firstLHCData.extraComponents == null) {
801 firstLHCData.extraComponents = new List<Component>();
802 }
803 firstLHCData.extraComponents.Add(component);
804 }
805
806 break;
807 }
808 }
809
810 if (firstLHCData != null && expectingFirstLHCData) {
811 firstLeapSpaceData = new OldLeapSpaceData();
812 firstLeapSpaceData.leapSpaceTransform = child;
813 firstLeapSpaceData.nonLHCChildTransforms = new List<Transform>();
814 foreach (var leapSpaceChild in child.GetChildren()) {
815 if (leapSpaceChild == firstLHCData.lhcTransform) continue;
816 firstLeapSpaceData.nonLHCChildTransforms.Add(leapSpaceChild);
817 }
818 break;
819 }
820 }
821
822 if (firstLeapSpaceData != null && expectingFirstLeapSpaceData) {
823 // This is our primary camera.
824 primaryCamData = camData;
825 }
826 else {
827 // Either we haven't found a LeapSpace yet or we've already found our first.
828 // So this is a secondary camera.
829 secondaryCamDatas.Add(camData);
830 }
831 }
832
833 // At the end of this process, we must have all three of these things in order
834 // to be an upgradeable rig:
835 // (1) a Primary camera, containing
836 // (2) a LeapSpace transform, containing
837 // (3) a LeapHandController transform
838
839 // If we don't have these things, we can't upgrade
840 // the rig! Not having these things, in fact, indicates it's probably not an
841 // old Leap rig at all.
842 if (primaryCamData == null) {
843 scannedRig.isUpgradeableOldRig = false;
844 scannedRig.cameraData = null;
845 scannedRig.detectedAsPotentialRig = false;
846 scannedRig.leapSpaceData = null;
847 scannedRig.lhcData = null;
848 scannedRig.handModelParentTransform = null;
849 scannedRig.reasonRigCannotBeUpgraded = "Scanned transform does not look like "
850 + "an old Leap rig.";
851 return false;
852 }
853 else {
854 // OK, we can upgrade this rig. Fill it with any remaining data we need.
855 didDetectOldRig = true;
856
857 scannedRig.cameraData = primaryCamData;
858 scannedRig.detectedAsPotentialRig = true;
859 scannedRig.leapSpaceData = firstLeapSpaceData;
860 scannedRig.lhcData = firstLHCData;
861 scannedRig.isUpgradeableOldRig = true;
862 scannedRig.reasonRigCannotBeUpgraded = "";
863
864 // Since we've come this far, we need to attempt to find the hand model
865 // parent transform. This will be the first child transform of the rig that
866 // contains one or more HandModelBase components.
867 // Not having one of these doesn't preclude updating the rig, since we can
868 // just make a new transform for this purpose.
869 var firstReasonableHandModelTransform = scannedRig.rigTransform.GetChildren()
870 .Query().Where(child =>
871 child.GetChildren().Query()
872 .Where(gc => gc.GetComponent<HandModelBase>() != null).Count() > 0)
873 .FirstOrDefault();
874 scannedRig.handModelParentTransform = firstReasonableHandModelTransform;
875
876 // If there is a LeapImageRetriever on the camera, this could well be an
877 // old Leap image rig, with two eyes.
878 var leapImageRetriever = primaryCamData.cameraTransform
879 .GetComponent<LeapImageRetriever>();
880 var rightEyeCamData = (OldCameraData)null;
881 if (leapImageRetriever != null) {
882 // If there is a secondary camera with a LeapEyeDislocator component, we'll
883 // assume that's the other (right) eye.
884 rightEyeCamData = secondaryCamDatas.Query()
885 .Where(cd => cd.cameraTransform.GetComponent<LeapEyeDislocator>() != null)
886 .FirstOrDefault();
887
888 if (rightEyeCamData != null) {
889 scannedRig.imageRigData = new ImageRigData();
890 scannedRig.imageRigData.rightEyeCamData = rightEyeCamData;
891 }
892 }
893 }
894 }
895
896 return didDetectOldRig;
897 }
898
903 private static void detectPotentialOldRigCameras(Transform rigTransform,
904 List<OldCameraData> detectedCameras) {
905 foreach (var child in rigTransform.GetChildren()) {
906 var eyeDislocator = child.GetComponent<LeapEyeDislocator>();
907 var camera = child.GetComponent<Camera>();
908 var leapXRProvider = child.GetComponent<LeapXRServiceProvider>();
909 var enableDepthBuffer = child.GetComponent<EnableDepthBuffer>();
910
911 if (camera == null) {
912 // Definitely no camera detected for this child.
913 continue;
914 }
915 else if (leapXRProvider != null) {
916 // A camera with a LeapXRServiceProvider on it is definitely not an old rig!
917 // This is probably an up-to-date rig.
918 continue;
919 }
920 else {
921 // OK, this could be an old rig camera. Get as much data as possible about it.
922 var oldCamData = new OldCameraData();
923 oldCamData.cameraTransform = child;
924 oldCamData.cameraComponent = camera;
925 oldCamData.leapEyeDislocator = eyeDislocator;
926 oldCamData.enableDepthBuffer = enableDepthBuffer;
927
928 // Add it to the detected cameras list. We'll process it more later.
929 detectedCameras.Add(oldCamData);
930 }
931 }
932 }
933
939 public static OldRigHierarchy DetectFor(Transform transform) {
940 var scannedRig = new OldRigHierarchy();
941 var didDetectOldRig = DetectFor(transform, scannedRig);
942 if (!didDetectOldRig) return null;
943 return scannedRig;
944 }
945
946 private static void fillMissingComponentIndices(Transform transform, List<int> toFill) {
947 toFill.Clear();
948 var tempList = new List<Component>();
949 transform.GetComponents(tempList);
950 for (int i = 0; i < tempList.Count; i++) {
951 var component = tempList[i];
952 if (component == null) {
953 toFill.Add(i);
954 }
955 }
956 }
957
958 #endregion
959
960 #region Upgrading
961
962 public class UpgradeOptions {
964 public bool camera_removeRightEyeCamera = true;
968 public bool lhc_removeMissingScripts = true;
970 }
971
972 public void Upgrade(UpgradeOptions options) {
973 if (options == null) { options = new UpgradeOptions(); }
974
975 if (!this.isUpgradeableOldRig) {
976 throw new InvalidOperationException(
977 "Aborting upgrade attempt: This rig is not upgradeable.");
978 }
979
980 // Rig transform: unmodified.
981
982 // Camera transform, then LeapSpace transform, then LHC transform.
983 if (cameraData == null) {
984 Debug.LogError("No camera data available for this rig during upgrade attempt.");
985 }
986 else {
987 var enableDepthBufferScript = this.cameraData.enableDepthBuffer;
989 && enableDepthBufferScript != null) {
990 Undo.DestroyObjectImmediate(enableDepthBufferScript);
991 }
992
993 var eyeDislocator = this.cameraData.leapEyeDislocator;
995 && eyeDislocator != null) {
996 Undo.DestroyObjectImmediate(eyeDislocator);
997 }
998
999 if (this.isImageRig) {
1000 var rightEyeCamData = this.imageRigData.rightEyeCamData;
1001 if (rightEyeCamData != null) {
1002 var rightEyeTransform = rightEyeCamData.cameraTransform;
1003 if (options.camera_removeRightEyeCamera
1004 && rightEyeTransform != null) {
1005 Undo.DestroyObjectImmediate(rightEyeTransform.gameObject);
1006 }
1007 }
1008 if (cameraData.cameraComponent != null
1009 && cameraData.cameraComponent.stereoTargetEye == StereoTargetEyeMask.Left) {
1010 cameraData.cameraComponent.stereoTargetEye = StereoTargetEyeMask.Both;
1011 }
1012 }
1013
1014 var cameraTransform = cameraData.cameraTransform;
1015
1016 if (leapSpaceData == null) {
1017 Debug.LogError("No LeapSpace data available for this rig during upgrade "
1018 + "attempt.");
1019 }
1020 else {
1021 var leapSpaceExtraChildren = leapSpaceData.nonLHCChildTransforms;
1023 && leapSpaceExtraChildren != null) {
1024 foreach (var extraChild in leapSpaceExtraChildren.Query().Where(t => t != null)) {
1025 Undo.SetTransformParent(extraChild, cameraTransform,
1026 "Move LeapSpace child to Camera");
1027 }
1028 }
1029
1030 var leapSpaceTransform = leapSpaceData.leapSpaceTransform;
1031
1032 if (lhcData == null) {
1033 Debug.LogError("No LeapHandController data available for this rig during "
1034 + "upgrade attempt.");
1035 }
1036 else {
1037 var lhcExtraChildren = lhcData.extraChildTransforms;
1039 && lhcExtraChildren != null) {
1040 foreach (var extraChild in lhcExtraChildren.Query().Where(t => t != null)) {
1041 Undo.SetTransformParent(extraChild, cameraTransform,
1042 "Move LHC child to Camera");
1043 }
1044 }
1045
1046 // Migrate the HandPool (now HandModelManager) to the hand model parent
1047 // transform if we could find one.
1048 var handModelManager = lhcData.handModelManager;
1049 var newHandModelManager = (HandModelManager)null;
1050 if (handModelManager != null && this.handModelParentTransform != null) {
1051 newHandModelManager
1052 = Undo.AddComponent<HandModelManager>(handModelParentTransform.gameObject);
1053 EditorUtility.CopySerialized(handModelManager, newHandModelManager);
1054
1055 EditorUtils.ReplaceSceneReferences(handModelManager, newHandModelManager);
1056 }
1057
1058 // Migrate the LeapServiceProvider on the LHC to a LeapXRServiceProvider on
1059 // the primary camera, and swap references over to it.
1060 var leapServiceProvider = lhcData.leapServiceProvider;
1061 var leapXRServiceProvider = (LeapXRServiceProvider)null;
1062 if (leapServiceProvider != null) {
1063 leapXRServiceProvider = Undo.AddComponent<LeapXRServiceProvider>(
1064 cameraData.cameraTransform.gameObject);
1065
1066 leapServiceProvider
1067 .CopySettingsToLeapXRServiceProvider(leapXRServiceProvider);
1068
1069 EditorUtils.ReplaceSceneReferences(leapServiceProvider,
1070 leapXRServiceProvider);
1071 }
1072
1073 if (newHandModelManager != null && leapXRServiceProvider != null) {
1074 newHandModelManager.leapProvider = leapXRServiceProvider;
1075 }
1076
1077 // Migrate any extra components on the LHC to the camera.
1078 var extraComponents = lhcData.extraComponents;
1079 if (extraComponents != null && extraComponents.Count > 0) {
1080 foreach (var component in extraComponents.Query().Where(c => c != null)) {
1081 var newComponent
1082 = cameraTransform.gameObject.AddComponent(component.GetType());
1083
1084 EditorUtility.CopySerialized(component, newComponent);
1085
1086 EditorUtils.ReplaceSceneReferences(component, newComponent);
1087 }
1088 }
1089 }
1090
1091 // Remove the LeapSpace transform, also destroying the LeapHandController
1092 // object.
1093 if (leapSpaceTransform != null) {
1094 Undo.DestroyObjectImmediate(leapSpaceTransform.gameObject);
1095 }
1096 }
1097 }
1098 }
1099
1100 #endregion
1101
1102 }
1103
1104}
1105
UnityEngine.Object UnityObject
UnityEngine.Component Component
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
The HandModelManager manages a pool of HandModelBases and makes HandRepresentations when a it detects...
Moves the camera to each eye position on pre-render. Only necessary for image pass-through (IR viewer...
Acquires images from a LeapServiceProvider and uploads image data as shader global data for use by an...
The LeapServiceProvider provides tracked Leap Hand data and images from the device via the Leap servi...
void CopySettingsToLeapXRServiceProvider(LeapXRServiceProvider leapXRServiceProvider)
Copies property settings from this LeapServiceProvider to the target LeapXRServiceProvider where appl...
The LeapXRServiceProvider expands on the standard LeapServiceProvider to account for the offset of th...
Old camera objects that weren't modified at all would have had a LeapEyeDislocator (formerly LeapVRCa...
List< Transform > nonLHCChildTransforms
Some rigs, like the old image rig or modifications to the old standard rig, may have non-LeapHandCont...
Description of an old Leap VR rig from before Core version 4.4.
static OldRigHierarchy DetectFor(Transform transform)
Detects if the argument Transform is the rig root of an old Leap rig, in which case an OldRigHierarch...
OldCameraData cameraData
The driven camera transform and component info of the rig hierarchy, or that of the LEFT eye if this ...
Transform handModelParentTransform
The parent of hand models in this rig that will receive the HandModelManager.
void Upgrade(UpgradeOptions options)
static bool DetectFor(Transform transform, OldRigHierarchy toFill)
Detects if the argument Transform is the rig root of an old Leap rig, modifying the passed-in old rig...
OldLeapHandControllerData lhcData
bool isUpgradeableOldRig
Whether this rig can be upgraded. Set after a DetectFor(transform) call.
string reasonRigCannotBeUpgraded
If the rig was detected as a potential rig but not upgradeable, this is the reason the rig cannot be ...
OldLeapSpaceData leapSpaceData
Transform rigTransform
The root transform of the old rig hierarchy.
bool detectedAsPotentialRig
Whether the scan data indicates the scanned transform is potentially an old Leap rig....