void Start() { if (waypoints.Length > 0) { // Create a new bezier path from the waypoints. BezierPath bezierPath = new BezierPath(waypoints, closedLoop, PathSpace.xyz); GetComponent <PathCreator> ().bezierPath = bezierPath; } }
void CreateBezier(Vector3 centre, bool defaultIs2D = false) { if (_bezierPath != null) { _bezierPath.OnModified -= BezierPathEdited; } var space = (defaultIs2D) ? PathSpace.xy : PathSpace.xyz; _bezierPath = new BezierPath(centre, false, space); _bezierPath.OnModified += BezierPathEdited; vertexPathUpToDate = false; if (bezierOrVertexPathModified != null) { bezierOrVertexPathModified(); } if (bezierCreated != null) { bezierCreated(); } }
/// Internal contructor VertexPath(BezierPath bezierPath, VertexPathUtility.PathSplitData pathSplitData, Transform transform) { this.transform = transform; space = bezierPath.Space; isClosedLoop = bezierPath.IsClosed; int numVerts = pathSplitData.vertices.Count; length = pathSplitData.cumulativeLength[numVerts - 1]; localPoints = new Vector3[numVerts]; localNormals = new Vector3[numVerts]; localTangents = new Vector3[numVerts]; cumulativeLengthAtEachVertex = new float[numVerts]; times = new float[numVerts]; bounds = new Bounds((pathSplitData.minMax.Min + pathSplitData.minMax.Max) / 2, pathSplitData.minMax.Max - pathSplitData.minMax.Min); // Figure out up direction for path up = (bounds.size.z > bounds.size.y) ? Vector3.up : -Vector3.forward; Vector3 lastRotationAxis = up; // Loop through the data and assign to arrays. for (int i = 0; i < localPoints.Length; i++) { localPoints[i] = pathSplitData.vertices[i]; localTangents[i] = pathSplitData.tangents[i]; cumulativeLengthAtEachVertex[i] = pathSplitData.cumulativeLength[i]; times[i] = cumulativeLengthAtEachVertex[i] / length; // Calculate normals if (space == PathSpace.xyz) { if (i == 0) { localNormals[0] = Vector3.Cross(lastRotationAxis, pathSplitData.tangents[0]).normalized; } else { // First reflection Vector3 offset = (localPoints[i] - localPoints[i - 1]); float sqrDst = offset.sqrMagnitude; Vector3 r = lastRotationAxis - offset * 2 / sqrDst * Vector3.Dot(offset, lastRotationAxis); Vector3 t = localTangents[i - 1] - offset * 2 / sqrDst * Vector3.Dot(offset, localTangents[i - 1]); // Second reflection Vector3 v2 = localTangents[i] - t; float c2 = Vector3.Dot(v2, v2); Vector3 finalRot = r - v2 * 2 / c2 * Vector3.Dot(v2, r); Vector3 n = Vector3.Cross(finalRot, localTangents[i]).normalized; localNormals[i] = n; lastRotationAxis = finalRot; } } else { localNormals[i] = Vector3.Cross(localTangents[i], up) * ((bezierPath.FlipNormals) ? 1 : -1); } } // Apply correction for 3d normals along a closed path if (space == PathSpace.xyz && isClosedLoop) { // Get angle between first and last normal (if zero, they're already lined up, otherwise we need to correct) float normalsAngleErrorAcrossJoin = Vector3.SignedAngle(localNormals[localNormals.Length - 1], localNormals[0], localTangents[0]); // Gradually rotate the normals along the path to ensure start and end normals line up correctly if (Mathf.Abs(normalsAngleErrorAcrossJoin) > 0.1f) // don't bother correcting if very nearly correct { for (int i = 1; i < localNormals.Length; i++) { float t = (i / (localNormals.Length - 1f)); float angle = normalsAngleErrorAcrossJoin * t; Quaternion rot = Quaternion.AngleAxis(angle, localTangents[i]); localNormals[i] = rot * localNormals[i] * ((bezierPath.FlipNormals) ? -1 : 1); } } } // Rotate normals to match up with user-defined anchor angles if (space == PathSpace.xyz) { for (int anchorIndex = 0; anchorIndex < pathSplitData.anchorVertexMap.Count - 1; anchorIndex++) { int nextAnchorIndex = (isClosedLoop) ? (anchorIndex + 1) % bezierPath.NumSegments : anchorIndex + 1; float startAngle = bezierPath.GetAnchorNormalAngle(anchorIndex) + bezierPath.GlobalNormalsAngle; float endAngle = bezierPath.GetAnchorNormalAngle(nextAnchorIndex) + bezierPath.GlobalNormalsAngle; float deltaAngle = Mathf.DeltaAngle(startAngle, endAngle); int startVertIndex = pathSplitData.anchorVertexMap[anchorIndex]; int endVertIndex = pathSplitData.anchorVertexMap[anchorIndex + 1]; int num = endVertIndex - startVertIndex; if (anchorIndex == pathSplitData.anchorVertexMap.Count - 2) { num += 1; } for (int i = 0; i < num; i++) { int vertIndex = startVertIndex + i; float t = i / (num - 1f); float angle = startAngle + deltaAngle * t; Quaternion rot = Quaternion.AngleAxis(angle, localTangents[vertIndex]); localNormals[vertIndex] = (rot * localNormals[vertIndex]) * ((bezierPath.FlipNormals) ? -1 : 1); } } } }
/// <summary> Splits bezier path into array of vertices along the path.</summary> ///<param name="maxAngleError">How much can the angle of the path change before a vertex is added. This allows fewer vertices to be generated in straighter sections.</param> ///<param name="minVertexDst">Vertices won't be added closer together than this distance, regardless of angle error.</param> ///<param name="accuracy">Higher value means the change in angle is checked more frequently.</param> public VertexPath(BezierPath bezierPath, Transform transform, float vertexSpacing) : this(bezierPath, VertexPathUtility.SplitBezierPathEvenly(bezierPath, Mathf.Max(vertexSpacing, minVertexSpacing), VertexPath.accuracy), transform) { }
/// <summary> Splits bezier path into array of vertices along the path.</summary> ///<param name="maxAngleError">How much can the angle of the path change before a vertex is added. This allows fewer vertices to be generated in straighter sections.</param> ///<param name="minVertexDst">Vertices won't be added closer together than this distance, regardless of angle error.</param> public VertexPath(BezierPath bezierPath, Transform transform, float maxAngleError = 0.3f, float minVertexDst = 0) : this(bezierPath, VertexPathUtility.SplitBezierPathByAngleError(bezierPath, maxAngleError, minVertexDst, VertexPath.accuracy), transform) { }