Пример #1
0
        void CreateBezier(Vector3 centre, bool defaultIs2D = false)
        {
            if (this.bezierPath != null)
            {
                this.bezierPath.OnModified -= this.BezierPathEdited;
            }

            var space = (defaultIs2D) ? PathSpace.Xy : PathSpace.Xyz;

            this.bezierPath = new BezierPath(centre, false, space);

            this.bezierPath.OnModified += this.BezierPathEdited;
            this.vertexPathUpToDate     = false;

            if (this.BezierOrVertexPathModified != null)
            {
                this.BezierOrVertexPathModified();
            }

            if (this.BezierCreated != null)
            {
                this.BezierCreated();
            }
        }
Пример #2
0
        /// Internal contructor
        VertexPath(BezierPath bezierPath, VertexPathUtility.PathSplitData pathSplitData)
        {
            this.Space        = bezierPath.Space;
            this.IsClosedLoop = bezierPath.IsClosed;
            var numVerts = pathSplitData.vertices.Count;

            this.Length = pathSplitData.cumulativeLength[numVerts - 1];

            this.Vertices = new Vector3[numVerts];
            this.Normals  = new Vector3[numVerts];
            this.Tangents = new Vector3[numVerts];
            this.CumulativeLengthAtEachVertex = new float[numVerts];
            this.Times  = new float[numVerts];
            this.Bounds = new Bounds(
                (pathSplitData.minMax.Min + pathSplitData.minMax.Max) / 2,
                pathSplitData.minMax.Max - pathSplitData.minMax.Min);

            // Figure out up direction for path
            this.Up = (this.Bounds.size.z > this.Bounds.size.y) ? Vector3.up : -Vector3.forward;
            var lastRotationAxis = this.Up;

            // Loop through the data and assign to arrays.
            for (var i = 0; i < this.Vertices.Length; i++)
            {
                this.Vertices[i] = pathSplitData.vertices[i];
                this.Tangents[i] = pathSplitData.tangents[i];
                this.CumulativeLengthAtEachVertex[i] = pathSplitData.cumulativeLength[i];
                this.Times[i] = this.CumulativeLengthAtEachVertex[i] / this.Length;

                // Calculate normals
                if (this.Space == PathSpace.Xyz)
                {
                    if (i == 0)
                    {
                        this.Normals[0] = Vector3.Cross(lastRotationAxis, pathSplitData.tangents[0]).normalized;
                    }
                    else
                    {
                        // First reflection
                        var offset = (this.Vertices[i] - this.Vertices[i - 1]);
                        var sqrDst = offset.sqrMagnitude;
                        var r      = lastRotationAxis - offset * 2 / sqrDst * Vector3.Dot(offset, lastRotationAxis);
                        var t      = this.Tangents[i - 1] - offset * 2 / sqrDst * Vector3.Dot(offset, this.Tangents[i - 1]);

                        // Second reflection
                        var v2 = this.Tangents[i] - t;
                        var c2 = Vector3.Dot(v2, v2);

                        var finalRot = r - v2 * 2 / c2 * Vector3.Dot(v2, r);
                        var n        = Vector3.Cross(finalRot, this.Tangents[i]).normalized;
                        this.Normals[i]  = n;
                        lastRotationAxis = finalRot;
                    }
                }
                else
                {
                    this.Normals[i] = Vector3.Cross(this.Tangents[i], this.Up) * ((bezierPath.FlipNormals) ? 1 : -1);
                }
            }

            // Apply correction for 3d normals along a closed path
            if (this.Space == PathSpace.Xyz && this.IsClosedLoop)
            {
                // Get angle between first and last normal (if zero, they're already lined up, otherwise we need to correct)
                var normalsAngleErrorAcrossJoin = Vector3.SignedAngle(
                    this.Normals[this.Normals.Length - 1],
                    this.Normals[0],
                    this.Tangents[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 (var i = 1; i < this.Normals.Length; i++)
                    {
                        var t     = (i / (this.Normals.Length - 1f));
                        var angle = normalsAngleErrorAcrossJoin * t;
                        var rot   = Quaternion.AngleAxis(angle, this.Tangents[i]);
                        this.Normals[i] = rot * this.Normals[i] * ((bezierPath.FlipNormals) ? -1 : 1);
                    }
                }
            }

            // Rotate normals to match up with user-defined anchor angles
            if (this.Space == PathSpace.Xyz)
            {
                for (var anchorIndex = 0; anchorIndex < pathSplitData.anchorVertexMap.Count - 1; anchorIndex++)
                {
                    var nextAnchorIndex = (this.IsClosedLoop) ? (anchorIndex + 1) % bezierPath.NumSegments : anchorIndex + 1;

                    var startAngle = bezierPath.GetAnchorNormalAngle(anchorIndex) + bezierPath.GlobalNormalsAngle;
                    var endAngle   = bezierPath.GetAnchorNormalAngle(nextAnchorIndex) + bezierPath.GlobalNormalsAngle;
                    var deltaAngle = Mathf.DeltaAngle(startAngle, endAngle);

                    var startVertIndex = pathSplitData.anchorVertexMap[anchorIndex];
                    var endVertIndex   = pathSplitData.anchorVertexMap[anchorIndex + 1];

                    var num = endVertIndex - startVertIndex;
                    if (anchorIndex == pathSplitData.anchorVertexMap.Count - 2)
                    {
                        num += 1;
                    }

                    for (var i = 0; i < num; i++)
                    {
                        var vertIndex = startVertIndex + i;
                        var t         = i / (num - 1f);
                        var angle     = startAngle + deltaAngle * t;
                        var rot       = Quaternion.AngleAxis(angle, this.Tangents[vertIndex]);
                        this.Normals[vertIndex] = (rot * this.Normals[vertIndex]) * ((bezierPath.FlipNormals) ? -1 : 1);
                    }
                }
            }
        }
Пример #3
0
 /// <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, float vertexSpacing) : this(
         bezierPath,
         VertexPathUtility.SplitBezierPathEvenly(bezierPath, Mathf.Max(vertexSpacing, MinVertexSpacing), Accuracy))
 {
 }
Пример #4
0
 /// <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, float maxAngleError = 0.3f, float minVertexDst = 0) : this(
         bezierPath,
         VertexPathUtility.SplitBezierPathByAngleError(bezierPath, maxAngleError, minVertexDst, Accuracy))
 {
 }