clean project

This commit is contained in:
Helar Jaadla
2022-03-07 17:52:41 +02:00
parent a174b45bd2
commit cbeb10ec35
5100 changed files with 837159 additions and 0 deletions

View File

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

View 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
}
}

View File

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

View File

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

View 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);
}
}
}

View File

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

View File

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

View File

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

View File

@@ -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);
}
}
}
}
}

View File

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

View File

@@ -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
}
}

View File

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

View File

@@ -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);
}
}
}

View File

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

View File

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

View File

@@ -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);
}
}
}

View File

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

View File

@@ -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;
}
}
}
}
}

View File

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

View File

@@ -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();
}
}
}

View File

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

View File

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

View File

@@ -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;
}
}
}

View File

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

View File

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

View 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";
}
}
}
}

View File

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

View File

@@ -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
}

View File

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

View File

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

View File

@@ -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);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 39acc9895ae6408898722a714edbe5ce
timeCreated: 1631575366

View File

@@ -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);
}
}
}

View File

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

View File

@@ -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);
}
}
}

View File

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

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7a4a7445af8149e0887018ba0cba6abb
timeCreated: 1627935350

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ca473a2dca4a42988bd13c46f6ed077f
timeCreated: 1631569404

View File

@@ -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;
}
}
}

View File

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

View File

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

View File

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

View File

@@ -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;
}
}
}

View File

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

View File

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

View File

@@ -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);
}
}
}
}
}

View File

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

View File

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

View File

@@ -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
}
}

View File

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

View File

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

View 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;
}
}
}

View File

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

View 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]");
}
}
}

View File

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

View 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.

View File

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

View File

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

View File

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

View 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

View File

@@ -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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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:

View File

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

View File

@@ -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}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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

View File

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

View File

@@ -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

View File

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

View File

@@ -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

View File

@@ -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