您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
301 行
12 KiB
301 行
12 KiB
using UnityEngine;
|
|
|
|
namespace UnityEditor.Experimental.VFX.Toolbox.ImageSequencer
|
|
{
|
|
[Processor("Sequence","Loop Sequence")]
|
|
class LoopingProcessor : ProcessorBase
|
|
{
|
|
public AnimationCurve curve;
|
|
public int syncFrame;
|
|
public int outputSequenceLength;
|
|
|
|
public override string shaderPath => "Packages/com.unity.vfx-toolbox/Editor/ImageSequencer/Shaders/Blend.shader";
|
|
|
|
public override string processorName => "Looping";
|
|
|
|
public override string label => $"{processorName} ({outputSequenceLength} frame(s), Sync : {syncFrame + 1})";
|
|
|
|
public override int sequenceLength
|
|
{
|
|
get
|
|
{
|
|
if (inputSequenceLength > 0)
|
|
return outputSequenceLength;
|
|
else
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public override void Default()
|
|
{
|
|
curve = new AnimationCurve();
|
|
curve.AddKey(0.25f, 0.0f);
|
|
curve.AddKey(0.75f, 1.0f);
|
|
syncFrame = 25;
|
|
outputSequenceLength = 25;
|
|
}
|
|
|
|
public override bool Process(int frame)
|
|
{
|
|
int inputlength = inputSequenceLength;
|
|
int outputlength = sequenceLength;
|
|
|
|
float t = (float)frame / outputlength;
|
|
|
|
float blendFactor = Mathf.Clamp(curve.Evaluate(t), 0.0f, 1.0f);
|
|
|
|
int Prev = Mathf.Clamp((int)Mathf.Ceil(syncFrame + frame), 0, inputlength - 1);
|
|
int Next = Mathf.Clamp((int)Mathf.Floor(syncFrame - (outputlength - frame)), 0, inputlength - 1);
|
|
|
|
Texture prevtex = RequestInputTexture(Prev);
|
|
Texture nexttex = RequestInputTexture(Next);
|
|
|
|
material.SetTexture("_MainTex", prevtex);
|
|
material.SetTexture("_AltTex", nexttex);
|
|
material.SetFloat("_BlendFactor", blendFactor);
|
|
|
|
ProcessFrame(frame, prevtex);
|
|
return true;
|
|
}
|
|
|
|
CurveDrawer m_CurveDrawer;
|
|
|
|
public override bool OnInspectorGUI(bool changed, SerializedObject serializedObject)
|
|
{
|
|
var outputSequenceLength = serializedObject.FindProperty("outputSequenceLength");
|
|
var syncFrame = serializedObject.FindProperty("syncFrame");
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
int sync = syncFrame.intValue;
|
|
int newSync = EditorGUILayout.IntSlider(VFXToolboxGUIUtility.Get("Input Sync Frame|The frame from input sequence that will be used at start and end of the output sequence."), sync, 0 + outputSequenceLength.intValue, inputSequenceLength - outputSequenceLength.intValue);
|
|
|
|
if (newSync != sync)
|
|
{
|
|
newSync = Mathf.Clamp(newSync, 0 + outputSequenceLength.intValue, inputSequenceLength - outputSequenceLength.intValue);
|
|
syncFrame.intValue = newSync;
|
|
}
|
|
|
|
int length = outputSequenceLength.intValue;
|
|
int newlength = EditorGUILayout.IntSlider(VFXToolboxGUIUtility.Get("Output Sequence Length|How many frames will be in the output sequence?"), length, 2, (inputSequenceLength / 2) + 1);
|
|
|
|
if (newlength != length)
|
|
{
|
|
newlength = Mathf.Min(newlength, Mathf.Max(1, (inputSequenceLength / 2)));
|
|
outputSequenceLength.intValue = newlength;
|
|
syncFrame.intValue = Mathf.Clamp(syncFrame.intValue, 0 + outputSequenceLength.intValue, inputSequenceLength - outputSequenceLength.intValue);
|
|
}
|
|
|
|
float seqRatio = -1.0f;
|
|
if (isCurrentlyPreviewed)
|
|
{
|
|
seqRatio = (previewSequenceLength > 1) ? (float)previewCurrentFrame / (previewSequenceLength - 1) : 0.0f;
|
|
}
|
|
|
|
// Draw Preview
|
|
GUILayout.Label(VFXToolboxGUIUtility.Get("Mix Curve"));
|
|
Rect preview_rect;
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
preview_rect = GUILayoutUtility.GetRect(200, 80);
|
|
}
|
|
|
|
EditorGUI.DrawRect(preview_rect, new Color(0.0f, 0.0f, 0.0f, 0.25f));
|
|
|
|
Rect gradient_rect = new RectOffset(40, 16, 0, 16).Remove(preview_rect);
|
|
float width = gradient_rect.width;
|
|
float height = gradient_rect.height;
|
|
Color topTrackColor = new Color(1.0f, 0.8f, 0.25f);
|
|
Color bottomTrackColor = new Color(0.25f, 0.8f, 1.0f);
|
|
|
|
using (new GUI.ClipScope(preview_rect))
|
|
{
|
|
GUI.color = topTrackColor;
|
|
Handles.color = topTrackColor;
|
|
GUI.Label(new Rect(0, 0, 32, 16), "In:", VFXToolboxStyles.miniLabel);
|
|
Handles.DrawLine(new Vector3(72, 8), new Vector3(width + 40 - 32, 8));
|
|
GUI.color = bottomTrackColor;
|
|
Handles.color = bottomTrackColor;
|
|
GUI.Label(new Rect(0, height - 16, 32, 16), "In:", VFXToolboxStyles.miniLabel);
|
|
Handles.DrawLine(new Vector3(72, height - 8), new Vector3(width + 40 - 32, height - 8));
|
|
GUI.color = Color.white;
|
|
Handles.color = Color.white;
|
|
GUI.Label(new Rect(0, height, 32, 16), "Out:", VFXToolboxStyles.miniLabel);
|
|
GUI.Label(new Rect(40, height, 32, 16), "1", VFXToolboxStyles.miniLabel);
|
|
GUI.Label(new Rect(width + 40 - 32, height, 32, 16), length.ToString(), VFXToolboxStyles.miniLabelRight);
|
|
Handles.DrawLine(new Vector3(72, height + 8), new Vector3(width + 40 - 32, height + 8));
|
|
}
|
|
|
|
AnimationCurve curve = serializedObject.FindProperty("curve").animationCurveValue;
|
|
using (new GUI.ClipScope(gradient_rect))
|
|
{
|
|
int seqLen = this.outputSequenceLength;
|
|
int syncF = syncFrame.intValue;
|
|
|
|
float w = Mathf.Ceil((float)width / seqLen);
|
|
|
|
for (int i = 0; i < seqLen; i++)
|
|
{
|
|
float t = (float)i / seqLen;
|
|
Color blended = Color.Lerp(bottomTrackColor, topTrackColor, curve.Evaluate(t));
|
|
EditorGUI.DrawRect(new Rect(i * w, 18, w, height - 36), blended);
|
|
}
|
|
|
|
GUI.color = topTrackColor;
|
|
GUI.Label(new Rect(0, 0, 32, 16), (syncF - seqLen + 1).ToString(), VFXToolboxStyles.miniLabel);
|
|
GUI.Label(new Rect(width - 32, 0, 32, 16), (syncF).ToString(), VFXToolboxStyles.miniLabelRight);
|
|
GUI.color = bottomTrackColor;
|
|
GUI.Label(new Rect(0, height - 16, 32, 16), (syncF + 1).ToString(), VFXToolboxStyles.miniLabel);
|
|
GUI.Label(new Rect(width - 32, height - 16, 32, 16), (syncF + seqLen).ToString(), VFXToolboxStyles.miniLabelRight);
|
|
GUI.color = Color.white;
|
|
|
|
}
|
|
|
|
// If previewing current sequence : draw trackbar
|
|
if (seqRatio >= 0.0f)
|
|
{
|
|
Handles.color = Color.white;
|
|
Handles.DrawLine(new Vector3(gradient_rect.xMin + seqRatio * gradient_rect.width, preview_rect.yMin), new Vector3(gradient_rect.xMin + seqRatio * gradient_rect.width, preview_rect.yMax));
|
|
}
|
|
|
|
// Curve Drawer
|
|
if (m_CurveDrawer == null)
|
|
{
|
|
m_CurveDrawer = new CurveDrawer(null, 0.0f, 1.0f, 0.0f, 1.0f, 140, false);
|
|
m_CurveDrawer.AddCurve(serializedObject.FindProperty("curve"), new Color(0.5f, 0.75f, 1.0f), "Looping Curve");
|
|
m_CurveDrawer.OnPostGUI = OnCurveFieldGUI;
|
|
}
|
|
|
|
if (m_CurveDrawer.OnGUILayout())
|
|
{
|
|
changed = true;
|
|
}
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
changed = true;
|
|
}
|
|
|
|
if (curve.keys.Length < 2 || curve.keys[0].value > 0.0f || curve.keys[curve.keys.Length - 1].value < 1.0f)
|
|
EditorGUILayout.HelpBox("Warning : Mix Curve must have first key's value equal 0 and last key's value equal 1 to achieve looping", MessageType.Warning);
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
bool CurveEquals(AnimationCurve target)
|
|
{
|
|
for (int i = 0; i < target.keys.Length; i++)
|
|
{
|
|
if (target[i].time != curve[i].time ||
|
|
target[i].value != curve[i].value ||
|
|
target[i].inTangent != curve[i].inTangent ||
|
|
target[i].outTangent != curve[i].outTangent)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void OnCurveFieldGUI(Rect renderArea, Rect curveArea)
|
|
{
|
|
float seqRatio = -1.0f;
|
|
if (isCurrentlyPreviewed)
|
|
{
|
|
seqRatio = (previewSequenceLength > 1) ? (float)previewCurrentFrame / (previewSequenceLength - 1) : 0.0f;
|
|
}
|
|
|
|
// If previewing current sequence : draw trackbar
|
|
if (seqRatio >= 0.0f)
|
|
{
|
|
Handles.color = Color.white;
|
|
Handles.DrawLine(new Vector3(curveArea.xMin + seqRatio * curveArea.width, renderArea.yMin), new Vector3(curveArea.xMin + seqRatio * curveArea.width, renderArea.yMax));
|
|
}
|
|
}
|
|
|
|
public override bool OnCanvasGUI(ImageSequencerCanvas canvas)
|
|
{
|
|
int inLength = inputSequenceLength;
|
|
int outLength = sequenceLength;
|
|
int syncFrame = this.syncFrame;
|
|
|
|
int outCurIDX = canvas.currentFrameIndex;
|
|
float outCurT = (float)outCurIDX / outLength;
|
|
int inSeqAIDX = (syncFrame - outLength) + outCurIDX;
|
|
int inSeqBIDX = syncFrame + outCurIDX;
|
|
|
|
AnimationCurve mixCurve = curve;
|
|
float mix = mixCurve.Evaluate(outCurT);
|
|
|
|
Color topTrackColor = canvas.styles.yellow;
|
|
Color bottomTrackColor = canvas.styles.cyan;
|
|
|
|
Vector2 top = canvas.CanvasToScreen(new Vector2(-canvas.currentFrame.texture.width, canvas.currentFrame.texture.height) / 2);
|
|
|
|
Rect rect = new Rect((int)top.x + 24, (int)top.y + 8, 260, 280);
|
|
EditorGUI.DrawRect(new RectOffset(8, 8, 8, 8).Add(rect), canvas.styles.backgroundPanelColor);
|
|
GUILayout.BeginArea(rect);
|
|
GUI.color = topTrackColor;
|
|
GUILayout.Label("Mix Chunk A (Input Range : " + (syncFrame - outLength + 1).ToString() + "-" + syncFrame.ToString() + ")", canvas.styles.label);
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
Rect imgARect = GUILayoutUtility.GetRect(100, 100);
|
|
imgARect.width = 100;
|
|
imgARect.height = 100;
|
|
|
|
GUI.color = Color.white;
|
|
#if !UNITY_2018_2_OR_NEWER
|
|
GL.sRGBWrite = (QualitySettings.activeColorSpace == ColorSpace.Linear);
|
|
#endif
|
|
GUI.DrawTexture(imgARect, RequestInputTexture(inSeqAIDX));
|
|
#if !UNITY_2018_2_OR_NEWER
|
|
GL.sRGBWrite = false;
|
|
#endif
|
|
GUI.color = canvas.styles.white;
|
|
Handles.DrawSolidRectangleWithOutline(imgARect, Color.clear, topTrackColor);
|
|
|
|
|
|
using (new GUILayout.VerticalScope())
|
|
{
|
|
GUI.color = topTrackColor;
|
|
GUILayout.Label("Frame #" + (inSeqAIDX + 1).ToString(), canvas.styles.miniLabel);
|
|
GUILayout.Label("Mixed at : " + (int)(mix * 100) + "%", canvas.styles.miniLabel);
|
|
}
|
|
}
|
|
|
|
GUILayout.Space(16);
|
|
GUI.color = bottomTrackColor;
|
|
GUILayout.Label("Mix Chunk B (Input Range : " + (syncFrame + 1).ToString() + "-" + (syncFrame + outLength).ToString() + ")", canvas.styles.label);
|
|
using (new GUILayout.HorizontalScope())
|
|
{
|
|
Rect imgBRect = GUILayoutUtility.GetRect(100, 100);
|
|
imgBRect.width = 100;
|
|
imgBRect.height = 100;
|
|
|
|
GUI.color = Color.white;
|
|
#if !UNITY_2018_2_OR_NEWER
|
|
GL.sRGBWrite = (QualitySettings.activeColorSpace == ColorSpace.Linear);
|
|
#endif
|
|
GUI.DrawTexture(imgBRect, RequestInputTexture(inSeqBIDX));
|
|
#if !UNITY_2018_2_OR_NEWER
|
|
GL.sRGBWrite = false;
|
|
#endif
|
|
|
|
GUI.color = canvas.styles.white;
|
|
Handles.DrawSolidRectangleWithOutline(imgBRect, Color.clear, bottomTrackColor);
|
|
|
|
using (new GUILayout.VerticalScope())
|
|
{
|
|
GUI.color = bottomTrackColor;
|
|
GUILayout.Label("Frame #" + (inSeqBIDX + 1).ToString(), canvas.styles.miniLabel);
|
|
GUILayout.Label("Mixed at : " + (int)((1.0f - mix) * 100) + "%", canvas.styles.miniLabel);
|
|
}
|
|
}
|
|
GUI.color = Color.white;
|
|
GUILayout.EndArea();
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|