clean project
This commit is contained in:
8
Assets/Oculus/Interaction/Editor.meta
Normal file
8
Assets/Oculus/Interaction/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e628d552f8b252d44815ffae12fd3976
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
532
Assets/Oculus/Interaction/Editor/EditorBase.cs
Normal file
532
Assets/Oculus/Interaction/Editor/EditorBase.cs
Normal file
@@ -0,0 +1,532 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Oculus.Interaction.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
Assets/Oculus/Interaction/Editor/EditorBase.cs.meta
Normal file
11
Assets/Oculus/Interaction/Editor/EditorBase.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79ba2d579e9d1f14593db01074139346
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Editor/Grab.meta
Normal file
8
Assets/Oculus/Interaction/Editor/Grab.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c93e89dd55b481b4aa6ed62d6c8227bd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
96
Assets/Oculus/Interaction/Editor/Grab/GrabbingRuleEditor.cs
Normal file
96
Assets/Oculus/Interaction/Editor/Grab/GrabbingRuleEditor.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.GrabAPI
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(GrabbingRule))]
|
||||
public class GrabbingRuleEditor : PropertyDrawer
|
||||
{
|
||||
private static Dictionary<string, bool> _unfolds = new Dictionary<string, bool>();
|
||||
|
||||
private static readonly string[] FINGER_PROPERTY_NAMES = new string[]
|
||||
{
|
||||
"_thumbRequirement",
|
||||
"_indexRequirement",
|
||||
"_middleRequirement",
|
||||
"_ringRequirement",
|
||||
"_pinkyRequirement",
|
||||
};
|
||||
|
||||
private const float ROW_HEIGHT = 20f;
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
InitializeUnfold(property);
|
||||
if (_unfolds[property.propertyPath])
|
||||
{
|
||||
return ROW_HEIGHT * (Constants.NUM_FINGERS + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ROW_HEIGHT * 1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
InitializeUnfold(property);
|
||||
Rect rowRect = new Rect(position.x, position.y, position.width, ROW_HEIGHT);
|
||||
_unfolds[property.propertyPath] = EditorGUI.Foldout(rowRect, _unfolds[property.propertyPath], label, true);
|
||||
|
||||
if (_unfolds[property.propertyPath])
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; i++)
|
||||
{
|
||||
rowRect.y += ROW_HEIGHT;
|
||||
SerializedProperty finger = property.FindPropertyRelative(FINGER_PROPERTY_NAMES[i]);
|
||||
HandFinger fingerID = (HandFinger)i;
|
||||
FingerRequirement current = (FingerRequirement)finger.intValue;
|
||||
FingerRequirement selected = (FingerRequirement)EditorGUI.EnumPopup(rowRect, $"{fingerID}: ", current);
|
||||
finger.intValue = (int)selected;
|
||||
}
|
||||
|
||||
rowRect.y += ROW_HEIGHT;
|
||||
DrawFlagProperty<FingerUnselectMode>(property, rowRect, "Unselect Mode", "_unselectMode", false);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private void InitializeUnfold(SerializedProperty property)
|
||||
{
|
||||
if (!_unfolds.ContainsKey(property.propertyPath))
|
||||
{
|
||||
_unfolds.Add(property.propertyPath, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawFlagProperty<TEnum>(SerializedProperty parentProperty, Rect position, string title, string fieldName, bool isFlags) where TEnum : Enum
|
||||
{
|
||||
SerializedProperty fieldProperty = parentProperty.FindPropertyRelative(fieldName);
|
||||
TEnum value = (TEnum)Enum.ToObject(typeof(TEnum), fieldProperty.intValue);
|
||||
Enum selectedValue = isFlags ?
|
||||
EditorGUI.EnumFlagsField(position, title, value)
|
||||
: EditorGUI.EnumPopup(position, title, value);
|
||||
fieldProperty.intValue = (int)Enum.ToObject(typeof(TEnum), selectedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17f32e95fcaa23e45a5ac1297f201be2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Editor/HandPosing.meta
Normal file
8
Assets/Oculus/Interaction/Editor/HandPosing.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5718f10d26354c844a38bf3280138563
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0d69d4b88de08343adc54816c3220a1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,105 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.HandPosing.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(HandGrabInteractable))]
|
||||
public class HandGrabInteractableEditor : UnityEditor.Editor
|
||||
{
|
||||
private HandGrabInteractable _interactable;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_interactable = target as HandGrabInteractable;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
DrawGrabPointsMenu();
|
||||
GUILayout.Space(20f);
|
||||
DrawGenerationMenu();
|
||||
}
|
||||
|
||||
private void DrawGrabPointsMenu()
|
||||
{
|
||||
if (GUILayout.Button("Refresh HandGrab Points"))
|
||||
{
|
||||
_interactable.GrabPoints.Clear();
|
||||
HandGrabPoint[] handGrabPoints = _interactable.GetComponentsInChildren<HandGrabPoint>();
|
||||
_interactable.GrabPoints.AddRange(handGrabPoints);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Add HandGrab Point"))
|
||||
{
|
||||
if (_interactable.GrabPoints.Count > 0)
|
||||
{
|
||||
AddHandGrabPoint(_interactable.GrabPoints[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHandGrabPoint();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Replicate Default Scaled HandGrab Points"))
|
||||
{
|
||||
if (_interactable.GrabPoints.Count > 0)
|
||||
{
|
||||
AddHandGrabPoint(_interactable.GrabPoints[0], 0.8f);
|
||||
AddHandGrabPoint(_interactable.GrabPoints[0], 1.2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("You have to provide a default HandGrabPoint first!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddHandGrabPoint(HandGrabPoint copy = null, float? scale = null)
|
||||
{
|
||||
HandGrabPoint point = _interactable.CreatePoint();
|
||||
if (copy != null)
|
||||
{
|
||||
HandGrabPointEditor.CloneHandGrabPoint(copy, point);
|
||||
if (scale.HasValue)
|
||||
{
|
||||
HandGrabPointData scaledData = point.SaveData();
|
||||
scaledData.scale = scale.Value;
|
||||
point.LoadData(scaledData, copy.RelativeTo);
|
||||
}
|
||||
}
|
||||
_interactable.GrabPoints.Add(point);
|
||||
}
|
||||
|
||||
private void DrawGenerationMenu()
|
||||
{
|
||||
if (GUILayout.Button("Create Mirrored HandGrabInteractable"))
|
||||
{
|
||||
HandGrabInteractable mirrorInteractable = HandGrabInteractable.Create(_interactable.RelativeTo);
|
||||
|
||||
foreach (HandGrabPoint point in _interactable.GrabPoints)
|
||||
{
|
||||
HandGrabPoint mirrorPoint = mirrorInteractable.CreatePoint();
|
||||
HandGrabPointEditor.MirrorHandGrabPoint(point, mirrorPoint);
|
||||
mirrorPoint.transform.SetParent(mirrorInteractable.transform);
|
||||
mirrorInteractable.GrabPoints.Add(mirrorPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5ce7770848930447885c9abba8bb99a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,325 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.Input;
|
||||
using Oculus.Interaction.HandPosing.Visuals;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.HandPosing.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(HandGrabPoint))]
|
||||
public class HandGrabPointEditor : UnityEditor.Editor
|
||||
{
|
||||
private HandGrabPoint _handGrabPoint;
|
||||
|
||||
private HandGhostProvider _ghostVisualsProvider;
|
||||
private HandGhost _handGhost;
|
||||
private HandPuppet _ghostPuppet;
|
||||
private Handedness _lastHandedness;
|
||||
|
||||
private HandPose _poseTransfer;
|
||||
private bool _editingFingers;
|
||||
|
||||
private SerializedProperty _handPoseProperty;
|
||||
|
||||
private const float GIZMO_SCALE = 0.005f;
|
||||
private static readonly Color FLEX_COLOR = new Color(0f, 1f, 1f, 0.5f);
|
||||
private static readonly Color SPREAD_COLOR = new Color(0.5f, 0.3f, 1f, 0.5f);
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_handGrabPoint = target as HandGrabPoint;
|
||||
_handPoseProperty = serializedObject.FindProperty("_handPose");
|
||||
AssignMissingGhostProvider();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
DestroyGhost();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
if (_handGrabPoint.HandPose != null
|
||||
&& _handPoseProperty != null)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_handPoseProperty);
|
||||
EditorGUILayout.Space();
|
||||
DrawGhostMenu(_handGrabPoint.HandPose, false);
|
||||
}
|
||||
else if (_handGhost != null)
|
||||
{
|
||||
DestroyGhost();
|
||||
}
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void DrawGhostMenu(HandPose handPose, bool forceCreate)
|
||||
{
|
||||
GUIStyle boldStyle = new GUIStyle(GUI.skin.label) { fontStyle = FontStyle.Bold };
|
||||
EditorGUILayout.LabelField("Interactive Edition", boldStyle);
|
||||
|
||||
HandGhostProvider provider = EditorGUILayout.ObjectField("Ghost Provider", _ghostVisualsProvider, typeof(HandGhostProvider), false) as HandGhostProvider;
|
||||
if (forceCreate
|
||||
|| provider != _ghostVisualsProvider
|
||||
|| _handGhost == null
|
||||
|| _lastHandedness != handPose.Handedness)
|
||||
{
|
||||
RegenerateGhost(provider);
|
||||
}
|
||||
_lastHandedness = handPose.Handedness;
|
||||
|
||||
if (_handGrabPoint.SnapSurface == null)
|
||||
{
|
||||
_editingFingers = true;
|
||||
}
|
||||
else if (GUILayout.Button(_editingFingers ? "Follow Surface" : "Edit fingers"))
|
||||
{
|
||||
_editingFingers = !_editingFingers;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSceneGUI()
|
||||
{
|
||||
SceneView view = SceneView.currentDrawingSceneView;
|
||||
if (view == null || _handGhost == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_editingFingers)
|
||||
{
|
||||
GhostEditFingers();
|
||||
if (AnyPuppetBoneChanged())
|
||||
{
|
||||
TransferGhostBoneRotations();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GhostFollowSurface();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void EditSnapPoint(Transform snapPoint)
|
||||
{
|
||||
Vector3 pos = snapPoint.position;
|
||||
Quaternion rot = snapPoint.rotation;
|
||||
Handles.TransformHandle(ref pos, ref rot);
|
||||
|
||||
if (pos != snapPoint.position)
|
||||
{
|
||||
Undo.RecordObject(snapPoint.transform, "SnapPoint Position");
|
||||
snapPoint.position = pos;
|
||||
}
|
||||
|
||||
if (rot != snapPoint.rotation)
|
||||
{
|
||||
Undo.RecordObject(snapPoint.transform, "SnapPoint Rotation");
|
||||
snapPoint.rotation = rot;
|
||||
}
|
||||
}
|
||||
|
||||
#region generation
|
||||
/// <summary>
|
||||
/// Generates a new HandGrabPointData that mirrors the provided one. Left hand becomes right hand and vice-versa.
|
||||
/// The mirror axis is defined by the surface of the snap point, if any, if none a best-guess is provided
|
||||
/// but note that it can then moved manually in the editor.
|
||||
/// </summary>
|
||||
/// <param name="originalPoint">The point to mirror</param>
|
||||
/// <param name="originalPoint">The target HandGrabPoint to set as mirrored of the originalPoint</param>
|
||||
public static void MirrorHandGrabPoint(HandGrabPoint originalPoint, HandGrabPoint mirrorPoint)
|
||||
{
|
||||
HandPose handPose = originalPoint.HandPose;
|
||||
|
||||
Handedness oppositeHandedness = handPose.Handedness == Handedness.Left ? Handedness.Right : Handedness.Left;
|
||||
|
||||
HandGrabPointData mirrorData = originalPoint.SaveData();
|
||||
mirrorData.handPose.Handedness = oppositeHandedness;
|
||||
|
||||
if (originalPoint.SnapSurface != null)
|
||||
{
|
||||
mirrorData.gripPose = originalPoint.SnapSurface.MirrorPose(mirrorData.gripPose);
|
||||
}
|
||||
else
|
||||
{
|
||||
mirrorData.gripPose = mirrorData.gripPose.MirrorPoseRotation(Vector3.forward, Vector3.up);
|
||||
Vector3 translation = Vector3.Project(mirrorData.gripPose.position, Vector3.right);
|
||||
mirrorData.gripPose.position = mirrorData.gripPose.position - 2f * translation;
|
||||
}
|
||||
|
||||
mirrorPoint.LoadData(mirrorData, originalPoint.RelativeTo);
|
||||
if (originalPoint.SnapSurface != null)
|
||||
{
|
||||
SnapSurfaces.ISnapSurface mirroredSurface = originalPoint.SnapSurface.CreateMirroredSurface(mirrorPoint.gameObject);
|
||||
mirrorPoint.InjectOptionalSurface(mirroredSurface);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CloneHandGrabPoint(HandGrabPoint originalPoint, HandGrabPoint targetPoint)
|
||||
{
|
||||
HandGrabPointData mirrorData = originalPoint.SaveData();
|
||||
targetPoint.LoadData(mirrorData, originalPoint.RelativeTo);
|
||||
if (originalPoint.SnapSurface != null)
|
||||
{
|
||||
SnapSurfaces.ISnapSurface mirroredSurface = originalPoint.SnapSurface.CreateDuplicatedSurface(targetPoint.gameObject);
|
||||
targetPoint.InjectOptionalSurface(mirroredSurface);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ghost
|
||||
|
||||
private void AssignMissingGhostProvider()
|
||||
{
|
||||
if (_ghostVisualsProvider != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HandGhostProvider[] providers = Resources.FindObjectsOfTypeAll<HandGhostProvider>();
|
||||
if (providers != null && providers.Length > 0)
|
||||
{
|
||||
_ghostVisualsProvider = providers[0];
|
||||
}
|
||||
}
|
||||
|
||||
private void RegenerateGhost(HandGhostProvider provider)
|
||||
{
|
||||
_ghostVisualsProvider = provider;
|
||||
DestroyGhost();
|
||||
CreateGhost();
|
||||
}
|
||||
|
||||
private void CreateGhost()
|
||||
{
|
||||
if (_ghostVisualsProvider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HandGhost ghostPrototype = _ghostVisualsProvider.GetHand(_handGrabPoint.HandPose.Handedness);
|
||||
_handGhost = GameObject.Instantiate(ghostPrototype, _handGrabPoint.transform);
|
||||
_handGhost.gameObject.hideFlags = HideFlags.HideAndDontSave;
|
||||
_handGhost.SetPose(_handGrabPoint);
|
||||
_ghostPuppet = _handGhost.GetComponent<HandPuppet>();
|
||||
}
|
||||
|
||||
private void DestroyGhost()
|
||||
{
|
||||
if (_handGhost != null)
|
||||
{
|
||||
GameObject.DestroyImmediate(_handGhost.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void GhostFollowSurface()
|
||||
{
|
||||
if (_handGhost == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Pose ghostTargetPose = _handGrabPoint.RelativeGrip;
|
||||
|
||||
if (_handGrabPoint.SnapSurface != null)
|
||||
{
|
||||
Vector3 mousePosition = Event.current.mousePosition;
|
||||
Ray ray = HandleUtility.GUIPointToWorldRay(mousePosition);
|
||||
Pose recorderPose = _handGrabPoint.transform.GetPose();
|
||||
if (_handGrabPoint.SnapSurface.CalculateBestPoseAtSurface(ray, recorderPose, out Pose target))
|
||||
{
|
||||
ghostTargetPose.position = _handGrabPoint.RelativeTo.InverseTransformPoint(target.position);
|
||||
ghostTargetPose.rotation = Quaternion.Inverse(_handGrabPoint.RelativeTo.rotation) * target.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
_handGhost.SetGripPose(ghostTargetPose, _handGrabPoint.RelativeTo);
|
||||
}
|
||||
|
||||
private void GhostEditFingers()
|
||||
{
|
||||
HandPuppet puppet = _handGhost.GetComponent<HandPuppet>();
|
||||
if (puppet != null && puppet.JointMaps != null)
|
||||
{
|
||||
DrawBonesRotator(puppet.JointMaps);
|
||||
}
|
||||
}
|
||||
|
||||
private void TransferGhostBoneRotations()
|
||||
{
|
||||
_poseTransfer = _handGrabPoint.HandPose;
|
||||
_ghostPuppet.CopyCachedJoints(ref _poseTransfer);
|
||||
_handGrabPoint.HandPose.CopyFrom(_poseTransfer);
|
||||
}
|
||||
|
||||
private void DrawBonesRotator(List<HandJointMap> bones)
|
||||
{
|
||||
foreach (HandJointMap bone in bones)
|
||||
{
|
||||
int metadataIndex = FingersMetadata.HandJointIdToIndex(bone.id);
|
||||
HandFinger finger = FingersMetadata.HAND_FINGER_ID[metadataIndex];
|
||||
|
||||
if (_handGrabPoint.HandPose.FingersFreedom[(int)finger] == JointFreedom.Free)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Handles.color = FLEX_COLOR;
|
||||
Quaternion rotation = Handles.Disc(bone.transform.rotation, bone.transform.position,
|
||||
bone.transform.forward, GIZMO_SCALE, false, 0);
|
||||
|
||||
if (FingersMetadata.HAND_JOINT_CAN_SPREAD[metadataIndex])
|
||||
{
|
||||
Handles.color = SPREAD_COLOR;
|
||||
rotation = Handles.Disc(rotation, bone.transform.position,
|
||||
bone.transform.up, GIZMO_SCALE, false, 0);
|
||||
}
|
||||
|
||||
if (bone.transform.rotation != rotation)
|
||||
{
|
||||
Undo.RecordObject(bone.transform, "Bone Rotation");
|
||||
bone.transform.rotation = rotation;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detects if we have moved the transforms of the fingers so the data can be kept up to date.
|
||||
/// To be used in Edit-mode.
|
||||
/// </summary>
|
||||
/// <returns>True if any of the fingers has moved from the previous frame.</returns>
|
||||
private bool AnyPuppetBoneChanged()
|
||||
{
|
||||
bool hasChanged = false;
|
||||
foreach (HandJointMap bone in _ghostPuppet.JointMaps)
|
||||
{
|
||||
if (bone.transform.hasChanged)
|
||||
{
|
||||
bone.transform.hasChanged = false;
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92b8a050249b4ea47b9da8fe38ed12a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,67 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.Input;
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.HandPosing.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(HandPose))]
|
||||
public class HandPoseEditor : PropertyDrawer
|
||||
{
|
||||
private bool _foldedFreedom = true;
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
DrawEnumProperty<Handedness>(property, "Handedness:", "_handedness", false);
|
||||
DrawFingersFreedomMenu(property);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private void DrawFingersFreedomMenu(SerializedProperty property)
|
||||
{
|
||||
_foldedFreedom = EditorGUILayout.Foldout(_foldedFreedom, "Fingers Freedom", true);
|
||||
if (_foldedFreedom)
|
||||
{
|
||||
SerializedProperty fingersFreedom = property.FindPropertyRelative("_fingersFreedom");
|
||||
EditorGUILayout.BeginVertical();
|
||||
for (int i = 0; i < Constants.NUM_FINGERS; i++)
|
||||
{
|
||||
SerializedProperty finger = fingersFreedom.GetArrayElementAtIndex(i);
|
||||
HandFinger fingerID = (HandFinger)i;
|
||||
JointFreedom current = (JointFreedom)finger.intValue;
|
||||
JointFreedom selected = (JointFreedom)EditorGUILayout.EnumPopup($"{fingerID}: ", current);
|
||||
finger.intValue = (int)selected;
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEnumProperty<TEnum>(SerializedProperty parentProperty, string title, string fieldName, bool isFlags) where TEnum : Enum
|
||||
{
|
||||
SerializedProperty fieldProperty = parentProperty.FindPropertyRelative(fieldName);
|
||||
TEnum value = (TEnum)Enum.ToObject(typeof(TEnum), fieldProperty.intValue);
|
||||
Enum selectedValue = isFlags ?
|
||||
EditorGUILayout.EnumFlagsField(title, value)
|
||||
: EditorGUILayout.EnumPopup(title, value);
|
||||
fieldProperty.intValue = (int)Enum.ToObject(typeof(TEnum), selectedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25b4f8dbe894a92489fe06cc956a42e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eef729dcc033d3e419718da8e409c0f3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,163 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.HandPosing.SnapSurfaces.Editor
|
||||
{
|
||||
[CustomEditor(typeof(BoxSurface))]
|
||||
[CanEditMultipleObjects]
|
||||
public class BoxEditor : UnityEditor.Editor
|
||||
{
|
||||
private static readonly Color NONINTERACTABLE_COLOR = new Color(0f, 1f, 1f, 0.1f);
|
||||
private static readonly Color INTERACTABLE_COLOR = new Color(0f, 1f, 1f, 0.5f);
|
||||
|
||||
private BoxBoundsHandle _boxHandle = new BoxBoundsHandle();
|
||||
private BoxSurface _surface;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_boxHandle.handleColor = INTERACTABLE_COLOR;
|
||||
_boxHandle.wireframeColor = NONINTERACTABLE_COLOR;
|
||||
_boxHandle.axes = PrimitiveBoundsHandle.Axes.X | PrimitiveBoundsHandle.Axes.Z;
|
||||
|
||||
_surface = (target as BoxSurface);
|
||||
}
|
||||
|
||||
public void OnSceneGUI()
|
||||
{
|
||||
DrawRotator(_surface);
|
||||
DrawBoxEditor(_surface);
|
||||
DrawSlider(_surface);
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
DrawSnapLines(_surface);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSnapLines(BoxSurface surface)
|
||||
{
|
||||
Handles.color = INTERACTABLE_COLOR;
|
||||
|
||||
Vector3 rightAxis = surface.Rotation * Vector3.right;
|
||||
Vector3 forwardAxis = surface.Rotation * Vector3.forward;
|
||||
Vector3 forwardOffset = forwardAxis * surface.Size.z;
|
||||
|
||||
Vector3 bottomLeft = surface.transform.position - rightAxis * surface.Size.x * (1f - surface.WidthOffset);
|
||||
Vector3 bottomRight = surface.transform.position + rightAxis * surface.Size.x * (surface.WidthOffset);
|
||||
Vector3 topLeft = bottomLeft + forwardOffset;
|
||||
Vector3 topRight = bottomRight + forwardOffset;
|
||||
|
||||
Handles.DrawLine(bottomLeft + rightAxis * surface.SnapOffset.y, bottomRight + rightAxis * surface.SnapOffset.x);
|
||||
Handles.DrawLine(topLeft - rightAxis * surface.SnapOffset.x, topRight - rightAxis * surface.SnapOffset.y);
|
||||
Handles.DrawLine(bottomLeft - forwardAxis * surface.SnapOffset.z, topLeft - forwardAxis * surface.SnapOffset.w);
|
||||
Handles.DrawLine(bottomRight + forwardAxis * surface.SnapOffset.w, topRight + forwardAxis * surface.SnapOffset.z);
|
||||
}
|
||||
|
||||
private void DrawSlider(BoxSurface surface)
|
||||
{
|
||||
Handles.color = INTERACTABLE_COLOR;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Vector3 rightDir = surface.Rotation * Vector3.right;
|
||||
Vector3 forwardDir = surface.Rotation * Vector3.forward;
|
||||
Vector3 bottomRight = surface.transform.position
|
||||
+ rightDir * surface.Size.x * (surface.WidthOffset);
|
||||
Vector3 bottomLeft = surface.transform.position
|
||||
- rightDir * surface.Size.x * (1f - surface.WidthOffset);
|
||||
Vector3 topRight = bottomRight + forwardDir * surface.Size.z;
|
||||
|
||||
Vector3 rightHandle = DrawOffsetHandle(bottomRight + rightDir * surface.SnapOffset.x, rightDir);
|
||||
Vector3 leftHandle = DrawOffsetHandle(bottomLeft + rightDir * surface.SnapOffset.y, -rightDir);
|
||||
Vector3 topHandle = DrawOffsetHandle(topRight + forwardDir * surface.SnapOffset.z, forwardDir);
|
||||
Vector3 bottomHandle = DrawOffsetHandle(bottomRight + forwardDir * surface.SnapOffset.w, -forwardDir);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(surface, "Change Offset Box");
|
||||
Vector4 offset = surface.SnapOffset;
|
||||
offset.x = DistanceToHandle(bottomRight, rightHandle, rightDir);
|
||||
offset.y = DistanceToHandle(bottomLeft, leftHandle, rightDir);
|
||||
offset.z = DistanceToHandle(topRight, topHandle, forwardDir);
|
||||
offset.w = DistanceToHandle(bottomRight, bottomHandle, forwardDir);
|
||||
surface.SnapOffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 DrawOffsetHandle(Vector3 point, Vector3 dir)
|
||||
{
|
||||
float size = HandleUtility.GetHandleSize(point) * 0.2f;
|
||||
return Handles.Slider(point, dir, size, Handles.ConeHandleCap, 0f);
|
||||
}
|
||||
|
||||
private float DistanceToHandle(Vector3 origin, Vector3 handlePoint, Vector3 dir)
|
||||
{
|
||||
float distance = Vector3.Distance(origin, handlePoint);
|
||||
if (Vector3.Dot(handlePoint - origin, dir) < 0f)
|
||||
{
|
||||
distance = -distance;
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
private void DrawRotator(BoxSurface surface)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Quaternion rotation = Handles.RotationHandle(surface.Rotation, surface.transform.position);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(surface, "Change Rotation Box");
|
||||
surface.Rotation = rotation;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBoxEditor(BoxSurface surface)
|
||||
{
|
||||
Quaternion rot = surface.Rotation;
|
||||
Vector3 size = surface.Size;
|
||||
|
||||
Vector3 snapP = surface.transform.position;
|
||||
|
||||
_boxHandle.size = size;
|
||||
float widthPos = Mathf.Lerp(-size.x * 0.5f, size.x * 0.5f, surface.WidthOffset);
|
||||
_boxHandle.center = new Vector3(widthPos, 0f, size.z * 0.5f);
|
||||
|
||||
Matrix4x4 handleMatrix = Matrix4x4.TRS(
|
||||
snapP,
|
||||
rot,
|
||||
Vector3.one
|
||||
);
|
||||
|
||||
using (new Handles.DrawingScope(handleMatrix))
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_boxHandle.DrawHandle();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(surface, "Change Box Properties");
|
||||
|
||||
surface.Size = _boxHandle.size;
|
||||
float width = _boxHandle.size.x;
|
||||
surface.WidthOffset = width != 0f ? (_boxHandle.center.x + width * 0.5f) / width : 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
private float RemapClamped(float value, (float, float) from, (float, float) to)
|
||||
{
|
||||
value = Mathf.Clamp(value, from.Item1, from.Item2);
|
||||
return to.Item1 + (value - from.Item1) * (to.Item2 - to.Item1) / (from.Item2 - from.Item1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baf3d860debef0947b62cdebdd94cb74
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,132 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.HandPosing.SnapSurfaces.Editor
|
||||
{
|
||||
[CustomEditor(typeof(CylinderSurface))]
|
||||
[CanEditMultipleObjects]
|
||||
public class CylinderEditor : UnityEditor.Editor
|
||||
{
|
||||
private static readonly Color NONINTERACTABLE_COLOR = new Color(0f, 1f, 1f, 0.1f);
|
||||
private static readonly Color INTERACTABLE_COLOR = new Color(0f, 1f, 1f, 0.5f);
|
||||
private const float DRAW_SURFACE_ANGULAR_RESOLUTION = 5f;
|
||||
|
||||
private ArcHandle _arcHandle = new ArcHandle();
|
||||
private Vector3[] _surfaceEdges;
|
||||
|
||||
CylinderSurface _surface;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_arcHandle.SetColorWithRadiusHandle(INTERACTABLE_COLOR, 0f);
|
||||
_surface = (target as CylinderSurface);
|
||||
}
|
||||
|
||||
public void OnSceneGUI()
|
||||
{
|
||||
DrawEndsCaps(_surface);
|
||||
DrawArcEditor(_surface);
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
DrawSurfaceVolume(_surface);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEndsCaps(CylinderSurface surface)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
Quaternion handleRotation = (surface.RelativeTo ?? surface.transform).rotation;
|
||||
|
||||
Vector3 startPosition = Handles.PositionHandle(surface.StartPoint, handleRotation);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(surface, "Change Start Cylinder Position");
|
||||
surface.StartPoint = startPosition;
|
||||
}
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Vector3 endPosition = Handles.PositionHandle(surface.EndPoint, handleRotation);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(surface, "Change Start Cylinder Position");
|
||||
surface.EndPoint = endPosition;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSurfaceVolume(CylinderSurface surface)
|
||||
{
|
||||
Vector3 start = surface.StartPoint;
|
||||
Vector3 end = surface.EndPoint;
|
||||
float radius = surface.Radius;
|
||||
|
||||
Handles.color = INTERACTABLE_COLOR;
|
||||
Handles.DrawWireArc(end,
|
||||
surface.Direction,
|
||||
surface.StartAngleDir,
|
||||
surface.Angle,
|
||||
radius);
|
||||
|
||||
Handles.DrawLine(start, end);
|
||||
Handles.DrawLine(start, start + surface.StartAngleDir * radius);
|
||||
Handles.DrawLine(start, start + surface.EndAngleDir * radius);
|
||||
Handles.DrawLine(end, end + surface.StartAngleDir * radius);
|
||||
Handles.DrawLine(end, end + surface.EndAngleDir * radius);
|
||||
|
||||
int edgePoints = Mathf.CeilToInt((2 * surface.Angle) / DRAW_SURFACE_ANGULAR_RESOLUTION) + 3;
|
||||
if (_surfaceEdges == null
|
||||
|| _surfaceEdges.Length != edgePoints)
|
||||
{
|
||||
_surfaceEdges = new Vector3[edgePoints];
|
||||
}
|
||||
|
||||
Handles.color = NONINTERACTABLE_COLOR;
|
||||
int i = 0;
|
||||
for (float angle = 0f; angle < surface.Angle; angle += DRAW_SURFACE_ANGULAR_RESOLUTION)
|
||||
{
|
||||
Vector3 direction = Quaternion.AngleAxis(angle, surface.Direction) * surface.StartAngleDir;
|
||||
_surfaceEdges[i++] = start + direction * radius;
|
||||
_surfaceEdges[i++] = end + direction * radius;
|
||||
}
|
||||
_surfaceEdges[i++] = start + surface.EndAngleDir * radius;
|
||||
_surfaceEdges[i++] = end + surface.EndAngleDir * radius;
|
||||
Handles.DrawPolyLine(_surfaceEdges);
|
||||
}
|
||||
|
||||
private void DrawArcEditor(CylinderSurface surface)
|
||||
{
|
||||
float radius = surface.Radius;
|
||||
_arcHandle.angle = surface.Angle;
|
||||
_arcHandle.radius = radius;
|
||||
|
||||
Matrix4x4 handleMatrix = Matrix4x4.TRS(
|
||||
surface.StartPoint,
|
||||
Quaternion.LookRotation(surface.StartAngleDir, surface.Direction),
|
||||
Vector3.one
|
||||
);
|
||||
using (new Handles.DrawingScope(handleMatrix))
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_arcHandle.DrawHandle();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(surface, "Change Cylinder Properties");
|
||||
surface.Angle = _arcHandle.angle;
|
||||
radius = _arcHandle.radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69099ed7427360a4ab3734573c188647
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,77 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.HandPosing.SnapSurfaces.Editor
|
||||
{
|
||||
[CustomEditor(typeof(SphereSurface))]
|
||||
[CanEditMultipleObjects]
|
||||
public class SphereEditor : UnityEditor.Editor
|
||||
{
|
||||
private static readonly Color NONINTERACTABLE_COLOR = new Color(0f, 1f, 1f, 0.1f);
|
||||
private static readonly Color INTERACTABLE_COLOR = new Color(0f, 1f, 1f, 0.5f);
|
||||
|
||||
private SphereBoundsHandle _sphereHandle = new SphereBoundsHandle();
|
||||
private SphereSurface _surface;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_sphereHandle.SetColor(INTERACTABLE_COLOR);
|
||||
_sphereHandle.midpointHandleDrawFunction = null;
|
||||
|
||||
_surface = (target as SphereSurface);
|
||||
}
|
||||
|
||||
public void OnSceneGUI()
|
||||
{
|
||||
DrawCentre(_surface);
|
||||
Handles.color = Color.white;
|
||||
DrawSphereEditor(_surface);
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
DrawSurfaceVolume(_surface);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCentre(SphereSurface surface)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Quaternion handleRotation = (surface.RelativeTo ?? surface.transform).rotation;
|
||||
Vector3 centrePosition = Handles.PositionHandle(surface.Centre, handleRotation);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(surface, "Change Centre Sphere Position");
|
||||
surface.Centre = centrePosition;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSurfaceVolume(SphereSurface surface)
|
||||
{
|
||||
Handles.color = INTERACTABLE_COLOR;
|
||||
Vector3 startLine = surface.Centre;
|
||||
Vector3 endLine = startLine + surface.Rotation * Vector3.forward * surface.Radius;
|
||||
Handles.DrawDottedLine(startLine, endLine, 5);
|
||||
}
|
||||
private void DrawSphereEditor(SphereSurface surface)
|
||||
{
|
||||
_sphereHandle.radius = surface.Radius;
|
||||
_sphereHandle.center = surface.Centre;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_sphereHandle.DrawHandle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee7657a153e652d448fa1b7775ca7f8c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Editor/HandPosing/Visuals.meta
Normal file
8
Assets/Oculus/Interaction/Editor/HandPosing/Visuals.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5760a4e866e11cb46a5adff4e32acc44
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,114 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.Input;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System;
|
||||
|
||||
namespace Oculus.Interaction.HandPosing.Visuals.Editor
|
||||
{
|
||||
[CustomEditor(typeof(HandPuppet))]
|
||||
public class HandPuppetEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
|
||||
HandPuppet puppet = target as HandPuppet;
|
||||
if (GUILayout.Button("Auto-Assign Bones"))
|
||||
{
|
||||
SkinnedMeshRenderer skinnedHand = puppet.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||
if (skinnedHand != null)
|
||||
{
|
||||
SetPrivateValue(puppet, "_jointMaps", AutoAsignBones(skinnedHand));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<HandJointMap> AutoAsignBones(SkinnedMeshRenderer skinnedHand)
|
||||
{
|
||||
List<HandJointMap> maps = new List<HandJointMap>();
|
||||
Transform root = skinnedHand.rootBone;
|
||||
Regex regEx = new Regex(@"Hand(\w*)(\d)");
|
||||
foreach (var bone in FingersMetadata.HAND_JOINT_IDS)
|
||||
{
|
||||
Match match = regEx.Match(bone.ToString());
|
||||
if (match != Match.Empty)
|
||||
{
|
||||
string boneName = match.Groups[1].Value.ToLower();
|
||||
string boneNumber = match.Groups[2].Value;
|
||||
Transform skinnedBone = RecursiveSearchForChildrenContainingPattern(root, "col", boneName, boneNumber);
|
||||
if (skinnedBone != null)
|
||||
{
|
||||
maps.Add(new HandJointMap()
|
||||
{
|
||||
id = bone,
|
||||
transform = skinnedBone,
|
||||
rotationOffset = Vector3.zero
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return maps;
|
||||
}
|
||||
|
||||
private Transform RecursiveSearchForChildrenContainingPattern(Transform root, string ignorePattern, params string[] args)
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < root.childCount; i++)
|
||||
{
|
||||
Transform child = root.GetChild(i);
|
||||
string childName = child.name.ToLower();
|
||||
|
||||
bool shouldCheck = string.IsNullOrEmpty(ignorePattern)|| !childName.Contains(ignorePattern);
|
||||
if (shouldCheck)
|
||||
{
|
||||
bool containsAllArgs = args.All(a => childName.Contains(a));
|
||||
Transform result = containsAllArgs ? child
|
||||
: RecursiveSearchForChildrenContainingPattern(child, ignorePattern, args);
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void SetPrivateValue(object instance, string fieldName, object value)
|
||||
{
|
||||
FieldInfo fieldData = GetPrivateField(instance, fieldName);
|
||||
fieldData.SetValue(instance, value);
|
||||
}
|
||||
|
||||
private static FieldInfo GetPrivateField(object instance, string fieldName)
|
||||
{
|
||||
Type type = instance.GetType();
|
||||
FieldInfo fieldData = null;
|
||||
while (type != null && fieldData == null)
|
||||
{
|
||||
fieldData = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
type = type.BaseType;
|
||||
}
|
||||
return fieldData;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb714303644f5c343bd2c80559c02856
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Editor/Hands.meta
Normal file
8
Assets/Oculus/Interaction/Editor/Hands.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d1754bb0e390e44e906221c5091ed9a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
188
Assets/Oculus/Interaction/Editor/Hands/HandVisualEditor.cs
Normal file
188
Assets/Oculus/Interaction/Editor/Hands/HandVisualEditor.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.Input;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.Hands.Editor
|
||||
{
|
||||
[CustomEditor(typeof(HandVisual))]
|
||||
public class HandVisualEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawPropertiesExcluding(serializedObject);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
HandVisual visual = (HandVisual)target;
|
||||
InitializeSkeleton(visual);
|
||||
|
||||
if (visual.Hand == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(GUILayout.Button("Auto Map Joints"))
|
||||
{
|
||||
AutoMapJoints(visual);
|
||||
EditorUtility.SetDirty(visual);
|
||||
EditorSceneManager.MarkSceneDirty(visual.gameObject.scene);
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Joints", EditorStyles.boldLabel);
|
||||
HandJointId start = HandJointId.HandStart;
|
||||
HandJointId end = HandJointId.HandEnd;
|
||||
|
||||
for (int i = (int)start; i < (int)end; ++i)
|
||||
{
|
||||
string jointName = HandJointLabelFromJointId((HandJointId)i);
|
||||
visual.Joints[i] = (Transform)EditorGUILayout.ObjectField(jointName,
|
||||
visual.Joints[i], typeof(Transform), true);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string[] _fbxHandSidePrefix = { "l_", "r_" };
|
||||
private static readonly string _fbxHandBonePrefix = "b_";
|
||||
|
||||
private static readonly string[] _fbxHandBoneNames =
|
||||
{
|
||||
"wrist",
|
||||
"forearm_stub",
|
||||
"thumb0",
|
||||
"thumb1",
|
||||
"thumb2",
|
||||
"thumb3",
|
||||
"index1",
|
||||
"index2",
|
||||
"index3",
|
||||
"middle1",
|
||||
"middle2",
|
||||
"middle3",
|
||||
"ring1",
|
||||
"ring2",
|
||||
"ring3",
|
||||
"pinky0",
|
||||
"pinky1",
|
||||
"pinky2",
|
||||
"pinky3"
|
||||
};
|
||||
|
||||
private static readonly string[] _fbxHandFingerNames =
|
||||
{
|
||||
"thumb",
|
||||
"index",
|
||||
"middle",
|
||||
"ring",
|
||||
"pinky"
|
||||
};
|
||||
|
||||
private void InitializeSkeleton(HandVisual visual)
|
||||
{
|
||||
if (visual.Joints.Count == 0)
|
||||
{
|
||||
for (int i = (int)HandJointId.HandStart; i < (int)HandJointId.HandEnd; ++i)
|
||||
{
|
||||
visual.Joints.Add(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoMapJoints(HandVisual visual)
|
||||
{
|
||||
if (visual.Hand == null)
|
||||
{
|
||||
InitializeSkeleton(visual);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = (int)HandJointId.HandStart; i < (int)HandJointId.HandEnd; ++i)
|
||||
{
|
||||
string fbxBoneName = FbxBoneNameFromHandJointId(visual, (HandJointId)i);
|
||||
Transform t = visual.transform.FindChildRecursive(fbxBoneName);
|
||||
visual.Joints[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
private string FbxBoneNameFromHandJointId(HandVisual visual, HandJointId handJointId)
|
||||
{
|
||||
if (handJointId >= HandJointId.HandThumbTip && handJointId <= HandJointId.HandPinkyTip)
|
||||
{
|
||||
return _fbxHandSidePrefix[(int)visual.Hand.Handedness] + _fbxHandFingerNames[(int)handJointId - (int)HandJointId.HandThumbTip] + "_finger_tip_marker";
|
||||
}
|
||||
else
|
||||
{
|
||||
return _fbxHandBonePrefix + _fbxHandSidePrefix[(int)visual.Hand.Handedness] + _fbxHandBoneNames[(int)handJointId];
|
||||
}
|
||||
}
|
||||
|
||||
// force aliased enum values to the more appropriate value
|
||||
private static string HandJointLabelFromJointId(HandJointId handJointId)
|
||||
{
|
||||
switch (handJointId)
|
||||
{
|
||||
case HandJointId.HandWristRoot:
|
||||
return "HandWristRoot";
|
||||
case HandJointId.HandForearmStub:
|
||||
return "HandForearmStub";
|
||||
case HandJointId.HandThumb0:
|
||||
return "HandThumb0";
|
||||
case HandJointId.HandThumb1:
|
||||
return "HandThumb1";
|
||||
case HandJointId.HandThumb2:
|
||||
return "HandThumb2";
|
||||
case HandJointId.HandThumb3:
|
||||
return "HandThumb3";
|
||||
case HandJointId.HandIndex1:
|
||||
return "HandIndex1";
|
||||
case HandJointId.HandIndex2:
|
||||
return "HandIndex2";
|
||||
case HandJointId.HandIndex3:
|
||||
return "HandIndex3";
|
||||
case HandJointId.HandMiddle1:
|
||||
return "HandMiddle1";
|
||||
case HandJointId.HandMiddle2:
|
||||
return "HandMiddle2";
|
||||
case HandJointId.HandMiddle3:
|
||||
return "HandMiddle3";
|
||||
case HandJointId.HandRing1:
|
||||
return "HandRing1";
|
||||
case HandJointId.HandRing2:
|
||||
return "HandRing2";
|
||||
case HandJointId.HandRing3:
|
||||
return "HandRing3";
|
||||
case HandJointId.HandPinky0:
|
||||
return "HandPinky0";
|
||||
case HandJointId.HandPinky1:
|
||||
return "HandPinky1";
|
||||
case HandJointId.HandPinky2:
|
||||
return "HandPinky2";
|
||||
case HandJointId.HandPinky3:
|
||||
return "HandPinky3";
|
||||
case HandJointId.HandThumbTip:
|
||||
return "HandThumbTip";
|
||||
case HandJointId.HandIndexTip:
|
||||
return "HandIndexTip";
|
||||
case HandJointId.HandMiddleTip:
|
||||
return "HandMiddleTip";
|
||||
case HandJointId.HandRingTip:
|
||||
return "HandRingTip";
|
||||
case HandJointId.HandPinkyTip:
|
||||
return "HandPinkyTip";
|
||||
default:
|
||||
return "HandUnknown";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 037bf294d05876e4c8dd96432f39faaa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Oculus.Interaction.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:2a230cb87a1d3ba4a98bdc0ddae76e6c",
|
||||
"GUID:f64c9ebcd7899c3448a08dc9f9ddbe30"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48af58ae5328ff048acacd924604a804
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Editor/PoseDetection.meta
Normal file
8
Assets/Oculus/Interaction/Editor/PoseDetection.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 275f3583fdaef334aa875c7f886a086c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,322 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.PoseDetection.Editor.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Oculus.Interaction.PoseDetection.Editor
|
||||
{
|
||||
namespace Model
|
||||
{
|
||||
public class FeatureConfigList
|
||||
{
|
||||
private readonly SerializedProperty _root;
|
||||
private uint _flags;
|
||||
private readonly IReadOnlyDictionary<int, FeatureDescription> _featureDescriptions;
|
||||
|
||||
public FeatureConfigList(SerializedProperty root,
|
||||
IReadOnlyDictionary<int, FeatureDescription> featureDescriptions)
|
||||
{
|
||||
Assert.IsNotNull(root);
|
||||
|
||||
_root = root;
|
||||
_flags = GetFlags(_root);
|
||||
_featureDescriptions = featureDescriptions;
|
||||
}
|
||||
|
||||
private uint GetFlags(SerializedProperty root)
|
||||
{
|
||||
if (!root.isArray)
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
uint flags = 0U;
|
||||
for (int i = 0; i < root.arraySize; i++)
|
||||
{
|
||||
var elemProp = root.GetArrayElementAtIndex(i);
|
||||
var featureProp = elemProp.FindPropertyRelative("_feature");
|
||||
flags |= 1U << featureProp.enumValueIndex;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public uint Flags
|
||||
{
|
||||
get => _flags;
|
||||
set
|
||||
{
|
||||
uint flagsToCreate = value;
|
||||
for (int i = 0; i < _root.arraySize;)
|
||||
{
|
||||
var elemProp = _root.GetArrayElementAtIndex(i);
|
||||
var featureProp = elemProp.FindPropertyRelative("_feature");
|
||||
uint propFlags = (1U << featureProp.enumValueIndex);
|
||||
if ((flagsToCreate & propFlags) == 0U)
|
||||
{
|
||||
// Feature is in list, but not flags... delete list entry.
|
||||
_root.DeleteArrayElementAtIndex(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Feature is in list, and in flags; remove from list of things we need to create.
|
||||
flagsToCreate &= ~propFlags;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Create missing elements.
|
||||
foreach (var feature in _featureDescriptions.Keys)
|
||||
{
|
||||
uint flags = 1U << feature;
|
||||
if ((flagsToCreate & flags) == 0U)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var lastIndex = _root.arraySize;
|
||||
_root.InsertArrayElementAtIndex(lastIndex);
|
||||
var model = new FeatureConfig(_root.GetArrayElementAtIndex(lastIndex));
|
||||
model.Feature = feature;
|
||||
model.FeatureState = _featureDescriptions[feature].FeatureStates[0].Id;
|
||||
}
|
||||
|
||||
_flags = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<FeatureConfig> ConfigModels
|
||||
{
|
||||
get
|
||||
{
|
||||
List<FeatureConfig> models = new List<FeatureConfig>(_root.arraySize);
|
||||
for (int i = 0; i < _root.arraySize; i++)
|
||||
{
|
||||
models.Add(new FeatureConfig(_root.GetArrayElementAtIndex(i)));
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FeatureConfig
|
||||
{
|
||||
SerializedProperty _modeProp;
|
||||
SerializedProperty _featureProp;
|
||||
SerializedProperty _stateProp;
|
||||
|
||||
public FeatureConfig(SerializedProperty root)
|
||||
{
|
||||
_modeProp = root.FindPropertyRelative("_mode");
|
||||
_featureProp = root.FindPropertyRelative("_feature");
|
||||
_stateProp = root.FindPropertyRelative("_state");
|
||||
}
|
||||
|
||||
public FeatureStateActiveMode Mode
|
||||
{
|
||||
get => (FeatureStateActiveMode)_modeProp.enumValueIndex;
|
||||
set
|
||||
{
|
||||
if (value != (FeatureStateActiveMode)_modeProp.enumValueIndex)
|
||||
{
|
||||
_modeProp.enumValueIndex = (int)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Feature
|
||||
{
|
||||
get => _featureProp.enumValueIndex;
|
||||
set
|
||||
{
|
||||
if (value != _featureProp.enumValueIndex)
|
||||
{
|
||||
_featureProp.enumValueIndex = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string FeatureState
|
||||
{
|
||||
get => _stateProp.stringValue;
|
||||
set
|
||||
{
|
||||
if (value != _stateProp.stringValue)
|
||||
{
|
||||
_stateProp.stringValue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class FeatureListPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
public float ControlLineHeight => EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; // = 18 + 2
|
||||
public float BottomMargin => EditorGUIUtility.standardVerticalSpacing * 2;
|
||||
private const float IndentSize = 16;
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var height = base.GetPropertyHeight(property, label); // includes height of first line
|
||||
|
||||
var model = CreateModel(property);
|
||||
if (property.isExpanded)
|
||||
{
|
||||
var controlCount = model.ConfigModels.Count();
|
||||
height += controlCount * ControlLineHeight;
|
||||
height += BottomMargin;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
public override bool CanCacheInspectorGUI(SerializedProperty property)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect drawerPos, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(drawerPos, label, property);
|
||||
|
||||
var oldIndent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
|
||||
var labelPos = new Rect(drawerPos)
|
||||
{
|
||||
width = EditorGUIUtility.labelWidth - drawerPos.x,
|
||||
height = EditorGUIUtility.singleLineHeight
|
||||
};
|
||||
|
||||
var model = CreateModel(property);
|
||||
property.isExpanded = EditorGUI.Foldout(labelPos, property.isExpanded, label, true);
|
||||
if (property.isExpanded)
|
||||
{
|
||||
RenderExpanded(drawerPos, model);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderCollapsed(drawerPos, model);
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel = oldIndent;
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private void RenderExpanded(Rect drawerPos, FeatureConfigList model) {
|
||||
Rect controlPos = new Rect(drawerPos.x, drawerPos.y, drawerPos.width,
|
||||
EditorGUIUtility.singleLineHeight);
|
||||
|
||||
var flagsPos = Indent(controlPos, EditorGUIUtility.labelWidth);
|
||||
var newFlags = EnumToFlags(EditorGUI.EnumFlagsField(flagsPos, FlagsToEnum(model.Flags)));
|
||||
if (newFlags != model.Flags)
|
||||
{
|
||||
model.Flags = newFlags;
|
||||
}
|
||||
|
||||
controlPos = Indent(controlPos, IndentSize);
|
||||
foreach (var configModel in model.ConfigModels)
|
||||
{
|
||||
controlPos.y += ControlLineHeight;
|
||||
|
||||
// Render the label
|
||||
float indent = 0f;
|
||||
var labelPos = Indent(controlPos, indent);
|
||||
labelPos.width = EditorGUIUtility.labelWidth - IndentSize;
|
||||
var featureName = FeatureToString(configModel.Feature);
|
||||
featureName = ObjectNames.NicifyVariableName(featureName);
|
||||
|
||||
EditorGUI.PrefixLabel(labelPos, new GUIContent(featureName));
|
||||
|
||||
// Render the mode dropdown
|
||||
indent += labelPos.width;
|
||||
var modePos = Indent(controlPos, indent);
|
||||
var allowedModes = GetAllowedModes(configModel);
|
||||
if (allowedModes.Length > 1)
|
||||
{
|
||||
modePos.width = 70;
|
||||
configModel.Mode =
|
||||
(FeatureStateActiveMode)EditorGUI.EnumPopup(modePos, configModel.Mode);
|
||||
}
|
||||
else if (allowedModes.Length == 1)
|
||||
{
|
||||
configModel.Mode = allowedModes[0];
|
||||
modePos.width = 15;
|
||||
EditorGUI.SelectableLabel(modePos,
|
||||
ObjectNames.NicifyVariableName(allowedModes[0] + ": "));
|
||||
}
|
||||
else
|
||||
{
|
||||
modePos.width = -2;
|
||||
}
|
||||
|
||||
// Render the state dropdown
|
||||
indent += modePos.width + 2;
|
||||
var statePos = Indent(controlPos, indent);
|
||||
var featureStates = GetStatesForFeature(configModel.Feature);
|
||||
string[] options = featureStates.Select(fs => fs.Name).ToArray();
|
||||
int selectedIndex = Array.FindIndex(featureStates, fs => fs.Id == configModel.FeatureState);
|
||||
int newSelectedIndex = EditorGUI.Popup(statePos, selectedIndex, options);
|
||||
if (newSelectedIndex != selectedIndex) {
|
||||
configModel.FeatureState = featureStates[newSelectedIndex].Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderCollapsed(Rect drawerPos, FeatureConfigList model)
|
||||
{
|
||||
Rect controlPos = drawerPos;
|
||||
controlPos.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
var valuePos = Indent(controlPos, EditorGUIUtility.labelWidth + 2);
|
||||
valuePos.width = drawerPos.width - valuePos.x;
|
||||
var flagsEnum = FlagsToEnum(model.Flags);
|
||||
var values = Enum.GetValues(flagsEnum.GetType())
|
||||
.Cast<Enum>()
|
||||
.Where(e => flagsEnum.HasFlag(e))
|
||||
.Select(e => e.ToString());
|
||||
EditorGUI.SelectableLabel(valuePos, String.Join(", ", values));
|
||||
}
|
||||
|
||||
private static Rect Indent(Rect position, float indentWidth)
|
||||
{
|
||||
return new Rect(position)
|
||||
{
|
||||
x = position.x + indentWidth,
|
||||
width = position.width - indentWidth
|
||||
};
|
||||
}
|
||||
|
||||
protected virtual FeatureStateActiveMode[] GetAllowedModes(FeatureConfig model)
|
||||
{
|
||||
var statesForFeature = GetStatesForFeature(model.Feature);
|
||||
if (statesForFeature.Length > 2)
|
||||
return (FeatureStateActiveMode[])Enum.GetValues(typeof(FeatureStateActiveMode));
|
||||
else
|
||||
return new[] { FeatureStateActiveMode.Is };
|
||||
}
|
||||
|
||||
protected abstract Enum FlagsToEnum(uint flags);
|
||||
protected abstract uint EnumToFlags(Enum flags);
|
||||
protected abstract string FeatureToString(int featureIdx);
|
||||
protected abstract FeatureStateDescription[] GetStatesForFeature(int featureIdx);
|
||||
protected abstract Model.FeatureConfigList CreateModel(SerializedProperty property);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39acc9895ae6408898722a714edbe5ce
|
||||
timeCreated: 1631575366
|
||||
@@ -0,0 +1,425 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Oculus.Interaction.PoseDetection.Editor
|
||||
{
|
||||
public abstract class FeatureStateThresholdsEditor<TFeature> : UnityEditor.Editor
|
||||
where TFeature : unmanaged, Enum
|
||||
{
|
||||
#region static helpers
|
||||
public static readonly TFeature[] FeatureEnumValues = (TFeature[])Enum.GetValues(typeof(TFeature));
|
||||
public static TFeature IntToFeature(int value)
|
||||
{
|
||||
return FeatureEnumValues[value];
|
||||
}
|
||||
|
||||
public static int FeatureToInt(TFeature feature)
|
||||
{
|
||||
for (int i = 0; i < FeatureEnumValues.Length; i++)
|
||||
{
|
||||
TFeature enumVal = FeatureEnumValues[i];
|
||||
if (enumVal.Equals(feature))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Model Classes
|
||||
public class FeatureStateThresholdsModel
|
||||
{
|
||||
private readonly SerializedProperty _thresholdsProp;
|
||||
private readonly SerializedProperty _featureProp;
|
||||
public FeatureStateThresholdsModel(SerializedProperty self)
|
||||
{
|
||||
_featureProp = self.FindPropertyRelative("_feature");
|
||||
_thresholdsProp = self.FindPropertyRelative("_thresholds");
|
||||
Assert.IsNotNull(_featureProp);
|
||||
Assert.IsNotNull(_thresholdsProp);
|
||||
}
|
||||
|
||||
public TFeature Feature
|
||||
{
|
||||
get => IntToFeature(_featureProp.enumValueIndex);
|
||||
set => _featureProp.enumValueIndex = FeatureToInt(value);
|
||||
}
|
||||
|
||||
public SerializedProperty ThresholdsProp => _thresholdsProp;
|
||||
}
|
||||
|
||||
public class FeatureStateThresholdModel
|
||||
{
|
||||
private readonly SerializedProperty _thresholdMidpointProp;
|
||||
private readonly SerializedProperty _thresholdWidthProp;
|
||||
private readonly SerializedProperty _firstStateProp;
|
||||
private readonly SerializedProperty _secondStateProp;
|
||||
|
||||
public FeatureStateThresholdModel(SerializedProperty self)
|
||||
{
|
||||
_thresholdMidpointProp = self.FindPropertyRelative("_thresholdMidpoint");
|
||||
_thresholdWidthProp = self.FindPropertyRelative("_thresholdWidth");
|
||||
_firstStateProp = self.FindPropertyRelative("_firstState");
|
||||
_secondStateProp = self.FindPropertyRelative("_secondState");
|
||||
Assert.IsNotNull(_thresholdMidpointProp);
|
||||
Assert.IsNotNull(_thresholdWidthProp);
|
||||
Assert.IsNotNull(_firstStateProp);
|
||||
Assert.IsNotNull(_secondStateProp);
|
||||
}
|
||||
|
||||
public float ThresholdMidpoint{
|
||||
get => _thresholdMidpointProp.floatValue;
|
||||
set { _thresholdMidpointProp.floatValue = value; }
|
||||
}
|
||||
public float ThresholdWidth {
|
||||
get => _thresholdWidthProp.floatValue;
|
||||
set { _thresholdWidthProp.floatValue = value; }
|
||||
}
|
||||
public string FirstStateId {
|
||||
get => _firstStateProp.stringValue;
|
||||
set => _firstStateProp.stringValue = value;
|
||||
}
|
||||
public string SecondStateId {
|
||||
get => _secondStateProp.stringValue;
|
||||
set => _secondStateProp.stringValue = value;
|
||||
}
|
||||
|
||||
public float ToFirstWhenBelow => ThresholdMidpoint - ThresholdWidth * 0.5f;
|
||||
public float ToSecondWhenAbove => ThresholdMidpoint + ThresholdWidth * 0.5f;
|
||||
}
|
||||
#endregion
|
||||
|
||||
SerializedProperty _rootProperty;
|
||||
SerializedProperty _minTimeInStateProp;
|
||||
|
||||
private readonly bool[] _featureVisible = new bool [FeatureEnumValues.Length];
|
||||
|
||||
private readonly Color _visStateColorPro = new Color32(194, 194, 194, 255);
|
||||
private readonly Color _visStateColorLight = new Color32(56, 56, 56, 255);
|
||||
private readonly Color _visTransitionColorPro = new Color32(80, 80, 80, 255);
|
||||
private readonly Color _visTransitionColorLight = new Color32(160, 160, 160, 255);
|
||||
private readonly Color _visBorderColor = new Color32(0,0,0,255);
|
||||
private const float _visHeight = 20.0f;
|
||||
private const float _visMargin = 10.0f;
|
||||
|
||||
private IReadOnlyDictionary<TFeature, FeatureDescription> _featureDescriptions;
|
||||
|
||||
protected abstract IReadOnlyDictionary<TFeature, FeatureDescription> CreateFeatureDescriptions();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (_featureDescriptions == null)
|
||||
{
|
||||
_featureDescriptions = CreateFeatureDescriptions();
|
||||
}
|
||||
if (_featureDescriptions.Count != FeatureEnumValues.Length)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"CreateFeatureDescriptions() must return one key for each enum value.");
|
||||
}
|
||||
|
||||
_rootProperty = serializedObject.FindProperty("_featureThresholds");
|
||||
_minTimeInStateProp = serializedObject.FindProperty("_minTimeInState");
|
||||
|
||||
for (var index = 0; index < _featureVisible.Length; index++)
|
||||
{
|
||||
_featureVisible[index] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (_rootProperty == null || !_rootProperty.isArray || _minTimeInStateProp == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("All Features", EditorStyles.whiteLargeLabel);
|
||||
EditorGUILayout.PropertyField(_minTimeInStateProp);
|
||||
|
||||
GUILayout.Space(10);
|
||||
EditorGUILayout.LabelField("Per Feature", EditorStyles.whiteLargeLabel);
|
||||
foreach (TFeature feature in FeatureEnumValues)
|
||||
{
|
||||
FeatureStateThresholdsModel foundFeatureProp = null;
|
||||
for (int i = 0; i < _rootProperty.arraySize; ++i)
|
||||
{
|
||||
var featureThresholdsProp =
|
||||
new FeatureStateThresholdsModel(
|
||||
_rootProperty.GetArrayElementAtIndex(i));
|
||||
|
||||
if (featureThresholdsProp.Feature.Equals(feature))
|
||||
{
|
||||
foundFeatureProp = featureThresholdsProp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ref bool isVisible = ref _featureVisible[FeatureToInt(feature)];
|
||||
isVisible = EditorGUILayout.BeginFoldoutHeaderGroup(isVisible, $"{feature} Thresholds");
|
||||
if (!isVisible)
|
||||
{
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsFeatureThresholdsValid(foundFeatureProp))
|
||||
{
|
||||
if (GUILayout.Button("Create Config"))
|
||||
{
|
||||
foundFeatureProp = CreateFeatureStateConfig(feature);
|
||||
}
|
||||
else
|
||||
{
|
||||
foundFeatureProp = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundFeatureProp != null)
|
||||
{
|
||||
RenderFeatureStates(feature, foundFeatureProp);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private FeatureStateThresholdsModel CreateFeatureStateConfig(
|
||||
TFeature feature)
|
||||
{
|
||||
// Delete any old invalid configs for this feature.
|
||||
for (int i = 0; i < _rootProperty.arraySize;)
|
||||
{
|
||||
var model =
|
||||
new FeatureStateThresholdsModel(
|
||||
_rootProperty.GetArrayElementAtIndex(i));
|
||||
if (model.Feature.Equals(feature))
|
||||
{
|
||||
_rootProperty.DeleteArrayElementAtIndex(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new config
|
||||
int insertIndex = _rootProperty.arraySize;
|
||||
_rootProperty.InsertArrayElementAtIndex(insertIndex);
|
||||
var featureStateThresholds = new FeatureStateThresholdsModel(
|
||||
_rootProperty.GetArrayElementAtIndex(insertIndex))
|
||||
{
|
||||
Feature = feature
|
||||
};
|
||||
|
||||
// Set initial state
|
||||
ResetFeatureStates(featureStateThresholds);
|
||||
|
||||
return featureStateThresholds;
|
||||
}
|
||||
|
||||
private void ResetFeatureStates(FeatureStateThresholdsModel foundFeatureProp)
|
||||
{
|
||||
var states = _featureDescriptions[foundFeatureProp.Feature].FeatureStates;
|
||||
|
||||
var thresholdsArrayProp = foundFeatureProp.ThresholdsProp;
|
||||
foundFeatureProp.ThresholdsProp.arraySize = states.Length - 1;
|
||||
var featureDescription = _featureDescriptions[foundFeatureProp.Feature];
|
||||
float minExpectedValue = featureDescription.MinValueHint;
|
||||
float maxExpectedValue = featureDescription.MaxValueHint;
|
||||
|
||||
float range = maxExpectedValue - minExpectedValue;
|
||||
float initialWidth = range * 0.075f;
|
||||
float numStatesMultiplier = range / (states.Length);
|
||||
for (int stateIdx = 0; stateIdx < states.Length - 1; ++stateIdx)
|
||||
{
|
||||
var featureState = states[stateIdx];
|
||||
FeatureStateThresholdModel model = new FeatureStateThresholdModel(
|
||||
thresholdsArrayProp.GetArrayElementAtIndex(stateIdx));
|
||||
model.ThresholdMidpoint = minExpectedValue + (stateIdx + 1) * numStatesMultiplier;
|
||||
model.ThresholdWidth = initialWidth;
|
||||
model.FirstStateId = featureState.Id;
|
||||
model.SecondStateId = states[stateIdx + 1].Id;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsFeatureThresholdsValid(FeatureStateThresholdsModel foundFeatureModel)
|
||||
{
|
||||
if (foundFeatureModel == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var states = _featureDescriptions[foundFeatureModel.Feature].FeatureStates;
|
||||
if (foundFeatureModel.ThresholdsProp.arraySize != states.Length - 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var firstStateIdx = 0; firstStateIdx < states.Length - 1; firstStateIdx++)
|
||||
{
|
||||
var model = new FeatureStateThresholdModel(
|
||||
foundFeatureModel.ThresholdsProp.GetArrayElementAtIndex(firstStateIdx));
|
||||
if (states[firstStateIdx].Id != model.FirstStateId ||
|
||||
states[firstStateIdx + 1].Id != model.SecondStateId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RenderFeatureStates(TFeature feature, FeatureStateThresholdsModel featureStateThresholdsModel)
|
||||
{
|
||||
FeatureDescription featureDescription = _featureDescriptions[feature];
|
||||
|
||||
// Indent block
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
RenderFeatureDescription(featureDescription);
|
||||
|
||||
var states = _featureDescriptions[feature].FeatureStates;
|
||||
float minVal = float.MaxValue;
|
||||
float maxVal = float.MinValue;
|
||||
bool overlappingValues = false;
|
||||
float thresholdMaxWidth =
|
||||
featureDescription.MaxValueHint - featureDescription.MinValueHint;
|
||||
for (var firstStateIdx = 0; firstStateIdx < states.Length - 1; firstStateIdx++)
|
||||
{
|
||||
var firstState = states[firstStateIdx];
|
||||
var secondState = states[firstStateIdx + 1];
|
||||
EditorGUILayout.LabelField($"{firstState.Name} ⟷ {secondState.Name}", EditorStyles.label);
|
||||
|
||||
// Indent block
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
var model = new FeatureStateThresholdModel(
|
||||
featureStateThresholdsModel.ThresholdsProp.GetArrayElementAtIndex(firstStateIdx));
|
||||
|
||||
if (model.ToFirstWhenBelow <= maxVal || model.ToSecondWhenAbove <= maxVal)
|
||||
{
|
||||
overlappingValues = true;
|
||||
}
|
||||
|
||||
float thresholdMidpoint = model.ThresholdMidpoint;
|
||||
float thresholdWidth = model.ThresholdWidth;
|
||||
|
||||
float newMidpoint = EditorGUILayout.FloatField("Midpoint", thresholdMidpoint);
|
||||
float newWidth = EditorGUILayout.Slider("Width", thresholdWidth, 0.0f,
|
||||
thresholdMaxWidth);
|
||||
|
||||
if (Math.Abs(newMidpoint - thresholdMidpoint) > float.Epsilon ||
|
||||
Math.Abs(newWidth - thresholdWidth) > float.Epsilon)
|
||||
{
|
||||
// save new values.
|
||||
model.ThresholdMidpoint = newMidpoint;
|
||||
model.ThresholdWidth = newWidth;
|
||||
}
|
||||
|
||||
minVal = Mathf.Min(minVal, model.ToFirstWhenBelow);
|
||||
maxVal = Mathf.Max(maxVal, model.ToSecondWhenAbove);
|
||||
}
|
||||
}
|
||||
|
||||
float range = maxVal - minVal;
|
||||
if (range <= 0.0f)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Invalid threshold values", MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (overlappingValues)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Overlapping threshold values",
|
||||
MessageType.Warning);
|
||||
}
|
||||
|
||||
RenderFeatureStateGraphic(featureStateThresholdsModel,
|
||||
Mathf.Min(featureDescription.MinValueHint, minVal),
|
||||
Mathf.Max(featureDescription.MaxValueHint, maxVal));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderFeatureDescription(FeatureDescription featureDescription)
|
||||
{
|
||||
if (!String.IsNullOrWhiteSpace(featureDescription.ShortDescription))
|
||||
{
|
||||
EditorGUILayout.HelpBox(featureDescription.ShortDescription, MessageType.Info);
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField(
|
||||
new GUIContent("Expected value range", featureDescription.Description),
|
||||
new GUIContent($"[{featureDescription.MinValueHint}, {featureDescription.MaxValueHint}]"));
|
||||
}
|
||||
|
||||
private void RenderFeatureStateGraphic(FeatureStateThresholdsModel prop, float minVal,
|
||||
float maxVal)
|
||||
{
|
||||
var lastRect = GUILayoutUtility.GetLastRect();
|
||||
float xOffset = lastRect.xMin + _visMargin;
|
||||
float widgetWidth = lastRect.width - _visMargin;
|
||||
|
||||
GUILayout.Space(_visHeight + _visMargin * 2);
|
||||
|
||||
EditorGUI.DrawRect(
|
||||
new Rect(xOffset - 1, lastRect.yMax + _visMargin - 1, widgetWidth + 2.0f,
|
||||
_visHeight + 2.0f), _visBorderColor);
|
||||
|
||||
float range = maxVal - minVal;
|
||||
Color stateColor = EditorGUIUtility.isProSkin
|
||||
? _visStateColorPro
|
||||
: _visStateColorLight;
|
||||
Color transitionColor = EditorGUIUtility.isProSkin
|
||||
? _visTransitionColorPro
|
||||
: _visTransitionColorLight;
|
||||
for (var firstStateIdx = 0;
|
||||
firstStateIdx < prop.ThresholdsProp.arraySize;
|
||||
firstStateIdx++)
|
||||
{
|
||||
var model = new FeatureStateThresholdModel(
|
||||
prop.ThresholdsProp.GetArrayElementAtIndex(firstStateIdx));
|
||||
|
||||
float firstPc = ((model.ToFirstWhenBelow - minVal)) / range;
|
||||
EditorGUI.DrawRect(
|
||||
new Rect(Mathf.Floor(xOffset), lastRect.yMax + _visMargin,
|
||||
Mathf.Ceil(widgetWidth * firstPc), _visHeight), stateColor);
|
||||
xOffset += widgetWidth * firstPc;
|
||||
minVal = model.ToFirstWhenBelow;
|
||||
|
||||
float secondPc = ((model.ToSecondWhenAbove - minVal)) / range;
|
||||
EditorGUI.DrawRect(
|
||||
new Rect(Mathf.Floor(xOffset), lastRect.yMax + _visMargin,
|
||||
Mathf.Ceil(widgetWidth * secondPc), _visHeight), transitionColor);
|
||||
xOffset += widgetWidth * secondPc;
|
||||
minVal = model.ToSecondWhenAbove;
|
||||
}
|
||||
|
||||
float lastPc = ((maxVal - minVal)) / range;
|
||||
EditorGUI.DrawRect(
|
||||
new Rect(Mathf.Floor(xOffset), lastRect.yMax + _visMargin,
|
||||
Mathf.Ceil(widgetWidth * lastPc), _visHeight), stateColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 536a9cf65c7544ab9e4051eac951baa7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.PoseDetection.Editor.Model;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Oculus.Interaction.PoseDetection.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(ShapeRecognizer.FingerFeatureConfigList))]
|
||||
public class FingerFeatureListPropertyDrawer : FeatureListPropertyDrawer
|
||||
{
|
||||
[Flags]
|
||||
enum FingerFeatureFlags
|
||||
{
|
||||
Curl = 1 << 0,
|
||||
Flexion = 1 << 1,
|
||||
Abduction = 1 << 2,
|
||||
Opposition = 1 << 3
|
||||
}
|
||||
|
||||
protected override Enum FlagsToEnum(uint flags)
|
||||
{
|
||||
return (FingerFeatureFlags)flags;
|
||||
}
|
||||
|
||||
protected override uint EnumToFlags(Enum flags)
|
||||
{
|
||||
return (uint)(FingerFeatureFlags)flags;
|
||||
}
|
||||
|
||||
protected override string FeatureToString(int featureIdx)
|
||||
{
|
||||
return ((FingerFeature)featureIdx).ToString();
|
||||
}
|
||||
|
||||
protected override FeatureStateDescription[] GetStatesForFeature(int featureIdx)
|
||||
{
|
||||
return FingerFeatureProperties.FeatureDescriptions[(FingerFeature)featureIdx].FeatureStates;
|
||||
}
|
||||
|
||||
protected override FeatureConfigList CreateModel(SerializedProperty property)
|
||||
{
|
||||
var descriptions = FingerFeatureProperties.FeatureDescriptions
|
||||
.ToDictionary(p => (int)p.Key, p => p.Value);
|
||||
|
||||
return new FeatureConfigList(property.FindPropertyRelative("_value"),
|
||||
descriptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dffceaad44e34343a4e55875976ac097
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,27 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Oculus.Interaction.PoseDetection.Editor
|
||||
{
|
||||
[CustomEditor(typeof(FingerFeatureStateThresholds))]
|
||||
public class FingerFeatureStateThresholdsEditor
|
||||
: FeatureStateThresholdsEditor<FingerFeature>
|
||||
{
|
||||
protected override IReadOnlyDictionary<FingerFeature, FeatureDescription> CreateFeatureDescriptions()
|
||||
{
|
||||
return FingerFeatureProperties.FeatureDescriptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a4a7445af8149e0887018ba0cba6abb
|
||||
timeCreated: 1627935350
|
||||
@@ -0,0 +1,66 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.PoseDetection.Editor.Model;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Oculus.Interaction.PoseDetection.Editor
|
||||
{
|
||||
[Flags]
|
||||
public enum TransformFeatureFlags
|
||||
{
|
||||
WristUp = 1 << 0,
|
||||
WristDown = 1 << 1,
|
||||
PalmDown = 1 << 2,
|
||||
PalmUp = 1 << 3,
|
||||
PalmTowardsFace = 1 << 4,
|
||||
PalmAwayFromFace = 1 << 5,
|
||||
FingersUp = 1 << 6,
|
||||
FingersDown = 1 << 7,
|
||||
PinchClear = 1 << 8
|
||||
}
|
||||
|
||||
[CustomPropertyDrawer(typeof(TransformFeatureConfigList))]
|
||||
public class TransformConfigEditor : FeatureListPropertyDrawer
|
||||
{
|
||||
protected override Enum FlagsToEnum(uint flags)
|
||||
{
|
||||
return (TransformFeatureFlags)flags;
|
||||
}
|
||||
|
||||
protected override uint EnumToFlags(Enum flags)
|
||||
{
|
||||
return (uint)(TransformFeatureFlags)flags;
|
||||
}
|
||||
|
||||
protected override string FeatureToString(int featureIdx)
|
||||
{
|
||||
return ((TransformFeature)featureIdx).ToString();
|
||||
}
|
||||
|
||||
protected override FeatureStateDescription[] GetStatesForFeature(int featureIdx)
|
||||
{
|
||||
return TransformFeatureProperties.FeatureDescriptions[(TransformFeature)featureIdx].FeatureStates;
|
||||
}
|
||||
|
||||
protected override FeatureConfigList CreateModel(SerializedProperty property)
|
||||
{
|
||||
var descriptions = TransformFeatureProperties.FeatureDescriptions
|
||||
.ToDictionary(p => (int)p.Key, p => p.Value);
|
||||
|
||||
return new FeatureConfigList(property.FindPropertyRelative("_values"),
|
||||
descriptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca473a2dca4a42988bd13c46f6ed077f
|
||||
timeCreated: 1631569404
|
||||
@@ -0,0 +1,27 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Oculus.Interaction.PoseDetection.Editor
|
||||
{
|
||||
[CustomEditor(typeof(TransformFeatureStateThresholds))]
|
||||
class TransformFeatureStateThresholdModel
|
||||
: FeatureStateThresholdsEditor<TransformFeature>
|
||||
{
|
||||
protected override IReadOnlyDictionary<TransformFeature, FeatureDescription> CreateFeatureDescriptions()
|
||||
{
|
||||
return TransformFeatureProperties.FeatureDescriptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 195af56ffbd76364e83ff93de249a25a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Editor/Selection.meta
Normal file
8
Assets/Oculus/Interaction/Editor/Selection.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f157e4f37a940d40ac671a2d9df8e2e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4138c426cc3b2f46aadd6898a87f6e9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,93 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(ControllerOffset))]
|
||||
public class ControllerOffsetEditor : UnityEditor.Editor
|
||||
{
|
||||
private Transform _gripPoint;
|
||||
private ControllerOffset _controllerOffset;
|
||||
|
||||
private SerializedProperty _offsetPositionProperty;
|
||||
private SerializedProperty _rotationProperty;
|
||||
|
||||
private Pose _cachedPose;
|
||||
|
||||
private const float THICKNESS = 2f;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_controllerOffset = target as ControllerOffset;
|
||||
_offsetPositionProperty = serializedObject.FindProperty("_offset");
|
||||
_rotationProperty = serializedObject.FindProperty("_rotation");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
Transform point = EditorGUILayout.ObjectField("Optional Calculate Offset To", _gripPoint, typeof(Transform), true) as Transform;
|
||||
if (point != _gripPoint)
|
||||
{
|
||||
_gripPoint = point;
|
||||
if (_gripPoint != null)
|
||||
{
|
||||
Pose offset = _controllerOffset.transform.RelativeOffset(_gripPoint);
|
||||
_rotationProperty.quaternionValue = offset.rotation;
|
||||
_offsetPositionProperty.vector3Value = offset.position;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
GetEditorOffset(ref _cachedPose);
|
||||
Pose wristPose = _controllerOffset.transform.GetPose();
|
||||
_cachedPose.Postmultiply(wristPose);
|
||||
DrawAxis(_cachedPose);
|
||||
}
|
||||
|
||||
private void DrawAxis(in Pose pose)
|
||||
{
|
||||
float scale = HandleUtility.GetHandleSize(pose.position);
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
Handles.color = Color.red;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.right * scale, THICKNESS);
|
||||
Handles.color = Color.green;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.up * scale, THICKNESS);
|
||||
Handles.color = Color.blue;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.forward * scale, THICKNESS);
|
||||
#else
|
||||
Handles.color = Color.red;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.right * scale);
|
||||
Handles.color = Color.green;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.up * scale);
|
||||
Handles.color = Color.blue;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.forward * scale);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void GetEditorOffset(ref Pose pose)
|
||||
{
|
||||
pose.position = _offsetPositionProperty.vector3Value;
|
||||
pose.rotation = _rotationProperty.quaternionValue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65515f2ba0e41684cbc782bcd3460a0a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Editor/Selection/Hands.meta
Normal file
8
Assets/Oculus/Interaction/Editor/Selection/Hands.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 288b243a05b123a4c80d776930345735
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,107 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.Input;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Interaction.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(HandWristOffset))]
|
||||
public class HandWristOffsetEditor : UnityEditor.Editor
|
||||
{
|
||||
private Transform _gripPoint;
|
||||
private HandWristOffset _wristOffset;
|
||||
|
||||
private SerializedProperty _offsetPositionProperty;
|
||||
private SerializedProperty _rotationProperty;
|
||||
private SerializedProperty _handProperty;
|
||||
|
||||
private Pose _cachedPose;
|
||||
|
||||
private const float THICKNESS = 2f;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_wristOffset = target as HandWristOffset;
|
||||
|
||||
_offsetPositionProperty = serializedObject.FindProperty("_offset");
|
||||
_rotationProperty = serializedObject.FindProperty("_rotation");
|
||||
_handProperty = serializedObject.FindProperty("_hand");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
Transform point = EditorGUILayout.ObjectField("Optional Calculate Offset To", _gripPoint, typeof(Transform), true) as Transform;
|
||||
if (point != _gripPoint)
|
||||
{
|
||||
_gripPoint = point;
|
||||
if (_gripPoint != null)
|
||||
{
|
||||
Pose offset = _wristOffset.transform.RelativeOffset(_gripPoint);
|
||||
_rotationProperty.quaternionValue = FromOVRHandDataSource.WristFixupRotation * offset.rotation;
|
||||
_offsetPositionProperty.vector3Value = FromOVRHandDataSource.WristFixupRotation * offset.position;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
GetEditorOffset(ref _cachedPose);
|
||||
Pose wristPose = _wristOffset.transform.GetPose();
|
||||
wristPose.rotation = wristPose.rotation * FromOVRHandDataSource.WristFixupRotation;
|
||||
_cachedPose.Postmultiply(wristPose);
|
||||
DrawAxis(_cachedPose);
|
||||
}
|
||||
|
||||
private void DrawAxis(in Pose pose)
|
||||
{
|
||||
float scale = HandleUtility.GetHandleSize(pose.position);
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
Handles.color = Color.red;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.right * scale, THICKNESS);
|
||||
Handles.color = Color.green;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.up * scale, THICKNESS);
|
||||
Handles.color = Color.blue;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.forward * scale, THICKNESS);
|
||||
#else
|
||||
Handles.color = Color.red;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.right * scale);
|
||||
Handles.color = Color.green;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.up * scale);
|
||||
Handles.color = Color.blue;
|
||||
Handles.DrawLine(pose.position, pose.position + pose.forward * scale);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void GetEditorOffset(ref Pose pose)
|
||||
{
|
||||
pose.position = _offsetPositionProperty.vector3Value;
|
||||
pose.rotation = _rotationProperty.quaternionValue;
|
||||
|
||||
IHand hand = _handProperty?.objectReferenceValue as IHand;
|
||||
if (hand != null)
|
||||
{
|
||||
if (hand.Handedness == Handedness.Left)
|
||||
{
|
||||
pose.position = -pose.position;
|
||||
pose.rotation = Quaternion.Inverse(pose.rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44f030f288c72ff40a4b63d93aa1bd67
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Editor/UnityCanvas.meta
Normal file
8
Assets/Oculus/Interaction/Editor/UnityCanvas.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8653f05b6623448419a2c38aebc4a421
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,358 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.Editor;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEditor;
|
||||
|
||||
using props = Oculus.Interaction.UnityCanvas.CanvasRenderTexture.Properties;
|
||||
|
||||
namespace Oculus.Interaction.UnityCanvas.Editor
|
||||
{
|
||||
[CustomEditor(typeof(CanvasRenderTexture))]
|
||||
public class CanvasRenderTextureEditor : EditorBase
|
||||
{
|
||||
private const string DEFAULT_UI_NAME = "UI/Default";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private Func<bool> _isOverlayMode = () => false;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
var renderingMode = serializedObject.FindProperty(props.RenderingMode);
|
||||
_isOverlayMode = () => renderingMode.intValue == (int)RenderingMode.OVR_Overlay ||
|
||||
renderingMode.intValue == (int)RenderingMode.OVR_Underlay;
|
||||
|
||||
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)
|
||||
{
|
||||
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, p =>
|
||||
{
|
||||
var driveMode = serializedObject.FindProperty(props.DimensionDriveMode);
|
||||
if (driveMode.intValue == (int)CanvasRenderTexture.DriveMode.Auto)
|
||||
{
|
||||
EditorGUILayout.PropertyField(p);
|
||||
}
|
||||
});
|
||||
|
||||
Draw(props.GenerateMips, p =>
|
||||
{
|
||||
if (!_isOverlayMode())
|
||||
{
|
||||
EditorGUILayout.PropertyField(p);
|
||||
}
|
||||
});
|
||||
|
||||
Draw(props.UseAlphaToMask, props.AlphaCutoutThreshold, (maskProp, cutoutProp) =>
|
||||
{
|
||||
if (renderingMode.intValue == (int)RenderingMode.AlphaCutout)
|
||||
{
|
||||
EditorGUILayout.PropertyField(maskProp);
|
||||
|
||||
if (maskProp.boolValue == false)
|
||||
{
|
||||
EditorGUILayout.PropertyField(cutoutProp);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Draw(props.UseExpensiveSuperSample, props.EmulateWhileInEditor, props.DoUnderlayAA, (sampleProp, emulateProp, aaProp) =>
|
||||
{
|
||||
if (_isOverlayMode())
|
||||
{
|
||||
EditorGUILayout.PropertyField(sampleProp);
|
||||
|
||||
if (renderingMode.intValue == (int)RenderingMode.OVR_Underlay)
|
||||
{
|
||||
EditorGUILayout.PropertyField(aaProp);
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(emulateProp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnBeforeInspector()
|
||||
{
|
||||
base.OnBeforeInspector();
|
||||
|
||||
bool isEmpty;
|
||||
|
||||
AutoFix(AutoFixIsUsingScreenSpaceCanvas(), AutoFixSetToWorldSpaceCamera, "The OverlayRenderer only supports Canvases that are set to World Space.");
|
||||
AutoFix(AutoFixIsUsingDefaultUIShader(), AutoFixAssignOverlayShaderToGraphics, "Some Canvas Graphics are using the default UI shader, which has rendering issues when combined with Overlay rendering.");
|
||||
|
||||
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 AutoFixIsUsingDefaultUIShader()
|
||||
{
|
||||
if (UnityInfo.Version_2020_3_Or_Newer())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target.DefaultUIMaterial == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
target.GetComponentsInChildren(_tmpGraphics);
|
||||
foreach (var graphic in _tmpGraphics)
|
||||
{
|
||||
if (AutoFixIsExceptionCaseForDefaultUIShader(graphic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Material mat = graphic.material;
|
||||
if (mat == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Shader shader = mat.shader;
|
||||
if (shader == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shader.name == DEFAULT_UI_NAME)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void AutoFixAssignOverlayShaderToGraphics()
|
||||
{
|
||||
target.GetComponentsInChildren(_tmpGraphics);
|
||||
foreach (var graphic in _tmpGraphics)
|
||||
{
|
||||
if (AutoFixIsExceptionCaseForDefaultUIShader(graphic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Material mat = graphic.material;
|
||||
if (mat == null)
|
||||
{
|
||||
Undo.RecordObject(graphic, "Set Graphic Material");
|
||||
graphic.material = target.DefaultUIMaterial;
|
||||
EditorUtility.SetDirty(graphic);
|
||||
continue;
|
||||
}
|
||||
|
||||
Shader shader = mat.shader;
|
||||
if (shader == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shader.name == DEFAULT_UI_NAME)
|
||||
{
|
||||
Undo.RecordObject(graphic, "Set Graphic Material");
|
||||
graphic.material = target.DefaultUIMaterial;
|
||||
EditorUtility.SetDirty(graphic);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool AutoFixIsExceptionCaseForDefaultUIShader(Graphic graphic)
|
||||
{
|
||||
//Hardcoded edge-cases
|
||||
return graphic.GetType().Namespace == "TMPro" ||
|
||||
graphic.GetType().Name == "OCText";
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
target.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 maskedLayers = AutoFixGetMaskedLayers();
|
||||
var targetLayer = maskedLayers.FirstOrDefault();
|
||||
|
||||
target.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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34148f8fe2640204181a843e9af84fdd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Editor/Utils.meta
Normal file
8
Assets/Oculus/Interaction/Editor/Utils.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea40da6a90737ec4ba74d5b2a2aad178
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
466
Assets/Oculus/Interaction/Editor/Utils/HandAnimatorWizard.cs
Normal file
466
Assets/Oculus/Interaction/Editor/Utils/HandAnimatorWizard.cs
Normal file
@@ -0,0 +1,466 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using Oculus.Interaction.Input;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Oculus.Interaction.HandPosing.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// This wizard helps creating a set of fixed Animation Clips using HandTracking
|
||||
/// to be used in a skinned synthetic hand with an Animator.
|
||||
/// Assign a HandSkeletonVisual and click the buttons as you perform the relevant
|
||||
/// poses with your tracked hand. The output will be an Animator that can be directly
|
||||
/// used in a Skinned hand. Once you are done you can automatically create the opposite
|
||||
/// hand data by providing the strings internally used for differentiating the left and
|
||||
/// right transforms. (typically _l_ and _r_)
|
||||
/// Works great in conjunction with FromOVRControllerHandData.cs
|
||||
/// </summary>
|
||||
public class HandAnimatorWizard : ScriptableWizard
|
||||
{
|
||||
[SerializeField]
|
||||
private HandVisual _handVisual;
|
||||
[SerializeField]
|
||||
private string _folder = "GeneratedAnimations";
|
||||
[SerializeField]
|
||||
private string _controllerName = "HandController";
|
||||
|
||||
[Space]
|
||||
[InspectorButton("RecordHandFist")]
|
||||
[SerializeField]
|
||||
private string _recordHandFist;
|
||||
[SerializeField]
|
||||
private AnimationClip _handFist;
|
||||
|
||||
[InspectorButton("RecordHand3qtrFist")]
|
||||
[SerializeField]
|
||||
private string _recordHand3qtrFist;
|
||||
[SerializeField]
|
||||
private AnimationClip _hand3qtrFist;
|
||||
|
||||
[InspectorButton("RecordHandMidFist")]
|
||||
[SerializeField]
|
||||
private string _recordHandMidFist;
|
||||
[SerializeField]
|
||||
private AnimationClip _handMidFist;
|
||||
|
||||
[InspectorButton("RecordHandPinch")]
|
||||
[SerializeField]
|
||||
private string _recordHandPinch;
|
||||
[SerializeField]
|
||||
private AnimationClip _handPinch;
|
||||
|
||||
[InspectorButton("RecordHandCap")]
|
||||
[SerializeField]
|
||||
private string _recordHandCap;
|
||||
[SerializeField]
|
||||
private AnimationClip _handCap;
|
||||
|
||||
[InspectorButton("RecordThumbUp")]
|
||||
[SerializeField]
|
||||
private string _recordThumbUp;
|
||||
[SerializeField]
|
||||
private AnimationClip _thumbUp;
|
||||
|
||||
[InspectorButton("RecordIndexPoint")]
|
||||
[SerializeField]
|
||||
private string _recordIndexPoint;
|
||||
[SerializeField]
|
||||
private AnimationClip _indexPoint;
|
||||
|
||||
[Space]
|
||||
[InspectorButton("GenerateMasks")]
|
||||
[SerializeField]
|
||||
private string _generateMasks;
|
||||
[SerializeField]
|
||||
private AvatarMask _indexMask;
|
||||
[SerializeField]
|
||||
private AvatarMask _thumbMask;
|
||||
|
||||
[Space]
|
||||
[InspectorButton("GenerateAnimatorAsset")]
|
||||
[SerializeField]
|
||||
private string _generateAnimator;
|
||||
|
||||
[Space(40f)]
|
||||
[SerializeField]
|
||||
private string _handLeftPrefix = "_l_";
|
||||
[SerializeField]
|
||||
private string _handRightPrefix = "_r_";
|
||||
[InspectorButton("GenerateMirrorAnimatorAsset")]
|
||||
[SerializeField]
|
||||
private string _generateMirrorAnimator;
|
||||
|
||||
private Transform Root => _handVisual.Joints[0].parent;
|
||||
|
||||
private static readonly List<HandJointId> INDEX_MASK = new List<HandJointId>()
|
||||
{
|
||||
HandJointId.HandIndex1,
|
||||
HandJointId.HandIndex2,
|
||||
HandJointId.HandIndex3,
|
||||
HandJointId.HandIndexTip
|
||||
};
|
||||
|
||||
private static readonly List<HandJointId> THUMB_MASK = new List<HandJointId>()
|
||||
{
|
||||
HandJointId.HandThumb0,
|
||||
HandJointId.HandThumb1,
|
||||
HandJointId.HandThumb2,
|
||||
HandJointId.HandThumb3,
|
||||
HandJointId.HandThumbTip
|
||||
};
|
||||
|
||||
private const string FLEX_PARAM = "Flex";
|
||||
private const string PINCH_PARAM = "Pinch";
|
||||
|
||||
[MenuItem("Oculus/Interaction/Hand Animator Generator")]
|
||||
private static void CreateWizard()
|
||||
{
|
||||
ScriptableWizard.DisplayWizard<HandAnimatorWizard>("Hand Animator Generator", "Close");
|
||||
}
|
||||
|
||||
private void OnWizardCreate() { }
|
||||
|
||||
private void RecordHandFist()
|
||||
{
|
||||
_handFist = GenerateClipAsset("HandFist");
|
||||
}
|
||||
|
||||
private void RecordHand3qtrFist()
|
||||
{
|
||||
_hand3qtrFist = GenerateClipAsset("Hand3qtrFist");
|
||||
}
|
||||
|
||||
private void RecordHandMidFist()
|
||||
{
|
||||
_handMidFist = GenerateClipAsset("HandMidFist");
|
||||
}
|
||||
|
||||
private void RecordHandPinch()
|
||||
{
|
||||
_handPinch = GenerateClipAsset("HandPinch");
|
||||
}
|
||||
|
||||
private void RecordHandCap()
|
||||
{
|
||||
_handCap = GenerateClipAsset("HandCap");
|
||||
}
|
||||
|
||||
private void RecordThumbUp()
|
||||
{
|
||||
_thumbUp = GenerateClipAsset("ThumbUp");
|
||||
}
|
||||
|
||||
private void RecordIndexPoint()
|
||||
{
|
||||
_indexPoint = GenerateClipAsset("IndexPoint");
|
||||
}
|
||||
|
||||
public void GenerateMasks()
|
||||
{
|
||||
_indexMask = GenerateMaskAsset(INDEX_MASK, "indexMask");
|
||||
_thumbMask = GenerateMaskAsset(THUMB_MASK, "thumbMask");
|
||||
}
|
||||
|
||||
private void GenerateAnimatorAsset()
|
||||
{
|
||||
HandClips clips = new HandClips()
|
||||
{
|
||||
handFist = _handFist,
|
||||
hand3qtrFist = _hand3qtrFist,
|
||||
handMidFist = _handMidFist,
|
||||
handPinch = _handPinch,
|
||||
handCap = _handCap,
|
||||
thumbUp = _thumbUp,
|
||||
indexPoint = _indexPoint,
|
||||
|
||||
indexMask = _indexMask,
|
||||
thumbMask = _thumbMask
|
||||
};
|
||||
|
||||
GetHandPrefixes(out string prefix, out string mirrorPrefix);
|
||||
string path = GenerateAnimatorPath(prefix);
|
||||
CreateAnimator(path, clips);
|
||||
}
|
||||
|
||||
private void GenerateMirrorAnimatorAsset()
|
||||
{
|
||||
HandClips clips = new HandClips()
|
||||
{
|
||||
handFist = GenerateMirrorClipAsset(_handFist),
|
||||
hand3qtrFist = GenerateMirrorClipAsset(_hand3qtrFist),
|
||||
handMidFist = GenerateMirrorClipAsset(_handMidFist),
|
||||
handPinch = GenerateMirrorClipAsset(_handPinch),
|
||||
handCap = GenerateMirrorClipAsset(_handCap),
|
||||
thumbUp = GenerateMirrorClipAsset(_thumbUp),
|
||||
indexPoint = GenerateMirrorClipAsset(_indexPoint),
|
||||
|
||||
indexMask = GenerateMirrorMaskAsset(_indexMask),
|
||||
thumbMask = GenerateMirrorMaskAsset(_thumbMask)
|
||||
};
|
||||
|
||||
GetHandPrefixes(out string prefix, out string mirrorPrefix);
|
||||
string path = GenerateAnimatorPath(mirrorPrefix);
|
||||
CreateAnimator(path, clips);
|
||||
}
|
||||
|
||||
private AnimationClip GenerateClipAsset(string title)
|
||||
{
|
||||
GetHandPrefixes(out string prefix, out string mirrorPrefix);
|
||||
AnimationClip clip = new AnimationClip();
|
||||
|
||||
for (int i = (int)HandJointId.HandStart; i < (int)HandJointId.HandEnd; ++i)
|
||||
{
|
||||
Transform jointTransform = _handVisual.Joints[i];
|
||||
string path = GetGameObjectPath(jointTransform, Root);
|
||||
RegisterLocalPose(ref clip, jointTransform.GetPose(Space.Self), path);
|
||||
}
|
||||
|
||||
StoreAsset(clip, $"{title}{prefix}.anim");
|
||||
return clip;
|
||||
}
|
||||
|
||||
private AvatarMask GenerateMaskAsset(List<HandJointId> maskData, string title)
|
||||
{
|
||||
GetHandPrefixes(out string prefix, out string mirrorPrefix);
|
||||
AvatarMask mask = new AvatarMask();
|
||||
List<string> paths = new List<string>(maskData.Count);
|
||||
|
||||
foreach (var maskJoints in maskData)
|
||||
{
|
||||
Transform jointTransform = _handVisual.Joints[(int)maskJoints];
|
||||
string localPath = GetGameObjectPath(jointTransform, Root);
|
||||
paths.Add(localPath);
|
||||
}
|
||||
|
||||
mask.transformCount = paths.Count;
|
||||
for (int i = 0; i < paths.Count; ++i)
|
||||
{
|
||||
mask.SetTransformPath(i, paths[i]);
|
||||
mask.SetTransformActive(i, true);
|
||||
}
|
||||
|
||||
StoreAsset(mask, $"{title}{prefix}.mask");
|
||||
return mask;
|
||||
}
|
||||
|
||||
private AnimationClip GenerateMirrorClipAsset(AnimationClip originalClip)
|
||||
{
|
||||
if (originalClip == null)
|
||||
{
|
||||
Debug.LogError("Please generate a valid Clip first");
|
||||
return null;
|
||||
}
|
||||
GetHandPrefixes(out string prefix, out string mirrorPrefix);
|
||||
|
||||
AnimationClip mirrorClip = new AnimationClip();
|
||||
|
||||
EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(originalClip);
|
||||
foreach (EditorCurveBinding curveBinding in curveBindings)
|
||||
{
|
||||
string mirrorPath = curveBinding.path.Replace(prefix, mirrorPrefix);
|
||||
AnimationCurve curve = AnimationUtility.GetEditorCurve(originalClip, curveBinding);
|
||||
float invertFactor = curveBinding.propertyName.Contains("LocalPosition") ? -1f : 1f;
|
||||
|
||||
AnimationCurve mirrorCurve = new AnimationCurve();
|
||||
|
||||
for (int i = 0; i < curve.length; i++)
|
||||
{
|
||||
mirrorCurve.AddKey(curve[i].time, curve[i].value * invertFactor);
|
||||
}
|
||||
mirrorClip.SetCurve(mirrorPath, curveBinding.type, curveBinding.propertyName, mirrorCurve);
|
||||
}
|
||||
StoreAsset(mirrorClip, originalClip.name.Replace(prefix, mirrorPrefix));
|
||||
return mirrorClip;
|
||||
}
|
||||
|
||||
private AvatarMask GenerateMirrorMaskAsset(AvatarMask originalMask)
|
||||
{
|
||||
if (originalMask == null)
|
||||
{
|
||||
Debug.LogError("Please generate a valid mask first");
|
||||
return null;
|
||||
}
|
||||
GetHandPrefixes(out string prefix, out string mirrorPrefix);
|
||||
|
||||
AvatarMask mirrorMask = new AvatarMask();
|
||||
|
||||
mirrorMask.transformCount = originalMask.transformCount;
|
||||
for (int i = 0; i < originalMask.transformCount; ++i)
|
||||
{
|
||||
string mirrorPath = originalMask.GetTransformPath(i).Replace(prefix, mirrorPrefix);
|
||||
bool active = originalMask.GetTransformActive(i);
|
||||
mirrorMask.SetTransformPath(i, mirrorPath);
|
||||
mirrorMask.SetTransformActive(i, active);
|
||||
}
|
||||
|
||||
StoreAsset(mirrorMask, originalMask.name.Replace(prefix, mirrorPrefix));
|
||||
|
||||
return mirrorMask;
|
||||
}
|
||||
|
||||
private void RegisterLocalPose(ref AnimationClip clip, Pose pose, string path)
|
||||
{
|
||||
Vector3 euler = pose.rotation.eulerAngles;
|
||||
clip.SetCurve(path, typeof(Transform), "localEulerAngles.x", AnimationCurve.Constant(0f, 0.01f, euler.x));
|
||||
clip.SetCurve(path, typeof(Transform), "localEulerAngles.y", AnimationCurve.Constant(0f, 0.01f, euler.y));
|
||||
clip.SetCurve(path, typeof(Transform), "localEulerAngles.z", AnimationCurve.Constant(0f, 0.01f, euler.z));
|
||||
|
||||
Vector3 pos = pose.position;
|
||||
clip.SetCurve(path, typeof(Transform), "localPosition.x", AnimationCurve.Constant(0f, 0.01f, pos.x));
|
||||
clip.SetCurve(path, typeof(Transform), "localPosition.y", AnimationCurve.Constant(0f, 0.01f, pos.y));
|
||||
clip.SetCurve(path, typeof(Transform), "localPosition.z", AnimationCurve.Constant(0f, 0.01f, pos.z));
|
||||
}
|
||||
|
||||
private AnimatorController CreateAnimator(string path, HandClips clips)
|
||||
{
|
||||
AnimatorController animator = AnimatorController.CreateAnimatorControllerAtPath(path);
|
||||
|
||||
animator.AddParameter(FLEX_PARAM, AnimatorControllerParameterType.Float);
|
||||
animator.AddParameter(PINCH_PARAM, AnimatorControllerParameterType.Float);
|
||||
|
||||
animator.RemoveLayer(0);
|
||||
|
||||
CreateLayer(animator, "Flex Layer", null);
|
||||
CreateLayer(animator, "Thumb Layer", clips.thumbMask);
|
||||
CreateLayer(animator, "Point Layer", clips.indexMask);
|
||||
|
||||
CreateFlexStates(animator, 0, clips);
|
||||
CreateThumbUpStates(animator, 1, clips);
|
||||
CreatePointStates(animator, 2, clips);
|
||||
|
||||
return animator;
|
||||
}
|
||||
|
||||
private AnimatorControllerLayer CreateLayer(AnimatorController animator, string layerName, AvatarMask mask = null)
|
||||
{
|
||||
AnimatorControllerLayer layer = new AnimatorControllerLayer();
|
||||
layer.name = layerName;
|
||||
AnimatorStateMachine stateMachine = new AnimatorStateMachine();
|
||||
stateMachine.name = layer.name;
|
||||
AssetDatabase.AddObjectToAsset(stateMachine, animator);
|
||||
stateMachine.hideFlags = HideFlags.HideInHierarchy;
|
||||
layer.stateMachine = stateMachine;
|
||||
layer.avatarMask = mask;
|
||||
animator.AddLayer(layer);
|
||||
return layer;
|
||||
}
|
||||
|
||||
private void CreateFlexStates(AnimatorController animator, int layerIndex, HandClips clips)
|
||||
{
|
||||
BlendTree blendTree;
|
||||
AnimatorState flexState = animator.CreateBlendTreeInController("Flex", out blendTree, layerIndex);
|
||||
blendTree.blendType = BlendTreeType.FreeformCartesian2D;
|
||||
blendTree.blendParameter = FLEX_PARAM;
|
||||
blendTree.blendParameterY = PINCH_PARAM;
|
||||
blendTree.AddChild(clips.handCap, new Vector2(0f, 0f));
|
||||
blendTree.AddChild(clips.handPinch, new Vector2(0f, 0.835f));
|
||||
blendTree.AddChild(clips.handPinch, new Vector2(0f, 1f));
|
||||
blendTree.AddChild(clips.handMidFist, new Vector2(0.5f, 0f));
|
||||
blendTree.AddChild(clips.handMidFist, new Vector2(0.5f, 1f));
|
||||
blendTree.AddChild(clips.hand3qtrFist, new Vector2(0.835f, 0f));
|
||||
blendTree.AddChild(clips.hand3qtrFist, new Vector2(0.835f, 1f));
|
||||
blendTree.AddChild(clips.handFist, new Vector2(1f, 0f));
|
||||
blendTree.AddChild(clips.handFist, new Vector2(1f, 1f));
|
||||
animator.layers[layerIndex].stateMachine.defaultState = flexState;
|
||||
}
|
||||
|
||||
private void CreateThumbUpStates(AnimatorController animator, int layerIndex, HandClips clips)
|
||||
{
|
||||
BlendTree blendTree;
|
||||
AnimatorState flexState = animator.CreateBlendTreeInController("Thumbs Up", out blendTree, layerIndex);
|
||||
blendTree.blendType = BlendTreeType.Simple1D;
|
||||
blendTree.blendParameter = FLEX_PARAM;
|
||||
blendTree.AddChild(clips.handCap, 0f);
|
||||
blendTree.AddChild(clips.thumbUp, 1f);
|
||||
blendTree.useAutomaticThresholds = true;
|
||||
animator.layers[layerIndex].stateMachine.defaultState = flexState;
|
||||
}
|
||||
|
||||
private void CreatePointStates(AnimatorController animator, int layerIndex, HandClips clips)
|
||||
{
|
||||
BlendTree blendTree;
|
||||
AnimatorState flexState = animator.CreateBlendTreeInController("Point", out blendTree, layerIndex);
|
||||
blendTree.blendType = BlendTreeType.Simple1D;
|
||||
blendTree.blendParameter = FLEX_PARAM;
|
||||
blendTree.AddChild(clips.handCap, 0f);
|
||||
blendTree.AddChild(clips.indexPoint, 1f);
|
||||
blendTree.useAutomaticThresholds = true;
|
||||
animator.layers[layerIndex].stateMachine.defaultState = flexState;
|
||||
}
|
||||
|
||||
private void StoreAsset(Object asset, string name)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string targetFolder = Path.Combine("Assets", _folder);
|
||||
CreateFolder(targetFolder);
|
||||
string path = Path.Combine(targetFolder, name);
|
||||
AssetDatabase.CreateAsset(asset, path);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void CreateFolder(string targetFolder)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Directory.Exists(targetFolder))
|
||||
{
|
||||
Directory.CreateDirectory(targetFolder);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private string GenerateAnimatorPath(string prefix)
|
||||
{
|
||||
string targetFolder = Path.Combine("Assets", _folder);
|
||||
CreateFolder(targetFolder);
|
||||
string path = Path.Combine(targetFolder, $"{_controllerName}{prefix}.controller");
|
||||
return path;
|
||||
}
|
||||
|
||||
private static string GetGameObjectPath(Transform transform, Transform root)
|
||||
{
|
||||
string path = transform.name;
|
||||
while (transform.parent != null
|
||||
&& transform.parent != root)
|
||||
{
|
||||
transform = transform.parent;
|
||||
path = $"{transform.name}/{path}";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private void GetHandPrefixes(out string prefix, out string mirrorPrefix)
|
||||
{
|
||||
Handedness originalHandedness = _handVisual.Hand.Handedness;
|
||||
prefix = originalHandedness == Handedness.Left ? _handLeftPrefix : _handRightPrefix;
|
||||
mirrorPrefix = originalHandedness == Handedness.Left ? _handRightPrefix : _handLeftPrefix;
|
||||
}
|
||||
|
||||
private class HandClips
|
||||
{
|
||||
public AnimationClip handFist;
|
||||
public AnimationClip hand3qtrFist;
|
||||
public AnimationClip handMidFist;
|
||||
public AnimationClip handPinch;
|
||||
public AnimationClip handCap;
|
||||
public AnimationClip thumbUp;
|
||||
public AnimationClip indexPoint;
|
||||
|
||||
public AvatarMask indexMask;
|
||||
public AvatarMask thumbMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d513303388f205408a199c8f7a88885
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
37
Assets/Oculus/Interaction/Editor/Utils/OptionalDrawer.cs
Normal file
37
Assets/Oculus/Interaction/Editor/Utils/OptionalDrawer.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
/************************************************************************************
|
||||
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
||||
|
||||
Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
|
||||
https://developer.oculus.com/licenses/oculussdk/
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
ANY KIND, either express or implied. See the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
************************************************************************************/
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Oculus.Interaction.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]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f23e2cef5c87c842828dec6dd676b0b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
17
Assets/Oculus/Interaction/LICENSE
Normal file
17
Assets/Oculus/Interaction/LICENSE
Normal file
@@ -0,0 +1,17 @@
|
||||
Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
|
||||
You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
copy, modify, and distribute this software in source code or binary form for use
|
||||
in connection with the web services and APIs provided by Facebook.
|
||||
|
||||
As with any software that integrates with the Facebook platform, your use of
|
||||
this software is subject to the Facebook Platform Policy
|
||||
[http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
included in all copies or substantial portions of the software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
7
Assets/Oculus/Interaction/LICENSE.meta
Normal file
7
Assets/Oculus/Interaction/LICENSE.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ae7fa0df02dd7543bb7875531e22eb9
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Runtime.meta
Normal file
8
Assets/Oculus/Interaction/Runtime.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad6228a9ccc92e448b26059dce70a6be
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Runtime/Animations.meta
Normal file
8
Assets/Oculus/Interaction/Runtime/Animations.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db583baa22f417146abd434b0213be9e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Interaction/Runtime/Animations/Hands.meta
Normal file
8
Assets/Oculus/Interaction/Runtime/Animations/Hands.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 669386ac07a2c2f49b678016df2a7ca6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03b712ca2de00d845a4a8432ce8d7c1f
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2caa8b62d9cd644faeaecb80ea43226
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandCap_l_.anim
Normal file
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandCap_l_.anim
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 084df4ced109eed4cb2d1f4bc8204ac4
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandCap_r_.anim
Normal file
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandCap_r_.anim
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bc7ce953b327f747b7db6b0d87e796b
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,353 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1107 &-7628558860938981836
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Thumb Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -1888948341698880734}
|
||||
m_Position: {x: 200, y: 0, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: -1888948341698880734}
|
||||
--- !u!206 &-3192213461481483477
|
||||
BlendTree:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Point
|
||||
m_Childs:
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 084df4ced109eed4cb2d1f4bc8204ac4, type: 2}
|
||||
m_Threshold: 0
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 81850be3722257141a962f87f08bd7d7, type: 2}
|
||||
m_Threshold: 1
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
m_BlendParameter: Flex
|
||||
m_BlendParameterY: Flex
|
||||
m_MinThreshold: 0
|
||||
m_MaxThreshold: 1
|
||||
m_UseAutomaticThresholds: 1
|
||||
m_NormalizedBlendValues: 0
|
||||
m_BlendType: 0
|
||||
--- !u!206 &-2223252167233188817
|
||||
BlendTree:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Thumbs Up
|
||||
m_Childs:
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 084df4ced109eed4cb2d1f4bc8204ac4, type: 2}
|
||||
m_Threshold: 0
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: d383e35b8d2f63f4f8258d5eadab871e, type: 2}
|
||||
m_Threshold: 1
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
m_BlendParameter: Flex
|
||||
m_BlendParameterY: Flex
|
||||
m_MinThreshold: 0
|
||||
m_MaxThreshold: 1
|
||||
m_UseAutomaticThresholds: 1
|
||||
m_NormalizedBlendValues: 0
|
||||
m_BlendType: 0
|
||||
--- !u!1102 &-1888948341698880734
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Thumbs Up
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: -2223252167233188817}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: HandController_l_
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters:
|
||||
- m_Name: Flex
|
||||
m_Type: 1
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
- m_Name: Pinch
|
||||
m_Type: 1
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Flex Layer
|
||||
m_StateMachine: {fileID: 1594823119344177508}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
- serializedVersion: 5
|
||||
m_Name: Thumb Layer
|
||||
m_StateMachine: {fileID: -7628558860938981836}
|
||||
m_Mask: {fileID: 31900000, guid: 0f5a40b1c760daa49bb2861fd39edb59, type: 2}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
- serializedVersion: 5
|
||||
m_Name: Point Layer
|
||||
m_StateMachine: {fileID: 3098083256955168545}
|
||||
m_Mask: {fileID: 31900000, guid: e87d231d9435bbf44b39fc1b848769e8, type: 2}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
--- !u!206 &1010449700093287336
|
||||
BlendTree:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Flex
|
||||
m_Childs:
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 084df4ced109eed4cb2d1f4bc8204ac4, type: 2}
|
||||
m_Threshold: 0
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 55cdf5be56300094a98bf59c19c746b1, type: 2}
|
||||
m_Threshold: 0.125
|
||||
m_Position: {x: 0, y: 0.835}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 55cdf5be56300094a98bf59c19c746b1, type: 2}
|
||||
m_Threshold: 0.25
|
||||
m_Position: {x: 0, y: 1}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 2a62eebed83b25b4b8f2c21b3281f62c, type: 2}
|
||||
m_Threshold: 0.375
|
||||
m_Position: {x: 0.5, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 2a62eebed83b25b4b8f2c21b3281f62c, type: 2}
|
||||
m_Threshold: 0.5
|
||||
m_Position: {x: 0.5, y: 1}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 03b712ca2de00d845a4a8432ce8d7c1f, type: 2}
|
||||
m_Threshold: 0.625
|
||||
m_Position: {x: 0.835, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 03b712ca2de00d845a4a8432ce8d7c1f, type: 2}
|
||||
m_Threshold: 0.75
|
||||
m_Position: {x: 0.835, y: 1}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 86c200927e07323488de63f1cbcf1907, type: 2}
|
||||
m_Threshold: 0.875
|
||||
m_Position: {x: 1, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 86c200927e07323488de63f1cbcf1907, type: 2}
|
||||
m_Threshold: 1
|
||||
m_Position: {x: 1, y: 1}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
m_BlendParameter: Flex
|
||||
m_BlendParameterY: Pinch
|
||||
m_MinThreshold: 0
|
||||
m_MaxThreshold: 1
|
||||
m_UseAutomaticThresholds: 1
|
||||
m_NormalizedBlendValues: 0
|
||||
m_BlendType: 3
|
||||
--- !u!1107 &1594823119344177508
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Flex Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 6558856526756694975}
|
||||
m_Position: {x: 200, y: 0, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 6558856526756694975}
|
||||
--- !u!1107 &3098083256955168545
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Point Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 3298637349955912589}
|
||||
m_Position: {x: 200, y: 0, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 3298637349955912589}
|
||||
--- !u!1102 &3298637349955912589
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Point
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: -3192213461481483477}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1102 &6558856526756694975
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Flex
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 1010449700093287336}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a12c873a809a53a4d905e8a723d2bf9e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,353 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!206 &-9188025777202391703
|
||||
BlendTree:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Point
|
||||
m_Childs:
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 6bc7ce953b327f747b7db6b0d87e796b, type: 2}
|
||||
m_Threshold: 0
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 86a31394bfe0b3e4b871676d471ef8c6, type: 2}
|
||||
m_Threshold: 1
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
m_BlendParameter: Flex
|
||||
m_BlendParameterY: Flex
|
||||
m_MinThreshold: 0
|
||||
m_MaxThreshold: 1
|
||||
m_UseAutomaticThresholds: 1
|
||||
m_NormalizedBlendValues: 0
|
||||
m_BlendType: 0
|
||||
--- !u!1107 &-5932432453818324497
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Point Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 6544198812811141909}
|
||||
m_Position: {x: 200, y: 0, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 6544198812811141909}
|
||||
--- !u!1107 &-4303331548228400377
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Thumb Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -2380865389792614045}
|
||||
m_Position: {x: 200, y: 0, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: -2380865389792614045}
|
||||
--- !u!1102 &-2380865389792614045
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Thumbs Up
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 3269154092968826217}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: HandController_r_
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters:
|
||||
- m_Name: Flex
|
||||
m_Type: 1
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
- m_Name: Pinch
|
||||
m_Type: 1
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Flex Layer
|
||||
m_StateMachine: {fileID: 6815202928595392535}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
- serializedVersion: 5
|
||||
m_Name: Thumb Layer
|
||||
m_StateMachine: {fileID: -4303331548228400377}
|
||||
m_Mask: {fileID: 31900000, guid: b2d37b44e3ecc304f931c7d0b08304a5, type: 2}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
- serializedVersion: 5
|
||||
m_Name: Point Layer
|
||||
m_StateMachine: {fileID: -5932432453818324497}
|
||||
m_Mask: {fileID: 31900000, guid: 93061e99c8743d54c95868e4a065e9df, type: 2}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
--- !u!206 &3269154092968826217
|
||||
BlendTree:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Thumbs Up
|
||||
m_Childs:
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 6bc7ce953b327f747b7db6b0d87e796b, type: 2}
|
||||
m_Threshold: 0
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 06e5790983e91714d83eb62bd6d24071, type: 2}
|
||||
m_Threshold: 1
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
m_BlendParameter: Flex
|
||||
m_BlendParameterY: Flex
|
||||
m_MinThreshold: 0
|
||||
m_MaxThreshold: 1
|
||||
m_UseAutomaticThresholds: 1
|
||||
m_NormalizedBlendValues: 0
|
||||
m_BlendType: 0
|
||||
--- !u!206 &5002406659706533776
|
||||
BlendTree:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Flex
|
||||
m_Childs:
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 6bc7ce953b327f747b7db6b0d87e796b, type: 2}
|
||||
m_Threshold: 0
|
||||
m_Position: {x: 0, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 26aed7841cb5c9640aedf3cf82ed052e, type: 2}
|
||||
m_Threshold: 0.125
|
||||
m_Position: {x: 0, y: 0.835}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 26aed7841cb5c9640aedf3cf82ed052e, type: 2}
|
||||
m_Threshold: 0.25
|
||||
m_Position: {x: 0, y: 1}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 239acd9cecc4aaf4f98ec5420ef26571, type: 2}
|
||||
m_Threshold: 0.375
|
||||
m_Position: {x: 0.5, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 239acd9cecc4aaf4f98ec5420ef26571, type: 2}
|
||||
m_Threshold: 0.5
|
||||
m_Position: {x: 0.5, y: 1}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: d2caa8b62d9cd644faeaecb80ea43226, type: 2}
|
||||
m_Threshold: 0.625
|
||||
m_Position: {x: 0.835, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: d2caa8b62d9cd644faeaecb80ea43226, type: 2}
|
||||
m_Threshold: 0.75
|
||||
m_Position: {x: 0.835, y: 1}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 8d4626841b2612b44bc7cba26d19e492, type: 2}
|
||||
m_Threshold: 0.875
|
||||
m_Position: {x: 1, y: 0}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
- serializedVersion: 2
|
||||
m_Motion: {fileID: 7400000, guid: 8d4626841b2612b44bc7cba26d19e492, type: 2}
|
||||
m_Threshold: 1
|
||||
m_Position: {x: 1, y: 1}
|
||||
m_TimeScale: 1
|
||||
m_CycleOffset: 0
|
||||
m_DirectBlendParameter: Blend
|
||||
m_Mirror: 0
|
||||
m_BlendParameter: Flex
|
||||
m_BlendParameterY: Pinch
|
||||
m_MinThreshold: 0
|
||||
m_MaxThreshold: 1
|
||||
m_UseAutomaticThresholds: 1
|
||||
m_NormalizedBlendValues: 0
|
||||
m_BlendType: 3
|
||||
--- !u!1102 &5511475171330556889
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Flex
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 5002406659706533776}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1102 &6544198812811141909
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Point
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: -9188025777202391703}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1107 &6815202928595392535
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Flex Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 5511475171330556889}
|
||||
m_Position: {x: 200, y: 0, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 5511475171330556889}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dbd7e2355cd6f804bbe6c4244e38443a
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandFist_l_.anim
Normal file
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandFist_l_.anim
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86c200927e07323488de63f1cbcf1907
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandFist_r_.anim
Normal file
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandFist_r_.anim
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d4626841b2612b44bc7cba26d19e492
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a62eebed83b25b4b8f2c21b3281f62c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 239acd9cecc4aaf4f98ec5420ef26571
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandPinch_l_.anim
Normal file
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandPinch_l_.anim
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55cdf5be56300094a98bf59c19c746b1
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandPinch_r_.anim
Normal file
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/HandPinch_r_.anim
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26aed7841cb5c9640aedf3cf82ed052e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81850be3722257141a962f87f08bd7d7
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86a31394bfe0b3e4b871676d471ef8c6
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/ThumbUp_l_.anim
Normal file
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/ThumbUp_l_.anim
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d383e35b8d2f63f4f8258d5eadab871e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/ThumbUp_r_.anim
Normal file
1253
Assets/Oculus/Interaction/Runtime/Animations/Hands/ThumbUp_r_.anim
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06e5790983e91714d83eb62bd6d24071
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!319 &31900000
|
||||
AvatarMask:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: indexMask_l_
|
||||
m_Mask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
|
||||
m_Elements:
|
||||
- m_Path: b_l_wrist/b_l_index1
|
||||
m_Weight: 1
|
||||
- m_Path: b_l_wrist/b_l_index1/b_l_index2
|
||||
m_Weight: 1
|
||||
- m_Path: b_l_wrist/b_l_index1/b_l_index2/b_l_index3
|
||||
m_Weight: 1
|
||||
- m_Path: b_l_wrist/b_l_index1/b_l_index2/b_l_index3/l_index_finger_tip_marker
|
||||
m_Weight: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e87d231d9435bbf44b39fc1b848769e8
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 31900000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!319 &31900000
|
||||
AvatarMask:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: indexMask_r_
|
||||
m_Mask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
|
||||
m_Elements:
|
||||
- m_Path: b_r_wrist/b_r_index1
|
||||
m_Weight: 1
|
||||
- m_Path: b_r_wrist/b_r_index1/b_r_index2
|
||||
m_Weight: 1
|
||||
- m_Path: b_r_wrist/b_r_index1/b_r_index2/b_r_index3
|
||||
m_Weight: 1
|
||||
- m_Path: b_r_wrist/b_r_index1/b_r_index2/b_r_index3/l_index_finger_tip_marker
|
||||
m_Weight: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93061e99c8743d54c95868e4a065e9df
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 31900000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!319 &31900000
|
||||
AvatarMask:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: thumbMask_l_
|
||||
m_Mask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
|
||||
m_Elements:
|
||||
- m_Path: b_l_wrist/b_l_thumb0
|
||||
m_Weight: 1
|
||||
- m_Path: b_l_wrist/b_l_thumb0/b_l_thumb1
|
||||
m_Weight: 1
|
||||
- m_Path: b_l_wrist/b_l_thumb0/b_l_thumb1/b_l_thumb2
|
||||
m_Weight: 1
|
||||
- m_Path: b_l_wrist/b_l_thumb0/b_l_thumb1/b_l_thumb2/b_l_thumb3
|
||||
m_Weight: 1
|
||||
- m_Path: b_l_wrist/b_l_thumb0/b_l_thumb1/b_l_thumb2/b_l_thumb3/l_thumb_finger_tip_marker
|
||||
m_Weight: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f5a40b1c760daa49bb2861fd39edb59
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 31900000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user