コード例 #1
0
        void DrawHandle(int i)
        {
            Vector3 handlePosition = MathUtility.TransformPoint(BezierPath[i], creator.transform, BezierPath.Space);

            float anchorHandleSize  = GetHandleDiameter(GlobalDisplaySettings.anchorSize * Data.bezierHandleScale, BezierPath[i]);
            float controlHandleSize = GetHandleDiameter(GlobalDisplaySettings.controlSize * Data.bezierHandleScale, BezierPath[i]);

            bool  isAnchorPoint     = i % 3 == 0;
            bool  isInteractive     = isAnchorPoint || BezierPath.ControlPointMode != BezierPath.ControlMode.Automatic;
            float handleSize        = (isAnchorPoint) ? anchorHandleSize : controlHandleSize;
            bool  doTransformHandle = i == handleIndexToDisplayAsTransform;

            PathHandle.HandleColours handleColours = (isAnchorPoint) ? splineAnchorColours : splineControlColours;
            if (i == handleIndexToDisplayAsTransform)
            {
                handleColours.defaultColour = (isAnchorPoint) ? GlobalDisplaySettings.anchorSelected : GlobalDisplaySettings.controlSelected;
            }

            var cap = capFunctions[(isAnchorPoint) ? GlobalDisplaySettings.anchorShape : GlobalDisplaySettings.controlShape];

            handlePosition = PathHandle.DrawHandle(handlePosition, BezierPath.Space, isInteractive, handleSize, cap, handleColours, out PathHandle.HandleInputType handleInputType, i);

            if (doTransformHandle)
            {
                // Show normals rotate tool
                if (Data.showNormals && Tools.current == Tool.Rotate && isAnchorPoint && BezierPath.Space == PathSpace.xyz)
                {
                    Handles.color = handlesStartCol;

                    int     attachedControlIndex = (i == BezierPath.NumPoints - 1) ? i - 1 : i + 1;
                    Vector3 dir             = (BezierPath[attachedControlIndex] - handlePosition).normalized;
                    float   handleRotOffset = (360 + BezierPath.GlobalNormalsAngle) % 360;
                    anchorAngleHandle.radius = handleSize * 3;
                    anchorAngleHandle.angle  = handleRotOffset + BezierPath.GetAnchorNormalAngle(i / 3);
                    Vector3   handleDirection = Vector3.Cross(dir, Vector3.up);
                    Matrix4x4 handleMatrix    = Matrix4x4.TRS(
                        handlePosition,
                        Quaternion.LookRotation(handleDirection, dir),
                        Vector3.one
                        );

                    using (new Handles.DrawingScope(handleMatrix))
                    {
                        // draw the handle
                        EditorGUI.BeginChangeCheck();
                        anchorAngleHandle.DrawHandle();
                        if (EditorGUI.EndChangeCheck())
                        {
                            Undo.RecordObject(creator, "Set angle");
                            BezierPath.SetAnchorNormalAngle(i / 3, anchorAngleHandle.angle - handleRotOffset);
                        }
                    }
                }
                else
                {
                    handlePosition = Handles.DoPositionHandle(handlePosition, Quaternion.identity);
                }
            }

            switch (handleInputType)
            {
            case PathHandle.HandleInputType.LMBDrag:
                draggingHandleIndex             = i;
                handleIndexToDisplayAsTransform = -1;
                Repaint();
                break;

            case PathHandle.HandleInputType.LMBRelease:
                draggingHandleIndex             = -1;
                handleIndexToDisplayAsTransform = -1;
                Repaint();
                break;

            case PathHandle.HandleInputType.LMBClick:
                draggingHandleIndex = -1;
                if (Event.current.shift)
                {
                    handleIndexToDisplayAsTransform = -1;     // disable move tool if new point added
                }
                else
                {
                    if (handleIndexToDisplayAsTransform == i)
                    {
                        handleIndexToDisplayAsTransform = -1;     // disable move tool if clicking on point under move tool
                    }
                    else
                    {
                        handleIndexToDisplayAsTransform = i;
                    }
                }
                Repaint();
                break;

            case PathHandle.HandleInputType.LMBPress:
                if (handleIndexToDisplayAsTransform != i)
                {
                    handleIndexToDisplayAsTransform = -1;
                    Repaint();
                }
                break;
            }

            Vector3 localHandlePosition = MathUtility.InverseTransformPoint(handlePosition, creator.transform, BezierPath.Space);

            if (BezierPath[i] != localHandlePosition)
            {
                Undo.RecordObject(creator, "Move point");
                BezierPath.MovePoint(i, localHandlePosition);
            }
        }
コード例 #2
0
        /// Internal contructor
        VertexPath(BezierPath path, PathUtility.PathSplitData pathSplitData, Transform transform)
        {
            this.transform = transform;
            space          = path.Space;
            isClosedLoop   = path.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) * .5f, 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)
                {
                    localNormals[i] = Vector3.Cross(localTangents[i], up) * (path.FlipNormals ? 1 : -1);
                    continue;
                }

                if (i == 0)
                {
                    localNormals[0] = Vector3.Cross(lastRotationAxis, pathSplitData.tangents[0]).normalized;
                    continue;
                }

                // 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;
            }

            // Apply correction for 3d normals along a closed path
            if (space != PathSpace.xyz)
            {
                return;
            }

            if (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] * (path.FlipNormals ? -1 : 1);
                    }
                }
                return;
            }

            // Rotate normals to match up with user-defined anchor angles
            for (int anchorIndex = 0; anchorIndex < pathSplitData.anchorVertexMap.Count - 1; ++anchorIndex)
            {
                int nextAnchorIndex = isClosedLoop ? (anchorIndex + 1) % path.NumSegments : anchorIndex + 1;

                float startAngle = path.GetAnchorNormalAngle(anchorIndex) + path.GlobalNormalsAngle;
                float endAngle   = path.GetAnchorNormalAngle(nextAnchorIndex) + path.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]) * (path.FlipNormals ? -1 : 1);
                }
            }
        }