public string ExportToFile(bool useCurrentFileName) { string path; if (useCurrentFileName) { path = m_CurrentAsset.exportSettings.fileName; } else { string title = "Save Texture, use # for frame numbering."; string defaultFileName, extension, message; switch (m_CurrentAsset.exportSettings.exportMode) { case ImageSequence.ExportMode.EXR: defaultFileName = "Frame_#.exr"; extension = "exr"; message = "Save as EXR Texture"; break; case ImageSequence.ExportMode.Targa: defaultFileName = "Frame_#.tga"; extension = "tga"; message = "Save as TGA Texture"; break; case ImageSequence.ExportMode.PNG: defaultFileName = "Frame_#.png"; extension = "png"; message = "Save as PNG Texture"; break; default: return(null); } path = EditorUtility.SaveFilePanelInProject(title, defaultFileName, extension, message); if (path == null || path == "") { return(""); } } int frameCount = m_processorStack.outputSequence.length; if (frameCount > 1 && !Path.GetFileNameWithoutExtension(path).Contains("#")) { if (!EditorUtility.DisplayDialog("VFX Toolbox", "You are currently exporting a sequence of images with no # in filename for numbering, do you want to add _# as a suffix of the filename?", "Add Postfix", "Cancel Export")) { return(""); } string newpath = Path.GetDirectoryName(path) + "\\" + Path.GetFileNameWithoutExtension(path) + "_#" + Path.GetExtension(path); path = newpath; } ImageSequence.ExportSettings settings = m_CurrentAsset.exportSettings; bool bCanceled = false; try { int i = 1; foreach (ProcessingFrame frame in m_processorStack.outputSequence.frames) { if (VFXToolboxGUIUtility.DisplayProgressBar("Image Sequencer", "Exporting Frame #" + i + "/" + frameCount, (float)i / frameCount, 0, true)) { bCanceled = true; break; } Color[] inputs; if (frame.texture is Texture2D) { RenderTexture temp = RenderTexture.GetTemporary(frame.texture.width, frame.texture.height, 0, RenderTextureFormat.ARGBHalf); Graphics.Blit((Texture2D)frame.texture, temp); inputs = ReadBack(temp); } else // frame.texture is RenderTexture { frame.Process(); inputs = ReadBack((RenderTexture)frame.texture); } string fileName = GetNumberedFileName(path, i, frameCount); switch (m_CurrentAsset.exportSettings.exportMode) { case ImageSequence.ExportMode.EXR: MiniEXR.MiniEXR.MiniEXRWrite(fileName, (ushort)frame.texture.width, (ushort)frame.texture.height, settings.exportAlpha, inputs, true); break; case ImageSequence.ExportMode.Targa: MiniTGA.MiniTGA.MiniTGAWrite(fileName, (ushort)frame.texture.width, (ushort)frame.texture.height, settings.exportAlpha, inputs); break; case ImageSequence.ExportMode.PNG: byte[] bytes; if (m_processorStack.outputSequence.processor != null) { RenderTexture backup = RenderTexture.active; Texture2D texture = new Texture2D(frame.texture.width, frame.texture.height, TextureFormat.RGBA32, settings.generateMipMaps, !settings.sRGB); RenderTexture.active = (RenderTexture)frame.texture; RenderTexture ldrOutput = RenderTexture.GetTemporary(frame.texture.width, frame.texture.height, 0, RenderTextureFormat.ARGB32, settings.sRGB? RenderTextureReadWrite.sRGB: RenderTextureReadWrite.Linear); GL.sRGBWrite = (QualitySettings.activeColorSpace == ColorSpace.Linear); Graphics.Blit(frame.texture, ldrOutput); RenderTexture.active = ldrOutput; texture.ReadPixels(new Rect(0, 0, frame.texture.width, frame.texture.height), 0, 0); bytes = texture.EncodeToPNG(); RenderTexture.active = backup; } else { bytes = (frame.texture as Texture2D).EncodeToPNG(); } File.WriteAllBytes(fileName, bytes); break; default: return(null); } AssetDatabase.Refresh(); TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(fileName); importer.wrapMode = m_CurrentAsset.exportSettings.wrapMode; importer.filterMode = m_CurrentAsset.exportSettings.filterMode; switch (m_CurrentAsset.exportSettings.dataContents) { case ImageSequence.DataContents.Color: importer.textureType = TextureImporterType.Default; break; case ImageSequence.DataContents.NormalMap: importer.textureType = TextureImporterType.NormalMap; importer.convertToNormalmap = false; break; case ImageSequence.DataContents.NormalMapFromGrayscale: importer.textureType = TextureImporterType.NormalMap; importer.convertToNormalmap = true; break; case ImageSequence.DataContents.Sprite: importer.textureType = TextureImporterType.Sprite; importer.spriteImportMode = SpriteImportMode.Multiple; importer.spritesheet = GetSpriteMetaData(frame, m_processorStack.outputSequence.numU, m_processorStack.outputSequence.numV); break; } importer.mipmapEnabled = m_CurrentAsset.exportSettings.generateMipMaps; switch (m_CurrentAsset.exportSettings.exportMode) { case ImageSequence.ExportMode.Targa: importer.sRGBTexture = m_CurrentAsset.exportSettings.sRGB; importer.alphaSource = m_CurrentAsset.exportSettings.exportAlpha ? TextureImporterAlphaSource.FromInput : TextureImporterAlphaSource.None; importer.textureCompression = m_CurrentAsset.exportSettings.compress ? TextureImporterCompression.Compressed : TextureImporterCompression.Uncompressed; break; case ImageSequence.ExportMode.EXR: importer.sRGBTexture = false; importer.alphaSource = (m_CurrentAsset.exportSettings.exportAlpha && !m_CurrentAsset.exportSettings.compress) ? TextureImporterAlphaSource.FromInput : TextureImporterAlphaSource.None; importer.textureCompression = m_CurrentAsset.exportSettings.compress ? TextureImporterCompression.CompressedHQ : TextureImporterCompression.Uncompressed; break; case ImageSequence.ExportMode.PNG: importer.sRGBTexture = m_CurrentAsset.exportSettings.sRGB; importer.alphaSource = m_CurrentAsset.exportSettings.exportAlpha ? TextureImporterAlphaSource.FromInput : TextureImporterAlphaSource.None; importer.textureCompression = m_CurrentAsset.exportSettings.compress ? TextureImporterCompression.Compressed : TextureImporterCompression.Uncompressed; break; } AssetDatabase.ImportAsset(fileName, ImportAssetOptions.ForceUpdate); // Separate Alpha if (m_CurrentAsset.exportSettings.exportSeparateAlpha) { string alphaFilename = fileName.Substring(0, fileName.Length - 4) + "_alpha.tga"; // build alpha for (int k = 0; k < inputs.Length; k++) { float a = inputs[k].a; inputs[k] = new Color(a, a, a, a); } MiniTGA.MiniTGA.MiniTGAWrite(alphaFilename, (ushort)frame.texture.width, (ushort)frame.texture.height, false, inputs); AssetDatabase.Refresh(); TextureImporter alphaImporter = (TextureImporter)TextureImporter.GetAtPath(alphaFilename); if (m_CurrentAsset.exportSettings.dataContents == ImageSequence.DataContents.Sprite) { alphaImporter.textureType = TextureImporterType.Sprite; alphaImporter.spriteImportMode = SpriteImportMode.Multiple; alphaImporter.spritesheet = GetSpriteMetaData(frame, m_processorStack.outputSequence.numU, m_processorStack.outputSequence.numV); alphaImporter.alphaSource = TextureImporterAlphaSource.None; } else { alphaImporter.textureType = TextureImporterType.SingleChannel; alphaImporter.alphaSource = TextureImporterAlphaSource.FromGrayScale; } alphaImporter.wrapMode = m_CurrentAsset.exportSettings.wrapMode; alphaImporter.filterMode = m_CurrentAsset.exportSettings.filterMode; alphaImporter.sRGBTexture = false; alphaImporter.mipmapEnabled = m_CurrentAsset.exportSettings.generateMipMaps; alphaImporter.textureCompression = m_CurrentAsset.exportSettings.compress ? TextureImporterCompression.Compressed : TextureImporterCompression.Uncompressed; AssetDatabase.ImportAsset(alphaFilename, ImportAssetOptions.ForceUpdate); } i++; } } catch (System.Exception e) { VFXToolboxGUIUtility.ClearProgressBar(); Debug.LogError(e.Message); } VFXToolboxGUIUtility.ClearProgressBar(); if (bCanceled) { return(""); } else { return(path); } }
private void DrawExportPanelContent() { int length = m_processorStack.outputSequence.length; if (length > 0) { m_CurrentAssetSerializedObject.Update(); EditorGUI.BeginChangeCheck(); ImageSequence.ExportSettings prevState = m_CurrentAsset.exportSettings; using (new VFXToolboxGUIUtility.HeaderSectionScope("File Export Options")) { ImageSequence.ExportMode prevMode = m_CurrentAsset.exportSettings.exportMode; m_CurrentAsset.exportSettings.exportMode = (ImageSequence.ExportMode)EditorGUILayout.Popup(VFXToolboxGUIUtility.Get("Export Format"), (int)m_CurrentAsset.exportSettings.exportMode, GetExportModeFriendlyNames()); if (prevMode != m_CurrentAsset.exportSettings.exportMode) { m_CurrentAsset.exportSettings.fileName = ""; } switch (m_CurrentAsset.exportSettings.exportMode) { case ImageSequence.ExportMode.EXR: m_CurrentAsset.exportSettings.highDynamicRange = true; m_CurrentAsset.exportSettings.sRGB = false; break; case ImageSequence.ExportMode.PNG: case ImageSequence.ExportMode.Targa: m_CurrentAsset.exportSettings.highDynamicRange = false; break; } EditorGUI.BeginDisabledGroup(true); EditorGUILayout.TextField(VFXToolboxGUIUtility.Get("File Name|File name or pattern of the export sequence, using # characters will add frame number to the file name, use multiple ### to ensure leading zeroes."), m_CurrentAsset.exportSettings.fileName); EditorGUI.EndDisabledGroup(); Rect r = GUILayoutUtility.GetLastRect(); r.width += EditorGUIUtility.fieldWidth; if (Event.current.rawType == EventType.MouseDown && r.Contains(Event.current.mousePosition)) { PingOutputTexture(m_CurrentAsset.exportSettings.fileName); } if (!m_CurrentAsset.exportSettings.highDynamicRange) { m_CurrentAsset.exportSettings.sRGB = EditorGUILayout.Toggle(VFXToolboxGUIUtility.Get("sRGB (Color Data)|Whether the texture contains color (or not), HDR Data is always non sRGB."), m_CurrentAsset.exportSettings.sRGB); } EditorGUI.BeginDisabledGroup(m_CurrentAsset.exportSettings.compress && m_CurrentAsset.exportSettings.highDynamicRange); m_CurrentAsset.exportSettings.exportAlpha = EditorGUILayout.Toggle(VFXToolboxGUIUtility.Get("Export Alpha|Whether to export the alpha channel"), m_CurrentAsset.exportSettings.exportAlpha); EditorGUI.EndDisabledGroup(); m_CurrentAsset.exportSettings.exportSeparateAlpha = EditorGUILayout.Toggle(VFXToolboxGUIUtility.Get("Separate Alpha|Export the alpha channel as a separate TGA Grayscale file with a \"_alpha\" suffix."), m_CurrentAsset.exportSettings.exportSeparateAlpha); } using (new VFXToolboxGUIUtility.HeaderSectionScope("Texture Import Options")) { m_CurrentAsset.exportSettings.dataContents = (ImageSequence.DataContents)EditorGUILayout.EnumPopup(VFXToolboxGUIUtility.Get("Import as|Sets the importer mode"), m_CurrentAsset.exportSettings.dataContents); if (m_CurrentAsset.exportSettings.dataContents == ImageSequence.DataContents.Sprite) { FrameProcessor p = m_processorStack.processors[m_processorStack.processors.Count - 1]; if (((float)p.OutputWidth % p.NumU) != 0 || ((float)p.OutputHeight % p.NumV) != 0) { EditorGUILayout.HelpBox("Warning : texture size is not a multiplier of rows (" + p.NumU + ") and columns (" + p.NumV + ") count, this will lead to incorrect rendering of the sprite animation", MessageType.Warning); } } switch (m_CurrentAsset.exportSettings.dataContents) { case ImageSequence.DataContents.NormalMapFromGrayscale: case ImageSequence.DataContents.NormalMap: m_CurrentAsset.exportSettings.sRGB = false; m_CurrentAsset.exportSettings.exportAlpha = false; break; default: break; } if (!m_CurrentAsset.exportSettings.highDynamicRange) { m_CurrentAsset.exportSettings.sRGB = EditorGUILayout.Toggle(VFXToolboxGUIUtility.Get("sRGB (Color Data)|Whether the texture contains color (or not), HDR Data is always non sRGB."), m_CurrentAsset.exportSettings.sRGB); } m_CurrentAsset.exportSettings.compress = EditorGUILayout.Toggle(VFXToolboxGUIUtility.Get("Compress|Whether to apply texture compression (HDR Compressed Data does not support alpha channel)"), m_CurrentAsset.exportSettings.compress); m_CurrentAsset.exportSettings.generateMipMaps = EditorGUILayout.Toggle(VFXToolboxGUIUtility.Get("Generate MipMaps|Whether generate mipmaps."), m_CurrentAsset.exportSettings.generateMipMaps); m_CurrentAsset.exportSettings.wrapMode = (TextureWrapMode)EditorGUILayout.EnumPopup(VFXToolboxGUIUtility.Get("Wrap Mode|Texture Wrap mode"), m_CurrentAsset.exportSettings.wrapMode); m_CurrentAsset.exportSettings.filterMode = (FilterMode)EditorGUILayout.EnumPopup(VFXToolboxGUIUtility.Get("Filter Mode|Texture Filter mode"), m_CurrentAsset.exportSettings.filterMode); if (m_CurrentAsset.exportSettings.compress && m_CurrentAsset.exportSettings.highDynamicRange) { m_CurrentAsset.exportSettings.exportAlpha = false; } } if (GUILayout.Button("Export as New...", GUILayout.Height(24))) { string fileName = ""; fileName = ExportToFile(false); if (fileName != "") { m_CurrentAsset.exportSettings.fileName = fileName; m_CurrentAsset.exportSettings.frameCount = (ushort)m_processorStack.outputSequence.frames.Count; } } // Export Again if (m_CurrentAsset.exportSettings.fileName != null && ((m_CurrentAsset.exportSettings.fileName.EndsWith(".tga") && m_CurrentAsset.exportSettings.exportMode == ImageSequence.ExportMode.Targa) || (m_CurrentAsset.exportSettings.fileName.EndsWith(".exr") && m_CurrentAsset.exportSettings.exportMode == ImageSequence.ExportMode.EXR) || (m_CurrentAsset.exportSettings.fileName.EndsWith(".png") && m_CurrentAsset.exportSettings.exportMode == ImageSequence.ExportMode.PNG) )) { if (GUILayout.Button("Update Exported Assets", GUILayout.Height(24))) { UpdateExportedAssets(); } } if (m_CurrentAsset.exportSettings.dataContents == ImageSequence.DataContents.NormalMap) { EditorGUILayout.HelpBox("The selected import mode assumes that the frame data is a normal map. To generate a normal map from grayscale, use Normal Map From Grayscale instead.", MessageType.Info); } if (EditorGUI.EndChangeCheck()) { ImageSequence.ExportSettings curState = m_CurrentAsset.exportSettings; m_CurrentAsset.exportSettings = prevState; Undo.RecordObject(m_CurrentAsset, "Update Export Settings"); m_CurrentAsset.exportSettings = curState; m_CurrentAssetSerializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(m_CurrentAsset); AssetDatabase.Refresh(); } } else { EditorGUILayout.HelpBox("You do not have any frames to export.", MessageType.Warning); } }
public string ExportToFile(bool useCurrentFileName) { bool bIsInsideProject = true; string path; if (useCurrentFileName) { path = m_CurrentAsset.exportSettings.fileName; } else { string title = "Save Texture, use # for frame numbering."; string defaultFileName, extension; int count = m_processorStack.outputSequence.frames.Count; int numU = m_processorStack.outputSequence.numU; int numV = m_processorStack.outputSequence.numV; string defaultDir = Path.GetDirectoryName(AssetDatabase.GetAssetPath(m_CurrentAsset)); defaultFileName = m_CurrentAsset.name; if (count > 1) { defaultFileName += "_#"; } if (numU * numV != 1) { defaultFileName += "_" + numU + "x" + numV; } switch (m_CurrentAsset.exportSettings.exportMode) { case ImageSequence.ExportMode.EXR: defaultFileName += ".exr"; extension = "exr"; break; case ImageSequence.ExportMode.Targa: defaultFileName += ".tga"; extension = "tga"; break; case ImageSequence.ExportMode.PNG: defaultFileName += ".png"; extension = "png"; break; default: return(null); } path = EditorUtility.SaveFilePanel(title, defaultDir, defaultFileName, extension); if (path == null || path == "") { return(""); } if (path.Contains(Application.dataPath)) { path = path.Replace(Application.dataPath, "Assets"); } } if (!path.StartsWith("Assets/")) { bIsInsideProject = false; Debug.LogWarning("VFX Toolbox Warning : Saving a texture outside the project's scope. Import Settings will not be applied"); } int frameCount = m_processorStack.outputSequence.length; if (frameCount > 1 && !Path.GetFileNameWithoutExtension(path).Contains("#")) { if (!EditorUtility.DisplayDialog("VFX Toolbox", "You are currently exporting a sequence of images with no # in filename for numbering, do you want to add _# as a suffix of the filename?", "Add Postfix", "Cancel Export")) { return(""); } string newpath = Path.GetDirectoryName(path) + "\\" + Path.GetFileNameWithoutExtension(path) + "_#" + Path.GetExtension(path); path = newpath; } ImageSequence.ExportSettings settings = m_CurrentAsset.exportSettings; bool bCanceled = false; try { int i = 1; foreach (ProcessingFrame frame in m_processorStack.outputSequence.frames) { if (VFXToolboxGUIUtility.DisplayProgressBar("Image Sequencer", "Exporting Frame #" + i + "/" + frameCount, (float)i / frameCount, 0, true)) { bCanceled = true; break; } // Export frame : first, dump data into color array Color[] inputs; if (frame.texture is Texture2D) // if using input frame { RenderTexture temp = RenderTexture.GetTemporary(frame.texture.width, frame.texture.height, 0, RenderTextureFormat.ARGBHalf); Graphics.Blit((Texture2D)frame.texture, temp); inputs = ReadBack(temp); } else // frame.texture is RenderTexture { frame.Process(); inputs = ReadBack((RenderTexture)frame.texture); } string fileName = GetNumberedFileName(path, i, frameCount); // Dump data byte[] bytes; switch (m_CurrentAsset.exportSettings.exportMode) { case ImageSequence.ExportMode.EXR: #if UNITY_5_6_OR_NEWER // New Exporter { Texture2D texture = new Texture2D(frame.texture.width, frame.texture.height, TextureFormat.RGBAHalf, settings.generateMipMaps, !settings.sRGB); texture.SetPixels(inputs); texture.Apply(true); bytes = texture.EncodeToEXR(); } #else // Old Exporter { bytes = MiniEXR.MiniEXR.MiniEXRWrite((ushort)frame.texture.width, (ushort)frame.texture.height, settings.exportAlpha, inputs, true); } #endif break; case ImageSequence.ExportMode.Targa: { bytes = MiniTGA.MiniTGA.MiniTGAWrite((ushort)frame.texture.width, (ushort)frame.texture.height, settings.exportAlpha, inputs); } break; case ImageSequence.ExportMode.PNG: { Texture2D texture = new Texture2D(frame.texture.width, frame.texture.height, TextureFormat.RGBA32, settings.generateMipMaps, !settings.sRGB); texture.SetPixels(inputs); texture.Apply(true); bytes = texture.EncodeToPNG(); } break; default: { bytes = new byte[0] { }; // Empty file that should not happen } break; } File.WriteAllBytes(fileName, bytes); AssetDatabase.Refresh(); // Process Import if saved inside project if (bIsInsideProject) { TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(fileName); importer.wrapMode = m_CurrentAsset.exportSettings.wrapMode; importer.filterMode = m_CurrentAsset.exportSettings.filterMode; switch (m_CurrentAsset.exportSettings.dataContents) { case ImageSequence.DataContents.Color: importer.textureType = TextureImporterType.Default; break; case ImageSequence.DataContents.NormalMap: importer.textureType = TextureImporterType.NormalMap; importer.convertToNormalmap = false; break; case ImageSequence.DataContents.NormalMapFromGrayscale: importer.textureType = TextureImporterType.NormalMap; importer.convertToNormalmap = true; break; case ImageSequence.DataContents.Sprite: importer.textureType = TextureImporterType.Sprite; importer.spriteImportMode = SpriteImportMode.Multiple; importer.spritesheet = GetSpriteMetaData(frame, m_processorStack.outputSequence.numU, m_processorStack.outputSequence.numV); break; } importer.mipmapEnabled = m_CurrentAsset.exportSettings.generateMipMaps; switch (m_CurrentAsset.exportSettings.exportMode) { case ImageSequence.ExportMode.Targa: importer.sRGBTexture = m_CurrentAsset.exportSettings.sRGB; importer.alphaSource = m_CurrentAsset.exportSettings.exportAlpha ? TextureImporterAlphaSource.FromInput : TextureImporterAlphaSource.None; importer.textureCompression = m_CurrentAsset.exportSettings.compress ? TextureImporterCompression.Compressed : TextureImporterCompression.Uncompressed; break; case ImageSequence.ExportMode.EXR: importer.sRGBTexture = false; importer.alphaSource = (m_CurrentAsset.exportSettings.exportAlpha && !m_CurrentAsset.exportSettings.compress) ? TextureImporterAlphaSource.FromInput : TextureImporterAlphaSource.None; importer.textureCompression = m_CurrentAsset.exportSettings.compress ? TextureImporterCompression.CompressedHQ : TextureImporterCompression.Uncompressed; break; case ImageSequence.ExportMode.PNG: importer.sRGBTexture = m_CurrentAsset.exportSettings.sRGB; importer.alphaSource = m_CurrentAsset.exportSettings.exportAlpha ? TextureImporterAlphaSource.FromInput : TextureImporterAlphaSource.None; importer.textureCompression = m_CurrentAsset.exportSettings.compress ? TextureImporterCompression.Compressed : TextureImporterCompression.Uncompressed; break; } AssetDatabase.ImportAsset(fileName, ImportAssetOptions.ForceUpdate); } // Separate Alpha if (m_CurrentAsset.exportSettings.exportSeparateAlpha) { string alphaFilename = fileName.Substring(0, fileName.Length - 4) + "_alpha.tga"; // build alpha for (int k = 0; k < inputs.Length; k++) { float a = inputs[k].a; inputs[k] = new Color(a, a, a, a); } MiniTGA.MiniTGA.MiniTGAWrite(alphaFilename, (ushort)frame.texture.width, (ushort)frame.texture.height, false, inputs); AssetDatabase.Refresh(); // Process Importer for alpha if inside project if (bIsInsideProject) { TextureImporter alphaImporter = (TextureImporter)TextureImporter.GetAtPath(alphaFilename); if (m_CurrentAsset.exportSettings.dataContents == ImageSequence.DataContents.Sprite) { alphaImporter.textureType = TextureImporterType.Sprite; alphaImporter.spriteImportMode = SpriteImportMode.Multiple; alphaImporter.spritesheet = GetSpriteMetaData(frame, m_processorStack.outputSequence.numU, m_processorStack.outputSequence.numV); alphaImporter.alphaSource = TextureImporterAlphaSource.None; } else { alphaImporter.textureType = TextureImporterType.SingleChannel; alphaImporter.alphaSource = TextureImporterAlphaSource.FromGrayScale; } alphaImporter.wrapMode = m_CurrentAsset.exportSettings.wrapMode; alphaImporter.filterMode = m_CurrentAsset.exportSettings.filterMode; alphaImporter.sRGBTexture = false; alphaImporter.mipmapEnabled = m_CurrentAsset.exportSettings.generateMipMaps; alphaImporter.textureCompression = m_CurrentAsset.exportSettings.compress ? TextureImporterCompression.Compressed : TextureImporterCompression.Uncompressed; AssetDatabase.ImportAsset(alphaFilename, ImportAssetOptions.ForceUpdate); } } i++; } } catch (System.Exception e) { VFXToolboxGUIUtility.ClearProgressBar(); Debug.LogError(e.Message); } VFXToolboxGUIUtility.ClearProgressBar(); if (bCanceled) { return(""); } else { return(path); } }