您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

374 行
17 KiB

using UnityEngine;
using System.IO;
using VFXToolbox.MiniTGA;
namespace UnityEditor.Experimental.VFX.Toolbox.ImageSequencer
{
internal partial class ImageSequencer : EditorWindow
{
private string GetNumberedFileName(string pattern, int number, int maxFrames)
{
int numbering = (int)Mathf.Floor(Mathf.Log10(maxFrames))+1;
return pattern.Replace("#", number.ToString("D" + numbering.ToString()));
}
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_ProcessingNodeStack.outputSequence.frames.Count;
int numU = m_ProcessingNodeStack.outputSequence.numU;
int numV = m_ProcessingNodeStack.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_ProcessingNodeStack.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_ProcessingNodeStack.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.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_ProcessingNodeStack.outputSequence.numU, m_ProcessingNodeStack.outputSequence.numV);
break;
}
TextureImporterSettings importerSettings = new TextureImporterSettings();
importer.ReadTextureSettings(importerSettings);
if (m_CurrentAsset.exportSettings.outputShape == ImageSequence.OutputMode.Texture2DArray)
{
importerSettings.textureShape = TextureImporterShape.Texture2DArray;
importerSettings.flipbookColumns = m_ProcessingNodeStack.outputSequence.numU;
importerSettings.flipbookRows = m_ProcessingNodeStack.outputSequence.numV;
}
else if (m_CurrentAsset.exportSettings.outputShape == ImageSequence.OutputMode.Texture2D)
{
importerSettings.textureShape = TextureImporterShape.Texture2D;
}
importer.SetTextureSettings(importerSettings);
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.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_ProcessingNodeStack.outputSequence.numU, m_ProcessingNodeStack.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;
}
public static void PingOutputTexture(string fileName)
{
if (fileName == "")
return;
string dir = System.IO.Path.GetDirectoryName(fileName);
string file = System.IO.Path.GetFileNameWithoutExtension(fileName);
if(!fileName.StartsWith("Assets/"))
return;
if(fileName.Contains("#"))
{
if(System.IO.Directory.Exists(dir))
{
string[] guids = AssetDatabase.FindAssets(file.Replace('#', '*'), new string[] { dir });
fileName = AssetDatabase.GUIDToAssetPath(guids[0]);
}
}
bool fileFound = (fileName != "")&&(System.IO.File.Exists(fileName));
if(fileFound)
{
Texture texture = AssetDatabase.LoadAssetAtPath<Texture>(fileName);
if (texture != null) EditorGUIUtility.PingObject(texture);
}
else
{
Debug.LogWarning("Could not ping output texture, either the file was moved or removed, you probably need to export your sequence again");
}
}
private void PingCurrentAsset()
{
EditorGUIUtility.PingObject(m_CurrentAsset);
}
private void UpdateExportedAssets()
{
if (ExportToFile(true) != "")
m_CurrentAsset.exportSettings.frameCount = (ushort)m_ProcessingNodeStack.outputSequence.frames.Count;
else
m_CurrentAsset.exportSettings.frameCount = 0;
}
private Color[] ReadBack(RenderTexture renderTexture)
{
Color[] inputs = VFXToolboxUtility.ReadBack(renderTexture);
if(QualitySettings.activeColorSpace == ColorSpace.Linear && m_CurrentAsset.exportSettings.sRGB)
{
Color[] outputs = new Color[inputs.Length];
for (int j = 0; j < inputs.Length; j++)
{
outputs[j] = inputs[j].gamma;
}
return outputs;
}
return inputs;
}
private SpriteMetaData[] GetSpriteMetaData(ProcessingFrame frame, int numU, int numV)
{
SpriteMetaData[] result = new SpriteMetaData[numU * numV];
float width = (float)frame.texture.width / numU;
float height = (float)frame.texture.height / numV;
for(int i = 0; i < numU; i++)
for(int j = 0; j < numV; j++)
{
SpriteMetaData data = new SpriteMetaData();
data.name = "Frame_" + (i + (j * numU));
data.rect = new Rect(i * width, (numV - j - 1) * height, width, height);
result[i + (j * numU)] = data;
}
return result;
}
private static GUIContent[] GetExportModeFriendlyNames()
{
return new GUIContent[] { VFXToolboxGUIUtility.Get("Targa"), VFXToolboxGUIUtility.Get("OpenEXR (HDR)"), VFXToolboxGUIUtility.Get("PNG") };
}
}
}