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