//---------------------------------------------------------------------------------------------------------------------- /// Import images in the path to create StreamingImageSequence assets with those images /// <param name="path"> Can be a directory path or a file path</param> /// <param name="targetAsset"> The target asset where the images are assigned to</param> /// <param name="askToCopy"> Ask to copy if path is not under StreamingAssets. Default to true</param> internal static void ImportImages(string path, StreamingImageSequencePlayableAsset targetAsset, bool askToCopy = true) { Assert.IsFalse(string.IsNullOrEmpty(path)); FindFolderAndImages(path, out string folder, out List <string> relFilePaths); if (relFilePaths.Count <= 0) { EditorUtility.DisplayDialog(StreamingImageSequenceConstants.DIALOG_HEADER, @"No files in folder:: " + folder, "OK"); return; } //Estimate the asset name. Use the filename without numbers at the end string assetName = EstimateAssetName(relFilePaths[0]); // set dest folder string streamingAssetsPath = AssetEditorUtility.NormalizeAssetPath(Application.streamingAssetsPath); //Set importer param ImageFileImporterParam importerParam = new ImageFileImporterParam { strSrcFolder = folder, RelativeFilePaths = relFilePaths, CopyToStreamingAssets = true, TargetAsset = targetAsset }; //Import immediately if the assets are already under StreamingAssets if (folder.StartsWith(streamingAssetsPath) || !askToCopy) { importerParam.strDstFolder = importerParam.strSrcFolder; importerParam.CopyToStreamingAssets = false; ImageSequenceImporter.Import(importerParam); } else { importerParam.strDstFolder = Path.Combine(streamingAssetsPath, assetName).Replace("\\", "/"); ImageSequenceImportWindow.Show(importerParam); } }
//---------------------------------------------------------------------------------------------------------------------- public override void OnInspectorGUI() { //View resolution Vector2 res = ViewEditorUtility.GetMainGameViewSize(); EditorGUILayout.LabelField("Resolution (Modify GameView size to change)"); ++EditorGUI.indentLevel; EditorGUILayout.LabelField("Width", res.x.ToString(CultureInfo.InvariantCulture)); EditorGUILayout.LabelField("Height", res.y.ToString(CultureInfo.InvariantCulture)); --EditorGUI.indentLevel; EditorGUILayout.Space(15f); //Check if the asset is actually inspected if (null != TimelineEditor.selectedClip && TimelineEditor.selectedClip.asset != m_asset) { return; } ValidateAssetFolder(); string prevFolder = m_asset.GetFolder(); string newFolder = InspectorUtility.ShowFolderSelectorGUI("Cache Output Folder", "Select Folder", prevFolder, AssetEditorUtility.NormalizeAssetPath ); if (newFolder != prevFolder) { m_asset.SetFolder(AssetEditorUtility.NormalizeAssetPath(newFolder)); GUIUtility.ExitGUI(); } TimelineClipSISData timelineClipSISData = m_asset.GetBoundTimelineClipSISData(); if (null == timelineClipSISData) { return; } GUILayout.Space(15); //Capture Selected Frames using (new EditorGUILayout.VerticalScope(GUI.skin.box)) { ShowCaptureSelectedFramesGUI(TimelineEditor.selectedClip, timelineClipSISData); ShowLockFramesGUI(TimelineEditor.selectedClip, timelineClipSISData); } ShortcutBinding updateRenderCacheShortcut = ShortcutManager.instance.GetShortcutBinding(SISEditorConstants.SHORTCUT_UPDATE_RENDER_CACHE); GUILayout.Space(15); if (GUILayout.Button($"Update Render Cache ({updateRenderCacheShortcut})")) { PlayableDirector director = TimelineEditor.inspectedDirector; if (null == director) { EditorUtility.DisplayDialog("Streaming Image Sequence", "PlayableAsset is not loaded in scene. Please load the correct scene before doing this operation.", "Ok"); return; } //Loop time EditorCoroutineUtility.StartCoroutine(UpdateRenderCacheCoroutine(director, m_asset), this); } }
//--------------------------------------------------------------------------------------------------------------------- /// <summary> /// Import a timeline file exported from DCC tools into the scene in the Timeline object /// </summary> /// <param name="jsTimelinePath">The path of the file</param> /// <param name="destFolder">The dest folder of the imported files</param> public static void ImportTimeline(string jsTimelinePath, string destFolder = "") { // prepare asset name, paths, etc string assetName = Path.GetFileNameWithoutExtension(jsTimelinePath); string timelineFolder = Path.GetDirectoryName(jsTimelinePath); if (string.IsNullOrEmpty(timelineFolder)) { Debug.LogError("Can't get directory name for: " + jsTimelinePath); return; } timelineFolder = Path.Combine(timelineFolder, destFolder, assetName).Replace("\\", "/"); //Check if we are exporting from external asset if (!timelineFolder.StartsWith("Assets/")) { timelineFolder = Path.Combine("Assets", destFolder, assetName); } Directory.CreateDirectory(timelineFolder); string strJson = File.ReadAllText(jsTimelinePath); TimelineParam container = JsonUtility.FromJson <TimelineParam>(strJson); string assetFolder = container.assetFolder; if (string.IsNullOrEmpty(assetFolder)) { assetFolder = Path.GetDirectoryName(jsTimelinePath); } //delete existing objects in the scene that is pointing to the Director string timelinePath = Path.Combine(timelineFolder, assetName + "_Timeline.playable").Replace("\\", "/"); PlayableDirector director = RemovePlayableFromDirectorsInScene(timelinePath); if (null == director) { GameObject directorGo = new GameObject(assetName); director = directorGo.AddComponent <PlayableDirector>(); } //Create timeline asset TimelineAsset asset = ScriptableObject.CreateInstance <TimelineAsset>(); AssetEditorUtility.OverwriteAsset(asset, timelinePath); director.playableAsset = asset; string strHome = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); int numTracks = container.Tracks.Length; for (int index = numTracks - 1; index >= 0; index--) { var track = container.Tracks[index]; string strFootagePath = track.Footage; // remove '~' if necessary if (strFootagePath.StartsWith("~")) { strFootagePath = strHome + strFootagePath.Substring(1); } if (!Path.IsPathRooted(strFootagePath)) { strFootagePath = Path.Combine(assetFolder, strFootagePath); } string strFootageName = Path.GetFileNameWithoutExtension(strFootagePath); string strJsonFootage = File.ReadAllText(strFootagePath); StreamingImageSequencePlayableAssetParam trackMovieContainer = JsonUtility.FromJson <StreamingImageSequencePlayableAssetParam>(strJsonFootage); int numImages = trackMovieContainer.Pictures.Count; if (numImages > 0) { List <string> originalImagePaths = new List <string>(trackMovieContainer.Pictures); for (int xx = 0; xx < numImages; ++xx) { string fileName = trackMovieContainer.Pictures[xx]; // replace '~' with the path to home (for Linux environment if (fileName.StartsWith("~")) { fileName = strHome + fileName.Substring(1); } trackMovieContainer.Pictures[xx] = Path.GetFileName(fileName); } string destFootageFolder = Application.streamingAssetsPath; destFootageFolder = Path.Combine(destFootageFolder, strFootageName).Replace("\\", "/"); Directory.CreateDirectory(destFootageFolder); //make sure the directory exists trackMovieContainer.Folder = AssetEditorUtility.NormalizeAssetPath(destFootageFolder); for (int i = 0; i < numImages; ++i) { string destFilePath = Path.Combine(destFootageFolder, trackMovieContainer.Pictures[i]); if (File.Exists(destFilePath)) { File.Delete(destFilePath); } string srcFilePath = Path.GetFullPath(Path.Combine(assetFolder, originalImagePaths[i])).Replace("\\", "/"); FileUtil.CopyFileOrDirectory(srcFilePath, destFilePath); } } StreamingImageSequencePlayableAsset sisAsset = ScriptableObject.CreateInstance <StreamingImageSequencePlayableAsset>(); sisAsset.InitFolder(trackMovieContainer); string playableAssetPath = Path.Combine(timelineFolder, strFootageName + "_StreamingImageSequence.playable"); AssetEditorUtility.OverwriteAsset(sisAsset, playableAssetPath); StreamingImageSequenceTrack movieTrack = asset.CreateTrack <StreamingImageSequenceTrack>(null, strFootageName); TimelineClip clip = movieTrack.CreateDefaultClip(); clip.asset = sisAsset; clip.start = track.Start; clip.duration = track.Duration; clip.CreateCurves("Curves: " + clip.displayName); TimelineClipSISData sisData = new TimelineClipSISData(clip); sisAsset.InitTimelineClipCurve(clip); sisAsset.BindTimelineClipSISData(sisData); if (Object.FindObjectOfType(typeof(UnityEngine.EventSystems.EventSystem)) == null) { var es = new GameObject(); es.AddComponent <UnityEngine.EventSystems.EventSystem>(); es.AddComponent <UnityEngine.EventSystems.StandaloneInputModule>(); es.name = "EventSystem"; } GameObject canvasObj = null; Canvas canvas = Object.FindObjectOfType(typeof(Canvas)) as Canvas; if (canvas != null) { canvasObj = canvas.gameObject; } else { canvasObj = UIUtility.CreateCanvas().gameObject; } Transform directorT = director.gameObject.transform; directorT.SetParent(canvasObj.transform); directorT.localPosition = new Vector3(0.0f, 0.0f, 0.0f); GameObject imageGo = null; Transform imageT = directorT.Find(strFootageName); if (null == imageT) { imageGo = new GameObject(strFootageName); imageT = imageGo.transform; } else { imageGo = imageT.gameObject; } Image image = imageGo.GetOrAddComponent <Image>(); StreamingImageSequenceRenderer renderer = imageGo.GetOrAddComponent <StreamingImageSequenceRenderer>(); RectTransform rectTransform = imageGo.GetComponent <RectTransform>(); rectTransform.SetParent(directorT); rectTransform.localPosition = new Vector3(0.0f, 0.0f, 0.0f); rectTransform.sizeDelta = new Vector2(trackMovieContainer.Resolution.Width, trackMovieContainer.Resolution.Height); director.SetGenericBinding(movieTrack, renderer); EditorUtility.SetDirty(director); } //cause crash if this is called inside of OnImportAsset() UnityEditor.EditorApplication.delayCall += () => { AssetDatabase.Refresh(); if (null != director) { Selection.activeGameObject = director.gameObject; } }; }