Example #1
0
        void DrawBezierPathSceneEditor()
        {
            bool   displayControlPoints = data.displayControlPoints && (bezierPath.ControlPointMode != BezierPath.ControlMode.Automatic || !globalDisplaySettings.hideAutoControls);
            Bounds bounds = bezierPath.PathBounds;

            // Draw normals
            if (data.showNormals)
            {
                if (!hasUpdatedNormalsVertexPath)
                {
                    normalsVertexPath           = new VertexPath(bezierPath, normalsSpacing);
                    hasUpdatedNormalsVertexPath = true;
                }

                if (editingNormalsOld != data.showNormals)
                {
                    editingNormalsOld = data.showNormals;
                    Repaint();
                }

                Handles.color = globalDisplaySettings.normals;
                for (int i = 0; i < normalsVertexPath.NumVertices; i++)
                {
                    Vector3 prevVertex = normalsVertexPath.vertices[Mathf.Max(0, i - 1)];
                    Vector3 nextVertex = normalsVertexPath.vertices[Mathf.Min(normalsVertexPath.NumVertices - 1, i + 1)];
                    Vector3 forward    = prevVertex - nextVertex;
                    forward *= globalDisplaySettings.normalsWidth;

                    Vector3[] points = new Vector3[4];
                    points[0] = normalsVertexPath.vertices[i] - forward * 0.5f;
                    points[1] = points[0] + normalsVertexPath.normals[i] * globalDisplaySettings.normalsLength;
                    points[2] = points[1] + forward;
                    points[3] = points[0] + forward;
                    Handles.DrawSolidRectangleWithOutline(points, globalDisplaySettings.normals, globalDisplaySettings.normals);
                }
            }

            for (int i = 0; i < bezierPath.NumSegments; i++)
            {
                Vector3[] points = bezierPath.GetPointsInSegment(i);

                if (data.showPerSegmentBounds)
                {
                    Bounds segmentBounds = CubicBezierUtility.CalculateBounds(points);
                    Handles.color = globalDisplaySettings.segmentBounds;
                    Handles.DrawWireCube(segmentBounds.center, segmentBounds.size);
                }

                // Draw lines between control points
                if (displayControlPoints)
                {
                    Handles.color = (bezierPath.ControlPointMode == BezierPath.ControlMode.Automatic) ? globalDisplaySettings.handleDisabled : globalDisplaySettings.controlLine;
                    Handles.DrawLine(points[1], points[0]);
                    Handles.DrawLine(points[2], points[3]);
                }

                // Draw path
                bool  highlightSegment = (i == selectedSegmentIndex && Event.current.shift && draggingHandleIndex == -1 && mouseOverHandleIndex == -1);
                Color segmentCol       = (highlightSegment) ? globalDisplaySettings.highlightedPath : globalDisplaySettings.bezierPath;
                Handles.DrawBezier(points[0], points[3], points[1], points[2], segmentCol, null, 2);
            }

            // Draw rotate/scale/move tool
            if (data.pathTransformationEnabled && !Event.current.alt && !Event.current.shift)
            {
                if (Tools.current == Tool.Rotate)
                {
                    Undo.RecordObject(creator, "Rotate Path");
                    Quaternion newHandleRot = Handles.DoRotationHandle(currentHandleRot, bezierPath.Pivot);
                    Quaternion deltaRot     = newHandleRot * Quaternion.Inverse(currentHandleRot);
                    currentHandleRot = newHandleRot;

                    Quaternion newRot = deltaRot * bezierPath.Rotation;
                    bezierPath.Rotation = newRot;
                    if (shareTransformsWithPath)
                    {
                        creator.transform.rotation = newRot;
                        rotationOld = newRot;
                    }
                }
                else if (Tools.current == Tool.Scale)
                {
                    Undo.RecordObject(creator, "Scale Path");
                    bezierPath.Scale = Handles.DoScaleHandle(bezierPath.Scale, bezierPath.Pivot, Quaternion.identity, HandleUtility.GetHandleSize(bezierPath.Pivot));
                    if (shareTransformsWithPath)
                    {
                        creator.transform.localScale = bezierPath.Scale;
                        scaleOld = bezierPath.Scale;
                    }
                }
                else
                {
                    Undo.RecordObject(creator, "Move Path");

                    bezierPath.Pivot = bounds.center;
                    Vector3 newCentre   = Handles.DoPositionHandle(bezierPath.Pivot, Quaternion.identity);
                    Vector3 deltaCentre = newCentre - bezierPath.Pivot;
                    bezierPath.Position += deltaCentre;
                    if (shareTransformsWithPath)
                    {
                        creator.transform.position = bezierPath.Position;
                        positionOld = bezierPath.Position;
                    }
                }
            }

            if (data.showPathBounds)
            {
                Handles.color = globalDisplaySettings.bounds;
                Handles.DrawWireCube(bounds.center, bounds.size);
            }

            if (data.displayAnchorPoints)
            {
                for (int i = 0; i < bezierPath.NumPoints; i += 3)
                {
                    DrawHandle(i);
                }
            }
            if (displayControlPoints)
            {
                for (int i = 1; i < bezierPath.NumPoints - 1; i += 3)
                {
                    DrawHandle(i);
                    DrawHandle(i + 1);
                }
            }
        }
Example #2
0
        void DrawBezierPathSceneEditor()
        {
            bool   displayControlPoints = data.displayControlPoints && (bezierPath.ControlPointMode != BezierPath.ControlMode.Automatic || !globalDisplaySettings.hideAutoControls);
            Bounds bounds = bezierPath.CalculateBoundsWithTransform(creator.transform);

            if (Event.current.type == EventType.Repaint)
            {
                for (int i = 0; i < bezierPath.NumSegments; i++)
                {
                    Vector3[] points = bezierPath.GetPointsInSegment(i);
                    for (int j = 0; j < points.Length; j++)
                    {
                        points[j] = MathUtility.TransformPoint(points[j], creator.transform, bezierPath.Space);
                    }

                    if (data.showPerSegmentBounds)
                    {
                        Bounds segmentBounds = CubicBezierUtility.CalculateSegmentBounds(points[0], points[1], points[2], points[3]);
                        Handles.color = globalDisplaySettings.segmentBounds;
                        Handles.DrawWireCube(segmentBounds.center, segmentBounds.size);
                    }

                    // Draw lines between control points
                    if (displayControlPoints)
                    {
                        Handles.color = (bezierPath.ControlPointMode == BezierPath.ControlMode.Automatic) ? globalDisplaySettings.handleDisabled : globalDisplaySettings.controlLine;
                        Handles.DrawLine(points[1], points[0]);
                        Handles.DrawLine(points[2], points[3]);
                    }

                    // Draw path
                    bool  highlightSegment = (i == selectedSegmentIndex && Event.current.shift && draggingHandleIndex == -1 && mouseOverHandleIndex == -1);
                    Color segmentCol       = (highlightSegment) ? globalDisplaySettings.highlightedPath : globalDisplaySettings.bezierPath;
                    Handles.DrawBezier(points[0], points[3], points[1], points[2], segmentCol, null, 2);
                }

                if (data.showPathBounds)
                {
                    Handles.color = globalDisplaySettings.bounds;
                    Handles.DrawWireCube(bounds.center, bounds.size);
                }

                // Draw normals
                if (data.showNormals)
                {
                    if (!hasUpdatedNormalsVertexPath)
                    {
                        normalsVertexPath           = new VertexPath(bezierPath, creator.transform, normalsSpacing);
                        hasUpdatedNormalsVertexPath = true;
                    }

                    if (editingNormalsOld != data.showNormals)
                    {
                        editingNormalsOld = data.showNormals;
                        Repaint();
                    }

                    Vector3[] normalLines = new Vector3[normalsVertexPath.NumPoints * 2];
                    Handles.color = globalDisplaySettings.normals;
                    for (int i = 0; i < normalsVertexPath.NumPoints; i++)
                    {
                        normalLines[i * 2]     = normalsVertexPath.GetPoint(i);
                        normalLines[i * 2 + 1] = normalsVertexPath.GetPoint(i) + normalsVertexPath.GetNormal(i) * globalDisplaySettings.normalsLength;
                    }
                    Handles.DrawLines(normalLines);
                }
            }

            if (data.displayAnchorPoints)
            {
                for (int i = 0; i < bezierPath.NumPoints; i += 3)
                {
                    DrawHandle(i);
                }
            }
            if (displayControlPoints)
            {
                for (int i = 1; i < bezierPath.NumPoints - 1; i += 3)
                {
                    DrawHandle(i);
                    DrawHandle(i + 1);
                }
            }
        }
Example #3
0
        public ScreenSpacePolyLine(BezierPath bezierPath, Transform transform, float maxAngleError, float minVertexDst,
                                   float accuracy = 1)
        {
            this.transform    = transform;
            transformPosition = transform.position;
            transformRotation = transform.rotation;
            transformScale    = transform.localScale;

            // Split path in vertices based on angle error
            verticesWorld          = new List <Vector3>();
            vertexToPathSegmentMap = new List <int>();
            segmentStartIndices    = new int[bezierPath.NumSegments + 1];

            verticesWorld.Add(bezierPath[0]);
            vertexToPathSegmentMap.Add(0);
            Vector3 prevPointOnPath          = bezierPath[0];
            float   dstSinceLastVertex       = 0;
            Vector3 lastAddedPoint           = prevPointOnPath;
            float   dstSinceLastIntermediary = 0;

            for (int segmentIndex = 0; segmentIndex < bezierPath.NumSegments; segmentIndex++)
            {
                Vector3[] segmentPoints = bezierPath.GetPointsInSegment(segmentIndex);
                verticesWorld.Add(segmentPoints[0]);
                vertexToPathSegmentMap.Add(segmentIndex);
                segmentStartIndices[segmentIndex] = verticesWorld.Count - 1;

                prevPointOnPath          = segmentPoints[0];
                lastAddedPoint           = prevPointOnPath;
                dstSinceLastVertex       = 0;
                dstSinceLastIntermediary = 0;

                float estimatedSegmentLength = CubicBezierUtility.EstimateCurveLength(segmentPoints[0],
                                                                                      segmentPoints[1], segmentPoints[2], segmentPoints[3]);
                int   divisions = Mathf.CeilToInt(estimatedSegmentLength * accuracy * accuracyMultiplier);
                float increment = 1f / divisions;

                for (float t = increment; t <= 1; t += increment)
                {
                    Vector3 pointOnPath = CubicBezierUtility.EvaluateCurve(segmentPoints[0], segmentPoints[1],
                                                                           segmentPoints[2], segmentPoints[3], t);
                    Vector3 nextPointOnPath = CubicBezierUtility.EvaluateCurve(segmentPoints[0], segmentPoints[1],
                                                                               segmentPoints[2], segmentPoints[3], t + increment);

                    // angle at current point on path
                    float localAngle = 180 - MathUtility.MinAngle(prevPointOnPath, pointOnPath, nextPointOnPath);
                    // angle between the last added vertex, the current point on the path, and the next point on the path
                    float angleFromPrevVertex =
                        180 - MathUtility.MinAngle(lastAddedPoint, pointOnPath, nextPointOnPath);
                    float angleError = Mathf.Max(localAngle, angleFromPrevVertex);


                    if (angleError > maxAngleError && dstSinceLastVertex >= minVertexDst)
                    {
                        dstSinceLastVertex       = 0;
                        dstSinceLastIntermediary = 0;
                        verticesWorld.Add(pointOnPath);
                        vertexToPathSegmentMap.Add(segmentIndex);
                        lastAddedPoint = pointOnPath;
                    }
                    else
                    {
                        if (dstSinceLastIntermediary > intermediaryThreshold)
                        {
                            verticesWorld.Add(pointOnPath);
                            vertexToPathSegmentMap.Add(segmentIndex);
                            dstSinceLastIntermediary = 0;
                        }
                        else
                        {
                            dstSinceLastIntermediary += (pointOnPath - prevPointOnPath).magnitude;
                        }

                        dstSinceLastVertex += (pointOnPath - prevPointOnPath).magnitude;
                    }

                    prevPointOnPath = pointOnPath;
                }
            }

            segmentStartIndices[bezierPath.NumSegments] = verticesWorld.Count;

            // ensure final point gets added (unless path is closed loop)
            if (!bezierPath.IsClosed)
            {
                verticesWorld.Add(bezierPath[bezierPath.NumPoints - 1]);
            }
            else
            {
                verticesWorld.Add(bezierPath[0]);
            }

            // Calculate length
            cumululativeLengthWorld = new float[verticesWorld.Count];
            for (int i = 0; i < verticesWorld.Count; i++)
            {
                verticesWorld[i] = MathUtility.TransformPoint(verticesWorld[i], transform, bezierPath.Space);
                if (i > 0)
                {
                    pathLengthWorld           += (verticesWorld[i - 1] - verticesWorld[i]).magnitude;
                    cumululativeLengthWorld[i] = pathLengthWorld;
                }
            }
        }
Example #4
0
        void DrawBezierPathSceneEditor()
        {
            var displayControlPoints = Data.displayControlPoints &&
                                       (BezierPath.ControlPointMode != BezierPath.ControlMode.Automatic ||
                                        !_globalDisplaySettings.hideAutoControls);
            var bounds = BezierPath.PathBounds;

            // Draw normals
            if (Data.showNormals)
            {
                if (!_hasUpdatedNormalsVertexPath)
                {
                    _normalsVertexPath           = new VertexPath(BezierPath, NormalsSpacing);
                    _hasUpdatedNormalsVertexPath = true;
                }

                if (_editingNormalsOld != Data.showNormals)
                {
                    _editingNormalsOld = Data.showNormals;
                    Repaint();
                }

                Handles.color = _globalDisplaySettings.normals;
                for (var i = 0; i < _normalsVertexPath.NumVertices; i++)
                {
                    Handles.DrawLine(
                        _normalsVertexPath.Vertices[i],
                        _normalsVertexPath.Vertices[i] + _normalsVertexPath.Normals[i] * _globalDisplaySettings.normalsLength);
                }
            }

            for (var i = 0; i < BezierPath.NumSegments; i++)
            {
                var points = BezierPath.GetPointsInSegment(i);

                if (Data.showPerSegmentBounds)
                {
                    var segmentBounds = CubicBezierUtility.CalculateBounds(points);
                    Handles.color = _globalDisplaySettings.segmentBounds;
                    Handles.DrawWireCube(segmentBounds.center, segmentBounds.size);
                }

                // Draw lines between control points
                if (displayControlPoints)
                {
                    Handles.color = (BezierPath.ControlPointMode == BezierPath.ControlMode.Automatic)
                              ? _globalDisplaySettings.handleDisabled
                              : _globalDisplaySettings.controlLine;
                    Handles.DrawLine(points[1], points[0]);
                    Handles.DrawLine(points[2], points[3]);
                }

                // Draw path
                var highlightSegment = (i == _selectedSegmentIndex &&
                                        Event.current.shift &&
                                        _draggingHandleIndex == -1 &&
                                        _mouseOverHandleIndex == -1);
                var segmentCol =
                    (highlightSegment) ? _globalDisplaySettings.highlightedPath : _globalDisplaySettings.bezierPath;
                Handles.DrawBezier(points[0], points[3], points[1], points[2], segmentCol, null, 2);
            }

            // Draw rotate/scale/move tool
            if (Data.pathTransformationEnabled && !Event.current.alt && !Event.current.shift)
            {
                if (Tools.current == Tool.Rotate)
                {
                    Undo.RecordObject(_creator, "Rotate Path");
                    var newHandleRot = Handles.DoRotationHandle(_currentHandleRot, BezierPath.Pivot);
                    var deltaRot     = newHandleRot * Quaternion.Inverse(_currentHandleRot);
                    _currentHandleRot = newHandleRot;

                    var newRot = deltaRot * BezierPath.Rotation;
                    BezierPath.Rotation = newRot;
                    if (_shareTransformsWithPath)
                    {
                        _creator.transform.rotation = newRot;
                        _rotationOld = newRot;
                    }
                }
                else if (Tools.current == Tool.Scale)
                {
                    Undo.RecordObject(_creator, "Scale Path");
                    BezierPath.Scale = Handles.DoScaleHandle(
                        BezierPath.Scale,
                        BezierPath.Pivot,
                        Quaternion.identity,
                        HandleUtility.GetHandleSize(BezierPath.Pivot));
                    if (_shareTransformsWithPath)
                    {
                        _creator.transform.localScale = BezierPath.Scale;
                        _scaleOld = BezierPath.Scale;
                    }
                }
                else
                {
                    Undo.RecordObject(_creator, "Move Path");

                    BezierPath.Pivot = bounds.center;
                    var newCentre   = Handles.DoPositionHandle(BezierPath.Pivot, Quaternion.identity);
                    var deltaCentre = newCentre - BezierPath.Pivot;
                    BezierPath.Position += deltaCentre;
                    if (_shareTransformsWithPath)
                    {
                        _creator.transform.position = BezierPath.Position;
                        _positionOld = BezierPath.Position;
                    }
                }
            }

            if (Data.showPathBounds)
            {
                Handles.color = _globalDisplaySettings.bounds;
                Handles.DrawWireCube(bounds.center, bounds.size);
            }

            if (Data.displayAnchorPoints)
            {
                for (var i = 0; i < BezierPath.NumPoints; i += 3)
                {
                    DrawHandle(i);
                }
            }

            if (displayControlPoints)
            {
                for (var i = 1; i < BezierPath.NumPoints - 1; i += 3)
                {
                    DrawHandle(i);
                    DrawHandle(i + 1);
                }
            }
        }
Example #5
0
        public ScreenSpacePolyLine(BezierPath bezierPath, float maxAngleError, float minVertexDst, float accuracy = 1)
        {
            // Split path in vertices based on angle error
            VerticesWorld           = new List <Vector3>();
            _vertexToPathSegmentMap = new List <int>();
            _segmentStartIndices    = new int[bezierPath.NumSegments + 1];

            VerticesWorld.Add(bezierPath[0]);
            _vertexToPathSegmentMap.Add(0);
            var   prevPointOnPath          = bezierPath[0];
            float dstSinceLastVertex       = 0;
            var   lastAddedPoint           = prevPointOnPath;
            float dstSinceLastIntermediary = 0;

            for (var segmentIndex = 0; segmentIndex < bezierPath.NumSegments; segmentIndex++)
            {
                var segmentPoints = bezierPath.GetPointsInSegment(segmentIndex);
                VerticesWorld.Add(segmentPoints[0]);
                _vertexToPathSegmentMap.Add(segmentIndex);
                _segmentStartIndices[segmentIndex] = VerticesWorld.Count - 1;

                prevPointOnPath          = segmentPoints[0];
                lastAddedPoint           = prevPointOnPath;
                dstSinceLastVertex       = 0;
                dstSinceLastIntermediary = 0;

                var estimatedSegmentLength = CubicBezierUtility.EstimateCurveLength(
                    segmentPoints[0],
                    segmentPoints[1],
                    segmentPoints[2],
                    segmentPoints[3]);
                var divisions = Mathf.CeilToInt(estimatedSegmentLength * accuracy * AccuracyMultiplier);
                var increment = 1f / divisions;

                for (var t = increment; t <= 1; t += increment)
                {
                    var pointOnPath = CubicBezierUtility.EvaluateCurve(
                        segmentPoints[0],
                        segmentPoints[1],
                        segmentPoints[2],
                        segmentPoints[3],
                        t);
                    var nextPointOnPath = CubicBezierUtility.EvaluateCurve(
                        segmentPoints[0],
                        segmentPoints[1],
                        segmentPoints[2],
                        segmentPoints[3],
                        t + increment);

                    // angle at current point on path
                    var localAngle = 180 - MathUtility.MinAngle(prevPointOnPath, pointOnPath, nextPointOnPath);
                    // angle between the last added vertex, the current point on the path, and the next point on the path
                    var angleFromPrevVertex = 180 - MathUtility.MinAngle(lastAddedPoint, pointOnPath, nextPointOnPath);
                    var angleError          = Mathf.Max(localAngle, angleFromPrevVertex);

                    if (angleError > maxAngleError && dstSinceLastVertex >= minVertexDst)
                    {
                        dstSinceLastVertex       = 0;
                        dstSinceLastIntermediary = 0;
                        VerticesWorld.Add(pointOnPath);
                        _vertexToPathSegmentMap.Add(segmentIndex);
                        lastAddedPoint = pointOnPath;
                    }
                    else
                    {
                        if (dstSinceLastIntermediary > IntermediaryThreshold)
                        {
                            VerticesWorld.Add(pointOnPath);
                            _vertexToPathSegmentMap.Add(segmentIndex);
                            dstSinceLastIntermediary = 0;
                        }
                        else
                        {
                            dstSinceLastIntermediary += (pointOnPath - prevPointOnPath).magnitude;
                        }

                        dstSinceLastVertex += (pointOnPath - prevPointOnPath).magnitude;
                    }

                    prevPointOnPath = pointOnPath;
                }
            }

            _segmentStartIndices[bezierPath.NumSegments] = VerticesWorld.Count;

            // ensure final point gets added (unless path is closed loop)
            if (!bezierPath.IsClosed)
            {
                VerticesWorld.Add(bezierPath[bezierPath.NumPoints - 1]);
            }
            else
            {
                VerticesWorld.Add(bezierPath[0]);
            }

            // Calculate length
            _cumululativeLengthWorld = new float[VerticesWorld.Count];
            for (var i = 1; i < VerticesWorld.Count; i++)
            {
                _pathLengthWorld           += (VerticesWorld[i - 1] - VerticesWorld[i]).magnitude;
                _cumululativeLengthWorld[i] = _pathLengthWorld;
            }
        }
Example #6
0
    /// <summary>
    /// 0 means no curvature. 1 means max curvature defined by <see cref="maxCurvature"/>
    /// </summary>
    /// <param name="d"></param>
    /// <returns></returns>
    public float GetCurvatureAtDistance(float d)
    {
        float t = AbsoluteDistanceToT(d);

        return(Mathf.Clamp(CubicBezierUtility.EvaluateCurvature(GetPoints(), t), 0f, maxCurvature) / maxCurvature);
    }
Example #7
0
 /// <summary>
 /// 0 means no curvature. 1 means max curvature defined by <see cref="maxCurvature"/>
 /// </summary>
 /// <param name="t"></param>
 /// <returns></returns>
 public float GetCurvature(float t)
 {
     return(Mathf.Clamp(CubicBezierUtility.EvaluateCurvature(GetPoints(), t), 0f, maxCurvature) / maxCurvature);
 }
Example #8
0
 public Vector3 GetTangent(float t)
 {
     return(CubicBezierUtility.EvaluateCurveDerivative(GetPoints(), t).normalized);
 }
Example #9
0
 public Vector3 GetPoint(float t)
 {
     return(CubicBezierUtility.EvaluateCurve(GetPoints(), t));
 }