//============================================================================================ /** * @brief * *********************************************************************************************/ public void VerifyData() { if (m_targetMxMAnim == null) return; AnimationClip primaryClip = m_targetMxMAnim.TargetClip; if (primaryClip == null) return; for (int i = MotionSections.Count - 1; i >= 0; --i) { MotionSection section = MotionSections[i]; if (i - 1 >= 0) { if (MotionSections[i - 1].EndTime > primaryClip.length) { MotionSections.RemoveAt(i); continue; } } else if (section.EndTime > primaryClip.length) { section.EndTime = primaryClip.length; } } if (MotionSections.Count > 0) { MotionSections[MotionSections.Count - 1].EndTime = primaryClip.length; } }
//============================================================================================ /** * @brief * *********************************************************************************************/ public MotionSection(int a_id, MotionSection a_copy, float a_endTime) { MotionSectionId = a_id; MotionPresetId = a_copy.MotionPresetId; ModType = a_copy.ModType; SmoothType = a_copy.SmoothType; RawModValue = a_copy.RawModValue; UsePresets = a_copy.UsePresets; EndTime = a_endTime; }
public MotionSection(MotionSection a_copy) { MotionSectionId = a_copy.MotionSectionId; MotionPresetId = a_copy.MotionPresetId; ModType = a_copy.ModType; SmoothType = a_copy.SmoothType; RawModValue = a_copy.RawModValue; UsePresets = a_copy.UsePresets; EndTime = a_copy.EndTime; Selected = false; Dragging = false; }
//============================================================================================ /** * @brief * *********************************************************************************************/ public void AddPOI(float a_time) { Undo.RecordObject(m_targetMxMAnim as ScriptableObject, "Section added"); for (int i=0; i < MotionSections.Count; ++i) { if(a_time < MotionSections[i].EndTime) { MotionSection newSection = new MotionSection(i, MotionSections[i], a_time); //MotionSection newSection = new MotionSection(i, 0, EMotionModSmooth.Linear, a_time); MotionSections.Insert(i, newSection); for(int n=i+1; n < MotionSections.Count; ++n) { MotionSections[n].MotionSectionId = n; } break; } } }
public void GenerateModifiedAnimation(MxMPreProcessData a_preProcessData, string a_directory) { EditorUtility.DisplayProgressBar("Generate Modified Animations", "Scraping Old Anims", 0f); if (a_preProcessData != null) m_targetPreProcessData = a_preProcessData; ScrapGeneratedClips(); List<MotionSection> motionList = MotionModifier.MotionSections; MotionTimingPresets presets = m_targetPreProcessData.MotionTimingPresets; if (UseSpeedMods && m_clips != null && m_targetPreProcessData != null) { int blendSpaceId = 0; for (int i = 0; i < m_targetPreProcessData.BlendSpaces.Count; ++i) { if(this == m_targetPreProcessData.BlendSpaces[i]) { blendSpaceId = i; break; } } float cumTimeShift = 0f; //This is the cumulative amount of time shift at the point of modification; float curStartTime = 0f; //The start time for the current motion section //Loop clips and generate ndes ones foreach (AnimationClip clip in m_clips) { EditorUtility.DisplayProgressBar("Generate Modified Animation", "Copying Clip " + clip.name, 0f); var generatedClip = new AnimationClip(); EditorUtility.CopySerialized(clip, generatedClip); generatedClip.name = clip.name + "_MxM_MOD_" + blendSpaceId; var curveBindings = AnimationUtility.GetCurveBindings(generatedClip); List<AnimationCurve> workingCurves = new List<AnimationCurve>(curveBindings.Length + 1); List<AnimationEvent> newEvents = new List<AnimationEvent>(); //Create curves but don't add keys for (int i = 0; i < curveBindings.Length; ++i) { workingCurves.Add(new AnimationCurve()); } cumTimeShift = 0f; curStartTime = 0f; int[] startKeyIndex = new int[workingCurves.Count]; //The start key for the current motion section for (int i = 0; i < motionList.Count; ++i) { EditorUtility.DisplayProgressBar("Generate Modified Animation", "Modifying Section " + i + " of " + clip.name, ((float)i) / ((float)motionList.Count)); MotionSection motionSection = motionList[i]; float startWarpTime = curStartTime; float endWarpTime = motionSection.EndTime; float warpScale = motionSection.GetSpeedMod(curStartTime, presets, this); float localTimeShift = (endWarpTime - startWarpTime) - (endWarpTime - startWarpTime) * warpScale; //Shift Curve Keys for (int k = 0; k < curveBindings.Length; ++k) { EditorCurveBinding binding = curveBindings[k]; AnimationCurve originalCurve = AnimationUtility.GetEditorCurve(clip, binding); AnimationCurve workingCurve = workingCurves[k]; //Make a cut at the end only int endKeyIndex = originalCurve.AddKey(endWarpTime, originalCurve.Evaluate(endWarpTime)); if (endKeyIndex == -1) endKeyIndex = originalCurve.keys.Length - 1; //Add in the intermediate keys scaled relative to the start and shifted by the cumulative time shift for (int keyIndex = startKeyIndex[k]; i < motionList.Count - 1 ? keyIndex < endKeyIndex : keyIndex <= endKeyIndex; ++keyIndex) { Keyframe key = originalCurve.keys[keyIndex]; key.time = startWarpTime + ((key.time - startWarpTime) * warpScale) - cumTimeShift; key.inTangent /= warpScale; key.outTangent /= warpScale; workingCurve.AddKey(key); } startKeyIndex[k] = endKeyIndex; } //Shift Animation Clip EventsEvents foreach (AnimationEvent evt in generatedClip.events) { if (evt.time > startWarpTime && evt.time < endWarpTime) { //Scale & Shift evt.time = startWarpTime + ((evt.time - startWarpTime) * warpScale) - cumTimeShift; } newEvents.Add(evt); } } for (int i = 0; i < workingCurves.Count; ++i) { EditorUtility.DisplayProgressBar("Generate Modified Animation", "Generating Curves for clip: " + clip.name, ((float)i) / ((float)workingCurves.Count)); AnimationUtility.SetEditorCurve(generatedClip, curveBindings[i], workingCurves[i]); } AnimationUtility.SetAnimationEvents(generatedClip, newEvents.ToArray()); EditorUtility.SetDirty(generatedClip); AssetDatabase.CreateAsset(generatedClip, a_directory + "/" + generatedClip.name + ".anim"); AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(generatedClip)); GeneratedClips.Add(generatedClip); } //End loop clips. Generations is complete //Go through Motion Sections again and modify tag tracks and events cumTimeShift = 0f; //This is the cumulative amount of time shift at the point of modification; curStartTime = 0f; //The start time for the current motion section for (int i = 0; i < motionList.Count; ++i) { MotionSection motionSection = motionList[i]; float startWarpTime = curStartTime; float endWarpTime = motionSection.EndTime; float warpScale = motionSection.GetSpeedMod(curStartTime, presets, this); float localTimeShift = (endWarpTime - startWarpTime) - (endWarpTime - startWarpTime) * warpScale; //Shift MXM Tag Points foreach (TagTrack track in TagTracks) { TagTrack newTrack = new TagTrack(track); List<Vector2> tagList = newTrack.Tags; for (int k = 0; k < tagList.Count; ++k) { Vector2 newTag = tagList[k]; if (newTag.x > startWarpTime && newTag.x < endWarpTime) { newTag.x = startWarpTime + ((newTag.x - startWarpTime) * warpScale) - cumTimeShift; } if (newTag.y > startWarpTime && newTag.y < endWarpTime) { newTag.y = startWarpTime + ((newTag.y - startWarpTime) * warpScale) - cumTimeShift; } tagList[k] = newTag; } GeneratedTagTracks.Add(newTrack); } cumTimeShift += localTimeShift; curStartTime = endWarpTime; } } EditorUtility.SetDirty(this); EditorUtility.ClearProgressBar(); }
public void GenerateModifiedAnimation(MxMPreProcessData a_preProcessData, string a_directory) { EditorUtility.DisplayProgressBar("Generate Modified Animation", "Scraping Old Anims", 0f); if (a_preProcessData != null) m_targetPreProcessData = a_preProcessData; ScrapGeneratedClips(); if (UseSpeedMods) { if (PrimaryClip != null && m_targetPreProcessData != null) { EditorUtility.DisplayProgressBar("Generate Modified Animation", "Copying Clip " + PrimaryClip.name, 0f); GeneratedClip = new AnimationClip(); EditorUtility.CopySerialized(PrimaryClip, GeneratedClip); GeneratedClip.name = PrimaryClip.name + "_MxM_MOD"; var curveBindings = AnimationUtility.GetCurveBindings(GeneratedClip); List<AnimationCurve> workingCurves = new List<AnimationCurve>(curveBindings.Length + 1); List<AnimationEvent> newEvents = new List<AnimationEvent>(); List<MotionSection> motionList = MotionModifier.MotionSections; MotionTimingPresets presets = m_targetPreProcessData.MotionTimingPresets; GeneratedTagTracks = new List<TagTrack>(TagTracks); GeneratedFavourTagTracks = new List<TagTrack>(TagTracks); GeneratedUserBoolTracks = new List<TagTrackBase>(UserBoolTracks); GeneratedLeftFootStepTrack = new FootStepTagTrack(LeftFootStepTrack); GeneratedRightFootStepTrack = new FootStepTagTrack(RightFootStepTrack); GeneratedWarpPositionTrack = new TagTrackBase(WarpPositionTrack); GeneratedWarpRotationTrack = new TagTrackBase(WarpRotationTrack); GeneratedEnableRootMotionTrack = new TagTrackBase(EnableRootMotionTrack); GeneratedPoseFavourTrack = new FloatTagTrack(PoseFavourTrack); GeneratedWarpTrajLatTrack = new TagTrackBase(WarpTrajLatTrack); GeneratedWarpTrajLongTrack = new TagTrackBase(WarpTrajLongTrack); //Create curves but don't add keys for (int i = 0; i < curveBindings.Length; ++i) { workingCurves.Add(new AnimationCurve()); } float cumTimeShift = 0f; //This is the cumulative amount of time shift at the point of modification; float curStartTime = 0f; //The start time for the current motion section int[] startKeyIndex = new int[workingCurves.Count]; //The start key for the current motion section for (int i = 0; i < motionList.Count; ++i) { EditorUtility.DisplayProgressBar("Generate Modified Animation", "Modifying Section " + i + " of " + PrimaryClip.name, ((float)i) / ((float)motionList.Count)); MotionSection motionSection = motionList[i]; float startWarpTime = curStartTime; float endWarpTime = motionSection.EndTime; float warpScale = motionSection.GetSpeedMod(curStartTime, presets, this); float localTimeShift = (endWarpTime - startWarpTime) - (endWarpTime - startWarpTime) * warpScale; //Shift Curve Keys for (int k = 0; k < curveBindings.Length; ++k) { EditorCurveBinding binding = curveBindings[k]; AnimationCurve originalCurve = AnimationUtility.GetEditorCurve(PrimaryClip, binding); AnimationCurve workingCurve = workingCurves[k]; //Make a cut at the end only int endKeyIndex = originalCurve.AddKey(endWarpTime, originalCurve.Evaluate(endWarpTime)); if (endKeyIndex == -1) endKeyIndex = originalCurve.keys.Length - 1; //Add in the intermediate keys scaled relative to the start and shifted by the cumulative time shift for (int keyIndex = startKeyIndex[k]; i < motionList.Count - 1 ? keyIndex < endKeyIndex : keyIndex <= endKeyIndex; ++keyIndex) { Keyframe key = originalCurve.keys[keyIndex]; key.time = startWarpTime + ((key.time - startWarpTime) * warpScale) - cumTimeShift; key.inTangent /= warpScale; key.outTangent /= warpScale; workingCurve.AddKey(key); } startKeyIndex[k] = endKeyIndex; } //Shift Events foreach (AnimationEvent evt in GeneratedClip.events) { if (evt.time > startWarpTime && evt.time < endWarpTime) { //Scale & Shift evt.time = startWarpTime + ((evt.time - startWarpTime) * warpScale) - cumTimeShift; } newEvents.Add(evt); } //Shift MxM Events foreach (EventMarker evt in Events) { EventMarker newMarker = new EventMarker(evt); if (newMarker.EventTime > startWarpTime && evt.EventTime < endWarpTime) { evt.EventTime = startWarpTime + ((evt.EventTime - startWarpTime) * warpScale) - cumTimeShift; } GeneratedEvents.Add(newMarker); } //Shift MXM Tag Points foreach (TagTrack track in GeneratedTagTracks) { List<Vector2> tagList = track.Tags; for (int k = 0; k < tagList.Count; ++k) { Vector2 newTag = tagList[k]; if (newTag.x > startWarpTime && newTag.x < endWarpTime) { newTag.x = startWarpTime + ((newTag.x - startWarpTime) * warpScale) - cumTimeShift; } if (newTag.y > startWarpTime && newTag.y < endWarpTime) { newTag.y = startWarpTime + ((newTag.y - startWarpTime) * warpScale) - cumTimeShift; } tagList[k] = newTag; } } //Shift MXM FavourTag Points foreach (TagTrack track in GeneratedFavourTagTracks) { List<Vector2> tagList = track.Tags; for (int k = 0; k < tagList.Count; ++k) { Vector2 newTag = tagList[k]; if (newTag.x > startWarpTime && newTag.x < endWarpTime) { newTag.x = startWarpTime + ((newTag.x - startWarpTime) * warpScale) - cumTimeShift; } if (newTag.y > startWarpTime && newTag.y < endWarpTime) { newTag.y = startWarpTime + ((newTag.y - startWarpTime) * warpScale) - cumTimeShift; } tagList[k] = newTag; } } //Shift MxM User Tags foreach (TagTrackBase track in GeneratedUserBoolTracks) { ShiftTrackTags(track, startWarpTime, endWarpTime, warpScale, cumTimeShift); } //Shift MxM Utility Tags ShiftTrackTags(GeneratedLeftFootStepTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift); ShiftTrackTags(GeneratedRightFootStepTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift); ShiftTrackTags(GeneratedWarpPositionTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift); ShiftTrackTags(GeneratedWarpRotationTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift); ShiftTrackTags(GeneratedEnableRootMotionTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift); ShiftTrackTags(GeneratedPoseFavourTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift); ShiftTrackTags(GeneratedWarpTrajLatTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift); ShiftTrackTags(GeneratedWarpTrajLongTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift); cumTimeShift += localTimeShift; curStartTime = endWarpTime; } for (int i = 0; i < workingCurves.Count; ++i) { EditorUtility.DisplayProgressBar("Generate Modified Animation", "Generating Curves for clip: " + PrimaryClip.name, ((float)i) / ((float)workingCurves.Count)); AnimationUtility.SetEditorCurve(GeneratedClip, curveBindings[i], workingCurves[i]); } AnimationUtility.SetAnimationEvents(GeneratedClip, newEvents.ToArray()); EditorUtility.SetDirty(GeneratedClip); AssetDatabase.CreateAsset(GeneratedClip, a_directory + "/" + GeneratedClip.name + ".anim"); //AssetDatabase.AddObjectToAsset(GeneratedClip, m_targetPreProcessData); AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(GeneratedClip)); EditorUtility.SetDirty(this); EditorUtility.ClearProgressBar(); } else { Debug.LogWarning("Warning: Cannot generate modified animation with no PrimaryClip in MxMAnimationClipComposite"); } } }
//============================================================================================ /** * @brief * *********************************************************************************************/ public void DrawSections(ref Rect a_trackRect, ref Rect a_timelineRect, float a_zoom, MxMTaggingWindow a_taggingWindow) { Texture markerIcon = EditorGUIUtility.IconContent("Animation.EventMarker").image; Rect markerRect; Event evt = Event.current; float lastTime = 0f; MotionTimingPresets motionTimingPresets = null; if (a_taggingWindow != null) m_targetMxMAnim = a_taggingWindow.TargetMxMAnim; var targetPreProcess = m_targetMxMAnim.TargetPreProcess; if (m_targetMxMAnim != null && targetPreProcess != null) { motionTimingPresets = targetPreProcess.MotionTimingPresets; } string[] defenitionNames = null; if(motionTimingPresets != null) { defenitionNames = motionTimingPresets.GetDefenitionNames(); } float maxSpeedVariance = 0.5f; //Determine max variance for (int i = 0; i < MotionSections.Count; ++i) { MotionSection curSection = MotionSections[i]; float speedMod = 1f; speedMod = curSection.GetSpeedMod(lastTime, motionTimingPresets, m_targetMxMAnim); float speedVariance = 0f; if (speedMod > 1f) speedVariance = (speedMod / 1f) - 1f; else if (speedMod < 1f) speedVariance = (1f / speedMod) - 1f; if (speedVariance > maxSpeedVariance) maxSpeedVariance = speedVariance; lastTime = curSection.EndTime; } lastTime = 0f; for (int i = 0; i < MotionSections.Count; ++i) { MotionSection curSection = MotionSections[i]; markerRect = new Rect(curSection.EndTime * 75f * a_zoom - (markerIcon.width / 2f), a_trackRect.y, markerIcon.width, markerIcon.height); Vector3 start = new Vector3(markerRect.x + markerRect.width / 2f, markerRect.y + markerRect.height); Vector3 end = new Vector3(start.x, a_timelineRect.height); if (i != MotionSections.Count - 1) { GUI.DrawTexture(markerRect, markerIcon); Handles.color = Color.black; Handles.DrawLine(start, end); if (curSection.Selected) GUI.DrawTexture(markerRect, EditorUtil.EditorFunctions.GetHighlightTex()); markerRect.x -= 3f; markerRect.height = a_trackRect.height; markerRect.width += 6f; if (evt.isMouse && evt.button == 0) { switch (evt.type) { case EventType.MouseDown: { if (markerRect.Contains(evt.mousePosition)) { curSection.Selected = true; curSection.Dragging = true; a_taggingWindow.SelectSection(curSection, curSection.EndTime); } } break; case EventType.MouseUp: { curSection.Dragging = false; } break; case EventType.MouseDrag: { if (curSection.Dragging && curSection.Selected) { float desiredValueDelta = ((evt.delta.x / a_zoom)) / 75f; curSection.EndTime += desiredValueDelta; curSection.EndTime = Mathf.Clamp(curSection.EndTime, 0f, a_taggingWindow.TargetClip.length); a_taggingWindow.Modified(curSection.EndTime); } } break; } } } float speedMod = 1f; speedMod = curSection.GetSpeedMod(lastTime, motionTimingPresets, m_targetMxMAnim); float speedVariance = 0f; if (speedMod > 1f) { speedVariance = (speedMod / 1f) - 1f; } else if (speedMod < 1f) { speedVariance = (1f / speedMod) - 1f; } float heightRatio = speedVariance / maxSpeedVariance; if (speedMod < 1f) heightRatio *= -1; if (maxSpeedVariance < 0.001f) heightRatio = 0f; //Draw Baseline end = new Vector3(curSection.EndTime * 75f * a_zoom, a_timelineRect.height / 2f + 9f); start = new Vector3(lastTime * 75f * a_zoom, end.y); Handles.color = new Color(0f, 0f, 0f, 0.5f); Handles.DrawLine(start, end); //Draw limit line Handles.color = new Color(0f, 0f, 0f, 0.3f); if (speedMod > 1f + Mathf.Epsilon) { end.y = a_timelineRect.height / 2f + (a_timelineRect.height / 2f - 44f) + 9f; start.y = end.y; Handles.DrawLine(start, end); } else { //Draw limit line end.y = a_timelineRect.height / 2f - (a_timelineRect.height / 2f - 44f) + 9f; start.y = end.y; Handles.DrawLine(start, end); } //Draw Green Line end.y = a_timelineRect.height / 2f + heightRatio * (a_timelineRect.height / 2f - 44f) + 9f; start.y = end.y; Handles.color = Color.green; Handles.DrawLine(start, end); float invertedSpeedMod = 1f / speedMod; string speedString = invertedSpeedMod.ToString("F2"); speedString += "x"; float width = GUI.skin.label.CalcSize(new GUIContent(speedString)).x; GUI.Label(new Rect(start.x + (end.x - start.x) / 2f - width / 2f, end.y - 18f, width, 18f), speedString); Rect dataRect = new Rect(lastTime * 75f * a_zoom + 4, a_timelineRect.height / 1.75f, end.x - start.x - 8, a_timelineRect.height - (a_timelineRect.height / 1.75f) - 18f); if (speedMod > 1f + Mathf.Epsilon) { dataRect.y = 40f; } //Draw Drop Down Boxes GUI.Box(dataRect, "Section " + i); dataRect.x += 3f; dataRect.width -= 6f; GUILayout.BeginArea(dataRect); GUILayout.Space(18f); if (motionTimingPresets != null) { curSection.UsePresets = GUILayout.Toggle(curSection.UsePresets, new GUIContent("Use Preset")); } if (curSection.UsePresets && motionTimingPresets != null) { curSection.MotionPresetId = EditorGUILayout.Popup(curSection.MotionPresetId, defenitionNames); } else { float defaultLabelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 40f; curSection.ModType = (EMotionModType)EditorGUILayout.EnumPopup(new GUIContent("Type"), curSection.ModType); curSection.RawModValue = EditorGUILayout.FloatField(new GUIContent("Value"), curSection.RawModValue); if (curSection.RawModValue < 0.01f) curSection.RawModValue = 0.01f; EditorGUIUtility.labelWidth = defaultLabelWidth; } GUILayout.FlexibleSpace(); float originalDurationF = (curSection.EndTime - lastTime); float finalDurationF = ((curSection.EndTime - lastTime) * speedMod); string originalDuration = originalDurationF.ToString("F2"); string finalDuration = finalDurationF.ToString("F2"); float originalSpeedF = m_targetMxMAnim.GetAverageRootSpeed(lastTime, curSection.EndTime); float finalSpeedF = originalSpeedF * (originalDurationF / finalDurationF); string originalSpeed = originalSpeedF.ToString("F2"); string finalSpeed = finalSpeedF.ToString("F2"); EditorGUILayout.LabelField("Original: " + originalDuration + " sec | " + originalSpeed + "m/s"); EditorGUILayout.LabelField("Final: " + finalDuration + " sec | " + finalSpeed + "m/s"); GUILayout.EndArea(); lastTime = curSection.EndTime; } }