//---------------------------------------------------------------------------------------------------------------------- /// <inheritdoc/> public override ClipDrawOptions GetClipOptions(TimelineClip clip) { ClipDrawOptions clipOptions = base.GetClipOptions(clip); SceneCachePlayableAsset asset = clip.asset as SceneCachePlayableAsset; if (null == asset) { Debug.LogError("Asset is not a SceneCachePlayableAsset: " + clip.asset); return clipOptions; } SceneCacheClipData clipData = asset.GetBoundClipData(); if (null == clipData) return clipOptions; SceneCachePlayer scPlayer = asset.GetSceneCachePlayer(); if (null == scPlayer) { clipOptions.errorText = NO_SCENE_CACHE_ASSIGNED_ERROR; return clipOptions; } LimitedAnimationController overrideLimitedAnimationController =asset.GetOverrideLimitedAnimationController(); if (!scPlayer.IsLimitedAnimationOverrideable() && overrideLimitedAnimationController.IsEnabled()) { clipOptions.errorText = UNABLE_TO_OVERRIDE_LIMITED_ANIMATION_ERROR; return clipOptions; } clipOptions.tooltip = scPlayer.GetSceneCacheFilePath(); return clipOptions; }
//---------------------------------------------------------------------------------------------------------------------- //Called when a clip is changed by the Editor. (TrimStart, TrimEnd, etc) public override void OnClipChanged(TimelineClip clip) { base.OnClipChanged(clip); SceneCachePlayableAsset playableAsset = clip.asset as SceneCachePlayableAsset; if (null == playableAsset) { Debug.LogWarning("[MeshSync] Clip Internal Error: Asset is not SceneCache"); return; } //Check if the curves is null, which may happen if the clip is created using code ? if (null == clip.curves) { CreateClipCurve(clip); } SceneCacheClipData clipData = playableAsset.GetBoundClipData() as SceneCacheClipData; if (null == clipData) { //The clip is not ready. Not deserialized yet return; } //Always apply clipCurves to clipData AnimationCurve curve = AnimationUtility.GetEditorCurve(clip.curves, SceneCachePlayableAsset.GetTimeCurveBinding()); clipData.SetAnimationCurve(curve); }
//---------------------------------------------------------------------------------------------------------------------- private void DrawLimitedAnimationGUI(SceneCachePlayableAsset scPlayableAsset) { SceneCachePlayer scPlayer = scPlayableAsset.GetSceneCachePlayer(); bool disableScope = null == scPlayer; if (null != scPlayer) { disableScope |= (!scPlayer.IsLimitedAnimationOverrideable()); } if (disableScope) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.HelpBox( "Disabled because Limited Animation settings on the SceneCache GameObject is enabled, or the playback mode is set to interpolate", MessageType.Warning ); if (GUILayout.Button("Fix", GUILayout.Width(64), GUILayout.Height(36))) { scPlayer.AllowLimitedAnimationOverride(); Repaint(); } EditorGUILayout.EndHorizontal(); } using (new EditorGUI.DisabledScope(disableScope)) { SceneCachePlayerEditorUtility.DrawLimitedAnimationGUI(scPlayableAsset.GetOverrideLimitedAnimationController(), m_scPlayableAsset, scPlayer); } }
public IEnumerator CreatePlayableAsset() { EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects); //Add director GameObject directorGo = new GameObject("Director"); PlayableDirector director = directorGo.AddComponent <PlayableDirector>(); //Setup scene cache GameObject sceneCacheGo = new GameObject(); SceneCachePlayer sceneCachePlayer = sceneCacheGo.AddComponent <SceneCachePlayer>(); Assert.IsFalse(sceneCachePlayer.IsSceneCacheOpened()); SceneCachePlayerEditorUtility.ChangeSceneCacheFile(sceneCachePlayer, Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH)); //Create timeline asset TimelineAsset asset = ScriptableObject.CreateInstance <TimelineAsset>(); director.playableAsset = asset; //Create PlayableAsset/Track/ etc SceneCachePlayableAsset playableAsset = ScriptableObject.CreateInstance <SceneCachePlayableAsset>(); SceneCacheTrack sceneCacheTrack = asset.CreateTrack <SceneCacheTrack>(null, "TestSceneCacheTrack"); TimelineClip clip = sceneCacheTrack.CreateDefaultClip(); clip.asset = playableAsset; director.SetReferenceValue(playableAsset.GetSceneCachePlayerRef().exposedName, sceneCachePlayer); //Select gameObject and open Timeline Window. This will trigger the TimelineWindow's update etc. EditorApplication.ExecuteMenuItem("Window/Sequencing/Timeline"); Selection.activeTransform = directorGo.transform; yield return(null); director.time = 0; yield return(null); Assert.AreEqual(0, sceneCachePlayer.GetRequestedNormalizedTime()); double timePerFrame = 1.0f / sceneCacheTrack.timelineAsset.editorSettings.fps; double directorTime = clip.start + clip.duration - timePerFrame; SetDirectorTime(director, directorTime); yield return(null); //Check clipData and curve SceneCacheClipData clipData = playableAsset.GetBoundClipData(); Assert.IsNotNull(clipData); AnimationCurve curve = clipData.GetAnimationCurve(); Assert.IsNotNull(curve); float normalizedTime = curve.Evaluate((float)directorTime); Assert.AreEqual(normalizedTime, sceneCachePlayer.GetRequestedNormalizedTime()); }
//---------------------------------------------------------------------------------------------------------------------- private void CreateClipCurve(TimelineClip clip) { clip.CreateCurves("Curves: " + clip.displayName); //Init dummy linear curve AnimationCurve curve = AnimationCurve.Linear(0f,0f,(float)clip.duration,1f); AnimationUtility.SetEditorCurve(clip.curves, SceneCachePlayableAsset.GetTimeCurveBinding(),curve); TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved ); }
private static AnimationCurve VerifyAnimationCurve(TimelineClip clip) { SceneCachePlayableAsset sceneCachePlayableAsset = clip.asset as SceneCachePlayableAsset; Assert.IsNotNull(sceneCachePlayableAsset); AnimationCurve curve = sceneCachePlayableAsset.GetAnimationCurve(); Assert.IsNotNull(curve); return(curve); }
public IEnumerator EnsureMatchingAndLimitedFramesAreLoadedToScene() { InitTest(true, out PlayableDirector director, out SceneCachePlayer sceneCachePlayer, out TimelineClip clip0); yield return(null); ISceneCacheInfo scInfo = sceneCachePlayer.ExtractSceneCacheInfo(forceOpen: true); Assert.IsNotNull(scInfo); int numFrames = scInfo.GetNumFrames(); double timePerFrame = 1.0f / scInfo.GetSampleRate(); //Setup clip0 duration int halfFrames = Mathf.FloorToInt(numFrames * 0.5f); clip0.duration = halfFrames * timePerFrame; //Setup clip1 TimelineClip clip1 = clip0.GetParentTrack().CreateClip <SceneCachePlayableAsset>(); clip1.start = clip0.start + clip0.duration; clip1.clipIn = clip0.duration; clip1.duration = clip0.duration; SceneCachePlayableAsset playableAsset1 = clip1.asset as SceneCachePlayableAsset; Assert.IsNotNull(playableAsset1); director.SetReferenceValue(playableAsset1.GetSceneCachePlayerRef().exposedName, sceneCachePlayer); TimelineEditorUtility.RefreshTimelineEditor(RefreshReason.ContentsAddedOrRemoved | RefreshReason.WindowNeedsRedraw | RefreshReason.ContentsModified); yield return(null); //Setup Limited Animation const int NUM_FRAMES_TO_HOLD = 3; const int OFFSET = 1; LimitedAnimationController limitedAnimationController1 = playableAsset1.GetOverrideLimitedAnimationController(); limitedAnimationController1.Enable(NUM_FRAMES_TO_HOLD, OFFSET); yield return(IterateAllSceneCacheFrames(director, clip0, sceneCachePlayer, (int timelineFrame) => { EditorApplication.isPaused = true; Assert.AreEqual(timelineFrame, sceneCachePlayer.GetFrame()); })); yield return(IterateAllSceneCacheFrames(director, clip1, sceneCachePlayer, (int timelineFrame) => { int shownFrame = sceneCachePlayer.GetFrame(); if (shownFrame == (scInfo.GetNumFrames() - 1)) //clamped to the end frame { return; } Assert.Zero(shownFrame % NUM_FRAMES_TO_HOLD - OFFSET); })); }
//---------------------------------------------------------------------------------------------------------------------- internal static TimelineClip AddSceneCacheTrackAndClip(PlayableDirector director, string trackName, SceneCachePlayer sceneCachePlayer) { TimelineAsset timelineAsset = director.playableAsset as TimelineAsset; Assert.IsNotNull(timelineAsset); SceneCacheTrack sceneCacheTrack = timelineAsset.CreateTrack<SceneCacheTrack>(null, trackName); TimelineClip clip = sceneCacheTrack.CreateDefaultClip(); SceneCachePlayableAsset playableAsset = clip.asset as SceneCachePlayableAsset; Assert.IsNotNull(playableAsset); director.SetReferenceValue(playableAsset.GetSceneCachePlayerRef().exposedName, sceneCachePlayer ); return clip; }
//---------------------------------------------------------------------------------------------------------------------- /// <inheritdoc/> public override void OnCreate(TimelineClip clip, TrackAsset track, TimelineClip clonedFrom) { SceneCachePlayableAsset asset = clip.asset as SceneCachePlayableAsset; if (null == asset) { Debug.LogError("[MeshSync] Asset is not a SceneCachePlayableAsset: " + clip.asset); return; } SceneCachePlayerConfig config = MeshSyncProjectSettings.GetOrCreateSettings().GetDefaultSceneCachePlayerConfig(); asset.SetSnapToFrame((SnapToFrame) config.TimelineSnapToFrame); //OnCreate() is called before the clip is assigned to the track, but we need the track for creating curves. clip.TryMoveToTrack(track); }
//---------------------------------------------------------------------------------------------------------------------- /// <inheritdoc/> public override void OnCreate(TimelineClip clip, TrackAsset track, TimelineClip clonedFrom) { SceneCachePlayableAsset asset = clip.asset as SceneCachePlayableAsset; if (null == asset) { Debug.LogError("[MeshSync] Asset is not a SceneCachePlayableAsset: " + clip.asset); return; } //Track can be null during copy and paste if (null != track) { //This callback occurs before the clip is assigned to the track, but we need the track for creating curves. clip.TryMoveToTrack(track); } asset.Init(updateClipDurationOnCreatePlayable: null == clonedFrom); }
//---------------------------------------------------------------------------------------------------------------------- /// <inheritdoc/> public override void OnCreate(TimelineClip clip, TrackAsset track, TimelineClip clonedFrom) { SceneCachePlayableAsset asset = clip.asset as SceneCachePlayableAsset; if (null == asset) { Debug.LogError("[MeshSync] Asset is not a SceneCachePlayableAsset: " + clip.asset); return; } //OnCreate() is called before the clip is assigned to the track, but we need the track for creating curves. clip.parentTrack = track; //If the clip already has curves (because of cloning, etc), then we don't set anything if (null == clip.curves) { CreateClipCurve(clip); } }
public IEnumerator EnsureLimitedFramesAreLoadedToScene() { InitTest(true, out PlayableDirector director, out SceneCachePlayer sceneCachePlayer, out TimelineClip clip); yield return(null); //Setup Limited Animation const int NUM_FRAMES_TO_HOLD = 3; const int OFFSET = 1; SceneCachePlayableAsset sceneCachePlayableAsset = clip.asset as SceneCachePlayableAsset; Assert.IsNotNull(sceneCachePlayableAsset); LimitedAnimationController limitedAnimationController = sceneCachePlayableAsset.GetOverrideLimitedAnimationController(); limitedAnimationController.Enable(NUM_FRAMES_TO_HOLD, OFFSET); yield return(IterateAllSceneCacheFrames(director, clip, sceneCachePlayer, (int timelineFrame) => { int shownFrame = sceneCachePlayer.GetFrame(); Assert.Zero(shownFrame % NUM_FRAMES_TO_HOLD - OFFSET); })); }
public IEnumerator ChangeSceneCache() { InitTest(true, out PlayableDirector _, out SceneCachePlayer scPlayer, out TimelineClip clip); yield return(null); SceneCachePlayableAsset sceneCachePlayableAsset = clip.asset as SceneCachePlayableAsset; Assert.IsNotNull(sceneCachePlayableAsset); sceneCachePlayableAsset.SetSceneCachePlayerInEditor(null); double halfDuration = clip.duration * 0.5f; clip.duration = halfDuration; TimelineEditor.Refresh(RefreshReason.ContentsModified); yield return(null); sceneCachePlayableAsset.SetSceneCachePlayerInEditor(scPlayer); TimelineEditor.Refresh(RefreshReason.ContentsModified); yield return(null); Assert.IsTrue(Mathf.Approximately((float)halfDuration, (float)clip.duration), "Clip Duration has been reset."); }
//---------------------------------------------------------------------------------------------------------------------- /// <inheritdoc/> public override void DrawBackground(TimelineClip clip, ClipBackgroundRegion region) { base.DrawBackground(clip, region); SceneCachePlayableAsset asset = clip.asset as SceneCachePlayableAsset; if (null == asset) { Debug.LogError("Asset is not a SceneCachePlayableAsset: " + clip.asset); return; } SceneCacheClipData clipData = asset.GetBoundClipData(); if (null == clipData) return; LimitedAnimationController limitedAnimationController = asset.GetOverrideLimitedAnimationController(); if (!limitedAnimationController.IsEnabled()) { return; } int numFrames = limitedAnimationController.GetNumFramesToHold(); int offset = limitedAnimationController.GetFrameOffset(); GUIStyle style = new GUIStyle(GUI.skin.label) { alignment = TextAnchor.LowerRight, normal = { textColor = new Color(0.3f,0.9f,0.3f), } }; GUIContent laContent = new GUIContent($"Limited: {numFrames}, {offset}"); Vector2 laContentSize = style.CalcSize(laContent); Rect rect = region.position; if (rect.width <= laContentSize.x * 2) //2: arbitrary return; EditorGUI.LabelField(rect, laContent, style); }