/// <summary> /// Adds a node at the end of the spline. /// </summary> /// <param name="node"></param> public void AddNode(SplineNode node) { nodes.Add(node); if (nodes.Count != 1) { SplineNode previousNode = nodes[nodes.IndexOf(node) - 1]; CubicBezierCurve curve = new CubicBezierCurve(previousNode, node); curve.Changed.AddListener(() => UpdateAfterCurveChanged()); curves.Add(curve); } RaiseNodeCountChanged(); UpdateAfterCurveChanged(); }
public CurveSample(Vector3 location, Vector3 tangent, Vector3 up, Vector2 scale, float roll, float distanceInCurve, float timeInCurve, CubicBezierCurve curve) { this.location = location; this.tangent = tangent; this.up = up; this.roll = roll; this.scale = scale; this.distanceInCurve = distanceInCurve; this.timeInCurve = timeInCurve; this.curve = curve; index = -1; rotation = Quaternion.identity; }
/// <summary> /// Set the cubic Bézier curve to use to bend the source mesh, and begin to listen to curve control points for changes. /// </summary> /// <param name="curve"></param> /// <param name="update">If let to true, update the resulting mesh immediatly.</param> public void SetCurve(CubicBezierCurve curve, bool update = true) { if (this.curve != null) { this.curve.Changed.RemoveListener(() => Compute()); } this.curve = curve; curve.Changed.AddListener(() => Compute()); if (update) { Compute(); } }
private void OnEnable() { curves.Clear(); for (int i = 0; i < nodes.Count - 1; i++) { SplineNode n = nodes[i]; SplineNode next = nodes[i + 1]; CubicBezierCurve curve = new CubicBezierCurve(n, next); curve.Changed.AddListener(() => UpdateAfterCurveChanged()); curves.Add(curve); } RaiseNodeCountChanged(); UpdateAfterCurveChanged(); }
/// <summary> /// Refreshes the spline's internal list of curves. // </summary> public void RefreshCurves() { curves.Clear(); for (int i = 0; i < nodes.Count - 1; i++) { SplineNode n = nodes[i]; SplineNode next = nodes[i + 1]; CubicBezierCurve curve = new CubicBezierCurve(n, next); curve.Changed.AddListener(UpdateAfterCurveChanged); curves.Add(curve); } RaiseNodeListChanged(new ListChangedEventArgs <SplineNode>() { type = ListChangeType.clear }); UpdateAfterCurveChanged(); }
/// <summary> /// Sets a curve along which the mesh will be bent. /// The mesh will be updated if the curve changes. /// </summary> /// <param name="curve">The <see cref="CubicBezierCurve"/> to bend the source mesh along.</param> public void SetInterval(CubicBezierCurve curve) { if (this.curve == curve) { return; } if (curve == null) { throw new ArgumentNullException("curve"); } if (this.curve != null) { this.curve.Changed.RemoveListener(SetDirty); } this.curve = curve; spline = null; curve.Changed.AddListener(SetDirty); useSpline = false; SetDirty(); }
/// <summary> /// Insert the given node in the spline at index. Index must be greater than 0 and less than node count. /// </summary> /// <param name="index"></param> /// <param name="node"></param> public void InsertNode(int index, SplineNode node) { if (index == 0) { throw new Exception("Can't insert a node at index 0"); } SplineNode previousNode = nodes[index - 1]; SplineNode nextNode = nodes[index]; nodes.Insert(index, node); curves[index - 1].ConnectEnd(node); CubicBezierCurve curve = new CubicBezierCurve(node, nextNode); curve.Changed.AddListener(() => UpdateAfterCurveChanged()); curves.Insert(index, curve); RaiseNodeCountChanged(); UpdateAfterCurveChanged(); }
/// <summary> /// Adds a node at the end of the spline. /// </summary> /// <param name="node"></param> public void AddNode(SplineNode node) { nodes.Add(node); if (nodes.Count != 1) { SplineNode previousNode = nodes[nodes.IndexOf(node) - 1]; CubicBezierCurve curve = new CubicBezierCurve(previousNode, node); curve.Changed.AddListener(() => UpdateAfterCurveChanged()); curves.Add(curve); } RaiseNodeListeChanged(new ListChangedEventArgs <SplineNode>() { type = ListChangeType.Add, newItems = new List <SplineNode>() { node } }); UpdateAfterCurveChanged(); }
public void AddMultipleNodes(List <SplineNode> _nodes) { _nodes.ForEach(node => { nodes.Add(node); if (nodes.Count != 1) { SplineNode previousNode = nodes[nodes.IndexOf(node) - 1]; CubicBezierCurve curve = new CubicBezierCurve(previousNode, node); curve.Changed.AddListener(UpdateAfterCurveChanged); curves.Add(curve); } RaiseNodeListChanged(new ListChangedEventArgs <SplineNode>() { type = ListChangeType.Add, newItems = new List <SplineNode>() { node } }); UpdateAfterCurveChanged(); updateLoopBinding(); }); }
/// <summary> /// Remove the given node from the spline. The given node must exist and the spline must have more than 2 nodes. /// </summary> /// <param name="node"></param> public void RemoveNode(SplineNode node) { int index = nodes.IndexOf(node); if (nodes.Count <= 2) { throw new Exception("Can't remove the node because a spline needs at least 2 nodes."); } CubicBezierCurve toRemove = index == nodes.Count - 1? curves[index - 1] : curves[index]; if (index != 0 && index != nodes.Count - 1) { SplineNode nextNode = nodes[index + 1]; curves[index - 1].ConnectEnd(nextNode); } nodes.RemoveAt(index); toRemove.Changed.RemoveListener(() => UpdateAfterCurveChanged()); curves.Remove(toRemove); RaiseNodeCountChanged(); UpdateAfterCurveChanged(); }
/// <summary> /// Returns the tangent of spline at distance. Distance must be between 0 and spline length. /// </summary> /// <param name="d"></param> /// <returns></returns> public Vector3 GetTangentAlongSplineAtDistance(float d) { if (d < 0 || d > Length) { throw new ArgumentException(string.Format("Distance must be between 0 and spline length ({0}). Given distance was {1}.", Length, d)); } for (var i = 0; i < curves.Count; i++) { CubicBezierCurve curve = curves[i]; if (d > curve.Length) { if (i == curves.Count - 1) { return(curve.GetTangentAtDistance(curve.Length)); } d -= curve.Length; } else { return(curve.GetTangentAtDistance(d)); } } throw new Exception("Something went wrong with GetTangentAlongSplineAtDistance"); }
private void Compute() { if (source == null) { return; } if (generatedMesh == null) { generatedMesh = new Mesh(); } int nbVert = source.vertices.Length; // find the bounds along BendAxis float minX = float.MaxValue; float maxX = float.MinValue; foreach (Vertex vert in vertices) { Vector3 p = vert.v; if (sourceRotation != Quaternion.identity) { p = sourceRotation * p; } if (sourceTranslation != Vector3.zero) { p += sourceTranslation; } switch (BendAxis) { case Axis.X: maxX = Math.Max(maxX, p.x); minX = Math.Min(minX, p.x); break; case Axis.Z: maxX = Math.Max(maxX, p.z); minX = Math.Min(minX, p.z); break; default: throw new ArgumentOutOfRangeException(); } } float length = Math.Abs(maxX - minX); List <Vector3> deformedVerts = new List <Vector3>(nbVert); List <Vector3> deformedNormals = new List <Vector3>(nbVert); // for each mesh vertex, we have to find its projection on the curve foreach (Vertex vert in vertices) { Vector3 p = vert.v; Vector3 n = vert.n; // application of rotation if (sourceRotation != Quaternion.identity) { p = sourceRotation * p; n = sourceRotation * n; } if (sourceTranslation != Vector3.zero) { p += sourceTranslation; } float distanceRate; switch (BendAxis) { case Axis.X: distanceRate = Math.Abs(p.x - minX) / length; break; case Axis.Z: distanceRate = Math.Abs(p.z - minX) / length; break; default: throw new ArgumentOutOfRangeException(); } Vector3 curvePoint = curve.GetLocationAtDistance(curve.Length * distanceRate); Vector3 curveTangent = curve.GetTangentAtDistance(curve.Length * distanceRate); Quaternion q = CubicBezierCurve.GetRotationFromTangent(curveTangent); // application of scale float scaleAtDistance = startScale + (endScale - startScale) * distanceRate; p *= scaleAtDistance; // application of roll float rollAtDistance = startRoll + (endRoll - startRoll) * distanceRate; switch (BendAxis) { case Axis.X: p = Quaternion.AngleAxis(rollAtDistance, Vector3.right) * p; n = Quaternion.AngleAxis(rollAtDistance, Vector3.right) * n; // reset X value of p p = new Vector3(0, p.y, p.z); break; case Axis.Z: p = Quaternion.AngleAxis(rollAtDistance, Vector3.forward) * p; n = Quaternion.AngleAxis(rollAtDistance, Vector3.forward) * n; // reset Z value of p p = new Vector3(p.x, p.y, 0); break; default: throw new ArgumentOutOfRangeException(); } Vector3 fvert = q * p + curvePoint; deformedVerts.Add(fvert); deformedNormals.Add(q * n); } generatedMesh.vertices = deformedVerts.ToArray(); generatedMesh.normals = deformedNormals.ToArray(); generatedMesh.uv = source.uv; generatedMesh.triangles = source.triangles; GetComponent <MeshFilter>().mesh = generatedMesh; }