private void HandleSelectedSegmentModifications() { if (selectedSegmentIndex < 0 || selectedSegmentIndex >= water.Spline.Segments.Count) { return; } if (!water.Spline.IsSegmentValid(selectedSegmentIndex)) { return; } PSplineSegment segment = water.Spline.Segments[selectedSegmentIndex]; PSplineAnchor startAnchor = water.Spline.Anchors[segment.StartIndex]; PSplineAnchor endAnchor = water.Spline.Anchors[segment.EndIndex]; Vector3 worldStartPosition = water.transform.TransformPoint(startAnchor.Position); Vector3 worldEndPosition = water.transform.TransformPoint(endAnchor.Position); Vector3 worldStartTangent = water.transform.TransformPoint(segment.StartTangent); Vector3 worldEndTangent = water.transform.TransformPoint(segment.EndTangent); EditorGUI.BeginChangeCheck(); Handles.zTest = UnityEngine.Rendering.CompareFunction.Always; worldStartTangent = Handles.PositionHandle(worldStartTangent, Quaternion.identity); worldEndTangent = Handles.PositionHandle(worldEndTangent, Quaternion.identity); segment.StartTangent = water.transform.InverseTransformPoint(worldStartTangent); segment.EndTangent = water.transform.InverseTransformPoint(worldEndTangent); if (EditorGUI.EndChangeCheck()) { water.GenerateSplineMeshAtSegment(selectedSegmentIndex); } Handles.color = Color.white; Handles.DrawLine(worldStartPosition, worldStartTangent); Handles.DrawLine(worldEndPosition, worldEndTangent); }
public void RemoveAnchor(int index) { PSplineAnchor a = Anchors[index]; List <int> segmentIndices = FindSegments(index); for (int i = 0; i < segmentIndices.Count; ++i) { int sIndex = segmentIndices[i]; Segments[sIndex].Dispose(); } Segments.RemoveAll(s => s.StartIndex == index || s.EndIndex == index); Segments.ForEach(s => { if (s.StartIndex > index) { s.StartIndex -= 1; } if (s.EndIndex > index) { s.EndIndex -= 1; } }); Anchors.RemoveAt(index); }
public Vector3 EvaluateScale(int segmentIndex, float t) { PSplineSegment s = Segments[segmentIndex]; PSplineAnchor startAnchor = Anchors[s.StartIndex]; PSplineAnchor endAnchor = Anchors[s.EndIndex]; return(Vector3.Lerp(startAnchor.Scale, endAnchor.Scale, t)); }
public Quaternion EvaluateRotation(int segmentIndex, float t) { PSplineSegment s = Segments[segmentIndex]; PSplineAnchor startAnchor = Anchors[s.StartIndex]; PSplineAnchor endAnchor = Anchors[s.EndIndex]; return(Quaternion.Lerp(startAnchor.Rotation, endAnchor.Rotation, t)); }
private void HandleAddAnchor() { bool isLeftMouseUp = Event.current.type == EventType.MouseUp && Event.current.button == 0; bool isShift = Event.current.shift; if (!isLeftMouseUp) { return; } int raycastLayer = PSplineToolConfig.Instance.RaycastLayer; Ray r = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); RaycastHit hit; if (Physics.Raycast(r, out hit, 10000, LayerMask.GetMask(LayerMask.LayerToName(raycastLayer)))) { if (!isShift) { selectedAnchorIndex = -1; return; } Vector3 offset = Vector3.up * PSplineToolConfig.Instance.YOffset; Vector3 worldPos = hit.point + offset; Vector3 localPos = water.transform.InverseTransformPoint(worldPos); PSplineAnchor a = new PSplineAnchor(localPos); water.Spline.AddAnchor(a); if (selectedAnchorIndex >= 0 && selectedAnchorIndex < water.Spline.Anchors.Count - 1) { water.Spline.AddSegment(selectedAnchorIndex, water.Spline.Anchors.Count - 1); if (PSplineToolConfig.Instance.AutoTangent) { int[] segmentIndices = water.Spline.SmoothTangents(selectedAnchorIndex, water.Spline.Anchors.Count - 1); water.GenerateSplineMeshAtSegments(segmentIndices); } else { water.GenerateSplineMeshAtSegment(water.Spline.Segments.Count - 1); } } selectedAnchorIndex = water.Spline.Anchors.Count - 1; Event.current.Use(); } else { selectedAnchorIndex = -1; } }
public Vector3 EvaluatePosition(int segmentIndex, float t) { PSplineSegment s = Segments[segmentIndex]; PSplineAnchor startAnchor = Anchors[s.StartIndex]; PSplineAnchor endAnchor = Anchors[s.EndIndex]; Vector3 p0 = startAnchor.Position; Vector3 p1 = s.StartTangent; Vector3 p2 = s.EndTangent; Vector3 p3 = endAnchor.Position; t = Mathf.Clamp01(t); float oneMinusT = 1 - t; Vector3 p = oneMinusT * oneMinusT * oneMinusT * p0 + 3 * oneMinusT * oneMinusT * t * p1 + 3 * oneMinusT * t * t * p2 + t * t * t * p3; return(p); }
public override void Apply() { if (SplineCreator == null && Water == null) { return; } if (Water.MeshType != PWaterMeshType.Spline) { return; } GSpline gSpline = SplineCreator.Spline; PSpline pSpline = Water.Spline; pSpline.Dispose(); pSpline.Anchors.Clear(); pSpline.Segments.Clear(); for (int i = 0; i < gSpline.Anchors.Count; ++i) { PSplineAnchor a = (PSplineAnchor)gSpline.Anchors[i]; a.Position += Vector3.up * HeightOffset; pSpline.Anchors.Add(a); } for (int i = 0; i < gSpline.Segments.Count; ++i) { PSplineSegment s = (PSplineSegment)gSpline.Segments[i]; s.StartTangent += Vector3.up * HeightOffset; s.EndTangent += Vector3.up * HeightOffset; pSpline.Segments.Add(s); } Water.transform.position = transform.position; Water.transform.rotation = transform.rotation; Water.transform.localScale = transform.localScale; Water.SplineWidth = SplineCreator.Width + SplineCreator.FalloffWidth * 2; Water.GenerateSplineMesh(); Water.ReCalculateBounds(); }
private void DrawSelectedAnchorGUI() { int anchorIndex = splineEditingGUIDrawer.selectedAnchorIndex; if (anchorIndex < 0 || anchorIndex >= water.Spline.Anchors.Count) { return; } string label = "Selected Anchor"; string id = "poseidon-selected-anchor"; PEditorCommon.Foldout(label, true, id, () => { EditorGUI.indentLevel -= 1; PSplineAnchor a = water.Spline.Anchors[anchorIndex]; EditorGUI.BeginChangeCheck(); a.Position = PEditorCommon.InlineVector3Field("Position", a.Position); a.Rotation = Quaternion.Euler(PEditorCommon.InlineVector3Field("Rotation", a.Rotation.eulerAngles)); a.Scale = PEditorCommon.InlineVector3Field("Scale", a.Scale); water.Spline.Anchors[anchorIndex] = a; if (EditorGUI.EndChangeCheck()) { if (PSplineToolConfig.Instance.AutoTangent) { int[] segmentIndices = water.Spline.SmoothTangents(anchorIndex); water.GenerateSplineMeshAtSegments(segmentIndices); } else { List <int> segmentIndices = water.Spline.FindSegments(anchorIndex); water.GenerateSplineMeshAtSegments(segmentIndices); } } EditorGUI.indentLevel += 1; }); }
public PSplineSegment AddSegment(int startIndex, int endIndex) { PSplineSegment s = Segments.Find(s0 => (s0.StartIndex == startIndex && s0.EndIndex == endIndex) || (s0.StartIndex == endIndex && s0.EndIndex == startIndex)); if (s != null) { return(s); } PSplineSegment newSegment = new PSplineSegment(); newSegment.StartIndex = startIndex; newSegment.EndIndex = endIndex; Segments.Add(newSegment); PSplineAnchor startAnchor = Anchors[newSegment.StartIndex]; PSplineAnchor endAnchor = Anchors[newSegment.EndIndex]; Vector3 direction = (endAnchor.Position - startAnchor.Position).normalized; float length = (endAnchor.Position - startAnchor.Position).magnitude / 3; newSegment.StartTangent = startAnchor.Position + direction * length; newSegment.EndTangent = endAnchor.Position - direction * length; return(newSegment); }
private void HandleSelectTransformRemoveAnchor() { List <PSplineAnchor> anchors = water.Spline.Anchors; for (int i = 0; i < anchors.Count; ++i) { PSplineAnchor a = anchors[i]; Vector3 localPos = a.Position; Vector3 worldPos = water.transform.TransformPoint(localPos); float handleSize = HandleUtility.GetHandleSize(worldPos) * 0.2f; if (i == selectedAnchorIndex) { Handles.color = Handles.selectedColor; Handles.SphereHandleCap(0, worldPos, Quaternion.identity, handleSize, EventType.Repaint); bool isGlobalRotation = Tools.pivotRotation == PivotRotation.Global; EditorGUI.BeginChangeCheck(); if (Tools.current == Tool.Move) { worldPos = Handles.PositionHandle(worldPos, isGlobalRotation ? Quaternion.identity : a.Rotation); localPos = water.transform.InverseTransformPoint(worldPos); a.Position = localPos; } else if (Tools.current == Tool.Rotate && !PSplineToolConfig.Instance.AutoTangent) { a.Rotation = Handles.RotationHandle(a.Rotation, worldPos); } else if (Tools.current == Tool.Scale) { a.Scale = Handles.ScaleHandle(a.Scale, worldPos, isGlobalRotation ? Quaternion.identity : a.Rotation, HandleUtility.GetHandleSize(worldPos)); } anchors[i] = a; if (EditorGUI.EndChangeCheck()) { if (PSplineToolConfig.Instance.AutoTangent) { water.Spline.SmoothTangents(selectedAnchorIndex); } List <int> segmentIndices = water.Spline.FindSegments(selectedAnchorIndex); water.GenerateSplineMeshAtSegments(segmentIndices); } } else { Handles.color = Color.cyan; if (Handles.Button(worldPos, Quaternion.identity, handleSize, handleSize * 0.5f, Handles.SphereHandleCap)) { if (Event.current.control) { selectedAnchorIndex = -1; selectedSegmentIndex = -1; water.Spline.RemoveAnchor(i); } else if (Event.current.shift) { if (selectedAnchorIndex != i && selectedAnchorIndex >= 0 && selectedAnchorIndex < anchors.Count) { water.Spline.AddSegment(selectedAnchorIndex, i); if (PSplineToolConfig.Instance.AutoTangent) { int[] segmentsIndices = water.Spline.SmoothTangents(selectedAnchorIndex, i); water.GenerateSplineMeshAtSegments(segmentsIndices); } else { water.GenerateSplineMeshAtSegment(water.Spline.Segments.Count - 1); } selectedAnchorIndex = i; selectedSegmentIndex = -1; } } else { selectedAnchorIndex = i; selectedSegmentIndex = -1; } Event.current.Use(); } } } }
private void HandleSelectTransformRemoveSegment() { List <PSplineSegment> segments = water.Spline.Segments; List <PSplineAnchor> anchors = water.Spline.Anchors; for (int i = 0; i < segments.Count; ++i) { if (!water.Spline.IsSegmentValid(i)) { continue; } if (i == selectedSegmentIndex && !PSplineToolConfig.Instance.AutoTangent) { HandleSelectedSegmentModifications(); } int i0 = segments[i].StartIndex; int i1 = segments[i].EndIndex; PSplineAnchor a0 = anchors[i0]; PSplineAnchor a1 = anchors[i1]; Vector3 startPosition = water.transform.TransformPoint(a0.Position); Vector3 endPosition = water.transform.TransformPoint(a1.Position); Vector3 startTangent = water.transform.TransformPoint(segments[i].StartTangent); Vector3 endTangent = water.transform.TransformPoint(segments[i].EndTangent); Color color = (i == selectedSegmentIndex) ? Handles.selectedColor : Color.white; Color colorFade = new Color(color.r, color.g, color.b, color.a * 0.1f); Vector3[] bezierPoints = Handles.MakeBezierPoints(startPosition, endPosition, startTangent, endTangent, 11); Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual; Handles.color = color; Handles.DrawAAPolyLine(BEZIER_WIDTH, bezierPoints); Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater; Handles.color = colorFade; Handles.DrawAAPolyLine(BEZIER_WIDTH, bezierPoints); Matrix4x4 localToWorld = water.transform.localToWorldMatrix; Matrix4x4 splineToLocal = water.Spline.TRS(i, 0.5f); Matrix4x4 splineToWorld = localToWorld * splineToLocal; Vector3 arrow0 = splineToWorld.MultiplyPoint(Vector3.zero); splineToLocal = water.Spline.TRS(i, 0.45f); splineToWorld = localToWorld * splineToLocal; Vector3 arrow1 = splineToWorld.MultiplyPoint(Vector3.left * 0.5f); Vector3 arrow2 = splineToWorld.MultiplyPoint(Vector3.right * 0.5f); Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual; Handles.color = color; Handles.DrawAAPolyLine(BEZIER_WIDTH, arrow1, arrow0, arrow2); Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater; Handles.color = colorFade; Handles.DrawAAPolyLine(BEZIER_WIDTH, arrow1, arrow0, arrow2); if (Event.current.type == EventType.MouseUp && Event.current.button == 0) { float d0 = DistanceMouseToSpline(Event.current.mousePosition, bezierPoints); float d1 = DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[0]); float d2 = DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[bezierPoints.Length - 1]); if (d0 <= BEZIER_SELECT_DISTANCE && d1 > BEZIER_SELECT_DISTANCE && d2 > BEZIER_SELECT_DISTANCE) { selectedSegmentIndex = i; if (Event.current.control) { water.Spline.RemoveSegment(selectedSegmentIndex); selectedSegmentIndex = -1; GUI.changed = true; } //don't Use() the event here } else { if (selectedSegmentIndex == i) { selectedSegmentIndex = -1; } } } } Handles.zTest = UnityEngine.Rendering.CompareFunction.Always; }
public void AddAnchor(PSplineAnchor a) { Anchors.Add(a); }
public int[] SmoothTangents(params int[] anchorIndices) { int[] anchorRanks = new int[Anchors.Count]; Vector3[] directions = new Vector3[Anchors.Count]; float[] segmentLengths = new float[Segments.Count]; for (int i = 0; i < Segments.Count; ++i) { PSplineSegment s = Segments[i]; anchorRanks[s.StartIndex] += 1; anchorRanks[s.EndIndex] += 1; PSplineAnchor aStart = Anchors[s.StartIndex]; PSplineAnchor aEnd = Anchors[s.EndIndex]; Vector3 startToEnd = aEnd.Position - aStart.Position; Vector3 d = Vector3.Normalize(startToEnd); directions[s.StartIndex] += d; directions[s.EndIndex] += d; segmentLengths[i] = startToEnd.magnitude; } for (int i = 0; i < directions.Length; ++i) { if (anchorRanks[i] == 0) { continue; } directions[i] = Vector3.Normalize(directions[i] / anchorRanks[i]); } if (anchorIndices == null || anchorIndices.Length == 0) { anchorIndices = PUtilities.GetIndicesArray(Anchors.Count); } for (int i = 0; i < anchorIndices.Length; ++i) { int index = anchorIndices[i]; if (anchorRanks[index] > 0) { Quaternion rot = Quaternion.LookRotation(directions[index], Vector3.up); Anchors[index].Rotation = rot; } } List <int> segmentIndices = new List <int>(); for (int i = 0; i < Segments.Count; ++i) { PSplineSegment s = Segments[i]; for (int j = 0; j < anchorIndices.Length; ++j) { int anchorIndex = anchorIndices[j]; if (s.StartIndex == anchorIndex || s.EndIndex == anchorIndex) { segmentIndices.Add(i); } } } for (int i = 0; i < segmentIndices.Count; ++i) { int index = segmentIndices[i]; PSplineSegment s = Segments[index]; PSplineAnchor aStart = Anchors[s.StartIndex]; PSplineAnchor aEnd = Anchors[s.EndIndex]; float sLength = segmentLengths[index]; float tangentLength = sLength * 0.33f; Vector3 dirStart = directions[s.StartIndex]; Vector3 dirEnd = directions[s.EndIndex]; s.StartTangent = aStart.Position + dirStart * tangentLength; s.EndTangent = aEnd.Position - dirEnd * tangentLength; } return(segmentIndices.ToArray()); }