public static int GetNewTangentKeyMode(int currentTangentMode, TangentDirection leftRight, TangentMode mode) { int output = currentTangentMode; if (leftRight == TangentDirection.Left) { output &= -7; output |= ((int)mode) << 1; } else { output &= -25; output |= ((int)mode) << 3; } return output; }
public static Keyframe GetNew(float time, float value, TangentMode left, TangentMode right){ object boxed = new Keyframe(time,value); // cant use struct in reflection SetKeyBroken(boxed, true); SetKeyTangentMode(boxed, 0, left); SetKeyTangentMode(boxed, 1, right); Keyframe keyframe = (Keyframe)boxed; if (left == TangentMode.Stepped ) keyframe.inTangent = float.PositiveInfinity; if (right == TangentMode.Stepped ) keyframe.outTangent = float.PositiveInfinity; return keyframe; }
// UnityEditor.CurveUtility.cs (c) Unity Technologies public static void SetKeyTangentMode(object keyframe, int leftRight, TangentMode mode) { Type t = typeof( UnityEngine.Keyframe ); FieldInfo field = t.GetField( "m_TangentMode", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance ); int tangentMode = (int)field.GetValue(keyframe); if (leftRight == 0) { tangentMode &= -7; tangentMode |= (int) mode << 1; } else { tangentMode &= -25; tangentMode |= (int) mode << 3; } field.SetValue(keyframe, tangentMode); if (GetKeyTangentMode(tangentMode, leftRight) == mode) return; Debug.Log("bug"); }
/// <summary> /// Changes the tangent mode for all currently selected keyframes. /// </summary> /// <param name="mode">Tangent mode to set. If only in or out tangent mode is provided, the mode for the opposite /// tangent will be kept as is.</param> private void ChangeSelectionTangentMode(TangentMode mode) { if (disableCurveEdit) { ShowReadOnlyMessage(); return; } foreach (var selectedEntry in selectedKeyframes) { EdAnimationCurve curve = curveInfos[selectedEntry.curveIdx].curve; foreach (var keyframeIdx in selectedEntry.keyIndices) { if (mode == TangentMode.Auto || mode == TangentMode.Free) curve.SetTangentMode(keyframeIdx, mode); else { TangentMode newMode = curve.TangentModes[keyframeIdx]; if (mode.HasFlag((TangentMode) TangentType.In)) { // Replace only the in tangent mode, keeping the out tangent as is TangentMode inFlags = (TangentMode.InAuto | TangentMode.InFree | TangentMode.InLinear | TangentMode.InStep); newMode &= ~inFlags; newMode |= (mode & inFlags); } else { // Replace only the out tangent mode, keeping the in tangent as is TangentMode outFlags = (TangentMode.OutAuto | TangentMode.OutFree | TangentMode.OutLinear | TangentMode.OutStep); newMode &= ~outFlags; newMode |= (mode & outFlags); } curve.SetTangentMode(keyframeIdx, newMode); } } curve.Apply(); } window.RecordClipState(); OnCurveModified?.Invoke(); guiCurveDrawing.Rebuild(); }
extern public static void SetKeyRightTangentMode([NotNull] AnimationCurve curve, int index, TangentMode tangentMode);
extern private static void Internal_SetKeyRightTangentMode(ref Keyframe key, TangentMode tangentMode);
static void CreateAnimSlot(SpineArmatureEditor armatureEditor, AnimationClip clip, SpineData.AnimationSlotData[] animSlotDatas) { for (int i = 0; i < animSlotDatas.Length; ++i) { SpineData.AnimationSlotData animSlotData = animSlotDatas[i]; string slotName = animSlotData.name; Transform slot = armatureEditor.slotsKV[slotName]; SpineData.SlotData defaultSlotData = armatureEditor.slotsDataKV[slotName]; Color defaultColorData = defaultSlotData.color; AnimationCurve color_rcurve = new AnimationCurve(); AnimationCurve color_gcurve = new AnimationCurve(); AnimationCurve color_bcurve = new AnimationCurve(); AnimationCurve color_acurve = new AnimationCurve(); AnimationCurve display_curve = new AnimationCurve(); bool isHaveCurve = false; for (int j = 0; j < animSlotData.timelines.Length; ++j) { SpineData.SlotTimeline timeline = animSlotData.timelines[j]; string prevTweeneasing = "linear"; //前一帧的tweenEasing float[] prevCurves = null; if (j > 0) { prevTweeneasing = animSlotData.timelines[j - 1].tweenEasing; prevCurves = animSlotData.timelines[j - 1].curve; } TangentMode tanModeL = GetPrevFrameTangentMode(prevTweeneasing, prevCurves); TangentMode tanModeR = TangentMode.Linear; if (timeline.curve != null && timeline.curve.Length > 0) { tanModeR = TangentMode.Editable; isHaveCurve = true; } else { if (timeline.tweenEasing == "stepped") { tanModeR = TangentMode.Stepped; } else { tanModeR = TangentMode.Linear; } } if (timeline.type == "color") { if (!string.IsNullOrEmpty(timeline.color)) { Color c = SpineArmatureEditor.HexToColor(timeline.color); color_rcurve.AddKey(KeyframeUtil.GetNew(timeline.time, c.r, tanModeL, tanModeR)); color_gcurve.AddKey(KeyframeUtil.GetNew(timeline.time, c.g, tanModeL, tanModeR)); color_bcurve.AddKey(KeyframeUtil.GetNew(timeline.time, c.b, tanModeL, tanModeR)); color_acurve.AddKey(KeyframeUtil.GetNew(timeline.time, c.a, tanModeL, tanModeR)); //*defaultColorData.a } else if (color_acurve.length > 0) { color_rcurve.AddKey(KeyframeUtil.GetNew(timeline.time, defaultColorData.r, tanModeL, tanModeR)); color_gcurve.AddKey(KeyframeUtil.GetNew(timeline.time, defaultColorData.g, tanModeL, tanModeR)); color_bcurve.AddKey(KeyframeUtil.GetNew(timeline.time, defaultColorData.b, tanModeL, tanModeR)); color_acurve.AddKey(KeyframeUtil.GetNew(timeline.time, defaultColorData.a, tanModeL, tanModeR)); } } else if (timeline.type == "attachment") { if (string.IsNullOrEmpty(timeline.attachmentName)) { display_curve.AddKey(new Keyframe(timeline.time, -1f, float.PositiveInfinity, float.PositiveInfinity)); } else { for (int r = 0; r < slot.childCount; ++r) { if (slot.GetChild(r).name.Equals(timeline.attachmentName)) { display_curve.AddKey(new Keyframe(timeline.time, r, float.PositiveInfinity, float.PositiveInfinity)); break; } } } } } CurveExtension.OptimizesCurve(color_rcurve); CurveExtension.OptimizesCurve(color_gcurve); CurveExtension.OptimizesCurve(color_bcurve); CurveExtension.OptimizesCurve(color_acurve); CurveExtension.OptimizesCurve(display_curve); string path = ""; if (slotPathKV.ContainsKey(slot.name)) { path = slotPathKV[slot.name]; } else { path = GetNodeRelativePath(armatureEditor, slot); slotPathKV[slot.name] = path; } SetColorCurve <Slot>(path, clip, color_rcurve, "color.r", isHaveCurve, defaultColorData.r, animSlotData.timelines); SetColorCurve <Slot>(path, clip, color_gcurve, "color.g", isHaveCurve, defaultColorData.g, animSlotData.timelines); SetColorCurve <Slot>(path, clip, color_bcurve, "color.b", isHaveCurve, defaultColorData.b, animSlotData.timelines); SetColorCurve <Slot>(path, clip, color_acurve, "color.a", isHaveCurve, defaultColorData.a, animSlotData.timelines); //add pose AnimationCurve pose_color_rcurve = new AnimationCurve(); AnimationCurve pose_color_gcurve = new AnimationCurve(); AnimationCurve pose_color_bcurve = new AnimationCurve(); AnimationCurve pose_color_acurve = new AnimationCurve(); pose_color_rcurve.AddKey(new Keyframe(0f, defaultColorData.r)); pose_color_gcurve.AddKey(new Keyframe(0f, defaultColorData.g)); pose_color_bcurve.AddKey(new Keyframe(0f, defaultColorData.b)); pose_color_acurve.AddKey(new Keyframe(0f, defaultColorData.a)); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Slot), "color.r"), pose_color_rcurve); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Slot), "color.g"), pose_color_gcurve); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Slot), "color.b"), pose_color_bcurve); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Slot), "color.a"), pose_color_acurve); if (display_curve.keys != null && display_curve.keys.Length > 0 && CheckCurveValid(display_curve, slot.GetComponent <Slot>().displayIndex)) { clip.SetCurve(path, typeof(Slot), "m_DisplayIndex", display_curve); //add pose AnimationCurve pose_display_curve = new AnimationCurve(); pose_display_curve.AddKey(new Keyframe(0f, slot.GetComponent <Slot>().displayIndex)); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Slot), "m_DisplayIndex"), pose_display_curve); } } }
/// <summary> /// Recalculates tangents for all keyframes using the keyframe values and set tangent modes. /// </summary> private void UpdateTangents() { if (keyFrames.Length == 0) { return; } if (keyFrames.Length == 1) { keyFrames[0].inTangent = 0.0f; keyFrames[0].outTangent = 0.0f; return; } // First keyframe { KeyFrame keyThis = keyFrames[0]; KeyFrame keyNext = keyFrames[1]; keyThis.inTangent = 0.0f; TangentMode tangentMode = tangentModes[0]; if (tangentMode == TangentMode.Auto || tangentMode.HasFlag(TangentMode.OutAuto) || tangentMode.HasFlag(TangentMode.OutLinear)) { float diff = keyNext.time - keyThis.time; if (!MathEx.ApproxEquals(diff, 0.0f)) { keyThis.outTangent = (keyNext.value - keyThis.value) / diff; } else { keyThis.outTangent = float.PositiveInfinity; } } else if (tangentMode.HasFlag(TangentMode.OutStep)) { keyThis.outTangent = float.PositiveInfinity; } keyFrames[0] = keyThis; } // Inner keyframes for (int i = 1; i < keyFrames.Length - 1; i++) { KeyFrame keyPrev = keyFrames[i - 1]; KeyFrame keyThis = keyFrames[i]; KeyFrame keyNext = keyFrames[i + 1]; TangentMode tangentMode = tangentModes[i]; if (tangentMode == TangentMode.Auto) // Both automatic { float diff = keyNext.time - keyPrev.time; if (!MathEx.ApproxEquals(diff, 0.0f)) { keyThis.outTangent = (keyNext.value - keyPrev.value) / diff; } else { keyThis.outTangent = float.PositiveInfinity; } keyThis.inTangent = keyThis.outTangent; } else if (tangentMode == TangentMode.Free) // Both free { keyThis.inTangent = keyThis.outTangent; } else // Different per-tangent modes { // In tangent if (tangentMode.HasFlag(TangentMode.InAuto)) { float diff = keyNext.time - keyPrev.time; if (!MathEx.ApproxEquals(diff, 0.0f)) { keyThis.inTangent = (keyNext.value - keyPrev.value) / diff; } else { keyThis.inTangent = float.PositiveInfinity; } } else if (tangentMode.HasFlag(TangentMode.InLinear)) { float diff = keyThis.time - keyPrev.time; if (!MathEx.ApproxEquals(diff, 0.0f)) { keyThis.inTangent = (keyThis.value - keyPrev.value) / diff; } else { keyThis.inTangent = float.PositiveInfinity; } } else if (tangentMode.HasFlag(TangentMode.InStep)) { keyThis.inTangent = float.PositiveInfinity; } // Out tangent if (tangentMode.HasFlag(TangentMode.OutAuto)) { float diff = keyNext.time - keyPrev.time; if (!MathEx.ApproxEquals(diff, 0.0f)) { keyThis.outTangent = (keyNext.value - keyPrev.value) / diff; } else { keyThis.outTangent = float.PositiveInfinity; } } else if (tangentMode.HasFlag(TangentMode.OutLinear)) { float diff = keyNext.time - keyThis.time; if (!MathEx.ApproxEquals(diff, 0.0f)) { keyThis.outTangent = (keyNext.value - keyThis.value) / diff; } else { keyThis.outTangent = float.PositiveInfinity; } } else if (tangentMode.HasFlag(TangentMode.OutStep)) { keyThis.outTangent = float.PositiveInfinity; } } keyFrames[i] = keyThis; } // Last keyframe { KeyFrame keyThis = keyFrames[keyFrames.Length - 1]; KeyFrame keyPrev = keyFrames[keyFrames.Length - 2]; keyThis.outTangent = 0.0f; TangentMode tangentMode = tangentModes[tangentModes.Length - 1]; if (tangentMode == TangentMode.Auto || tangentMode.HasFlag(TangentMode.InAuto) || tangentMode.HasFlag(TangentMode.InLinear)) { float diff = keyThis.time - keyPrev.time; if (!MathEx.ApproxEquals(diff, 0.0f)) { keyThis.inTangent = (keyThis.value - keyPrev.value) / diff; } else { keyThis.inTangent = float.PositiveInfinity; } } else if (tangentMode.HasFlag(TangentMode.InStep)) { keyThis.inTangent = float.PositiveInfinity; } keyFrames[keyFrames.Length - 1] = keyThis; } }
public static Keyframe GetNew(float time, float value, TangentMode left, TangentMode right) { object boxed = new Keyframe(time, value); // cant use struct in reflection SetKeyBroken(boxed, true); SetKeyTangentMode(boxed, 0, left); SetKeyTangentMode(boxed, 1, right); Keyframe keyframe = (Keyframe)boxed; if (left == TangentMode.Stepped) { keyframe.inTangent = float.PositiveInfinity; } if (right == TangentMode.Stepped) { keyframe.outTangent = float.PositiveInfinity; } return(keyframe); }
static bool CreateAnimBone(SpineArmatureEditor armatureEditor, AnimationClip clip, SpineData.AnimationBoneData[] animBoneDatas) { Dictionary <string, string> bonePathKV = new Dictionary <string, string>(); for (int i = 0; i < animBoneDatas.Length; ++i) { SpineData.AnimationBoneData animBoneData = animBoneDatas[i]; Transform bone = armatureEditor.bonesKV[animBoneData.name]; AnimationCurve xcurve = new AnimationCurve(); AnimationCurve ycurve = new AnimationCurve(); AnimationCurve sxcurve = new AnimationCurve(); AnimationCurve sycurve = new AnimationCurve(); AnimationCurve rotatecurve = new AnimationCurve(); bool isHaveCurve = false; for (int j = 0; j < animBoneData.timelines.Length; ++j) { SpineData.BoneTimeline timeline = animBoneData.timelines[j]; string prevTweeneasing = "linear"; //前一帧的tweenEasing float[] prevCurves = null; if (j > 0) { prevTweeneasing = animBoneData.timelines[j - 1].tweenEasing; prevCurves = animBoneData.timelines[j - 1].curve; } TangentMode tanModeL = GetPrevFrameTangentMode(prevTweeneasing, prevCurves); TangentMode tanModeR = TangentMode.Linear; if (timeline.curve != null && timeline.curve.Length > 0) { tanModeR = TangentMode.Editable; isHaveCurve = true; } else { if (timeline.tweenEasing == "stepped") { tanModeR = TangentMode.Stepped; } else { tanModeR = TangentMode.Linear; } } if (timeline.type == "rotate") //rotate,scale,translate,shear { if (!float.IsNaN(timeline.angle)) { float rotate = timeline.angle + bone.localEulerAngles.z; rotatecurve.AddKey(KeyframeUtil.GetNew(timeline.time, rotate, tanModeL, tanModeR)); } } else if (timeline.type == "translate") { if (!float.IsNaN(timeline.x)) { xcurve.AddKey(KeyframeUtil.GetNew(timeline.time, timeline.x + bone.localPosition.x, tanModeL, tanModeR)); } if (!float.IsNaN(timeline.y)) { ycurve.AddKey(KeyframeUtil.GetNew(timeline.time, timeline.y + bone.localPosition.y, tanModeL, tanModeR)); } } else if (timeline.type == "scale") { if (!float.IsNaN(timeline.x)) { sxcurve.AddKey(KeyframeUtil.GetNew(timeline.time, timeline.x * bone.localScale.x, tanModeL, tanModeR)); } if (!float.IsNaN(timeline.y)) { sycurve.AddKey(KeyframeUtil.GetNew(timeline.time, timeline.y * bone.localScale.y, tanModeL, tanModeR)); } } } CurveExtension.OptimizesCurve(xcurve); CurveExtension.OptimizesCurve(ycurve); CurveExtension.OptimizesCurve(sxcurve); CurveExtension.OptimizesCurve(sycurve); CurveExtension.OptimizesCurve(rotatecurve); string path = ""; if (bonePathKV.ContainsKey(bone.name)) { path = bonePathKV[bone.name]; } else { path = GetNodeRelativePath(armatureEditor, bone); bonePathKV[bone.name] = path; if (slotPathKV.ContainsKey(bone.name) && slotPathKV[bone.name].Equals(path)) { Debug.LogError("Bone2D Error: Name conflict ->" + path); return(false); } } bool localPosFlag = false; if (xcurve.keys != null && xcurve.keys.Length > 0 && CheckCurveValid(xcurve, bone.localPosition.x)) { localPosFlag = true; } if (ycurve.keys != null && ycurve.keys.Length > 0 && CheckCurveValid(ycurve, bone.localPosition.y)) { localPosFlag = true; } if (localPosFlag) { if (isHaveCurve) { SetCustomCurveTangents(xcurve, animBoneData.timelines); } CurveExtension.UpdateAllLinearTangents(xcurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.x"), xcurve); if (isHaveCurve) { SetCustomCurveTangents(ycurve, animBoneData.timelines); } CurveExtension.UpdateAllLinearTangents(ycurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.y"), ycurve); //add pose AnimationCurve posexcurve = new AnimationCurve(); AnimationCurve poseycurve = new AnimationCurve(); posexcurve.AddKey(new Keyframe(0f, bone.localPosition.x)); poseycurve.AddKey(new Keyframe(0f, bone.localPosition.y)); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.x"), posexcurve); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.y"), poseycurve); } Bone myBone = bone.GetComponent <Bone>(); string scPath = path; if (myBone && myBone.inheritScale) { scPath = myBone.inheritScale.name; } bool localSc = false; if (sxcurve.keys != null && sxcurve.keys.Length > 0 && CheckCurveValid(sxcurve, bone.localScale.x)) { localSc = true; } if (sycurve.keys != null && sycurve.keys.Length > 0 && CheckCurveValid(sycurve, bone.localScale.y)) { localSc = true; } if (localSc) { if (isHaveCurve) { SetCustomCurveTangents(sxcurve, animBoneData.timelines); } CurveExtension.UpdateAllLinearTangents(sxcurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(scPath, typeof(Transform), "m_LocalScale.x"), sxcurve); if (isHaveCurve) { SetCustomCurveTangents(sycurve, animBoneData.timelines); } CurveExtension.UpdateAllLinearTangents(sycurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(scPath, typeof(Transform), "m_LocalScale.y"), sycurve); //add pose AnimationCurve posesxcurve = new AnimationCurve(); AnimationCurve posesycurve = new AnimationCurve(); posesxcurve.AddKey(new Keyframe(0f, bone.localScale.x)); posesycurve.AddKey(new Keyframe(0f, bone.localScale.y)); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalScale.x"), posesxcurve); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalScale.y"), posesycurve); } string rotatePath = path; if (myBone && myBone.inheritRotation) { rotatePath = myBone.inheritRotation.name; } if (rotatecurve.keys != null && rotatecurve.keys.Length > 0 && CheckCurveValid(rotatecurve, bone.localEulerAngles.z)) { CurveExtension.ClampCurveRotate360(rotatecurve, false); if (isHaveCurve) { SetCustomCurveTangents(rotatecurve, animBoneData.timelines); } CurveExtension.UpdateAllLinearTangents(rotatecurve); clip.SetCurve(rotatePath, typeof(Transform), "localEulerAngles.z", rotatecurve); //add pose AnimationCurve posesrotatecurve = new AnimationCurve(); posesrotatecurve.AddKey(new Keyframe(0f, bone.localEulerAngles.z)); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "localEulerAngles.z"), posesrotatecurve); } } return(true); }
/// <summary> /// Bezier curve constructor. /// </summary> /// <param name="from">First point.</param> /// <param name="to">Second point.</param> /// <param name="color">Line color.</param> /// <param name="lineWidth">Line width.</param> /// <param name="tangentMode">Tangent mode.</param> /// <param name="fromTangent">First tangent.</param> /// <param name="toTangent">Second tangent.</param> /// <param name="zindex">Drawing order.</param> /// <param name="drawEarly">If set to true, shape will render before controls.</param> public BezierCurve( Vector2 from, Vector2 to, Color color, float lineWidth = 1.0f, TangentMode tangentMode = TangentMode.AutoX, Vector2 fromTangent = default(Vector2), Vector2 toTangent = default(Vector2), int zindex = 0, bool drawEarly = false ) { From = from; To = to; FromTangent = fromTangent; ToTangent = toTangent; Tangents = tangentMode; LineWidth = lineWidth; TangentDistance = 0.3f; DrawColor = color; ZIndex = zindex; DrawEarly = drawEarly; }
public static void SetKeyTangentMode(ref Keyframe key, int leftRight, TangentMode mode) { if (leftRight == 0) { key.tangentMode &= -7; key.tangentMode |= (int) mode << 1; } else { key.tangentMode &= -25; key.tangentMode |= (int) mode << 3; } if (CurveUtility.GetKeyTangentMode(key, leftRight) == mode) return; Debug.Log((object) "bug"); }
private void HandleDragTangent() { EventType eventType = currentEvent.GetTypeForControl(m_DragTangentControlId); if ((!currentEvent.alt && GUIUtility.hotControl == 0 && m_HoveredTangentPoint != -1 && !EditorGUI.actionKey) || GUIUtility.hotControl == m_DragTangentControlId) { if (eventType == EventType.MouseDown && currentEvent.button == 0) { m_ActiveTangentPointIndex = m_HoveredTangentPoint; m_DragLeftTangent = m_HoveredLeftTangent; m_CurrentTangentMode = GetTangentMode(m_ActiveTangentPointIndex); if (m_DragLeftTangent) { m_SliderPosition = GetLeftTangent(m_HoveredTangentPoint) + GetPosition(m_HoveredTangentPoint); } else { m_SliderPosition = GetRightTangent(m_HoveredTangentPoint) + GetPosition(m_HoveredTangentPoint); } } var abortDrag = GUIUtility.hotControl == m_DragTangentControlId && m_ActiveTangentPointIndex != -1 && m_CurrentTangentMode != GetTangentMode(m_ActiveTangentPointIndex); var finishDrag = GUIUtility.hotControl == m_DragTangentControlId && eventType == EventType.MouseUp && currentEvent.button == 0; if (finishDrag || abortDrag) { Debug.Assert(m_ActiveTangentPointIndex != -1); var leftTangent = GetLeftTangent(m_ActiveTangentPointIndex); var rightTangent = GetRightTangent(m_ActiveTangentPointIndex); if (leftTangent.sqrMagnitude == 0f && rightTangent.sqrMagnitude == 0f) { SetTangentModeUseThisOne(m_ActiveTangentPointIndex, TangentMode.Linear); } m_ActiveTangentPointIndex = -1; } if (abortDrag) { GUIUtility.hotControl = 0; } if (eventType == EventType.Layout && GUIUtility.hotControl == 0) { HandleUtility.AddControl(m_DragTangentControlId, 0f); } EditorGUI.BeginChangeCheck(); Vector3 newPosition = DoSlider(m_DragTangentControlId, m_SliderPosition, GetUpVector(), GetRightVector(), GetHandleSize(m_SliderPosition), (int cid, Vector3 p, Quaternion q, float s, EventType et) => { }); if (EditorGUI.EndChangeCheck()) { RegisterUndoOnSliderChangedOnce(); var tangent = newPosition - GetPosition(m_ActiveTangentPointIndex); if (tangent.magnitude < GetHandleSize(GetPosition(m_ActiveTangentPointIndex))) { tangent = Vector3.zero; } var activeMode = GetTangentMode(m_ActiveTangentPointIndex); var doMirrorTangents = currentEvent.shift && activeMode != TangentMode.Linear; if (m_DragLeftTangent) { SetLeftTangent(m_ActiveTangentPointIndex, tangent); if (doMirrorTangents) { tangent *= -1f; SetRightTangent(m_ActiveTangentPointIndex, tangent); } } else { SetRightTangent(m_ActiveTangentPointIndex, tangent); if (doMirrorTangents) { tangent *= -1f; SetLeftTangent(m_ActiveTangentPointIndex, tangent); } } ValidateTangents(!m_DragLeftTangent); } } }
static void CreateFFDAnim(ArmatureEditor armatureEditor, AnimationClip clip, DragonBoneData.AnimSubData[] subDatas, Dictionary <string, Transform> transformKV) { if (subDatas == null) { return; } for (int i = 0; i < subDatas.Length; ++i) { DragonBoneData.AnimSubData animSubData = subDatas[i]; string slotName = string.IsNullOrEmpty(animSubData.slot) ? animSubData.name : animSubData.slot; Transform slotNode = transformKV[slotName]; List <AnimationCurve[]> vertexcurvexArray = null; List <AnimationCurve[]> vertexcurveyArray = null; if (slotNode.childCount > 0) { vertexcurvexArray = new List <AnimationCurve[]>(); vertexcurveyArray = new List <AnimationCurve[]>(); for (int j = 0; j < slotNode.childCount; ++j) { Transform ffdNode = slotNode.GetChild(j); if (ffdNode.name == animSubData.name) { AnimationCurve[] vertex_xcurves = new AnimationCurve[ffdNode.childCount]; AnimationCurve[] vertex_ycurves = new AnimationCurve[ffdNode.childCount]; for (int r = 0; r < vertex_xcurves.Length; ++r) { vertex_xcurves[r] = new AnimationCurve(); vertex_ycurves[r] = new AnimationCurve(); } vertexcurvexArray.Add(vertex_xcurves); vertexcurveyArray.Add(vertex_ycurves); } } } float during = animSubData.offset; float perKeyTime = 1f / armatureEditor.armatureData.frameRate; bool isHaveCurve = false; for (int j = 0; j < animSubData.frameDatas.Length; ++j) { DragonBoneData.AnimFrameData frameData = animSubData.frameDatas[j]; float prevTweeneasing = float.PositiveInfinity; //前一帧的tweenEasing float[] prevCurves = null; if (j > 0) { prevTweeneasing = animSubData.frameDatas[j - 1].tweenEasing; prevCurves = animSubData.frameDatas[j - 1].curve; } TangentMode tanModeL = GetPrevFrameTangentMode(prevTweeneasing, prevCurves); TangentMode tanModeR = TangentMode.Linear; if (frameData.curve != null && frameData.curve.Length > 0) { tanModeR = TangentMode.Editable; isHaveCurve = true; } else { if (frameData.tweenEasing == float.PositiveInfinity) { tanModeR = TangentMode.Stepped; } else if (frameData.tweenEasing == 0) { tanModeR = TangentMode.Linear; } else if (frameData.tweenEasing == 1) { tanModeR = TangentMode.Smooth; } else if (frameData.tweenEasing == 2) { tanModeR = TangentMode.Linear; } } //mesh animation if (vertexcurvexArray != null) { for (int k = 0; k < vertexcurvexArray.Count; ++k) { Transform ffdNode = slotNode.GetChild(k); if (ffdNode.name == animSubData.name) { AnimationCurve[] vertex_xcurves = vertexcurvexArray[k]; AnimationCurve[] vertex_ycurves = vertexcurveyArray[k]; int len = ffdNode.childCount; if (frameData.vertices != null && frameData.vertices.Length > 0) { for (int r = 0; r < len; ++r) { AnimationCurve vertex_xcurve = vertex_xcurves[r]; AnimationCurve vertex_ycurve = vertex_ycurves[r]; Transform vCtr = ffdNode.GetChild(r); //顶点控制点 if (r >= frameData.offset && r - frameData.offset < frameData.vertices.Length) { Keyframe kfx = KeyframeUtil.GetNew(during, vCtr.localPosition.x + frameData.vertices[r - frameData.offset].x, tanModeL, tanModeR); vertex_xcurve.AddKey(kfx); Keyframe kfy = KeyframeUtil.GetNew(during, vCtr.localPosition.y + frameData.vertices[r - frameData.offset].y, tanModeL, tanModeR); vertex_ycurve.AddKey(kfy); } else { Keyframe kfx = KeyframeUtil.GetNew(during, vCtr.localPosition.x, tanModeL, tanModeR); vertex_xcurve.AddKey(kfx); Keyframe kfy = KeyframeUtil.GetNew(during, vCtr.localPosition.y, tanModeL, tanModeR); vertex_ycurve.AddKey(kfy); } } } else { //add default vertex position for (int r = 0; r < len; ++r) { AnimationCurve vertex_xcurve = vertex_xcurves[r]; AnimationCurve vertex_ycurve = vertex_ycurves[r]; Transform vCtr = slotNode.GetChild(k).GetChild(r); //顶点控制点 Keyframe kfx = KeyframeUtil.GetNew(during, vCtr.localPosition.x, tanModeL, tanModeR); vertex_xcurve.AddKey(kfx); Keyframe kfy = KeyframeUtil.GetNew(during, vCtr.localPosition.y, tanModeL, tanModeR); vertex_ycurve.AddKey(kfy); } } } } } during += frameData.duration * perKeyTime; } string path = ""; if (slotPathKV.ContainsKey(slotName)) { path = slotPathKV[slotName]; } else { path = GetNodeRelativePath(armatureEditor, slotNode); slotPathKV[slotName] = path; } if (vertexcurvexArray != null) { for (int k = 0; k < vertexcurvexArray.Count; ++k) { Transform ffdNode = slotNode.GetChild(k); if (ffdNode.name == animSubData.name) { changedSpriteMeshsKV[path + "/" + ffdNode.name] = ffdNode.GetComponent <SpriteMesh>(); AnimationCurve[] vertex_xcurves = vertexcurvexArray[k]; AnimationCurve[] vertex_ycurves = vertexcurveyArray[k]; for (int r = 0; r < vertex_xcurves.Length; ++r) { AnimationCurve vertex_xcurve = vertex_xcurves[r]; AnimationCurve vertex_ycurve = vertex_ycurves[r]; Transform v = ffdNode.GetChild(r); string ctrlPath = path + "/" + ffdNode.name + "/" + v.name; CurveExtension.OptimizesCurve(vertex_xcurve); CurveExtension.OptimizesCurve(vertex_ycurve); bool vcurveFlag = false; if (vertex_xcurve.keys != null && vertex_xcurve.keys.Length > 0 && CheckCurveValid(vertex_xcurve, v.localPosition.x)) { vcurveFlag = true; } if (vertex_ycurve.keys != null && vertex_ycurve.keys.Length > 0 && CheckCurveValid(vertex_ycurve, v.localPosition.y)) { vcurveFlag = true; } if (vcurveFlag) { if (isHaveCurve) { SetCustomCurveTangents(vertex_xcurve, animSubData.frameDatas); } CurveExtension.UpdateAllLinearTangents(vertex_xcurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(ctrlPath, typeof(Transform), "m_LocalPosition.x"), vertex_xcurve); if (isHaveCurve) { SetCustomCurveTangents(vertex_ycurve, animSubData.frameDatas); } CurveExtension.UpdateAllLinearTangents(vertex_ycurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(ctrlPath, typeof(Transform), "m_LocalPosition.y"), vertex_ycurve); } } } } } } }
private void HandleInsertPointToEdge() { EventType eventType = currentEvent.GetTypeForControl(m_DragPointControlId); if (m_HoveredPointIndex == -1 && m_HoveredEdgeIndex != -1 && GUIUtility.hotControl == 0 && eventType == EventType.MouseDown && currentEvent.button == 0 && !currentEvent.shift) { RegisterUndo(); ClearSelection(); int nextIndex = SplineUtility.NextIndex(m_HoveredEdgeIndex, GetPointCount()); TangentMode leftTangentMode = GetTangentMode(m_HoveredEdgeIndex); TangentMode rightTangentMode = GetTangentMode(nextIndex); Vector3 leftStartPosition; Vector3 leftEndPosition; Vector3 leftStartTangent; Vector3 leftEndTangent; Vector3 rightStartPosition; Vector3 rightEndPosition; Vector3 rightStartTangent; Vector3 rightEndTangent; Vector3 position0 = GetPosition(m_HoveredEdgeIndex); Vector3 position1 = GetPosition(nextIndex); Vector3 tangent0 = GetRightTangent(m_HoveredEdgeIndex) + position0; Vector3 tangent1 = GetLeftTangent(nextIndex) + position1; BezierUtility.SplitBezier(m_ClosestPointT, position0, position1, tangent0, tangent1, out leftStartPosition, out leftEndPosition, out leftStartTangent, out leftEndTangent, out rightStartPosition, out rightEndPosition, out rightStartTangent, out rightEndTangent); if (leftTangentMode != TangentMode.Linear) { SetRightTangent(m_HoveredEdgeIndex, leftStartTangent - leftStartPosition); } if (rightTangentMode != TangentMode.Linear) { SetLeftTangent(nextIndex, rightEndTangent - rightEndPosition); } InsertPointAt(nextIndex, m_ClosestPoint); if (leftTangentMode != TangentMode.Linear || rightTangentMode != TangentMode.Linear) { if (leftTangentMode == TangentMode.Linear && rightTangentMode == TangentMode.Linear) { SetTangentModeUseThisOne(nextIndex, TangentMode.Linear); } else { SetTangentModeUseThisOne(nextIndex, TangentMode.Continuous); } SetLeftTangent(nextIndex, leftEndTangent - leftEndPosition); SetRightTangent(nextIndex, rightStartTangent - rightStartPosition); } m_HoveredPointIndex = nextIndex; m_HoveredEdgeIndex = -1; HandleUtility.nearestControl = m_DragPointControlId; } }
private TangentMode GetNextTangentMode(TangentMode current) { return((TangentMode)((((int)current) + 1) % Enum.GetValues(typeof(TangentMode)).Length)); }
static void CreateSlotAnim(ArmatureEditor armatureEditor, AnimationClip clip, DragonBoneData.AnimSubData[] subDatas, Dictionary <string, Transform> transformKV) { for (int i = 0; i < subDatas.Length; ++i) { DragonBoneData.AnimSubData animSubData = subDatas[i]; string slotName = string.IsNullOrEmpty(animSubData.slot) ? animSubData.name : animSubData.slot; Transform slotNode = transformKV[slotName]; DragonBoneData.SlotData defaultSlotData = armatureEditor.slotsDataKV[slotName]; DragonBoneData.ColorData defaultColorData = defaultSlotData.color; AnimationCurve color_rcurve = new AnimationCurve(); AnimationCurve color_gcurve = new AnimationCurve(); AnimationCurve color_bcurve = new AnimationCurve(); AnimationCurve color_acurve = new AnimationCurve(); AnimationCurve display_curve = new AnimationCurve(); float during = animSubData.offset; float perKeyTime = 1f / armatureEditor.armatureData.frameRate; bool isHaveCurve = false; for (int j = 0; j < animSubData.frameDatas.Length; ++j) { DragonBoneData.AnimFrameData frameData = animSubData.frameDatas[j]; float prevTweeneasing = float.PositiveInfinity; //前一帧的tweenEasing float[] prevCurves = null; if (j > 0) { prevTweeneasing = animSubData.frameDatas[j - 1].tweenEasing; prevCurves = animSubData.frameDatas[j - 1].curve; } TangentMode tanModeL = GetPrevFrameTangentMode(prevTweeneasing, prevCurves); TangentMode tanModeR = TangentMode.Linear; if (frameData.curve != null && frameData.curve.Length > 0) { tanModeR = TangentMode.Editable; isHaveCurve = true; } else { if (frameData.tweenEasing == float.PositiveInfinity) { tanModeR = TangentMode.Stepped; } else if (frameData.tweenEasing == 0) { tanModeR = TangentMode.Linear; } else if (frameData.tweenEasing == 1) { tanModeR = TangentMode.Smooth; } else if (frameData.tweenEasing == 2) { tanModeR = TangentMode.Linear; } } if (frameData.color != null) { if (defaultColorData == null) { defaultColorData = new DragonBoneData.ColorData(); } Color c = new Color( frameData.color.rM + frameData.color.r0, frameData.color.gM + frameData.color.g0, frameData.color.bM + frameData.color.b0, frameData.color.aM + frameData.color.a0 ); color_rcurve.AddKey(KeyframeUtil.GetNew(during, c.r, tanModeL, tanModeR)); color_gcurve.AddKey(KeyframeUtil.GetNew(during, c.g, tanModeL, tanModeR)); color_bcurve.AddKey(KeyframeUtil.GetNew(during, c.b, tanModeL, tanModeR)); color_acurve.AddKey(KeyframeUtil.GetNew(during, c.a, tanModeL, tanModeR)); } //改displyindex if (frameData.displayIndex > -2) { display_curve.AddKey(new Keyframe(during, frameData.displayIndex, float.PositiveInfinity, float.PositiveInfinity)); } during += frameData.duration * perKeyTime; } CurveExtension.OptimizesCurve(color_rcurve); CurveExtension.OptimizesCurve(color_gcurve); CurveExtension.OptimizesCurve(color_bcurve); CurveExtension.OptimizesCurve(color_acurve); CurveExtension.OptimizesCurve(display_curve); string path = ""; if (slotPathKV.ContainsKey(slotName)) { path = slotPathKV[slotName]; } else { path = GetNodeRelativePath(armatureEditor, slotNode); slotPathKV[slotNode.name] = path; } if (defaultColorData == null) { defaultColorData = new DragonBoneData.ColorData(); } float da = defaultColorData.aM + defaultColorData.a0; float dr = defaultColorData.rM + defaultColorData.r0; float dg = defaultColorData.gM + defaultColorData.g0; float db = defaultColorData.bM + defaultColorData.b0; SetColorCurve <Slot>(path, clip, color_rcurve, "color.r", isHaveCurve, dr, animSubData.frameDatas); SetColorCurve <Slot>(path, clip, color_gcurve, "color.g", isHaveCurve, dg, animSubData.frameDatas); SetColorCurve <Slot>(path, clip, color_bcurve, "color.b", isHaveCurve, db, animSubData.frameDatas); SetColorCurve <Slot>(path, clip, color_acurve, "color.a", isHaveCurve, da, animSubData.frameDatas); if (display_curve.keys != null && display_curve.keys.Length > 0 && CheckCurveValid(display_curve, slotNode.GetComponent <Slot>().displayIndex)) { clip.SetCurve(path, typeof(Slot), "m_DisplayIndex", display_curve); } } }
private static extern void Internal_selectKeyframe(IntPtr thisPtr, ref KeyframeRef keyframeRef, TangentMode tangentMode, bool selected);
public static void SetTangentMode(this IEditablePath path, int index, TangentMode tangentMode) { var localToWorldMatrix = path.localToWorldMatrix; path.localToWorldMatrix = Matrix4x4.identity; var controlPoint = path.GetPoint(index); var isEndpoint = path.isOpenEnded && (index == 0 || index == path.pointCount - 1); var oldTangentMode = controlPoint.tangentMode; controlPoint.tangentMode = tangentMode; controlPoint.RestoreTangents(); if (tangentMode == TangentMode.Linear) { controlPoint.localLeftTangent = Vector3.zero; controlPoint.localRightTangent = Vector3.zero; } else if (tangentMode == TangentMode.Continuous && !isEndpoint) { var isLeftLinear = controlPoint.localLeftTangent == Vector3.zero; var isRightLinear = controlPoint.localRightTangent == Vector3.zero; var tangentDotProduct = Vector3.Dot(controlPoint.localLeftTangent.normalized, controlPoint.localRightTangent.normalized); var isContinous = tangentDotProduct < 0f && (tangentDotProduct + 1) < 0.001f; var isLinear = isLeftLinear && isRightLinear; if ((isLinear || oldTangentMode == TangentMode.Broken) && !isContinous) { var prevPoint = path.GetPrevPoint(index); var nextPoint = path.GetNextPoint(index); var vLeft = prevPoint.position - controlPoint.position; var vRight = nextPoint.position - controlPoint.position; var rightDirection = Vector3.Cross(Vector3.Cross(vLeft, vRight), vLeft.normalized + vRight.normalized).normalized; var scale = 1f / 3f; if (isLeftLinear) { controlPoint.localLeftTangent = vLeft.magnitude * scale * -rightDirection; } else { controlPoint.localLeftTangent = controlPoint.localLeftTangent.magnitude * -rightDirection; } if (isRightLinear) { controlPoint.localRightTangent = vRight.magnitude * scale * rightDirection; } else { controlPoint.localRightTangent = controlPoint.localRightTangent.magnitude * rightDirection; } } } else { var isLeftLinear = controlPoint.localLeftTangent == Vector3.zero; var isRightLinear = controlPoint.localRightTangent == Vector3.zero; if (isLeftLinear || isRightLinear) { if (isLeftLinear) { controlPoint.localLeftTangent = path.CalculateLocalLeftTangent(index); } if (isRightLinear) { controlPoint.localRightTangent = path.CalculateLocalRightTangent(index); } } } controlPoint.StoreTangents(); path.SetPoint(index, controlPoint); path.localToWorldMatrix = localToWorldMatrix; }
static void CreateBoneAnim(ArmatureEditor armatureEditor, AnimationClip clip, DragonBoneData.AnimSubData[] subDatas, Dictionary <string, Transform> transformKV) { if (subDatas == null) { return; } Dictionary <string, string> bonePathKV = new Dictionary <string, string>(); for (int i = 0; i < subDatas.Length; ++i) { DragonBoneData.AnimSubData animSubData = subDatas[i]; string boneName = animSubData.name; Transform boneNode = transformKV[boneName]; DragonBoneData.TransformData defaultTransformData = armatureEditor.bonesDataKV[animSubData.name].transform; AnimationCurve xcurve = new AnimationCurve(); AnimationCurve ycurve = new AnimationCurve(); AnimationCurve sxcurve = new AnimationCurve(); AnimationCurve sycurve = new AnimationCurve(); AnimationCurve rotatecurve = new AnimationCurve(); float during = animSubData.offset; float perKeyTime = 1f / armatureEditor.armatureData.frameRate; bool isHaveCurve = false; for (int j = 0; j < animSubData.frameDatas.Length; ++j) { DragonBoneData.AnimFrameData frameData = animSubData.frameDatas[j]; float prevTweeneasing = float.PositiveInfinity; //前一帧的tweenEasing float[] prevCurves = null; if (j > 0) { prevTweeneasing = animSubData.frameDatas[j - 1].tweenEasing; prevCurves = animSubData.frameDatas[j - 1].curve; } TangentMode tanModeL = GetPrevFrameTangentMode(prevTweeneasing, prevCurves); TangentMode tanModeR = TangentMode.Linear; if (frameData.curve != null && frameData.curve.Length > 0) { tanModeR = TangentMode.Editable; isHaveCurve = true; } else { if (frameData.tweenEasing == float.PositiveInfinity) { tanModeR = TangentMode.Stepped; } else if (frameData.tweenEasing == 0) { tanModeR = TangentMode.Linear; } else if (frameData.tweenEasing == 1) { tanModeR = TangentMode.Smooth; } else if (frameData.tweenEasing == 2) { tanModeR = TangentMode.Linear; } } if (frameData.transformData != null) { if (!float.IsNaN(frameData.transformData.x)) { if (!float.IsNaN(defaultTransformData.x)) { xcurve.AddKey(KeyframeUtil.GetNew(during, frameData.transformData.x + defaultTransformData.x, tanModeL, tanModeR)); } else { xcurve.AddKey(KeyframeUtil.GetNew(during, frameData.transformData.x, tanModeL, tanModeR)); } } else if (!float.IsNaN(defaultTransformData.x)) { xcurve.AddKey(KeyframeUtil.GetNew(during, defaultTransformData.x, tanModeL, tanModeR)); } if (!float.IsNaN(frameData.transformData.y)) { if (!float.IsNaN(defaultTransformData.y)) { ycurve.AddKey(KeyframeUtil.GetNew(during, frameData.transformData.y + defaultTransformData.y, tanModeL, tanModeR)); } else { ycurve.AddKey(KeyframeUtil.GetNew(during, frameData.transformData.y, tanModeL, tanModeR)); } } else if (!float.IsNaN(defaultTransformData.y)) { ycurve.AddKey(KeyframeUtil.GetNew(during, defaultTransformData.y, tanModeL, tanModeR)); } if (!float.IsNaN(frameData.transformData.rotate)) { float rotate = frameData.transformData.rotate + defaultTransformData.rotate; rotatecurve.AddKey(KeyframeUtil.GetNew(during, rotate, tanModeL, tanModeR)); } else if (!float.IsNaN(defaultTransformData.rotate)) { rotatecurve.AddKey(KeyframeUtil.GetNew(during, boneNode.localEulerAngles.z, tanModeL, tanModeR)); } if (!float.IsNaN(frameData.transformData.scx)) { sxcurve.AddKey(KeyframeUtil.GetNew(during, frameData.transformData.scx * defaultTransformData.scx, tanModeL, tanModeR)); } else { sxcurve.AddKey(KeyframeUtil.GetNew(during, boneNode.localScale.x, tanModeL, tanModeR)); } if (!float.IsNaN(frameData.transformData.scy)) { sycurve.AddKey(KeyframeUtil.GetNew(during, frameData.transformData.scy * defaultTransformData.scy, tanModeL, tanModeR)); } else { sycurve.AddKey(KeyframeUtil.GetNew(during, boneNode.localScale.y, tanModeL, tanModeR)); } } during += frameData.duration * perKeyTime; } CurveExtension.OptimizesCurve(xcurve); CurveExtension.OptimizesCurve(ycurve); CurveExtension.OptimizesCurve(sxcurve); CurveExtension.OptimizesCurve(sycurve); CurveExtension.OptimizesCurve(rotatecurve); string path = ""; if (bonePathKV.ContainsKey(boneName)) { path = bonePathKV[boneName]; } else { path = GetNodeRelativePath(armatureEditor, boneNode); bonePathKV[boneName] = path; } bool localPosFlag = false; if (xcurve.keys != null && xcurve.keys.Length > 0 && CheckCurveValid(xcurve, boneNode.localPosition.x)) { localPosFlag = true; } if (ycurve.keys != null && ycurve.keys.Length > 0 && CheckCurveValid(ycurve, boneNode.localPosition.y)) { localPosFlag = true; } if (localPosFlag) { if (isHaveCurve) { SetCustomCurveTangents(xcurve, animSubData.frameDatas); } CurveExtension.UpdateAllLinearTangents(xcurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.x"), xcurve); if (isHaveCurve) { SetCustomCurveTangents(ycurve, animSubData.frameDatas); } CurveExtension.UpdateAllLinearTangents(ycurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.y"), ycurve); } bool localSc = false; if (sxcurve.keys != null && sxcurve.keys.Length > 0 && CheckCurveValid(sxcurve, defaultTransformData.scx)) { localSc = true; } if (sycurve.keys != null && sycurve.keys.Length > 0 && CheckCurveValid(sycurve, defaultTransformData.scy)) { localSc = true; } if (localSc) { if (isHaveCurve) { SetCustomCurveTangents(sxcurve, animSubData.frameDatas); } CurveExtension.UpdateAllLinearTangents(sxcurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalScale.x"), sxcurve); if (isHaveCurve) { SetCustomCurveTangents(sycurve, animSubData.frameDatas); } CurveExtension.UpdateAllLinearTangents(sycurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalScale.y"), sycurve); } if (rotatecurve.keys != null && rotatecurve.keys.Length > 0 && CheckCurveValid(rotatecurve, defaultTransformData.rotate)) { CurveExtension.ClampCurveRotate360(rotatecurve); if (isHaveCurve) { SetCustomCurveTangents(rotatecurve, animSubData.frameDatas); } CurveExtension.UpdateAllLinearTangents(rotatecurve); clip.SetCurve(path, typeof(Transform), "localEulerAngles.z", rotatecurve); } } }
void SetKeyTangentMode(ref Keyframe key, int leftRight, TangentMode mode) { if (leftRight == 0) { key.tangentMode &= ~kLeftTangentMask; key.tangentMode |= (int)mode << 1; } else { key.tangentMode &= ~kRightTangentMask; key.tangentMode |= (int)mode << 3; } if (GetKeyTangentMode (key, leftRight) != mode) Debug.Log("bug"); }
public void SetTangent(int leftRight, TangentMode mode, List<KeyIdentifier> keysToSet) { List<int> list = new List<int>(); foreach (KeyIdentifier current in keysToSet) { AnimationCurve curve = current.curve; Keyframe keyframe = current.keyframe; CurveUtility.SetKeyBroken(ref keyframe, true); if (leftRight == 2) { CurveUtility.SetKeyTangentMode(ref keyframe, 0, mode); CurveUtility.SetKeyTangentMode(ref keyframe, 1, mode); } else { CurveUtility.SetKeyTangentMode(ref keyframe, leftRight, mode); if (CurveUtility.GetKeyTangentMode(keyframe, 1 - leftRight) == TangentMode.Smooth) { CurveUtility.SetKeyTangentMode(ref keyframe, 1 - leftRight, TangentMode.Editable); } } if (mode == TangentMode.Stepped && (leftRight == 0 || leftRight == 2)) { keyframe.inTangent = float.PositiveInfinity; } if (mode == TangentMode.Stepped && (leftRight == 1 || leftRight == 2)) { keyframe.outTangent = float.PositiveInfinity; } curve.MoveKey(current.key, keyframe); CurveUtility.UpdateTangentsFromModeSurrounding(curve, current.key); list.Add(current.curveId); } this.updater.UpdateCurves(list, "Set Tangents"); }
static void CreateSlotAnim(ArmatureEditor armatureEditor, AnimationClip clip, DragonBoneData.AnimSubData[] subDatas, Dictionary <string, Transform> transformKV) { for (int i = 0; i < subDatas.Length; ++i) { DragonBoneData.AnimSubData animSubData = subDatas[i]; string slotName = string.IsNullOrEmpty(animSubData.slot) ? animSubData.name : animSubData.slot; Transform slotNode = transformKV[slotName]; DragonBoneData.SlotData defaultSlotData = armatureEditor.slotsDataKV[slotName]; DragonBoneData.ColorData defaultColorData = defaultSlotData.color; AnimationCurve color_rcurve = new AnimationCurve(); AnimationCurve color_gcurve = new AnimationCurve(); AnimationCurve color_bcurve = new AnimationCurve(); AnimationCurve color_acurve = new AnimationCurve(); Renderer[] renders = slotNode.GetComponentsInChildren <Renderer>(); AnimationCurve[] renderCurves = new AnimationCurve[renders.Length]; for (int r = 0; r < renderCurves.Length; ++r) { renderCurves[r] = new AnimationCurve(); } float during = animSubData.offset; float perKeyTime = 1f / armatureEditor.armatureData.frameRate; bool isHaveCurve = false; for (int j = 0; j < animSubData.frameDatas.Length; ++j) { DragonBoneData.AnimFrameData frameData = animSubData.frameDatas[j]; float prevTweeneasing = float.PositiveInfinity; //前一帧的tweenEasing float[] prevCurves = null; if (j > 0) { prevTweeneasing = animSubData.frameDatas[j - 1].tweenEasing; prevCurves = animSubData.frameDatas[j - 1].curve; } TangentMode tanModeL = GetPrevFrameTangentMode(prevTweeneasing, prevCurves); TangentMode tanModeR = TangentMode.Linear; if (frameData.curve != null && frameData.curve.Length > 0) { tanModeR = TangentMode.Editable; isHaveCurve = true; } else { if (frameData.tweenEasing == float.PositiveInfinity) { tanModeR = TangentMode.Stepped; } else if (frameData.tweenEasing == 0) { tanModeR = TangentMode.Linear; } else if (frameData.tweenEasing == 1) { tanModeR = TangentMode.Smooth; } else if (frameData.tweenEasing == 2) { tanModeR = TangentMode.Linear; } } if (frameData.color != null) { if (defaultColorData == null) { defaultColorData = new DragonBoneData.ColorData(); } Color c = new Color( frameData.color.rM + frameData.color.r0, frameData.color.gM + frameData.color.g0, frameData.color.bM + frameData.color.b0, frameData.color.aM + frameData.color.a0 ); color_rcurve.AddKey(KeyframeUtil.GetNew(during, c.r, tanModeL, tanModeR)); color_gcurve.AddKey(KeyframeUtil.GetNew(during, c.g, tanModeL, tanModeR)); color_bcurve.AddKey(KeyframeUtil.GetNew(during, c.b, tanModeL, tanModeR)); color_acurve.AddKey(KeyframeUtil.GetNew(during, c.a, tanModeL, tanModeR)); } //改displyindex if (frameData.displayIndex == -1) { for (int r = 0; r < renders.Length; ++r) { renderCurves[r].AddKey(new Keyframe(during, 0f, float.PositiveInfinity, float.PositiveInfinity)); } } else { for (int r = 0; r < renders.Length; ++r) { if (r != frameData.displayIndex) { renderCurves[r].AddKey(new Keyframe(during, 0f, float.PositiveInfinity, float.PositiveInfinity)); } else { renderCurves[r].AddKey(new Keyframe(during, 1f, float.PositiveInfinity, float.PositiveInfinity)); } } } during += frameData.duration * perKeyTime; } CurveExtension.OptimizesCurve(color_rcurve); CurveExtension.OptimizesCurve(color_gcurve); CurveExtension.OptimizesCurve(color_bcurve); CurveExtension.OptimizesCurve(color_acurve); string path = ""; if (slotPathKV.ContainsKey(slotName)) { path = slotPathKV[slotName]; } else { path = GetNodeRelativePath(armatureEditor, slotNode); slotPathKV[slotNode.name] = path; } if (defaultColorData == null) { defaultColorData = new DragonBoneData.ColorData(); } float da = defaultColorData.aM + defaultColorData.a0; float dr = defaultColorData.rM + defaultColorData.r0; float dg = defaultColorData.gM + defaultColorData.g0; float db = defaultColorData.bM + defaultColorData.b0; if (armatureEditor.useUnitySprite) { SpriteRenderer[] sprites = slotNode.GetComponentsInChildren <SpriteRenderer>(); if (sprites != null) { for (int z = 0; z < sprites.Length; ++z) { string childPath = path + "/" + sprites[z].name; SetColorCurve <SpriteRenderer>(childPath, clip, color_rcurve, "m_Color.r", isHaveCurve, dr, animSubData.frameDatas); SetColorCurve <SpriteRenderer>(childPath, clip, color_gcurve, "m_Color.g", isHaveCurve, dg, animSubData.frameDatas); SetColorCurve <SpriteRenderer>(childPath, clip, color_bcurve, "m_Color.b", isHaveCurve, db, animSubData.frameDatas); SetColorCurve <SpriteRenderer>(childPath, clip, color_acurve, "m_Color.a", isHaveCurve, da, animSubData.frameDatas); } } } else { SpriteFrame[] sprites = slotNode.GetComponentsInChildren <SpriteFrame>(); if (sprites != null) { for (int z = 0; z < sprites.Length; ++z) { string childPath = path + "/" + sprites[z].name; bool anim_r = SetColorCurve <SpriteFrame>(childPath, clip, color_rcurve, "m_color.r", isHaveCurve, dr, animSubData.frameDatas); bool anim_g = SetColorCurve <SpriteFrame>(childPath, clip, color_gcurve, "m_color.g", isHaveCurve, dg, animSubData.frameDatas); bool anim_b = SetColorCurve <SpriteFrame>(childPath, clip, color_bcurve, "m_color.b", isHaveCurve, db, animSubData.frameDatas); bool anim_a = SetColorCurve <SpriteFrame>(childPath, clip, color_acurve, "m_color.a", isHaveCurve, da, animSubData.frameDatas); if (anim_r || anim_g || anim_b || anim_a) { changedSpriteFramesKV[childPath] = sprites[z]; } } } SpriteMesh[] spriteMeshs = slotNode.GetComponentsInChildren <SpriteMesh>(); if (spriteMeshs != null) { for (int z = 0; z < spriteMeshs.Length; ++z) { string childPath = path + "/" + spriteMeshs[z].name; bool anim_r = SetColorCurve <SpriteMesh>(childPath, clip, color_rcurve, "m_color.r", isHaveCurve, da, animSubData.frameDatas); bool anim_g = SetColorCurve <SpriteMesh>(childPath, clip, color_gcurve, "m_color.g", isHaveCurve, dg, animSubData.frameDatas); bool anim_b = SetColorCurve <SpriteMesh>(childPath, clip, color_bcurve, "m_color.b", isHaveCurve, db, animSubData.frameDatas); bool anim_a = SetColorCurve <SpriteMesh>(childPath, clip, color_acurve, "m_color.a", isHaveCurve, da, animSubData.frameDatas); if (anim_r || anim_g || anim_b || anim_a) { changedSpriteMeshsKV[childPath] = spriteMeshs[z]; } } } } for (int r = 0; r < renderCurves.Length; ++r) { AnimationCurve ac = renderCurves[r]; Renderer render = renders[r]; float defaultValue = render.enabled? 1: 0; if (ac.keys != null && ac.keys.Length > 0 && CheckCurveValid(ac, defaultValue)) { clip.SetCurve(path + "/" + render.name, typeof(GameObject), "m_IsActive", ac); //m_Enabled } } } }
/// <summary> /// Checks if the tangent should be displayed, depending on the active tangent mode. /// </summary> /// <param name="mode">Tangent mode for the keyframe.</param> /// <param name="type">Which tangent to check for.</param> /// <returns>True if the tangent should be displayed.</returns> private bool IsTangentDisplayed(TangentMode mode, TangentType type) { if (mode == TangentMode.Auto) return false; else if (mode == TangentMode.Free) return true; if (type == TangentType.In) return mode.HasFlag(TangentMode.InFree); else return mode.HasFlag(TangentMode.OutFree); }
public static TangentMode5 ToTangentMode5(this TangentMode _this) { return((TangentMode5)_this); }
///Display curves that belong to serializeContext and transformContext parent, at time and with timeSpan. public void Draw3DCurve(IAnimatableData animatable, IKeyable keyable, Transform transformContext, float time, float timeSpan = 50f) { this.animatable = animatable; // this.keyable = keyable; var curves = animatable.GetCurves(); if (curves == null || curves.Length != 3) { return; } var curveX = curves[0]; var curveY = curves[1]; var curveZ = curves[2]; if (curveX.length < 2 || curveY.length < 2 || curveZ.length < 2) { return; } if (curveX.length != curveY.length || curveY.length != curveZ.length) { return; } var serializeContext = keyable as Object; var e = Event.current; var start = (float)Mathf.FloorToInt(time - (timeSpan / 2)); var end = (float)Mathf.CeilToInt(time + (timeSpan / 2)); start = Mathf.Max(start, Mathf.Min(curveX[0].time, curveY[0].time, curveZ[0].time)); end = Mathf.Min(end, Mathf.Max(curveX[curveX.length - 1].time, curveY[curveY.length - 1].time, curveZ[curveZ.length - 1].time)); if (curveX.length != lastCurveLength) { lastCurveLength = curveX.length; kIndex = -1; } //1. Keyframes. for (var k = 0; k < curveX.length; k++) { EditorGUI.BeginChangeCheck(); var forceChanged = false; var keyX = curveX[k]; var keyY = curveY[k]; var keyZ = curveZ[k]; if (keyX.time < start) { continue; } if (keyX.time > end) { break; } var tangentModeX = CurveUtility.GetKeyTangentMode(keyX); var tangentModeY = CurveUtility.GetKeyTangentMode(keyY); var tangentModeZ = CurveUtility.GetKeyTangentMode(keyZ); var haveSameTangents = tangentModeX == tangentModeY && tangentModeY == tangentModeZ; var tangentMode = haveSameTangents ? tangentModeX : TangentMode.Editable; var isBroken = CurveUtility.GetKeyBroken(keyX) && CurveUtility.GetKeyBroken(keyY) && CurveUtility.GetKeyBroken(keyZ); var pos = new Vector3(keyX.value, keyY.value, keyZ.value); if (transformContext != null) { pos = transformContext.TransformPoint(pos); } Handles.Label(pos, keyX.time.ToString("0.00")); ///MOUSE EVENTS var screenPos = HandleUtility.WorldToGUIPoint(pos); if (((Vector2)screenPos - e.mousePosition).magnitude < 10) { if (e.type == EventType.MouseDown) { if (e.button == 0 && kIndex != k) { kIndex = k; GUIUtility.hotControl = 0; SceneView.RepaintAll(); e.Use(); } if (e.button == 1 && kIndex == k) { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Jump Time Here"), false, () => { keyable.root.currentTime = curveX[kIndex].time + keyable.startTime; }); menu.AddItem(new GUIContent("Smooth"), tangentMode == TangentMode.Smooth, () => { contextAction = ContextAction.SetTangentMode; contextTangentMode = TangentMode.Smooth; }); menu.AddItem(new GUIContent("Linear"), tangentMode == TangentMode.Linear, () => { contextAction = ContextAction.SetTangentMode; contextTangentMode = TangentMode.Linear; }); menu.AddItem(new GUIContent("Constant"), tangentMode == TangentMode.Constant, () => { contextAction = ContextAction.SetTangentMode; contextTangentMode = TangentMode.Constant; }); menu.AddItem(new GUIContent("Editable"), tangentMode == TangentMode.Editable, () => { contextAction = ContextAction.SetTangentMode; contextTangentMode = TangentMode.Editable; }); if (tangentMode == TangentMode.Editable) { menu.AddItem(new GUIContent("Tangents/Connected"), !isBroken, () => { contextAction = ContextAction.SetBrokenMode; contextBrokenMode = false; }); menu.AddItem(new GUIContent("Tangents/Broken"), isBroken, () => { contextAction = ContextAction.SetBrokenMode; contextBrokenMode = true; }); } menu.AddSeparator("/"); menu.AddItem(new GUIContent("Delete"), false, () => { contextAction = ContextAction.Delete; }); menu.ShowAsContext(); e.Use(); } } } ///APPLY CONTEXT ACTIONS if (contextAction != ContextAction.None && k == kIndex) { var _contextAction = contextAction; contextAction = ContextAction.None; forceChanged = true; if (_contextAction == ContextAction.SetBrokenMode) { Undo.RecordObject(serializeContext, "Animation Curve Change"); curveX.SetKeyBroken(kIndex, contextBrokenMode); curveY.SetKeyBroken(kIndex, contextBrokenMode); curveZ.SetKeyBroken(kIndex, contextBrokenMode); NotifyChange(); return; } if (_contextAction == ContextAction.SetTangentMode) { Undo.RecordObject(serializeContext, "Animation Curve Change"); curveX.SetKeyTangentMode(kIndex, contextTangentMode); curveY.SetKeyTangentMode(kIndex, contextTangentMode); curveZ.SetKeyTangentMode(kIndex, contextTangentMode); NotifyChange(); return; } if (_contextAction == ContextAction.Delete) { Undo.RecordObject(serializeContext, "Animation Curve Change"); curveX.RemoveKey(k); curveY.RemoveKey(k); curveZ.RemoveKey(k); kIndex = -1; NotifyChange(); return; } } ///POSITION var pointSize = HandleUtility.GetHandleSize(pos) * 0.05f; var newValue = pos; if (kIndex == k) { if (Tools.current == Tool.Move) { newValue = Handles.PositionHandle(pos, Quaternion.identity); } else { newValue = Handles.FreeMoveHandle(pos, Quaternion.identity, pointSize, Vector3.zero, Handles.RectangleHandleCap); } } var cam = SceneView.lastActiveSceneView.camera; Handles.RectangleHandleCap(0, pos, cam.transform.rotation, pointSize, EventType.Repaint); if (transformContext != null) { newValue = transformContext.InverseTransformPoint(newValue); } keyX.value = newValue.x; keyY.value = newValue.y; keyZ.value = newValue.z; ///TANGENTS if (haveSameTangents && tangentMode == TangentMode.Editable) { if (kIndex == k) { if (k != 0) { var inHandle = new Vector3(-keyX.inTangent, -keyY.inTangent, -keyZ.inTangent); inHandle /= HANDLE_DISTANCE_COMPENSATION; inHandle = newValue + inHandle; if (transformContext != null) { inHandle = transformContext.TransformPoint(inHandle); } var handleSize = HandleUtility.GetHandleSize(inHandle) * 0.05f; var newInHandle = Handles.FreeMoveHandle(inHandle, Quaternion.identity, handleSize, Vector3.zero, Handles.CircleHandleCap); Handles.DrawLine(pos, newInHandle); if (transformContext != null) { newInHandle = transformContext.InverseTransformPoint(newInHandle); } newInHandle -= newValue; newInHandle *= HANDLE_DISTANCE_COMPENSATION; keyX.inTangent = -newInHandle.x; keyY.inTangent = -newInHandle.y; keyZ.inTangent = -newInHandle.z; if (!isBroken) { keyX.outTangent = keyX.inTangent; keyY.outTangent = keyY.inTangent; keyZ.outTangent = keyZ.inTangent; } } if (k < curveX.length - 1) { var outHandle = new Vector3(keyX.outTangent, keyY.outTangent, keyZ.outTangent); outHandle /= HANDLE_DISTANCE_COMPENSATION; outHandle = newValue + outHandle; if (transformContext != null) { outHandle = transformContext.TransformPoint(outHandle); } var handleSize = HandleUtility.GetHandleSize(outHandle) * 0.05f; var newOutHandle = Handles.FreeMoveHandle(outHandle, Quaternion.identity, handleSize, Vector3.zero, Handles.CircleHandleCap); Handles.DrawLine(pos, newOutHandle); if (transformContext != null) { newOutHandle = transformContext.InverseTransformPoint(newOutHandle); } newOutHandle -= newValue; newOutHandle *= HANDLE_DISTANCE_COMPENSATION; keyX.outTangent = newOutHandle.x; keyY.outTangent = newOutHandle.y; keyZ.outTangent = newOutHandle.z; if (!isBroken) { keyX.inTangent = keyX.outTangent; keyY.inTangent = keyY.outTangent; keyZ.inTangent = keyZ.outTangent; } } } } ///APPLY if (EditorGUI.EndChangeCheck() || forceChanged) { Undo.RecordObject(serializeContext, "Animation Curve Change"); curveX.MoveKey(k, keyX); curveY.MoveKey(k, keyY); curveZ.MoveKey(k, keyZ); EditorUtility.SetDirty(serializeContext); NotifyChange(); } } ///2. Motion Path Handles.color = Prefs.motionPathsColor; var lastDrawnPos = Vector3.zero; for (var t = start; t <= end; t += DRAW_RESOLUTION) { var pos = new Vector3(curveX.Evaluate(t), curveY.Evaluate(t), curveZ.Evaluate(t)); var nextPos = new Vector3(curveX.Evaluate(t + DRAW_RESOLUTION), curveY.Evaluate(t + DRAW_RESOLUTION), curveZ.Evaluate(t + DRAW_RESOLUTION)); if (transformContext != null) { pos = transformContext.TransformPoint(pos); nextPos = transformContext.TransformPoint(nextPos); } if ((pos - lastDrawnPos).magnitude > DRAW_THRESHOLD) { lastDrawnPos = pos; Handles.SphereHandleCap(0, pos, Quaternion.identity, 0.02f, EventType.Repaint); Handles.DrawLine(pos, nextPos); } } Handles.color = Color.white; ///3. GUI if (kIndex >= 0) { var guiRect = new Rect(Screen.width - 300, Screen.height - 190, 280, 130); var kx = curveX[kIndex]; var ky = curveY[kIndex]; var kz = curveZ[kIndex]; EditorGUI.BeginChangeCheck(); { Handles.BeginGUI(); GUILayout.BeginArea(guiRect); EditorTools.BeginBody("Keyframe Parameters"); kx.value = EditorGUILayout.FloatField("X", kx.value); ky.value = EditorGUILayout.FloatField("Y", ky.value); kz.value = EditorGUILayout.FloatField("Z", kz.value); GUI.enabled = CurveUtility.GetKeyTangentMode(kx) == TangentMode.Editable; var inTangent = new Vector3(kx.inTangent, ky.inTangent, kz.inTangent); inTangent = EditorGUILayout.Vector3Field("", inTangent); kx.inTangent = inTangent.x; ky.inTangent = inTangent.y; kz.inTangent = inTangent.z; GUI.enabled = CurveUtility.GetKeyBroken(kx); var outTangent = new Vector3(kx.outTangent, ky.outTangent, kz.outTangent); outTangent = EditorGUILayout.Vector3Field("", outTangent); kx.outTangent = outTangent.x; ky.outTangent = outTangent.y; kz.outTangent = outTangent.z; GUI.enabled = true; EditorTools.EndBody(); GUILayout.EndArea(); Handles.EndGUI(); } if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(serializeContext, "Animation Curve Change"); curveX.MoveKey(kIndex, kx); curveY.MoveKey(kIndex, ky); curveZ.MoveKey(kIndex, kz); EditorUtility.SetDirty(serializeContext); NotifyChange(); } } /* * for (var k = 0; k < curveX.length - 1; k++){ * var keyX = curveX[k]; * var keyY = curveY[k]; * var keyZ = curveZ[k]; * var nextKeyX = curveX[k+1]; * var nextKeyY = curveY[k+1]; * var nextKeyZ = curveZ[k+1]; * * var t = new Vector3(keyX.time, keyY.time, keyZ.time); * var nextT = new Vector3(nextKeyX.time, nextKeyY.time, nextKeyZ.time); * * var tangent = new Vector3( keyX.outTangent, keyY.outTangent, keyZ.outTangent ); * var nextTangent = new Vector3( nextKeyX.inTangent, nextKeyY.inTangent, nextKeyZ.inTangent ); * * var pos = new Vector3( keyX.value, keyY.value, keyZ.value ); * var nextPos = new Vector3( nextKeyX.value, nextKeyY.value, nextKeyZ.value ); * * if (transformContext != null){ * pos = transformContext.TransformPoint(pos); * nextPos = transformContext.TransformPoint(nextPos); * } * * var num = (nextT - t) * 0.333333f; * var tangentPos = new Vector3( pos.x + num.x * tangent.x, pos.y + num.y * tangent.y, pos.z + num.z * tangent.z ); * var nextTangentPos = new Vector3( nextPos.x - num.x * nextTangent.x, nextPos.y - num.y * nextTangent.y, nextPos.z - num.z * nextTangent.z ); * * Handles.DrawBezier(pos, nextPos, tangentPos, nextTangentPos, Prefs.motionPathsColor, null, 1.5f); * } */ }
public void SetRightTangent(int index, Vector3 position, bool setToLinear, bool mirror, Vector3 cachedLeftTangent, TangentMode cachedTangentMode) { var controlPoint = editablePath.GetPoint(index); controlPoint.tangentMode = cachedTangentMode; controlPoint.rightTangent = position; controlPoint.mirrorLeft = true; if (setToLinear) { controlPoint.rightTangent = controlPoint.position; controlPoint.leftTangent = cachedLeftTangent; } else if (controlPoint.tangentMode == TangentMode.Continuous || mirror) { var magnitude = controlPoint.localLeftTangent.magnitude; if (mirror) { magnitude = controlPoint.localRightTangent.magnitude; } controlPoint.localLeftTangent = magnitude * -controlPoint.localRightTangent.normalized; } editablePath.SetPoint(index, controlPoint); editablePath.UpdateTangentMode(index); }
static void CreateAnimDeform(SpineArmatureEditor armatureEditor, AnimationClip clip, SpineData.AnimationDeformData[] animDeformDatas) { string[] skins = armatureEditor.armature.GetComponent <Armature>().skins; bool multiSkin = (skins == null || skins.Length <= 1)? false : true; for (int i = 0; i < animDeformDatas.Length; ++i) { SpineData.AnimationDeformData animDeformData = animDeformDatas[i]; if (animDeformData.timelines == null || animDeformData.timelines.Length == 0) { continue; } Dictionary <string, AnimationCurve[]> xCurveKV = new Dictionary <string, AnimationCurve[]>(); //key is attachment name Dictionary <string, AnimationCurve[]> yCurveKV = new Dictionary <string, AnimationCurve[]>(); Transform slot = armatureEditor.slotsKV[animDeformData.slotName]; bool isHaveCurve = false; for (int j = 0; j < animDeformData.timelines.Length; ++j) { SpineData.DeformTimeline timeline = animDeformData.timelines[j]; Transform attachment = multiSkin? slot.Find(animDeformData.skinName + "/" + timeline.attachment) : slot.Find(timeline.attachment); string prevTweeneasing = "linear"; //前一帧的tweenEasing float[] prevCurves = null; if (j > 0) { prevTweeneasing = animDeformData.timelines[j - 1].tweenEasing; prevCurves = animDeformData.timelines[j - 1].curve; } TangentMode tanModeL = GetPrevFrameTangentMode(prevTweeneasing, prevCurves); TangentMode tanModeR = TangentMode.Linear; if (timeline.curve != null && timeline.curve.Length > 0) { tanModeR = TangentMode.Editable; isHaveCurve = true; } else { if (timeline.tweenEasing == "stepped") { tanModeR = TangentMode.Stepped; } else { tanModeR = TangentMode.Linear; } } if (!xCurveKV.ContainsKey(timeline.attachment)) { xCurveKV[timeline.attachment] = new AnimationCurve[attachment.childCount]; yCurveKV[timeline.attachment] = new AnimationCurve[attachment.childCount]; } AnimationCurve[] xCurveArray = xCurveKV[timeline.attachment]; AnimationCurve[] yCurveArray = yCurveKV[timeline.attachment]; int len = attachment.childCount; if (timeline.vertices != null && timeline.vertices.Length > 0) { for (int r = 0; r < len; ++r) { if (xCurveArray[r] == null) { xCurveArray[r] = new AnimationCurve(); yCurveArray[r] = new AnimationCurve(); } AnimationCurve xCurve = xCurveArray[r]; AnimationCurve yCurve = yCurveArray[r]; Transform vCtr = attachment.GetChild(r); //vertex control if (r >= timeline.offset && r - timeline.offset < timeline.vertices.Length) { Vector3 v = timeline.vertices[r - timeline.offset]; v += vCtr.localPosition; Keyframe kfx = KeyframeUtil.GetNew(timeline.time, v.x, tanModeL, tanModeR); xCurve.AddKey(kfx); Keyframe kfy = KeyframeUtil.GetNew(timeline.time, v.y, tanModeL, tanModeR); yCurve.AddKey(kfy); } else { Keyframe kfx = KeyframeUtil.GetNew(timeline.time, vCtr.localPosition.x, tanModeL, tanModeR); xCurve.AddKey(kfx); Keyframe kfy = KeyframeUtil.GetNew(timeline.time, vCtr.localPosition.y, tanModeL, tanModeR); yCurve.AddKey(kfy); } } } else { //add default vertex position for (int r = 0; r < len; ++r) { if (xCurveArray[r] == null) { xCurveArray[r] = new AnimationCurve(); yCurveArray[r] = new AnimationCurve(); } AnimationCurve xCurve = xCurveArray[r]; AnimationCurve yCurve = yCurveArray[r]; Transform vCtr = attachment.GetChild(r); //vertex control Keyframe kfx = KeyframeUtil.GetNew(timeline.time, vCtr.localPosition.x, tanModeL, tanModeR); xCurve.AddKey(kfx); Keyframe kfy = KeyframeUtil.GetNew(timeline.time, vCtr.localPosition.y, tanModeL, tanModeR); yCurve.AddKey(kfy); } } } string path = ""; if (slotPathKV.ContainsKey(slot.name)) { path = slotPathKV[slot.name]; } else { path = GetNodeRelativePath(armatureEditor, slot); slotPathKV[slot.name] = path; } if (multiSkin) { path += "/" + animDeformData.skinName; } foreach (string attachmentName in xCurveKV.Keys) { AnimationCurve[] vertex_xcurves = xCurveKV[attachmentName]; AnimationCurve[] vertex_ycurves = yCurveKV[attachmentName]; Transform attachment = multiSkin? slot.Find(animDeformData.skinName + "/" + attachmentName) : slot.Find(attachmentName); int len = attachment.childCount; for (int r = 0; r < len; ++r) { AnimationCurve vertex_xcurve = vertex_xcurves[r]; AnimationCurve vertex_ycurve = vertex_ycurves[r]; Transform v = attachment.GetChild(r); string ctrlPath = path + "/" + attachment.name + "/" + v.name; CurveExtension.OptimizesCurve(vertex_xcurve); CurveExtension.OptimizesCurve(vertex_ycurve); bool vcurveFlag = false; if (vertex_xcurve.keys != null && vertex_xcurve.keys.Length > 0 && CheckCurveValid(vertex_xcurve, v.localPosition.x)) { vcurveFlag = true; } if (vertex_ycurve.keys != null && vertex_ycurve.keys.Length > 0 && CheckCurveValid(vertex_ycurve, v.localPosition.y)) { vcurveFlag = true; } if (vcurveFlag) { if (isHaveCurve) { SetCustomCurveTangents(vertex_xcurve, animDeformData.timelines); } CurveExtension.UpdateAllLinearTangents(vertex_xcurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(ctrlPath, typeof(Transform), "m_LocalPosition.x"), vertex_xcurve); if (isHaveCurve) { SetCustomCurveTangents(vertex_ycurve, animDeformData.timelines); } CurveExtension.UpdateAllLinearTangents(vertex_ycurve); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(ctrlPath, typeof(Transform), "m_LocalPosition.y"), vertex_ycurve); //add pose AnimationCurve pose_vertex_xcurve = new AnimationCurve(); AnimationCurve pose_vertex_ycurve = new AnimationCurve(); pose_vertex_xcurve.AddKey(new Keyframe(0f, v.localPosition.x)); pose_vertex_ycurve.AddKey(new Keyframe(0f, v.localPosition.y)); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(ctrlPath, typeof(Transform), "m_LocalPosition.x"), pose_vertex_xcurve); AnimationUtility.SetEditorCurve(poseClip, EditorCurveBinding.FloatCurve(ctrlPath, typeof(Transform), "m_LocalPosition.y"), pose_vertex_ycurve); } } } } }
public void AddTangentMenuItems(GenericMenu menu, List <KeyIdentifier> keyList) { bool flag = keyList.Count > 0; bool on = flag; bool on2 = flag; bool on3 = flag; bool on4 = flag; bool flag2 = flag; bool flag3 = flag; bool flag4 = flag; bool flag5 = flag; bool flag6 = flag; bool flag7 = flag; foreach (KeyIdentifier current in keyList) { Keyframe keyframe = current.keyframe; TangentMode keyTangentMode = CurveUtility.GetKeyTangentMode(keyframe, 0); TangentMode keyTangentMode2 = CurveUtility.GetKeyTangentMode(keyframe, 1); bool keyBroken = CurveUtility.GetKeyBroken(keyframe); if (keyTangentMode != TangentMode.Smooth || keyTangentMode2 != TangentMode.Smooth) { on = false; } if (keyBroken || keyTangentMode != TangentMode.Editable || keyTangentMode2 != TangentMode.Editable) { on2 = false; } if (keyBroken || keyTangentMode != TangentMode.Editable || keyframe.inTangent != 0f || keyTangentMode2 != TangentMode.Editable || keyframe.outTangent != 0f) { on3 = false; } if (!keyBroken) { on4 = false; } if (!keyBroken || keyTangentMode != TangentMode.Editable) { flag2 = false; } if (!keyBroken || keyTangentMode != TangentMode.Linear) { flag3 = false; } if (!keyBroken || keyTangentMode != TangentMode.Stepped) { flag4 = false; } if (!keyBroken || keyTangentMode2 != TangentMode.Editable) { flag5 = false; } if (!keyBroken || keyTangentMode2 != TangentMode.Linear) { flag6 = false; } if (!keyBroken || keyTangentMode2 != TangentMode.Stepped) { flag7 = false; } } if (flag) { menu.AddItem(EditorGUIUtility.TextContent("Auto"), on, new GenericMenu.MenuFunction2(this.SetSmooth), keyList); menu.AddItem(EditorGUIUtility.TextContent("Free Smooth"), on2, new GenericMenu.MenuFunction2(this.SetEditable), keyList); menu.AddItem(EditorGUIUtility.TextContent("Flat"), on3, new GenericMenu.MenuFunction2(this.SetFlat), keyList); menu.AddItem(EditorGUIUtility.TextContent("Broken"), on4, new GenericMenu.MenuFunction2(this.SetBroken), keyList); menu.AddSeparator(string.Empty); menu.AddItem(EditorGUIUtility.TextContent("Left Tangent/Free"), flag2, new GenericMenu.MenuFunction2(this.SetLeftEditable), keyList); menu.AddItem(EditorGUIUtility.TextContent("Left Tangent/Linear"), flag3, new GenericMenu.MenuFunction2(this.SetLeftLinear), keyList); menu.AddItem(EditorGUIUtility.TextContent("Left Tangent/Constant"), flag4, new GenericMenu.MenuFunction2(this.SetLeftConstant), keyList); menu.AddItem(EditorGUIUtility.TextContent("Right Tangent/Free"), flag5, new GenericMenu.MenuFunction2(this.SetRightEditable), keyList); menu.AddItem(EditorGUIUtility.TextContent("Right Tangent/Linear"), flag6, new GenericMenu.MenuFunction2(this.SetRightLinear), keyList); menu.AddItem(EditorGUIUtility.TextContent("Right Tangent/Constant"), flag7, new GenericMenu.MenuFunction2(this.SetRightConstant), keyList); menu.AddItem(EditorGUIUtility.TextContent("Both Tangents/Free"), flag5 && flag2, new GenericMenu.MenuFunction2(this.SetBothEditable), keyList); menu.AddItem(EditorGUIUtility.TextContent("Both Tangents/Linear"), flag6 && flag3, new GenericMenu.MenuFunction2(this.SetBothLinear), keyList); menu.AddItem(EditorGUIUtility.TextContent("Both Tangents/Constant"), flag7 && flag4, new GenericMenu.MenuFunction2(this.SetBothConstant), keyList); } else { menu.AddDisabledItem(EditorGUIUtility.TextContent("Auto")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Free Smooth")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Flat")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Broken")); menu.AddSeparator(string.Empty); menu.AddDisabledItem(EditorGUIUtility.TextContent("Left Tangent/Free")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Left Tangent/Linear")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Left Tangent/Constant")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Right Tangent/Free")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Right Tangent/Linear")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Right Tangent/Constant")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Both Tangents/Free")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Both Tangents/Linear")); menu.AddDisabledItem(EditorGUIUtility.TextContent("Both Tangents/Constant")); } }
public void OnGUI() { bool hasChanged = false; AnimationClip newClip = EditorGUILayout.ObjectField("Clip", clip, typeof(AnimationClip), false) as AnimationClip; if (newClip != clip) { animatorController = null; clip = newClip; hasChanged = true; } RuntimeAnimatorController newAnimatorController = EditorGUILayout.ObjectField("AnimatorController", animatorController, typeof(RuntimeAnimatorController), false) as RuntimeAnimatorController; if (newAnimatorController != animatorController) { animatorController = newAnimatorController; selectedClipIndex = 0; clip = animatorController.animationClips[selectedClipIndex]; hasChanged = true; } if (animatorController != null) { string[] clipNames = animatorController.animationClips.Select((c) => c.name).ToArray(); int newSelectedClipIndex = EditorGUILayout.Popup(selectedClipIndex, clipNames); if (newSelectedClipIndex != selectedClipIndex) { clip = animatorController.animationClips[newSelectedClipIndex]; selectedClipIndex = newSelectedClipIndex; hasChanged = true; } } EditorGUILayout.Space(); if (criterias.Count < 1) { criterias.Add(new BindingSearchCriteria()); } for (int i = 0; i < criterias.Count; i++) { BindingSearchCriteria criteria = criterias[i]; EditorGUILayout.BeginHorizontal(); BindingSearchCriteria.BindingParameter newParameter = (BindingSearchCriteria.BindingParameter)EditorGUILayout.EnumPopup(criteria.bindingParameter, GUILayout.Width(100f)); BindingSearchCriteria.Type newType = (BindingSearchCriteria.Type)EditorGUILayout.EnumPopup(criteria.type, GUILayout.Width(100f)); string newText = EditorGUILayout.TextField(criteria.text); if (newText != criteria.text || newParameter != criteria.bindingParameter || newType != criteria.type) { hasChanged = true; } criteria.text = newText; criteria.bindingParameter = newParameter; criteria.type = newType; if (i == criterias.Count - 1) { if (GUILayout.Button("+", GUILayout.Width(30f))) { criterias.Add(new BindingSearchCriteria()); } } EditorGUILayout.EndHorizontal(); } EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Operation:", GUILayout.Width(100f)); operation = (Operation)EditorGUILayout.EnumPopup(operation, GUILayout.Width(100f)); EditorGUILayout.LabelField("Value:", GUILayout.Width(40f)); if (operation == Operation.SetTangents) { tangentMode = (TangentMode)EditorGUILayout.EnumPopup(tangentMode); } else { operationValue = EditorGUILayout.FloatField(operationValue); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); if (GUILayout.Button("Apply")) { Apply(); hasChanged = true; } if (hasChanged) { UpdateBindings(); } scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, true, true); if (clip != null && chosenBindings != null) { foreach (string binding in chosenBindingsDescriptions) { EditorGUILayout.SelectableLabel(binding); } } EditorGUILayout.EndScrollView(); }
internal static void SetKeyLeftTangentMode(ref Keyframe key, TangentMode tangentMode) { key.tangentMode &= ~kLeftTangentMask; key.tangentMode |= ((int) tangentMode) << 1; }
/// <summary> /// Raises the GUI event. /// </summary> void OnGUI() { EditorGUILayout.LabelField(new GUIContent(pathMagicLogo), GUILayout.Width(142), GUILayout.Height(28)); if (_go == null) { EditorGUILayout.HelpBox("Create a new parameter path by pressing the New button", MessageType.Info); } else { EditorGUI.BeginChangeCheck(); EditorGUILayout.LabelField(new GUIContent("General")); EditorGUILayout.BeginVertical("Box"); _type = (PathTemplateType)EditorGUILayout.EnumPopup(new GUIContent("Path template", "Select a template path"), _type); _samples = EditorGUILayout.IntField(new GUIContent("Samples", "Number of samples to generate"), _samples); if (_samples < 3) { _samples = 3; } _closed = EditorGUILayout.Toggle(new GUIContent("Closed", "Generate a loop-ed path"), _closed); EditorGUILayout.EndVertical(); EditorGUILayout.LabelField("Prperties"); EditorGUILayout.BeginVertical("Box"); if (_type == PathTemplateType.Circular) { _sameXYRadius = EditorGUILayout.Toggle(new GUIContent("Same X/Y radius", "Circle have same X/Y radius?"), _sameXYRadius); } if (_sameXYRadius || _type == PathTemplateType.Linear) { _radiusX = _radiusY = EditorGUILayout.FloatField(new GUIContent("Radius", "The radius of the circle"), _radiusX); } else { _radiusX = EditorGUILayout.FloatField(new GUIContent("Radius X", "The X radius of the circle"), _radiusX); _radiusY = EditorGUILayout.FloatField(new GUIContent("Radius Y", "The Y radius of the circle"), _radiusY); } if (_type == PathTemplateType.Circular) { _yAdvance = EditorGUILayout.FloatField(new GUIContent("Y Advance", "Eache waypoint Y is increased by this value (Spiral template)"), _yAdvance); _periods = EditorGUILayout.FloatField(new GUIContent("Cycles", "Number of cycles around the circle"), _periods); EditorGUILayout.MinMaxSlider(new GUIContent("Min/Max angles", "Start angle and end angle"), ref _startAngle, ref _endAngle, 0f, 360f); _tangentMode = (TangentMode)EditorGUILayout.EnumPopup(new GUIContent("Tangents align", "Type of generated bezier tangents"), _tangentMode); } _sameTangentRadius = EditorGUILayout.Toggle(new GUIContent("Same tangent radius", "Tangents are symmetric in radius?"), _sameTangentRadius); if (_sameTangentRadius) { _inTangentRadius = _outTangentRadius = EditorGUILayout.FloatField(new GUIContent("Tangents radius", "In and out tangents radius"), _inTangentRadius); } else { _inTangentRadius = EditorGUILayout.FloatField(new GUIContent("In tangent radius", "In tangent radius"), _inTangentRadius); _outTangentRadius = EditorGUILayout.FloatField(new GUIContent("Out tangent radius", "Out tangent radius"), _outTangentRadius); } EditorGUILayout.EndVertical(); if (EditorGUI.EndChangeCheck()) { CreateThePath(); } } if (GUILayout.Button(new GUIContent("New", "Leaves current generated path (if there is one) and create a new one"))) { InitializePath(); } }
internal static void SetKeyRightTangentMode(ref Keyframe key, TangentMode tangentMode) { key.tangentMode &= ~kRightTangentMask; key.tangentMode |= ((int) tangentMode) << 5; }
internal static void SetKeyRightTangentMode(ref Keyframe key, TangentMode tangentMode) { Internal_SetKeyRightTangentMode(ref key, tangentMode); }
public static void SetKeyRightTangentMode(AnimationCurve curve, int index, TangentMode tangentMode) { if (curve == null) { throw new ArgumentNullException("curve"); } if ((index < 0) || (index >= curve.length)) { throw new ArgumentException("Index out of bounds."); } Keyframe key = curve[index]; if (tangentMode != TangentMode.Free) { SetKeyBroken(ref key, true); } SetKeyRightTangentMode(ref key, tangentMode); curve.MoveKey(index, key); UpdateTangentsFromModeSurrounding(curve, index); }
void OnSceneGUI() { GUI.changed = false; // Get the keyframes of the AnimationCurve to be manipulated Keyframe[] keys = script.spline.keys; // Set defaultLocalRotation so that the initial local rotation will be the zero point for the rotation limit if (!Application.isPlaying && !script.defaultLocalRotationOverride) { script.defaultLocalRotation = script.transform.localRotation; } if (script.axis == Vector3.zero) { return; } // Make the curve loop script.spline.postWrapMode = WrapMode.Loop; script.spline.preWrapMode = WrapMode.Loop; DrawRotationSphere(script.transform.position); // Display the main axis DrawArrow(script.transform.position, Direction(script.axis), colorDefault, "Axis", 0.02f); Vector3 swing = script.axis.normalized; // Editing tools GUI Handles.BeginGUI(); GUILayout.BeginArea(new Rect(10, 10, 440, 100), "Rotation Limit Spline", "Window"); // Scale Mode and Tangent Mode GUILayout.BeginHorizontal(); scaleMode = (ScaleMode)EditorGUILayout.EnumPopup("Drag Handle", scaleMode); tangentMode = (TangentMode)EditorGUILayout.EnumPopup("Drag Tangents", tangentMode); GUILayout.EndHorizontal(); EditorGUILayout.Space(); if (Inspector.Button("Rotate 90 degrees", "Rotate rotation limit around axis.", script, GUILayout.Width(220))) { if (!Application.isPlaying) { Undo.RecordObject(script, "Handle Value"); } for (int i = 0; i < keys.Length; i++) { keys[i].time += 90; } } // Cloning values from another RotationLimitSpline EditorGUILayout.BeginHorizontal(); if (Inspector.Button("Clone From", "Make this rotation limit identical to another", script, GUILayout.Width(220))) { CloneLimit(); keys = script.spline.keys; } clone = (RotationLimitSpline)EditorGUILayout.ObjectField("", clone, typeof(RotationLimitSpline), true); EditorGUILayout.EndHorizontal(); GUILayout.EndArea(); Handles.EndGUI(); // Draw keyframes for (int i = 0; i < keys.Length - 1; i++) { float angle = keys[i].time; // Start drawing handles Quaternion offset = Quaternion.AngleAxis(angle, swing); Quaternion rotation = Quaternion.AngleAxis(keys[i].value, offset * script.crossAxis); Vector3 position = script.transform.position + Direction(rotation * swing); Handles.Label(position, " " + i.ToString()); // Dragging Values if (selectedHandle == i) { Handles.color = colorHandles; switch (scaleMode) { case ScaleMode.Limit: float inputValue = keys[i].value; inputValue = Mathf.Clamp(Inspector.ScaleValueHandleSphere(inputValue, position, Quaternion.identity, 0.5f, 0), 0.01f, 180); if (keys[i].value != inputValue) { if (!Application.isPlaying) { Undo.RecordObject(script, "Handle Value"); } keys[i].value = inputValue; } break; case ScaleMode.Angle: float inputTime = keys[i].time; inputTime = Inspector.ScaleValueHandleSphere(inputTime, position, Quaternion.identity, 0.5f, 0); if (keys[i].time != inputTime) { if (!Application.isPlaying) { Undo.RecordObject(script, "Handle Angle"); } keys[i].time = inputTime; } break; } } // Handle select button if (selectedHandle != i) { Handles.color = Color.blue; if (Inspector.SphereButton(position, script.transform.rotation, 0.05f, 0.05f)) { selectedHandle = i; } } // Tangents if (selectedHandle == i) { // Evaluate positions before and after the key to get the tangent positions Vector3 prevPosition = GetAnglePosition(keys[i].time - 1); Vector3 nextPosition = GetAnglePosition(keys[i].time + 1); // Draw handles for the tangents Handles.color = Color.white; Vector3 toNext = (nextPosition - position).normalized * 0.3f; float outTangent = keys[i].outTangent; outTangent = Inspector.ScaleValueHandleSphere(outTangent, position + toNext, Quaternion.identity, 0.2f, 0); Vector3 toPrev = (prevPosition - position).normalized * 0.3f; float inTangent = keys[i].inTangent; inTangent = Inspector.ScaleValueHandleSphere(inTangent, position + toPrev, Quaternion.identity, 0.2f, 0); if (outTangent != keys[i].outTangent || inTangent != keys[i].inTangent) { selectedHandle = i; } // Make the other tangent match the dragged tangent (if in "Smooth" TangentMode) switch (tangentMode) { case TangentMode.Smooth: if (outTangent != keys[i].outTangent) { if (!Application.isPlaying) { Undo.RecordObject(script, "Tangents"); } keys[i].outTangent = outTangent; keys[i].inTangent = outTangent; } else if (inTangent != keys[i].inTangent) { if (!Application.isPlaying) { Undo.RecordObject(script, "Tangents"); } keys[i].outTangent = inTangent; keys[i].inTangent = inTangent; } break; case TangentMode.Independent: if (outTangent != keys[i].outTangent) { if (!Application.isPlaying) { Undo.RecordObject(script, "Tangents"); } keys[i].outTangent = outTangent; } else if (inTangent != keys[i].inTangent) { if (!Application.isPlaying) { Undo.RecordObject(script, "Tangents"); } keys[i].inTangent = inTangent; } break; } // Draw lines and labels to tangent handles Handles.color = Color.white; GUI.color = Color.white; Handles.DrawLine(position, position + toNext); Handles.Label(position + toNext, " Out"); Handles.DrawLine(position, position + toPrev); Handles.Label(position + toPrev, " In"); } } // Selected Point GUI if (selectedHandle != -1) { Handles.BeginGUI(); GUILayout.BeginArea(new Rect(Screen.width - 240, Screen.height - 200, 230, 150), "Handle " + selectedHandle.ToString(), "Window"); if (Inspector.Button("Delete", "Delete this handle", script)) { if (keys.Length > 4) { deleteHandle = selectedHandle; } else if (!Warning.logged) { script.LogWarning("Spline Rotation Limit should have at least 3 handles"); } } if (Inspector.Button("Add Handle", "Add a new handle next to this one", script)) { addHandle = selectedHandle; } // Clamp the key angles to previous and next handle angles float prevTime = 0, nextTime = 0; if (selectedHandle < keys.Length - 2) { nextTime = keys[selectedHandle + 1].time; } else { nextTime = keys[0].time + 360; } if (selectedHandle == 0) { prevTime = keys[keys.Length - 2].time - 360; } else { prevTime = keys[selectedHandle - 1].time; } // Angles float inputTime = keys[selectedHandle].time; inputTime = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Angle", "Angle of the point (0-360)."), inputTime), prevTime, nextTime); if (keys[selectedHandle].time != inputTime) { if (!Application.isPlaying) { Undo.RecordObject(script, "Handle Angle"); } keys[selectedHandle].time = inputTime; } // Limits float inputValue = keys[selectedHandle].value; inputValue = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Limit", "Max angular limit from Axis at this angle"), inputValue), 0, 180); if (keys[selectedHandle].value != inputValue) { if (!Application.isPlaying) { Undo.RecordObject(script, "Handle Limit"); } keys[selectedHandle].value = inputValue; } // In Tangents float inputInTangent = keys[selectedHandle].inTangent; inputInTangent = EditorGUILayout.FloatField(new GUIContent("In Tangent", "In tangent of the handle point on the spline"), inputInTangent); if (keys[selectedHandle].inTangent != inputInTangent) { if (!Application.isPlaying) { Undo.RecordObject(script, "Handle In Tangent"); } keys[selectedHandle].inTangent = inputInTangent; } // Out tangents float inputOutTangent = keys[selectedHandle].outTangent; inputOutTangent = EditorGUILayout.FloatField(new GUIContent("Out Tangent", "Out tangent of the handle point on the spline"), inputOutTangent); if (keys[selectedHandle].outTangent != inputOutTangent) { if (!Application.isPlaying) { Undo.RecordObject(script, "Handle Out Tangent"); } keys[selectedHandle].outTangent = inputOutTangent; } GUILayout.EndArea(); Handles.EndGUI(); } // Make sure the keyframes are valid; ValidateKeyframes(keys); // Replace the AnimationCurve keyframes with the manipulated keyframes script.spline.keys = keys; // Display limits for (int i = 0; i < 360; i += 2) { float evaluatedLimit = script.spline.Evaluate((float)i); Quaternion offset = Quaternion.AngleAxis(i, swing); Quaternion evaluatedRotation = Quaternion.AngleAxis(evaluatedLimit, offset * script.crossAxis); Quaternion testRotation = Quaternion.AngleAxis(179.9f, offset * script.crossAxis); Quaternion limitedRotation = script.LimitSwing(testRotation); Vector3 evaluatedDirection = evaluatedRotation * swing; Vector3 limitedDirection = limitedRotation * swing; // Display the limit points in red if they are out of range bool isValid = Vector3.Distance(evaluatedDirection, limitedDirection) < 0.01f && evaluatedLimit >= 0; Color color = isValid ? colorDefaultTransparent : colorInvalid; Vector3 limitPoint = script.transform.position + Direction(evaluatedDirection); Handles.color = color; if (i == 0) { zeroPoint = limitPoint; } Handles.DrawLine(script.transform.position, limitPoint); if (i > 0) { Handles.color = isValid ? colorDefault : colorInvalid; Handles.DrawLine(limitPoint, lastPoint); if (i == 358) { Handles.DrawLine(limitPoint, zeroPoint); } } lastPoint = limitPoint; } // Deleting points if (deleteHandle != -1) { DeleteHandle(deleteHandle); selectedHandle = -1; deleteHandle = -1; } // Adding points if (addHandle != -1) { AddHandle(addHandle); addHandle = -1; } Handles.color = Color.white; if (GUI.changed) { EditorUtility.SetDirty(script); } }
public static void SetCustomTangents(AnimationCurve curve, int i, int nextI, float[] tangentArray) { float diffValue = curve[nextI].value - curve[i].value; float diffTime = curve[nextI].time - curve[i].time; if (diffValue == 0) { return; } float cx1 = tangentArray[0]; float cy1 = tangentArray[1]; float cx2 = tangentArray[2]; float cy2 = tangentArray[3]; Vector2 p0 = new Vector2(0, curve[i].value); Vector2 p3 = new Vector2(diffTime, curve[nextI].value); Vector2 cOrig1 = new Vector2(diffTime * cx1, curve[i].value); cOrig1.y += diffValue > 0 ? diffValue * cy1 : -1.0f * Mathf.Abs(diffValue * cy1); Vector2 cOrig2 = new Vector2(diffTime * cx2, curve[i].value); cOrig2.y += diffValue > 0 ? diffValue * cy2 : -1.0f * Mathf.Abs(diffValue * cy2); Vector2 p1 = GetBezierPoint(p0, cOrig1, cOrig2, p3, 1.0f / 3.0f); Vector2 p2 = GetBezierPoint(p0, cOrig1, cOrig2, p3, 2.0f / 3.0f); Vector2 c1tg, c2tg, c1, c2; CalcControlPoints(p0, p1, p2, p3, out c1, out c2); c1tg = c1 - p0; c2tg = c2 - p3; float outTangent = c1tg.y / c1tg.x; float inTangent = c2tg.y / c2tg.x; object thisKeyframeBoxed = curve[i]; object nextKeyframeBoxed = curve[nextI]; if (!KeyframeUtil.isKeyBroken(thisKeyframeBoxed)) { KeyframeUtil.SetKeyBroken(thisKeyframeBoxed, true); } TangentMode mode = TangentMode.Editable; if (cx1 == 0f && cy1 == 0f) { mode = TangentMode.Linear; } KeyframeUtil.SetKeyTangentMode(thisKeyframeBoxed, 1, mode); if (!KeyframeUtil.isKeyBroken(nextKeyframeBoxed)) { KeyframeUtil.SetKeyBroken(nextKeyframeBoxed, true); } mode = TangentMode.Editable; if (cx2 == 1f && cy2 == 1f) { mode = TangentMode.Linear; } KeyframeUtil.SetKeyTangentMode(nextKeyframeBoxed, 0, mode); Keyframe thisKeyframe = (Keyframe)thisKeyframeBoxed; Keyframe nextKeyframe = (Keyframe)nextKeyframeBoxed; thisKeyframe.outTangent = outTangent; nextKeyframe.inTangent = inTangent; curve.MoveKey(i, thisKeyframe); curve.MoveKey(nextI, nextKeyframe); //* test method float startTime = thisKeyframe.time; for (float j = 0; j < 25f; j++) { float t = j / 25.0f; curve.Evaluate(startTime + diffTime * t); } }
/// <summary>Marks the specified key-frame as selected, changing the way it is displayed.</summary> /// <param name="keyframeRef">Keyframe reference containing the curve and keyframe index.</param> /// <param name="tangentMode">Type of tangent to display on the selected keyframe.</param> /// <param name="selected">True to select it, false to deselect it.</param> public void SelectKeyframe(KeyframeRef keyframeRef, TangentMode tangentMode, bool selected) { Internal_selectKeyframe(mCachedPtr, ref keyframeRef, tangentMode, selected); }
public void SetBoth(TangentMode mode, List<KeyIdentifier> keysToSet) { List<ChangedCurve> curve1 = new List<ChangedCurve>(); List<int> curveIds = new List<int>(); using (List<KeyIdentifier>.Enumerator enumerator = keysToSet.GetEnumerator()) { while (enumerator.MoveNext()) { KeyIdentifier current = enumerator.Current; AnimationCurve curve2 = current.curve; Keyframe keyframe = current.keyframe; CurveUtility.SetKeyBroken(ref keyframe, false); CurveUtility.SetKeyTangentMode(ref keyframe, 1, mode); CurveUtility.SetKeyTangentMode(ref keyframe, 0, mode); if (mode == TangentMode.Editable) { float smoothTangent = CurveUtility.CalculateSmoothTangent(keyframe); keyframe.inTangent = smoothTangent; keyframe.outTangent = smoothTangent; } curve2.MoveKey(current.key, keyframe); CurveUtility.UpdateTangentsFromModeSurrounding(curve2, current.key); ChangedCurve changedCurve = new ChangedCurve(curve2, current.binding); if (!curve1.Contains(changedCurve)) curve1.Add(changedCurve); curveIds.Add(current.curveId); } } if (this.updater is DopeSheetEditor) this.updater.UpdateCurves(curve1, "Set Tangents"); else this.updater.UpdateCurves(curveIds, "Set Tangents"); }
public void SetTangent(int leftRight, TangentMode mode, List<KeyIdentifier> keysToSet) { List<int> curveIds = new List<int>(); List<ChangedCurve> curve1 = new List<ChangedCurve>(); using (List<KeyIdentifier>.Enumerator enumerator = keysToSet.GetEnumerator()) { while (enumerator.MoveNext()) { KeyIdentifier current = enumerator.Current; AnimationCurve curve2 = current.curve; Keyframe keyframe = current.keyframe; CurveUtility.SetKeyBroken(ref keyframe, true); if (leftRight == 2) { CurveUtility.SetKeyTangentMode(ref keyframe, 0, mode); CurveUtility.SetKeyTangentMode(ref keyframe, 1, mode); } else { CurveUtility.SetKeyTangentMode(ref keyframe, leftRight, mode); if (CurveUtility.GetKeyTangentMode(keyframe, 1 - leftRight) == TangentMode.Smooth) CurveUtility.SetKeyTangentMode(ref keyframe, 1 - leftRight, TangentMode.Editable); } if (mode == TangentMode.Stepped && (leftRight == 0 || leftRight == 2)) keyframe.inTangent = float.PositiveInfinity; if (mode == TangentMode.Stepped && (leftRight == 1 || leftRight == 2)) keyframe.outTangent = float.PositiveInfinity; curve2.MoveKey(current.key, keyframe); CurveUtility.UpdateTangentsFromModeSurrounding(curve2, current.key); ChangedCurve changedCurve = new ChangedCurve(curve2, current.binding); if (!curve1.Contains(changedCurve)) curve1.Add(changedCurve); curveIds.Add(current.curveId); } } if (this.updater is DopeSheetEditor) this.updater.UpdateCurves(curve1, "Set Tangents"); else this.updater.UpdateCurves(curveIds, "Set Tangents"); }
//... public static void SetKeyTangentMode(this AnimationCurve curve, int index, TangentMode tangentMode) { SetKeyLeftTangentMode(curve, index, tangentMode); SetKeyRightTangentMode(curve, index, tangentMode); SetKeyBroken(curve, index, false); }
public static Keyframe GetNew( float time, float value, TangentMode leftAndRight) { return GetNew(time,value, leftAndRight,leftAndRight); }
//... public static void SetKeyRightTangentMode(AnimationCurve curve, int index, TangentMode tangentMode) { AnimationUtility.SetKeyRightTangentMode(curve, index, (AnimationUtility.TangentMode)tangentMode); }
public void SetBoth(TangentMode mode, List<KeyIdentifier> keysToSet) { List<int> list = new List<int>(); foreach (KeyIdentifier current in keysToSet) { AnimationCurve curve = current.curve; Keyframe keyframe = current.keyframe; CurveUtility.SetKeyBroken(ref keyframe, false); CurveUtility.SetKeyTangentMode(ref keyframe, 1, mode); CurveUtility.SetKeyTangentMode(ref keyframe, 0, mode); if (mode == TangentMode.Editable) { float num = CurveUtility.CalculateSmoothTangent(keyframe); keyframe.inTangent = num; keyframe.outTangent = num; } curve.MoveKey(current.key, keyframe); CurveUtility.UpdateTangentsFromModeSurrounding(curve, current.key); list.Add(current.curveId); } this.updater.UpdateCurves(list, "Set Tangents"); }
private static TangentMode GetNextTangentMode(TangentMode tangentMode) { return((TangentMode)((((int)tangentMode) + 1) % Enum.GetValues(typeof(TangentMode)).Length)); }
public static void SetKeyTangentMode(ref Keyframe key, int leftRight, TangentMode mode) { if (leftRight == 0) { key.tangentMode &= -7; key.tangentMode |= (int)((int)mode << 1); } else { key.tangentMode &= -25; key.tangentMode |= (int)((int)mode << 3); } if (CurveUtility.GetKeyTangentMode(key, leftRight) != mode) { Debug.Log("bug"); } }
public static Keyframe GetNew(float time, float value, TangentMode leftAndRight) { return(GetNew(time, value, leftAndRight, leftAndRight)); }
void OnSceneGUI() { GUI.changed = false; // Get the keyframes of the AnimationCurve to be manipulated Keyframe[] keys = script.spline.keys; // Set defaultLocalRotation so that the initial local rotation will be the zero point for the rotation limit if (!Application.isPlaying) script.defaultLocalRotation = script.transform.localRotation; if (script.axis == Vector3.zero) return; // Make the curve loop script.spline.postWrapMode = WrapMode.Loop; script.spline.preWrapMode = WrapMode.Loop; DrawRotationSphere(script.transform.position); // Display the main axis DrawArrow(script.transform.position, Direction(script.axis), colorDefault, "Axis", 0.02f); Vector3 swing = script.axis.normalized; // Editing tools GUI Handles.BeginGUI(); GUILayout.BeginArea(new Rect(10, Screen.height - 140, 440, 90), "Rotation Limit Spline", "Window"); // Scale Mode and Tangent Mode GUILayout.BeginHorizontal(); scaleMode = (ScaleMode)EditorGUILayout.EnumPopup("Drag Handle", scaleMode); tangentMode = (TangentMode)EditorGUILayout.EnumPopup("Drag Tangents", tangentMode); GUILayout.EndHorizontal(); EditorGUILayout.Space(); if (Inspector.Button("Rotate 90 degrees", "Rotate rotation limit around axis.", script, GUILayout.Width(220))) { if (!Application.isPlaying) Undo.RecordObject(script, "Handle Value"); for (int i = 0; i < keys.Length; i++) keys[i].time += 90; } // Cloning values from another RotationLimitSpline EditorGUILayout.BeginHorizontal(); if (Inspector.Button("Clone From", "Make this rotation limit identical to another", script, GUILayout.Width(220))) { CloneLimit(); keys = script.spline.keys; } clone = (RotationLimitSpline)EditorGUILayout.ObjectField("", clone, typeof(RotationLimitSpline), true); EditorGUILayout.EndHorizontal(); GUILayout.EndArea(); Handles.EndGUI(); // Draw keyframes for (int i = 0; i < keys.Length - 1; i++) { float angle = keys[i].time; // Start drawing handles Quaternion offset = Quaternion.AngleAxis(angle, swing); Quaternion rotation = Quaternion.AngleAxis(keys[i].value, offset * script.crossAxis); Vector3 position = script.transform.position + Direction(rotation * swing); Handles.Label(position, " " + i.ToString()); // Dragging Values if (selectedHandle == i) { Handles.color = colorHandles; switch(scaleMode) { case ScaleMode.Limit: float inputValue = keys[i].value; inputValue = Mathf.Clamp(Handles.ScaleValueHandle(inputValue, position, Quaternion.identity, 0.5f, Handles.SphereCap, 0), 0.01f, 180); if (keys[i].value != inputValue) { if (!Application.isPlaying) Undo.RecordObject(script, "Handle Value"); keys[i].value = inputValue; } break; case ScaleMode.Angle: float inputTime = keys[i].time; inputTime = Handles.ScaleValueHandle(inputTime, position, Quaternion.identity, 0.5f, Handles.SphereCap, 0); if (keys[i].time != inputTime) { if (!Application.isPlaying) Undo.RecordObject(script, "Handle Angle"); keys[i].time = inputTime; } break; } } // Handle select button if (selectedHandle != i) { Handles.color = Color.blue; if (Handles.Button(position, script.transform.rotation, 0.05f, 0.05f, Handles.SphereCap)) { selectedHandle = i; } } // Tangents if (selectedHandle == i) { // Evaluate positions before and after the key to get the tangent positions Vector3 prevPosition = GetAnglePosition(keys[i].time - 1); Vector3 nextPosition = GetAnglePosition(keys[i].time + 1); // Draw handles for the tangents Handles.color = Color.white; Vector3 toNext = (nextPosition - position).normalized * 0.3f; float outTangent = keys[i].outTangent; outTangent = Handles.ScaleValueHandle(outTangent, position + toNext, Quaternion.identity, 0.2f, Handles.SphereCap, 0); Vector3 toPrev = (prevPosition - position).normalized * 0.3f; float inTangent = keys[i].inTangent; inTangent = Handles.ScaleValueHandle(inTangent, position + toPrev, Quaternion.identity, 0.2f, Handles.SphereCap, 0); if (outTangent != keys[i].outTangent || inTangent != keys[i].inTangent) selectedHandle = i; // Make the other tangent match the dragged tangent (if in "Smooth" TangentMode) switch(tangentMode) { case TangentMode.Smooth: if (outTangent != keys[i].outTangent) { if (!Application.isPlaying) Undo.RecordObject(script, "Tangents"); keys[i].outTangent = outTangent; keys[i].inTangent = outTangent; } else if (inTangent != keys[i].inTangent) { if (!Application.isPlaying) Undo.RecordObject(script, "Tangents"); keys[i].outTangent = inTangent; keys[i].inTangent = inTangent; } break; case TangentMode.Independent: if (outTangent != keys[i].outTangent) { if (!Application.isPlaying) Undo.RecordObject(script, "Tangents"); keys[i].outTangent = outTangent; } else if (inTangent != keys[i].inTangent) { if (!Application.isPlaying) Undo.RecordObject(script, "Tangents"); keys[i].inTangent = inTangent; } break; } // Draw lines and labels to tangent handles Handles.color = Color.white; GUI.color = Color.white; Handles.DrawLine(position, position + toNext); Handles.Label(position + toNext, " Out"); Handles.DrawLine(position, position + toPrev); Handles.Label(position + toPrev, " In"); } } // Selected Point GUI if (selectedHandle != -1) { Handles.BeginGUI(); GUILayout.BeginArea(new Rect(Screen.width - 240, Screen.height - 200, 230, 150), "Handle " + selectedHandle.ToString(), "Window"); if (Inspector.Button("Delete", "Delete this handle", script)) { if (keys.Length > 4) { deleteHandle = selectedHandle; } else if (!Warning.logged) script.LogWarning("Spline Rotation Limit should have at least 3 handles"); } if (Inspector.Button("Add Handle", "Add a new handle next to this one", script)) { addHandle = selectedHandle; } // Clamp the key angles to previous and next handle angles float prevTime = 0, nextTime = 0; if (selectedHandle < keys.Length - 2) nextTime = keys[selectedHandle + 1].time; else nextTime = keys[0].time + 360; if (selectedHandle == 0) prevTime = keys[keys.Length - 2].time - 360; else prevTime = keys[selectedHandle - 1].time; // Angles float inputTime = keys[selectedHandle].time; inputTime = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Angle", "Angle of the point (0-360)."), inputTime), prevTime, nextTime); if (keys[selectedHandle].time != inputTime) { if (!Application.isPlaying) Undo.RecordObject(script, "Handle Angle"); keys[selectedHandle].time = inputTime; } // Limits float inputValue = keys[selectedHandle].value; inputValue = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Limit", "Max angular limit from Axis at this angle"), inputValue), 0, 180); if (keys[selectedHandle].value != inputValue) { if (!Application.isPlaying) Undo.RecordObject(script, "Handle Limit"); keys[selectedHandle].value = inputValue; } // In Tangents float inputInTangent = keys[selectedHandle].inTangent; inputInTangent = EditorGUILayout.FloatField(new GUIContent("In Tangent", "In tangent of the handle point on the spline"), inputInTangent); if (keys[selectedHandle].inTangent != inputInTangent) { if (!Application.isPlaying) Undo.RecordObject(script, "Handle In Tangent"); keys[selectedHandle].inTangent = inputInTangent; } // Out tangents float inputOutTangent = keys[selectedHandle].outTangent; inputOutTangent = EditorGUILayout.FloatField(new GUIContent("Out Tangent", "Out tangent of the handle point on the spline"), inputOutTangent); if (keys[selectedHandle].outTangent != inputOutTangent) { if (!Application.isPlaying) Undo.RecordObject(script, "Handle Out Tangent"); keys[selectedHandle].outTangent = inputOutTangent; } GUILayout.EndArea(); Handles.EndGUI(); } // Make sure the keyframes are valid; ValidateKeyframes(keys); // Replace the AnimationCurve keyframes with the manipulated keyframes script.spline.keys = keys; // Display limits for (int i = 0; i < 360; i+= 2) { float evaluatedLimit = script.spline.Evaluate((float)i); Quaternion offset = Quaternion.AngleAxis(i, swing); Quaternion evaluatedRotation = Quaternion.AngleAxis(evaluatedLimit, offset * script.crossAxis); Quaternion testRotation = Quaternion.AngleAxis(179.9f, offset * script.crossAxis); Quaternion limitedRotation = script.LimitSwing(testRotation); Vector3 evaluatedDirection = evaluatedRotation * swing; Vector3 limitedDirection = limitedRotation * swing; // Display the limit points in red if they are out of range bool isValid = Vector3.Distance(evaluatedDirection, limitedDirection) < 0.01f && evaluatedLimit >= 0; Color color = isValid? colorDefaultTransparent: colorInvalid; Vector3 limitPoint = script.transform.position + Direction(evaluatedDirection); Handles.color = color; if (i == 0) zeroPoint = limitPoint; Handles.DrawLine(script.transform.position, limitPoint); if (i > 0) { Handles.color = isValid? colorDefault: colorInvalid; Handles.DrawLine(limitPoint, lastPoint); if (i == 358) Handles.DrawLine(limitPoint, zeroPoint); } lastPoint = limitPoint; } // Deleting points if (deleteHandle != -1) { DeleteHandle(deleteHandle); selectedHandle = -1; deleteHandle = -1; } // Adding points if (addHandle != -1) { AddHandle(addHandle); addHandle = -1; } Handles.color = Color.white; if (GUI.changed) EditorUtility.SetDirty(script); }
/// <summary> /// Draws zero, one or two tangents for the specified keyframe. Whether tangents are drawn depends on the provided /// mode. /// </summary> /// <param name="keyFrame">Keyframe to draw the tangents for.</param> /// <param name="tangentMode">Type of tangents in the keyframe.</param> private void DrawTangents(KeyFrame keyFrame, TangentMode tangentMode) { Vector2I keyframeCoords = CurveToPixelSpace(new Vector2(keyFrame.time, keyFrame.value)); if (IsTangentDisplayed(tangentMode, TangentType.In)) { Vector2I tangentCoords = GetTangentPosition(keyFrame, TangentType.In); canvas.DrawLine(keyframeCoords, tangentCoords, Color.LightGray); DrawDiamond(tangentCoords, 2, Color.Green, Color.Black); } if (IsTangentDisplayed(tangentMode, TangentType.Out)) { Vector2I tangentCoords = GetTangentPosition(keyFrame, TangentType.Out); canvas.DrawLine(keyframeCoords, tangentCoords, Color.LightGray); DrawDiamond(tangentCoords, 2, Color.Green, Color.Black); } }