浏览代码

Added Support for Texture2DArrays

/feature-flipbook-2darray
Thomas ICHÉ 5 年前
当前提交
f4f43a58
共有 7 个文件被更改,包括 158 次插入118 次删除
  1. 4
      CHANGELOG.md
  2. 2
      Editor/Common/Canvas/VFXToolboxCanvas.cs
  3. 185
      Editor/ImageSequencer/ImageSequenceAssetEditor.cs
  4. 58
      Editor/ImageSequencer/ImageSequencer.Export.cs
  5. 13
      Editor/ImageSequencer/ImageSequencer.GUI.cs
  6. 10
      Editor/ImageSequencer/Serialization/ImageSequence.cs
  7. 4
      package.json

4
CHANGELOG.md


The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [2.1.0-preview] - 2020 - XX - XX
* Added support for Texture2D Arrays
## [2.0.0-preview] - 2020-03-23
* Refactored Processor API

2
Editor/Common/Canvas/VFXToolboxCanvas.cs


}
private Texture m_Texture;
internal CanvasGUIDelegate onCanvasGUI;
internal event CanvasGUIDelegate onCanvasGUI;
internal delegate void CanvasGUIDelegate();
internal VFXToolboxCanvas(Rect displayRect, string shaderName = "Packages/com.unity.vfx-toolbox/Editor/Common/Canvas/Shaders/VFXToolboxCanvas.shader")

185
Editor/ImageSequencer/ImageSequenceAssetEditor.cs


[CustomEditor(typeof(ImageSequence))]
internal class ImageSequenceAssetEditor : Editor
{
ImageSequence sequence;
private bool m_PreviewInput = false;
private bool m_PreviewOutput = false;
private bool m_RequireConstantRepaint = false;

return m_RequireConstantRepaint;
}
private void OnEnable()
{
sequence = serializedObject.targetObject as ImageSequence;
InitializePreview();
}
protected override void OnHeaderGUI()

m_PreviewInput = GUILayout.Toggle(m_PreviewInput, VFXToolboxGUIUtility.Get("Preview"), EditorStyles.miniButton);
}
if(inputFrameCount > 0 && m_PreviewInput)
if (inputFrameCount > 0 && m_PreviewInput)
if(inputFrameCount > 1)
if (inputFrameCount > 1)
index = (int)Mathf.Floor((time * 30) % inputFrameCount);
index = (int)Mathf.Floor((time * 30) % inputFrameCount);
}
else
{

}
}
GUILayout.Space(24);
VFXToolboxGUIUtility.ToggleableHeader(true, false, "Processors");
{

EditorGUI.indentLevel++;
for(int i = 0; i < processorsCount; i++)
for (int i = 0; i < processorsCount; i++)
EditorGUILayout.LabelField("#"+i+" - " + item.Settings.label + (item.Enabled?"":" (Disabled)"));
EditorGUILayout.LabelField("#" + i + " - " + item.Settings.label + (item.Enabled ? "" : " (Disabled)"));
GUILayout.Space(24);
VFXToolboxGUIUtility.ToggleableHeader(true, false, "Export Settings");

EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.EnumPopup(VFXToolboxGUIUtility.Get("Export Format"), mode);
EditorGUI.EndDisabledGroup();
EditorGUILayout.TextField("Exporting to ", fileName);
EditorGUILayout.TextField("Export Path", fileName);
Rect r = GUILayoutUtility.GetLastRect();
r.width += EditorGUIUtility.fieldWidth;
if (Event.current.rawType == EventType.MouseDown && r.Contains(Event.current.mousePosition))
{
ImageSequencer.PingOutputTexture(fileName);
}
string dir = System.IO.Path.GetDirectoryName(fileName);
string file = System.IO.Path.GetFileNameWithoutExtension(fileName);
string[] assets;
if(!fileName.StartsWith("Assets/"))
{
EditorGUILayout.HelpBox("The output sequence has been exported outside the project, preview will be unavailable", MessageType.Warning);
return;
}
if(fileName.Contains("#"))
{
if(System.IO.Directory.Exists(dir))
{
string[] guids = AssetDatabase.FindAssets(file.Replace('#', '*'), new string[] { dir });
assets = new string[guids.Length];
for(int i = 0; i < guids.Length; i++)
{
assets[i] = AssetDatabase.GUIDToAssetPath(guids[i]);
}
}
else
assets = new string[] { };
}
else
{
assets = new string[] { fileName };
}
int outputFrameCount;
if (frameCount.intValue == assets.Length)
outputFrameCount = frameCount.intValue;
else
outputFrameCount = 0; // Something went wrong
if(outputFrameCount > 0)
{
if(outputFrameCount > 1)
{
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.Label("Output sequence contains " + assets.Length + " frame(s).");
GUILayout.FlexibleSpace();
m_PreviewOutput = GUILayout.Toggle(m_PreviewOutput, VFXToolboxGUIUtility.Get("Preview"), EditorStyles.miniButton);
}
if(m_PreviewOutput)
{
m_RequireConstantRepaint = true;
float time = (float)EditorApplication.timeSinceStartup;
int index = (int)Mathf.Floor((time * 30) % outputFrameCount);
var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(assets[index]);
DrawAnimatedPreviewLayout(texture, ((float)index / outputFrameCount));
}
else
{
m_PreviewOutput = false;
}
}
else // Only one frame
{
var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(assets[0]);
if (texture != null)
DrawAnimatedPreviewLayout(texture, 0.0f);
else
EditorGUILayout.HelpBox("Output Texture could not be loaded, maybe the file was deleted. Please export again using the editor", MessageType.Error);
}
}
else
{
EditorGUILayout.HelpBox("The output sequence does not match the number of files on disk, you probably need to export your sequence again", MessageType.Warning);
}
EditorGUILayout.HelpBox("This asset has not yet been exported. Please open editor and export it to generate a sequence.",MessageType.None);
EditorGUILayout.HelpBox("This asset has not yet been exported. Please open editor and export it to generate a sequence.", MessageType.None);
private void DrawAnimatedPreviewLayout(Texture2D texture, float progress)
private void DrawAnimatedPreviewLayout(Texture texture, float progress)
float width = EditorGUIUtility.currentViewWidth-32;
float width = EditorGUIUtility.currentViewWidth - 32;
if(ratio >= 1)
if (ratio >= 1)
texture_rect = GUILayoutUtility.GetRect(height / ratio, height);
else
texture_rect = GUILayoutUtility.GetRect(width, width * ratio);

}
}
#region PREVIEW
public int previewFrame = 0;
Texture previewTexture;
public Material arrayPreviewMaterial;
static readonly int s_ShaderColorMask = Shader.PropertyToID("_ColorMask");
static readonly int s_ShaderSliceIndex = Shader.PropertyToID("_SliceIndex");
static readonly int s_ShaderMip = Shader.PropertyToID("_Mip");
static readonly int s_ShaderToSrgb = Shader.PropertyToID("_ToSRGB");
static readonly int s_ShaderIsNormalMap = Shader.PropertyToID("_IsNormalMap");
void InitializePreview()
{
if (HasPreviewGUI())
previewTexture = AssetDatabase.LoadAssetAtPath<Texture>(sequence.exportSettings.fileName);
arrayPreviewMaterial = (Material)EditorGUIUtility.LoadRequired("Previews/Preview2DTextureArrayMaterial.mat");
arrayPreviewMaterial.SetInt(s_ShaderColorMask, 15);
arrayPreviewMaterial.SetInt(s_ShaderMip, 0);
arrayPreviewMaterial.SetInt(s_ShaderToSrgb, QualitySettings.activeColorSpace == ColorSpace.Linear ? 1 : 0);
arrayPreviewMaterial.SetInt(s_ShaderIsNormalMap, 0);
}
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
if (previewTexture == null)
InitializePreview();
base.OnPreviewGUI(r, background);
if (previewTexture is Texture2D)
{
EditorGUI.DrawTextureTransparent(r, previewTexture, ScaleMode.ScaleToFit, (float)previewTexture.width / previewTexture.height);
}
else if (previewTexture is Texture2DArray)
{
EditorGUI.DrawPreviewTexture(r, previewTexture, arrayPreviewMaterial, ScaleMode.ScaleToFit, (float)previewTexture.width/previewTexture.height, 0);
}
}
public override void OnPreviewSettings()
{
if (previewTexture == null)
InitializePreview();
if (previewTexture is Texture2DArray)
{
Texture2DArray array = previewTexture as Texture2DArray;
GUILayout.Label("Frame");
previewFrame = EditorGUILayout.IntSlider(previewFrame, 0, array.depth-1);
arrayPreviewMaterial.SetInt(s_ShaderSliceIndex, previewFrame);
}
}
public override bool HasPreviewGUI()
{
if (serializedObject.targetObjects.Length > 1) // No Multiple Preview
return false;
ImageSequence.ExportSettings exportSettings = sequence.exportSettings;
if (exportSettings.fileName == null // No Preview if not exported
|| !exportSettings.fileName.StartsWith("Assets/") // No External Preview
|| exportSettings.fileName.Contains("#")) // No Multiple Frame Preview
return false;
return true;
}
#endregion
}
}

58
Editor/ImageSequencer/ImageSequencer.Export.cs


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))
if (VFXToolboxGUIUtility.DisplayProgressBar("Image Sequencer", "Exporting Frame #" + i + "/" + frameCount, (float)i / frameCount, 0, true))
{
bCanceled = true;
break;

Graphics.Blit((Texture2D)frame.texture, temp);
Graphics.Blit((Texture2D)frame.texture, temp);
inputs = ReadBack(temp);
}
else // frame.texture is RenderTexture

// Dump data
byte[] bytes;
switch(m_CurrentAsset.exportSettings.exportMode)
switch (m_CurrentAsset.exportSettings.exportMode)
{
case ImageSequence.ExportMode.EXR:
#if UNITY_5_6_OR_NEWER

bytes = texture.EncodeToEXR();
}
#else
// Old Exporter
{
bytes = MiniEXR.MiniEXR.MiniEXRWrite((ushort)frame.texture.width, (ushort)frame.texture.height, settings.exportAlpha, inputs, true);
}
// Old Exporter
{
bytes = MiniEXR.MiniEXR.MiniEXRWrite((ushort)frame.texture.width, (ushort)frame.texture.height, settings.exportAlpha, inputs, true);
}
#endif
break;
case ImageSequence.ExportMode.Targa:

AssetDatabase.Refresh();
// Process Import if saved inside project
if(bIsInsideProject)
if (bIsInsideProject)
switch(m_CurrentAsset.exportSettings.dataContents)
switch (m_CurrentAsset.exportSettings.dataContents)
{
case ImageSequence.DataContents.Color:
importer.textureType = TextureImporterType.Default;

importer.convertToNormalmap = false;
break;
case ImageSequence.DataContents.NormalMapFromGrayscale:
importer.textureType = TextureImporterType.NormalMap;
importer.convertToNormalmap = true;
importer.convertToNormalmap = false;
break;
case ImageSequence.DataContents.NormalMapFromGrayscale:
importer.textureType = TextureImporterType.NormalMap;
importer.convertToNormalmap = true;
importer.spritesheet = GetSpriteMetaData(frame, m_ProcessingNodeStack.outputSequence.numU, m_ProcessingNodeStack.outputSequence.numV );
importer.spritesheet = GetSpriteMetaData(frame, m_ProcessingNodeStack.outputSequence.numU, m_ProcessingNodeStack.outputSequence.numV);
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);
switch(m_CurrentAsset.exportSettings.exportMode)
switch (m_CurrentAsset.exportSettings.exportMode)
{
case ImageSequence.ExportMode.Targa:
importer.sRGBTexture = m_CurrentAsset.exportSettings.sRGB;

{
string alphaFilename = fileName.Substring(0, fileName.Length - 4) + "_alpha.tga";
// build alpha
for(int k = 0; k < inputs.Length; k++)
for (int k = 0; k < inputs.Length; k++)
MiniTGA.MiniTGAWrite(alphaFilename,(ushort)frame.texture.width, (ushort)frame.texture.height, false, inputs);
MiniTGA.MiniTGAWrite(alphaFilename, (ushort)frame.texture.width, (ushort)frame.texture.height, false, inputs);
if(bIsInsideProject)
if (bIsInsideProject)
{
TextureImporter alphaImporter = (TextureImporter)TextureImporter.GetAtPath(alphaFilename);

if(fileFound)
{
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(fileName);
Texture texture = AssetDatabase.LoadAssetAtPath<Texture>(fileName);
if (texture != null) EditorGUIUtility.PingObject(texture);
}
else

13
Editor/ImageSequencer/ImageSequencer.GUI.cs


using (new VFXToolboxGUIUtility.HeaderSectionScope("Texture Import Options"))
{
m_CurrentAsset.exportSettings.outputShape = (ImageSequence.OutputMode)EditorGUILayout.EnumPopup(VFXToolboxGUIUtility.Get("Output Shape|Selects whether export as simple 2D Texture, flipbook as 2D texture, or full sequence as 2D texture"), m_CurrentAsset.exportSettings.outputShape);
if(m_CurrentAsset.exportSettings.outputShape == ImageSequence.OutputMode.Texture2DArray)
{
ProcessingNode n = m_ProcessingNodeStack.nodes[m_ProcessingNodeStack.nodes.Count - 1];
if(((float)n.OutputWidth / n.NumU)%1.0f > 0.0f || ((float)n.OutputHeight / n.NumV) % 1.0f > 0.0f)
{
EditorGUILayout.HelpBox("Row and Column Counts are not exact multiples of the resolution, some padding will occur in the export", MessageType.Warning);
} else if ((!Mathf.IsPowerOfTwo(n.OutputWidth / n.NumU) || !Mathf.IsPowerOfTwo(n.OutputHeight / n.NumV)) && m_CurrentAsset.exportSettings.compress && m_CurrentAsset.exportSettings.generateMipMaps)
{
EditorGUILayout.HelpBox("Texture 2D Arrays with mip maps cannot be compressed if U and V dimensions are not power of two", MessageType.Warning);
}
}
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)
{

10
Editor/ImageSequencer/Serialization/ImageSequence.cs


{
public string fileName;
public ushort frameCount;
public OutputMode outputShape;
public ExportMode exportMode;
public bool exportAlpha;
public bool exportSeparateAlpha;

public FilterMode filterMode;
public DataContents dataContents;
}
public static ExportSettings defaultExportSettings
{

Targa = 0,
EXR = 1,
PNG = 2
}
[System.Serializable]
public enum OutputMode
{
Texture2D = 0,
Texture2DArray = 1
}
[System.Serializable]

4
package.json


{
"name": "com.unity.vfx-toolbox",
"displayName": "VFX Toolbox",
"version": "2.0.0-preview",
"version": "2.1.0-preview",
"description": "Additional Tools for VFX Artists.\n\n* Image Sequencer\n* Houdini Exporters for Visual Effect Graph",
"keywords": [
"vfx",

],
"type": "tool",
"hideInEditor": false,
"unity": "2019.3"
"unity": "2020.2"
}
正在加载...
取消
保存