internal static bool CreateSceneCachePlayerAndPrefab(string sceneCacheFilePath, string prefabPath, string assetsFolder, out SceneCachePlayer player, out GameObject prefab) { player = null; prefab = null; GameObject go = new GameObject(); go.name = Path.GetFileNameWithoutExtension(sceneCacheFilePath); player = AddSceneCachePlayer(go, sceneCacheFilePath, assetsFolder); if (null == player) { Object.DestroyImmediate(go); return false; } //Optimize serialization by ensuring to serialize the key values at the end player.EnableKeyValuesSerialization(false); prefab = player.gameObject.SaveAsPrefab(prefabPath); if (null == prefab) { Object.DestroyImmediate(go); return false; } player.EnableKeyValuesSerialization(true); PrefabUtility.ApplyPrefabInstance(player.gameObject, InteractionMode.AutomatedAction); Undo.RegisterCreatedObjectUndo(go, "SceneCachePlayer"); return true; }
//---------------------------------------------------------------------------------------------------------------------- /// <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; }
public static GameObject CreateSceneCachePlayerPrefab(string path) { GameObject go = CreateSceneCachePlayer(path); if (go == null) { return(null); } // export materials & animation and generate prefab SceneCachePlayer player = go.GetComponent <SceneCachePlayer>(); player.UpdatePlayer(); player.ExportMaterials(false, true); player.ResetTimeAnimation(); player.handleAssets = false; SceneData scene = player.GetLastScene(); if (!scene.submeshesHaveUniqueMaterial) { MeshSyncPlayerConfig config = player.GetConfig(); config.SyncMaterialList = false; } string prefabPath = string.Format("Assets/SceneCache/{0}.prefab", go.name); PrefabUtility.SaveAsPrefabAssetAndConnect(go, prefabPath, InteractionMode.AutomatedAction); return(go); }
public void ChangeSceneCacheOnDirectPrefab() { //Initial setup const string DEST_PREFAB_PATH = "Assets/TestSceneCache.prefab"; const string ASSETS_FOLDER = "Assets/TestSceneCacheAssets"; bool prefabCreated = SceneCachePlayerEditorUtility.CreateSceneCachePlayerAndPrefab( Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH), DEST_PREFAB_PATH, ASSETS_FOLDER, out SceneCachePlayer player, out GameObject prefab ); Assert.IsTrue(prefabCreated); //Check the prefab Assert.IsFalse(prefab.IsPrefabInstance()); Assert.IsTrue(prefab.IsPrefab()); SceneCachePlayer prefabPlayer = prefab.GetComponent <SceneCachePlayer>(); Assert.IsNotNull(prefabPlayer); Camera cam0 = prefabPlayer.GetComponentInChildren <Camera>(); Light light0 = prefabPlayer.GetComponentInChildren <Light>(); //Change TestDataComponents comps = ChangeSceneCacheFileAndVerify(prefabPlayer, Path.GetFullPath(MeshSyncTestEditorConstants.SPHERE_TEST_DATA_PATH) ); Assert.AreEqual(cam0, comps.cam); Assert.AreEqual(light0, comps.light); //Cleanup Object.DestroyImmediate(player.gameObject); DeleteSceneCachePlayerPrefab(prefab); }
//---------------------------------------------------------------------------------------------------------------------- void DeleteSceneCachePlayerPrefab(GameObject prefab) { Assert.IsTrue(prefab.IsPrefab()); SceneCachePlayer prefabPlayer = prefab.GetComponent <SceneCachePlayer>(); Assert.IsNotNull(prefabPlayer); string assetsFolder = prefabPlayer.GetAssetsFolder(); //Check assets folder Assert.IsTrue(Directory.Exists(assetsFolder)); string[] prefabAssetGUIDs = AssetDatabase.FindAssets("", new[] { assetsFolder }); Assert.Greater(prefabAssetGUIDs.Length, 0); //Cleanup foreach (string guid in prefabAssetGUIDs) { AssetDatabase.DeleteAsset(AssetDatabase.GUIDToAssetPath(guid)); } FileUtil.DeleteFileOrDirectory(assetsFolder); string prefabPath = AssetDatabase.GetAssetPath(prefab); Assert.IsFalse(string.IsNullOrEmpty(prefabPath)); AssetDatabase.DeleteAsset(prefabPath); AssetDatabase.Refresh(); }
//---------------------------------------------------------------------------------------------------------------------- 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 void ChangeSceneCacheOnDirectPrefab() { //Initial setup const string DEST_PREFAB_PATH = "Assets/TestSceneCache.prefab"; const string ASSETS_FOLDER = "Assets/TestSceneCacheAssets"; bool prefabCreated = SceneCachePlayerEditorUtility.CreateSceneCachePlayerAndPrefab( Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH), DEST_PREFAB_PATH, ASSETS_FOLDER, out SceneCachePlayer player, out GameObject prefab ); Assert.IsTrue(prefabCreated); //Check the prefab Assert.IsFalse(prefab.IsPrefabInstance()); Assert.IsTrue(prefab.IsPrefab()); SceneCachePlayer prefabPlayer = prefab.GetComponent <SceneCachePlayer>(); Assert.IsNotNull(prefabPlayer); //Change string newSceneCacheFilePath = Path.GetFullPath(MeshSyncTestEditorConstants.SPHERE_TEST_DATA_PATH); SceneCachePlayerEditorUtility.ChangeSceneCacheFile(prefabPlayer, newSceneCacheFilePath); string convertedPath = newSceneCacheFilePath.Replace('\\', '/'); Assert.AreEqual(convertedPath, player.GetSceneCacheFilePath()); //Cleanup Object.DestroyImmediate(player.gameObject); DeleteSceneCachePlayerPrefab(prefab); }
private static SceneCachePlayer CreateTestSceneCachePlayer() { GameObject sceneCacheGo = new GameObject(); SceneCachePlayer sceneCachePlayer = sceneCacheGo.AddComponent <SceneCachePlayer>(); SceneCachePlayerEditorUtility.ChangeSceneCacheFile(sceneCachePlayer, Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH)); return(sceneCachePlayer); }
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()); }
//---------------------------------------------------------------------------------------------------------------------- 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; }
//---------------------------------------------------------------------------------------------------------------------- private static void InitTest(bool enableSceneCacheGo, out PlayableDirector director, out SceneCachePlayer sceneCachePlayer, out TimelineClip clip) { EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects); director = CreateTestDirector(); sceneCachePlayer = CreateTestSceneCachePlayer(); sceneCachePlayer.gameObject.SetActive(enableSceneCacheGo); clip = SceneCachePlayerEditorUtility.AddSceneCacheTrackAndClip(director, "TestSceneCacheTrack", sceneCachePlayer); TimelineEditorUtility.SelectDirectorInTimelineWindow(director); //trigger the TimelineWindow's update etc. TimelineEditorUtility.RefreshTimelineEditor(); }
//---------------------------------------------------------------------------------------------------------------------- bool DrawCacheFile(SceneCachePlayer t) { t.ShowCacheFileInInspector(EditorGUILayout.Foldout(t.IsCacheFileShownInInspector(), "File", true, GetDefaultFoldoutStyle())); if (!t.IsCacheFileShownInInspector()) { return(false); } bool changed = false; //Show Selector GUI. Check if we should reopen string fullPath = t.GetSceneCacheFilePath(); string prevNormalizedPath = AssetEditorUtility.NormalizePath(fullPath); string newNormalizedPath = EditorGUIDrawerUtility.DrawFileSelectorGUI("Cache File Path", "MeshSync", prevNormalizedPath, "sc", OnSceneCacheFileReload); newNormalizedPath = AssetEditorUtility.NormalizePath(newNormalizedPath); if (newNormalizedPath != prevNormalizedPath) { ChangeSceneCacheFileInInspector(t, newNormalizedPath); } if (!string.IsNullOrEmpty(fullPath) && !fullPath.StartsWith(Application.streamingAssetsPath)) { GUILayout.BeginHorizontal(); const float BUTTON_WIDTH = 50.0f; if (GUILayout.Button("Copy", GUILayout.Width(BUTTON_WIDTH))) { string dstPath = Misc.CopyFileToStreamingAssets(fullPath); ChangeSceneCacheFileInInspector(t, dstPath); } GUILayout.Label("Scene Cache file to StreamingAssets"); EditorGUILayout.LabelField("(RECOMMENDED)", EditorStyles.boldLabel); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(15); } EditorGUILayout.Space(); //[TODO-sin: 2022-3-14] This may cause crash when sliding the values back and forth. Find out why // preload { // changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Preload", // guiFunc: () => (EditorGUILayout.IntSlider("Preload Length", t.GetPreloadLength(), 0, t.frameCount)), // updateFunc: (int preloadLength) => { t.SetPreloadLength(preloadLength); }); } return(changed); }
//---------------------------------------------------------------------------------------------------------------------- internal static void ChangeSceneCacheFile(SceneCachePlayer cachePlayer, string sceneCacheFilePath) { string prefabPath = null; GameObject go = cachePlayer.gameObject; //Check if it's possible to reuse the old assetsFolder string assetsFolder = cachePlayer.GetAssetsFolder(); if (string.IsNullOrEmpty(assetsFolder)) { MeshSyncRuntimeSettings runtimeSettings = MeshSyncRuntimeSettings.GetOrCreateSettings(); string scOutputPath = runtimeSettings.GetSceneCacheOutputPath(); assetsFolder = Path.Combine(scOutputPath, Path.GetFileNameWithoutExtension(sceneCacheFilePath)); } bool isPrefabInstance = cachePlayer.gameObject.IsPrefabInstance(); //We are directly modifying a prefab if (!isPrefabInstance && go.IsPrefab()) { prefabPath = AssetDatabase.GetAssetPath(go); CreateSceneCachePlayerAndPrefab(sceneCacheFilePath, prefabPath, assetsFolder, out SceneCachePlayer player, out GameObject newPrefab); Object.DestroyImmediate(player.gameObject); return; } if (isPrefabInstance) { GameObject prefab = PrefabUtility.GetCorrespondingObjectFromSource(cachePlayer.gameObject); prefabPath = AssetDatabase.GetAssetPath(prefab); } cachePlayer.CloseCache(); //[TODO-sin: 2020-9-28] Find out if it is possible to do undo properly Undo.RegisterFullObjectHierarchyUndo(cachePlayer.gameObject, "SceneCachePlayer"); cachePlayer.Init(assetsFolder); cachePlayer.OpenCacheInEditor(sceneCacheFilePath); //Save as prefab again if (string.IsNullOrEmpty(prefabPath)) { return; } //Prevent overwriting ".sc" file itself bool isPrefabExt = (Path.GetExtension(prefabPath).ToLower() == ".prefab"); if (isPrefabExt) { cachePlayer.gameObject.SaveAsPrefab(prefabPath); } }
public void ChangeSceneCacheOnGameObject() { //Initial setup GameObject go = new GameObject(); SceneCachePlayer player = go.AddComponent <SceneCachePlayer>(); Assert.IsFalse(player.IsSceneCacheOpened()); //Change SceneCachePlayerEditorUtility.ChangeSceneCacheFile(player, Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH)); Assert.IsTrue(player.IsSceneCacheOpened()); SceneCachePlayerEditorUtility.ChangeSceneCacheFile(player, Path.GetFullPath(MeshSyncTestEditorConstants.SPHERE_TEST_DATA_PATH)); Assert.IsTrue(player.IsSceneCacheOpened()); //Cleanup Object.DestroyImmediate(go); }
//---------------------------------------------------------------------------------------------------------------------- private static SceneCachePlayer AddSceneCachePlayer(GameObject go, string sceneCacheFilePath, string assetsFolder) { if (!ValidateSceneCacheOutputPath()) { return null; } SceneCachePlayer player = go.GetOrAddComponent<SceneCachePlayer>(); player.Init(assetsFolder); if (!player.OpenCacheInEditor(sceneCacheFilePath)) { return null; } return player; }
//---------------------------------------------------------------------------------------------------------------------- public override void OnImportAsset(AssetImportContext ctx) { //Ignore assets outside Assets folder (for example: Packages, etc) if (!ctx.assetPath.StartsWith("Assets/")) { return; } GameObject go = new GameObject(); SceneCachePlayer player = go.AddComponent <SceneCachePlayer>(); SceneCachePlayerEditorUtility.ChangeSceneCacheFile(player, ctx.assetPath); string objectName = Path.GetFileNameWithoutExtension(ctx.assetPath); go.name = objectName; ctx.AddObjectToAsset(objectName, go); ctx.SetMainObject(go); }
//---------------------------------------------------------------------------------------------------------------------- static TestDataComponents ChangeSceneCacheFileAndVerify(SceneCachePlayer player, string scPath) { SceneCachePlayerEditorUtility.ChangeSceneCacheFile(player, scPath); string savedScFilePath = player.GetSceneCacheFilePath(); Assert.AreEqual(AssetEditorUtility.NormalizePath(scPath), savedScFilePath); Assert.IsTrue(AssetEditorUtility.IsPathNormalized(savedScFilePath), $"{savedScFilePath} is not normalized"); Assert.IsTrue(player.transform.childCount > 0); TestDataComponents ret = new TestDataComponents( player.GetComponentInChildren <Camera>(), player.GetComponentInChildren <Light>(), player.GetComponentInChildren <MeshRenderer>() ); Assert.IsNotNull(ret.cam); Assert.IsNotNull(ret.light); Assert.IsNotNull(ret.meshRenderer); return(ret); }
public static GameObject CreateSceneCachePlayer(string path) { // create temporary GO to make prefab GameObject go = new GameObject(); go.name = System.IO.Path.GetFileNameWithoutExtension(path); SceneCachePlayer player = go.AddComponent <SceneCachePlayer>(); player.rootObject = go.GetComponent <Transform>(); player.assetDir = new DataPath(DataPath.Root.DataPath, string.Format("SceneCache/{0}", go.name)); player.markMeshesDynamic = true; player.dontSaveAssetsInScene = true; if (!player.OpenCache(path)) { Debug.LogError("Failed to open " + path + ". Possible reasons: file format version does not match, or the file is not scene cache."); DestroyImmediate(go); return(null); } return(go); }
//---------------------------------------------------------------------------------------------------------------------- private static bool DrawPlaybackMode(SceneCachePlayer t) { t.ShowPlaybackInInspector(EditorGUILayout.Foldout(t.IsPlaybackInInspectorShown(), "Playback", true, GetDefaultFoldoutStyle())); if (!t.IsPlaybackInInspectorShown()) { return(false); } bool changed = false; changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Playback Mode", guiFunc: () => (SceneCachePlaybackMode)EditorGUILayout.EnumPopup("Playback Mode", t.GetPlaybackMode()), updateFunc: (SceneCachePlaybackMode mode) => { t.SetPlaybackMode(mode); SceneCachePlayerEditorUtility.RefreshSceneCache(t); } ); ++EditorGUI.indentLevel; changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Time", guiFunc: () => (EditorGUILayout.FloatField("Time", t.GetTime())), updateFunc: (float time) => { t.SetTime(Mathf.Max(0, time)); }); using (new EditorGUI.DisabledScope(t.GetPlaybackMode() == SceneCachePlaybackMode.Interpolate)) { changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Frame", guiFunc: () => (EditorGUILayout.IntField("Frame", t.GetFrame())), updateFunc: (int frame) => { t.SetTimeByFrame(Mathf.Max(0, frame)); }); } --EditorGUI.indentLevel; using (new EditorGUI.DisabledScope(t.GetPlaybackMode() == SceneCachePlaybackMode.Interpolate)) { changed |= SceneCachePlayerEditorUtility.DrawLimitedAnimationGUI(t.GetLimitedAnimationController(), t, t); } EditorGUILayout.Space(); return(changed); }
//---------------------------------------------------------------------------------------------------------------------- internal static bool DrawLimitedAnimationGUI(LimitedAnimationController ctrl, Object target, SceneCachePlayer sc) { bool changed = false; const string UNDO_TEXT = "SceneCache: Limited Animation"; //Limited Animation changed |= EditorGUIDrawerUtility.DrawUndoableGUI(target, UNDO_TEXT, guiFunc: () => (EditorGUILayout.Toggle("Limited Animation", ctrl.IsEnabled())), updateFunc: (bool limitedAnimation) => { ctrl.SetEnabled(limitedAnimation); SceneCachePlayerEditorUtility.RefreshSceneCache(sc); }); ++EditorGUI.indentLevel; using (new EditorGUI.DisabledScope(!ctrl.IsEnabled())) { changed |= EditorGUIDrawerUtility.DrawUndoableGUI(target, UNDO_TEXT, guiFunc: () => ( EditorGUILayout.IntField("Num Frames to Hold", ctrl.GetNumFramesToHold()) ), updateFunc: (int frames) => { ctrl.SetNumFramesToHold(frames); SceneCachePlayerEditorUtility.RefreshSceneCache(sc); }); changed |= EditorGUIDrawerUtility.DrawUndoableGUI(target, UNDO_TEXT, guiFunc: () => ( EditorGUILayout.IntField("Frame Offset", ctrl.GetFrameOffset()) ), updateFunc: (int offset) => { ctrl.SetFrameOffset(offset); SceneCachePlayerEditorUtility.RefreshSceneCache(sc); }); } --EditorGUI.indentLevel; EditorGUILayout.Space(); return changed; }
private static void DrawCacheInfo(SceneCachePlayer t) { ISceneCacheInfo scInfo = t.ExtractSceneCacheInfo(forceOpen: false); if (null == scInfo) { return; } t.ShowInfoInInspector(EditorGUILayout.Foldout(t.IsInfoInInspectorShown(), "Info", true, GetDefaultFoldoutStyle())); if (!t.IsInfoInInspectorShown()) { return; } ++EditorGUI.indentLevel; const int leftWidth = 160; int numFrames = scInfo.GetNumFrames(); float sampleRate = scInfo.GetSampleRate(); TimeRange timeRange = scInfo.GetTimeRange(); EditorGUILayout.BeginHorizontal(); GUILayout.Label($"Num Frames: {numFrames}", GUILayout.MaxWidth(leftWidth)); GUILayout.Label($"Start Time: {timeRange.start,15:N4}"); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUILayout.Label($"Frame Rate: {sampleRate}", GUILayout.MaxWidth(leftWidth)); GUILayout.Label($"End Time : {timeRange.end,15:N4}"); EditorGUILayout.EndHorizontal(); --EditorGUI.indentLevel; EditorGUILayout.Space(); EditorGUILayout.Space(); }
//---------------------------------------------------------------------------------------------------------------------- public override void OnInspectorGUI() { if (m_scPlayableAsset.IsNullRef()) return; SerializedObject so = serializedObject; EditorGUILayout.PropertyField(so.FindProperty("m_sceneCachePlayerRef"), SCENE_CACHE_PLAYER); SceneCacheClipData clipData = m_scPlayableAsset.GetBoundClipData(); if (null == clipData) return; SceneCachePlayer scPlayer = m_scPlayableAsset.GetSceneCachePlayer(); if (null == scPlayer) return; DrawLimitedAnimationGUI(m_scPlayableAsset); { // Curve Operations GUILayout.BeginVertical("Box"); EditorGUILayout.LabelField("Curves", EditorStyles.boldLabel); const float BUTTON_X = 30; const float BUTTON_WIDTH = 160f; if (DrawGUIButton(BUTTON_X, BUTTON_WIDTH,"To Linear")) { m_scPlayableAsset.SetCurveToLinearInEditor(); } if (DrawGUIButton(BUTTON_X, BUTTON_WIDTH,"Apply Original")) { m_scPlayableAsset.ApplyOriginalSceneCacheCurveInEditor(); } GUILayout.EndVertical(); } so.ApplyModifiedProperties(); }
internal static bool CreateSceneCachePlayerAndPrefab(string sceneCacheFilePath, string prefabPath, string assetsFolder, out SceneCachePlayer player, out GameObject prefab) { player = null; prefab = null; GameObject go = new GameObject(); go.name = Path.GetFileNameWithoutExtension(sceneCacheFilePath); player = AddSceneCachePlayer(go, sceneCacheFilePath, assetsFolder); if (null == player) { Object.DestroyImmediate(go); return false; } prefab = player.gameObject.SaveAsPrefab(prefabPath); if (null == prefab) { Object.DestroyImmediate(go); return false; } Undo.RegisterCreatedObjectUndo(go, "SceneCachePlayer"); return true; }
public override void OnInspectorGUI() { var so = serializedObject; SceneCachePlayer t = target as SceneCachePlayer; EditorGUILayout.Space(); DrawCacheSettings(t, so); DrawPlayerSettings(t, so); MeshSyncPlayerConfig config = t.GetConfig(); if (config.Profiling) { EditorGUILayout.TextArea(t.dbgProfileReport, GUILayout.Height(120)); EditorGUILayout.Space(); } DrawMaterialList(t); DrawTextureList(t); DrawAnimationTweak(t); DrawExportAssets(t); DrawPluginVersion(); so.ApplyModifiedProperties(); }
//---------------------------------------------------------------------------------------------------------------------- internal static void ChangeSceneCacheFile(SceneCachePlayer cachePlayer, string sceneCacheFilePath) { string prefabPath = null; GameObject go = cachePlayer.gameObject; //Check if it's possible to reuse the old assetsFolder string assetsFolder = cachePlayer.GetAssetsFolder(); if (string.IsNullOrEmpty(assetsFolder)) { MeshSyncProjectSettings projectSettings = MeshSyncProjectSettings.GetOrCreateSettings(); string scOutputPath = projectSettings.GetSceneCacheOutputPath(); assetsFolder = Path.Combine(scOutputPath, Path.GetFileNameWithoutExtension(sceneCacheFilePath)); } bool isPrefabInstance = cachePlayer.gameObject.IsPrefabInstance(); //We are directly modifying a prefab if (!isPrefabInstance && go.IsPrefab()) { prefabPath = AssetDatabase.GetAssetPath(go); CreateSceneCachePlayerAndPrefab(sceneCacheFilePath, prefabPath, assetsFolder, out SceneCachePlayer player, out GameObject newPrefab); Object.DestroyImmediate(player.gameObject); return; } if (isPrefabInstance) { GameObject prefab = PrefabUtility.GetCorrespondingObjectFromSource(cachePlayer.gameObject); //GetCorrespondingObjectFromSource() may return the ".sc" GameObject instead of the prefab //due to the SceneCacheImporter string assetPath = AssetDatabase.GetAssetPath(prefab); if (Path.GetExtension(assetPath).ToLower() == ".prefab") { prefabPath = assetPath; } else { isPrefabInstance = false; } } cachePlayer.CloseCache(); //[TODO-sin: 2020-9-28] Find out if it is possible to do undo properly Undo.RegisterFullObjectHierarchyUndo(cachePlayer.gameObject, "SceneCachePlayer"); Dictionary<string,EntityRecord> prevRecords = new Dictionary<string, EntityRecord>(cachePlayer.GetClientObjects()); GameObject tempGO = null; Dictionary<Transform, Transform> nonPrefabTrans = new Dictionary<Transform, Transform>(); //nonPrefab -> origParent if (isPrefabInstance) { //Move non-prefab transforms tempGO = new GameObject("Temp"); FindNonPrefabChildren(cachePlayer.transform, ref nonPrefabTrans); nonPrefabTrans.Keys.SetParent(tempGO.transform); PrefabUtility.UnpackPrefabInstance(cachePlayer.gameObject, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); } //remove irrelevant components of the GameObject if the entity type is different void ChangeEntityTypeCB(GameObject updatedGo, TransformData data) { string dataPath = data.path; if (!prevRecords.ContainsKey(dataPath)) return; EntityRecord prevRecord = prevRecords[dataPath]; if (data.entityType == prevRecord.dataType) return; DestroyIrrelevantComponents(updatedGo, data.entityType); } cachePlayer.onUpdateEntity += ChangeEntityTypeCB; cachePlayer.Init(assetsFolder); cachePlayer.OpenCacheInEditor(sceneCacheFilePath); cachePlayer.onUpdateEntity -= ChangeEntityTypeCB; IDictionary<string,EntityRecord> curRecords = cachePlayer.GetClientObjects(); DeleteInvalidRecordedGameObjects(prevRecords, curRecords); if (!isPrefabInstance) { return; } cachePlayer.gameObject.SaveAsPrefab(prefabPath); //Save as prefab if it was originally a prefab instance //Move nonPrefab transforms back foreach (KeyValuePair<Transform, Transform> kv in nonPrefabTrans) { Transform origParent = kv.Value; Transform t = kv.Key; if (null == origParent) { ObjectUtility.Destroy(t.gameObject); } else { t.SetParent(origParent); } } ObjectUtility.Destroy(tempGO); }
//---------------------------------------------------------------------------------------------------------------------- bool DrawCacheSettings(SceneCachePlayer t) { bool changed = false; GUIStyle styleFold = EditorStyles.foldout; styleFold.fontStyle = FontStyle.Bold; t.foldCacheSettings = EditorGUILayout.Foldout(t.foldCacheSettings, "Player", true, styleFold); if (t.foldCacheSettings) { //Show Selector GUI. Check if we should reopen string fullPath = t.GetSceneCacheFilePath(); string prevNormalizedPath = AssetEditorUtility.NormalizePath(fullPath); string newNormalizedPath = EditorGUIDrawerUtility.DrawFileSelectorGUI("Cache File Path", "MeshSync", prevNormalizedPath, "sc", OnSceneCacheFileReload); newNormalizedPath = AssetEditorUtility.NormalizePath(newNormalizedPath); if (newNormalizedPath != prevNormalizedPath) { ChangeSceneCacheFileInInspector(t, newNormalizedPath); } if (!string.IsNullOrEmpty(fullPath) && !fullPath.StartsWith(Application.streamingAssetsPath)) { GUILayout.BeginHorizontal(); const float BUTTON_WIDTH = 50.0f; if (GUILayout.Button("Copy", GUILayout.Width(BUTTON_WIDTH))) { string dstPath = Misc.CopyFileToStreamingAssets(fullPath); ChangeSceneCacheFileInInspector(t, dstPath); } GUILayout.Label("Scene Cache file to StreamingAssets"); EditorGUILayout.LabelField("(RECOMMENDED)", EditorStyles.boldLabel); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(15); } EditorGUILayout.Space(); //Time Unit changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Time Unit", guiFunc: () => (SceneCachePlayer.TimeUnit)EditorGUILayout.Popup("Time Unit", (int)t.GetTimeUnit(), TIME_UNIT_ENUMS), updateFunc: (SceneCachePlayer.TimeUnit timeUnit) => { t.SetTimeUnit(timeUnit); t.ResetTimeAnimation(); } ); SceneCachePlayer.TimeUnit selectedTimeUnit = t.GetTimeUnit(); if (selectedTimeUnit == SceneCachePlayer.TimeUnit.Seconds) { changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Time", guiFunc: () => (EditorGUILayout.FloatField("Time", t.GetTime())), updateFunc: (float time) => { t.SetTime(time); }); changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Interpolation", guiFunc: () => (EditorGUILayout.Toggle("Interpolation", t.GetInterpolation())), updateFunc: (bool toggle) => { t.SetInterpolation(toggle); }); } else if (selectedTimeUnit == SceneCachePlayer.TimeUnit.Frames) { changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Base Frame", guiFunc: () => ((SceneCachePlayer.BaseFrame)EditorGUILayout.Popup("Base Frame", (int)t.GetBaseFrame(), BASE_FRAME_ENUMS)), updateFunc: (SceneCachePlayer.BaseFrame baseFrame) => { t.SetBaseFrame(baseFrame); t.ResetTimeAnimation(); }); changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Frame", guiFunc: () => (EditorGUILayout.IntField("Frame", t.GetFrame())), updateFunc: (int frame) => { t.SetFrame(frame); }); } // preload { changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Preload", guiFunc: () => (EditorGUILayout.IntSlider("Preload Length", t.GetPreloadLength(), 0, t.frameCount)), updateFunc: (int preloadLength) => { t.SetPreloadLength(preloadLength); }); } EditorGUILayout.Space(); } return(changed); }
//---------------------------------------------------------------------------------------------------------------------- private static void ChangeSceneCacheFileInInspector(SceneCachePlayer cachePlayer, string sceneCacheFilePath) { SceneCachePlayerEditorUtility.ChangeSceneCacheFile(cachePlayer, sceneCacheFilePath); }
//---------------------------------------------------------------------------------------------------------------------- private static bool DrawSceneCacheImportSettings(SceneCachePlayer t) { bool changed = false; MeshSyncPlayerConfig playerConfig = t.GetConfigV(); t.foldImportSettings = EditorGUILayout.Foldout(t.foldImportSettings, "Import Settings", true, GetBoldFoldoutStyle()); if (t.foldImportSettings) { IHasModelImporterSettings importer = AssetImporter.GetAtPath(t.GetSceneCacheFilePath()) as IHasModelImporterSettings; ModelImporterSettings importerSettings = playerConfig.GetModelImporterSettings(); if (null == importer) { MeshSyncInspectorUtility.DrawModelImporterSettingsGUI(t, importerSettings); } else { bool isOverride = t.IsModelImporterSettingsOverridden(); EditorGUILayout.BeginHorizontal(); EditorGUIDrawerUtility.DrawUndoableGUI(t, "Override", guiFunc: () => GUILayout.Toggle(isOverride, "", GUILayout.MaxWidth(15.0f)), updateFunc: (bool overrideValue) => { t.OverrideModelImporterSettings(overrideValue); }); using (new EditorGUI.DisabledScope(!isOverride)) { EditorGUIDrawerUtility.DrawUndoableGUI(t, "Create Materials", guiFunc: () => (bool)EditorGUILayout.Toggle("Create Materials", importerSettings.CreateMaterials), updateFunc: (bool createMat) => { importerSettings.CreateMaterials = createMat; }); } EditorGUILayout.EndHorizontal(); using (new EditorGUI.DisabledScope(!isOverride)) { ++EditorGUI.indentLevel; MeshSyncInspectorUtility.DrawModelImporterMaterialSearchMode(t, importerSettings); --EditorGUI.indentLevel; } } changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Animation Interpolation", guiFunc: () => EditorGUILayout.Popup(new GUIContent("Animation Interpolation"), playerConfig.AnimationInterpolation, MeshSyncEditorConstants.ANIMATION_INTERPOLATION_ENUMS), updateFunc: (int val) => { playerConfig.AnimationInterpolation = val; } ); changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Keyframe Reduction", guiFunc: () => EditorGUILayout.Toggle("Keyframe Reduction", playerConfig.KeyframeReduction), updateFunc: (bool toggle) => { playerConfig.KeyframeReduction = toggle; } ); if (playerConfig.KeyframeReduction) { EditorGUI.indentLevel++; changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Threshold", guiFunc: () => EditorGUILayout.FloatField("Threshold", playerConfig.ReductionThreshold), updateFunc: (float val) => { playerConfig.ReductionThreshold = val; } ); changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Erase Flat Curves", guiFunc: () => EditorGUILayout.Toggle("Erase Flat Curves", playerConfig.ReductionEraseFlatCurves), updateFunc: (bool toggle) => { playerConfig.ReductionEraseFlatCurves = toggle; } ); EditorGUI.indentLevel--; } changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Z-Up Correction", guiFunc: () => EditorGUILayout.Popup(new GUIContent("Z-Up Correction"), playerConfig.ZUpCorrection, MeshSyncEditorConstants.Z_UP_CORRECTION_ENUMS), updateFunc: (int val) => { playerConfig.ZUpCorrection = val; } ); EditorGUILayout.Space(); } return(changed); }
void DrawCacheSettings(SceneCachePlayer t, SerializedObject so) { var styleFold = EditorStyles.foldout; styleFold.fontStyle = FontStyle.Bold; t.foldCacheSettings = EditorGUILayout.Foldout(t.foldCacheSettings, "Player", true, styleFold); if (t.foldCacheSettings) { // cache file path EditorGUILayout.PropertyField(so.FindProperty("m_cacheFilePath")); var dataPath = t.cacheFilePath; if (dataPath.root != DataPath.Root.StreamingAssets) { GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Copy to StreamingAssets", GUILayout.Width(160.0f))) { var srcPath = dataPath.fullPath; var dstPath = Misc.CopyFileToStreamingAssets(dataPath.fullPath); Undo.RecordObject(t, "SceneCachePlayer"); t.OpenCache(dstPath); Repaint(); } if (GUILayout.Button("Move to StreamingAssets", GUILayout.Width(160.0f))) { t.CloseCache(); var srcPath = dataPath.fullPath; var dstPath = Misc.MoveFileToStreamingAssets(dataPath.fullPath); Undo.RecordObject(t, "SceneCachePlayer"); t.OpenCache(dstPath); Repaint(); } GUILayout.EndHorizontal(); } EditorGUILayout.Space(); // time / frame System.Action resetTimeAnimation = () => { so.ApplyModifiedProperties(); t.ResetTimeAnimation(); }; EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(so.FindProperty("m_timeUnit")); if (EditorGUI.EndChangeCheck()) { resetTimeAnimation(); } if (t.timeUnit == SceneCachePlayer.TimeUnit.Seconds) { EditorGUILayout.PropertyField(so.FindProperty("m_time")); EditorGUILayout.PropertyField(so.FindProperty("m_interpolation")); } else if (t.timeUnit == SceneCachePlayer.TimeUnit.Frames) { EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(so.FindProperty("m_baseFrame")); if (EditorGUI.EndChangeCheck()) { resetTimeAnimation(); } EditorGUILayout.PropertyField(so.FindProperty("m_frame")); } // preload { var preloadLength = so.FindProperty("m_preloadLength"); preloadLength.intValue = EditorGUILayout.IntSlider("Preload Length", preloadLength.intValue, 0, t.frameCount); } EditorGUILayout.Space(); } }
private IEnumerator IterateAllSceneCacheFrames(PlayableDirector director, TimelineClip clip, SceneCachePlayer scPlayer, Action <int> afterUpdateFunc) { ISceneCacheInfo scInfo = scPlayer.ExtractSceneCacheInfo(forceOpen: true); Assert.IsNotNull(scInfo); double timePerFrame = 1.0f / scInfo.GetSampleRate(); //Use (numFrames-1) because when it becomes invisible when Timeline reaches the last frame for (int i = 0; i < scInfo.GetNumFrames() - 1; ++i) { double elapsedTime = i * timePerFrame; if (elapsedTime >= clip.duration) { yield break; } double directorTime = clip.start + i * timePerFrame; SetDirectorTime(director, directorTime); //this will trigger change in the time of the SceneCachePlayable yield return(null); afterUpdateFunc(i); } }