private void _AddPoint(CatmullRomUniform spline) { MUndo.RecordObject(target, "add point"); MUndo.RecordObject(this, "add point"); if (m_curPtIdx < 0) { m_curPtIdx = spline.PointCount - 1; } if (m_curPtIdx != spline.PointCount - 1) { float v = (float)m_curPtIdx + 0.5f; Vector3 newPos = spline.Interp(v / (spline.PointCount - 1)); spline.InsertPointAfter(m_curPtIdx, newPos); } else { float unitLen = spline.CurveLength / (spline.PointCount - 1); Vector3 dir = spline.Tangent(1f); spline.InsertPointAfter(m_curPtIdx, spline[m_curPtIdx] + dir * unitLen); } m_curPtIdx++; }
private void DrawHandles(CatmullRomUniform spline, Transform tr) { if (m_curPtIdx >= 0 && m_curPtIdx < spline.PointCount) { Tools.current = Tool.None; } else { m_curPtIdx = -1; return; } Event e = Event.current; if (e.keyCode == KeyCode.Escape && e.rawType == EventType.KeyDown) { m_curPtIdx = -1; return; } Vector3 pt = tr.TransformPoint(spline[m_curPtIdx]); pt = Handles.PositionHandle(pt, Quaternion.identity); if (GUI.changed) { MUndo.RecordObject(target, "move point"); spline[m_curPtIdx] = tr.InverseTransformPoint(pt); } }
/// <summary> /// 1. draw spline /// 2. draw points /// 3. draw handles /// </summary> public void OnSceneGUI() { CatmullRomUniformBehaviour behaviour = (CatmullRomUniformBehaviour)target; CatmullRomUniform spline = (CatmullRomUniform)behaviour.Spline; Transform tr = behaviour.transform; DrawSpline(spline, tr); if (!ms_isMultiEdit) { DrawPoints(spline, tr); DrawHandles(spline, tr); // prevent de-selection by clicking EUtil.SceneViewPreventDeselecByClick(m_curPtIdx >= 0); // shortcut Event e = Event.current; switch (e.type) { case EventType.KeyUp: { if (e.keyCode == KeyCode.X) { if (m_curPtIdx >= 0) { _DelPoint(spline); } } else if (e.keyCode == KeyCode.I) { if (m_curPtIdx < 0) { m_curPtIdx = spline.PointCount - 1; } _AddPoint(spline); } else if (e.keyCode == KeyCode.C) { if (m_curPtIdx >= 0) { EUtil.SceneViewLookAt(tr.TransformPoint(spline[m_curPtIdx]), ms_lookAtDist); } } } break; } } }
private void _ToggleCycle(CatmullRomUniform spline) { if (!spline.Cycle && spline.PointCount < 3) { EUtil.ShowNotification("Need at least 3 points to make cycle"); return; } spline.Cycle = !spline.Cycle; if (m_curPtIdx >= spline.PointCount) { m_curPtIdx = spline.PointCount - 1; } }
private void DrawPoints(CatmullRomUniform spline, Transform tr) { if (!ms_drawPts) { return; } Camera sceneViewCam = Camera.current; Transform camTr = sceneViewCam.transform; // draw point and selection EUtil.PushHandleColor(SplineConst.SplinePtColor); for (int i = 0; i < spline.PointCount; ++i) { if (spline.Cycle && i == spline.PointCount - 1) //don't draw button for last point if is cycle { continue; } bool isSelPoint = false; if (i == m_curPtIdx) { isSelPoint = true; EUtil.PushHandleColor(Handles.selectedColor); } Vector3 pt = tr.TransformPoint(spline[i]); if (Handles.Button(pt, camTr.rotation, ms_ptSize, ms_ptSize, Handles.DotCap)) { m_curPtIdx = i; Repaint(); } if (isSelPoint) { EUtil.PopHandleColor(); } } EUtil.PopHandleColor(); if (ms_foldoutTSlider) { Vector3 tPos = tr.TransformPoint(spline.Interp(m_tSlider)); Handles.CircleCap(GUIUtility.GetControlID(FocusType.Passive), tPos, camTr.rotation, ms_ptSize); } }
public static void DrawSpline(CatmullRomUniform spline, Transform owner) { List <Vector3> interPts = spline.InterPoints; List <Vector3> tangents = spline.InterTangents; List <Vector3> ups = spline.InterUps; Vector3 p0, p1; Vector3 prevBino = Vector3.right; p0 = owner.TransformPoint(interPts[0]); for (int i = 0; i < interPts.Count; ++i) { Vector3 tan = owner.TransformDirection(tangents[i]).normalized; Vector3 up = owner.TransformDirection(ups[i]).normalized; Vector3 bino = Vector3.Cross(up, tan).normalized; if (bino == Vector3.zero) { bino = prevBino; } else { prevBino = bino; } if (ms_drawArrow) { Handles.DrawLine(p0, p0 + (bino - tan) * ms_arrowLineLen); Handles.DrawLine(p0, p0 - (bino + tan) * ms_arrowLineLen); } if (ms_drawUp) { Handles.DrawLine(p0, p0 + up * ms_arrowLineLen); } if (i + 1 < interPts.Count) { p1 = owner.TransformPoint(interPts[i + 1]); Handles.DrawLine(p0, p1); p0 = p1; } } }
private void _OnUndoRedo() { CatmullRomUniformBehaviour behaviour = (CatmullRomUniformBehaviour)target; if (behaviour == null) { Undo.undoRedoPerformed -= _OnUndoRedo; return; } CatmullRomUniform spline = (CatmullRomUniform)behaviour.Spline; if (spline == null) { Undo.undoRedoPerformed -= _OnUndoRedo; return; } spline.SetDirty(); }
private void _DelPoint(CatmullRomUniform spline) { if (spline.PointCount <= 2) { EUtil.ShowNotification("The spline needs at least 2 points"); return; } if (spline.Cycle && spline.PointCount <= 4) { EUtil.ShowNotification("Cannot delete any points to maintain cycle"); return; } if (m_curPtIdx < 0) { return; } MUndo.RecordObject(target, "del point"); MUndo.RecordObject(this, "del point"); spline.RemovePoint(m_curPtIdx); m_curPtIdx = Mathf.Min(spline.PointCount - 1, m_curPtIdx); }
public override void OnInspectorGUI() { if (targets.Length > 1) { EditorGUILayout.HelpBox("Cannot edit multiple spline together", MessageType.Info, true); ms_isMultiEdit = true; return; } else { ms_isMultiEdit = false; } CatmullRomUniformBehaviour behaviour = (CatmullRomUniformBehaviour)target; CatmullRomUniform spline = (CatmullRomUniform)behaviour.Spline; GUILayout.Space(5f); EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button(new GUIContent("Add Point", "hotkey: I"), EditorStyles.toolbarButton)) { _AddPoint(spline); } if (GUILayout.Button(new GUIContent("Del Point", "hotkey: X"), EditorStyles.toolbarButton)) { _DelPoint(spline); } if (GUILayout.Button(spline.Cycle ? "Break Cycle" : "Make Cycle", EditorStyles.toolbarButton)) { _ToggleCycle(spline); } } EditorGUILayout.EndHorizontal(); GUILayout.Space(5f); if (m_curPtIdx >= 0) { EditorGUILayout.BeginHorizontal(); { MUndo.RecordObject(this, "change current point"); GUILayout.Label("Current Point"); if (GUILayout.Button("<<")) { m_curPtIdx = Mathf.Max(0, m_curPtIdx - 1); } EditorGUI.BeginChangeCheck(); m_curPtIdx = EditorGUILayout.IntField(m_curPtIdx); if (EditorGUI.EndChangeCheck()) { m_curPtIdx = Mathf.Clamp(m_curPtIdx, 0, spline.PointCount); } GUILayout.Label(" / " + (spline.PointCount - 1)); if (GUILayout.Button(">>")) { m_curPtIdx = Mathf.Min(m_curPtIdx + 1, spline.PointCount - 1); } } EditorGUILayout.EndHorizontal(); MUndo.RecordObject(target, "modify control point"); EUtil.PushLabelWidth(80f); spline[m_curPtIdx] = EUtil.DrawV3P(new GUIContent("Position"), spline[m_curPtIdx]); spline.SetTilt(m_curPtIdx, EditorGUILayout.FloatField("Tilt", spline.GetTilt(m_curPtIdx))); EUtil.PopLabelWidth(); } ms_foldoutSettings = EditorGUILayout.Foldout(ms_foldoutSettings, "Settings"); if (ms_foldoutSettings) { MUndo.RecordObject(this, "change setting"); spline.Resolution = EditorGUILayout.IntField("Point/Seg", spline.Resolution); spline.TwistMtd = (ETwistMethod)EditorGUILayout.EnumPopup(new GUIContent("Twist Method", "Decide how to calculate the base-up direction before applying tilt"), spline.TwistMtd); ms_drawArrow = EditorGUILayout.Toggle("Draw Arrow", ms_drawArrow); ms_drawUp = EditorGUILayout.Toggle("Draw Up", ms_drawUp); ms_arrowLineLen = EditorGUILayout.FloatField("Arrow LineLen", ms_arrowLineLen); ms_drawPts = EditorGUILayout.Toggle("Draw points", ms_drawPts); ms_ptSize = EditorGUILayout.FloatField("Point size", ms_ptSize); ms_lookAtDist = EditorGUILayout.FloatField(new GUIContent("LookAt dist", "the distance from camera to target point when camera in follow mode"), ms_lookAtDist); } ms_foldoutTSlider = EditorGUILayout.Foldout(ms_foldoutTSlider, "T slider"); if (ms_foldoutTSlider) { EditorGUI.BeginChangeCheck(); EUtil.PushLabelWidth(20f); m_tSlider = EditorGUILayout.Slider("T", m_tSlider, 0, 1f); EUtil.PopLabelWidth(); if (EditorGUI.EndChangeCheck()) { //Transform tr = behaviour.transform; EUtil.SceneViewLookAt( behaviour.GetTransformedPosition(m_tSlider), Quaternion.LookRotation(behaviour.GetTransformedTangent(m_tSlider), behaviour.GetTransformedUp(m_tSlider)), ms_lookAtDist); } } if (GUI.changed) { EUtil.RepaintSceneView(); } }