Skip to content

Commit b597efb

Browse files
committed
Adds Bezier line data provider and inspector
1 parent ad2cfda commit b597efb

File tree

4 files changed

+279
-0
lines changed

4 files changed

+279
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
using Microsoft.MixedReality.Toolkit.Core.Definitions.Utilities;
5+
using Microsoft.MixedReality.Toolkit.Core.Utilities.Lines.DataProviders;
6+
using System.Collections.Generic;
7+
using UnityEditor;
8+
using UnityEditorInternal;
9+
using UnityEngine;
10+
11+
namespace Microsoft.MixedReality.Toolkit.Core.Inspectors.Utilities.Lines
12+
{
13+
[CustomEditor(typeof(BezierDataProvider))]
14+
public class BezierDataProviderInspector : BaseLineDataProviderInspector
15+
{
16+
private const float OverlappingPointThreshold = 0.015f;
17+
private const float HandleSizeModifier = 0.04f;
18+
private const float PickSizeModifier = 0.06f;
19+
20+
private static readonly HashSet<int> OverlappingPointIndexes = new HashSet<int>();
21+
22+
private static readonly Vector2 ControlPointButtonSize = new Vector2(16, 16);
23+
private static readonly Vector2 LeftControlPointPositionOffset = Vector2.left * 12;
24+
private static readonly Vector2 RightControlPointPositionOffset = Vector2.right * 24;
25+
26+
private static readonly Vector2 ControlPointButtonHandleOffset = Vector3.up * 24;
27+
28+
private static readonly GUIContent PositionContent = new GUIContent("Position");
29+
30+
private SerializedProperty controlPoints;
31+
32+
private BezierDataProvider bezierData;
33+
34+
private int selectedHandleIndex = -1;
35+
36+
protected override void OnEnable()
37+
{
38+
base.OnEnable();
39+
40+
controlPoints = serializedObject.FindProperty("controlPoints");
41+
42+
bezierData = (BezierDataProvider)target;
43+
}
44+
45+
public override void OnInspectorGUI()
46+
{
47+
base.OnInspectorGUI();
48+
serializedObject.Update();
49+
50+
// We always draw line points for bezier.
51+
DrawLinePoints = true;
52+
53+
EditorGUILayout.PropertyField(controlPoints, true);
54+
55+
serializedObject.ApplyModifiedProperties();
56+
}
57+
58+
protected override void OnSceneGUI()
59+
{
60+
base.OnSceneGUI();
61+
62+
// We skip the first point as it should always remain at the GameObject's local origin (Pose.ZeroIdentity)
63+
for (int i = 0; i < 4; i++)
64+
{
65+
bool isTangentHandle = i % 3 != 0;
66+
67+
serializedObject.Update();
68+
69+
bool isLastPoint = i == 3;
70+
71+
var controlPointPosition = LineData.GetPoint(i);
72+
var controlPointProperty = controlPoints.FindPropertyRelative("point" + (i + 1));
73+
74+
// Draw our tangent lines
75+
Handles.color = Color.gray;
76+
if (i == 0)
77+
{
78+
Handles.DrawLine(LineData.GetPoint(0), LineData.GetPoint(1));
79+
}
80+
else if (!isTangentHandle)
81+
{
82+
Handles.DrawLine(LineData.GetPoint(i), LineData.GetPoint(i - 1));
83+
84+
if (!isLastPoint)
85+
{
86+
Handles.DrawLine(LineData.GetPoint(i), LineData.GetPoint(i + 1));
87+
}
88+
}
89+
90+
Handles.color = isTangentHandle ? Color.white : Color.green;
91+
float handleSize = HandleUtility.GetHandleSize(controlPointPosition);
92+
93+
if (Handles.Button(controlPointPosition, Quaternion.identity, handleSize * HandleSizeModifier, handleSize * PickSizeModifier, Handles.DotHandleCap))
94+
{
95+
selectedHandleIndex = i;
96+
}
97+
98+
// Draw our handles
99+
if (Tools.current == Tool.Move && selectedHandleIndex == i)
100+
{
101+
EditorGUI.BeginChangeCheck();
102+
103+
var newTargetPosition = Handles.PositionHandle(controlPointPosition, Quaternion.identity);
104+
105+
if (EditorGUI.EndChangeCheck())
106+
{
107+
Undo.RecordObject(LineData, "Change Bezier Point Position");
108+
LineData.SetPoint(i, newTargetPosition);
109+
}
110+
}
111+
112+
serializedObject.ApplyModifiedProperties();
113+
}
114+
}
115+
116+
private void DrawControlPointElement(Rect rect, int index, bool isActive, bool isFocused)
117+
{
118+
bool lastMode = EditorGUIUtility.wideMode;
119+
EditorGUIUtility.wideMode = true;
120+
121+
var lastLabelWidth = EditorGUIUtility.labelWidth;
122+
EditorGUIUtility.labelWidth = 88f;
123+
124+
var property = controlPoints.GetArrayElementAtIndex(index);
125+
var fieldHeight = EditorGUIUtility.singleLineHeight * 0.5f;
126+
var labelRect = new Rect(rect.x - 8f, rect.y + fieldHeight * 2, rect.width, EditorGUIUtility.singleLineHeight);
127+
var positionRect = new Rect(rect.x, rect.y + fieldHeight, rect.width, EditorGUIUtility.singleLineHeight);
128+
var rotationRect = new Rect(rect.x, rect.y + fieldHeight * 3, rect.width, EditorGUIUtility.singleLineHeight);
129+
130+
EditorGUI.LabelField(labelRect, $"{index + 1}");
131+
132+
EditorGUI.indentLevel++;
133+
134+
GUI.enabled = index != 0;
135+
136+
EditorGUI.BeginChangeCheck();
137+
EditorGUI.PropertyField(positionRect, property.FindPropertyRelative("position"), PositionContent);
138+
bool hasPositionChanged = EditorGUI.EndChangeCheck();
139+
140+
if (hasPositionChanged)
141+
{
142+
EditorUtility.SetDirty(target);
143+
}
144+
145+
GUI.enabled = true;
146+
EditorGUI.indentLevel--;
147+
EditorGUIUtility.wideMode = lastMode;
148+
EditorGUIUtility.labelWidth = lastLabelWidth;
149+
}
150+
}
151+
}

Assets/MixedRealityToolkit/Inspectors/Utilities/Lines/DataProviders/BezierDataProviderInspector.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
using Microsoft.MixedReality.Toolkit.Core.Definitions.Utilities;
5+
using System;
6+
using UnityEngine;
7+
8+
namespace Microsoft.MixedReality.Toolkit.Core.Utilities.Lines.DataProviders
9+
{
10+
public class BezierDataProvider : BaseMixedRealityLineDataProvider
11+
{
12+
[Serializable]
13+
private struct BezierPointSet
14+
{
15+
public BezierPointSet(float spread)
16+
{
17+
Point1 = Vector3.right * spread * 0.5f;
18+
Point2 = Vector3.right * spread * 0.25f;
19+
Point3 = Vector3.left * spread * 0.25f;
20+
Point4 = Vector3.left * spread * 0.5f;
21+
}
22+
23+
public Vector3 Point1;
24+
public Vector3 Point2;
25+
public Vector3 Point3;
26+
public Vector3 Point4;
27+
}
28+
29+
public override int PointCount { get { return 4; } }
30+
31+
[Header("Bezier Settings")]
32+
[SerializeField]
33+
private BezierPointSet controlPoints = new BezierPointSet(0.5f);
34+
35+
protected override Vector3 GetPointInternal(int pointIndex)
36+
{
37+
switch (pointIndex)
38+
{
39+
case 0:
40+
return controlPoints.Point1;
41+
42+
case 1:
43+
return controlPoints.Point2;
44+
45+
case 2:
46+
return controlPoints.Point3;
47+
48+
case 3:
49+
return controlPoints.Point4;
50+
51+
default:
52+
return Vector3.zero;
53+
}
54+
}
55+
56+
protected override void SetPointInternal(int pointIndex, Vector3 point)
57+
{
58+
switch (pointIndex)
59+
{
60+
case 0:
61+
controlPoints.Point1 = point;
62+
break;
63+
64+
case 1:
65+
controlPoints.Point2 = point;
66+
break;
67+
68+
case 2:
69+
controlPoints.Point3 = point;
70+
break;
71+
72+
case 3:
73+
controlPoints.Point4 = point;
74+
break;
75+
76+
default:
77+
break;
78+
}
79+
}
80+
81+
protected override Vector3 GetPointInternal(float normalizedDistance)
82+
{
83+
return LineUtility.InterpolateBezierPoints(controlPoints.Point1, controlPoints.Point2, controlPoints.Point3, controlPoints.Point4, normalizedDistance);
84+
}
85+
86+
protected override float GetUnClampedWorldLengthInternal()
87+
{
88+
// Crude approximation
89+
// TODO optimize
90+
float distance = 0f;
91+
Vector3 last = GetUnClampedPoint(0f);
92+
for (int i = 1; i < 10; i++)
93+
{
94+
Vector3 current = GetUnClampedPoint((float)i / 10);
95+
distance += Vector3.Distance(last, current);
96+
}
97+
return distance;
98+
}
99+
100+
protected override Vector3 GetUpVectorInternal(float normalizedLength)
101+
{
102+
// Bezeir up vectors just use transform up
103+
return transform.up;
104+
}
105+
}
106+
}

Assets/MixedRealityToolkit/Utilities/Lines/DataProviders/BezierDataProvider.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)