胡佳骏 1 year ago
commit
c6741a9989
100 changed files with 7189 additions and 0 deletions
  1. 8 0
      Editor.meta
  2. 521 0
      Editor/EditorBase.cs
  3. 11 0
      Editor/EditorBase.cs.meta
  4. 8 0
      Editor/EnvFix.meta
  5. 117 0
      Editor/EnvFix/ModifyUnityAndroidAppManifestSample.cs
  6. 11 0
      Editor/EnvFix/ModifyUnityAndroidAppManifestSample.cs.meta
  7. 819 0
      Editor/EnvFix/UXREnvFix.cs
  8. 11 0
      Editor/EnvFix/UXREnvFix.cs.meta
  9. 50 0
      Editor/EnvFix/UXRSDKConfigEditor.cs
  10. 11 0
      Editor/EnvFix/UXRSDKConfigEditor.cs.meta
  11. 8 0
      Editor/Interaction.meta
  12. 16 0
      Editor/Interaction/EditorConstants.cs
  13. 11 0
      Editor/Interaction/EditorConstants.cs.meta
  14. 69 0
      Editor/Interaction/InputModuleSwitchActiveEditor.cs
  15. 11 0
      Editor/Interaction/InputModuleSwitchActiveEditor.cs.meta
  16. 8 0
      Editor/Interaction/Poke.meta
  17. 33 0
      Editor/Interaction/Poke/BoxProximityFieldEditor.cs
  18. 11 0
      Editor/Interaction/Poke/BoxProximityFieldEditor.cs.meta
  19. 32 0
      Editor/Interaction/Poke/CircleProximityFieldEditor.cs
  20. 11 0
      Editor/Interaction/Poke/CircleProximityFieldEditor.cs.meta
  21. 135 0
      Editor/Interaction/Poke/CylinderProximityFieldEditor.cs
  22. 11 0
      Editor/Interaction/Poke/CylinderProximityFieldEditor.cs.meta
  23. 66 0
      Editor/Interaction/Poke/PokeInteractableEditor.cs
  24. 11 0
      Editor/Interaction/Poke/PokeInteractableEditor.cs.meta
  25. 8 0
      Editor/Interaction/Surfaces.meta
  26. 78 0
      Editor/Interaction/Surfaces/CylinderSurfaceEditor.cs
  27. 11 0
      Editor/Interaction/Surfaces/CylinderSurfaceEditor.cs.meta
  28. 86 0
      Editor/Interaction/Surfaces/PlaneSurfaceEditor.cs
  29. 11 0
      Editor/Interaction/Surfaces/PlaneSurfaceEditor.cs.meta
  30. 8 0
      Editor/Interaction/UnityCanvas.meta
  31. 43 0
      Editor/Interaction/UnityCanvas/CanvasMeshRendererEditor.cs
  32. 11 0
      Editor/Interaction/UnityCanvas/CanvasMeshRendererEditor.cs.meta
  33. 238 0
      Editor/Interaction/UnityCanvas/CanvasRenderTextureEditor.cs
  34. 11 0
      Editor/Interaction/UnityCanvas/CanvasRenderTextureEditor.cs.meta
  35. 133 0
      Editor/Interaction/UnityCanvas/OVRCanvasMeshRendererEditor.cs
  36. 11 0
      Editor/Interaction/UnityCanvas/OVRCanvasMeshRendererEditor.cs.meta
  37. 8 0
      Editor/InterfaceSupport.meta
  38. 245 0
      Editor/InterfaceSupport/InterfaceDrawer.cs
  39. 11 0
      Editor/InterfaceSupport/InterfaceDrawer.cs.meta
  40. 149 0
      Editor/InterfaceSupport/InterfacePicker.cs
  41. 11 0
      Editor/InterfaceSupport/InterfacePicker.cs.meta
  42. 26 0
      Editor/InterfaceSupport/OptionalDrawer.cs
  43. 11 0
      Editor/InterfaceSupport/OptionalDrawer.cs.meta
  44. 21 0
      Editor/Rokid.Unity.XR.Editor.asmdef
  45. 7 0
      Editor/Rokid.Unity.XR.Editor.asmdef.meta
  46. 8 0
      Editor/Textures.meta
  47. BIN
      Editor/Textures/RokidIcon.png
  48. 96 0
      Editor/Textures/RokidIcon.png.meta
  49. 8 0
      Runtime.meta
  50. 12 0
      Runtime/ApiConstants.cs
  51. 11 0
      Runtime/ApiConstants.cs.meta
  52. 8 0
      Runtime/Components.meta
  53. 8 0
      Runtime/Components/AxisRender.meta
  54. 114 0
      Runtime/Components/AxisRender/Axis.cs
  55. 11 0
      Runtime/Components/AxisRender/Axis.cs.meta
  56. 403 0
      Runtime/Components/AxisRender/Axis.prefab
  57. 7 0
      Runtime/Components/AxisRender/Axis.prefab.meta
  58. 870 0
      Runtime/Components/AxisRender/Axis.unity
  59. 7 0
      Runtime/Components/AxisRender/Axis.unity.meta
  60. 8 0
      Runtime/Components/DragUI.meta
  61. 116 0
      Runtime/Components/DragUI/BezierDragUI.cs
  62. 3 0
      Runtime/Components/DragUI/BezierDragUI.cs.meta
  63. 93 0
      Runtime/Components/DragUI/DragUI.cs
  64. 11 0
      Runtime/Components/DragUI/DragUI.cs.meta
  65. 8 0
      Runtime/Components/Ruler.meta
  66. 99 0
      Runtime/Components/Ruler/Ruler.cs
  67. 11 0
      Runtime/Components/Ruler/Ruler.cs.meta
  68. 80 0
      Runtime/Components/Ruler/Ruler.mat
  69. 8 0
      Runtime/Components/Ruler/Ruler.mat.meta
  70. 1090 0
      Runtime/Components/Ruler/Ruler.prefab
  71. 7 0
      Runtime/Components/Ruler/Ruler.prefab.meta
  72. 8 0
      Runtime/Resources.meta
  73. 8 0
      Runtime/Resources/Audio.meta
  74. BIN
      Runtime/Resources/Audio/ButtonDown.wav
  75. 22 0
      Runtime/Resources/Audio/ButtonDown.wav.meta
  76. BIN
      Runtime/Resources/Audio/ButtonUp.wav
  77. 22 0
      Runtime/Resources/Audio/ButtonUp.wav.meta
  78. BIN
      Runtime/Resources/Audio/ModuleChangeAudio.wav
  79. 22 0
      Runtime/Resources/Audio/ModuleChangeAudio.wav.meta
  80. 8 0
      Runtime/Resources/Configs.meta
  81. 20 0
      Runtime/Resources/Configs/DeviceFuncMatchInfo.json
  82. 7 0
      Runtime/Resources/Configs/DeviceFuncMatchInfo.json.meta
  83. BIN
      Runtime/Resources/Configs/DeviceFuncMatchInfo.xlsx
  84. 7 0
      Runtime/Resources/Configs/DeviceFuncMatchInfo.xlsx.meta
  85. 50 0
      Runtime/Resources/Configs/DeviceInfo.json
  86. 7 0
      Runtime/Resources/Configs/DeviceInfo.json.meta
  87. BIN
      Runtime/Resources/Configs/DeviceInfo.xlsx
  88. 7 0
      Runtime/Resources/Configs/DeviceInfo.xlsx.meta
  89. 8 0
      Runtime/Resources/Materials.meta
  90. 8 0
      Runtime/Resources/Materials/BuidIn.meta
  91. 107 0
      Runtime/Resources/Materials/BuidIn/HandMesh_Finger.mat
  92. 8 0
      Runtime/Resources/Materials/BuidIn/HandMesh_Finger.mat.meta
  93. 167 0
      Runtime/Resources/Materials/BuidIn/HandMesh_Palm.mat
  94. 8 0
      Runtime/Resources/Materials/BuidIn/HandMesh_Palm.mat.meta
  95. 151 0
      Runtime/Resources/Materials/BuidIn/RokidHand.mat
  96. 8 0
      Runtime/Resources/Materials/BuidIn/RokidHand.mat.meta
  97. 8 0
      Runtime/Resources/Materials/URP.meta
  98. 138 0
      Runtime/Resources/Materials/URP/HandMesh_Finger.mat
  99. 8 0
      Runtime/Resources/Materials/URP/HandMesh_Finger.mat.meta
  100. 147 0
      Runtime/Resources/Materials/URP/HandMesh_Palm.mat

+ 8 - 0
Editor.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e3f99f970f48def49bbf78f86e4f54bc
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 521 - 0
Editor/EditorBase.cs

@@ -0,0 +1,521 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Assertions;
+using UnityEditor;
+
+namespace Rokid.UXR.Editor
+{
+    /// <summary>
+    /// A utility class for building custom editors with less work required.
+    /// </summary>
+    public class EditorBase : UnityEditor.Editor
+    {
+
+        #region API
+
+        protected virtual void OnEnable() { }
+
+        protected virtual void OnDisable() { }
+
+        /// <summary>
+        /// You must put all of the editor specifications into OnInit
+        /// </summary>
+        protected virtual void OnInit() { }
+
+        /// <summary>
+        /// Call in OnInit with one or more property names to hide them from the inspector.
+        ///
+        /// This is preferable to using [HideInInspector] because it still allows the property to
+        /// be viewed when using the Inspector debug mode.
+        /// </summary>
+        protected void Hide(params string[] properties)
+        {
+            Assert.IsTrue(properties.Length > 0, "Should always hide at least one property.");
+            if (!ValidateProperties(properties))
+            {
+                return;
+            }
+
+            _hiddenProperties.UnionWith(properties);
+        }
+
+        /// <summary>
+        /// Call in OnInit with one or more property names to defer drawing them until after all
+        /// non-deferred properties have been drawn.  All deferred properties will be drawn in the order
+        /// they are passed in to calls to Defer.
+        /// </summary>
+        protected void Defer(params string[] properties)
+        {
+            Assert.IsTrue(properties.Length > 0, "Should always defer at least one property.");
+            if (!ValidateProperties(properties))
+            {
+                return;
+            }
+
+            foreach (var property in properties)
+            {
+                if (_deferredProperties.Contains(property))
+                {
+                    continue;
+                }
+
+                _deferredProperties.Add(property);
+                _deferredActions.Add(() =>
+                {
+                    DrawProperty(serializedObject.FindProperty(property));
+                });
+            }
+        }
+
+        /// <summary>
+        /// Call in OnInit with a single property name and a custom property drawer.  Equivalent
+        /// to calling Draw and then Defer for the property.
+        /// </summary>
+        protected void Defer(string property, Action<SerializedProperty> customDrawer)
+        {
+            Draw(property, customDrawer);
+            Defer(property);
+        }
+
+        /// <summary>
+        /// Call in OnInit with a single delegate to have it be called after all other non-deferred
+        /// properties have been drawn.
+        /// </summary>
+        protected void Defer(Action deferredAction)
+        {
+            _deferredActions.Add(deferredAction);
+        }
+
+        /// <summary>
+        /// Call in OnInit to specify a custom drawer for a single property.  Whenever the property is drawn,
+        /// it will use the provided property drawer instead of the default one.
+        /// </summary>
+        protected void Draw(string property, Action<SerializedProperty> drawer)
+        {
+            if (!ValidateProperties(property))
+            {
+                return;
+            }
+
+            _customDrawers.Add(property, drawer);
+        }
+
+        /// <summary>
+        /// Call in OnInit to specify a custom drawer for a single property.  Include an extra property that gets
+        /// lumped in with the primary property.  The extra property is not drawn normally, and is instead grouped in
+        /// with the primary property.  Can be used in situations where a collection of properties need to be drawn together.
+        /// </summary>
+        protected void Draw(string property,
+            string withExtra0,
+            Action<SerializedProperty, SerializedProperty> drawer)
+        {
+            if (!ValidateProperties(property, withExtra0))
+            {
+                return;
+            }
+
+            Hide(withExtra0);
+            Draw(property, p =>
+            {
+                drawer(p,
+                    serializedObject.FindProperty(withExtra0));
+            });
+        }
+
+        protected void Draw(string property,
+            string withExtra0,
+            string withExtra1,
+            Action<SerializedProperty, SerializedProperty, SerializedProperty> drawer)
+        {
+            if (!ValidateProperties(property, withExtra0, withExtra1))
+            {
+                return;
+            }
+
+            Hide(withExtra0);
+            Hide(withExtra1);
+            Draw(property, p =>
+            {
+                drawer(p,
+                    serializedObject.FindProperty(withExtra0),
+                    serializedObject.FindProperty(withExtra1));
+            });
+        }
+
+        protected void Draw(string property,
+            string withExtra0,
+            string withExtra1,
+            string withExtra2,
+            Action<SerializedProperty, SerializedProperty, SerializedProperty, SerializedProperty>
+                drawer)
+        {
+            if (!ValidateProperties(property, withExtra0, withExtra1, withExtra2))
+            {
+                return;
+            }
+
+            Hide(withExtra0);
+            Hide(withExtra1);
+            Hide(withExtra2);
+            Draw(property, p =>
+            {
+                drawer(p,
+                    serializedObject.FindProperty(withExtra0),
+                    serializedObject.FindProperty(withExtra1),
+                    serializedObject.FindProperty(withExtra2));
+            });
+        }
+
+        protected void Draw(string property,
+            string withExtra0,
+            string withExtra1,
+            string withExtra2,
+            string withExtra3,
+            Action<SerializedProperty, SerializedProperty, SerializedProperty, SerializedProperty,
+                SerializedProperty> drawer)
+        {
+            if (!ValidateProperties(property, withExtra0, withExtra1, withExtra2, withExtra3))
+            {
+                return;
+            }
+
+            Hide(withExtra0);
+            Hide(withExtra1);
+            Hide(withExtra2);
+            Hide(withExtra3);
+            Draw(property, p =>
+            {
+                drawer(p,
+                    serializedObject.FindProperty(withExtra0),
+                    serializedObject.FindProperty(withExtra1),
+                    serializedObject.FindProperty(withExtra2),
+                    serializedObject.FindProperty(withExtra3));
+            });
+        }
+
+        protected void Conditional(string boolPropName, bool showIf, params string[] toHide)
+        {
+            if (!ValidateProperties(boolPropName) || !ValidateProperties(toHide))
+            {
+                return;
+            }
+
+            var boolProp = serializedObject.FindProperty(boolPropName);
+            if (boolProp.propertyType != SerializedPropertyType.Boolean)
+            {
+                Debug.LogError(
+                    $"Must provide a Boolean property to this Conditional method, but the property {boolPropName} had a type of {boolProp.propertyType}");
+                return;
+            }
+
+            List<Func<bool>> conditions;
+            foreach (var prop in toHide)
+            {
+                if (!_propertyDrawConditions.TryGetValue(prop, out conditions))
+                {
+                    conditions = new List<Func<bool>>();
+                    _propertyDrawConditions[prop] = conditions;
+                }
+
+                conditions.Add(() =>
+                {
+                    if (boolProp.hasMultipleDifferentValues)
+                    {
+                        return false;
+                    }
+                    else
+                    {
+                        return boolProp.boolValue == showIf;
+                    }
+                });
+            }
+        }
+
+        protected void Conditional<T>(string enumPropName, T showIf, params string[] toHide)
+            where T : Enum
+        {
+            if (!ValidateProperties(enumPropName) || !ValidateProperties(toHide))
+            {
+                return;
+            }
+
+            var enumProp = serializedObject.FindProperty(enumPropName);
+            if (enumProp.propertyType != SerializedPropertyType.Enum)
+            {
+                Debug.LogError(
+                    $"Must provide a Boolean property to this Conditional method, but the property {enumPropName} had a type of {enumProp.propertyType}");
+                return;
+            }
+
+            List<Func<bool>> conditions;
+            foreach (var prop in toHide)
+            {
+                if (!_propertyDrawConditions.TryGetValue(prop, out conditions))
+                {
+                    conditions = new List<Func<bool>>();
+                    _propertyDrawConditions[prop] = conditions;
+                }
+
+                conditions.Add(() =>
+                {
+                    if (enumProp.hasMultipleDifferentValues)
+                    {
+                        return false;
+                    }
+                    else
+                    {
+                        return enumProp.intValue == showIf.GetHashCode();
+                    }
+                });
+            }
+        }
+
+        /// <summary>
+        /// Call in OnInit to specify a custom decorator for a single property.  Before a property is drawn,
+        /// all of the decorators will be drawn first.
+        /// </summary>
+        protected void Decorate(string property, Action<SerializedProperty> decorator)
+        {
+            if (!ValidateProperties(property))
+            {
+                return;
+            }
+
+            List<Action<SerializedProperty>> decorators;
+            if (!_customDecorators.TryGetValue(property, out decorators))
+            {
+                decorators = new List<Action<SerializedProperty>>();
+                _customDecorators[property] = decorators;
+            }
+
+            decorators.Add(decorator);
+        }
+
+        /// <summary>
+        /// Call in OnInit to specify a custom grouping behaviour for a range of properties.  Specify the first
+        /// and last property (inclusive) and the action to take BEFORE the first property is drawn, and the action
+        /// to take AFTER the last property is drawn.
+        /// </summary>
+        protected void Group(string firstProperty, string lastProperty, Action beginGroup,
+            Action endGroup)
+        {
+            if (!ValidateProperties(firstProperty) || !ValidateProperties(lastProperty))
+            {
+                return;
+            }
+
+            _groupBegins.Add(firstProperty, beginGroup);
+            _groupEnds.Add(lastProperty, endGroup);
+        }
+
+        /// <summary>
+        /// A utility version of the more generic Group method.
+        /// Call in OnInit to specify a range of properties that should be grouped within a styled vertical
+        /// layout group.
+        /// </summary>
+        protected void Group(string firstProperty, string lastProperty, GUIStyle style)
+        {
+            if (style == null)
+            {
+                Debug.LogError(
+                    "Cannot provide a null style to EditorBase.Group.  If you are acquiring a " +
+                    "Style from the EditorStyles class, try calling Group from with on OnInit instead " +
+                    "of from within OnEnable.");
+                return;
+            }
+
+            Group(firstProperty,
+                lastProperty,
+                () => EditorGUILayout.BeginVertical(style),
+                () => EditorGUILayout.EndVertical());
+        }
+
+        /// <summary>
+        /// Groups the given properties into a foldout with a given name.
+        /// </summary>
+        protected void Foldout(string firstProperty, string lastProperty, string foldoutName,
+            bool showByDefault = false)
+        {
+            Group(firstProperty,
+                lastProperty,
+                () =>
+                {
+                    bool shouldShow;
+                    if (!_foldouts.TryGetValue(foldoutName, out shouldShow))
+                    {
+                        shouldShow = showByDefault;
+                    }
+
+                    shouldShow = EditorGUILayout.Foldout(shouldShow, foldoutName);
+
+                    _foldouts[foldoutName] = shouldShow;
+                    EditorGUI.indentLevel++;
+
+                    _currentStates.Push(shouldShow);
+                },
+                () =>
+                {
+                    EditorGUI.indentLevel--;
+                    _currentStates.Pop();
+                });
+        }
+
+        protected virtual void OnBeforeInspector() { }
+        protected virtual void OnAfterInspector(bool anyPropertiesModified) { }
+
+        #endregion
+
+        #region IMPLEMENTATION
+
+        [NonSerialized]
+        private bool _hasInitBeenCalled = false;
+
+        private HashSet<string> _hiddenProperties = new HashSet<string>();
+        private HashSet<string> _deferredProperties = new HashSet<string>();
+        private List<Action> _deferredActions = new List<Action>();
+
+        private Dictionary<string, bool> _foldouts = new Dictionary<string, bool>();
+        private Stack<bool> _currentStates = new Stack<bool>();
+
+        private Dictionary<string, Action<SerializedProperty>> _customDrawers =
+            new Dictionary<string, Action<SerializedProperty>>();
+
+        private Dictionary<string, List<Action<SerializedProperty>>> _customDecorators =
+            new Dictionary<string, List<Action<SerializedProperty>>>();
+
+        private Dictionary<string, Action> _groupBegins = new Dictionary<string, Action>();
+        private Dictionary<string, Action> _groupEnds = new Dictionary<string, Action>();
+
+        private Dictionary<string, List<Func<bool>>> _propertyDrawConditions =
+            new Dictionary<string, List<Func<bool>>>();
+
+        public override void OnInspectorGUI()
+        {
+            if (!_hasInitBeenCalled)
+            {
+                OnInit();
+                _hasInitBeenCalled = true;
+            }
+
+            SerializedProperty it = serializedObject.GetIterator();
+            it.NextVisible(enterChildren: true);
+
+            //Draw script header
+            EditorGUI.BeginDisabledGroup(true);
+            EditorGUILayout.PropertyField(it);
+            EditorGUI.EndDisabledGroup();
+
+            OnBeforeInspector();
+
+            EditorGUI.BeginChangeCheck();
+
+            while (it.NextVisible(enterChildren: false))
+            {
+                //Don't draw deferred properties in this pass, we will draw them after everything else
+                if (_deferredProperties.Contains(it.name))
+                {
+                    continue;
+                }
+
+                DrawProperty(it);
+            }
+
+            foreach (var deferredAction in _deferredActions)
+            {
+                deferredAction();
+            }
+
+            bool anyModified = EditorGUI.EndChangeCheck();
+
+            OnAfterInspector(anyModified);
+
+            serializedObject.ApplyModifiedProperties();
+        }
+
+        private void DrawProperty(SerializedProperty property)
+        {
+            Action groupBeginAction;
+            if (_groupBegins.TryGetValue(property.name, out groupBeginAction))
+            {
+                groupBeginAction();
+            }
+
+            try
+            {
+                //Don't draw if we are in a property that is currently hidden by a foldout
+                if (_currentStates.Any(s => s == false))
+                {
+                    return;
+                }
+
+                //Don't draw hidden properties
+                if (_hiddenProperties.Contains(property.name))
+                {
+                    return;
+                }
+
+                List<Func<bool>> conditions;
+                if (_propertyDrawConditions.TryGetValue(property.name, out conditions))
+                {
+                    foreach (var condition in conditions)
+                    {
+                        if (!condition())
+                        {
+                            return;
+                        }
+                    }
+                }
+
+                //First draw all decorators for the property
+                List<Action<SerializedProperty>> decorators;
+                if (_customDecorators.TryGetValue(property.name, out decorators))
+                {
+                    foreach (var decorator in decorators)
+                    {
+                        decorator(property);
+                    }
+                }
+
+                //Then draw the property itself, using a custom drawer if needed
+                Action<SerializedProperty> customDrawer;
+                if (_customDrawers.TryGetValue(property.name, out customDrawer))
+                {
+                    customDrawer(property);
+                }
+                else
+                {
+                    EditorGUILayout.PropertyField(property, includeChildren: true);
+                }
+
+            }
+            finally
+            {
+                Action groupEndAction;
+                if (_groupEnds.TryGetValue(property.name, out groupEndAction))
+                {
+                    groupEndAction();
+                }
+            }
+        }
+
+        private bool ValidateProperties(params string[] properties)
+        {
+            foreach (var property in properties)
+            {
+                if (serializedObject.FindProperty(property) == null)
+                {
+                    Debug.LogWarning(
+                        $"Could not find property {property}, maybe it was deleted or renamed?");
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        #endregion
+    }
+
+}

+ 11 - 0
Editor/EditorBase.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: efc67d10ea67840feb4200629eff21b3
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Editor/EnvFix.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ea6c44bfb9a77481896bd2db025fcfd8
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 117 - 0
Editor/EnvFix/ModifyUnityAndroidAppManifestSample.cs

@@ -0,0 +1,117 @@
+using System.IO;
+using System.Text;
+using System.Xml;
+using UnityEditor.Android;
+using UnityEngine;
+
+namespace Rokid.UXR.Editor {	
+	public class ModifyUnityAndroidAppManifestSample : IPostGenerateGradleAndroidProject
+	{
+	
+	    public void OnPostGenerateGradleAndroidProject(string basePath)
+	    {
+	        // If needed, add condition checks on whether you need to run the modification routine.
+	        // For example, specific configuration/app options enabled
+	        var androidManifest = new AndroidManifest(GetManifestPath(basePath));
+	
+	        androidManifest.SetHardwareAccel();
+	        // Add your XML manipulation routines
+	        androidManifest.Save();
+	    }
+	
+	    public int callbackOrder { get { return 1; } }
+	
+	    private string _manifestFilePath;
+	
+	    private string GetManifestPath(string basePath)
+	    {
+	        if (string.IsNullOrEmpty(_manifestFilePath))
+	        {
+	            var pathBuilder = new StringBuilder(basePath);
+	            pathBuilder.Append(Path.DirectorySeparatorChar).Append("src");
+	            pathBuilder.Append(Path.DirectorySeparatorChar).Append("main");
+	            pathBuilder.Append(Path.DirectorySeparatorChar).Append("AndroidManifest.xml");
+	            _manifestFilePath = pathBuilder.ToString();
+	        }
+	        return _manifestFilePath;
+	    }
+	}
+	
+	
+	internal class AndroidXmlDocument : XmlDocument
+	{
+	    private string m_Path;
+	    protected XmlNamespaceManager nsMgr;
+	    public readonly string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";
+	
+	    public AndroidXmlDocument(string path)
+	    {
+	        m_Path = path;
+        using (var reader = new XmlTextReader(m_Path))
+	        {
+	            reader.Read();
+	            Load(reader);
+	        }
+	        nsMgr = new XmlNamespaceManager(NameTable);
+	        nsMgr.AddNamespace("android", AndroidXmlNamespace);
+	    }
+	
+	    public string Save()
+	    {
+	        return SaveAs(m_Path);
+	    }
+	
+	    public string SaveAs(string path)
+	    {
+        using (var writer = new XmlTextWriter(path, new UTF8Encoding(false)))
+	        {
+	            writer.Formatting = Formatting.Indented;
+	            Save(writer);
+	        }
+	        return path;
+	    }
+	}
+	
+	
+	internal class AndroidManifest : AndroidXmlDocument
+	{
+	    private readonly XmlElement ApplicationElement;
+	
+	    public AndroidManifest(string path) : base(path)
+	    {
+	        ApplicationElement = SelectSingleNode("/manifest/application") as XmlElement;
+	    }
+	
+	    private XmlAttribute CreateAndroidAttribute(string key, string value)
+	    {
+	        XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace);
+	        attr.Value = value;
+	        return attr;
+	    }
+	
+	    internal XmlNode GetActivityWithLaunchIntent()
+	    {
+	        return SelectSingleNode("/manifest/application/activity[intent-filter/action/@android:name='android.intent.action.MAIN' and " +
+	                "intent-filter/category/@android:name='android.intent.category.LAUNCHER']", nsMgr);
+	    }
+	
+	    internal XmlNode GetActivityWithUXR()
+	    {
+	        return SelectSingleNode("/manifest/application/activity[meta-data/@android:name='unityplayer.UnityActivity'] ", nsMgr);
+	    }
+	
+	    internal void SetApplicationTheme(string appTheme)
+	    {
+	        ApplicationElement.Attributes.Append(CreateAndroidAttribute("theme", appTheme));
+	    }
+	
+	    internal void SetStartingActivityName(string activityName)
+	    {
+	        GetActivityWithLaunchIntent().Attributes.Append(CreateAndroidAttribute("name", activityName));
+	    }
+	    internal void SetHardwareAccel()
+	    {
+	        GetActivityWithUXR().Attributes.Append(CreateAndroidAttribute("hardwareAccelerated", "true"));
+	    }
+	}
+}

+ 11 - 0
Editor/EnvFix/ModifyUnityAndroidAppManifestSample.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fc1a1f835ce7742599eb4c2d18a33d74
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 819 - 0
Editor/EnvFix/UXREnvFix.cs

@@ -0,0 +1,819 @@
+using System.Net.Http.Headers;
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.Rendering;
+using UnityEngine.XR.Management;
+using UnityEditor.XR.Management;
+/*
+namespace Rokid.UXR.Editor
+{
+    [InitializeOnLoad]
+    public class UXREnvFix : EditorWindow
+    {
+        #region  Config
+        private const string ignorePrefix = "UXREnvFix";
+        private static FixItem[] fixItems;
+        private static UXREnvFix window;
+        private Vector2 scrollPosition;
+        private static string cardboardVersion = "1.21.4";
+        private static string minUnityVersion = "2020.3.26";
+        private static AndroidSdkVersions minSdkVersion = AndroidSdkVersions.AndroidApiLevel26;
+        private static AndroidArchitecture targetArchitecture = AndroidArchitecture.ARM64;
+
+        #endregion
+
+        static UXREnvFix()
+        {
+            EditorApplication.update -= OnUpdate;
+            EditorApplication.update += OnUpdate;
+        }
+
+        private static void OnUpdate()
+        {
+            bool show = false;
+
+            if (fixItems == null) { RegisterItems(); }
+            foreach (var item in fixItems)
+            {
+                if (!item.IsIgnored() && !item.IsValid() && item.Level > MessageType.Warning && item.IsAutoPop())
+                {
+                    show = true;
+                }
+            }
+
+            if (show)
+            {
+                ShowWindow();
+            }
+
+            EditorApplication.update -= OnUpdate;
+        }
+
+        private static void RegisterItems()
+        {
+            fixItems = new FixItem[]
+            {
+                new CheckBuildTarget(MessageType.Error),
+                new CheckUnityMinVersion(MessageType.Error), 
+            // #if UNITY_2020_3_OR_NEWER
+	            //     new CheckCardboardPackage(MessageType.Error),
+            // #endif 
+	            new CkeckMTRendering(MessageType.Error),
+                new CkeckAndroidGraphicsAPI(MessageType.Error),
+                new CkeckAndroidOrientation(MessageType.Warning),
+	            // new CkeckColorSpace(MessageType.Warning),
+	            new CheckOptimizedFramePacing(MessageType.Warning),
+                new CheckMinmumAPILevel(MessageType.Error),
+                new CheckArchitecture(MessageType.Error)
+            };
+        }
+
+        [MenuItem("UXR/Env/Project Environment Fix", false)]
+        public static void ShowWindow()
+        {
+            RegisterItems();
+            window = GetWindow<UXREnvFix>(true);
+            window.minSize = new Vector2(320, 300);
+            window.maxSize = new Vector2(320, 800);
+            window.titleContent = new GUIContent("UXR SDK | Environment Fix");
+        }
+
+        //[MenuItem("UXR/Env/Delete Ignore", false)]
+        public static void DeleteIgonre()
+        {
+            foreach (var item in fixItems)
+            {
+                item.DeleteIgonre();
+            }
+        }
+
+        public void OnGUI()
+        {
+            string resourcePath = GetResourcePath();
+            Texture2D logo = AssetDatabase.LoadAssetAtPath<Texture2D>(resourcePath + "RokidIcon.png");
+            Rect rect = GUILayoutUtility.GetRect(position.width, 80, GUI.skin.box);
+            GUI.DrawTexture(rect, logo, ScaleMode.ScaleToFit);
+
+            string aboutText = "This window provides tips to help fix common issues with UXR SDK and your project.";
+            EditorGUILayout.LabelField(aboutText, EditorStyles.textArea);
+
+            int ignoredCount = 0;
+            int fixableCount = 0;
+            int invalidNotIgnored = 0;
+
+            for (int i = 0; i < fixItems.Length; i++)
+            {
+                FixItem item = fixItems[i];
+
+                bool ignored = item.IsIgnored();
+                bool valid = item.IsValid();
+                bool fixable = item.IsFixable();
+
+                if (!valid && !ignored && fixable)
+                {
+                    fixableCount++;
+                }
+
+                if (!valid && !ignored)
+                {
+                    invalidNotIgnored++;
+                }
+
+                if (ignored)
+                {
+                    ignoredCount++;
+                }
+            }
+
+            Rect issuesRect = EditorGUILayout.GetControlRect();
+            GUI.Box(new Rect(issuesRect.x - 4, issuesRect.y, issuesRect.width + 8, issuesRect.height), "Tips", EditorStyles.toolbarButton);
+
+            if (invalidNotIgnored > 0)
+            {
+                scrollPosition = GUILayout.BeginScrollView(scrollPosition);
+                {
+                    for (int i = 0; i < fixItems.Length; i++)
+                    {
+                        FixItem item = fixItems[i];
+
+                        if (!item.IsIgnored() && !item.IsValid())
+                        {
+                            invalidNotIgnored++;
+
+                            GUILayout.BeginVertical("box");
+                            {
+                                item.DrawGUI();
+
+                                EditorGUILayout.BeginHorizontal();
+                                {
+                                    // Aligns buttons to the right
+                                    GUILayout.FlexibleSpace();
+
+                                    if (item.IsFixable())
+                                    {
+                                        if (GUILayout.Button("Fix"))
+                                            item.Fix();
+                                    }
+
+                                    //if (GUILayout.Button("Ignore"))
+                                    //    check.Ignore();
+                                }
+                                EditorGUILayout.EndHorizontal();
+                            }
+                            GUILayout.EndVertical();
+                        }
+                    }
+                }
+                GUILayout.EndScrollView();
+            }
+
+            GUILayout.FlexibleSpace();
+
+            if (invalidNotIgnored == 0)
+            {
+                GUILayout.BeginHorizontal();
+                {
+                    GUILayout.FlexibleSpace();
+
+                    GUILayout.BeginVertical();
+                    {
+                        GUILayout.Label("No issue found");
+
+                        if (GUILayout.Button("Close Window"))
+                            Close();
+                    }
+                    GUILayout.EndVertical();
+
+                    GUILayout.FlexibleSpace();
+                }
+                GUILayout.EndHorizontal();
+
+                GUILayout.FlexibleSpace();
+            }
+
+            EditorGUILayout.BeginHorizontal("box");
+            {
+                if (fixableCount > 0)
+                {
+                    if (GUILayout.Button("Accept All"))
+                    {
+                        if (EditorUtility.DisplayDialog("Accept All", "Are you sure?", "Yes, Accept All", "Cancel"))
+                        {
+                            for (int i = 0; i < fixItems.Length; i++)
+                            {
+                                FixItem item = fixItems[i];
+
+                                if (!item.IsIgnored() &&
+                                    !item.IsValid())
+                                {
+                                    if (item.IsFixable())
+                                        item.Fix();
+                                }
+                            }
+                        }
+                    }
+                }
+
+            }
+            GUILayout.EndHorizontal();
+        }
+
+        private string GetResourcePath()
+        {
+            var ms = MonoScript.FromScriptableObject(this);
+            var path = AssetDatabase.GetAssetPath(ms);
+            path = Path.GetDirectoryName(path);
+            return path + "\\Textures\\";
+        }
+
+        private abstract class FixItem
+        {
+            protected string key;
+            protected MessageType level;
+
+            public MessageType Level
+            {
+                get
+                {
+                    return level;
+                }
+            }
+
+            public FixItem(MessageType level)
+            {
+                this.level = level;
+            }
+
+            public void Ignore()
+            {
+                EditorPrefs.SetBool(ignorePrefix + key, true);
+            }
+
+            public bool IsIgnored()
+            {
+                return EditorPrefs.HasKey(ignorePrefix + key);
+            }
+
+            public void DeleteIgonre()
+            {
+                RKLog.Info("DeleteIgnore" + ignorePrefix + key);
+                EditorPrefs.DeleteKey(ignorePrefix + key);
+            }
+
+            public abstract bool IsValid();
+
+            public abstract bool IsAutoPop();
+
+            public abstract void DrawGUI();
+
+            public abstract bool IsFixable();
+
+            public abstract void Fix();
+
+            protected void DrawContent(string title, string msg)
+            {
+                EditorGUILayout.HelpBox(title, level);
+                EditorGUILayout.LabelField(msg, EditorStyles.textArea);
+            }
+        }
+
+        private class CheckCardboardPackage : FixItem
+        {
+            private enum PackageStates
+            {
+                None,
+                WaitingForList,
+                Failed,
+                Added,
+            }
+
+            UnityEditor.PackageManager.Requests.ListRequest request;
+            PackageStates packageState = PackageStates.None;
+            bool isvalid = true;
+            bool initOnStart;
+            bool hasLoader;
+
+            public CheckCardboardPackage(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+                request = null;
+                isvalid = true;
+#if UNITY_2020_3_OR_NEWER
+                EditorApplication.update -= CheckPackageUpdate;
+                EditorApplication.update += CheckPackageUpdate;
+#endif
+            }
+
+#if UNITY_2020_3_OR_NEWER
+            void CheckPackageUpdate()
+            {
+                switch (packageState)
+                {
+                    case PackageStates.None:
+                        request = UnityEditor.PackageManager.Client.List(true, false);
+                        packageState = PackageStates.WaitingForList;
+                        break;
+
+                    case PackageStates.WaitingForList:
+                        if (request.IsCompleted)
+                        {
+                            if (request.Error != null || request.Status == UnityEditor.PackageManager.StatusCode.Failure)
+                            {
+                                packageState = PackageStates.Failed;
+                                break;
+                            }
+
+                            UnityEditor.PackageManager.PackageCollection col = request.Result;
+                            foreach (var info in col)
+                            {
+                                if (info.name == "com.google.xr.cardboard" && info.version == cardboardVersion)
+                                {
+                                    packageState = PackageStates.Added;
+
+                                    isvalid = true;
+
+                                    break;
+                                }
+                            }
+                            if (packageState != PackageStates.Added) isvalid = false;
+                        }
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+
+#endif
+
+            public override bool IsValid()
+            {
+                return (isvalid && initOnStart && hasLoader);
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"You must upgrade Cardboard XR Plugin to version:" + cardboardVersion + @",
+	in dropdown list of Window> Package Manager >'+' Button >Add package from disk >Select the package.json file in the root directory of the local Cardboard XR Plugin .
+	Select XR Plug-in Management in the Project Settings window>Initialize XR on Startup checked>Cardboard XR Plugin Checked";
+                DrawContent("Cardboard XR Plugin is not setup correctly", message);
+            }
+
+            public override bool IsFixable()
+            {
+                if (isvalid)
+                {
+                    XRGeneralSettings sets = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(BuildTargetGroup.Android);
+
+                    if (sets != null)
+                    {
+                        initOnStart = sets.InitManagerOnStart;
+
+                        XRManagerSettings plugins = sets.AssignedSettings;
+                        var loaders = sets.Manager.activeLoaders;
+
+                        hasLoader = false;
+
+                        for (int i = 0; i < loaders.Count; i++)
+                        {
+                            if (loaders[i].GetType() == typeof(Rokid.XR.Core.XRLoader))
+                                hasLoader = true;
+                            break;
+                        }
+                        if (!hasLoader || !initOnStart) return true;
+                    }
+                }
+                return false;
+            }
+
+            public override void Fix()
+            {
+                var sets = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(BuildTargetGroup.Android);
+                bool initOnStart = sets.InitManagerOnStart;
+
+                if (!initOnStart) sets.InitManagerOnStart = true;
+
+                XRManagerSettings plugins = sets.AssignedSettings;
+                var loaders = sets.Manager.activeLoaders;
+                bool hasLoader = false;
+
+                for (int i = 0; i < loaders.Count; i++)
+                {
+                    if (loaders[i].GetType() == typeof(Rokid.XR.Core.XRLoader))
+                        hasLoader = true;
+                    break;
+                }
+
+                if (!hasLoader)
+                {
+                    var xrLoader = new Rokid.XR.Core.XRLoader();
+                    plugins.TryAddLoader(xrLoader);
+                }
+            }
+
+            public override bool IsAutoPop()
+            {
+                return false;
+            }
+        }
+
+        private class CkeckAndroidGraphicsAPI : FixItem
+        {
+            public CkeckAndroidGraphicsAPI(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+            }
+
+            public override bool IsValid()
+            {
+                if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
+                {
+                    if (PlayerSettings.GetUseDefaultGraphicsAPIs(BuildTarget.Android))
+                    {
+                        return false;
+                    }
+                    var graphics = PlayerSettings.GetGraphicsAPIs(BuildTarget.Android);
+                    if (graphics != null && graphics.Length >= 1 &&
+                        graphics[0] == UnityEngine.Rendering.GraphicsDeviceType.OpenGLES3)
+                    {
+                        return true;
+                    }
+                    return false;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"Graphics APIs should be set to OpenGLES.  Player Settings > Other Settings > Graphics APIs , choose 'OpenGLES3'.";
+                DrawContent("Graphics APIs is not OpenGLES", message);
+            }
+
+            public override bool IsFixable()
+            {
+                return true;
+            }
+
+            public override void Fix()
+            {
+                if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
+                {
+                    PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.Android, false);
+                    PlayerSettings.SetGraphicsAPIs(BuildTarget.Android, new GraphicsDeviceType[1] { GraphicsDeviceType.OpenGLES3 });
+                }
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+        }
+
+        private class CkeckMTRendering : FixItem
+        {
+            public CkeckMTRendering(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+            }
+
+            public override bool IsValid()
+            {
+                if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
+                {
+                    return !PlayerSettings.GetMobileMTRendering(BuildTargetGroup.Android);
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"In order to run correct on mobile devices, the RenderingThreadingMode should be set. 
+	in dropdown list of Player Settings > Other Settings > Multithreaded Rendering, close toggle.";
+                DrawContent("Multithreaded Rendering not close", message);
+            }
+
+            public override bool IsFixable()
+            {
+                return true;
+            }
+
+            public override void Fix()
+            {
+                if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
+                {
+                    PlayerSettings.SetMobileMTRendering(BuildTargetGroup.Android, false);
+                }
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+        }
+
+        private class CkeckAndroidOrientation : FixItem
+        {
+            public CkeckAndroidOrientation(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+            }
+
+            public override bool IsValid()
+            {
+                return PlayerSettings.defaultInterfaceOrientation == UIOrientation.Portrait;
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"In order to display correct on mobile devices, the orientation should be set to portrait. 
+	in dropdown list of Player Settings > Resolution and Presentation > Default Orientation, choose 'Portrait'.";
+                DrawContent("Orientation is not portrait", message);
+            }
+
+            public override bool IsFixable()
+            {
+                return true;
+            }
+
+            public override void Fix()
+            {
+                if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
+                {
+                    PlayerSettings.defaultInterfaceOrientation = UIOrientation.Portrait;
+                }
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+        }
+
+        private class CkeckColorSpace : FixItem
+        {
+            public CkeckColorSpace(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+            }
+
+            public override bool IsValid()
+            {
+                return PlayerSettings.colorSpace == ColorSpace.Gamma;
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"In order to display correct on mobile devices, the colorSpace should be set to gamma. 
+	in dropdown list of Player Settings > Other Settings > Color Space, choose 'Gamma'.";
+                DrawContent("ColorSpace is not Linear", message);
+            }
+
+            public override bool IsFixable()
+            {
+                return true;
+            }
+
+            public override void Fix()
+            {
+                if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
+                {
+                    PlayerSettings.colorSpace = ColorSpace.Gamma;
+                }
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+        }
+
+        private class CkeckAndroidPermission : FixItem
+        {
+            public CkeckAndroidPermission(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+            }
+
+            public override bool IsValid()
+            {
+                if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
+                {
+                    return PlayerSettings.Android.forceInternetPermission;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"In order to run correct on mobile devices, the internet access premission should be set. 
+	in dropdown list of Player Settings > Other Settings > Internet Access, choose 'Require'.";
+                DrawContent("internet access permission not available", message);
+            }
+
+            public override bool IsFixable()
+            {
+                return true;
+            }
+
+            public override void Fix()
+            {
+                if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
+                {
+                    PlayerSettings.Android.forceInternetPermission = true;
+                }
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+        }
+
+        //todo...添加最低版本号的检查
+        private class CheckUnityMinVersion : FixItem
+        {
+            string unityVersion;//
+
+            public CheckUnityMinVersion(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+                unityVersion = Application.unityVersion;
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"The minimum Unity version required is 2020.3.36";
+                DrawContent("Unity version not valid ", message);
+            }
+
+            public override void Fix()
+            {
+
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+
+            public override bool IsFixable()
+            {
+                return unityVersion.CompareTo(minUnityVersion) == 1;
+            }
+
+            public override bool IsValid()
+            {
+                return unityVersion.CompareTo(minUnityVersion) == 1;
+            }
+        }
+
+        private class CheckOptimizedFramePacing : FixItem
+        {
+            public CheckOptimizedFramePacing(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"The optimizedFramePacing need to unselect";
+                DrawContent("OptimizedFramePacing", message);
+            }
+
+            public override void Fix()
+            {
+                PlayerSettings.Android.optimizedFramePacing = false;
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+
+            public override bool IsFixable()
+            {
+                return true;
+            }
+
+            public override bool IsValid()
+            {
+                return PlayerSettings.Android.optimizedFramePacing == false;
+            }
+        }
+
+        private class CheckMinmumAPILevel : FixItem
+        {
+            public CheckMinmumAPILevel(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"The minSdkVersion needs to be " + minSdkVersion.ToString();
+                DrawContent("MinSDKVersion", message);
+            }
+
+            public override void Fix()
+            {
+                PlayerSettings.Android.minSdkVersion = minSdkVersion;
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+
+            public override bool IsFixable()
+            {
+                return true;
+            }
+
+            public override bool IsValid()
+            {
+                return PlayerSettings.Android.minSdkVersion >= minSdkVersion;
+            }
+        }
+
+        private class CheckArchitecture : FixItem
+        {
+            public CheckArchitecture(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"The Target Architecture should be " + targetArchitecture;
+                DrawContent("Target Architecture", message);
+            }
+
+            public override void Fix()
+            {
+                PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, ScriptingImplementation.IL2CPP);
+                PlayerSettings.Android.targetArchitectures = targetArchitecture;
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+
+            public override bool IsFixable()
+            {
+                return true;
+            }
+
+            public override bool IsValid()
+            {
+                return PlayerSettings.GetScriptingBackend(BuildTargetGroup.Android) == ScriptingImplementation.IL2CPP &&
+                    PlayerSettings.Android.targetArchitectures == targetArchitecture;
+            }
+        }
+
+
+        private class CheckBuildTarget : FixItem
+        {
+            public CheckBuildTarget(MessageType level) : base(level)
+            {
+                key = this.GetType().Name;
+            }
+
+            public override void DrawGUI()
+            {
+                string message = @"The Build Target should be Android";
+                DrawContent("Build Target", message);
+            }
+
+            public override void Fix()
+            {
+                EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android);
+            }
+
+            public override bool IsAutoPop()
+            {
+                return true;
+            }
+
+            public override bool IsFixable()
+            {
+                return true;
+            }
+
+            public override bool IsValid()
+            {
+                return EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android;
+            }
+        }
+    }
+}*/

+ 11 - 0
Editor/EnvFix/UXREnvFix.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8a16578a2f3946d42922d3fae8ddb24f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 50 - 0
Editor/EnvFix/UXRSDKConfigEditor.cs

@@ -0,0 +1,50 @@
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+using Rokid.UXR.Config;
+
+namespace Rokid.UXR.Editor
+{
+    public class UXRSDKConfigEditor : MonoBehaviour
+    {
+        //[MenuItem("Assets/UXR/Config/Build SDKConfig")]
+        public static void BuildSDKConfig()
+        {
+            BuildConfig<UXRSDKConfig>("UXRSDKConfig");
+        }
+
+        public static void BuildConfig<T>(string name) where T : ScriptableObject
+        {
+            T data = null;
+            string folderPath = GetSelectedDirAssetsPath();
+            string spriteDataPath = folderPath + string.Format("/{0}.asset", name);
+
+            data = AssetDatabase.LoadAssetAtPath<T>(spriteDataPath);
+            if (data == null)
+            {
+                data = ScriptableObject.CreateInstance<T>();
+                AssetDatabase.CreateAsset(data, spriteDataPath);
+            }
+            RKLog.Info("Create Config In Folder:" + spriteDataPath);
+            EditorUtility.SetDirty(data);
+            AssetDatabase.SaveAssets();
+        }
+
+        public static string GetSelectedDirAssetsPath()
+        {
+            string path = string.Empty;
+
+            foreach (UnityEngine.Object obj in Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets))
+            {
+                path = AssetDatabase.GetAssetPath(obj);
+                if (!string.IsNullOrEmpty(path) && File.Exists(path))
+                {
+                    path = Path.GetDirectoryName(path);
+                    break;
+                }
+            }
+
+            return path;
+        }
+    }
+}

+ 11 - 0
Editor/EnvFix/UXRSDKConfigEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9988f2e84abccfb4fbb8cad8e8da7558
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Editor/Interaction.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1553e371b94ab469b8133ca55a61506b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 16 - 0
Editor/Interaction/EditorConstants.cs

@@ -0,0 +1,16 @@
+using UnityEngine;
+
+namespace Rokid.UXR.Editor {	
+	public class EditorConstants
+	{
+	    public static readonly Color PRIMARY_COLOR = new Color(0f, 1f, 1f, 0.5f);
+	    public static readonly Color PRIMARY_COLOR_DISABLED = new Color(0f, 1f, 1f, 0.1f);
+	
+	    public static readonly Color SECONDARY_COLOR = new Color(0.5f, 0.3f, 1f, 0.5f);
+	    public static readonly Color SECONDARY_COLOR_DISABLED = new Color(0.5f, 0.3f, 1f, 0.1f);
+	
+	    public static readonly float LINE_THICKNESS = 2f;
+	
+	    public static readonly float ROW_HEIGHT = 20f;
+	}
+}

+ 11 - 0
Editor/Interaction/EditorConstants.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ce72a9235e0f447bfa3efa1b6ac2a8c2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 69 - 0
Editor/Interaction/InputModuleSwitchActiveEditor.cs

@@ -0,0 +1,69 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEditor.AnimatedValues;
+using Rokid.UXR.Interaction;
+
+namespace Rokid.UXR.Editor
+{
+    [CustomEditor(typeof(InputModuleSwitchActive))]
+    public class InputModuleSwitchActiveEditor : UnityEditor.Editor
+    {
+        SerializedProperty activeModuleType;
+        SerializedProperty handActiveDetail;
+        SerializedProperty behaviour;
+        AnimBool showHandInfo;
+        private void OnEnable()
+        {
+            activeModuleType = serializedObject.FindProperty("activeModuleType");
+            handActiveDetail = serializedObject.FindProperty("handActiveDetail");
+            behaviour = serializedObject.FindProperty("behaviour");
+            showHandInfo = new AnimBool(Repaint);
+#if UNITY_2021_3_OR_NEWER
+            SetAnimBools(true);
+#endif
+        }
+
+        void SetAnimBool(AnimBool a, bool value, bool instant)
+        {
+            if (instant)
+                a.value = value;
+            else
+                a.target = value;
+        }
+
+#if UNITY_2021_3_OR_NEWER
+        void SetAnimBools(bool instant)
+        {
+            SetAnimBool(showHandInfo, !activeModuleType.hasMultipleDifferentValues && Contain(activeModuleType.enumValueFlag, (int)ActiveModuleType.Gesture), instant);
+        }
+#endif
+
+        private bool Contain(int inData, int targetData)
+        {
+            return (inData & targetData) == targetData;
+        }
+
+
+
+        public override void OnInspectorGUI()
+        {
+#if UNITY_2021_3_OR_NEWER
+            SetAnimBools(false);
+            serializedObject.Update();
+            EditorGUILayout.PropertyField(activeModuleType);
+            if (EditorGUILayout.BeginFadeGroup(showHandInfo.faded))
+            {
+                EditorGUI.indentLevel++;
+                EditorGUILayout.PropertyField(handActiveDetail);
+                EditorGUI.indentLevel--;
+            }
+            EditorGUILayout.EndFadeGroup();
+            EditorGUILayout.PropertyField(behaviour);
+            EditorGUILayout.Space();
+            serializedObject.ApplyModifiedProperties();
+#else
+	        base.OnInspectorGUI();
+#endif
+        }
+    }
+}

+ 11 - 0
Editor/Interaction/InputModuleSwitchActiveEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 409ac0b6a802c45b9a3bcf17f4b18a21
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Editor/Interaction/Poke.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 60ef453abc0f6463eb505dfa4e6d682c
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 33 - 0
Editor/Interaction/Poke/BoxProximityFieldEditor.cs

@@ -0,0 +1,33 @@
+using UnityEditor;
+using UnityEngine;
+using Rokid.UXR.Interaction;
+
+namespace Rokid.UXR.Editor
+{
+    [CustomEditor(typeof(BoxProximityField))]
+    public class BoxProximityFieldEditor : UnityEditor.Editor
+    {
+        private SerializedProperty _boxTransformProperty;
+
+        private void Awake()
+        {
+            _boxTransformProperty = serializedObject.FindProperty("_boxTransform");
+        }
+
+        public void OnSceneGUI()
+        {
+            Debug.Log("Draw OnSceneGUI");
+            Handles.color = EditorConstants.PRIMARY_COLOR;
+
+            Transform boxTransform = _boxTransformProperty.objectReferenceValue as Transform;
+
+            if (boxTransform != null)
+            {
+                using (new Handles.DrawingScope(boxTransform.localToWorldMatrix))
+                {
+                    Handles.DrawWireCube(Vector3.zero, Vector3.one);
+                }
+            }
+        }
+    }
+}

+ 11 - 0
Editor/Interaction/Poke/BoxProximityFieldEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2d5dae4c09a1d4d079719163ca529cb7
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 32 - 0
Editor/Interaction/Poke/CircleProximityFieldEditor.cs

@@ -0,0 +1,32 @@
+using UnityEditor;
+using UnityEngine;
+using Rokid.UXR.Interaction;
+
+namespace Rokid.UXR.Editor
+{
+    [CustomEditor(typeof(CircleProximityField))]
+    public class CircleProximityFieldEditor : UnityEditor.Editor
+    {
+        private SerializedProperty _transformProperty;
+        private SerializedProperty _radiusProperty;
+
+        private void Awake()
+        {
+            _transformProperty = serializedObject.FindProperty("_transform");
+            _radiusProperty = serializedObject.FindProperty("_radius");
+        }
+
+        public void OnSceneGUI()
+        {
+            Handles.color = EditorConstants.PRIMARY_COLOR;
+
+            Transform transform = _transformProperty.objectReferenceValue as Transform;
+            float radius = _radiusProperty.floatValue * transform.lossyScale.x;
+#if UNITY_2020_2_OR_NEWER
+            Handles.DrawWireDisc(transform.position, -transform.forward, radius, EditorConstants.LINE_THICKNESS);
+#else
+            Handles.DrawWireDisc(transform.position, -transform.forward, radius);
+#endif
+        }
+    }
+}

+ 11 - 0
Editor/Interaction/Poke/CircleProximityFieldEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b9a2e33915c4e4495ab8bee9488e6b15
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 135 - 0
Editor/Interaction/Poke/CylinderProximityFieldEditor.cs

@@ -0,0 +1,135 @@
+
+using UnityEditor;
+using UnityEngine;
+using Rokid.UXR.Interaction;
+namespace Rokid.UXR.Editor
+{
+    [CustomEditor(typeof(CylinderProximityField))]
+    public class CylinderProximityFieldEditor : UnityEditor.Editor
+    {
+        private const int SEGMENTS_PER_UNIT = 5;
+
+        private SerializedProperty _curvedPlaneProperty;
+
+        private void OnEnable()
+        {
+            _curvedPlaneProperty = serializedObject.FindProperty("_curvedPlane");
+        }
+
+        public override void OnInspectorGUI()
+        {
+            serializedObject.Update();
+            CylinderProximityField proxField = target as CylinderProximityField;
+            if (_curvedPlaneProperty.objectReferenceValue != null &&
+                _curvedPlaneProperty.objectReferenceValue != proxField)
+            {
+                GUIStyle italicLabel = new GUIStyle(GUI.skin.label);
+                italicLabel.fontStyle = FontStyle.Italic;
+
+                EditorGUILayout.Space();
+                EditorGUILayout.LabelField($"{typeof(ICurvedPlane).Name} properties overridden by " +
+                    $"{_curvedPlaneProperty.objectReferenceValue.GetType().Name}", italicLabel);
+                EditorGUILayout.PropertyField(_curvedPlaneProperty);
+            }
+            else
+            {
+                DrawDefaultInspector();
+            }
+            serializedObject.ApplyModifiedProperties();
+        }
+
+        public void OnSceneGUI()
+        {
+            ICurvedPlane curvedPlane = _curvedPlaneProperty.objectReferenceValue as ICurvedPlane;
+            if (curvedPlane == null)
+            {
+                curvedPlane = target as ICurvedPlane;
+            }
+
+            if (curvedPlane.Cylinder == null ||
+                curvedPlane.ArcDegrees <= 0f)
+            {
+                return;
+            }
+
+            Handles.color = EditorConstants.PRIMARY_COLOR;
+
+            // Handle infinite height using scene camera Y
+            float top, bottom;
+            if (curvedPlane.Top <= curvedPlane.Bottom)
+            {
+                if (SceneView.lastActiveSceneView != null &&
+                    SceneView.lastActiveSceneView.camera != null)
+                {
+                    Vector3 cameraPos =
+                        curvedPlane.Cylinder.transform.InverseTransformPoint(
+                            SceneView.lastActiveSceneView.camera.transform.position);
+                    bottom = cameraPos.y - 10;
+                    top = cameraPos.y + 10;
+                }
+                else
+                {
+                    bottom = -30;
+                    top = 30;
+                }
+            }
+            else
+            {
+                bottom = curvedPlane.Bottom;
+                top = curvedPlane.Top;
+            }
+
+            float height = top - bottom;
+            float width = curvedPlane.ArcDegrees * Mathf.Deg2Rad * curvedPlane.Cylinder.Radius;
+            int verticalSegments = Mathf.Max(2, Mathf.CeilToInt(SEGMENTS_PER_UNIT * height));
+            int horizontalSegments = Mathf.Max(2, Mathf.FloorToInt(SEGMENTS_PER_UNIT * width));
+
+            for (int v = 0; v <= verticalSegments; ++v)
+            {
+                float y = Mathf.Lerp(bottom, top, (float)v / verticalSegments);
+                DrawArc(curvedPlane, y);
+            }
+
+            for (int h = 0; h <= horizontalSegments; ++h)
+            {
+                float x = Mathf.Lerp(-curvedPlane.ArcDegrees / 2,
+                                     curvedPlane.ArcDegrees / 2,
+                                     (float)h / horizontalSegments);
+                DrawLine(curvedPlane, bottom, top, x);
+            }
+        }
+
+        private void DrawArc(ICurvedPlane curvedPlane, float y)
+        {
+            Vector3 center = curvedPlane.Cylinder.transform.TransformPoint(new Vector3(0, y, 0));
+            Vector3 forward = curvedPlane.Cylinder.transform.TransformDirection(
+                Quaternion.Euler(0, curvedPlane.Rotation - curvedPlane.ArcDegrees / 2, 0) *
+                Vector3.forward);
+
+            Handles.DrawWireArc(center,
+                     curvedPlane.Cylinder.transform.up,
+                     forward,
+                     curvedPlane.ArcDegrees,
+                     curvedPlane.Cylinder.Radius * curvedPlane.Cylinder.transform.lossyScale.z
+#if UNITY_2020_2_OR_NEWER
+                     , EditorConstants.LINE_THICKNESS
+#endif
+                     );
+        }
+
+        private void DrawLine(ICurvedPlane curvedPlane, float bottom, float top, float deg)
+        {
+            Vector3 forward = Quaternion.Euler(0, curvedPlane.Rotation + deg, 0) *
+                Vector3.forward * curvedPlane.Cylinder.Radius;
+
+            Vector3 p1 = curvedPlane.Cylinder.transform.TransformPoint((Vector3.up * bottom) + forward);
+            Vector3 p2 = curvedPlane.Cylinder.transform.TransformPoint((Vector3.up * top) + forward);
+
+#if UNITY_2020_2_OR_NEWER
+            Handles.DrawLine(p1, p2, EditorConstants.LINE_THICKNESS);
+#else
+            Handles.DrawLine(p1, p2);
+#endif
+        }
+    }
+}

+ 11 - 0
Editor/Interaction/Poke/CylinderProximityFieldEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 74290836ec4b4a34abf34313e6af3d73
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 66 - 0
Editor/Interaction/Poke/PokeInteractableEditor.cs

@@ -0,0 +1,66 @@
+using UnityEditor;
+using UnityEngine;
+using Rokid.UXR.Interaction;
+namespace Rokid.UXR.Editor
+{
+    [CustomEditor(typeof(PokeInteractable))]
+    public class PokeInteractableEditor : UnityEditor.Editor
+    {
+        private PokeInteractable _interactable;
+
+        private SerializedProperty _proximityFieldProperty;
+        private SerializedProperty _surfaceProperty;
+
+        private static readonly float DRAW_RADIUS = 0.02f;
+
+        private void Awake()
+        {
+            _interactable = target as PokeInteractable;
+
+            _proximityFieldProperty = serializedObject.FindProperty("_proximityField");
+            _surfaceProperty = serializedObject.FindProperty("_surface");
+        }
+
+        public void OnSceneGUI()
+        {
+            Handles.color = EditorConstants.PRIMARY_COLOR;
+            PlaneSurface plane = _surfaceProperty.objectReferenceValue as PlaneSurface;
+
+            if (plane == null)
+            {
+                // TODO support non-planar surfaces for this gizmo?
+                return;
+            }
+
+            Transform triggerPlaneTransform = plane.transform;
+            IProximityField proximityField = _proximityFieldProperty.objectReferenceValue as IProximityField;
+
+            if (triggerPlaneTransform == null
+                || proximityField == null)
+            {
+                return;
+            }
+
+            Vector3 touchPoint = triggerPlaneTransform.position - triggerPlaneTransform.forward * _interactable.MaxDistance;
+            Vector3 proximalPoint = proximityField.ComputeClosestPoint(touchPoint);
+
+            Handles.DrawSolidDisc(touchPoint, triggerPlaneTransform.forward, DRAW_RADIUS);
+
+#if UNITY_2020_2_OR_NEWER
+            Handles.DrawLine(touchPoint, proximalPoint, EditorConstants.LINE_THICKNESS);
+
+            Handles.DrawLine(proximalPoint - triggerPlaneTransform.right * DRAW_RADIUS,
+                proximalPoint + triggerPlaneTransform.right * DRAW_RADIUS, EditorConstants.LINE_THICKNESS);
+            Handles.DrawLine(proximalPoint - triggerPlaneTransform.up * DRAW_RADIUS,
+                proximalPoint + triggerPlaneTransform.up * DRAW_RADIUS, EditorConstants.LINE_THICKNESS);
+#else
+	            Handles.DrawLine(touchPoint, proximalPoint);
+	
+	            Handles.DrawLine(proximalPoint - triggerPlaneTransform.right * DRAW_RADIUS,
+	                proximalPoint + triggerPlaneTransform.right * DRAW_RADIUS);
+	            Handles.DrawLine(proximalPoint - triggerPlaneTransform.up * DRAW_RADIUS,
+	                proximalPoint + triggerPlaneTransform.up * DRAW_RADIUS);
+#endif
+        }
+    }
+}

+ 11 - 0
Editor/Interaction/Poke/PokeInteractableEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 308350aa983f9894b8b098e2eba08a60
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Editor/Interaction/Surfaces.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5771bb80af4e24e0797534d71532b4f8
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 78 - 0
Editor/Interaction/Surfaces/CylinderSurfaceEditor.cs

@@ -0,0 +1,78 @@
+using UnityEngine;
+using UnityEditor;
+using Rokid.UXR.Interaction;
+namespace Rokid.UXR.Editor
+{
+    [CustomEditor(typeof(CylinderSurface))]
+    public class CylinderSurfaceEditor : UnityEditor.Editor
+    {
+        private const int NUM_SEGMENTS = 30;
+
+        private static readonly Color ValidColor = Color.green * 0.8f;
+
+        private static readonly Color InvalidColor = Color.red * 0.8f;
+
+        public void OnSceneGUI()
+        {
+            CylinderSurface cylinder = target as CylinderSurface;
+
+            if (cylinder.Cylinder != null)
+            {
+                Draw(cylinder);
+            }
+        }
+
+        public static void Draw(CylinderSurface cylinderSurface)
+        {
+            Color prevColor = Handles.color;
+            Handles.color = cylinderSurface.IsValid ? ValidColor : InvalidColor;
+
+            float gizmoHeight = cylinderSurface.Height;
+            float camYOffset = 0;
+            bool infiniteHeight = cylinderSurface.Height <= 0;
+
+            if (infiniteHeight && SceneView.lastActiveSceneView?.camera != null)
+            {
+                gizmoHeight = 1000f;
+                Vector3 sceneCamPos = SceneView.lastActiveSceneView.camera.transform.position;
+                camYOffset = cylinderSurface.Cylinder.transform.InverseTransformPoint(sceneCamPos).y;
+            }
+
+            for (int i = 0; i < 2; ++i)
+            {
+                bool isTop = i == 1;
+                float y = isTop ? gizmoHeight / 2 : -gizmoHeight / 2;
+                int numSegments = (int)(NUM_SEGMENTS * Mathf.Max(cylinderSurface.Radius / 2, 1));
+                Vector3 prevSegmentWorld = Vector3.zero;
+
+                for (int seg = 0; seg <= numSegments; ++seg)
+                {
+                    float ratio = (float)seg / numSegments * Mathf.PI * 2;
+                    float x = Mathf.Cos(ratio) * cylinderSurface.Radius;
+                    float z = Mathf.Sin(ratio) * cylinderSurface.Radius;
+                    Vector3 curSegmentLocal = new Vector3(x, y + camYOffset, z);
+                    Vector3 curSegmentWorld = cylinderSurface.Cylinder.transform.TransformPoint(curSegmentLocal);
+
+                    if (isTop) // Draw connecting lines from top circle
+                    {
+                        Vector3 bottomVert = new Vector3(curSegmentLocal.x,
+                                                         curSegmentLocal.y - gizmoHeight,
+                                                         curSegmentLocal.z);
+                        bottomVert = cylinderSurface.Cylinder.transform.TransformPoint(bottomVert);
+                        Handles.DrawLine(curSegmentWorld, bottomVert);
+                    }
+
+                    if (seg > 0 && !infiniteHeight)
+                    {
+                        Handles.DrawLine(curSegmentWorld, prevSegmentWorld);
+                    }
+
+                    prevSegmentWorld = curSegmentWorld;
+                }
+            }
+
+            Handles.color = prevColor;
+        }
+    }
+
+}

+ 11 - 0
Editor/Interaction/Surfaces/CylinderSurfaceEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e07ffae6a51b8ba438d7976a6c2dfd0d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 86 - 0
Editor/Interaction/Surfaces/PlaneSurfaceEditor.cs

@@ -0,0 +1,86 @@
+
+using UnityEngine;
+using UnityEditor;
+using Rokid.UXR.Interaction;
+namespace Rokid.UXR.Editor
+{
+    [CustomEditor(typeof(PlaneSurface))]
+    public class PlaneSurfaceEditor : UnityEditor.Editor
+    {
+        private const int NUM_SEGMENTS = 40;
+        private const float FADE_DISTANCE = 10f;
+
+        private static readonly Color Color = EditorConstants.PRIMARY_COLOR_DISABLED;
+
+        private static float Interval => FADE_DISTANCE / NUM_SEGMENTS;
+
+        public void OnSceneGUI()
+        {
+            PlaneSurface plane = target as PlaneSurface;
+            Draw(plane);
+        }
+
+        public static void Draw(PlaneSurface plane)
+        {
+            Vector3 origin = plane.transform.position;
+
+            if (SceneView.lastActiveSceneView?.camera != null)
+            {
+                Transform camTransform = SceneView.lastActiveSceneView.camera.transform;
+                if (plane.ClosestSurfacePoint(camTransform.position, out SurfaceHit hit, 0))
+                {
+                    Vector3 hitDelta = PoseUtils.Delta(plane.transform, new Pose(hit.Point, plane.transform.rotation)).position;
+                    hitDelta.x = Mathf.RoundToInt(hitDelta.x / Interval) * Interval;
+                    hitDelta.y = Mathf.RoundToInt(hitDelta.y / Interval) * Interval;
+                    hitDelta.z = 0f;
+                    origin = PoseUtils.Multiply(plane.transform.GetPose(), new Pose(hitDelta, Quaternion.identity)).position;
+                }
+            }
+
+            DrawLines(origin, plane.Normal, plane.transform.up, Color);
+            DrawLines(origin, plane.Normal, -plane.transform.up, Color);
+            DrawLines(origin, plane.Normal, plane.transform.right, Color);
+            DrawLines(origin, plane.Normal, -plane.transform.right, Color);
+        }
+
+        private static void DrawLines(in Vector3 origin,
+                                      in Vector3 normal,
+                                      in Vector3 direction,
+                                      in Color baseColor)
+        {
+            Color prevColor = Handles.color;
+            Color color = baseColor;
+            Vector3 offsetOrigin = origin;
+
+            for (int i = 0; i < NUM_SEGMENTS; ++i)
+            {
+                Handles.color = color;
+
+                Vector3 cross = Vector3.Cross(normal, direction).normalized;
+                float interval = Interval;
+
+                for (int j = -NUM_SEGMENTS; j < NUM_SEGMENTS; ++j)
+                {
+                    float horizStart = interval * j;
+                    float horizEnd = horizStart + interval;
+
+                    Vector3 start = offsetOrigin + cross * horizStart;
+                    Vector3 end = offsetOrigin + cross * horizEnd;
+
+                    color.a = 1f - Mathf.Abs((float)j / NUM_SEGMENTS);
+                    color.a *= 1f - ((float)i / NUM_SEGMENTS);
+                    color.a *= color.a;
+
+                    Handles.color = color;
+                    Handles.DrawLine(start, end);
+                }
+
+                offsetOrigin += direction * interval;
+                color = baseColor;
+            }
+
+            Handles.color = prevColor;
+        }
+    }
+
+}

+ 11 - 0
Editor/Interaction/Surfaces/PlaneSurfaceEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cc41df2906bfe5d4a97191241199d6bd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Editor/Interaction/UnityCanvas.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 307cfae6ee7564c1cb54b0c0e74241f6
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 43 - 0
Editor/Interaction/UnityCanvas/CanvasMeshRendererEditor.cs

@@ -0,0 +1,43 @@
+
+using UnityEditor;
+using Rokid.UXR.Interaction;
+namespace Rokid.UXR.Editor
+{
+    using props = CanvasMeshRenderer.Properties;
+    [CustomEditor(typeof(CanvasMeshRenderer))]
+    public class CanvasMeshRendererEditor : EditorBase
+    {
+        public new CanvasMeshRenderer target
+        {
+            get
+            {
+                return base.target as CanvasMeshRenderer;
+            }
+        }
+
+        protected override void OnEnable()
+        {
+            var renderingModeProp = serializedObject.FindProperty(props.RenderingMode);
+
+            Draw(props.RenderingMode, (modeProp) =>
+            {
+                RenderingMode value = (RenderingMode)modeProp.intValue;
+                value = (RenderingMode)EditorGUILayout.EnumPopup("Rendering Mode", value);
+                modeProp.intValue = (int)value;
+            });
+
+            Draw(props.UseAlphaToMask, props.AlphaCutoutThreshold, (maskProp, cutoutProp) =>
+            {
+                if (renderingModeProp.intValue == (int)RenderingMode.AlphaCutout)
+                {
+                    EditorGUILayout.PropertyField(maskProp);
+
+                    if (maskProp.boolValue == false)
+                    {
+                        EditorGUILayout.PropertyField(cutoutProp);
+                    }
+                }
+            });
+        }
+    }
+}

+ 11 - 0
Editor/Interaction/UnityCanvas/CanvasMeshRendererEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: db65613a594f713489f00e3bbff90e17
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 238 - 0
Editor/Interaction/UnityCanvas/CanvasRenderTextureEditor.cs

@@ -0,0 +1,238 @@
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+using UnityEditor;
+using Rokid.UXR.Interaction;
+
+namespace Rokid.UXR.Editor
+{
+    using props = CanvasRenderTexture.Properties;
+
+    [CustomEditor(typeof(CanvasRenderTexture))]
+    public class CanvasRenderTextureEditor : EditorBase
+    {
+        private static List<CanvasRenderer> _tmpRenderers = new List<CanvasRenderer>();
+        private static List<Graphic> _tmpGraphics = new List<Graphic>();
+
+        public new CanvasRenderTexture target
+        {
+            get
+            {
+                return base.target as CanvasRenderTexture;
+            }
+        }
+
+        protected override void OnEnable()
+        {
+            var canvasProp = serializedObject.FindProperty(props.Canvas);
+
+            Draw(props.Resolution, props.DimensionDriveMode, (resProp, modeProp) =>
+            {
+                Rect rect = GUILayoutUtility.GetRect(0, EditorGUIUtility.singleLineHeight);
+
+                Rect labelRect = rect;
+                labelRect.width = EditorGUIUtility.labelWidth;
+
+                Rect dropdownRect = rect;
+                dropdownRect.x = rect.xMax - 70;
+                dropdownRect.width = 70;
+
+                Rect contentRect = rect;
+                contentRect.xMin = labelRect.xMax;
+                contentRect.xMax = dropdownRect.xMin;
+
+                GUI.Label(labelRect, resProp.displayName);
+
+                if (modeProp.intValue == (int)CanvasRenderTexture.DriveMode.Auto && canvasProp.objectReferenceValue != null)
+                {
+                    using (new EditorGUI.DisabledScope(true))
+                    {
+                        EditorGUI.Vector2IntField(contentRect, GUIContent.none, target.CalcAutoResolution());
+                    }
+                }
+                else
+                {
+                    resProp.vector2IntValue = EditorGUI.Vector2IntField(contentRect, GUIContent.none, resProp.vector2IntValue);
+                }
+
+                EditorGUI.PropertyField(dropdownRect, modeProp, GUIContent.none);
+            });
+
+            Draw(props.PixelsPerUnit, props.GenerateMipMaps, (pixelsPerUnit, mipmaps) =>
+            {
+                var driveMode = serializedObject.FindProperty(props.DimensionDriveMode);
+                if (driveMode.intValue == (int)CanvasRenderTexture.DriveMode.Auto)
+                {
+                    EditorGUILayout.PropertyField(pixelsPerUnit);
+                }
+                EditorGUILayout.PropertyField(mipmaps);
+            });
+        }
+
+        protected override void OnBeforeInspector()
+        {
+            base.OnBeforeInspector();
+
+            bool isEmpty;
+
+            AutoFix(AutoFixIsUsingScreenSpaceCanvas(), AutoFixSetToWorldSpaceCamera, "The OverlayRenderer only supports Canvases that are set to World Space.");
+
+            AutoFix(isEmpty = AutoFixIsMaskEmpty(), AutoFixAssignUIToMask, "The rendering Mask is empty, it needs to contain at least one layer for rendering to function.");
+
+            if (!isEmpty)
+            {
+                AutoFix(AutoFixAnyCamerasRenderingTargetLayers(), AutoFixRemoveRenderingMaskFromCameras, "Some cameras are rendering using a layer that is specified here as a Rendering layer. This can cause the UI to be rendered twice.");
+                AutoFix(AutoFixAnyRenderersOnUnrenderedLayers(), AutoFixMoveRenderersToMaskedLayers, "Some CanvasRenderers are using a layer that is not included in the rendered LayerMask.");
+            }
+        }
+
+        #region AutoFix
+
+        private bool AutoFix(bool needsFix, Action fixAction, string message)
+        {
+            if (needsFix)
+            {
+                using (new EditorGUILayout.HorizontalScope())
+                {
+                    EditorGUILayout.HelpBox(message, MessageType.Warning);
+                    if (GUILayout.Button("Auto-Fix", GUILayout.ExpandHeight(true)))
+                    {
+                        fixAction();
+                    }
+                }
+            }
+
+            return needsFix;
+        }
+
+        private bool AutoFixIsUsingScreenSpaceCanvas()
+        {
+            Canvas canvas = target.GetComponent<Canvas>();
+            if (canvas == null)
+            {
+                return false;
+            }
+
+            return canvas.renderMode != RenderMode.WorldSpace;
+        }
+
+        private void AutoFixSetToWorldSpaceCamera()
+        {
+            Canvas canvas = target.GetComponent<Canvas>();
+            if (canvas != null)
+            {
+                Undo.RecordObject(canvas, "Set Canvas To World Space");
+                canvas.renderMode = RenderMode.WorldSpace;
+            }
+        }
+
+        private bool AutoFixIsMaskEmpty()
+        {
+            var layerProp = serializedObject.FindProperty(props.RenderLayers);
+            return layerProp.intValue == 0;
+        }
+
+        public void AutoFixAssignUIToMask()
+        {
+            Undo.RecordObject(target, "Set Overlay Mask");
+            var layerProp = serializedObject.FindProperty(props.RenderLayers);
+            layerProp.intValue = CanvasRenderTexture.DEFAULT_UI_LAYERMASK;
+            serializedObject.ApplyModifiedProperties();
+        }
+
+        private bool AutoFixAnyRenderersOnUnrenderedLayers()
+        {
+            var canvasProp = serializedObject.FindProperty(props.Canvas);
+            Canvas canvas = canvasProp.objectReferenceValue as Canvas;
+
+            if (canvas == null)
+            {
+                return false;
+            }
+
+            canvas.gameObject.GetComponentsInChildren(_tmpRenderers);
+            foreach (var renderer in _tmpRenderers)
+            {
+                int layer = renderer.gameObject.layer;
+                if (((1 << layer) & target.RenderingLayers) == 0)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private void AutoFixMoveRenderersToMaskedLayers()
+        {
+            var canvasProp = serializedObject.FindProperty(props.Canvas);
+            Canvas canvas = canvasProp.objectReferenceValue as Canvas;
+
+            if (canvas == null)
+            {
+                return;
+            }
+
+            var maskedLayers = AutoFixGetMaskedLayers();
+            var targetLayer = maskedLayers.FirstOrDefault();
+
+            canvas.gameObject.GetComponentsInChildren(_tmpRenderers);
+            foreach (var renderer in _tmpRenderers)
+            {
+                int layer = renderer.gameObject.layer;
+                if ((layer & target.RenderingLayers) == 0)
+                {
+                    Undo.RecordObject(renderer.gameObject, "Set Overlay Layer");
+                    renderer.gameObject.layer = targetLayer;
+                }
+            }
+        }
+
+        private bool AutoFixAnyCamerasRenderingTargetLayers()
+        {
+            var cameras = FindObjectsOfType<Camera>();
+            foreach (var camera in cameras)
+            {
+                //Ignore the special camera we create to render to the overlay
+                if (camera == target.OverlayCamera)
+                {
+                    continue;
+                }
+
+                if ((camera.cullingMask & target.RenderingLayers) != 0)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private void AutoFixRemoveRenderingMaskFromCameras()
+        {
+            var cameras = FindObjectsOfType<Camera>();
+            foreach (var camera in cameras)
+            {
+                Undo.RecordObject(camera, "Set Camera Culling Mask");
+                camera.cullingMask = camera.cullingMask & ~target.RenderingLayers;
+            }
+        }
+
+        private List<int> AutoFixGetMaskedLayers()
+        {
+            List<int> maskedLayers = new List<int>();
+            for (int i = 0; i < 32; i++)
+            {
+                if ((target.RenderingLayers & (1 << i)) != 0)
+                {
+                    maskedLayers.Add(i);
+                }
+            }
+            return maskedLayers;
+        }
+        #endregion
+    }
+}

+ 11 - 0
Editor/Interaction/UnityCanvas/CanvasRenderTextureEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 34148f8fe2640204181a843e9af84fdd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 133 - 0
Editor/Interaction/UnityCanvas/OVRCanvasMeshRendererEditor.cs

@@ -0,0 +1,133 @@
+
+using System;
+using UnityEngine;
+using UnityEditor;
+using Rokid.UXR.Interaction;
+
+namespace Rokid.UXR.Editor
+{
+    using props = RKCanvasMeshRenderer.Properties;
+    using baseProps = CanvasMeshRenderer.Properties;
+    using rtprops = CanvasRenderTexture.Properties;
+    [CustomEditor(typeof(RKCanvasMeshRenderer))]
+    public class RKCanvasMeshRendererEditor : EditorBase
+    {
+        public new RKCanvasMeshRenderer target
+        {
+            get
+            {
+                return base.target as RKCanvasMeshRenderer;
+            }
+        }
+
+        protected override void OnEnable()
+        {
+            Defer(baseProps.UseAlphaToMask, baseProps.AlphaCutoutThreshold);
+            var renderingMode = serializedObject.FindProperty(baseProps.RenderingMode);
+
+            bool CheckIsOVR()
+            {
+                return renderingMode.intValue == (int)RKRenderingMode.Underlay ||
+                       renderingMode.intValue == (int)RKRenderingMode.Overlay;
+            }
+
+            Draw(props.RuntimeOffset, (offsetProp) =>
+            {
+                if (CheckIsOVR())
+                {
+                    EditorGUILayout.PropertyField(offsetProp);
+                }
+            });
+
+            Draw(baseProps.RenderingMode, props.CanvasMesh, (modeProp, meshProp) =>
+            {
+                EditorGUILayout.PropertyField(meshProp);
+                RKRenderingMode value = (RKRenderingMode)modeProp.intValue;
+                value = (RKRenderingMode)EditorGUILayout.EnumPopup("Rendering Mode", value);
+                modeProp.intValue = (int)value;
+            });
+
+            Draw(props.EnableSuperSampling, props.EmulateWhileInEditor, props.DoUnderlayAntiAliasing, (sampleProp, emulateProp, aaProp) =>
+            {
+                if (CheckIsOVR())
+                {
+                    EditorGUILayout.PropertyField(sampleProp);
+                    if (renderingMode.intValue == (int)RKRenderingMode.Underlay)
+                    {
+                        EditorGUILayout.PropertyField(aaProp);
+                    }
+                    EditorGUILayout.PropertyField(emulateProp);
+                }
+            });
+
+            Draw(baseProps.UseAlphaToMask, baseProps.AlphaCutoutThreshold, (maskProp, cutoutProp) =>
+            {
+                if (renderingMode.intValue == (int)RKRenderingMode.AlphaCutout)
+                {
+                    EditorGUILayout.PropertyField(maskProp);
+
+                    if (maskProp.boolValue == false)
+                    {
+                        EditorGUILayout.PropertyField(cutoutProp);
+                    }
+                }
+            });
+        }
+
+        protected override void OnBeforeInspector()
+        {
+            base.OnBeforeInspector();
+            AutoFix(AutoFixIsUsingMipMaps(), AutoFixDisableMipMaps, $"{nameof(CanvasRenderTexture)} " +
+            $"is generating mip maps, but these are ignored when using OVR Overlay/Underlay rendering.");
+        }
+
+
+        private bool AutoFix(bool needsFix, Action fixAction, string message)
+        {
+            if (needsFix)
+            {
+                using (new EditorGUILayout.HorizontalScope())
+                {
+                    EditorGUILayout.HelpBox(message, MessageType.Warning);
+                    if (GUILayout.Button("Auto-Fix", GUILayout.ExpandHeight(true)))
+                    {
+                        fixAction();
+                    }
+                }
+            }
+
+            return needsFix;
+        }
+
+        private bool AutoFixIsUsingMipMaps()
+        {
+            var modeProp = serializedObject.FindProperty(baseProps.RenderingMode);
+            RKRenderingMode mode = (RKRenderingMode)modeProp.intValue;
+            if (mode != RKRenderingMode.Overlay && mode != RKRenderingMode.Underlay)
+            {
+                return false;
+            }
+
+            var rtProp = serializedObject.FindProperty(props.CanvasRenderTexture);
+            CanvasRenderTexture canvasRT = rtProp.objectReferenceValue as CanvasRenderTexture;
+            if (canvasRT == null)
+            {
+                return false;
+            }
+
+            var mipProp = new SerializedObject(canvasRT).FindProperty(rtprops.GenerateMipMaps);
+            return mipProp.boolValue;
+        }
+
+        private void AutoFixDisableMipMaps()
+        {
+            var rtProp = serializedObject.FindProperty(props.CanvasRenderTexture);
+            CanvasRenderTexture canvasRT = rtProp.objectReferenceValue as CanvasRenderTexture;
+            var rtSO = new SerializedObject(canvasRT);
+            var mipProp = rtSO.FindProperty(rtprops.GenerateMipMaps);
+            mipProp.boolValue = false;
+            rtSO.ApplyModifiedProperties();
+        }
+    }
+
+}

+ 11 - 0
Editor/Interaction/UnityCanvas/OVRCanvasMeshRendererEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 17dd37b61cae04688b739cd37ec3615a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Editor/InterfaceSupport.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0e93701f7111c8343b48fc4a99b918d5
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 245 - 0
Editor/InterfaceSupport/InterfaceDrawer.cs

@@ -0,0 +1,245 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+using Rokid.UXR.Interaction;
+
+namespace Rokid.UXR.Editor
+{
+
+    /// <summary>
+    /// This property drawer is the meat of the interface support implementation. When
+    /// the value of field with this attribute is modified, the new value is tested
+    /// against the interface expected. If the component matches, the new value is
+    /// accepted. Otherwise, the old value is maintained.
+    /// </summary>
+    [CustomPropertyDrawer(typeof(InterfaceAttribute))]
+    public class InterfaceDrawer : PropertyDrawer
+    {
+        private int _filteredObjectPickerID;
+        private static readonly Type[] _singleMonoBehaviourType = new Type[1] { typeof(MonoBehaviour) };
+
+        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+        {
+            _filteredObjectPickerID = GUIUtility.GetControlID(FocusType.Passive);
+            if (property.serializedObject.isEditingMultipleObjects) return;
+
+            if (property.propertyType != SerializedPropertyType.ObjectReference)
+            {
+                EditorGUI.LabelField(position, label.text, "InterfaceType Attribute can only be used with MonoBehaviour Components.");
+                return;
+            }
+
+            EditorGUI.BeginProperty(position, label, property);
+
+            Type[] attTypes = GetInterfaceTypes(property);
+
+            // Pick a specific component
+            MonoBehaviour oldComponent = property.objectReferenceValue as MonoBehaviour;
+            string oldComponentName = "";
+
+            GameObject temporaryGameObject = null;
+
+            string attTypesName = GetTypesName(attTypes);
+            if (Event.current.type == EventType.Repaint)
+            {
+                if (oldComponent == null)
+                {
+                    temporaryGameObject = new GameObject("None (" + attTypesName + ")");
+                    oldComponent = temporaryGameObject.AddComponent<InterfaceMono>();
+                }
+                else
+                {
+                    oldComponentName = oldComponent.name;
+                    oldComponent.name = oldComponentName + " (" + attTypesName + ")";
+                }
+            }
+
+            Component currentComponent = EditorGUI.ObjectField(position, label, oldComponent, typeof(Component), true) as Component;
+
+            int objectPickerID = GUIUtility.GetControlID(FocusType.Passive) - 1;
+            ReplaceObjectPickerForControl(attTypes, objectPickerID);
+            if (Event.current.commandName == "ObjectSelectorUpdated"
+                && EditorGUIUtility.GetObjectPickerControlID() == _filteredObjectPickerID)
+            {
+                UnityEngine.Object pickedObject = EditorGUIUtility.GetObjectPickerObject();
+                if (pickedObject is GameObject)
+                {
+                    currentComponent = (pickedObject as GameObject).transform;
+                }
+                else
+                {
+                    currentComponent = pickedObject as Component;
+                }
+            }
+
+            MonoBehaviour currentMono = currentComponent as MonoBehaviour;
+
+            if (Event.current.type == EventType.Repaint)
+            {
+                if (temporaryGameObject != null)
+                    GameObject.DestroyImmediate(temporaryGameObject);
+                else
+                    oldComponent.name = oldComponentName;
+            }
+
+            // If a component is assigned, make sure it is the interface we are looking for.
+            if (currentMono != null)
+            {
+                // Make sure component is of the right interface
+                if (!IsAssignableFromTypes(currentMono.GetType(), attTypes))
+                    // Component failed. Check game object.
+                    foreach (Type attType in attTypes)
+                    {
+                        currentMono = currentMono.gameObject.GetComponent(attType) as MonoBehaviour;
+                        if (currentMono == null)
+                        {
+                            break;
+                        }
+                    }
+
+                // Item failed test. Do not override old component
+                if (currentMono == null)
+                {
+                    if (oldComponent != null && !IsAssignableFromTypes(oldComponent.GetType(), attTypes))
+                    {
+                        temporaryGameObject = new GameObject("None (" + attTypesName + ")");
+                        MonoBehaviour temporaryComponent = temporaryGameObject.AddComponent<InterfaceMono>();
+                        currentMono = EditorGUI.ObjectField(position, label, temporaryComponent, typeof(MonoBehaviour), true) as MonoBehaviour;
+                        GameObject.DestroyImmediate(temporaryGameObject);
+                    }
+                }
+            }
+            else if (currentComponent is Transform)
+            {
+                // If assigned component is a Transform, this means a GameObject was dragged into the property field.
+                // Find all matching components on the transform's GameObject and open the picker window.
+
+                List<MonoBehaviour> monos = new List<MonoBehaviour>();
+                monos.AddRange(currentComponent.gameObject.GetComponents<MonoBehaviour>().
+                    Where((mono) => IsAssignableFromTypes(mono.GetType(), attTypes)));
+
+                if (monos.Count > 1)
+                {
+                    EditorApplication.delayCall += () => InterfacePicker.Show(property, monos);
+                }
+                else
+                {
+                    currentMono = monos.Count == 1 ? monos[0] : null;
+                }
+            }
+
+            if (currentComponent == null || currentMono != null)
+            {
+                property.objectReferenceValue = currentMono;
+            }
+
+            EditorGUI.EndProperty();
+        }
+
+        private bool IsAssignableFromTypes(Type source, Type[] targets)
+        {
+            foreach (Type t in targets)
+            {
+                if (!t.IsAssignableFrom(source))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        private static string GetTypesName(Type[] attTypes)
+        {
+            if (attTypes.Length == 1)
+            {
+                return GetTypeName(attTypes[0]);
+            }
+
+            string typesString = "";
+            for (int i = 0; i < attTypes.Length; i++)
+            {
+                if (i > 0)
+                {
+                    typesString += ", ";
+                }
+
+                typesString += GetTypeName(attTypes[i]);
+            }
+
+            return typesString;
+        }
+
+        private static string GetTypeName(Type attType)
+        {
+            if (!attType.IsGenericType)
+            {
+                return attType.Name;
+            }
+
+            var genericTypeNames = attType.GenericTypeArguments.Select(GetTypeName);
+            return $"{attType.Name}<{string.Join(", ", genericTypeNames)}>";
+        }
+
+        private Type[] GetInterfaceTypes(SerializedProperty property)
+        {
+            InterfaceAttribute att = (InterfaceAttribute)attribute;
+            Type[] t = att.Types;
+            if (!String.IsNullOrEmpty(att.TypeFromFieldName))
+            {
+                var thisType = property.serializedObject.targetObject.GetType();
+                while (thisType != null)
+                {
+                    var referredFieldInfo = thisType.GetField(att.TypeFromFieldName,
+                        BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+                    if (referredFieldInfo != null)
+                    {
+                        t = new Type[1] { referredFieldInfo.FieldType };
+                        break;
+                    }
+
+                    thisType = thisType.BaseType;
+                }
+            }
+
+            return t ?? _singleMonoBehaviourType;
+        }
+
+        void ReplaceObjectPickerForControl(Type[] attTypes, int replacePickerID)
+        {
+            var currentObjectPickerID = EditorGUIUtility.GetObjectPickerControlID();
+            if (currentObjectPickerID != replacePickerID)
+            {
+                return;
+            }
+
+            var derivedTypes = TypeCache.GetTypesDerivedFrom(attTypes[0]);
+            HashSet<Type> validTypes = new HashSet<Type>(derivedTypes);
+            for (int i = 1; i < attTypes.Length; i++)
+            {
+                var derivedTypesIntersect = TypeCache.GetTypesDerivedFrom(attTypes[i]);
+                validTypes.IntersectWith(derivedTypesIntersect);
+            }
+
+            //start filter with a long empty area to allow for easy clicking and typing
+            var filterBuilder = new System.Text.StringBuilder("                       ");
+            foreach (Type type in validTypes)
+            {
+                if (type.IsGenericType)
+                {
+                    continue;
+                }
+                filterBuilder.Append("t:" + type.FullName + " ");
+            }
+            string filter = filterBuilder.ToString();
+            EditorGUIUtility.ShowObjectPicker<Component>(null, true, filter, _filteredObjectPickerID);
+        }
+    }
+
+
+    public sealed class InterfaceMono : MonoBehaviour { }
+
+}

+ 11 - 0
Editor/InterfaceSupport/InterfaceDrawer.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b2fd211401b34f246897eb204ff3ca43
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 149 - 0
Editor/InterfaceSupport/InterfacePicker.cs

@@ -0,0 +1,149 @@
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEditor;
+using Rokid.UXR.Interaction;
+namespace Rokid.UXR.Editor
+{
+
+    public class InterfacePicker : EditorWindow
+    {
+        private class MonoInspector
+        {
+            public readonly MonoBehaviour Mono;
+            public readonly UnityEditor.Editor Editor;
+
+            public MonoInspector(MonoBehaviour mono)
+            {
+                Mono = mono;
+                Editor = UnityEditor.Editor.CreateEditor(mono);
+            }
+
+            public void Destroy()
+            {
+                DestroyImmediate(Editor);
+            }
+        }
+
+        private static class GUIStyles
+        {
+            public static readonly GUIStyle Default;
+            public static readonly GUIStyle Window;
+            public static readonly GUIStyle Inspector;
+
+            private static readonly RectOffset padding =
+                new RectOffset(EDGE_PADDING_PX,
+                               EDGE_PADDING_PX,
+                               EDGE_PADDING_PX,
+                               EDGE_PADDING_PX);
+
+            static GUIStyles()
+            {
+                Default = new GUIStyle();
+                Window = new GUIStyle(Default);
+                Window.padding = padding;
+                Inspector = new GUIStyle(GUI.skin.window);
+                Inspector.padding = padding;
+            }
+        }
+
+        private const float SELECT_BUTTON_HEIGHT_PX = 32f;
+        private const float LABEL_COLUMN_RATIO = 0.4f;
+        private const int EDGE_PADDING_PX = 8;
+
+        public static bool AnyOpen => HasOpenInstances<InterfacePicker>();
+
+        private Object _target;
+        private string _propertyPath;
+        private List<MonoInspector> _monoInspectors;
+        private Vector2 _scrollPos = Vector2.zero;
+
+        public static void Show(SerializedProperty prop, List<MonoBehaviour> monos)
+        {
+            if (monos == null ||
+                monos.Count == 0 ||
+                prop == null)
+            {
+                return;
+            }
+
+            InterfacePicker picker = GetWindow<InterfacePicker>(true);
+
+            picker._propertyPath = prop.propertyPath;
+            picker._target = prop.serializedObject.targetObject;
+            picker._monoInspectors?.ForEach((mi) => mi.Destroy());
+            picker._monoInspectors = new List<MonoInspector>();
+            picker.titleContent = new GUIContent(monos[0].gameObject.name);
+            monos.ForEach((m) => picker._monoInspectors.Add(new MonoInspector(m)));
+
+            picker.ShowUtility();
+        }
+
+        private void OnGUI()
+        {
+            if (_target == null)
+            {
+                Close();
+                return;
+            }
+
+            Prune();
+            DrawAll();
+        }
+
+        private void OnDestroy()
+        {
+            _monoInspectors.ForEach((mi) => mi.Destroy());
+        }
+
+        private void Prune()
+        {
+            _monoInspectors.FindAll((m) => m.Mono == null).ForEach((mi) =>
+            {
+                _monoInspectors.Remove(mi);
+                mi.Destroy();
+            });
+        }
+
+        private void DrawAll()
+        {
+            _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, GUIStyles.Window);
+            foreach (var monoInspector in _monoInspectors)
+            {
+                EditorGUILayout.Separator();
+                EditorGUILayout.BeginVertical(GUIStyles.Inspector);
+                DrawHeader(monoInspector);
+                EditorGUILayout.Separator();
+                DrawComponent(monoInspector);
+                EditorGUILayout.EndVertical();
+            }
+            GUILayout.FlexibleSpace();
+            EditorGUILayout.EndScrollView();
+        }
+
+        private void DrawHeader(MonoInspector monoInspector)
+        {
+            if (GUILayout.Button($"{monoInspector.Mono.GetType().Name}",
+                GUILayout.Height(SELECT_BUTTON_HEIGHT_PX)))
+            {
+                Apply(monoInspector.Mono);
+                Close();
+            }
+        }
+
+        private void DrawComponent(MonoInspector monoInspector)
+        {
+            GUI.enabled = false;
+            EditorGUIUtility.labelWidth = position.width * LABEL_COLUMN_RATIO;
+            monoInspector.Editor.OnInspectorGUI();
+            GUI.enabled = true;
+        }
+
+        private void Apply(MonoBehaviour mono)
+        {
+            SerializedProperty property =
+                new SerializedObject(_target).FindProperty(_propertyPath);
+            property.objectReferenceValue = mono;
+            property.serializedObject.ApplyModifiedProperties();
+        }
+    }
+}

+ 11 - 0
Editor/InterfaceSupport/InterfacePicker.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 13ee802452fb40949acff6a643c6d06a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 26 - 0
Editor/InterfaceSupport/OptionalDrawer.cs

@@ -0,0 +1,26 @@
+using UnityEngine;
+using UnityEditor;
+using Rokid.UXR.Interaction;
+
+namespace Rokid.UXR.Editor
+{
+    /// <summary>
+    /// Adds an [Optional] label in the inspector over any SerializedField with this attribute.
+    /// </summary>
+    [CustomPropertyDrawer(typeof(OptionalAttribute))]
+    public class OptionalDrawer : DecoratorDrawer
+    {
+        private static readonly float HEADER_SIZE_AS_PERCENT = 0.25f;
+
+        public override float GetHeight()
+        {
+            return base.GetHeight() * (1f + HEADER_SIZE_AS_PERCENT);
+        }
+
+        public override void OnGUI(Rect position)
+        {
+            position.y += GetHeight() * HEADER_SIZE_AS_PERCENT / (1f + HEADER_SIZE_AS_PERCENT);
+            EditorGUI.LabelField(position, "[Optional]");
+        }
+    }
+}

+ 11 - 0
Editor/InterfaceSupport/OptionalDrawer.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 404c5108e420549d6b2907d6827532b9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 21 - 0
Editor/Rokid.Unity.XR.Editor.asmdef

@@ -0,0 +1,21 @@
+{
+    "name": "Rokid.Unity.XR.Editor",
+    "rootNamespace": "",
+    "references": [
+        "GUID:e40ba710768534012815d3193fa296cb",
+        "GUID:f9fe0089ec81f4079af78eb2287a6163",
+        "GUID:2f52f0b6cfdc94464bcc067a11c8e1b6",
+        "GUID:fe14bc9dd681249d19cf4ef377c7e29e"
+    ],
+    "includePlatforms": [
+        "Editor"
+    ],
+    "excludePlatforms": [],
+    "allowUnsafeCode": false,
+    "overrideReferences": false,
+    "precompiledReferences": [],
+    "autoReferenced": true,
+    "defineConstraints": [],
+    "versionDefines": [],
+    "noEngineReferences": false
+}

+ 7 - 0
Editor/Rokid.Unity.XR.Editor.asmdef.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 3212ef8a892204f888080dd1016daf25
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Editor/Textures.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ed500a16274db2b4a91b1ce1fba38395
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Editor/Textures/RokidIcon.png


+ 96 - 0
Editor/Textures/RokidIcon.png.meta

@@ -0,0 +1,96 @@
+fileFormatVersion: 2
+guid: 13a3cac1e18100e4e9bfa5e20ee32507
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 11
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  vTOnly: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 0
+    wrapV: 0
+    wrapW: 0
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 0
+  spriteTessellationDetail: -1
+  textureType: 0
+  textureShape: 1
+  singleChannelComponent: 0
+  flipbookRows: 1
+  flipbookColumns: 1
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  ignorePngGamma: 0
+  applyGammaDecoding: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d3fec4b5bf562425eb2e57bbd066f07a
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 12 - 0
Runtime/ApiConstants.cs

@@ -0,0 +1,12 @@
+namespace Rokid.UXR
+{
+    /// <summary>
+    /// API library constants
+    /// </summary>
+    public static class ApiConstants
+    {
+        public const string UXR_GFX_PLUGIN = "GfxPluginRokidXRLoader";
+    }
+}
+
+

+ 11 - 0
Runtime/ApiConstants.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7f07a18323643ee4e80fad9f840cfb52
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Components.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 99dafeb21278e4fd2a99431bdac5aef2
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Components/AxisRender.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 55d2d7c9e2621401e8207fa514e0f7fa
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 114 - 0
Runtime/Components/AxisRender/Axis.cs

@@ -0,0 +1,114 @@
+using UnityEngine;
+
+namespace Rokid.UXR.Components
+{
+    public class Axis : MonoBehaviour
+    {
+        [Range(0.2f, 0.5f)]
+        public float arrowBottomSize = 0.2f;
+        [Range(0.2f, 0.5f)]
+        public float arrowHeight = 0.3f;
+        [Range(0.2f, 5)]
+        public float xLength = 2;
+        [Range(0.2f, 5)]
+        public float yLength = 2;
+        [Range(0.2f, 5)]
+        public float zLength = 2;
+
+        [Range(0.05f, 0.1f)]
+        public float lineTickness = 0.05f;//轴线的粗细
+
+        [Range(0.1f, 1)]
+        public float centerSize = 0.1f;
+
+
+        void Start()
+        {
+            transform.Find("X").GetComponent<MeshFilter>().mesh = DrawArrow(arrowHeight, arrowBottomSize, xLength, lineTickness, lineTickness);
+            transform.Find("Y").GetComponent<MeshFilter>().mesh = DrawArrow(arrowHeight, arrowBottomSize, yLength, lineTickness, lineTickness);
+            transform.Find("Z").GetComponent<MeshFilter>().mesh = DrawArrow(arrowHeight, arrowBottomSize, zLength, lineTickness, lineTickness);
+            UpdateArrowTsf();
+        }
+
+
+        /// <summary>
+        /// inspector 数据发生改变是调用
+        /// </summary>
+        void OnValidate()
+        {
+            // transform.Find("X").GetComponent<MeshFilter>().mesh = DrawArrow(arrowHeight, arrowBottomSize, xLength, lineTickness, lineTickness);
+            // transform.Find("Y").GetComponent<MeshFilter>().mesh = DrawArrow(arrowHeight, arrowBottomSize, yLength, lineTickness, lineTickness);
+            // transform.Find("Z").GetComponent<MeshFilter>().mesh = DrawArrow(arrowHeight, arrowBottomSize, zLength, lineTickness, lineTickness);
+            // UpdateArrowTsf();
+        }
+
+        /// <summary>
+        /// 根据输入箭头的长度不同更新箭头的位置
+        /// </summary>
+        void UpdateArrowTsf()
+        {
+            transform.Find("X").localPosition = new Vector3(xLength, 0, 0);
+            transform.Find("Y").localPosition = new Vector3(0, yLength, 0);
+            transform.Find("Z").localPosition = new Vector3(0, 0, zLength);
+            transform.Find("Center").localScale = Vector3.one * centerSize;
+        }
+
+
+        /// <summary>
+        /// 绘制箭头
+        /// </summary>
+        /// <param name="arrowHeight"></param>
+        /// <param name="arrowBottom"></param>
+        /// <param name="height"></param>
+        /// <param name="width"></param>
+        /// <param name="length"></param>
+        /// <returns></returns>
+        public Mesh DrawArrow(float arrowHeight, float arrowBottom, float height, float width, float length)
+        {
+            var arrow = new Mesh();
+            arrow.Clear();
+            Vector3[] vertexs = new Vector3[13];
+            //箭头
+            vertexs[0] = new Vector3(-arrowBottom / 2, 0, -arrowBottom / 2);
+            vertexs[1] = new Vector3(arrowBottom / 2, 0, -arrowBottom / 2);
+            vertexs[2] = new Vector3(arrowBottom / 2, 0, arrowBottom / 2);
+            vertexs[3] = new Vector3(-arrowBottom / 2, 0, arrowBottom / 2);
+            vertexs[4] = new Vector3(0, arrowHeight, 0);
+            //箭头尾部的线段
+            vertexs[5] = new Vector3(-width / 2, 0, -length / 2);
+            vertexs[6] = new Vector3(width / 2, 0, -length / 2);
+            vertexs[7] = new Vector3(width / 2, 0, length / 2);
+            vertexs[8] = new Vector3(-width / 2, 0, length / 2);
+
+            vertexs[9] = new Vector3(-width / 2, -height, -length / 2);
+            vertexs[10] = new Vector3(width / 2, -height, -length / 2);
+            vertexs[11] = new Vector3(width / 2, -height, length / 2);
+            vertexs[12] = new Vector3(-width / 2, -height, length / 2);
+            arrow.vertices = vertexs;
+            //顶点法线遵循左手螺旋定则
+            int[] vertexIndices = new int[] { 
+	            //bottom
+	            0,1,2,0,2,3,
+	            //up01
+	            0,4,1,
+	            //up02
+	            1,4,2,
+	            //up03
+	            2,4,3,
+	            //up04
+	            0,3,4,
+	            //箭头尾部...
+	            5,10,9,5,6,10,
+                6,11,10,6,7,11,
+                7,12,11,7,8,12,
+                5,9,12,5,12,8,
+                9,10,12,10,11,12
+            };
+            arrow.vertices = vertexs;
+            //自动计算法线
+            arrow.RecalculateNormals();
+            arrow.SetIndices(vertexIndices, MeshTopology.Triangles, 0);
+            return arrow;
+        }
+    }
+}

+ 11 - 0
Runtime/Components/AxisRender/Axis.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 346ff803281364fbeb63d5d61414b981
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 403 - 0
Runtime/Components/AxisRender/Axis.prefab

@@ -0,0 +1,403 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &6627355741593455057
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6627355741593455071}
+  - component: {fileID: 1814796021}
+  m_Layer: 0
+  m_Name: Axis
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &6627355741593455071
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355741593455057}
+  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:
+  - {fileID: 6627355742826359590}
+  - {fileID: 6627355742373579691}
+  - {fileID: 6627355741887904743}
+  - {fileID: 6627355742626991644}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1814796021
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355741593455057}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 346ff803281364fbeb63d5d61414b981, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  arrowBottomSize: 0.2
+  arrowHeight: 0.264
+  xLength: 1
+  yLength: 1
+  zLength: 1
+  lineTickness: 0.05
+  centerSize: 0.17
+--- !u!1 &6627355741887904740
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6627355741887904743}
+  - component: {fileID: 6627355741887904737}
+  - component: {fileID: 6627355741887904742}
+  m_Layer: 0
+  m_Name: X
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &6627355741887904743
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355741887904740}
+  m_LocalRotation: {x: -0, y: -0, z: -0.7071068, w: 0.7071068}
+  m_LocalPosition: {x: 1, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6627355741593455071}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: -90}
+--- !u!33 &6627355741887904737
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355741887904740}
+  m_Mesh: {fileID: 0}
+--- !u!23 &6627355741887904742
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355741887904740}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 8d02947cd503b44e1a1e3b504e7e81dd, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!1 &6627355742373579688
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6627355742373579691}
+  - component: {fileID: 6627355742373579701}
+  - component: {fileID: 6627355742373579690}
+  m_Layer: 0
+  m_Name: Z
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &6627355742373579691
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742373579688}
+  m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 1}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6627355741593455071}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 90, y: -90, z: -90}
+--- !u!33 &6627355742373579701
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742373579688}
+  m_Mesh: {fileID: 0}
+--- !u!23 &6627355742373579690
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742373579688}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 6e9b7508bf48648a099b795b0c878b8a, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!1 &6627355742626991645
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6627355742626991644}
+  - component: {fileID: 6627355742626991641}
+  - component: {fileID: 6627355742626991646}
+  - component: {fileID: 6627355742626991647}
+  m_Layer: 0
+  m_Name: Center
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &6627355742626991644
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742626991645}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 0.17, y: 0.17, z: 0.17}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6627355741593455071}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &6627355742626991641
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742626991645}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &6627355742626991646
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742626991645}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!65 &6627355742626991647
+BoxCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742626991645}
+  m_Material: {fileID: 0}
+  m_IsTrigger: 0
+  m_Enabled: 1
+  serializedVersion: 2
+  m_Size: {x: 1, y: 1, z: 1}
+  m_Center: {x: 0, y: 0, z: 0}
+--- !u!1 &6627355742826359591
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6627355742826359590}
+  - component: {fileID: 6627355742826359587}
+  - component: {fileID: 6627355742826359584}
+  m_Layer: 0
+  m_Name: Y
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &6627355742826359590
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742826359591}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 1, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6627355741593455071}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &6627355742826359587
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742826359591}
+  m_Mesh: {fileID: 0}
+--- !u!23 &6627355742826359584
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6627355742826359591}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 5e3593fba45c1412e8931afb2df6e9c9, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}

+ 7 - 0
Runtime/Components/AxisRender/Axis.prefab.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: a0d9481f43b1247a181d896b4c83bc57
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 870 - 0
Runtime/Components/AxisRender/Axis.unity

@@ -0,0 +1,870 @@
+%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: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 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_IndirectSpecularColor: {r: 0.44657815, g: 0.49641192, b: 0.57481617, a: 1}
+  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: 2
+    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
+    accuratePlacement: 0
+    maxJobWorkers: 0
+    preserveTilesOutsideBounds: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1001 &200799249
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 1814796021, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: xLength
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455057, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_Name
+      value: Axis
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_RootOrder
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741593455071, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355741887904737, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_Mesh
+      value: 
+      objectReference: {fileID: 2118394036}
+    - target: {fileID: 6627355741887904743, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6627355742373579701, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_Mesh
+      value: 
+      objectReference: {fileID: 674577489}
+    - target: {fileID: 6627355742826359587, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+      propertyPath: m_Mesh
+      value: 
+      objectReference: {fileID: 705353688}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: a0d9481f43b1247a181d896b4c83bc57, type: 3}
+--- !u!1 &510500232
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 510500234}
+  - component: {fileID: 510500233}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &510500233
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 510500232}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+  m_Intensity: 1
+  m_Range: 10
+  m_SpotAngle: 30
+  m_InnerSpotAngle: 21.80208
+  m_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+    m_CullingMatrixOverride:
+      e00: 1
+      e01: 0
+      e02: 0
+      e03: 0
+      e10: 0
+      e11: 1
+      e12: 0
+      e13: 0
+      e20: 0
+      e21: 0
+      e22: 1
+      e23: 0
+      e30: 0
+      e31: 0
+      e32: 0
+      e33: 1
+    m_UseCullingMatrixOverride: 0
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 4
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+  m_UseBoundingSphereOverride: 0
+  m_UseViewFrustumForShadowCasterCull: 1
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &510500234
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 510500232}
+  m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+  m_LocalPosition: {x: 0, y: 3, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!43 &674577489
+Mesh:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: 
+  serializedVersion: 10
+  m_SubMeshes:
+  - serializedVersion: 2
+    firstByte: 0
+    indexCount: 48
+    topology: 0
+    baseVertex: 0
+    firstVertex: 0
+    vertexCount: 13
+    localAABB:
+      m_Center: {x: 0, y: -0.368, z: 0}
+      m_Extent: {x: 0.1, y: 0.63199997, z: 0.1}
+  m_Shapes:
+    vertices: []
+    shapes: []
+    channels: []
+    fullWeights: []
+  m_BindPose: []
+  m_BoneNameHashes: 
+  m_RootBoneNameHash: 0
+  m_BonesAABB: []
+  m_VariableBoneCountWeights:
+    m_Data: 
+  m_MeshCompression: 0
+  m_IsReadable: 1
+  m_KeepVertices: 1
+  m_KeepIndices: 1
+  m_IndexFormat: 0
+  m_IndexBuffer: 00000100020000000200030000000400010001000400020002000400030000000300040005000a000900050006000a0006000b000a00060007000b0007000c000b00070008000c00050009000c0005000c00080009000a000c000a000b000c00
+  m_VertexData:
+    serializedVersion: 3
+    m_VertexCount: 13
+    m_Channels:
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 3
+    - stream: 0
+      offset: 12
+      format: 0
+      dimension: 3
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    m_DataSize: 312
+    _typelessdata: cdccccbd00000000cdccccbd000000000000000000000000cdcccc3d00000000cdccccbd000000000000000000000000cdcccc3d00000000cdcccc3d000000000000000000000000cdccccbd00000000cdcccc3d00000000000000000000000000000000022b873e00000000000000000000000000000000cdccccbc00000000cdccccbc000000000000000000000000cdcccc3c00000000cdccccbc000000000000000000000000cdcccc3c00000000cdcccc3c000000000000000000000000cdccccbc00000000cdcccc3c000000000000000000000000cdccccbc000080bfcdccccbc000000000000000000000000cdcccc3c000080bfcdccccbc000000000000000000000000cdcccc3c000080bfcdcccc3c000000000000000000000000cdccccbc000080bfcdcccc3c000000000000000000000000
+  m_CompressedMesh:
+    m_Vertices:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_UV:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Normals:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Tangents:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Weights:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_NormalSigns:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_TangentSigns:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_FloatColors:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_BoneIndices:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Triangles:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_UVInfo: 0
+  m_LocalAABB:
+    m_Center: {x: 0, y: -0.368, z: 0}
+    m_Extent: {x: 0.1, y: 0.63199997, z: 0.1}
+  m_MeshUsageFlags: 0
+  m_BakedConvexCollisionMesh: 
+  m_BakedTriangleCollisionMesh: 
+  m_MeshMetrics[0]: 1
+  m_MeshMetrics[1]: 1
+  m_MeshOptimizationFlags: 1
+  m_StreamData:
+    serializedVersion: 2
+    offset: 0
+    size: 0
+    path: 
+--- !u!43 &705353688
+Mesh:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: 
+  serializedVersion: 10
+  m_SubMeshes:
+  - serializedVersion: 2
+    firstByte: 0
+    indexCount: 48
+    topology: 0
+    baseVertex: 0
+    firstVertex: 0
+    vertexCount: 13
+    localAABB:
+      m_Center: {x: 0, y: -0.368, z: 0}
+      m_Extent: {x: 0.1, y: 0.63199997, z: 0.1}
+  m_Shapes:
+    vertices: []
+    shapes: []
+    channels: []
+    fullWeights: []
+  m_BindPose: []
+  m_BoneNameHashes: 
+  m_RootBoneNameHash: 0
+  m_BonesAABB: []
+  m_VariableBoneCountWeights:
+    m_Data: 
+  m_MeshCompression: 0
+  m_IsReadable: 1
+  m_KeepVertices: 1
+  m_KeepIndices: 1
+  m_IndexFormat: 0
+  m_IndexBuffer: 00000100020000000200030000000400010001000400020002000400030000000300040005000a000900050006000a0006000b000a00060007000b0007000c000b00070008000c00050009000c0005000c00080009000a000c000a000b000c00
+  m_VertexData:
+    serializedVersion: 3
+    m_VertexCount: 13
+    m_Channels:
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 3
+    - stream: 0
+      offset: 12
+      format: 0
+      dimension: 3
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    m_DataSize: 312
+    _typelessdata: cdccccbd00000000cdccccbd000000000000000000000000cdcccc3d00000000cdccccbd000000000000000000000000cdcccc3d00000000cdcccc3d000000000000000000000000cdccccbd00000000cdcccc3d00000000000000000000000000000000022b873e00000000000000000000000000000000cdccccbc00000000cdccccbc000000000000000000000000cdcccc3c00000000cdccccbc000000000000000000000000cdcccc3c00000000cdcccc3c000000000000000000000000cdccccbc00000000cdcccc3c000000000000000000000000cdccccbc000080bfcdccccbc000000000000000000000000cdcccc3c000080bfcdccccbc000000000000000000000000cdcccc3c000080bfcdcccc3c000000000000000000000000cdccccbc000080bfcdcccc3c000000000000000000000000
+  m_CompressedMesh:
+    m_Vertices:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_UV:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Normals:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Tangents:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Weights:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_NormalSigns:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_TangentSigns:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_FloatColors:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_BoneIndices:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Triangles:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_UVInfo: 0
+  m_LocalAABB:
+    m_Center: {x: 0, y: -0.368, z: 0}
+    m_Extent: {x: 0.1, y: 0.63199997, z: 0.1}
+  m_MeshUsageFlags: 0
+  m_BakedConvexCollisionMesh: 
+  m_BakedTriangleCollisionMesh: 
+  m_MeshMetrics[0]: 1
+  m_MeshMetrics[1]: 1
+  m_MeshOptimizationFlags: 1
+  m_StreamData:
+    serializedVersion: 2
+    offset: 0
+    size: 0
+    path: 
+--- !u!1 &1925705329
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1925705332}
+  - component: {fileID: 1925705331}
+  - component: {fileID: 1925705330}
+  m_Layer: 0
+  m_Name: Main Camera
+  m_TagString: MainCamera
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!81 &1925705330
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1925705329}
+  m_Enabled: 1
+--- !u!20 &1925705331
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1925705329}
+  m_Enabled: 1
+  serializedVersion: 2
+  m_ClearFlags: 1
+  m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+  m_projectionMatrixMode: 1
+  m_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  m_FocalLength: 50
+  m_NormalizedViewPortRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  near clip plane: 0.3
+  far clip plane: 1000
+  field of view: 60
+  orthographic: 0
+  orthographic size: 5
+  m_Depth: -1
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingPath: -1
+  m_TargetTexture: {fileID: 0}
+  m_TargetDisplay: 0
+  m_TargetEye: 3
+  m_HDR: 1
+  m_AllowMSAA: 1
+  m_AllowDynamicResolution: 0
+  m_ForceIntoRT: 0
+  m_OcclusionCulling: 1
+  m_StereoConvergence: 10
+  m_StereoSeparation: 0.022
+--- !u!4 &1925705332
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1925705329}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 1, z: -10}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!43 &2118394036
+Mesh:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: 
+  serializedVersion: 10
+  m_SubMeshes:
+  - serializedVersion: 2
+    firstByte: 0
+    indexCount: 48
+    topology: 0
+    baseVertex: 0
+    firstVertex: 0
+    vertexCount: 13
+    localAABB:
+      m_Center: {x: 0, y: -0.368, z: 0}
+      m_Extent: {x: 0.1, y: 0.63199997, z: 0.1}
+  m_Shapes:
+    vertices: []
+    shapes: []
+    channels: []
+    fullWeights: []
+  m_BindPose: []
+  m_BoneNameHashes: 
+  m_RootBoneNameHash: 0
+  m_BonesAABB: []
+  m_VariableBoneCountWeights:
+    m_Data: 
+  m_MeshCompression: 0
+  m_IsReadable: 1
+  m_KeepVertices: 1
+  m_KeepIndices: 1
+  m_IndexFormat: 0
+  m_IndexBuffer: 00000100020000000200030000000400010001000400020002000400030000000300040005000a000900050006000a0006000b000a00060007000b0007000c000b00070008000c00050009000c0005000c00080009000a000c000a000b000c00
+  m_VertexData:
+    serializedVersion: 3
+    m_VertexCount: 13
+    m_Channels:
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 3
+    - stream: 0
+      offset: 12
+      format: 0
+      dimension: 3
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    - stream: 0
+      offset: 0
+      format: 0
+      dimension: 0
+    m_DataSize: 312
+    _typelessdata: cdccccbd00000000cdccccbd000000000000000000000000cdcccc3d00000000cdccccbd000000000000000000000000cdcccc3d00000000cdcccc3d000000000000000000000000cdccccbd00000000cdcccc3d00000000000000000000000000000000022b873e00000000000000000000000000000000cdccccbc00000000cdccccbc000000000000000000000000cdcccc3c00000000cdccccbc000000000000000000000000cdcccc3c00000000cdcccc3c000000000000000000000000cdccccbc00000000cdcccc3c000000000000000000000000cdccccbc000080bfcdccccbc000000000000000000000000cdcccc3c000080bfcdccccbc000000000000000000000000cdcccc3c000080bfcdcccc3c000000000000000000000000cdccccbc000080bfcdcccc3c000000000000000000000000
+  m_CompressedMesh:
+    m_Vertices:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_UV:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Normals:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Tangents:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Weights:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_NormalSigns:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_TangentSigns:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_FloatColors:
+      m_NumItems: 0
+      m_Range: 0
+      m_Start: 0
+      m_Data: 
+      m_BitSize: 0
+    m_BoneIndices:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_Triangles:
+      m_NumItems: 0
+      m_Data: 
+      m_BitSize: 0
+    m_UVInfo: 0
+  m_LocalAABB:
+    m_Center: {x: 0, y: -0.368, z: 0}
+    m_Extent: {x: 0.1, y: 0.63199997, z: 0.1}
+  m_MeshUsageFlags: 0
+  m_BakedConvexCollisionMesh: 
+  m_BakedTriangleCollisionMesh: 
+  m_MeshMetrics[0]: 1
+  m_MeshMetrics[1]: 1
+  m_MeshOptimizationFlags: 1
+  m_StreamData:
+    serializedVersion: 2
+    offset: 0
+    size: 0
+    path: 

+ 7 - 0
Runtime/Components/AxisRender/Axis.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: f53703071e3f4491d877a00c3135a6ae
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Components/DragUI.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: bb6585224e9b941a78af51d7856e1f63
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 116 - 0
Runtime/Components/DragUI/BezierDragUI.cs

@@ -0,0 +1,116 @@
+using System.Runtime.InteropServices.WindowsRuntime;
+using Rokid.UXR.Interaction;
+using UnityEngine;
+using UnityEngine.EventSystems;
+
+namespace Rokid.UXR.Components
+{
+    public class BezierDragUI : MonoBehaviour, IDragHandler, IEndDragHandler, IBeginDragHandler, IBezierCurveDrag
+    {
+        [SerializeField]
+        public RectTransform canvas;//得到canvas的ugui坐标
+        private RectTransform imgRect;
+        private Vector2 offset;//临时记录点击点与UI的相对位置
+
+        private bool IsDraging;
+
+        void Start()
+        {
+            //初始化组件
+            imgRect = GetComponent<RectTransform>();
+        }
+
+        public void OnDrag(PointerEventData eventData)
+        {
+            // UnityEngine.RKLog.Info("On Drag");
+            Vector2 mouseDrag = eventData.position; //当鼠标拖动时的屏幕坐标
+            Vector2 uguiPos; //用来接收转换后的拖动坐标
+            bool isRect = RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas, mouseDrag, eventData.enterEventCamera, out uguiPos);
+            if (isRect && Mathf.Abs(uguiPos.x) < Screen.width && Mathf.Abs(uguiPos.y) < Screen.height)
+            {
+                //设置图片的ugui坐标与鼠标的ugui坐标保持不变
+                if (!UseBezierCurve)
+                {
+                    imgRect.anchoredPosition = offset + uguiPos;
+                }
+                else
+                {
+                    anchoredPos = offset + uguiPos;
+                }
+            }
+        }
+
+        public void OnBeginDrag(PointerEventData eventData)
+        {
+            IsDraging = true;
+
+            // 保存点击点的坐标
+            HitPoint = transform.InverseTransformPoint(eventData.pointerCurrentRaycast.worldPosition);
+
+            //开始拖拽
+            //这里必须先更换父物体否则,offset会计算出问题
+            Vector2 mouseDown = eventData.position;
+            Vector2 mouseUguiPos;
+            bool isRect = RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas, mouseDown, eventData.enterEventCamera, out mouseUguiPos);
+            if (isRect && Mathf.Abs(mouseUguiPos.x) < Screen.width && Mathf.Abs(mouseUguiPos.y) < Screen.height)
+            {
+                offset = imgRect.anchoredPosition - mouseUguiPos;
+            }
+            else
+            {
+                offset = imgRect.anchoredPosition;
+            }
+        }
+
+        public void OnEndDrag(PointerEventData eventData)
+        {
+            RKLog.Info("On End Drag");
+            IsDraging = false;
+        }
+
+        #region BezierCurve
+        [SerializeField]
+        private bool UseBezierCurve = true;
+        [SerializeField]
+        private float moveLerpTime = 0.05f;
+
+        private Vector3 HitPoint;
+
+        private Vector2 anchoredPos;
+
+        public bool IsEnablePinchBezierCurve()
+        {
+            return UseBezierCurve;
+        }
+
+        public bool IsEnableGripBezierCurve()
+        {
+            return false;
+        }
+
+        public bool IsInBezierCurveDragging()
+        {
+            return IsDraging;
+        }
+
+        public Vector3 GetBezierCurveEndPoint()
+        {
+            return transform.TransformPoint(HitPoint);
+        }
+
+        private void Update()
+        {
+            if (UseBezierCurve && IsDraging)
+            {
+                imgRect.anchoredPosition = Vector2.Lerp(imgRect.anchoredPosition, anchoredPos, 1f - Mathf.Pow(moveLerpTime, Time.deltaTime));
+            }
+        }
+
+        public Vector3 GetBezierCurveEndNormal()
+        {
+            return transform.forward;
+        }
+
+        #endregion
+    }
+}

+ 3 - 0
Runtime/Components/DragUI/BezierDragUI.cs.meta

@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 244fd80fbbdb48429dded8275e0e2d3e
+timeCreated: 1689313746

+ 93 - 0
Runtime/Components/DragUI/DragUI.cs

@@ -0,0 +1,93 @@
+using UnityEngine;
+using UnityEngine.EventSystems;
+
+namespace Rokid.UXR.Components {
+
+    public class DragUI : MonoBehaviour, IDragHandler, IEndDragHandler, IBeginDragHandler
+    {
+
+        [SerializeField]
+        public RectTransform canvas;//得到canvas的ugui坐标
+        [SerializeField]
+        public Transform frontParent;
+        private RectTransform imgRect;
+        private CanvasGroup canvasGroup;
+        private Transform oldParent;
+        private Transform nowParent;
+        public int sibiling;
+        private Vector2 offset;//临时记录点击点与UI的相对位置
+
+        void Start()
+        {
+            //初始化组件
+            imgRect = GetComponent<RectTransform>();
+            canvasGroup = GetComponent<CanvasGroup>();
+            sibiling = transform.GetSiblingIndex();
+            oldParent = transform.parent;
+        }
+
+        public void OnDrag(PointerEventData eventData)
+        {
+            // UnityEngine.RKLog.Info("On Drag");
+            Vector2 mouseDrag = eventData.position; //当鼠标拖动时的屏幕坐标
+            Vector2 uguiPos; //用来接收转换后的拖动坐标
+            bool isRect = RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas, mouseDrag, eventData.enterEventCamera, out uguiPos);
+            if (isRect)
+            {
+                //设置图片的ugui坐标与鼠标的ugui坐标保持不变
+                imgRect.anchoredPosition = offset + uguiPos;
+            }
+        }
+
+        public void OnBeginDrag(PointerEventData eventData)
+        {
+            //开始拖拽
+            canvasGroup.blocksRaycasts = false;
+            //这里必须先更换父物体否则,offset会计算出问题
+            nowParent = transform.parent;
+            transform.SetParent(frontParent);
+            Vector2 mouseDown = eventData.position;
+            Vector2 mouseUguiPos;
+            bool isRect = RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas, mouseDown, eventData.enterEventCamera, out mouseUguiPos);
+            if (isRect)
+            {
+                offset = imgRect.anchoredPosition - mouseUguiPos;
+            }
+        }
+
+        public void OnEndDrag(PointerEventData eventData)
+        {
+            RKLog.Info("On End Drag");
+            if (eventData.pointerCurrentRaycast.gameObject != null)
+            {
+                if (eventData.pointerCurrentRaycast.gameObject.name == "Grid")
+                {
+                    Transform targetParent = eventData.pointerCurrentRaycast.gameObject.transform;
+                    if (targetParent.childCount > 0)
+                    {
+                        RKLog.Info("Change Position");
+                        //交换位置
+                        Transform target = targetParent.GetChild(0);
+                        target.SetParent(oldParent);
+                        target.localPosition = Vector3.zero;
+                    }
+                    transform.SetParent(targetParent);
+                    transform.localPosition = Vector3.zero;
+                }
+                else
+                {
+                    //返回
+                    transform.SetParent(oldParent);
+                    transform.localPosition = Vector3.zero;
+                }
+            }
+            else
+            {
+                //返回
+                transform.SetParent(oldParent);
+                transform.localPosition = Vector3.zero;
+            }
+            canvasGroup.blocksRaycasts = true;
+        }
+	}
+}

+ 11 - 0
Runtime/Components/DragUI/DragUI.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: afb82eabe48714d00962bfe0d713b0cc
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Components/Ruler.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ba10ac96f020543bfb330d81799fa386
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 99 - 0
Runtime/Components/Ruler/Ruler.cs

@@ -0,0 +1,99 @@
+using System.Threading.Tasks;
+using System.Net.Http.Headers;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.Linq;
+using UnityEngine.UI;
+
+namespace Rokid.UXR.Components {
+	[ExecuteInEditMode]
+	public class Ruler : MonoBehaviour
+	{
+	    /// <summary>
+	    /// 缓存直尺的刻度
+	    /// </summary>
+	    /// <typeparam name="int"></typeparam>
+	    /// <typeparam name="GameObject"></typeparam>
+	    /// <returns></returns>
+	    public Dictionary<int, GameObject> dialDict = new Dictionary<int, GameObject>();
+	
+	    /// <summary>
+	    /// 直尺长度
+	    /// </summary>
+	    [Range(1, 15)]
+	    public int length = 1;
+	
+	    /// <summary>
+	    /// 直尺刻度显示
+	    /// </summary>
+	    public GameObject tempDial;
+	
+	    public Transform ruler;
+	
+	    private float oldLength;
+	
+	    private void Update()
+	    {
+	        if (oldLength != length)
+	        {
+	            oldLength = length;
+	            //更新直尺长度
+	            ShowDial(length);
+	
+	            ruler.transform.localScale = new Vector3(0.4f, length, 1);
+	        }
+	    }
+	
+	    /// <summary>
+	    /// 显示直尺的刻度
+	    /// </summary>
+	    private void ShowDial(int length)
+	    {
+	        foreach (var item in dialDict.Values)
+	        {
+	            if (item == null || item.gameObject == null)
+	                continue;
+	            item.gameObject.SetActive(false);
+	        }
+	        for (int i = 1; i < length; i++)
+	        {
+	            if (dialDict.ContainsKey(i) && dialDict[i].gameObject != null)
+	            {
+	                dialDict[i].gameObject.SetActive(true);
+	            }
+	            else
+	            {
+	                //先查找是否已经实例化tip如果
+	                Transform tsf = transform.Find(i + "m");
+	                if (tsf != null)
+	                {
+	                    if (dialDict.ContainsKey(i))
+	                    {
+	                        dialDict[i] = tsf.gameObject;
+	                    }
+	                    else
+	                    {
+	                        dialDict.Add(i, tsf.gameObject);
+	                    }
+	                    return;
+	                }
+	                GameObject go = GameObject.Instantiate(tempDial, new Vector3(0, 0.001f, i), Quaternion.Euler(90, 0, 0));
+	                go.SetActive(true);
+	                go.transform.SetParent(this.transform);
+	                go.transform.localPosition = new Vector3(0, 0.001f, i);
+	                if (dialDict.ContainsKey(i))
+	                {
+	                    dialDict[i] = go;
+	                }
+	                else
+	                {
+	                    dialDict.Add(i, go);
+	                }
+	                go.GetComponentInChildren<Text>().text = i + "m";
+	                go.name = i + "m";
+	            }
+	        }
+	    }
+	}
+}

+ 11 - 0
Runtime/Components/Ruler/Ruler.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 07c55bcdeafb248e1b38df40bee155ed
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 80 - 0
Runtime/Components/Ruler/Ruler.mat

@@ -0,0 +1,80 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 8
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: Ruler
+  m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
+  m_ValidKeywords: []
+  m_InvalidKeywords: []
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Ints: []
+    m_Floats:
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 0.83137256, g: 0.41436365, b: 0.3411765, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+  m_BuildTextureStacks: []

+ 8 - 0
Runtime/Components/Ruler/Ruler.mat.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: fd5e181fad6dc4fe2963590845b4aa11
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1090 - 0
Runtime/Components/Ruler/Ruler.prefab

@@ -0,0 +1,1090 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &481768132
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 481768133}
+  - component: {fileID: 481768136}
+  - component: {fileID: 481768135}
+  - component: {fileID: 481768134}
+  m_Layer: 5
+  m_Name: 3m
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &481768133
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 481768132}
+  m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 3}
+  m_LocalScale: {x: 0.0010000002, y: 0.00063999975, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 1064727407}
+  m_Father: {fileID: 852901351178864662}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0.001}
+  m_SizeDelta: {x: 210.5994, y: 132.1606}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!223 &481768136
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 481768132}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 2
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  m_ReceivesEvents: 1
+  m_OverrideSorting: 0
+  m_OverridePixelPerfect: 0
+  m_SortingBucketNormalizedSize: 0
+  m_AdditionalShaderChannelsFlag: 0
+  m_SortingLayerID: 0
+  m_SortingOrder: 0
+  m_TargetDisplay: 0
+--- !u!114 &481768135
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 481768132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_UiScaleMode: 0
+  m_ReferencePixelsPerUnit: 100
+  m_ScaleFactor: 1
+  m_ReferenceResolution: {x: 800, y: 600}
+  m_ScreenMatchMode: 0
+  m_MatchWidthOrHeight: 0
+  m_PhysicalUnit: 3
+  m_FallbackScreenDPI: 96
+  m_DefaultSpriteDPI: 96
+  m_DynamicPixelsPerUnit: 1
+  m_PresetInfoIsWorld: 1
+--- !u!114 &481768134
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 481768132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+--- !u!1 &834135152
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 834135153}
+  - component: {fileID: 834135155}
+  - component: {fileID: 834135154}
+  m_Layer: 5
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &834135153
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 834135152}
+  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: 893259215}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &834135155
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 834135152}
+  m_CullTransparentMesh: 1
+--- !u!114 &834135154
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 834135152}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 5
+    m_MaxSize: 99
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: 1m
+--- !u!1 &854310193
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 854310194}
+  - component: {fileID: 854310197}
+  - component: {fileID: 854310196}
+  - component: {fileID: 854310195}
+  m_Layer: 5
+  m_Name: 2m
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &854310194
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 854310193}
+  m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 2}
+  m_LocalScale: {x: 0.0010000002, y: 0.00063999975, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 1097457120}
+  m_Father: {fileID: 852901351178864662}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0.001}
+  m_SizeDelta: {x: 210.5994, y: 132.1606}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!223 &854310197
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 854310193}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 2
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  m_ReceivesEvents: 1
+  m_OverrideSorting: 0
+  m_OverridePixelPerfect: 0
+  m_SortingBucketNormalizedSize: 0
+  m_AdditionalShaderChannelsFlag: 0
+  m_SortingLayerID: 0
+  m_SortingOrder: 0
+  m_TargetDisplay: 0
+--- !u!114 &854310196
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 854310193}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_UiScaleMode: 0
+  m_ReferencePixelsPerUnit: 100
+  m_ScaleFactor: 1
+  m_ReferenceResolution: {x: 800, y: 600}
+  m_ScreenMatchMode: 0
+  m_MatchWidthOrHeight: 0
+  m_PhysicalUnit: 3
+  m_FallbackScreenDPI: 96
+  m_DefaultSpriteDPI: 96
+  m_DynamicPixelsPerUnit: 1
+  m_PresetInfoIsWorld: 1
+--- !u!114 &854310195
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 854310193}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+--- !u!1 &893259214
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 893259215}
+  - component: {fileID: 893259218}
+  - component: {fileID: 893259217}
+  - component: {fileID: 893259216}
+  m_Layer: 5
+  m_Name: 1m
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &893259215
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 893259214}
+  m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 1}
+  m_LocalScale: {x: 0.0010000002, y: 0.00063999975, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 834135153}
+  m_Father: {fileID: 852901351178864662}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0.001}
+  m_SizeDelta: {x: 210.5994, y: 132.1606}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!223 &893259218
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 893259214}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 2
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  m_ReceivesEvents: 1
+  m_OverrideSorting: 0
+  m_OverridePixelPerfect: 0
+  m_SortingBucketNormalizedSize: 0
+  m_AdditionalShaderChannelsFlag: 0
+  m_SortingLayerID: 0
+  m_SortingOrder: 0
+  m_TargetDisplay: 0
+--- !u!114 &893259217
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 893259214}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_UiScaleMode: 0
+  m_ReferencePixelsPerUnit: 100
+  m_ScaleFactor: 1
+  m_ReferenceResolution: {x: 800, y: 600}
+  m_ScreenMatchMode: 0
+  m_MatchWidthOrHeight: 0
+  m_PhysicalUnit: 3
+  m_FallbackScreenDPI: 96
+  m_DefaultSpriteDPI: 96
+  m_DynamicPixelsPerUnit: 1
+  m_PresetInfoIsWorld: 1
+--- !u!114 &893259216
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 893259214}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+--- !u!1 &1064727406
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1064727407}
+  - component: {fileID: 1064727409}
+  - component: {fileID: 1064727408}
+  m_Layer: 5
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &1064727407
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1064727406}
+  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: 481768133}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &1064727409
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1064727406}
+  m_CullTransparentMesh: 1
+--- !u!114 &1064727408
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1064727406}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 5
+    m_MaxSize: 99
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: 3m
+--- !u!1 &1097457119
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1097457120}
+  - component: {fileID: 1097457122}
+  - component: {fileID: 1097457121}
+  m_Layer: 5
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &1097457120
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1097457119}
+  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: 854310194}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &1097457122
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1097457119}
+  m_CullTransparentMesh: 1
+--- !u!114 &1097457121
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1097457119}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 5
+    m_MaxSize: 99
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: 2m
+--- !u!1 &1771256536
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1771256537}
+  - component: {fileID: 1771256539}
+  - component: {fileID: 1771256538}
+  m_Layer: 5
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &1771256537
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1771256536}
+  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: 1774184631}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &1771256539
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1771256536}
+  m_CullTransparentMesh: 1
+--- !u!114 &1771256538
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1771256536}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 5
+    m_MaxSize: 99
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: 4m
+--- !u!1 &1774184630
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1774184631}
+  - component: {fileID: 1774184634}
+  - component: {fileID: 1774184633}
+  - component: {fileID: 1774184632}
+  m_Layer: 5
+  m_Name: 4m
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &1774184631
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1774184630}
+  m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 4}
+  m_LocalScale: {x: 0.0010000002, y: 0.00063999975, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 1771256537}
+  m_Father: {fileID: 852901351178864662}
+  m_RootOrder: 5
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0.001}
+  m_SizeDelta: {x: 210.5994, y: 132.1606}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!223 &1774184634
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1774184630}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 2
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  m_ReceivesEvents: 1
+  m_OverrideSorting: 0
+  m_OverridePixelPerfect: 0
+  m_SortingBucketNormalizedSize: 0
+  m_AdditionalShaderChannelsFlag: 0
+  m_SortingLayerID: 0
+  m_SortingOrder: 0
+  m_TargetDisplay: 0
+--- !u!114 &1774184633
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1774184630}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_UiScaleMode: 0
+  m_ReferencePixelsPerUnit: 100
+  m_ScaleFactor: 1
+  m_ReferenceResolution: {x: 800, y: 600}
+  m_ScreenMatchMode: 0
+  m_MatchWidthOrHeight: 0
+  m_PhysicalUnit: 3
+  m_FallbackScreenDPI: 96
+  m_DefaultSpriteDPI: 96
+  m_DynamicPixelsPerUnit: 1
+  m_PresetInfoIsWorld: 1
+--- !u!114 &1774184632
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1774184630}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+--- !u!1 &852901351178864663
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 852901351178864662}
+  - component: {fileID: 5021363340827820944}
+  m_Layer: 0
+  m_Name: Ruler
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &852901351178864662
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901351178864663}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: -1.8, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 852901352323921821}
+  - {fileID: 852901352695060161}
+  - {fileID: 893259215}
+  - {fileID: 854310194}
+  - {fileID: 481768133}
+  - {fileID: 1774184631}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &5021363340827820944
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901351178864663}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 07c55bcdeafb248e1b38df40bee155ed, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  length: 5
+  tempDial: {fileID: 852901352695060162}
+  ruler: {fileID: 852901352323921821}
+--- !u!1 &852901351681725174
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 852901351681725173}
+  - component: {fileID: 852901351681725130}
+  - component: {fileID: 852901351681725131}
+  - component: {fileID: 852901351681725172}
+  m_Layer: 0
+  m_Name: Quad
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &852901351681725173
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901351681725174}
+  m_LocalRotation: {x: 0, y: 0.0010472151, z: 0, w: 0.9999995}
+  m_LocalPosition: {x: 0, y: 0.5, z: 0}
+  m_LocalScale: {x: 0.1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 852901352323921821}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0.12, z: 0}
+--- !u!33 &852901351681725130
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901351681725174}
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &852901351681725131
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901351681725174}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: fd5e181fad6dc4fe2963590845b4aa11, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!64 &852901351681725172
+MeshCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901351681725174}
+  m_Material: {fileID: 0}
+  m_IsTrigger: 0
+  m_Enabled: 1
+  serializedVersion: 4
+  m_Convex: 0
+  m_CookingOptions: 30
+  m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!1 &852901352323921822
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 852901352323921821}
+  m_Layer: 0
+  m_Name: Ruler
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &852901352323921821
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901352323921822}
+  m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 0.4, y: 5, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 852901351681725173}
+  m_Father: {fileID: 852901351178864662}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0}
+--- !u!1 &852901352519926799
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 852901352519926798}
+  - component: {fileID: 852901352519926796}
+  - component: {fileID: 852901352519926797}
+  m_Layer: 5
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &852901352519926798
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901352519926799}
+  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: 852901352695060161}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &852901352519926796
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901352519926799}
+  m_CullTransparentMesh: 1
+--- !u!114 &852901352519926797
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901352519926799}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 5
+    m_MaxSize: 99
+    m_Alignment: 4
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 0
+    m_LineSpacing: 1
+  m_Text: 1m
+--- !u!1 &852901352695060162
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 852901352695060161}
+  - component: {fileID: 852901352695060166}
+  - component: {fileID: 852901352695060167}
+  - component: {fileID: 852901352695060160}
+  m_Layer: 5
+  m_Name: Dial
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!224 &852901352695060161
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901352695060162}
+  m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 0.0010000002, y: 0.0006399998, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 852901352519926798}
+  m_Father: {fileID: 852901351178864662}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 210.5994, y: 132.1606}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!223 &852901352695060166
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901352695060162}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 2
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  m_ReceivesEvents: 1
+  m_OverrideSorting: 0
+  m_OverridePixelPerfect: 0
+  m_SortingBucketNormalizedSize: 0
+  m_AdditionalShaderChannelsFlag: 0
+  m_SortingLayerID: 0
+  m_SortingOrder: 0
+  m_TargetDisplay: 0
+--- !u!114 &852901352695060167
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901352695060162}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_UiScaleMode: 0
+  m_ReferencePixelsPerUnit: 100
+  m_ScaleFactor: 1
+  m_ReferenceResolution: {x: 800, y: 600}
+  m_ScreenMatchMode: 0
+  m_MatchWidthOrHeight: 0
+  m_PhysicalUnit: 3
+  m_FallbackScreenDPI: 96
+  m_DefaultSpriteDPI: 96
+  m_DynamicPixelsPerUnit: 1
+  m_PresetInfoIsWorld: 1
+--- !u!114 &852901352695060160
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 852901352695060162}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295

+ 7 - 0
Runtime/Components/Ruler/Ruler.prefab.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8dd8c6e456da046afa611f2e11d5f727
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Resources.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4fc4a61cfee0b4658878d91fe15f4da0
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Resources/Audio.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e8237752030904a22a7c33b565c99961
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Runtime/Resources/Audio/ButtonDown.wav


+ 22 - 0
Runtime/Resources/Audio/ButtonDown.wav.meta

@@ -0,0 +1,22 @@
+fileFormatVersion: 2
+guid: 35080f41331ed594e8f5819a68b57e3b
+AudioImporter:
+  externalObjects: {}
+  serializedVersion: 6
+  defaultSettings:
+    loadType: 2
+    sampleRateSetting: 0
+    sampleRateOverride: 44100
+    compressionFormat: 1
+    quality: 1
+    conversionMode: 0
+  platformSettingOverrides: {}
+  forceToMono: 0
+  normalize: 1
+  preloadAudioData: 1
+  loadInBackground: 0
+  ambisonic: 0
+  3D: 1
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Runtime/Resources/Audio/ButtonUp.wav


+ 22 - 0
Runtime/Resources/Audio/ButtonUp.wav.meta

@@ -0,0 +1,22 @@
+fileFormatVersion: 2
+guid: e4a41b3ade7fe514eb4b85d8ee4f55e2
+AudioImporter:
+  externalObjects: {}
+  serializedVersion: 6
+  defaultSettings:
+    loadType: 2
+    sampleRateSetting: 0
+    sampleRateOverride: 44100
+    compressionFormat: 1
+    quality: 1
+    conversionMode: 0
+  platformSettingOverrides: {}
+  forceToMono: 0
+  normalize: 1
+  preloadAudioData: 1
+  loadInBackground: 0
+  ambisonic: 0
+  3D: 1
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Runtime/Resources/Audio/ModuleChangeAudio.wav


+ 22 - 0
Runtime/Resources/Audio/ModuleChangeAudio.wav.meta

@@ -0,0 +1,22 @@
+fileFormatVersion: 2
+guid: fcae4596902ff094f8f4b9961f084645
+AudioImporter:
+  externalObjects: {}
+  serializedVersion: 6
+  defaultSettings:
+    loadType: 0
+    sampleRateSetting: 0
+    sampleRateOverride: 44100
+    compressionFormat: 1
+    quality: 1
+    conversionMode: 0
+  platformSettingOverrides: {}
+  forceToMono: 0
+  normalize: 1
+  preloadAudioData: 1
+  loadInBackground: 0
+  ambisonic: 0
+  3D: 1
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Resources/Configs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1f06423afd76744a49bde7b91eb760cb
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 20 - 0
Runtime/Resources/Configs/DeviceFuncMatchInfo.json

@@ -0,0 +1,20 @@
+[
+  {
+    "Id": 1,
+    "FuncName": "CameraFunc",
+    "GlassDeviceModels": "Rokid Air Pro|Rokid Air Pro+|Rokid Max Pro|Rokid Max Plus",
+    "UseCamera": 1
+  },
+  {
+    "Id": 2,
+    "FuncName": "HandTracking",
+    "GlassDeviceModels": "Rokid Max Pro",
+    "UseCamera": 1
+  },
+  {
+    "Id": 4,
+    "FuncName": "Slam",
+    "GlassDeviceModels": "Rokid Max Pro|Rokid Air Pro+",
+    "UseCamera": 1
+  }
+]

+ 7 - 0
Runtime/Resources/Configs/DeviceFuncMatchInfo.json.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 073df8a8910d8498c950325aebe7baef
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Runtime/Resources/Configs/DeviceFuncMatchInfo.xlsx


+ 7 - 0
Runtime/Resources/Configs/DeviceFuncMatchInfo.xlsx.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 39ef3e34e705f4c9b9d689b9aa6a0ebf
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 50 - 0
Runtime/Resources/Configs/DeviceInfo.json

@@ -0,0 +1,50 @@
+[
+  {
+    "DeviceId": 1,
+    "DeviceName": "Rokid Air",
+    "PID": 5679,
+    "CameraFov": 20.3,
+    "HaveCamera": 0,
+    "HaveGesture": 0
+  },
+  {
+    "DeviceId": 2,
+    "DeviceName": "Rokid Air Pro",
+    "PID": 5679,
+    "CameraFov": 20.3,
+    "HaveCamera": 1,
+    "HaveGesture": 0
+  },
+  {
+    "DeviceId": 3,
+    "DeviceName": "Rokid Air Pro+",
+    "PID": 5677,
+    "CameraFov": 20.3,
+    "HaveCamera": 1,
+    "HaveGesture": 0
+  },
+  {
+    "DeviceId": 4,
+    "DeviceName": "Rokid Max",
+    "PID": 5677,
+    "CameraFov": 24.0,
+    "HaveCamera": 0,
+    "HaveGesture": 0
+  },
+  {
+    "DeviceId": 5,
+    "DeviceName": "Rokid Max Pro",
+    "PID": 5677,
+    "CameraFov": 24.0,
+    "HaveCamera": 1,
+    "HaveGesture": 1
+  },
+  {
+    "DeviceId": 6,
+    "DeviceName": "Rokid Max Plus",
+    "PID": 8576,
+    "CameraFov": 24.0,
+    "HaveCamera": 1,
+    "HaveGesture": 0
+  }
+]

+ 7 - 0
Runtime/Resources/Configs/DeviceInfo.json.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 7e4d1dc44f8654978ab3e3032808c56a
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Runtime/Resources/Configs/DeviceInfo.xlsx


+ 7 - 0
Runtime/Resources/Configs/DeviceInfo.xlsx.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: e2a14622e7f714e0aaa654d1f11a67fd
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Resources/Materials.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 32231861b84b041c3949030fd9cc2f78
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Resources/Materials/BuidIn.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d16077e0798124387a00fa9fd7cdced3
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 107 - 0
Runtime/Resources/Materials/BuidIn/HandMesh_Finger.mat

@@ -0,0 +1,107 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 8
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: HandMesh_Finger
+  m_Shader: {fileID: 4800000, guid: 925656a8b01451e40a21fd6da5125139, type: 3}
+  m_ValidKeywords: []
+  m_InvalidKeywords: []
+  m_LightmapFlags: 0
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: 4000
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _Mask:
+        m_Texture: {fileID: 2800000, guid: cd1e10daf45dd0647b1abc0b77bff6ee, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _TextureSample0:
+        m_Texture: {fileID: 2800000, guid: a357272578748644f9d0f9622fa4c597, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _texcoord:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Ints: []
+    m_Floats:
+    - _Bias: 0.01
+    - _BumpScale: 1
+    - _ChromaticAberration: 0.1
+    - _Color_Tweak: 1.23
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _FR_Bias: 0.41
+    - _FR_Power: 1
+    - _FR_Scale: 1
+    - _Float0: 0
+    - _Float1: 0.65
+    - _Float2: 1.09
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Mask_Tweak: 1.7
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _Power: 0
+    - _Scale: 0
+    - _Smoothness: 2.37
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    - __dirty: 0
+    m_Colors:
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _Color0: {r: 1, g: 1, b: 1, a: 0}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+  m_BuildTextureStacks: []

+ 8 - 0
Runtime/Resources/Materials/BuidIn/HandMesh_Finger.mat.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 242c387842881994e85b32b721427b3c
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 167 - 0
Runtime/Resources/Materials/BuidIn/HandMesh_Palm.mat

@@ -0,0 +1,167 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: HandMesh_Palm
+  m_Shader: {fileID: 4800000, guid: c5128d89437c1f641b47c90d6f29fbb2, type: 3}
+  m_ShaderKeywords: WIREFRAME_COLOR_TEXTURE_TRANSPARENCY_ON WIREFRAME_FRESNEL_ON
+    WIREFRAME_LIGHT_ATTENTION_ON
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: 4000
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _FalloffTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ShadowTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _Wireframe_AmbientOcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _Wireframe_ColorTexture:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _Wireframe_NormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _texcoord:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _texcoord4:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BumpScale: 1
+    - _Cull: 2
+    - _CurvedWorldTitle: 0
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _EdgeLength: 19.1
+    - _FR_Scale: 0.56
+    - _Float2: 1.07
+    - _Float6: 1.76
+    - _Float7: 3.92
+    - _Float8: -0.98
+    - _GlossMapScale: 1
+    - _Glossiness: 0
+    - _GlossyReflections: 1
+    - _MaxTriSize: 25
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _Power: 1.49
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _TessPhongStrength: 1
+    - _UVSec: 0
+    - _WireSmoothness: 3
+    - _WireThickness: 175
+    - _WireframeShader_Diameter: 1
+    - _WireframeShader_Smoothness: 0.1
+    - _WireframeShader_Thickness: 0
+    - _Wireframe_AmbientOcclusion: 0
+    - _Wireframe_AmbientOcclusionStrength: 1
+    - _Wireframe_BaseVertexColor: 0
+    - _Wireframe_BumpEnumID: 0
+    - _Wireframe_ColorEmissionStrength: 2.66
+    - _Wireframe_DistanceFade: 0
+    - _Wireframe_DistanceFadeEnd: 10
+    - _Wireframe_DistanceFadeStart: 5
+    - _Wireframe_DynamicMaskEdgeSmooth: 0
+    - _Wireframe_DynamicMaskEffectsBaseTexEnumID: 0
+    - _Wireframe_DynamicMaskEffectsBaseTexInvert: 0
+    - _Wireframe_DynamicMaskEnumID: 0
+    - _Wireframe_DynamicMaskInvert: 0
+    - _Wireframe_DynamicMaskType: 1
+    - _Wireframe_FresnelBias: 0.017
+    - _Wireframe_FresnelEnumID: 0
+    - _Wireframe_FresnelInvert: 1
+    - _Wireframe_FresnelPow: 1
+    - _Wireframe_ImprovedBlendEnumID: 0
+    - _Wireframe_IncludeLightEnumID: 1
+    - _Wireframe_MetaPassMultiplier: 2.57
+    - _Wireframe_NormalScale: 1
+    - _Wireframe_NormalizeEdges: 0
+    - _Wireframe_RenderingOptions_PBREnumID: 0
+    - _Wireframe_Title_GI_Options: 0
+    - _Wireframe_Title_M_Options: 0
+    - _Wireframe_Title_Rendering_Options: 0
+    - _Wireframe_Title_S_Options: 0
+    - _Wireframe_Title_UAR_Options: 0
+    - _Wireframe_Title_V_Options: 0
+    - _Wireframe_Title_W_Options: 0
+    - _Wireframe_TransparencyEnumID: 0
+    - _Wireframe_Transparency_M_Options: 0
+    - _Wireframe_TransparentTex_Alpha_Offset: 0.166
+    - _Wireframe_TransparentTex_Invert: 0
+    - _Wireframe_TryQuad: 0
+    - _Wireframe_WireVertexColor: 0
+    - _ZWrite: 1
+    - __dirty: 0
+    m_Colors:
+    - _BaseColor: {r: 0, g: 0, b: 0, a: 0}
+    - _Color: {r: 0, g: 0, b: 0, a: 1}
+    - _Color5: {r: 1, g: 0, b: 0, a: 0}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+    - _WireColor: {r: 0, g: 1, b: 0, a: 1}
+    - _Wireframe_Color: {r: 1, g: 1, b: 1, a: 1}
+    - _Wireframe_ColorTexture_Scroll: {r: 0, g: 0, b: 0, a: 0}
+    - _Wireframe_MainTex_Scroll: {r: 0, g: 0, b: 0, a: 0}
+  m_BuildTextureStacks: []

+ 8 - 0
Runtime/Resources/Materials/BuidIn/HandMesh_Palm.mat.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0757c93f797b4f7408b94f4e9f15f6eb
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 151 - 0
Runtime/Resources/Materials/BuidIn/RokidHand.mat

@@ -0,0 +1,151 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 8
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: RokidHand
+  m_Shader: {fileID: 4800000, guid: b895d3431e75dc345a72e171f82bfbea, type: 3}
+  m_ValidKeywords: []
+  m_InvalidKeywords:
+  - _COLORGRADIENT_ON
+  - _FRESNEL_ON
+  - _KEYWORD0_ON
+  m_LightmapFlags: 0
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _FingerGlowMask:
+        m_Texture: {fileID: 2800000, guid: 67be4f15fa1af0c4486fedbfeb87774c, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _GlowMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTexture:
+        m_Texture: {fileID: 2800000, guid: 36532bb67ccd4bf49aa15a717ea43f3d, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _TextureSample0:
+        m_Texture: {fileID: 2800000, guid: 84508b93f15f2b64386ec07486afc7a3, type: 3}
+        m_Scale: {x: 1.71, y: 0.93}
+        m_Offset: {x: 0, y: 0}
+    - _texcoord:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Ints: []
+    m_Floats:
+    - _Alpha: 1
+    - _BumpScale: 1
+    - _ColorGradient: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _EnableConfidence: 0
+    - _Fresnel: 1
+    - _FresnelOpacity: 0
+    - _FresnelOpacityPower: 3.66
+    - _FresnelPower: 4.43
+    - _GlobalOpacity: 0.714
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _IndexGlowValue: 0
+    - _Metallic: 0
+    - _MiddleGlowValue: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Opacity: 0.484
+    - _OutlineFresnelOpacity: 0
+    - _OutlineFresnelPower: 2.462451
+    - _OutlineGlowIntensity: 1
+    - _OutlineGradient: 0
+    - _OutlineIntensity: 1
+    - _OutlineOpacity: 0.736
+    - _OutlinePinchRange: 0.15
+    - _OutlineSphereHardness: 0.15
+    - _OutlineWidth: 0.00052
+    - _Parallax: 0.02
+    - _PinchIntensity: 0
+    - _PinchRange: 0.12
+    - _PinkyGlowValue: 0
+    - _RingGlowValue: 0
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _TextureOpacity: 1
+    - _ThumbGlowValue: 0
+    - _UVSec: 0
+    - _UseTexture: 0
+    - _WristFade: 0.238
+    - _WristLocalOffset: 0.06
+    - _WristRange: 0.08
+    - _WristScale: 1
+    - _ZWrite: 1
+    - __dirty: 0
+    m_Colors:
+    - _Color: {r: 1, g: 0.44811308, b: 0.44811308, a: 1}
+    - _ColorBottom: {r: 1, g: 1, b: 1, a: 1}
+    - _ColorGlow: {r: 0.1215686, g: 0.1254902, b: 0.1294117, a: 1}
+    - _ColorPrimary: {r: 1, g: 0.4481132, b: 0.4481132, a: 1}
+    - _ColorSecondary: {r: 1, g: 0.8443396, b: 0.8443396, a: 1}
+    - _ColorTop: {r: 0.13207549, g: 0.13207549, b: 0.13207549, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+    - _FingerGlowColor: {r: 1, g: 1, b: 1, a: 1}
+    - _MainColor: {r: 0.1960784, g: 0.2039215, b: 0.2117647, a: 1}
+    - _OutlineColor: {r: 1, g: 1, b: 1, a: 0.78431374}
+    - _OutlineColorBottom: {r: 0, g: 0.19427729, b: 1, a: 1}
+    - _OutlineColorTop: {r: 1, g: 0, b: 0, a: 1}
+    - _OutlineGlowColor: {r: 0.4339623, g: 0.4339623, b: 0.4339623, a: 1}
+    - _OutlineJointColor: {r: 1, g: 0, b: 0, a: 1}
+    - _PinchColor: {r: 1, g: 0, b: 0, a: 1}
+    - _PinchPosition: {r: 0, g: 0, b: 0, a: 0}
+    - _WristLocalOffset: {r: -0.01, g: 0.01, b: 0, a: 0}
+    - _WristPosition: {r: 0, g: 0, b: 0, a: 0}
+  m_BuildTextureStacks: []

+ 8 - 0
Runtime/Resources/Materials/BuidIn/RokidHand.mat.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a5586b52504cb44bf91f8714a99c6e0a
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 2100000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Resources/Materials/URP.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 70ef347f9102148f1aac90888aedd46e
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 138 - 0
Runtime/Resources/Materials/URP/HandMesh_Finger.mat

@@ -0,0 +1,138 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &-7076763131281629734
+MonoBehaviour:
+  m_ObjectHideFlags: 11
+  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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  version: 5
+--- !u!21 &2100000
+Material:
+  serializedVersion: 8
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: HandMesh_Finger
+  m_Shader: {fileID: -6465566751694194690, guid: 82250e34d26de1846bed5563e4134689,
+    type: 3}
+  m_ValidKeywords: []
+  m_InvalidKeywords: []
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: 4000
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BaseMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _SampleTexture2D_2a2f7a77cc98434ba58850bd61046216_Texture_1:
+        m_Texture: {fileID: 2800000, guid: 4725325b136d0bf419e8334dfa5f3554, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _SpecGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _Texture2D:
+        m_Texture: {fileID: 2800000, guid: ab57dc2bf5b848e46bd647c46c30ee34, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - unity_Lightmaps:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - unity_LightmapsInd:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - unity_ShadowMasks:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Ints: []
+    m_Floats:
+    - _AlphaClip: 0
+    - _Blend: 0
+    - _BumpScale: 1
+    - _ClearCoatMask: 0
+    - _ClearCoatSmoothness: 0
+    - _Cull: 2
+    - _Cutoff: 0.5
+    - _DetailAlbedoMapScale: 1
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _EnvironmentReflections: 1
+    - _GlossMapScale: 0
+    - _Glossiness: 0
+    - _GlossyReflections: 0
+    - _Metallic: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.005
+    - _QueueControl: 1
+    - _QueueOffset: 0
+    - _ReceiveShadows: 1
+    - _Smoothness: 0.5
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _Surface: 0
+    - _WorkflowMode: 1
+    - _ZWrite: 1
+    - alpha: 7.79
+    - metallic: 0.87
+    - smoothness: 1.34
+    m_Colors:
+    - _BaseColor: {r: 1, g: 1, b: 1, a: 1}
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+    - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
+  m_BuildTextureStacks: []

+ 8 - 0
Runtime/Resources/Materials/URP/HandMesh_Finger.mat.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b4be02817bdd39b4d9087eabaed21187
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 2100000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 147 - 0
Runtime/Resources/Materials/URP/HandMesh_Palm.mat

@@ -0,0 +1,147 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 8
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: HandMesh_Palm
+  m_Shader: {fileID: -6465566751694194690, guid: c2f731d4ab8ab6740b4122c7ffdc4c8d,
+    type: 3}
+  m_ValidKeywords: []
+  m_InvalidKeywords: []
+  m_LightmapFlags: 2
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: 4000
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - Texture_Blue:
+        m_Texture: {fileID: 2800000, guid: ab57dc2bf5b848e46bd647c46c30ee34, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - Texture_wireframe:
+        m_Texture: {fileID: 2800000, guid: 2ff9aed8a051d1d4c9d7a2878d7bcd7f, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _BaseMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _SpecGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _Texture2D:
+        m_Texture: {fileID: 2800000, guid: 2ff9aed8a051d1d4c9d7a2878d7bcd7f, type: 3}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - unity_Lightmaps:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - unity_LightmapsInd:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - unity_ShadowMasks:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Ints: []
+    m_Floats:
+    - BlueColor: 1
+    - FR_Power: 0.83
+    - Metallic: 0.78
+    - Opacity: 2.23
+    - Smoothness: 2.3
+    - _AlphaClip: 0
+    - _Blend: 0
+    - _BumpScale: 1
+    - _ClearCoatMask: 0
+    - _ClearCoatSmoothness: 0
+    - _Cull: 2
+    - _Cutoff: 0.5
+    - _DetailAlbedoMapScale: 1
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _Emission: 4.87
+    - _EnvironmentReflections: 1
+    - _GlossMapScale: 0
+    - _Glossiness: 0
+    - _GlossyReflections: 0
+    - _Metallic: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.005
+    - _QueueControl: 1
+    - _QueueOffset: 0
+    - _ReceiveShadows: 1
+    - _Smoothness: 0.5
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _Surface: 0
+    - _WorkflowMode: 1
+    - _ZWrite: 1
+    m_Colors:
+    - BaseColor: {r: 0, g: 0, b: 0, a: 0}
+    - SpecularColor: {r: 1, g: 1, b: 1, a: 0}
+    - _BaseColor: {r: 1, g: 1, b: 1, a: 1}
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+    - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
+  m_BuildTextureStacks: []
+--- !u!114 &4112330979068935020
+MonoBehaviour:
+  m_ObjectHideFlags: 11
+  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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  version: 5

Some files were not shown because too many files changed in this diff