diff --git a/Assets/SplineMesh/Scripts/Bezier/CubicBezierCurve.cs b/Assets/SplineMesh/Scripts/Bezier/CubicBezierCurve.cs
index 322ca2f..08dd50e 100644
--- a/Assets/SplineMesh/Scripts/Bezier/CubicBezierCurve.cs
+++ b/Assets/SplineMesh/Scripts/Bezier/CubicBezierCurve.cs
@@ -84,10 +84,19 @@ private Vector3 GetLocation(float t) {
float omt = 1f - t;
float omt2 = omt * omt;
float t2 = t * t;
+
+
+ // old version, before free tangents
+ //return
+ // n1.Position * (omt2 * omt) +
+ // n1.Direction * (3f * omt2 * t) +
+ // GetInverseDirection() * (3f * omt * t2) +
+ // n2.Position * (t2 * t);
+
return
n1.Position * (omt2 * omt) +
- n1.Direction * (3f * omt2 * t) +
- GetInverseDirection() * (3f * omt * t2) +
+ n1.DirectionOut * (3f * omt2 * t) +
+ n2.DirectionIn * (3f * omt * t2) +
n2.Position * (t2 * t);
}
@@ -100,11 +109,21 @@ private Vector3 GetTangent(float t) {
float omt = 1f - t;
float omt2 = omt * omt;
float t2 = t * t;
+
+
+ // old version, before free tangents
+ //Vector3 tangent =
+ // n1.Position * (-omt2) +
+ // n1.Direction * (3 * omt2 - 2 * omt) +
+ // GetInverseDirection() * (-3 * t2 + 2 * t) +
+ // n2.Position * (t2);
+
Vector3 tangent =
n1.Position * (-omt2) +
- n1.Direction * (3 * omt2 - 2 * omt) +
- GetInverseDirection() * (-3 * t2 + 2 * t) +
+ n1.DirectionOut * (3 * omt2 - 2 * omt) +
+ n2.DirectionIn * (-3 * t2 + 2 * t) +
n2.Position * (t2);
+
return tangent.normalized;
}
diff --git a/Assets/SplineMesh/Scripts/Bezier/Spline.cs b/Assets/SplineMesh/Scripts/Bezier/Spline.cs
index f9991e8..e93faca 100644
--- a/Assets/SplineMesh/Scripts/Bezier/Spline.cs
+++ b/Assets/SplineMesh/Scripts/Bezier/Spline.cs
@@ -213,6 +213,81 @@ public void InsertNode(int index, SplineNode node) {
updateLoopBinding();
}
+ ///
+ /// Split the spline by adding a node at the specific time
+ /// the tangents of previous and following node are modified
+ /// in order to not alter the curve shape.
+ ///
+ /// previous and next node tangent type become SplineNode.TangentType.Free
+ ///
+ ///
+ public void SplitAtTime(float time)
+ {
+ if (time <= 0f || time >= (float)nodes.Count - 1)
+ throw new Exception(string.Format("Can't split at time {0}. Use a value between 0 and {1}", time, (float)nodes.Count - 1));
+
+ CurveSample time_sample = GetSample(time);
+ Vector3 new_point_position = time_sample.location;
+
+
+ // percent position between two nodes
+ float percentage = time % 1;
+ int index = Mathf.FloorToInt(time);
+
+ /**
+ * P0 = starting point
+ * P3 = ending point
+ *
+ * P1 = P0 control point
+ * P2 = mirror of P3 control point (we need the inverse, not the real cp)
+ */
+
+ SplineNode starting_node = nodes[index];
+
+ Vector3 p0 = starting_node.Position;
+ Vector3 p1 = starting_node.DirectionOut;
+
+ SplineNode ending_node = nodes[index + 1];
+ Vector3 p3 = ending_node.Position;
+ Vector3 p2 = ending_node.DirectionIn;
+
+
+ // we need to find a positoin at percentage% between P0 and P1
+ Vector3 m0 = p0 + (p1 - p0) * percentage;
+ Vector3 m1 = p1 + (p2 - p1) * percentage;
+ Vector3 m2 = p2 + (p3 - p2) * percentage;
+
+ Vector3 q0 = m0 + (m1 - m0) * percentage;
+ Vector3 q1 = m1 + (m2 - m1) * percentage;
+
+ Vector3 new_point_direction_in = q0;
+ Vector3 new_point_direction_out = q1;
+
+ // create the new node with previous calculated params
+ SplineNode n = new SplineNode(new_point_position, new_point_direction_out, new_point_direction_in); //time_sample.tangent);
+ n.DirectionType = SplineNode.TangentType.Free;
+
+
+ // we also need to alter the directionOut of the previous point
+ // its new direction is m0
+ // in order to alter it, the tangent type must be free
+ if (nodes[index].DirectionType != SplineNode.TangentType.Free)
+ {
+ nodes[index].DirectionType = SplineNode.TangentType.Free;
+ }
+ nodes[index].DirectionOut = m0;
+
+ // we also need to alter the directionIn of the final point
+ // its new direction is m2
+ // in order to alter it, the tangent type must be free
+ if (nodes[index + 1].DirectionType != SplineNode.TangentType.Free)
+ {
+ nodes[index + 1].DirectionType = SplineNode.TangentType.Free;
+ }
+ nodes[index + 1].DirectionIn = m2;
+ InsertNode(index + 1, n);
+ }
+
///
/// Remove the given node from the spline. The given node must exist and the spline must have more than 2 nodes.
///
diff --git a/Assets/SplineMesh/Scripts/Bezier/SplineNode.cs b/Assets/SplineMesh/Scripts/Bezier/SplineNode.cs
index a8b3d72..6096508 100644
--- a/Assets/SplineMesh/Scripts/Bezier/SplineNode.cs
+++ b/Assets/SplineMesh/Scripts/Bezier/SplineNode.cs
@@ -4,54 +4,189 @@
using UnityEngine;
using UnityEngine.Events;
-namespace SplineMesh {
+namespace SplineMesh
+{
///
/// Spline node storing a position and a direction (tangent).
/// Note : you shouldn't modify position and direction manualy but use dedicated methods instead, to insure event raising.
///
[Serializable]
- public class SplineNode {
+ public class SplineNode
+ {
+
///
/// Node position
///
- public Vector3 Position {
+ public Vector3 Position
+ {
get { return position; }
- set {
+ set
+ {
if (position.Equals(value)) return;
position.x = value.x;
position.y = value.y;
position.z = value.z;
- if(Changed != null) Changed(this, EventArgs.Empty);
+ if (Changed != null) Changed(this, EventArgs.Empty);
}
}
[SerializeField]
private Vector3 position;
+
+ ///
+ /// Tangent vector type of the node
+ /// - Mirrored (default): The in and out tangent vectors are symetrical around the node.
+ /// - Aligned: the in and out tangent vectors are also opposed but they can have different lengths, hence different curvature
+ /// ( to be implemented )
+ /// - Free: the in and out vectors can be completly independant.
+ ///
+ public enum TangentType { Mirrored, Free };
+
///
- /// Node direction
+ /// Node tangent type
///
- public Vector3 Direction {
- get { return direction; }
- set {
- if (direction.Equals(value)) return;
- direction.x = value.x;
- direction.y = value.y;
- direction.z = value.z;
+ public TangentType DirectionType
+ {
+ get { return directionType; }
+ set
+ {
+ if (directionType.Equals(value)) return;
+ directionType = value;
if (Changed != null) Changed(this, EventArgs.Empty);
}
}
+
+ [SerializeField]
+ public TangentType directionType = TangentType.Mirrored;
+
+ ///
+ /// Node direction;
+ /// this parameter could be removed in a future version, use
+ /// directionIn / directionOut
+ /// USE DirectionOut and DirectionIn
+ ///
+ public Vector3 Direction
+ {
+ get
+ {
+ return DirectionOut;
+ }
+ set
+ {
+ DirectionOut = value;
+ }
+ }
+
+
[SerializeField]
private Vector3 direction;
+
+
+ public Vector3 DirectionIn
+ {
+ get {
+ /*
+ * for backward compatibility:
+ * saved nodes will have direction not zero, and directionout == Vector3.zero
+ *
+ * if this situation occurs, we update directionOut
+ */
+
+ if (directionIn == Vector3.zero && direction != Vector3.zero)
+ {
+ directionIn.x = 2 * position.x - direction.x;
+ directionIn.y = 2 * position.y - direction.y;
+ directionIn.z = 2 * position.z - direction.z;
+ }
+
+ return directionIn;
+ }
+ set
+ {
+
+ if (directionIn.Equals(value)) return;
+ directionIn.x = value.x;
+ directionIn.y = value.y;
+ directionIn.z = value.z;
+
+
+ // we are setting DirectionIn, but the TangentType is mirrored:
+ // we need that directionOut is altered too, with the opposite value
+
+ if (directionType == TangentType.Mirrored)
+ {
+ directionOut.x = 2 * position.x - directionIn.x;
+ directionOut.y = 2 * position.y - directionIn.y;
+ directionOut.z = 2 * position.z - directionIn.z;
+ }
+
+
+ if (Changed != null) Changed(this, EventArgs.Empty);
+ }
+ }
+
+ [SerializeField]
+ private Vector3 directionIn;
+
+
+
+
+ public Vector3 DirectionOut
+ {
+ get {
+ /*
+ * for backward compatibility:
+ * saved nodes will have direction not zero, and directionout == Vector3.zero
+ *
+ * if this situation occurs, we update directionOut
+ */
+
+ if(directionOut == Vector3.zero && direction != Vector3.zero)
+ {
+ directionOut = direction;
+ }
+
+ return directionOut;
+ }
+ set
+ {
+ if (directionOut.Equals(value)) return;
+ directionOut.x = value.x;
+ directionOut.y = value.y;
+ directionOut.z = value.z;
+
+
+ // we are setting DirectionOut, but the TangentType is mirrored:
+ // we need that directionIn is altered too, with the opposite value
+ if (directionType == TangentType.Mirrored)
+ {
+
+ directionIn.x = 2 * position.x - directionOut.x;
+ directionIn.y = 2 * position.y - directionOut.y;
+ directionIn.z = 2 * position.z - directionOut.z;
+
+ }
+
+ if (Changed != null) Changed(this, EventArgs.Empty);
+ }
+ }
+
+ [SerializeField]
+ private Vector3 directionOut;
+
+
///
/// Up vector to apply at this node.
/// Usefull to specify the orientation when the tangent blend with the world UP (gimball lock)
/// This value is not used on the spline itself but is commonly used on bended content.
///
- public Vector3 Up {
+ public Vector3 Up
+ {
get { return up; }
- set {
+ set
+ {
if (up.Equals(value)) return;
up.x = value.x;
up.y = value.y;
@@ -66,9 +201,11 @@ public Vector3 Up {
/// Scale to apply at this node.
/// This value is not used on the spline itself but is commonly used on bended content.
///
- public Vector2 Scale {
+ public Vector2 Scale
+ {
get { return scale; }
- set {
+ set
+ {
if (scale.Equals(value)) return;
scale.x = value.x;
scale.y = value.y;
@@ -82,9 +219,11 @@ public Vector2 Scale {
/// Roll to apply at this node.
/// This value is not used on the spline itself but is commonly used on bended content.
///
- public float Roll {
+ public float Roll
+ {
get { return roll; }
- set {
+ set
+ {
if (roll == value) return;
roll = value;
if (Changed != null) Changed(this, EventArgs.Empty);
@@ -93,11 +232,30 @@ public float Roll {
[SerializeField]
private float roll;
- public SplineNode(Vector3 position, Vector3 direction) {
+ public SplineNode(Vector3 position, Vector3 direction)
+ {
Position = position;
Direction = direction;
}
+ public SplineNode(Vector3 position, Vector3 new_directionOut, Vector3 new_directionIn)
+ {
+
+
+ // this causes a side effect in DirectionOut that I could not solve
+ //DirectionOut = directionOut;
+ //DirectionIn = directionIn;
+
+ directionOut = new_directionOut;
+ directionIn = new_directionIn;
+
+
+ // due to the previous issue, we set position as last item so that the event handler is notified
+ Position = position;
+
+
+ }
+
///
/// Event raised when position, direction, scale or roll changes.
///
diff --git a/Assets/SplineMesh/Scripts/Editor/SplineEditor.cs b/Assets/SplineMesh/Scripts/Editor/SplineEditor.cs
index 3e80321..caa5dd4 100644
--- a/Assets/SplineMesh/Scripts/Editor/SplineEditor.cs
+++ b/Assets/SplineMesh/Scripts/Editor/SplineEditor.cs
@@ -3,9 +3,11 @@
using UnityEditor;
using UnityEngine;
-namespace SplineMesh {
+namespace SplineMesh
+{
[CustomEditor(typeof(Spline))]
- public class SplineEditor : Editor {
+ public class SplineEditor : Editor
+ {
private const int QUAD_SIZE = 12;
private Color CURVE_COLOR = new Color(0.8f, 0.8f, 0.8f);
@@ -16,10 +18,11 @@ public class SplineEditor : Editor {
private static bool showUpVector = false;
- private enum SelectionType {
+ private enum SelectionType
+ {
Node,
- Direction,
- InverseDirection,
+ DirectionOut,
+ DirectionIn,
Up
}
@@ -31,7 +34,8 @@ private enum SelectionType {
private GUIStyle nodeButtonStyle, directionButtonStyle, upButtonStyle;
- private void OnEnable() {
+ private void OnEnable()
+ {
Texture2D t = new Texture2D(1, 1);
t.SetPixel(0, 0, CURVE_BUTTON_COLOR);
t.Apply();
@@ -50,87 +54,105 @@ private void OnEnable() {
upButtonStyle = new GUIStyle();
upButtonStyle.normal.background = t;
selection = null;
-
+
Undo.undoRedoPerformed -= spline.RefreshCurves;
Undo.undoRedoPerformed += spline.RefreshCurves;
}
- SplineNode AddClonedNode(SplineNode node) {
+ SplineNode AddClonedNode(SplineNode node)
+ {
int index = spline.nodes.IndexOf(node);
SplineNode res = new SplineNode(node.Position, node.Direction);
- if (index == spline.nodes.Count - 1) {
+ if (index == spline.nodes.Count - 1)
+ {
spline.AddNode(res);
- } else {
+ }
+ else
+ {
spline.InsertNode(index + 1, res);
}
return res;
}
- void OnSceneGUI() {
+ void OnSceneGUI()
+ {
Event e = Event.current;
- if (e.type == EventType.MouseDown) {
+ if (e.type == EventType.MouseDown)
+ {
Undo.RegisterCompleteObjectUndo(spline, "change spline topography");
// if alt key pressed, we will have to create a new node if node position is changed
- if (e.alt) {
+ if (e.alt)
+ {
mustCreateNewNode = true;
}
}
- if (e.type == EventType.MouseUp) {
+ if (e.type == EventType.MouseUp)
+ {
mustCreateNewNode = false;
}
// disable game object transform gyzmo
- // if the spline script is active
- if (Selection.activeGameObject == spline.gameObject) {
- if (!spline.enabled) {
- Tools.current = Tool.Move;
- } else {
- Tools.current = Tool.None;
- if (selection == null && spline.nodes.Count > 0)
- selection = spline.nodes[0];
- }
+ if (Selection.activeGameObject == spline.gameObject)
+ {
+ Tools.current = Tool.None;
+ if (selection == null && spline.nodes.Count > 0)
+ selection = spline.nodes[0];
}
// draw a bezier curve for each curve in the spline
- foreach (CubicBezierCurve curve in spline.GetCurves()) {
+ foreach (CubicBezierCurve curve in spline.GetCurves())
+ {
Handles.DrawBezier(spline.transform.TransformPoint(curve.n1.Position),
spline.transform.TransformPoint(curve.n2.Position),
- spline.transform.TransformPoint(curve.n1.Direction),
- spline.transform.TransformPoint(curve.GetInverseDirection()),
+ spline.transform.TransformPoint(curve.n1.DirectionOut),
+ //spline.transform.TransformPoint(curve.GetInverseDirection()), // old version, replaced by curve.n2.DirectionIn
+ spline.transform.TransformPoint(curve.n2.DirectionIn),
CURVE_COLOR,
null,
3);
}
- if (!spline.enabled)
- return;
-
// draw the selection handles
- switch (selectionType) {
+ switch (selectionType)
+ {
case SelectionType.Node:
// place a handle on the node and manage position change
Vector3 newPosition = spline.transform.InverseTransformPoint(Handles.PositionHandle(spline.transform.TransformPoint(selection.Position), Quaternion.identity));
- if (newPosition != selection.Position) {
+ if (newPosition != selection.Position)
+ {
// position handle has been moved
- if (mustCreateNewNode) {
+ if (mustCreateNewNode)
+ {
mustCreateNewNode = false;
selection = AddClonedNode(selection);
selection.Direction += newPosition - selection.Position;
selection.Position = newPosition;
- } else {
+ }
+ else
+ {
selection.Direction += newPosition - selection.Position;
selection.Position = newPosition;
}
}
break;
- case SelectionType.Direction:
- var result = Handles.PositionHandle(spline.transform.TransformPoint(selection.Direction), Quaternion.identity);
- selection.Direction = spline.transform.InverseTransformPoint(result);
+ case SelectionType.DirectionOut:
+
+
+ // default scenario, the handle is positioned directly on selection.DirectionOut
+ Vector3 directionOutHandlePosition = selection.DirectionOut;
+
+
+ //var directionOutResult = Handles.PositionHandle(spline.transform.TransformPoint(directionOutHandlePosition), Quaternion.identity);
+ var directionOutResult = Handles.PositionHandle(spline.transform.TransformPoint(directionOutHandlePosition), Quaternion.identity);
+ selection.DirectionOut = spline.transform.InverseTransformPoint(directionOutResult);
break;
- case SelectionType.InverseDirection:
- result = Handles.PositionHandle(2 * spline.transform.TransformPoint(selection.Position) - spline.transform.TransformPoint(selection.Direction), Quaternion.identity);
- selection.Direction = 2 * selection.Position - spline.transform.InverseTransformPoint(result);
+
+
+ case SelectionType.DirectionIn:
+ var result = Handles.PositionHandle(spline.transform.TransformPoint(selection.DirectionIn), Quaternion.identity);
+ selection.DirectionIn = spline.transform.InverseTransformPoint(result);
break;
+
case SelectionType.Up:
result = Handles.PositionHandle(spline.transform.TransformPoint(selection.Position + selection.Up), Quaternion.LookRotation(selection.Direction - selection.Position));
selection.Up = (spline.transform.InverseTransformPoint(result) - selection.Position).normalized;
@@ -139,56 +161,87 @@ void OnSceneGUI() {
// draw the handles of all nodes, and manage selection motion
Handles.BeginGUI();
- foreach (SplineNode n in spline.nodes) {
- var dir = spline.transform.TransformPoint(n.Direction);
+ foreach (SplineNode n in spline.nodes)
+ {
+ //var dir = spline.transform.TransformPoint(n.Direction);
+
+ var dirIn = spline.transform.TransformPoint(n.DirectionIn);
+ var dirOut = spline.transform.TransformPoint(n.DirectionOut);
+
+
+
var pos = spline.transform.TransformPoint(n.Position);
- var invDir = spline.transform.TransformPoint(2 * n.Position - n.Direction);
+ //var invDir = spline.transform.TransformPoint(2 * n.Position - n.Direction);
+ var invDir = spline.transform.TransformPoint(2 * n.Position - n.DirectionOut);
var up = spline.transform.TransformPoint(n.Position + n.Up);
// first we check if at least one thing is in the camera field of view
if (!(CameraUtility.IsOnScreen(pos) ||
- CameraUtility.IsOnScreen(dir) ||
- CameraUtility.IsOnScreen(invDir) ||
- (showUpVector && CameraUtility.IsOnScreen(up)))) {
+ CameraUtility.IsOnScreen(dirIn) ||
+ CameraUtility.IsOnScreen(dirOut) ||
+ // CameraUtility.IsOnScreen(invDir) ||
+ (showUpVector && CameraUtility.IsOnScreen(up))))
+ {
continue;
}
Vector3 guiPos = HandleUtility.WorldToGUIPoint(pos);
- if (n == selection) {
- Vector3 guiDir = HandleUtility.WorldToGUIPoint(dir);
- Vector3 guiInvDir = HandleUtility.WorldToGUIPoint(invDir);
+ if (n == selection)
+ {
+ Vector3 guiDirIn = HandleUtility.WorldToGUIPoint(dirIn);
+ Vector3 guiDirOut = HandleUtility.WorldToGUIPoint(dirOut);
+ //Vector3 guiInvDir = HandleUtility.WorldToGUIPoint(invDir);
Vector3 guiUp = HandleUtility.WorldToGUIPoint(up);
// for the selected node, we also draw a line and place two buttons for directions
Handles.color = DIRECTION_COLOR;
- Handles.DrawLine(guiDir, guiInvDir);
+ //Handles.DrawLine(guiDir, guiInvDir);
+ Handles.DrawLine(guiDirIn, guiPos);
+ Handles.DrawLine(guiDirOut, guiPos);
+
// draw quads direction and inverse direction if they are not selected
- if (selectionType != SelectionType.Node) {
- if (Button(guiPos, directionButtonStyle)) {
+ if (selectionType != SelectionType.Node)
+ {
+ if (Button(guiPos, directionButtonStyle))
+ {
selectionType = SelectionType.Node;
}
}
- if (selectionType != SelectionType.Direction) {
- if (Button(guiDir, directionButtonStyle)) {
- selectionType = SelectionType.Direction;
+
+ if (selectionType != SelectionType.DirectionOut)
+ {
+ if (Button(guiDirOut, directionButtonStyle))
+ {
+ selectionType = SelectionType.DirectionOut;
}
}
- if (selectionType != SelectionType.InverseDirection) {
- if (Button(guiInvDir, directionButtonStyle)) {
- selectionType = SelectionType.InverseDirection;
+
+
+
+ if (selectionType != SelectionType.DirectionIn)
+ {
+ if (Button(guiDirIn, directionButtonStyle))
+ {
+ selectionType = SelectionType.DirectionIn;
}
}
- if (showUpVector) {
+ if (showUpVector)
+ {
Handles.color = Color.green;
Handles.DrawLine(guiPos, guiUp);
- if (selectionType != SelectionType.Up) {
- if (Button(guiUp, upButtonStyle)) {
+ if (selectionType != SelectionType.Up)
+ {
+ if (Button(guiUp, upButtonStyle))
+ {
selectionType = SelectionType.Up;
}
}
}
- } else {
- if (Button(guiPos, nodeButtonStyle)) {
+ }
+ else
+ {
+ if (Button(guiPos, nodeButtonStyle))
+ {
selection = n;
selectionType = SelectionType.Node;
}
@@ -200,30 +253,39 @@ void OnSceneGUI() {
EditorUtility.SetDirty(target);
}
- bool Button(Vector2 position, GUIStyle style) {
+ bool Button(Vector2 position, GUIStyle style)
+ {
return GUI.Button(new Rect(position - new Vector2(QUAD_SIZE / 2, QUAD_SIZE / 2), new Vector2(QUAD_SIZE, QUAD_SIZE)), GUIContent.none, style);
}
- public override void OnInspectorGUI() {
+ public override void OnInspectorGUI()
+ {
serializedObject.Update();
// hint
EditorGUILayout.HelpBox("Hold Alt and drag a node to create a new one.", MessageType.Info);
- if(spline.nodes.IndexOf(selection) < 0) {
+ if (spline.nodes.IndexOf(selection) < 0)
+ {
selection = null;
}
// add button
- if (selection == null) {
+ if (selection == null)
+ {
GUI.enabled = false;
}
- if (GUILayout.Button("Add node after selected")) {
+ if (GUILayout.Button("Add node after selected"))
+ {
Undo.RecordObject(spline, "add spline node");
+
SplineNode newNode = new SplineNode(selection.Direction, selection.Direction + selection.Direction - selection.Position);
var index = spline.nodes.IndexOf(selection);
- if(index == spline.nodes.Count - 1) {
+ if (index == spline.nodes.Count - 1)
+ {
spline.AddNode(newNode);
- } else {
+ }
+ else
+ {
spline.InsertNode(index + 1, newNode);
}
selection = newNode;
@@ -232,10 +294,12 @@ public override void OnInspectorGUI() {
GUI.enabled = true;
// delete button
- if (selection == null || spline.nodes.Count <= 2) {
+ if (selection == null || spline.nodes.Count <= 2)
+ {
GUI.enabled = false;
}
- if (GUILayout.Button("Delete selected node")) {
+ if (GUILayout.Button("Delete selected node"))
+ {
Undo.RecordObject(spline, "delete spline node");
spline.RemoveNode(selection);
selection = null;
@@ -249,12 +313,15 @@ public override void OnInspectorGUI() {
// nodes
EditorGUILayout.PropertyField(nodesProp);
EditorGUI.indentLevel++;
- if (nodesProp.isExpanded) {
- for (int i = 0; i < nodesProp.arraySize; i++) {
+ if (nodesProp.isExpanded)
+ {
+ for (int i = 0; i < nodesProp.arraySize; i++)
+ {
SerializedProperty nodeProp = nodesProp.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(nodeProp);
EditorGUI.indentLevel++;
- if (nodeProp.isExpanded) {
+ if (nodeProp.isExpanded)
+ {
drawNodeData(nodeProp, spline.nodes[i]);
}
EditorGUI.indentLevel--;
@@ -262,62 +329,113 @@ public override void OnInspectorGUI() {
}
EditorGUI.indentLevel--;
- if (selection != null) {
+ if (selection != null)
+ {
int index = spline.nodes.IndexOf(selection);
SerializedProperty nodeProp = nodesProp.GetArrayElementAtIndex(index);
EditorGUILayout.LabelField("Selected node (node " + index + ")");
EditorGUI.indentLevel++;
drawNodeData(nodeProp, selection);
EditorGUI.indentLevel--;
- } else {
+ }
+ else
+ {
EditorGUILayout.LabelField("No selected node");
}
}
- private void drawNodeData(SerializedProperty nodeProperty, SplineNode node) {
- using (var check = new EditorGUI.ChangeCheckScope()) {
+ private void drawNodeData(SerializedProperty nodeProperty, SplineNode node)
+ {
+ using (var check = new EditorGUI.ChangeCheckScope())
+ {
var positionProp = nodeProperty.FindPropertyRelative("position");
EditorGUILayout.PropertyField(positionProp, new GUIContent("Position"));
- if (check.changed) {
+ if (check.changed)
+ {
node.Position = positionProp.vector3Value;
}
}
- using (var check = new EditorGUI.ChangeCheckScope()) {
- var directionProp = nodeProperty.FindPropertyRelative("direction");
- EditorGUILayout.PropertyField(directionProp, new GUIContent("Direction"));
- if (check.changed) {
- node.Direction = directionProp.vector3Value;
+ using (var check = new EditorGUI.ChangeCheckScope())
+ {
+ var directionTypeProp = nodeProperty.FindPropertyRelative("directionType");
+ EditorGUILayout.PropertyField(directionTypeProp, new GUIContent("Direction Type"));
+ if (check.changed)
+ {
+ node.DirectionType = (SplineNode.TangentType)directionTypeProp.enumValueIndex;
+ }
+ }
+
+
+ // hidden, to use DirectionIn and DirectionOut
+ //using (var check = new EditorGUI.ChangeCheckScope())
+ //{
+ // var directionProp = nodeProperty.FindPropertyRelative("direction");
+ // EditorGUILayout.PropertyField(directionProp, new GUIContent("Direction"));
+ // if (check.changed)
+ // {
+ // node.Direction = directionProp.vector3Value;
+ // }
+ //}
+
+ if (true || node.directionType != SplineNode.TangentType.Mirrored)
+ {
+
+ using (var check = new EditorGUI.ChangeCheckScope())
+ {
+ var directionInProp = nodeProperty.FindPropertyRelative("directionIn");
+ EditorGUILayout.PropertyField(directionInProp, new GUIContent("DirectionIn"));
+ if (check.changed)
+ {
+ node.DirectionIn = directionInProp.vector3Value;
+ }
+ }
+ }
+
+ using (var check = new EditorGUI.ChangeCheckScope())
+ {
+ var directionOutProp = nodeProperty.FindPropertyRelative("directionOut");
+ EditorGUILayout.PropertyField(directionOutProp, new GUIContent("DirectionOut"));
+ if (check.changed)
+ {
+ node.DirectionOut = directionOutProp.vector3Value;
}
}
- using (var check = new EditorGUI.ChangeCheckScope()) {
+ using (var check = new EditorGUI.ChangeCheckScope())
+ {
var upProp = nodeProperty.FindPropertyRelative("up");
EditorGUILayout.PropertyField(upProp, new GUIContent("Up"));
- if (check.changed) {
+ if (check.changed)
+ {
node.Up = upProp.vector3Value;
}
}
- using (var check = new EditorGUI.ChangeCheckScope()) {
+ using (var check = new EditorGUI.ChangeCheckScope())
+ {
var scaleProp = nodeProperty.FindPropertyRelative("scale");
EditorGUILayout.PropertyField(scaleProp, new GUIContent("Scale"));
- if (check.changed) {
+ if (check.changed)
+ {
node.Scale = scaleProp.vector2Value;
}
}
- using (var check = new EditorGUI.ChangeCheckScope()) {
+ using (var check = new EditorGUI.ChangeCheckScope())
+ {
var rollProp = nodeProperty.FindPropertyRelative("roll");
EditorGUILayout.PropertyField(rollProp, new GUIContent("Roll"));
- if (check.changed) {
+ if (check.changed)
+ {
node.Roll = rollProp.floatValue;
}
}
}
[MenuItem("GameObject/3D Object/Spline")]
- public static void CreateSpline() {
+ public static void CreateSpline()
+ {
new GameObject("Spline", typeof(Spline));
}
}