您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
303 行
12 KiB
303 行
12 KiB
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace UnityEditor.VFXToolbox.ImageSequencer
|
|
{
|
|
class AssembleProcessor : GPUFrameProcessor<AssembleProcessorSettings>
|
|
{
|
|
public AssembleProcessor(FrameProcessorStack processorStack, ProcessorInfo info)
|
|
: base ("Packages/com.unity.vfx-toolbox/ImageSequencer/Editor/Shaders/AssembleBlit.shader", processorStack, info)
|
|
{ }
|
|
|
|
protected override void UpdateOutputSize()
|
|
{
|
|
switch(settings.Mode)
|
|
{
|
|
case AssembleProcessorSettings.AssembleMode.FullSpriteSheet:
|
|
|
|
SetOutputSize( InputSequence.width * settings.FlipbookNumU, InputSequence.height * settings.FlipbookNumV);
|
|
break;
|
|
|
|
case AssembleProcessorSettings.AssembleMode.VerticalSequence:
|
|
|
|
SetOutputSize( InputSequence.width, InputSequence.height * settings.FlipbookNumV);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
public override string GetLabel()
|
|
{
|
|
string numU = (settings.Mode == AssembleProcessorSettings.AssembleMode.VerticalSequence) ? "*" : settings.FlipbookNumU.ToString();
|
|
string numV = settings.FlipbookNumV.ToString();
|
|
return string.Format("{0} ({1}x{2})",GetName(), numU,numV);
|
|
}
|
|
|
|
public override string GetName()
|
|
{
|
|
return "Assemble Flipbook";
|
|
}
|
|
|
|
public override bool Process(int frame)
|
|
{
|
|
int length = InputSequence.length;
|
|
|
|
RenderTexture backup = RenderTexture.active;
|
|
|
|
switch(settings.Mode)
|
|
{
|
|
case AssembleProcessorSettings.AssembleMode.FullSpriteSheet:
|
|
|
|
// Blit Every Image inside output
|
|
for(int i = 0; i < (settings.FlipbookNumU*settings.FlipbookNumV); i++)
|
|
{
|
|
int u = i % settings.FlipbookNumU;
|
|
int v = (settings.FlipbookNumV-1)-(int)Mathf.Floor((float)i / settings.FlipbookNumU);
|
|
|
|
Vector2 size = new Vector2(1.0f/settings.FlipbookNumU, 1.0f/settings.FlipbookNumV);
|
|
int idx = Mathf.Clamp(i, 0, length - 1);
|
|
|
|
Texture currentTexture = InputSequence.RequestFrame(idx).texture;
|
|
|
|
Vector4 ClipCoordinates = new Vector4(u*size.x,v*size.y,size.x,size.y);
|
|
|
|
m_Material.SetTexture("_MainTex", currentTexture);
|
|
m_Material.SetVector("_CC", ClipCoordinates);
|
|
|
|
Graphics.Blit(currentTexture, (RenderTexture)m_OutputSequence.frames[0].texture, m_Material);
|
|
}
|
|
|
|
RenderTexture.active = backup;
|
|
|
|
break;
|
|
|
|
case AssembleProcessorSettings.AssembleMode.VerticalSequence:
|
|
|
|
// Blit Every N'th Image inside output
|
|
int cycleLength = InputSequence.length / settings.FlipbookNumV;
|
|
|
|
for(int i = 0; i < settings.FlipbookNumV; i++)
|
|
{
|
|
int u = 0;
|
|
int v = settings.FlipbookNumV-1-i;
|
|
|
|
Vector2 size = new Vector2(1.0f, 1.0f/settings.FlipbookNumV);
|
|
int idx = Mathf.Clamp((i * cycleLength)+frame, 0, length - 1);
|
|
|
|
Texture currentTexture = InputSequence.RequestFrame(idx).texture;
|
|
|
|
Vector4 ClipCoordinates = new Vector4(u*size.x,v*size.y,size.x,size.y);
|
|
|
|
m_Material.SetTexture("_MainTex", currentTexture);
|
|
m_Material.SetVector("_CC", ClipCoordinates);
|
|
|
|
Graphics.Blit(currentTexture, (RenderTexture)m_OutputSequence.frames[frame].texture, m_Material);
|
|
}
|
|
|
|
RenderTexture.active = backup;
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override int GetProcessorSequenceLength()
|
|
{
|
|
switch(settings.Mode)
|
|
{
|
|
case AssembleProcessorSettings.AssembleMode.FullSpriteSheet:
|
|
return 1;
|
|
|
|
case AssembleProcessorSettings.AssembleMode.VerticalSequence:
|
|
return InputSequence.length / settings.FlipbookNumV;
|
|
|
|
default:
|
|
return 1; // Should not happen, unless someone messes up with files...
|
|
|
|
}
|
|
}
|
|
|
|
protected override bool DrawSidePanelContent(bool hasChanged)
|
|
{
|
|
|
|
var flipbookNumU = m_SerializedObject.FindProperty("FlipbookNumU");
|
|
var flipbookNumV = m_SerializedObject.FindProperty("FlipbookNumV");
|
|
var mode = m_SerializedObject.FindProperty("Mode");
|
|
|
|
var assembleMode = (AssembleProcessorSettings.AssembleMode)mode.intValue;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
assembleMode = (AssembleProcessorSettings.AssembleMode)EditorGUILayout.EnumPopup(VFXToolboxGUIUtility.Get("Assemble Mode"), assembleMode);
|
|
if(assembleMode != (AssembleProcessorSettings.AssembleMode)mode.intValue )
|
|
{
|
|
mode.intValue = (int)assembleMode;
|
|
hasChanged = true;
|
|
}
|
|
|
|
switch(assembleMode)
|
|
{
|
|
case AssembleProcessorSettings.AssembleMode.FullSpriteSheet:
|
|
|
|
int newU = EditorGUILayout.IntField(VFXToolboxGUIUtility.Get("Columns (U) : "),flipbookNumU.intValue);
|
|
int newV = EditorGUILayout.IntField(VFXToolboxGUIUtility.Get("Rows (V) : "), flipbookNumV.intValue);
|
|
|
|
if(InputSequence.length > 0)
|
|
{
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
GUILayout.Label(VFXToolboxGUIUtility.Get("Find Best Ratios"), GUILayout.Width(EditorGUIUtility.labelWidth));
|
|
if (GUILayout.Button(VFXToolboxGUIUtility.Get("Get")))
|
|
{
|
|
float frameRatio = (float)InputSequence.frames[0].texture.width / (float)InputSequence.frames[0].texture.height;
|
|
int length = InputSequence.frames.Count;
|
|
List<int> ratios = new List<int>();
|
|
SortedDictionary<int,float> coeffs = new SortedDictionary<int,float>();
|
|
float rad = Mathf.Sqrt(length);
|
|
for(int i = (int)rad; i >=1; i--)
|
|
{
|
|
if(((float)length / (float)i) % 1.0f == 0.0f)
|
|
{
|
|
float pageRatio = (float)i / (length / i);
|
|
float fullRatio = frameRatio * pageRatio;
|
|
float divergence = Mathf.Abs(Mathf.Log(fullRatio, 2.0f) % 1.0f);
|
|
|
|
if(!ratios.Contains(i))
|
|
{
|
|
ratios.Add(i);
|
|
coeffs.Add(i, divergence);
|
|
}
|
|
|
|
fullRatio = frameRatio / pageRatio;
|
|
divergence = Mathf.Abs(Mathf.Log(fullRatio, 2.0f) % 1.0f);
|
|
|
|
if(!ratios.Contains(length / i))
|
|
{
|
|
ratios.Add(length / i);
|
|
coeffs.Add((length / i), divergence);
|
|
}
|
|
}
|
|
}
|
|
|
|
GenericMenu menu = new GenericMenu();
|
|
|
|
var sortedValues = coeffs.OrderBy(kvp => kvp.Value);
|
|
|
|
foreach(KeyValuePair<int, float> kvp in sortedValues)
|
|
{
|
|
int value = kvp.Key;
|
|
|
|
menu.AddItem(new GUIContent(value + " x " + (length / value) + ((kvp.Value == 0.0f)? " (PERFECT)": "")), false, MenuSetFlipbookUV, value);
|
|
}
|
|
if (menu.GetItemCount() > 0)
|
|
menu.ShowAsContext();
|
|
}
|
|
}
|
|
EditorGUILayout.HelpBox("Find Best Ratios will try to find matching possibilities for the current sequence, ordered by ratio pertinence, meaning that first results will have less stretch when resized to power-of-two textures.", MessageType.Info);
|
|
}
|
|
|
|
|
|
if(newU != flipbookNumU.intValue)
|
|
{
|
|
newU = Mathf.Clamp(newU, 1, InputSequence.length / newV);
|
|
flipbookNumU.intValue = newU;
|
|
}
|
|
|
|
if(newV != flipbookNumV.intValue)
|
|
{
|
|
newV = Mathf.Clamp(newV, 1, InputSequence.length / newU);
|
|
flipbookNumV.intValue = newV;
|
|
}
|
|
break;
|
|
|
|
case AssembleProcessorSettings.AssembleMode.VerticalSequence:
|
|
|
|
int numRows = EditorGUILayout.IntField(VFXToolboxGUIUtility.Get("Rows (V) : "), flipbookNumV.intValue);
|
|
|
|
if(numRows != flipbookNumV.intValue)
|
|
{
|
|
numRows = Mathf.Clamp(numRows, 1, InputSequence.length);
|
|
flipbookNumV.intValue = numRows;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
UpdateOutputSize();
|
|
Invalidate();
|
|
hasChanged = true;
|
|
}
|
|
|
|
return hasChanged;
|
|
}
|
|
|
|
private void MenuSetFlipbookUV(object o)
|
|
{
|
|
int length = InputSequence.length;
|
|
int numU = (int)o;
|
|
int numV = length / numU;
|
|
m_SerializedObject.Update();
|
|
var flipbookNumU = m_SerializedObject.FindProperty("FlipbookNumU");
|
|
var flipbookNumV = m_SerializedObject.FindProperty("FlipbookNumV");
|
|
|
|
flipbookNumU.intValue = numU;
|
|
flipbookNumV.intValue = numV;
|
|
|
|
m_SerializedObject.ApplyModifiedProperties();
|
|
UpdateOutputSize();
|
|
Invalidate();
|
|
}
|
|
|
|
public override bool OnCanvasGUI(ImageSequencerCanvas canvas)
|
|
{
|
|
if (Event.current.type != EventType.Repaint)
|
|
return false;
|
|
|
|
Vector2 topRight;
|
|
Vector2 bottomLeft;
|
|
|
|
topRight = canvas.CanvasToScreen(new Vector2(-canvas.currentFrame.texture.width/2 , canvas.currentFrame.texture.height/2 ));
|
|
bottomLeft = canvas.CanvasToScreen(new Vector2(canvas.currentFrame.texture.width/2 , -canvas.currentFrame.texture.height/2 ));
|
|
|
|
// Texts
|
|
GUI.color = canvas.styles.green;
|
|
for(int i = 0; i < settings.FlipbookNumU; i++)
|
|
{
|
|
float cw = (topRight.x - bottomLeft.x) / settings.FlipbookNumU;
|
|
GUI.Label(new Rect(bottomLeft.x + i * cw , topRight.y - 16 , cw, 16), (i+1).ToString(), canvas.styles.miniLabelCenter);
|
|
}
|
|
|
|
for(int i = 0; i < settings.FlipbookNumV; i++)
|
|
{
|
|
float ch = (bottomLeft.y-topRight.y) / settings.FlipbookNumV;
|
|
VFXToolboxGUIUtility.GUIRotatedLabel(new Rect(bottomLeft.x - 8, topRight.y + i * ch, 16, ch), (i+1).ToString(), -90.0f, canvas.styles.miniLabelCenter);
|
|
}
|
|
|
|
GUI.color = Color.white;
|
|
return false;
|
|
}
|
|
|
|
protected override int GetNumU()
|
|
{
|
|
switch(settings.Mode)
|
|
{
|
|
case AssembleProcessorSettings.AssembleMode.FullSpriteSheet:
|
|
return settings.FlipbookNumU * InputSequence.numU;
|
|
case AssembleProcessorSettings.AssembleMode.VerticalSequence:
|
|
return InputSequence.numU;
|
|
default:
|
|
return InputSequence.numU;
|
|
}
|
|
|
|
}
|
|
|
|
protected override int GetNumV()
|
|
{
|
|
return settings.FlipbookNumV * InputSequence.numV;
|
|
}
|
|
}
|
|
}
|