示例#1
0
        /// <summary>
        /// Displays a disc handle.
        /// </summary>
        /// <returns>
        /// The disc radius.
        /// </returns>
        /// <param name="id">Control identifier.</param>
        /// <param name="radius">Radius.</param>
        /// <param name="origin">Origin.</param>
        /// <param name="orientation">Orientation.</param>
        /// <param name="label">Label.</param>
        /// <param name="fillMode">Fill mode.</param>
        private static float DoDisc(
            int id, float radius, Vector3 origin, Quaternion orientation, string label, FillMode fillMode
            )
        {
            // set handle matrix
            Matrix4x4 oldMatrix = Handles.matrix;

            Handles.matrix *= Matrix4x4.TRS(origin, orientation, Vector3.one);
            // create handles
            radius =
                LinearHandles.Dot(id, val: radius, origin: Vector3.zero, direction: Vector3.forward, label: label);
            radius = LinearHandles.Dot(id, val: radius, origin: Vector3.zero, direction: Vector3.right);
            radius = LinearHandles.Dot(id, val: radius, origin: Vector3.zero, direction: Vector3.back);
            radius = LinearHandles.Dot(id, val: radius, origin: Vector3.zero, direction: Vector3.left);
            // draw disc
            Color color = Handles.color;

            SceneGUI.SetHandleAlpha(color.a * SceneGUI.LineAlphaScalar);
            Handles.DrawWireDisc(Vector3.zero, Vector3.up, radius);
            // optionally fill the disc
            if (fillMode == FillMode.Solid)
            {
                SceneGUI.SetHandleAlpha(color.a * SceneGUI.FillAlphaScalar);
                Handles.DrawSolidDisc(Vector3.zero, Vector3.up, radius);
            }
            // reset color
            Handles.color = color;
            // reset handle matrix
            Handles.matrix = oldMatrix;
            // return the result
            return(radius);
        }
示例#2
0
        /// <summary>
        /// Displays the helix twist curve handles.
        /// </summary>
        /// <param name="baseId">Base identifier.</param>
        /// <param name="helix">Helix.</param>
        private static void DoHelixTwistHandles(int baseId, Helix helix)
        {
            float          v;
            AnimationCurve width    = helix.Width;
            AnimationCurve newTwist = new AnimationCurve(helix.Twist.keys);

            Keyframe[] newKeys = newTwist.keys;
            for (int i = 0; i < newKeys.Length; ++i)
            {
                // compute the disc center
                Vector3 discCenter = Vector3.forward * newKeys[i].time * helix.Length;
                v = newKeys[i].value;
                // create an arc handle
                float helixWidth = width.Evaluate(newKeys[i].time);
                v = ArcHandles.SolidAngle(
                    ObjectX.GenerateHashCode(baseId, s_TwistHandleHash, i, 1),
                    v, discCenter,
                    Quaternion.LookRotation(Vector3.right, Vector3.forward),
                    helixWidth,
                    string.Format("{0:0} Degrees", v)
                    );
                Handles.DrawWireDisc(discCenter, Vector3.forward, helixWidth);
                newKeys[i].value = v;
                // create time adjustment handles for intermediary keys
                if (i == 0 || i == newKeys.Length - 1)
                {
                    continue;
                }
                v = newKeys[i].time * helix.Length;
                int id = ObjectX.GenerateHashCode(baseId, s_TwistHandleHash, i, 2);
                v = LinearHandles.Cone(id, v, Vector3.zero, Vector3.forward, capScale: s_TimeAdjustHandleSize);
                v = Mathf.Clamp(
                    v / helix.Length,
                    Mathf.Epsilon * 2f,
                    1f - Mathf.Epsilon * 2f
                    );
                if (Mathf.Abs(v - newKeys[i].time) > s_RequiredMinHandleChange)
                {
                    newKeys[i].time = v;
                }
                // TODO: Fix problems with keys moving over each other
            }
            newTwist.keys = newKeys;
            helix.Twist   = newTwist;
        }
示例#3
0
        /// <summary>
        /// Display a helix length handle.
        /// </summary>
        /// <param name="baseId">Base identifier.</param>
        /// <param name="helix">Helix.</param>
        private static void DoHelixLengthHandle(int baseId, Helix helix)
        {
            float length = helix.Length;
            int   id     = ObjectX.GenerateHashCode(baseId, s_LengthHandleHash);

            length = LinearHandles.Arrow(
                id,
                length,
                Vector3.zero,
                Vector3.forward,
                string.Format("Length: {0:0.###}", length),
                s_LengthHandleSize
                );
            if (Mathf.Abs(length - helix.Length) < s_RequiredMinHandleChange)
            {
                length = helix.Length;
            }
            helix.Length = length;
        }
示例#4
0
        /// <summary>
        /// Displays helix width handles.
        /// </summary>
        /// <param name="baseId">Base identifier.</param>
        /// <param name="helix">Helix.</param>
        private static void DoHelixWidthHandles(int baseId, Helix helix)
        {
            float          v;
            AnimationCurve twist    = helix.Twist;
            AnimationCurve newWidth = helix.Width;

            Keyframe[] newKeys = newWidth.keys;
            for (int i = 0; i < newKeys.Length; ++i)
            {
                // compute the disc center
                Vector3 discCenter = Vector3.forward * newKeys[i].time * helix.Length;
                // compute the angle of the handle around the length
                Quaternion angle = Quaternion.AngleAxis(twist.Evaluate(newKeys[i].time), Vector3.forward);
                // create a cone handle with a slight offset to not overlap the arc handle
                v = newKeys[i].value + s_WidthHandleOffset;
                int id = ObjectX.GenerateHashCode(baseId, s_WidthHandleHash, i, 1);
                v = LinearHandles.Cone(id, v, discCenter, angle * Vector3.right, capScale: s_WidthHandleSize);
                newKeys[i].value = v - s_WidthHandleOffset;
                // create time adjustment handles for intermediary keys
                if (i == 0 || i == newKeys.Length - 1)
                {
                    continue;
                }
                v  = newKeys[i].time * helix.Length;
                id = ObjectX.GenerateHashCode(baseId, s_WidthHandleHash, i, 2);
                v  = LinearHandles.Cone(id, v, Vector3.zero, Vector3.forward, capScale: s_TimeAdjustHandleSize);
                v  = Mathf.Clamp(
                    v / helix.Length,
                    Mathf.Epsilon * 2f,
                    1f - Mathf.Epsilon * 2f
                    );
                if (Mathf.Abs(v - newKeys[i].time) > s_RequiredMinHandleChange)
                {
                    newKeys[i].time = v;
                }
                // TODO: Fix problems with keys moving over each other
            }
            newWidth.keys = newKeys;
            helix.Width   = newWidth;
        }
示例#5
0
 /// <summary>
 /// Displays the wedge radius handle.
 /// </summary>
 /// <returns>The handle's angle value.</returns>
 /// <param name="id">Control identifier.</param>
 /// <param name="radius">Radius.</param>
 /// <param name="wedgeCenter">Wedge center.</param>
 /// <param name="direction">Direction.</param>
 /// <param name="label">Label.</param>
 private static float WedgeRadiusHandle(
     int id, float radius, Vector3 wedgeCenter, Vector3 direction, string label
     )
 {
     return(LinearHandles.Cone(id, radius, wedgeCenter, direction, label, s_RadiusHandleScale));
 }
示例#6
0
        /// <summary>
        /// Displays a shape handle of the specified type.
        /// </summary>
        /// <remarks> If the user is holding Alt, the center will stay locked in place.</remarks>
        /// <param name="baseId">Base identifier.</param>
        /// <param name="size">Size.</param>
        /// <param name="center">Center.</param>
        /// <param name="orientation">Orientation.</param>
        /// <param name="type">Type.</param>
        private static void DoShapeHandle(
            int baseId, ref Vector3 size, ref Vector3 center, Quaternion orientation, WireShapeType type
            )
        {
            // set handle matrix
            Matrix4x4 oldMatrix = Handles.matrix;

            Handles.matrix *= Matrix4x4.TRS(center, orientation, Vector3.one);
            // generate control Ids
            int rightId   = ObjectX.GenerateHashCode(baseId, (int)type, (int)EditAxis.X, 1);
            int leftId    = ObjectX.GenerateHashCode(baseId, (int)type, (int)EditAxis.X, 2);
            int upId      = ObjectX.GenerateHashCode(baseId, (int)type, (int)EditAxis.Y, 1);
            int downId    = ObjectX.GenerateHashCode(baseId, (int)type, (int)EditAxis.Y, 2);
            int forwardId = ObjectX.GenerateHashCode(baseId, (int)type, (int)EditAxis.Z, 1);
            int backId    = ObjectX.GenerateHashCode(baseId, (int)type, (int)EditAxis.Z, 2);
            int currentId = GUIUtility.hotControl;
            int nearestId = HandleUtility.nearestControl;

            // cache the center and size when a handle is clicked to use for shift/alt dragging
            switch (Event.current.type)
            {
            case EventType.MouseDown:
                if (
                    nearestId == leftId || nearestId == rightId ||
                    nearestId == upId || nearestId == downId ||
                    nearestId == forwardId || nearestId == backId
                    )
                {
                    s_OnClickCenter[baseId] = center;
                    s_OnClickSize[baseId]   = size;
                }
                break;

            case EventType.MouseUp:
                s_OnClickCenter.Remove(baseId);
                s_OnClickSize.Remove(baseId);
                currentId = 0;
                break;
            }
            // make sure size is not negative on any dimension
            size = new Vector3(Mathf.Max(0f, size.x), Mathf.Max(0f, size.y), Mathf.Max(0f, size.z));
            // display right/left handles
            float   right  = size.x * 0.5f;
            float   left   = -size.x * 0.5f;
            Vector3 offset = Handles.matrix.GetScale();

            offset = new Vector3(
                offset.x == 0f ? 0f : 1f / offset.x,
                offset.y == 0f ? 0f : 1f / offset.y,
                offset.z == 0f ? 0f : 1f / offset.z
                );
            offset *= s_HandleOffset;
            right   = LinearHandles.Dot(
                rightId, val: right, origin: Vector3.right * offset.x, direction: Vector3.right
                );
            right = Mathf.Max(right, left);
            left  =
                LinearHandles.Dot(leftId, val: left, origin: Vector3.left * offset.x, direction: Vector3.right);
            left = Mathf.Min(right, left);
            // display up/down handles
            float up   = size.y * 0.5f;
            float down = -size.y * 0.5f;

            up   = LinearHandles.Dot(upId, val: up, origin: Vector3.up * offset.y, direction: Vector3.up);
            up   = Mathf.Max(up, down);
            down = LinearHandles.Dot(downId, val: down, origin: Vector3.down * offset.y, direction: Vector3.up);
            down = Mathf.Min(up, down);
            // display forward/back handles
            float forward = size.z * 0.5f;
            float back    = -size.z * 0.5f;

            forward = LinearHandles.Dot(
                forwardId, val: forward, origin: Vector3.forward * offset.z, direction: Vector3.forward
                );
            forward = Mathf.Max(forward, back);
            back    =
                LinearHandles.Dot(backId, val: back, origin: Vector3.back * offset.z, direction: Vector3.forward);
            back = Mathf.Min(forward, back);
            // store which axes are being edited
            EditAxis editAxis = EditAxis.None;

            if (currentId == rightId || currentId == leftId)
            {
                editAxis = EditAxis.X;
            }
            else if (currentId == upId || currentId == downId)
            {
                editAxis = EditAxis.Y;
            }
            else if (currentId == forwardId || currentId == backId)
            {
                editAxis = EditAxis.Z;
            }
            // apply constraints to size based on shape type
            size.x = Mathf.Max(0f, right - left);
            size.y = Mathf.Max(0f, up - down);
            size.z = Mathf.Max(0f, forward - back);
            Vector3 deltaCenter = 0.5f * new Vector3(right + left, up + down, forward + back);
            float   delta;

            switch (type)
            {
            case WireShapeType.Capsule:
                switch (editAxis)
                {
                case EditAxis.X:
                    delta          = Mathf.Min(size.x, size.y) - size.x;
                    size.x        += delta;
                    size.z         = size.x;
                    deltaCenter.x += delta * 0.5f;
                    break;

                case EditAxis.Y:
                    delta          = Mathf.Max(size.y, size.x, size.z) - size.y;
                    size.y        += delta;
                    deltaCenter.y += delta * 0.5f;
                    break;

                case EditAxis.Z:
                    delta          = Mathf.Min(size.z, size.y) - size.z;
                    size.z        += delta;
                    size.x         = size.z;
                    deltaCenter.z += delta * 0.5f;
                    break;
                }
                break;

            case WireShapeType.Cylinder:
                switch (editAxis)
                {
                case EditAxis.X:
                    delta          = Mathf.Min(size.x, size.y) - size.x;
                    size.x        += delta;
                    size.z         = size.x;
                    deltaCenter.x += delta * 0.5f;
                    break;

                case EditAxis.Z:
                    delta          = Mathf.Min(size.z, size.y) - size.z;
                    size.z        += delta;
                    size.x         = size.z;
                    deltaCenter.z += delta * 0.5f;
                    break;
                }
                break;

            case WireShapeType.Sphere:
                switch (editAxis)
                {
                case EditAxis.X:
                    size.y = size.z = size.x;
                    break;

                case EditAxis.Y:
                    size.x = size.z = size.y;
                    break;

                case EditAxis.Z:
                    size.x = size.y = size.z;
                    break;
                }
                break;
            }
            // apply new center
            center += orientation * deltaCenter;
            // scale uniformly using cached size if holding shift key
            if (s_OnClickSize.ContainsKey(baseId) && Event.current.shift)
            {
                float scaleFactor = 1f;
                switch (editAxis)
                {
                case EditAxis.X:
                    scaleFactor = s_OnClickSize[baseId].x > 0f ? size.x / s_OnClickSize[baseId].x : 0f;
                    break;

                case EditAxis.Y:
                    scaleFactor = s_OnClickSize[baseId].y > 0f ? size.y / s_OnClickSize[baseId].y : 0f;
                    break;

                case EditAxis.Z:
                    scaleFactor = s_OnClickSize[baseId].z > 0f ? size.z / s_OnClickSize[baseId].z : 0f;
                    break;
                }
                size = s_OnClickSize[baseId] * scaleFactor;
            }
            // use cached center if holding alt key
            if (s_OnClickCenter.ContainsKey(baseId) && Event.current.alt)
            {
                center = s_OnClickCenter[baseId];
            }
            // draw wire shape
            switch (type)
            {
            case WireShapeType.Box:
                DrawWireBox(size);
                break;

            case WireShapeType.Capsule:
                DrawWireCylinder(new CylinderProperties(height: size.y, radius: size.x * 0.5f), CylinderCap.Capsule);
                break;

            case WireShapeType.Cylinder:
                DrawWireCylinder(new CylinderProperties(height: size.y, radius: size.x * 0.5f), CylinderCap.Cylinder);
                break;

            case WireShapeType.Sphere:
                float radius = size.x * 0.5f;
                Handles.DrawWireDisc(Vector3.zero, Vector3.right, radius);
                Handles.DrawWireDisc(Vector3.zero, Vector3.up, radius);
                Handles.DrawWireDisc(Vector3.zero, Vector3.forward, radius);
                // TODO: get this working in non-identity orientations
//				Vector3 nml = Handles.matrix.MultiplyPoint(Vector3.zero) - Camera.current.transform.position;
//				float sqrMagRecip = 1f / nml.sqrMagnitude;
//				float sqrRadius = radius * radius;
//				radius = Mathf.Sqrt(sqrRadius - (sqrRadius * sqrRadius * sqrMagRecip));
//				Handles.DrawWireDisc(
//					Vector3.zero - sqrRadius * nml * sqrMagRecip, Handles.matrix.inverse.MultiplyVector(nml), radius
//				);
                break;
            }
            // reset handle matrix
            Handles.matrix = oldMatrix;
        }