1st draft
This commit is contained in:
Родитель
4f2475bbca
Коммит
91447d342d
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a08b35c30775e274cacf0ab18c4d82cb
|
||||
folderAsset: yes
|
||||
timeCreated: 1491415339
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d603226de9e3cc44e89a6c7354da487d
|
||||
folderAsset: yes
|
||||
timeCreated: 1491415339
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a6b346140d4dd0c48b4431a7f27d450d
|
||||
folderAsset: yes
|
||||
timeCreated: 1491415339
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Recorder.FrameRecorder;
|
||||
|
||||
namespace UnityEditor.Recorder.FrameRecorder
|
||||
{
|
||||
public abstract class DefaultImageRecorderSettingsEditor : RecorderSettingsEditor
|
||||
{
|
||||
string[] m_Displays;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
var displayCount = Display.displays.Length;
|
||||
m_Displays = new string[displayCount];
|
||||
for (int i = 0; i < displayCount; i++)
|
||||
m_Displays[i] = string.Format("Display {0}", i + 1);
|
||||
}
|
||||
|
||||
protected override void OnInputGui()
|
||||
{
|
||||
var settingsObj = serializedObject.targetObject as ImageRecorderSettings;
|
||||
|
||||
m_LayoutHelper.AddEnumProperty("Source:", serializedObject, () => settingsObj.m_InputType);
|
||||
|
||||
switch (settingsObj.m_InputType)
|
||||
{
|
||||
case EImageSourceType.GameDisplay:
|
||||
{
|
||||
m_LayoutHelper.indentLevel++;
|
||||
|
||||
m_LayoutHelper.AddEnumProperty("Size:", serializedObject, () => settingsObj.m_SizeMode);
|
||||
|
||||
switch (settingsObj.m_SizeMode)
|
||||
{
|
||||
case EImageSizeMode.Dynamic:
|
||||
break;
|
||||
case EImageSizeMode.FullScreen:
|
||||
break;
|
||||
case EImageSizeMode.Width:
|
||||
m_LayoutHelper.AddIntProperty("Resolution (width)", serializedObject, () => settingsObj.m_Width);
|
||||
break;
|
||||
case EImageSizeMode.Custom:
|
||||
m_LayoutHelper.AddIntProperty("Resolution (width)", serializedObject, () => settingsObj.m_Width);
|
||||
m_LayoutHelper.AddIntProperty("Resolution (height)", serializedObject, () => settingsObj.m_Height);
|
||||
break;
|
||||
}
|
||||
|
||||
m_LayoutHelper.indentLevel--;
|
||||
break;
|
||||
}
|
||||
case EImageSourceType.RenderTexture:
|
||||
{
|
||||
OnCustomInputGui();
|
||||
break;
|
||||
}
|
||||
|
||||
case EImageSourceType.TaggedCamera:
|
||||
{
|
||||
m_LayoutHelper.indentLevel++;
|
||||
m_LayoutHelper.AddStringProperty("Tags:", serializedObject, () => settingsObj.m_CameraTag);
|
||||
m_LayoutHelper.indentLevel--;
|
||||
break;
|
||||
}
|
||||
|
||||
case EImageSourceType.MainCamera:
|
||||
break;
|
||||
}
|
||||
|
||||
base.OnInputGui();
|
||||
}
|
||||
|
||||
protected override void OnEncodingGui()
|
||||
{
|
||||
//base.OnOutputGui();
|
||||
//var settingsObj = target as ImageRecorderSettings;
|
||||
|
||||
/*
|
||||
|
||||
switch (settingsObj.m_InputType)
|
||||
{
|
||||
case EImageSourceType.GameDisplay:
|
||||
{
|
||||
m_LayoutHelper.AddBoolProperty("Scale image size", serializedObject, () => settingsObj.m_ScaleImage);
|
||||
|
||||
if (settingsObj.m_ScaleImage)
|
||||
{
|
||||
settingsObj.m_PreserveSourceAspectRatio = true;
|
||||
m_LayoutHelper.AddIntProperty("Resolution (width)", serializedObject, () => settingsObj.m_Width);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EImageSourceType.MainCamera:
|
||||
case EImageSourceType.TaggedCamera:
|
||||
{
|
||||
settingsObj.m_PreserveSourceAspectRatio = true;
|
||||
m_LayoutHelper.AddIntProperty("Resolution (width)", serializedObject, () => settingsObj.m_Width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
protected virtual void OnCustomInputGui()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 34dd54c4c05f9c7429eb3f50bcdac0f4
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,157 @@
|
|||
using System;
|
||||
using System.Resources;
|
||||
using Assets.Unity.FrameRecorder.Scripts.Editor;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Recorder.FrameRecorder;
|
||||
using UnityEngine.Recorder.FrameRecorder.Timeline;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Recorder.FrameRecorder.Timeline
|
||||
{
|
||||
[CustomEditor(typeof(FrameRecorderClip), true)]
|
||||
public class RecorderClipEditor : Editor, IRecorderSelectorTarget
|
||||
{
|
||||
RecorderSettingsEditor m_SettingsEditor;
|
||||
TimelineAsset m_Timeline;
|
||||
RecorderSelector m_recorderSelector;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
m_recorderSelector = new RecorderSelector(this);
|
||||
var shot = this.target as FrameRecorderClip;
|
||||
var editorType = RecorderSettingsEditor.FindEditorForRecorder(shot.recorderType);
|
||||
if (editorType != null)
|
||||
{
|
||||
m_SettingsEditor = Editor.CreateEditor(shot.m_Settings, editorType) as RecorderSettingsEditor;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
m_recorderSelector.OnGui();
|
||||
|
||||
if (m_SettingsEditor != null)
|
||||
{
|
||||
m_SettingsEditor.showBounds = false;
|
||||
m_Timeline = FindTimelineAsset();
|
||||
|
||||
PushTimelineIntoRecorder();
|
||||
|
||||
using (new EditorGUI.DisabledScope(EditorApplication.isPlaying))
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Settings ID:");
|
||||
EditorGUILayout.TextField((m_SettingsEditor.target as FrameRecorderSettings).m_UniqueID);
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
|
||||
m_SettingsEditor.OnInspectorGUI();
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
PushRecorderIntoTimeline();
|
||||
|
||||
serializedObject.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string recorderCategory
|
||||
{
|
||||
get
|
||||
{
|
||||
var shot = this.target as FrameRecorderClip;
|
||||
return shot.m_RecorderCategory;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
var shot = this.target as FrameRecorderClip;
|
||||
if (shot.m_RecorderCategory != value)
|
||||
{
|
||||
shot.m_RecorderCategory = value;
|
||||
m_SettingsEditor = null;
|
||||
shot.recorderType = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string selectedRecorder
|
||||
{
|
||||
get
|
||||
{
|
||||
var shot = this.target as FrameRecorderClip;
|
||||
return shot.m_RecorderTypeName;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRecorder(Type newRecorderType)
|
||||
{
|
||||
var clip = this.target as FrameRecorderClip;
|
||||
|
||||
if (newRecorderType == null || (m_SettingsEditor != null && m_SettingsEditor.target != null && clip.recorderType == newRecorderType))
|
||||
return;
|
||||
|
||||
clip.recorderType = newRecorderType;
|
||||
|
||||
var editorType = RecorderSettingsEditor.FindEditorForRecorder(clip.recorderType);
|
||||
if (editorType != null)
|
||||
{
|
||||
var assetGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(clip));
|
||||
clip.m_Settings = RecordersInventory.CreateRecorderSettings(clip.recorderType, assetGuid, "TmLn-Clip:" + assetGuid);
|
||||
m_SettingsEditor = CreateEditor(clip.m_Settings, editorType) as RecorderSettingsEditor;
|
||||
}
|
||||
else
|
||||
Debug.LogError(string.Format("No editor class declared for recorder of type " + newRecorderType.FullName));
|
||||
}
|
||||
|
||||
TimelineAsset FindTimelineAsset()
|
||||
{
|
||||
if (!AssetDatabase.Contains(target))
|
||||
return null;
|
||||
|
||||
var path = AssetDatabase.GetAssetPath(target);
|
||||
var objs = AssetDatabase.LoadAllAssetsAtPath(path);
|
||||
|
||||
foreach (var obj in objs)
|
||||
{
|
||||
if (obj != null && AssetDatabase.IsMainAsset(obj))
|
||||
return obj as TimelineAsset;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void PushTimelineIntoRecorder()
|
||||
{
|
||||
if (m_Timeline == null)
|
||||
return;
|
||||
|
||||
var settings = m_SettingsEditor.target as FrameRecorderSettings;
|
||||
settings.m_DurationMode = DurationMode.Indefinite;
|
||||
|
||||
// Time
|
||||
settings.m_FrameRate = m_Timeline.editorSettings.fps;
|
||||
}
|
||||
|
||||
void PushRecorderIntoTimeline()
|
||||
{
|
||||
if (m_Timeline == null)
|
||||
return;
|
||||
|
||||
var settings = m_SettingsEditor.target as FrameRecorderSettings;
|
||||
settings.m_DurationMode = DurationMode.Indefinite;
|
||||
|
||||
// Time
|
||||
m_Timeline.editorSettings.fps = (float)settings.m_FrameRate;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c7fe8472aebc45f4b93027b60a4003b3
|
||||
timeCreated: 1491415344
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Recorder.FrameRecorder;
|
||||
|
||||
namespace Assets.Unity.FrameRecorder.Scripts.Editor
|
||||
{
|
||||
interface IRecorderSelectorTarget
|
||||
{
|
||||
string recorderCategory { get; set; }
|
||||
string selectedRecorder { get; }
|
||||
void SetRecorder(Type newRecorderType);
|
||||
}
|
||||
|
||||
class RecorderSelector
|
||||
{
|
||||
IRecorderSelectorTarget m_target;
|
||||
string[] categoryRecorders;
|
||||
|
||||
public RecorderSelector(IRecorderSelectorTarget target)
|
||||
{
|
||||
m_target = target;
|
||||
}
|
||||
|
||||
int GetCategoryIndex()
|
||||
{
|
||||
var categories = RecordersInventory.availableCategories;
|
||||
for (int i = 0; i < categories.Length; i++)
|
||||
if (categories[i] == m_target.recorderCategory)
|
||||
return i;
|
||||
|
||||
if (categories.Length > 0)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SetCategoryFromIndex(int index)
|
||||
{
|
||||
if (index >= 0)
|
||||
{
|
||||
m_target.recorderCategory = RecordersInventory.availableCategories[index];
|
||||
categoryRecorders = RecordersInventory.recordersByCategory[m_target.recorderCategory]
|
||||
.Select(x => x.displayName)
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_target.recorderCategory = string.Empty;
|
||||
categoryRecorders = new string[0];
|
||||
}
|
||||
|
||||
return index >= 0;
|
||||
}
|
||||
|
||||
int GetRecorderIndex()
|
||||
{
|
||||
if (!RecordersInventory.recordersByCategory.ContainsKey(m_target.recorderCategory))
|
||||
return -1;
|
||||
|
||||
var categoryRecorders = RecordersInventory.recordersByCategory[m_target.recorderCategory];
|
||||
for (int i = 0; i < categoryRecorders.Count; i++)
|
||||
if (categoryRecorders[i].recorder.AssemblyQualifiedName == m_target.selectedRecorder)
|
||||
return i;
|
||||
|
||||
|
||||
if (categoryRecorders.Count > 0)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
Type GetRecorderFromIndex(int index)
|
||||
{
|
||||
if (index >= 0)
|
||||
return RecordersInventory.recordersByCategory[m_target.recorderCategory][index].recorder;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OnGui()
|
||||
{
|
||||
// Group selection
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
SetCategoryFromIndex(EditorGUILayout.Popup("Record what:", GetCategoryIndex(), RecordersInventory.availableCategories));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// Recorder in group selection
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
var newIndex = EditorGUILayout.Popup("Using Recorder:", GetRecorderIndex(), categoryRecorders);
|
||||
m_target.SetRecorder(GetRecorderFromIndex(newIndex));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b94e4c4dfdb07cb43b93121a598b6e00
|
||||
timeCreated: 1493839035
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,222 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Recorder.FrameRecorder.Utilities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Recorder.FrameRecorder;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
|
||||
namespace UnityEditor.Recorder.FrameRecorder
|
||||
{
|
||||
public class RecorderEditorAttribute : Attribute
|
||||
{
|
||||
public Type recorderType { get; private set; }
|
||||
|
||||
public RecorderEditorAttribute(Type type)
|
||||
{
|
||||
recorderType = type;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class RecorderSettingsEditor : Editor
|
||||
{
|
||||
static SortedDictionary<string, Type> m_Editors;
|
||||
|
||||
internal LayoutHelper m_LayoutHelper;
|
||||
|
||||
public virtual Vector2 minSize
|
||||
{
|
||||
get { return new Vector2(0, 0); }
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
m_LayoutHelper = new LayoutHelper(GUILayout.Width(175));
|
||||
}
|
||||
|
||||
protected virtual void OnDisable() {}
|
||||
|
||||
protected virtual void Awake() {}
|
||||
|
||||
public bool isValid
|
||||
{
|
||||
get { return (target as FrameRecorderSettings).isValid; }
|
||||
}
|
||||
|
||||
public bool showBounds { get; set; }
|
||||
|
||||
bool m_FoldoutInput = true;
|
||||
bool m_FoldoutEncoder = true;
|
||||
bool m_FoldoutTime = true;
|
||||
bool m_FoldoutBounds = true;
|
||||
bool m_FoldoutOutput = true;
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
m_LayoutHelper.indentLevel = 0;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
serializedObject.Update();
|
||||
|
||||
OnInputGroupGui();
|
||||
OnOutputGroupGui();
|
||||
OnEncodingGroupGui();
|
||||
OnTimeGroupGui();
|
||||
OnBoundsGroupGui();
|
||||
OnExtraGroupsGui();
|
||||
|
||||
var settingsObj = serializedObject.targetObject as FrameRecorderSettings;
|
||||
m_LayoutHelper.AddBoolProperty("Verbose logging", serializedObject, () => settingsObj.m_Verbose);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
EditorGUI.EndChangeCheck();
|
||||
}
|
||||
|
||||
protected virtual void OnInputGui()
|
||||
{
|
||||
m_LayoutHelper.AddIntProperty("Capture every n'th frame", serializedObject, () => (target as FrameRecorderSettings).m_CaptureEveryNthFrame);
|
||||
}
|
||||
|
||||
protected virtual void OnOutputGui()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnEncodingGui()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnTimeGui()
|
||||
{
|
||||
var settingsObj = serializedObject.targetObject as FrameRecorderSettings;
|
||||
|
||||
m_LayoutHelper.AddEnumProperty("Frame rate mode", serializedObject, () => settingsObj.m_FrameRateMode);
|
||||
m_LayoutHelper.indentLevel++;
|
||||
var label = settingsObj.m_FrameRateMode == FrameRateMode.Fixed ? "Frame rate" : "Max frame rate";
|
||||
m_LayoutHelper.AddDoubleProperty(label, serializedObject, () => settingsObj.m_FrameRate);
|
||||
m_LayoutHelper.indentLevel--;
|
||||
}
|
||||
|
||||
protected virtual void OnBounds()
|
||||
{
|
||||
var settingsObj = serializedObject.targetObject as FrameRecorderSettings;
|
||||
|
||||
m_LayoutHelper.AddEnumProperty("Recording Duration", serializedObject, () => settingsObj.m_DurationMode);
|
||||
|
||||
m_LayoutHelper.indentLevel++;
|
||||
switch (settingsObj.m_DurationMode)
|
||||
{
|
||||
case DurationMode.Indefinite:
|
||||
break;
|
||||
case DurationMode.SingleFrame:
|
||||
{
|
||||
m_LayoutHelper.AddIntProperty("Frame", serializedObject, () => settingsObj.m_StartFrame, "Tooltip");
|
||||
settingsObj.m_EndFrame = settingsObj.m_StartFrame;
|
||||
break;
|
||||
}
|
||||
case DurationMode.FrameInterval:
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
m_LayoutHelper.AddPropertyLabel("Frames");
|
||||
m_LayoutHelper.AddIntProperty(serializedObject, () => settingsObj.m_StartFrame);
|
||||
m_LayoutHelper.AddIntProperty(serializedObject, () => settingsObj.m_EndFrame);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
break;
|
||||
}
|
||||
case DurationMode.TimeInterval:
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
m_LayoutHelper.AddPropertyLabel("Time");
|
||||
m_LayoutHelper.AddFloatProperty(serializedObject, () => settingsObj.m_StartTime);
|
||||
m_LayoutHelper.AddFloatProperty(serializedObject, () => settingsObj.m_EndTime);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_LayoutHelper.indentLevel--;
|
||||
}
|
||||
|
||||
|
||||
protected virtual void OnInputGroupGui()
|
||||
{
|
||||
m_FoldoutInput = EditorGUILayout.Foldout(m_FoldoutInput, "Input");
|
||||
if (m_FoldoutInput)
|
||||
{
|
||||
m_LayoutHelper.indentLevel++;
|
||||
OnInputGui();
|
||||
m_LayoutHelper.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnOutputGroupGui()
|
||||
{
|
||||
m_FoldoutOutput = EditorGUILayout.Foldout(m_FoldoutOutput, "Output");
|
||||
if (m_FoldoutOutput)
|
||||
{
|
||||
m_LayoutHelper.indentLevel++;
|
||||
OnOutputGui();
|
||||
m_LayoutHelper.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnEncodingGroupGui()
|
||||
{
|
||||
m_FoldoutEncoder = EditorGUILayout.Foldout(m_FoldoutEncoder, "Encoding");
|
||||
if (m_FoldoutEncoder)
|
||||
{
|
||||
m_LayoutHelper.indentLevel++;
|
||||
OnEncodingGui();
|
||||
m_LayoutHelper.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnTimeGroupGui()
|
||||
{
|
||||
m_FoldoutTime = EditorGUILayout.Foldout(m_FoldoutTime, "Time");
|
||||
if (m_FoldoutTime)
|
||||
{
|
||||
m_LayoutHelper.indentLevel++;
|
||||
OnTimeGui();
|
||||
m_LayoutHelper.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnBoundsGroupGui()
|
||||
{
|
||||
if (showBounds)
|
||||
{
|
||||
m_FoldoutBounds = EditorGUILayout.Foldout(m_FoldoutBounds, "Bounds / Limits");
|
||||
if (m_FoldoutBounds)
|
||||
{
|
||||
m_LayoutHelper.indentLevel++;
|
||||
OnBounds();
|
||||
m_LayoutHelper.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnExtraGroupsGui()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private static void Init()
|
||||
{
|
||||
if (m_Editors != null)
|
||||
return;
|
||||
|
||||
m_Editors = new SortedDictionary<string, Type>();
|
||||
foreach (var editor in ClassHelpers.FilterByAttribute<RecorderEditorAttribute>())
|
||||
{
|
||||
var attrib = editor.Value[0];
|
||||
m_Editors.Add((attrib as RecorderEditorAttribute).recorderType.FullName, editor.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public static Type FindEditorForRecorder(Type recorder)
|
||||
{
|
||||
Init();
|
||||
return m_Editors.ContainsKey(recorder.FullName) ? m_Editors[recorder.FullName] : null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c2d3ad15b5919624bbfcb237e18fd2ec
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Assets.Unity.FrameRecorder.Scripts.Editor;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Recorder.FrameRecorder;
|
||||
|
||||
namespace UnityEditor.Recorder.FrameRecorder
|
||||
{
|
||||
public class RecorderWindow : EditorWindow, IRecorderSelectorTarget
|
||||
{
|
||||
[SerializeField] string m_RecorderTypeName;
|
||||
[SerializeField] string m_RecorderCategory;
|
||||
[SerializeField] RecorderSettingsEditor m_SettingsEditor;
|
||||
bool m_PendingStartRecording;
|
||||
RecorderSelector m_recorderSelector;
|
||||
|
||||
Type recorderType
|
||||
{
|
||||
get { return Type.GetType(m_RecorderTypeName); }
|
||||
set { m_RecorderTypeName = value == null ? string.Empty : value.AssemblyQualifiedName; }
|
||||
}
|
||||
|
||||
public static void ShowAndPreselectCategory( string category )
|
||||
{
|
||||
var window = GetWindow(typeof(RecorderWindow), false, "Recorder") as RecorderWindow;
|
||||
|
||||
if( RecordersInventory.recordersByCategory.ContainsKey(category) )
|
||||
window.m_RecorderCategory = category;
|
||||
}
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
m_recorderSelector = new RecorderSelector(this);
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (m_PendingStartRecording && EditorApplication.isPlaying)
|
||||
DelayedStartRecording();
|
||||
|
||||
var size = new Vector2(300, 400);
|
||||
|
||||
using (new EditorGUI.DisabledScope(EditorApplication.isPlaying))
|
||||
m_recorderSelector.OnGui();
|
||||
|
||||
if (m_SettingsEditor != null)
|
||||
{
|
||||
m_SettingsEditor.showBounds = true;
|
||||
using (new EditorGUI.DisabledScope(EditorApplication.isPlaying))
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
var editorMinSize = m_SettingsEditor.minSize;
|
||||
if (editorMinSize.x > minSize.x) size.x = editorMinSize.x;
|
||||
if (editorMinSize.y > minSize.y) size.y = editorMinSize.y;
|
||||
|
||||
m_SettingsEditor.OnInspectorGUI();
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
RecordButton();
|
||||
}
|
||||
|
||||
minSize = size;
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
{
|
||||
StopRecording();
|
||||
UnityHelpers.Destroy(m_SettingsEditor);
|
||||
}
|
||||
|
||||
void RecordButton()
|
||||
{
|
||||
var settings = (FrameRecorderSettings)m_SettingsEditor.target;
|
||||
var recorderGO = FrameRecorderGOControler.FindRecorder(settings);
|
||||
|
||||
if (recorderGO == null)
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(!m_SettingsEditor.isValid))
|
||||
{
|
||||
if (GUILayout.Button("Start Recording"))
|
||||
StartRecording();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("Stop Recording"))
|
||||
StopRecording();
|
||||
}
|
||||
}
|
||||
|
||||
void StartRecording()
|
||||
{
|
||||
if (!EditorApplication.isPlaying || EditorApplication.isPlaying)
|
||||
{
|
||||
m_PendingStartRecording = true;
|
||||
EditorApplication.isPlaying = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
StartRecording(false);
|
||||
}
|
||||
|
||||
void DelayedStartRecording()
|
||||
{
|
||||
m_PendingStartRecording = false;
|
||||
StartRecording(true);
|
||||
}
|
||||
|
||||
void StartRecording(bool autoExitPlayMode)
|
||||
{
|
||||
var settings = (FrameRecorderSettings)m_SettingsEditor.target;
|
||||
var go = FrameRecorderGOControler.HookupRecorder(settings);
|
||||
var session = new RecordingSession()
|
||||
{
|
||||
m_Recorder = RecordersInventory.InstantiateRecorder(recorderType, settings),
|
||||
m_RecorderGO = go,
|
||||
m_RecordingStartTS = Time.time / Time.timeScale,
|
||||
m_FrameIndex = 0
|
||||
};
|
||||
|
||||
var component = go.AddComponent<RecorderComponent>();
|
||||
component.session = session;
|
||||
component.autoExitPlayMode = autoExitPlayMode;
|
||||
|
||||
session.BeginRecording();
|
||||
}
|
||||
|
||||
void StopRecording()
|
||||
{
|
||||
if (m_SettingsEditor != null)
|
||||
{
|
||||
var settings = (FrameRecorderSettings)m_SettingsEditor.target;
|
||||
if (settings != null)
|
||||
{
|
||||
var recorderGO = FrameRecorderGOControler.FindRecorder(settings);
|
||||
if (recorderGO != null)
|
||||
{
|
||||
UnityHelpers.Destroy(recorderGO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRecorder(Type newRecorderType)
|
||||
{
|
||||
if (newRecorderType == null || (m_SettingsEditor != null && recorderType == newRecorderType))
|
||||
return;
|
||||
|
||||
recorderType = newRecorderType;
|
||||
|
||||
var editorType = RecorderSettingsEditor.FindEditorForRecorder(recorderType);
|
||||
if (editorType != null)
|
||||
{
|
||||
if (m_SettingsEditor != null)
|
||||
{
|
||||
UnityHelpers.Destroy(m_SettingsEditor.target);
|
||||
UnityHelpers.Destroy(m_SettingsEditor);
|
||||
m_SettingsEditor = null;
|
||||
}
|
||||
|
||||
var settings = RecordersInventory.CreateRecorderSettings(recorderType, "N/A", "RecorderWindow");
|
||||
m_SettingsEditor = UnityEditor.Editor.CreateEditor(settings, editorType) as RecorderSettingsEditor;
|
||||
m_SettingsEditor.hideFlags = HideFlags.DontUnloadUnusedAsset; // <-- this means life time is manually managed by this class!!
|
||||
}
|
||||
else
|
||||
Debug.LogError(string.Format("No editor class declared for recorder of type " + newRecorderType.FullName));
|
||||
}
|
||||
|
||||
public string recorderCategory
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_RecorderCategory;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (m_RecorderCategory != value)
|
||||
{
|
||||
m_RecorderCategory = value;
|
||||
m_SettingsEditor = null;
|
||||
recorderType = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string selectedRecorder
|
||||
{
|
||||
get { return m_RecorderTypeName; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d99962793b726bf4881e4b1719950d8f
|
||||
timeCreated: 1491415344
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d548afd490f5254c9ca1d8b802ddff3
|
||||
folderAsset: yes
|
||||
timeCreated: 1491415339
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,259 @@
|
|||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Recorder.FrameRecorder.Utilities
|
||||
{
|
||||
class LayoutHelper
|
||||
{
|
||||
public delegate T OnValueChangedDelegate<T>(T oldValue, T newValue);
|
||||
|
||||
private string[] m_Indents = new[] { "", " ", " ", " ", " "};
|
||||
GUILayoutOption m_LableLayoutOption;
|
||||
|
||||
public LayoutHelper(GUILayoutOption lableLayoutOption)
|
||||
{
|
||||
m_LableLayoutOption = lableLayoutOption;
|
||||
}
|
||||
|
||||
int m_IndentLevel;
|
||||
|
||||
|
||||
public int indentLevel
|
||||
{
|
||||
get { return m_IndentLevel; }
|
||||
set
|
||||
{
|
||||
m_IndentLevel = value;
|
||||
if (m_IndentLevel < 0) m_IndentLevel = 0;
|
||||
if (m_IndentLevel >= m_Indents.Length) m_IndentLevel = m_Indents.Length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string indentation
|
||||
{
|
||||
get { return m_Indents[m_IndentLevel]; }
|
||||
}
|
||||
|
||||
public void AddPropertyLabel(string text)
|
||||
{
|
||||
GUILayout.Label(m_Indents[m_IndentLevel] + text, m_LableLayoutOption);
|
||||
}
|
||||
|
||||
public void AddPropertyLabel(string label, string tooltip)
|
||||
{
|
||||
GUILayout.Label(new GUIContent(m_Indents[m_IndentLevel] + label, tooltip), m_LableLayoutOption);
|
||||
}
|
||||
|
||||
public bool AddEnumProperty(string label, SerializedObject serObj, Expression<Func<object>> propertySelector, string tooltip = "")
|
||||
{
|
||||
var property = serObj.FindProperty(propertySelector);
|
||||
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
AddPropertyLabel(label, tooltip);
|
||||
|
||||
var selectionFromInspector = property.intValue;
|
||||
var actualSelected = EditorGUILayout.Popup(selectionFromInspector, property.enumDisplayNames);
|
||||
var changed = actualSelected != property.intValue;
|
||||
property.intValue = actualSelected;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public bool AddFlagEnumProperty(string label, SerializedObject serObj, Expression<Func<object>> propertySelector, string tooltip = "")
|
||||
{
|
||||
var property = serObj.FindProperty(propertySelector);
|
||||
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
AddPropertyLabel(label, tooltip);
|
||||
|
||||
var selectionFromInspector = (int)Math.Log(property.intValue, 2);
|
||||
var actualSelected = 1 << EditorGUILayout.Popup(selectionFromInspector, property.enumDisplayNames);
|
||||
var changed = actualSelected != property.intValue;
|
||||
property.intValue = actualSelected;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public bool AddEnumProperty(string label, SerializedObject serObj, Expression<Func<object>> propertySelector, string[] values, string tooltip = "")
|
||||
{
|
||||
var property = serObj.FindProperty(propertySelector);
|
||||
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
AddPropertyLabel(label, tooltip);
|
||||
|
||||
var selectionFromInspector = property.intValue;
|
||||
var actualSelected = EditorGUILayout.Popup(selectionFromInspector, values);
|
||||
var changed = actualSelected != property.intValue;
|
||||
property.intValue = actualSelected;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public bool AddStringProperty(string label, SerializedObject serObj, Expression<Func<object>> propertySelector, string tooltip = "")
|
||||
{
|
||||
var property = serObj.FindProperty(propertySelector);
|
||||
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
AddPropertyLabel(label);
|
||||
|
||||
var orgValue = property.stringValue;
|
||||
var newValue = EditorGUILayout.TextField(new GUIContent("", tooltip), orgValue);
|
||||
var changed = orgValue != newValue;
|
||||
property.stringValue = newValue;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public bool AddIntProperty(string label, SerializedProperty property, string tooltip = "")
|
||||
{
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
AddPropertyLabel(label);
|
||||
|
||||
var orgValue = property.intValue;
|
||||
var newValue = EditorGUILayout.IntField(new GUIContent("", tooltip), orgValue);
|
||||
var changed = orgValue != newValue;
|
||||
property.intValue = newValue;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public bool AddIntProperty(string label, SerializedObject serObj, Expression<Func<object>> propertySelector, string tooltip = "")
|
||||
{
|
||||
return AddIntProperty(label, serObj.FindProperty(propertySelector), tooltip);
|
||||
}
|
||||
|
||||
public bool AddIntProperty(SerializedProperty property)
|
||||
{
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
var orgValue = property.intValue;
|
||||
var newValue = EditorGUILayout.IntField(orgValue);
|
||||
var changed = orgValue != newValue;
|
||||
property.intValue = newValue;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public bool AddFloatProperty(SerializedObject serObj, Expression<Func<object>> propertySelector)
|
||||
{
|
||||
return AddFloatProperty(serObj.FindProperty(propertySelector));
|
||||
}
|
||||
|
||||
public bool AddFloatProperty(SerializedProperty property)
|
||||
{
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
var orgValue = property.floatValue;
|
||||
var newValue = EditorGUILayout.FloatField(orgValue);
|
||||
var changed = orgValue != newValue;
|
||||
property.floatValue = newValue;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public bool AddIntProperty(SerializedObject serObj, Expression<Func<object>> propertySelector)
|
||||
{
|
||||
return AddIntProperty(serObj.FindProperty(propertySelector));
|
||||
}
|
||||
|
||||
public bool AddIntProperty(SerializedProperty parentSerProp, Expression<Func<object>> propertySelector)
|
||||
{
|
||||
return AddIntProperty(parentSerProp.FindPropertyRelative(propertySelector));
|
||||
}
|
||||
|
||||
public bool AddFloatProperty(string label, SerializedObject serObj, Expression<Func<object>> propertySelector, string tooltip = "")
|
||||
{
|
||||
var property = serObj.FindProperty(propertySelector);
|
||||
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
AddPropertyLabel(label);
|
||||
|
||||
var orgValue = property.floatValue;
|
||||
var newValue = EditorGUILayout.FloatField(new GUIContent("", tooltip), orgValue);
|
||||
var changed = orgValue != newValue;
|
||||
property.floatValue = newValue;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public bool AddDoubleProperty(string label, SerializedObject serObj, Expression<Func<object>> propertySelector, string tooltip = "")
|
||||
{
|
||||
var property = serObj.FindProperty(propertySelector);
|
||||
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
AddPropertyLabel(label);
|
||||
|
||||
var orgValue = property.doubleValue;
|
||||
var newValue = EditorGUILayout.DoubleField(new GUIContent("", tooltip), orgValue);
|
||||
var changed = orgValue != newValue;
|
||||
property.doubleValue = newValue;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public bool AddBoolProperty(string label, SerializedObject serObj, Expression<Func<object>> propertySelector, string tooltip = "")
|
||||
{
|
||||
var property = serObj.FindProperty(propertySelector);
|
||||
|
||||
var ourRect = EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.BeginProperty(ourRect, GUIContent.none, property);
|
||||
|
||||
AddPropertyLabel(label);
|
||||
|
||||
var orgValue = property.boolValue;
|
||||
var newValue = EditorGUILayout.Toggle(new GUIContent("", tooltip), orgValue);
|
||||
var changed = orgValue != newValue;
|
||||
property.boolValue = newValue;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b25434794c2520040b7ec0687028cb7e
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace UnityEditor.Recorder.FrameRecorder.Utilities
|
||||
{
|
||||
public static class SerializableObjHelper
|
||||
{
|
||||
public static SerializedProperty FindProperty(this SerializedObject obj, Expression<Func<object>> exp)
|
||||
{
|
||||
var body = exp.Body as MemberExpression;
|
||||
if (body == null)
|
||||
{
|
||||
var ubody = (UnaryExpression)exp.Body;
|
||||
body = ubody.Operand as MemberExpression;
|
||||
}
|
||||
|
||||
var name = body.Member.Name;
|
||||
|
||||
return obj.FindProperty(name);
|
||||
}
|
||||
|
||||
public static SerializedProperty FindPropertyRelative(this SerializedProperty obj, Expression<Func<object>> exp)
|
||||
{
|
||||
var body = exp.Body as MemberExpression;
|
||||
if (body == null)
|
||||
{
|
||||
var ubody = (UnaryExpression)exp.Body;
|
||||
body = ubody.Operand as MemberExpression;
|
||||
}
|
||||
|
||||
var name = body.Member.Name;
|
||||
|
||||
return obj.FindPropertyRelative(name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b91f080b208afff4d94678e466eeecc4
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 465980b32e42e4a439d49f4d4bf0ef31
|
||||
folderAsset: yes
|
||||
timeCreated: 1491417212
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6cbec5a6a20c2074e9b44e94a96092d6
|
||||
folderAsset: yes
|
||||
timeCreated: 1491415339
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,158 @@
|
|||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.DataSource
|
||||
{
|
||||
public class CameraAsRenderTexture : RenderTextureSource
|
||||
{
|
||||
Shader m_shCopy;
|
||||
Material m_mat_copy;
|
||||
Mesh m_quad;
|
||||
CommandBuffer m_cb;
|
||||
Camera m_Camera;
|
||||
bool m_cameraChanged;
|
||||
|
||||
protected int m_Width;
|
||||
protected int m_Height;
|
||||
protected EImageSizeMode m_SizeMode;
|
||||
|
||||
public Camera TargetCamera
|
||||
{
|
||||
get { return m_Camera; }
|
||||
|
||||
set
|
||||
{
|
||||
if (m_Camera != value)
|
||||
{
|
||||
ReleaseCamera();
|
||||
m_Camera = value;
|
||||
m_cameraChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Shader CopyShader
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_shCopy == null)
|
||||
{
|
||||
// TODO: make this Non Editor compatible
|
||||
// Figure out where this shader should reside.
|
||||
m_shCopy = AssetDatabase.LoadAssetAtPath<Shader>(AssetDatabase.GUIDToAssetPath("55d39f733f4029f4cbc92b5c2279e15b"));
|
||||
}
|
||||
return m_shCopy;
|
||||
}
|
||||
|
||||
set { m_shCopy = value; }
|
||||
}
|
||||
|
||||
public CameraAsRenderTexture(EImageSizeMode sizeMode, int width, int height)
|
||||
{
|
||||
m_SizeMode = sizeMode;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_quad = CreateFullscreenQuad();
|
||||
}
|
||||
|
||||
public void PrepareNewFrame()
|
||||
{
|
||||
// initialize scratch buffer
|
||||
var newTexture = PrepFrameRenderTexture();
|
||||
|
||||
// initialize command buffer
|
||||
if (m_Camera != null && m_cameraChanged || newTexture)
|
||||
{
|
||||
if (m_cb != null)
|
||||
{
|
||||
m_Camera.RemoveCommandBuffer(CameraEvent.AfterEverything, m_cb);
|
||||
m_cb.Release();
|
||||
}
|
||||
|
||||
// TODO: This should not be here!!!
|
||||
m_mat_copy = new Material(CopyShader);
|
||||
if (m_Camera.targetTexture != null)
|
||||
m_mat_copy.EnableKeyword("OFFSCREEN");
|
||||
|
||||
var tid = Shader.PropertyToID("_TmpFrameBuffer");
|
||||
m_cb = new CommandBuffer { name = "Frame Recorder: copy frame buffer" };
|
||||
m_cb.GetTemporaryRT(tid, -1, -1, 0, FilterMode.Bilinear);
|
||||
m_cb.Blit(BuiltinRenderTextureType.CurrentActive, tid);
|
||||
m_cb.SetRenderTarget(buffer);
|
||||
m_cb.DrawMesh(m_quad, Matrix4x4.identity, m_mat_copy, 0, 0);
|
||||
m_cb.ReleaseTemporaryRT(tid);
|
||||
m_Camera.AddCommandBuffer(CameraEvent.AfterEverything, m_cb);
|
||||
|
||||
m_cameraChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
ReleaseCamera();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected virtual void ReleaseCamera()
|
||||
{
|
||||
if (m_cb != null)
|
||||
{
|
||||
if (m_Camera != null)
|
||||
m_Camera.RemoveCommandBuffer(CameraEvent.AfterEverything, m_cb);
|
||||
|
||||
m_cb.Release();
|
||||
m_cb = null;
|
||||
}
|
||||
|
||||
if (m_mat_copy != null)
|
||||
UnityHelpers.Destroy(m_mat_copy);
|
||||
}
|
||||
|
||||
bool PrepFrameRenderTexture()
|
||||
{
|
||||
var height = (int)(m_Width / m_Camera.aspect);
|
||||
if (buffer != null)
|
||||
{
|
||||
if (buffer.IsCreated() && buffer.width == m_Width && buffer.height == height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ReleaseBuffer();
|
||||
}
|
||||
|
||||
buffer = new RenderTexture(m_Width, height, 0, RenderTextureFormat.ARGB32)
|
||||
{
|
||||
wrapMode = TextureWrapMode.Repeat
|
||||
};
|
||||
buffer.Create();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Mesh CreateFullscreenQuad()
|
||||
{
|
||||
var vertices = new Vector3[4]
|
||||
{
|
||||
new Vector3(1.0f, 1.0f, 0.0f),
|
||||
new Vector3(-1.0f, 1.0f, 0.0f),
|
||||
new Vector3(-1.0f, -1.0f, 0.0f),
|
||||
new Vector3(1.0f, -1.0f, 0.0f),
|
||||
};
|
||||
var indices = new[] { 0, 1, 2, 2, 3, 0 };
|
||||
|
||||
var r = new Mesh
|
||||
{
|
||||
vertices = vertices,
|
||||
triangles = indices
|
||||
};
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 852b7afeb4df2254e81cc4c6d11ca313
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.DataSource
|
||||
{
|
||||
public class DisplayAsRenderTexture : CameraAsRenderTexture
|
||||
{
|
||||
public int m_DisplayID;
|
||||
|
||||
public void PrepareNewFrame(RecordingSession session)
|
||||
{
|
||||
if (TargetCamera != null && TargetCamera.targetDisplay != m_DisplayID)
|
||||
TargetCamera = null;
|
||||
|
||||
if (TargetCamera == null)
|
||||
{
|
||||
var displayGO = new GameObject();
|
||||
displayGO.name = "CameraHostGO-" + displayGO.GetInstanceID();
|
||||
displayGO.transform.parent = session.m_RecorderGO.transform;
|
||||
var camera = displayGO.AddComponent<Camera>();
|
||||
camera.clearFlags = CameraClearFlags.Nothing;
|
||||
camera.cullingMask = 0;
|
||||
camera.renderingPath = RenderingPath.DeferredShading;
|
||||
camera.targetDisplay = m_DisplayID;
|
||||
camera.rect = new Rect(0, 0, 1, 1);
|
||||
camera.depth = float.MaxValue;
|
||||
|
||||
TargetCamera = camera;
|
||||
}
|
||||
|
||||
base.PrepareNewFrame();
|
||||
}
|
||||
|
||||
public DisplayAsRenderTexture(int width)
|
||||
: base( EImageSizeMode.Width, width, 0) {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9eef97e3b03eb7d489aba82d5d15fb99
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.DataSource
|
||||
{
|
||||
public class GameViewAsRenderTexture : CameraAsRenderTexture
|
||||
{
|
||||
GameViewWindow m_GameView;
|
||||
|
||||
public void PrepareNewFrame(RecordingSession session)
|
||||
{
|
||||
if (TargetCamera == null)
|
||||
{
|
||||
var displayGO = new GameObject();
|
||||
displayGO.name = "CameraHostGO-" + displayGO.GetInstanceID();
|
||||
displayGO.transform.parent = session.m_RecorderGO.transform;
|
||||
var camera = displayGO.AddComponent<Camera>();
|
||||
camera.clearFlags = CameraClearFlags.Nothing;
|
||||
camera.cullingMask = 0;
|
||||
camera.renderingPath = RenderingPath.DeferredShading;
|
||||
camera.targetDisplay = 0;
|
||||
camera.rect = new Rect(0, 0, 1, 1);
|
||||
camera.depth = float.MaxValue;
|
||||
|
||||
TargetCamera = camera;
|
||||
}
|
||||
|
||||
base.PrepareNewFrame();
|
||||
}
|
||||
|
||||
public GameViewAsRenderTexture( EImageSizeMode sizeMode, int width, int height)
|
||||
: base(sizeMode, width, height)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void BeginRecording()
|
||||
{
|
||||
m_GameView = new GameViewWindow();
|
||||
m_GameView.FullScreenGameWindow( m_SizeMode, m_Width, m_Height );
|
||||
m_Width = (int)m_GameView.size.x;
|
||||
m_Height = (int)m_GameView.size.y;
|
||||
}
|
||||
|
||||
public void EndRecording()
|
||||
{
|
||||
if (m_GameView != null)
|
||||
m_GameView.RestoreGameWindow();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f1701eab2c131b34ebbfd0f24ee466b2
|
||||
timeCreated: 1493928434
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.DataSource
|
||||
{
|
||||
public class RecorderSource : IDisposable
|
||||
{
|
||||
public int SourceID { get; set; }
|
||||
|
||||
~RecorderSource()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9f956c0b0f15ce74aac4600909d4e55f
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.DataSource
|
||||
{
|
||||
public abstract class RenderTextureSource : RecorderSource
|
||||
{
|
||||
public RenderTexture buffer { get; set; }
|
||||
|
||||
public RenderTexture UnlinkBuffer()
|
||||
{
|
||||
var temp = buffer;
|
||||
buffer = null;
|
||||
return temp;
|
||||
}
|
||||
|
||||
public void ReleaseBuffer()
|
||||
{
|
||||
if (buffer != null)
|
||||
{
|
||||
buffer.Release();
|
||||
buffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
ReleaseBuffer();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1dd8c8968d3848743a824ed5191b2805
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||
public class FrameRecorderClassAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ca62b38426adb1d47ad6cd6c94001b6a
|
||||
timeCreated: 1491415344
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder
|
||||
{
|
||||
public class FrameRecorderGOControler
|
||||
{
|
||||
const string k_HostGoName = "UnityEngine.Recorder.FrameRecorder";
|
||||
|
||||
public static GameObject GetGameObject()
|
||||
{
|
||||
return GameObject.Find(k_HostGoName) ?? new GameObject(k_HostGoName);
|
||||
}
|
||||
|
||||
public static GameObject GetSettingsRoot()
|
||||
{
|
||||
var root = GetGameObject();
|
||||
var settingsTr = root.transform.Find("Settings");
|
||||
GameObject settingsGO;
|
||||
if (settingsTr == null)
|
||||
{
|
||||
settingsGO = new GameObject("Settings");
|
||||
settingsGO.transform.parent = root.transform;
|
||||
}
|
||||
else
|
||||
settingsGO = settingsTr.gameObject;
|
||||
|
||||
return settingsGO;
|
||||
}
|
||||
|
||||
public static GameObject GetRecordersRoot()
|
||||
{
|
||||
var root = GetGameObject();
|
||||
var settingsTr = root.transform.Find("Recording");
|
||||
GameObject settingsGO;
|
||||
if (settingsTr == null)
|
||||
{
|
||||
settingsGO = new GameObject("Recording");
|
||||
settingsGO.transform.parent = root.transform;
|
||||
}
|
||||
else
|
||||
settingsGO = settingsTr.gameObject;
|
||||
|
||||
return settingsGO;
|
||||
}
|
||||
|
||||
public static GameObject HookupRecorder(FrameRecorderSettings settings)
|
||||
{
|
||||
var ctrl = GetRecordersRoot();
|
||||
|
||||
var recorderGO = new GameObject(settings.m_UniqueID);
|
||||
recorderGO.transform.parent = ctrl.transform;
|
||||
|
||||
return recorderGO;
|
||||
}
|
||||
|
||||
public static GameObject FindRecorder(FrameRecorderSettings settings)
|
||||
{
|
||||
var ctrl = GetRecordersRoot();
|
||||
var go = ctrl.transform.Find(settings.m_UniqueID);
|
||||
return go == null ? null : go.gameObject;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e378e9c2cad5a7e48a6931f63edd1421
|
||||
timeCreated: 1491415344
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder
|
||||
{
|
||||
public enum EImageSourceType
|
||||
{
|
||||
GameDisplay,
|
||||
SceneView,
|
||||
MainCamera,
|
||||
TaggedCamera,
|
||||
RenderTexture
|
||||
}
|
||||
|
||||
public enum FrameRateMode
|
||||
{
|
||||
Variable,
|
||||
Fixed,
|
||||
}
|
||||
|
||||
public enum DurationMode
|
||||
{
|
||||
Indefinite,
|
||||
SingleFrame,
|
||||
FrameInterval,
|
||||
TimeInterval
|
||||
}
|
||||
|
||||
public class FrameRecorderSettings : MonoBehaviour
|
||||
{
|
||||
public string m_UniqueID;
|
||||
public string m_OwnerAssetID;
|
||||
public int m_CaptureEveryNthFrame = 1;
|
||||
public FrameRateMode m_FrameRateMode = FrameRateMode.Fixed;
|
||||
public double m_FrameRate = 24.0;
|
||||
public int m_StartFrame;
|
||||
public int m_EndFrame = 1000;
|
||||
public float m_StartTime = 0.0f;
|
||||
public float m_EndTime = 1.0f;
|
||||
public DurationMode m_DurationMode;
|
||||
public bool m_Verbose = false;
|
||||
|
||||
public virtual bool isValid
|
||||
{
|
||||
get { return m_FrameRate > 0; }
|
||||
}
|
||||
|
||||
public virtual void OnEnable()
|
||||
{
|
||||
GarbageCollect();
|
||||
|
||||
if (string.IsNullOrEmpty(m_UniqueID))
|
||||
m_UniqueID = string.Format("{0}-{1}", GetType().Name, Guid.NewGuid());
|
||||
}
|
||||
|
||||
public bool fixedDuration
|
||||
{
|
||||
get { return m_DurationMode != DurationMode.Indefinite; }
|
||||
}
|
||||
|
||||
void GarbageCollect()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (string.IsNullOrEmpty(m_OwnerAssetID))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var guid = new Guid(m_OwnerAssetID);
|
||||
if (guid == Guid.Empty)
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it's associated asset, if there was one, still exists. If it does not: cleanup / delete this setting
|
||||
if (string.IsNullOrEmpty(AssetDatabase.GUIDToAssetPath(m_OwnerAssetID)))
|
||||
{
|
||||
UnityHelpers.Destroy(gameObject);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 180842267b7175e4c9dedaf1f548db0f
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder
|
||||
{
|
||||
|
||||
public enum EImageSizeMode
|
||||
{
|
||||
Dynamic,
|
||||
FullScreen,
|
||||
Width,
|
||||
Custom
|
||||
}
|
||||
|
||||
public class ImageRecorderSettings : FrameRecorderSettings
|
||||
{
|
||||
public EImageSizeMode m_SizeMode = EImageSizeMode.Dynamic;
|
||||
public int m_Width = 1024;
|
||||
public int m_Height = 768;
|
||||
|
||||
public EImageSourceType m_InputType = EImageSourceType.GameDisplay;
|
||||
public int m_ScreenID = 0;
|
||||
public string m_CameraTag;
|
||||
|
||||
public override bool isValid
|
||||
{
|
||||
get { return base.isValid && m_Width > 0 && m_Height > 0; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f3941bff05f4e88479d3c4741b63bbf1
|
||||
timeCreated: 1491415344
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Recorder.FrameRecorder.DataSource;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder
|
||||
{
|
||||
public enum ERecordingSessionStage
|
||||
{
|
||||
BeginRecording,
|
||||
NewFrameStarting,
|
||||
NewFrameReady,
|
||||
FrameDone,
|
||||
EndRecording,
|
||||
}
|
||||
|
||||
public abstract class Recorder : ScriptableObject
|
||||
{
|
||||
double m_OriginalCaptureFrameRate;
|
||||
|
||||
public int recordedFramesCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Concept: container class for Recorder Source objects that assumes nothing on the contained source object
|
||||
///
|
||||
/// Motivation: let's recorders use any type of object as a source of data to record.
|
||||
/// </summary>
|
||||
protected struct BoxedSource
|
||||
{
|
||||
public System.Object m_Source;
|
||||
public SortedDictionary<ERecordingSessionStage, Action<RecordingSession>> m_StageHandlers;
|
||||
|
||||
public BoxedSource(System.Object source)
|
||||
{
|
||||
m_Source = source;
|
||||
m_StageHandlers = new SortedDictionary<ERecordingSessionStage, Action<RecordingSession>>();
|
||||
}
|
||||
|
||||
public void SignalNewStage(ERecordingSessionStage stage, RecordingSession session)
|
||||
{
|
||||
if (m_StageHandlers.ContainsKey(stage))
|
||||
m_StageHandlers[stage](session);
|
||||
}
|
||||
}
|
||||
protected List<BoxedSource> m_BoxedSources;
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
recordedFramesCount = 0;
|
||||
recording = false;
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract FrameRecorderSettings settings { get; set; }
|
||||
|
||||
// returns true if recording is starting. false if failed to begin recording or was already recording
|
||||
public virtual bool BeginRecording(RecordingSession session)
|
||||
{
|
||||
if (recording)
|
||||
return false;
|
||||
|
||||
if (settings.m_Verbose)
|
||||
Debug.Log(string.Format("Recorder {0} starting to record", GetType().Name));
|
||||
|
||||
m_OriginalCaptureFrameRate = Time.captureFramerate;
|
||||
var fixedRate = settings.m_FrameRateMode == FrameRateMode.Fixed ? (int)settings.m_FrameRate : m_OriginalCaptureFrameRate;
|
||||
if (fixedRate != m_OriginalCaptureFrameRate)
|
||||
{
|
||||
if (Time.captureFramerate > 0)
|
||||
Debug.LogWarning(string.Format("Frame Recorder {0} is set to record at a fixed rate and another component has already set a conflicting value for [Time.captureFramerate], new value being applied : {1}!", GetType().Name, fixedRate));
|
||||
Time.captureFramerate = (int)fixedRate;
|
||||
|
||||
if (settings.m_Verbose)
|
||||
Debug.Log("Frame recorder set fixed frame rate to " + fixedRate);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void EndRecording(RecordingSession ctx)
|
||||
{
|
||||
if (!recording)
|
||||
return;
|
||||
recording = false;
|
||||
|
||||
if (Time.captureFramerate != m_OriginalCaptureFrameRate)
|
||||
{
|
||||
Time.captureFramerate = (int)m_OriginalCaptureFrameRate;
|
||||
if (settings.m_Verbose)
|
||||
Debug.Log("Frame recorder resetting fixed frame rate to original value of " + m_OriginalCaptureFrameRate);
|
||||
}
|
||||
|
||||
foreach (var source in m_BoxedSources)
|
||||
{
|
||||
if (source.m_Source is IDisposable)
|
||||
(source.m_Source as IDisposable).Dispose();
|
||||
}
|
||||
|
||||
Debug.Log(string.Format("{0} recording stopped, total frame count: {1}", GetType().Name, recordedFramesCount));
|
||||
}
|
||||
|
||||
public abstract void RecordFrame(RecordingSession ctx);
|
||||
public virtual void PrepareNewFrame(RecordingSession ctx)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool SkipFrame(RecordingSession ctx)
|
||||
{
|
||||
return !recording || (ctx.m_FrameIndex % settings.m_CaptureEveryNthFrame) != 0;
|
||||
}
|
||||
|
||||
public bool recording { get; protected set; }
|
||||
|
||||
public void SignalSourcesOfStage(ERecordingSessionStage stage, RecordingSession session)
|
||||
{
|
||||
if (m_BoxedSources != null)
|
||||
{
|
||||
foreach (var boxedSource in m_BoxedSources)
|
||||
boxedSource.SignalNewStage(stage, session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 58fe471fc3009fb4d8cf266a5cc5a7a1
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class RecorderComponent : MonoBehaviour
|
||||
{
|
||||
public bool autoExitPlayMode { get; set; }
|
||||
public RecordingSession session { get; set; }
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (session != null && session.recording)
|
||||
{
|
||||
session.m_CurrentFrameStartTS = (Time.time / Time.timeScale) - session.m_RecordingStartTS;
|
||||
session.m_FrameIndex++;
|
||||
|
||||
session.PrepareNewFrame();
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator RecordFrame()
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
if (session != null && session.recording)
|
||||
{
|
||||
session.RecordFrame();
|
||||
|
||||
switch (session.m_Recorder.settings.m_DurationMode)
|
||||
{
|
||||
case DurationMode.Indefinite:
|
||||
break;
|
||||
case DurationMode.SingleFrame:
|
||||
enabled = false;
|
||||
break;
|
||||
case DurationMode.FrameInterval:
|
||||
if (session.m_FrameIndex >= session.settings.m_EndFrame)
|
||||
enabled = false;
|
||||
break;
|
||||
case DurationMode.TimeInterval:
|
||||
if (session.m_CurrentFrameStartTS >= session.settings.m_EndTime)
|
||||
enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
if (session != null && session.recording)
|
||||
{
|
||||
if (session.m_FrameIndex >= session.settings.m_StartFrame)
|
||||
{
|
||||
StartCoroutine(RecordFrame());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDisable()
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
session.Dispose();
|
||||
session = null;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (autoExitPlayMode)
|
||||
UnityEditor.EditorApplication.isPlaying = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
{
|
||||
if (session != null)
|
||||
session.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6122dab7ff1764c468a03aa29f49ea5b
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,225 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder
|
||||
{
|
||||
public class RecorderInfo
|
||||
{
|
||||
public Type recorder;
|
||||
public Type settings;
|
||||
public string category;
|
||||
public string displayName;
|
||||
|
||||
public static RecorderInfo Instantiate<TRecoder, TSettings>(string category, string displayName)
|
||||
where TRecoder : class
|
||||
where TSettings : class
|
||||
{
|
||||
return new RecorderInfo()
|
||||
{
|
||||
recorder = typeof(TRecoder),
|
||||
settings = typeof(TSettings),
|
||||
category = category,
|
||||
displayName = displayName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// to be internal once inside unity code base
|
||||
public static class RecordersInventory
|
||||
{
|
||||
internal static SortedDictionary<string, RecorderInfo> recorders { get; private set; }
|
||||
|
||||
static void Init()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (RecordersInventory.recorders != null)
|
||||
return;
|
||||
|
||||
RecordersInventory.recorders = new SortedDictionary<string, RecorderInfo>();
|
||||
var recorders = ClassHelpers.FilterByAttribute<FrameRecorderClassAttribute>(false);
|
||||
foreach (var recorder in recorders)
|
||||
AddRecorder(recorder.Key);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
static SortedDictionary<string, List<RecorderInfo>> m_RecordersByCategory;
|
||||
|
||||
public static SortedDictionary<string, List<RecorderInfo>> recordersByCategory
|
||||
{
|
||||
get
|
||||
{
|
||||
Init();
|
||||
return m_RecordersByCategory;
|
||||
}
|
||||
}
|
||||
|
||||
static string[] m_AvailableCategories;
|
||||
public static string[] availableCategories
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_AvailableCategories == null)
|
||||
{
|
||||
m_AvailableCategories = RecordersInventory.ListRecorders()
|
||||
.GroupBy(x => x.category)
|
||||
.Select(x => x.Key)
|
||||
.OrderBy(x => x)
|
||||
.ToArray();
|
||||
}
|
||||
return m_AvailableCategories;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool AddRecorder(Type recorderType)
|
||||
{
|
||||
RecorderInfo recInfo = null;
|
||||
var method = recorderType.GetMethod("GetRecorderInfo", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
|
||||
if (method != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
recInfo = method.Invoke(null, null) as RecorderInfo;
|
||||
|
||||
if (recInfo != null)
|
||||
{
|
||||
if (recorders == null)
|
||||
recorders = new SortedDictionary<string, RecorderInfo>();
|
||||
recorders.Add(recInfo.recorder.FullName, recInfo);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (m_RecordersByCategory == null)
|
||||
m_RecordersByCategory = new SortedDictionary<string, List<RecorderInfo>>();
|
||||
|
||||
if (!m_RecordersByCategory.ContainsKey(recInfo.category))
|
||||
m_RecordersByCategory.Add(recInfo.category, new List<RecorderInfo>());
|
||||
|
||||
m_RecordersByCategory[recInfo.category].Add(recInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError(String.Format("The recorder class '{0}' need to provide method: static RecorderInfo GetRecorderInfo(...)", recorderType.FullName));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static RecorderInfo GetRecorder<TRecorder>() where TRecorder : class
|
||||
{
|
||||
return GetRecorder(typeof(TRecorder));
|
||||
}
|
||||
|
||||
static RecorderInfo GetRecorder(Type recorderType)
|
||||
{
|
||||
Init();
|
||||
if (recorders.ContainsKey(recorderType.FullName))
|
||||
return recorders[recorderType.FullName];
|
||||
|
||||
#if UNITY_EDITOR
|
||||
return null;
|
||||
#else
|
||||
if (AddRecorder(recorderType))
|
||||
return recorders[recorderType.FullName];
|
||||
else
|
||||
return null
|
||||
#endif
|
||||
}
|
||||
|
||||
public static IEnumerable<RecorderInfo> ListRecorders()
|
||||
{
|
||||
Init();
|
||||
|
||||
foreach (var recorderInfo in recorders)
|
||||
{
|
||||
yield return recorderInfo.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static Recorder InstantiateRecorder(Type recorderType, FrameRecorderSettings settings)
|
||||
{
|
||||
Init();
|
||||
var factory = GetRecorder(recorderType);
|
||||
if (factory != null)
|
||||
{
|
||||
var recorder = ScriptableObject.CreateInstance(recorderType) as Recorder;
|
||||
recorder.Reset();
|
||||
recorder.settings = settings;
|
||||
return recorder;
|
||||
}
|
||||
else
|
||||
throw new ArgumentException("No factory was registered for " + recorderType.Name);
|
||||
}
|
||||
|
||||
public static FrameRecorderSettings CreateRecorderSettings(Type recorderType, string ownerAssetId, string uniqueId)
|
||||
{
|
||||
Init();
|
||||
var recorderinfo = GetRecorder(recorderType);
|
||||
if (recorderinfo != null)
|
||||
{
|
||||
var rootRecordingGO = FrameRecorderGOControler.GetSettingsRoot();
|
||||
|
||||
var transform = rootRecordingGO.transform.Find(uniqueId);
|
||||
if (transform == null)
|
||||
return New(recorderinfo.settings, ownerAssetId, uniqueId);
|
||||
|
||||
var settings = (FrameRecorderSettings)transform.GetComponent(recorderinfo.settings);
|
||||
if (settings == null || settings.GetType() != recorderinfo.settings)
|
||||
{
|
||||
UnityHelpers.Destroy(transform.gameObject);
|
||||
return New(recorderinfo.settings, ownerAssetId, uniqueId);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
else
|
||||
throw new ArgumentException("No factory was registered for " + recorderType.Name);
|
||||
}
|
||||
|
||||
public static void DeleteSettings(string uniqueId)
|
||||
{
|
||||
var bank = FrameRecorderGOControler.GetSettingsRoot();
|
||||
|
||||
GameObject settingsGO = null;
|
||||
var t = bank.transform.Find(uniqueId);
|
||||
if (t != null)
|
||||
settingsGO = t.gameObject;
|
||||
|
||||
if (settingsGO == null)
|
||||
return;
|
||||
|
||||
UnityHelpers.Destroy(settingsGO);
|
||||
}
|
||||
|
||||
static FrameRecorderSettings New(Type type, string ownerAssetId, string uniqueId)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(uniqueId))
|
||||
DeleteSettings(uniqueId);
|
||||
|
||||
var bank = FrameRecorderGOControler.GetSettingsRoot();
|
||||
|
||||
var settingsGO = new GameObject();
|
||||
settingsGO.transform.parent = bank.transform;
|
||||
var settings = (FrameRecorderSettings)settingsGO.AddComponent(type);
|
||||
settings.m_UniqueID = uniqueId;
|
||||
settings.m_OwnerAssetID = ownerAssetId;
|
||||
|
||||
settingsGO.name = settings.m_UniqueID;
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e11d656cf6217cb41ba5443ff354aea7
|
||||
timeCreated: 1491415344
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder
|
||||
{
|
||||
public class RecordingSession : IDisposable
|
||||
{
|
||||
public Recorder m_Recorder;
|
||||
public GameObject m_RecorderGO;
|
||||
public List<UnityEngine.Object> m_ObjsOfInterest;
|
||||
public int m_FrameIndex; // count starts at 0.
|
||||
public double m_CurrentFrameStartTS;
|
||||
public double m_RecordingStartTS;
|
||||
|
||||
public FrameRecorderSettings settings { get { return m_Recorder.settings; } }
|
||||
public bool recording { get { return m_Recorder.recording; } }
|
||||
|
||||
public bool BeginRecording()
|
||||
{
|
||||
if (!m_Recorder.BeginRecording(this))
|
||||
return false;
|
||||
m_Recorder.SignalSourcesOfStage(ERecordingSessionStage.BeginRecording, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void EndRecording()
|
||||
{
|
||||
m_Recorder.EndRecording(this);
|
||||
m_Recorder.SignalSourcesOfStage(ERecordingSessionStage.EndRecording, this);
|
||||
}
|
||||
|
||||
public void RecordFrame()
|
||||
{
|
||||
m_Recorder.SignalSourcesOfStage(ERecordingSessionStage.NewFrameReady, this);
|
||||
if (!m_Recorder.SkipFrame(this))
|
||||
{
|
||||
m_Recorder.RecordFrame(this);
|
||||
m_Recorder.recordedFramesCount++;
|
||||
}
|
||||
m_Recorder.SignalSourcesOfStage(ERecordingSessionStage.FrameDone, this);
|
||||
}
|
||||
|
||||
public void PrepareNewFrame()
|
||||
{
|
||||
m_Recorder.SignalSourcesOfStage(ERecordingSessionStage.NewFrameStarting, this);
|
||||
m_Recorder.PrepareNewFrame(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_Recorder != null)
|
||||
{
|
||||
if (recording)
|
||||
EndRecording();
|
||||
|
||||
UnityHelpers.Destroy(m_Recorder);
|
||||
UnityHelpers.Destroy(m_RecorderGO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 061b0c1d04c01f54fa322b11b8662964
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,144 @@
|
|||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine.Recorder.FrameRecorder.DataSource;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder
|
||||
{
|
||||
public abstract class RenderTextureRecorder<T> : Recorder where T : ImageRecorderSettings
|
||||
{
|
||||
[SerializeField]
|
||||
protected T m_Settings;
|
||||
public override FrameRecorderSettings settings
|
||||
{
|
||||
get { return m_Settings; }
|
||||
set { m_Settings = (T)value; }
|
||||
}
|
||||
|
||||
protected string m_OutputFile;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static EditorWindow GetMainGameView()
|
||||
{
|
||||
System.Type T = System.Type.GetType("UnityEditor.GameView,UnityEditor");
|
||||
System.Reflection.MethodInfo GetMainGameView = T.GetMethod("GetMainGameView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||
System.Object Res = GetMainGameView.Invoke(null, null);
|
||||
return (EditorWindow)Res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public override bool BeginRecording(RecordingSession session)
|
||||
{
|
||||
base.BeginRecording(session);
|
||||
|
||||
m_BoxedSources = new List<BoxedSource>();
|
||||
|
||||
// Targetting explicit cameras?
|
||||
if (session.m_ObjsOfInterest != null)
|
||||
{
|
||||
foreach (var objOfInterest in session.m_ObjsOfInterest)
|
||||
{
|
||||
if (!(objOfInterest is Camera))
|
||||
continue;
|
||||
|
||||
var source = new CameraAsRenderTexture( EImageSizeMode.Width, m_Settings.m_Width, 0)
|
||||
{
|
||||
TargetCamera = (Camera)objOfInterest
|
||||
};
|
||||
var boxedSource = new BoxedSource(source);
|
||||
boxedSource.m_StageHandlers.Add(ERecordingSessionStage.NewFrameStarting, (x) => source.PrepareNewFrame());
|
||||
|
||||
m_BoxedSources.Add(boxedSource);
|
||||
}
|
||||
}
|
||||
|
||||
// Targetting a game display?
|
||||
if (m_Settings.m_InputType == EImageSourceType.GameDisplay)
|
||||
{
|
||||
var source = new GameViewAsRenderTexture(m_Settings.m_SizeMode, m_Settings.m_Width, m_Settings.m_Height );
|
||||
var boxedSource = new BoxedSource(source);
|
||||
boxedSource.m_StageHandlers.Add(ERecordingSessionStage.NewFrameStarting, (x) => source.PrepareNewFrame(session) );
|
||||
boxedSource.m_StageHandlers.Add(ERecordingSessionStage.BeginRecording, (x) => source.BeginRecording() );
|
||||
boxedSource.m_StageHandlers.Add(ERecordingSessionStage.EndRecording, (x) => source.EndRecording() );
|
||||
|
||||
m_BoxedSources.Add(boxedSource);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Targetting the scene view?
|
||||
#if UNITY_EDITOR
|
||||
/*
|
||||
if (m_Settings.m_InputType == EImageSourceType.SceneView)
|
||||
{
|
||||
if (!m_Settings.m_ScaleImage)
|
||||
{
|
||||
m_Settings.m_Width = (int)SceneView.currentDrawingSceneView.position.width;
|
||||
}
|
||||
|
||||
var source = new DisplayAsRenderTexture(m_Settings.m_Width);
|
||||
var boxedSource = new BoxedSource(source);
|
||||
boxedSource.m_StageHandlers.Add(ERecordingSessionStage.NewFrameStarting,
|
||||
(x) =>
|
||||
{
|
||||
source.m_DisplayID = m_Settings.m_ScreenID;
|
||||
source.PrepareNewFrame(session);
|
||||
});
|
||||
|
||||
m_BoxedSources.Add(boxedSource);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
// Targetting "Main Camera"
|
||||
if (m_Settings.m_InputType == EImageSourceType.MainCamera)
|
||||
{
|
||||
var source = new CameraAsRenderTexture(EImageSizeMode.Width, m_Settings.m_Width, 0);
|
||||
var boxedSource = new BoxedSource(source);
|
||||
boxedSource.m_StageHandlers.Add(ERecordingSessionStage.NewFrameStarting,
|
||||
(x) =>
|
||||
{
|
||||
source.TargetCamera = Camera.main;
|
||||
source.PrepareNewFrame();
|
||||
});
|
||||
|
||||
m_BoxedSources.Add(boxedSource);
|
||||
}
|
||||
|
||||
// Targetting a "tagged Camera"
|
||||
if (m_Settings.m_InputType == EImageSourceType.TaggedCamera)
|
||||
{
|
||||
var source = new CameraAsRenderTexture(EImageSizeMode.Width, m_Settings.m_Width, 0);
|
||||
var boxedSource = new BoxedSource(source);
|
||||
boxedSource.m_StageHandlers.Add(ERecordingSessionStage.NewFrameStarting,
|
||||
(x) =>
|
||||
{
|
||||
var candidates = GameObject.FindGameObjectsWithTag(m_Settings.m_CameraTag);
|
||||
if (candidates.Length > 0)
|
||||
{
|
||||
foreach (var candidate in candidates)
|
||||
{
|
||||
var cam = candidate.GetComponent<Camera>();
|
||||
if (cam != null)
|
||||
{
|
||||
source.TargetCamera = cam;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("No GameObject found with tag: " + m_Settings.m_CameraTag);
|
||||
}
|
||||
source.PrepareNewFrame();
|
||||
});
|
||||
|
||||
m_BoxedSources.Add(boxedSource);
|
||||
}
|
||||
|
||||
return recording = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e971ec30698b0bf41bd9afdd5694c8ba
|
||||
timeCreated: 1491415344
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d710ed9c46e2cf948ac52d735f4a83f0
|
||||
folderAsset: yes
|
||||
timeCreated: 1491415339
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.Timeline
|
||||
{
|
||||
public class FrameRecorderClip : PlayableAsset, ITimelineClipAsset
|
||||
{
|
||||
[SerializeField] public string m_RecorderTypeName;
|
||||
[SerializeField] public string m_RecorderCategory;
|
||||
|
||||
public FrameRecorderSettings m_Settings;
|
||||
Type m_RecorderType;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_RecorderTypeName))
|
||||
return;
|
||||
|
||||
var assetGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(this));
|
||||
m_Settings = RecordersInventory.CreateRecorderSettings(recorderType, assetGuid, "TmLn-Clip:" + assetGuid);
|
||||
}
|
||||
|
||||
public Type recorderType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_RecorderType == null && !string.IsNullOrEmpty(m_RecorderTypeName))
|
||||
m_RecorderType = Type.GetType(m_RecorderTypeName);
|
||||
return m_RecorderType;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_RecorderType != value)
|
||||
{
|
||||
m_RecorderType = value;
|
||||
m_RecorderTypeName = value != null ? m_RecorderType.AssemblyQualifiedName : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ClipCaps clipCaps
|
||||
{
|
||||
get { return ClipCaps.None; }
|
||||
}
|
||||
|
||||
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
|
||||
{
|
||||
var playable = ScriptPlayable<FrameRecorderPlayable>.Create( graph );
|
||||
var behaviour = playable.GetBehaviour();
|
||||
if (recorderType != null && UnityHelpers.IsPlaying())
|
||||
{
|
||||
behaviour.session = new RecordingSession()
|
||||
{
|
||||
m_Recorder = RecordersInventory.InstantiateRecorder(recorderType, m_Settings),
|
||||
m_RecorderGO = FrameRecorderGOControler.HookupRecorder(m_Settings),
|
||||
m_RecordingStartTS = Time.time,
|
||||
m_FrameIndex = 0
|
||||
};
|
||||
}
|
||||
return playable;
|
||||
}
|
||||
|
||||
public virtual void OnDestroy()
|
||||
{
|
||||
RecordersInventory.DeleteSettings(m_Settings.m_UniqueID);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f1e95aa6d658d694785bfde37c857fff
|
||||
timeCreated: 1491415344
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine.Recorder.FrameRecorder.Utilities;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Note: Totally ignores the time info comming from the playable infrastructure. Only conciders scaled time.
|
||||
/// </summary>
|
||||
public class FrameRecorderPlayable : PlayableBehaviour
|
||||
{
|
||||
PlayState m_PlayState = PlayState.Paused;
|
||||
public RecordingSession session { get; set; }
|
||||
WaitForEndOfFrameComponent endOfFrameComp;
|
||||
bool m_FirstOneSkipped;
|
||||
|
||||
public override void OnGraphStart(Playable playable)
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
// does not support multiple starts...
|
||||
session.BeginRecording();
|
||||
m_PlayState = PlayState.Paused;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGraphStop(Playable playable)
|
||||
{
|
||||
if (session != null)
|
||||
session.EndRecording();
|
||||
}
|
||||
|
||||
public override void PrepareFrame(Playable playable, FrameData info)
|
||||
{
|
||||
if (session != null && session.recording)
|
||||
{
|
||||
session.m_CurrentFrameStartTS = (Time.time / Time.timeScale) - session.m_RecordingStartTS;
|
||||
session.PrepareNewFrame();
|
||||
}
|
||||
}
|
||||
|
||||
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
if (endOfFrameComp == null)
|
||||
{
|
||||
endOfFrameComp = session.m_RecorderGO.AddComponent<WaitForEndOfFrameComponent>();
|
||||
endOfFrameComp.m_playable = this;
|
||||
}
|
||||
|
||||
if (session.recording)
|
||||
session.m_FrameIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void OnBehaviourPlay(Playable playable, FrameData info)
|
||||
{
|
||||
if (session == null)
|
||||
return;
|
||||
|
||||
// Assumption: OnPlayStateChanged( PlayState.Playing ) ONLY EVER CALLED ONCE for this type of playable.
|
||||
session.m_RecordingStartTS = Time.time / Time.timeScale;
|
||||
m_PlayState = PlayState.Playing;
|
||||
}
|
||||
|
||||
public override void OnBehaviourPause(Playable playable, FrameData info)
|
||||
{
|
||||
if (session == null)
|
||||
return;
|
||||
if (session.recording && m_PlayState == PlayState.Playing)
|
||||
session.EndRecording();
|
||||
|
||||
m_PlayState = PlayState.Paused;
|
||||
}
|
||||
|
||||
public void FrameEnded()
|
||||
{
|
||||
if (session != null && session.recording)
|
||||
session.RecordFrame();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d580900d83be2664c9c035d6e50791fe
|
||||
timeCreated: 1491415344
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,12 @@
|
|||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.Timeline
|
||||
{
|
||||
[System.Serializable]
|
||||
[TrackClipType(typeof(FrameRecorderClip))]
|
||||
[TrackMediaType(TimelineAsset.MediaType.Script)]
|
||||
[TrackColor(0.53f, 0.0f, 0.08f)]
|
||||
public class FrameRecorderTrack : TrackAsset
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0e6cf5671577b7344ba25c25b4346ce4
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.Timeline
|
||||
{
|
||||
// the purpose of this class is to signal the FrameRecorderPlayable when frame is done.
|
||||
[ExecuteInEditMode]
|
||||
class WaitForEndOfFrameComponent : MonoBehaviour
|
||||
{
|
||||
[NonSerialized]
|
||||
public FrameRecorderPlayable m_playable;
|
||||
|
||||
public IEnumerator WaitForEndOfFrame()
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
if(m_playable != null)
|
||||
m_playable.FrameEnded();
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
StartCoroutine(WaitForEndOfFrame());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fb0550cc97f23464f99f702c09306f21
|
||||
timeCreated: 1491590881
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9706f1322d8993d46b6110692af7e26b
|
||||
folderAsset: yes
|
||||
timeCreated: 1491415339
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.Utilities
|
||||
{
|
||||
public class ClassHelpers
|
||||
{
|
||||
public static IEnumerable<KeyValuePair<Type, object[]>> FilterByAttribute<T>(bool inherit = false)
|
||||
{
|
||||
var attribType = typeof(T);
|
||||
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
foreach (var t in a.GetTypes())
|
||||
{
|
||||
var attributes = t.GetCustomAttributes(attribType, inherit);
|
||||
if (attributes.Length != 0)
|
||||
yield return new KeyValuePair<Type, object[]>(t, attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static T GetAttribute<T>(Type type) where T : class
|
||||
{
|
||||
var attributes = type.GetCustomAttributes(typeof(T), true);
|
||||
if (attributes.Length == 0)
|
||||
return null;
|
||||
else
|
||||
return attributes[0] as T;
|
||||
}
|
||||
|
||||
public static T GetAttribute<T>(MethodInfo methofInfo) where T : class
|
||||
{
|
||||
var attributes = methofInfo.GetCustomAttributes(typeof(T), true);
|
||||
|
||||
if (attributes.Length == 0)
|
||||
return null;
|
||||
else
|
||||
return attributes[0] as T;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bb4bca9c0585ca14fbd975b3380f946e
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,153 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.Utilities
|
||||
{
|
||||
public class GameViewWindow
|
||||
{
|
||||
|
||||
|
||||
public static class LayoutUtility {
|
||||
|
||||
private static MethodInfo _miLoadWindowLayout;
|
||||
private static MethodInfo _miSaveWindowLayout;
|
||||
private static MethodInfo _miReloadWindowLayoutMenu;
|
||||
|
||||
private static bool _available;
|
||||
private static string _layoutsPath;
|
||||
|
||||
static LayoutUtility() {
|
||||
Type tyWindowLayout = Type.GetType("UnityEditor.WindowLayout,UnityEditor");
|
||||
Type tyEditorUtility = Type.GetType("UnityEditor.EditorUtility,UnityEditor");
|
||||
Type tyInternalEditorUtility = Type.GetType("UnityEditorInternal.InternalEditorUtility,UnityEditor");
|
||||
|
||||
if (tyWindowLayout != null && tyEditorUtility != null && tyInternalEditorUtility != null) {
|
||||
MethodInfo miGetLayoutsPath = tyWindowLayout.GetMethod("GetLayoutsPath", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
_miLoadWindowLayout = tyWindowLayout.GetMethod("LoadWindowLayout", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string) }, null);
|
||||
_miSaveWindowLayout = tyWindowLayout.GetMethod("SaveWindowLayout", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string) }, null);
|
||||
_miReloadWindowLayoutMenu = tyInternalEditorUtility.GetMethod("ReloadWindowLayoutMenu", BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (miGetLayoutsPath == null || _miLoadWindowLayout == null || _miSaveWindowLayout == null || _miReloadWindowLayoutMenu == null)
|
||||
return;
|
||||
|
||||
_layoutsPath = (string)miGetLayoutsPath.Invoke(null, null);
|
||||
if (string.IsNullOrEmpty(_layoutsPath))
|
||||
return;
|
||||
|
||||
_available = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets a value indicating whether all required Unity API
|
||||
// functionality is available for usage.
|
||||
public static bool IsAvailable {
|
||||
get { return _available; }
|
||||
}
|
||||
|
||||
// Gets absolute path of layouts directory.
|
||||
// Returns `null` when not available.
|
||||
public static string LayoutsPath {
|
||||
get { return _layoutsPath; }
|
||||
}
|
||||
|
||||
// Save current window layout to asset file.
|
||||
// `assetPath` must be relative to project directory.
|
||||
public static void SaveLayoutToAsset(string assetPath) {
|
||||
SaveLayout(Path.Combine(Directory.GetCurrentDirectory(), assetPath));
|
||||
}
|
||||
|
||||
// Load window layout from asset file.
|
||||
// `assetPath` must be relative to project directory.
|
||||
public static void LoadLayoutFromAsset(string assetPath) {
|
||||
if (_miLoadWindowLayout != null) {
|
||||
string path = Path.Combine(Directory.GetCurrentDirectory(), assetPath);
|
||||
_miLoadWindowLayout.Invoke(null, new object[] { path });
|
||||
}
|
||||
}
|
||||
|
||||
// Save current window layout to file.
|
||||
// `path` must be absolute.
|
||||
public static void SaveLayout(string path) {
|
||||
if (_miSaveWindowLayout != null)
|
||||
_miSaveWindowLayout.Invoke(null, new object[] { path });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Rect m_OrgPosition;
|
||||
Vector2 m_OrgSize;
|
||||
Vector2 m_OrgMaxSize;
|
||||
EImageSizeMode m_SizeMode = EImageSizeMode.Dynamic;
|
||||
public Vector2 size { get; private set; }
|
||||
|
||||
//The size of the toolbar above the game view, excluding the OS border.
|
||||
private static int tabHeight = 22;
|
||||
|
||||
static EditorWindow GetMainGameView()
|
||||
{
|
||||
EditorApplication.ExecuteMenuItem("Window/Game");
|
||||
|
||||
System.Type T = System.Type.GetType("UnityEditor.GameView,UnityEditor");
|
||||
System.Reflection.MethodInfo GetMainGameView = T.GetMethod("GetMainGameView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||
System.Object Res = GetMainGameView.Invoke(null, null);
|
||||
return (EditorWindow)Res;
|
||||
}
|
||||
|
||||
public void FullScreenGameWindow( EImageSizeMode sizeMode, int width, int height )
|
||||
{
|
||||
m_SizeMode = sizeMode;
|
||||
var gameView = GetMainGameView();
|
||||
|
||||
m_OrgPosition = gameView.position;
|
||||
m_OrgSize = gameView.minSize;
|
||||
m_OrgMaxSize = gameView.maxSize;
|
||||
switch (sizeMode)
|
||||
{
|
||||
case EImageSizeMode.Dynamic:
|
||||
{
|
||||
size = new Vector2(gameView.position.width, gameView.position.height);
|
||||
return;
|
||||
}
|
||||
case EImageSizeMode.FullScreen:
|
||||
{
|
||||
width = Screen.currentResolution.width;
|
||||
height = Screen.currentResolution.height;
|
||||
break;
|
||||
}
|
||||
case EImageSizeMode.Width:
|
||||
{
|
||||
height = (int)((height / (double)Screen.currentResolution.width) * width);
|
||||
break;
|
||||
}
|
||||
case EImageSizeMode.Custom:
|
||||
break;
|
||||
}
|
||||
|
||||
var newPos = new Rect(0, 0 - tabHeight, Screen.currentResolution.width, Screen.currentResolution.height + tabHeight);
|
||||
gameView.position = newPos;
|
||||
size = new Vector2(width, height);
|
||||
gameView.minSize = size = new Vector2(width, height + tabHeight);;
|
||||
gameView.maxSize = gameView.minSize;
|
||||
gameView.position = newPos;
|
||||
}
|
||||
|
||||
public void RestoreGameWindow()
|
||||
{
|
||||
if (m_SizeMode != EImageSizeMode.Dynamic)
|
||||
{
|
||||
var gameView = GetMainGameView();
|
||||
gameView.Close();
|
||||
gameView = GetMainGameView();
|
||||
gameView.minSize = m_OrgSize;
|
||||
gameView.maxSize = m_OrgMaxSize;
|
||||
gameView.position = m_OrgPosition;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1f428d7759a94b145b1aa0a53a11071f
|
||||
timeCreated: 1493926581
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.Utilities
|
||||
{
|
||||
public static class RecordersCache
|
||||
{
|
||||
class CachedRecorder
|
||||
{
|
||||
public Type type { get; set; }
|
||||
public string category { get; set; }
|
||||
}
|
||||
|
||||
static List<RecorderInfo> m_RecordersCache;
|
||||
|
||||
static void Init()
|
||||
{
|
||||
if (m_RecordersCache == null)
|
||||
{
|
||||
m_RecordersCache = RecordersInventory.recorders
|
||||
.OrderBy((x) => x.Key)
|
||||
.Select((x) => x.Value)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public static int GroupedIndexOfRecorder(Type recorder, string category)
|
||||
{
|
||||
Init();
|
||||
|
||||
var skipped = 0;
|
||||
var any = false;
|
||||
for (var i = 0; i < m_RecordersCache.Count; i++)
|
||||
{
|
||||
if (string.Compare(category, m_RecordersCache[i].category, StringComparison.InvariantCultureIgnoreCase) == 0)
|
||||
skipped++;
|
||||
else if (m_RecordersCache[i].recorder == recorder)
|
||||
return i - skipped;
|
||||
else
|
||||
any = true;
|
||||
}
|
||||
|
||||
if (any)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static Type RecorderFromGroupedIndex(int index, string category)
|
||||
{
|
||||
Init();
|
||||
|
||||
var filteredIndex = 0;
|
||||
foreach (var t in m_RecordersCache)
|
||||
{
|
||||
if (string.Compare(category, t.category, StringComparison.InvariantCultureIgnoreCase) != 0)
|
||||
continue;
|
||||
|
||||
if (index == filteredIndex)
|
||||
return t.recorder;
|
||||
filteredIndex++;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string[] GetNameOfRecordersInGroup(string category)
|
||||
{
|
||||
Init();
|
||||
|
||||
// count them
|
||||
int count = 0;
|
||||
foreach (var item in m_RecordersCache)
|
||||
if (string.Compare(category, item.category, StringComparison.InvariantCultureIgnoreCase) == 0)
|
||||
count++;
|
||||
|
||||
// store them
|
||||
var result = new string[count];
|
||||
if (count > 0)
|
||||
{
|
||||
count = 0;
|
||||
foreach (var item in m_RecordersCache)
|
||||
if (string.Compare(category, item.category, StringComparison.InvariantCultureIgnoreCase) == 0)
|
||||
result[count++] = item.recorder.FullName;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9ea1d95d7f0add84091f7807bcbd2d82
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,31 @@
|
|||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace UnityEngine.Recorder.FrameRecorder.Utilities
|
||||
{
|
||||
public static class UnityHelpers
|
||||
{
|
||||
public static void Destroy(Object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return;
|
||||
#if UNITY_EDITOR
|
||||
if (UnityEditor.EditorApplication.isPlaying)
|
||||
Object.Destroy(obj);
|
||||
else
|
||||
Object.DestroyImmediate(obj);
|
||||
#else
|
||||
Object.Destroy(m_HostGO);
|
||||
#endif
|
||||
obj = null;
|
||||
}
|
||||
|
||||
public static bool IsPlaying()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return UnityEditor.EditorApplication.isPlaying;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 639bab1152ec3984184d25ab38abd226
|
||||
timeCreated: 1491415343
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a843bc4482baa5846971389324919dad
|
||||
folderAsset: yes
|
||||
timeCreated: 1491415339
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d55140aa4996ef248b1e815274e1c193
|
||||
folderAsset: yes
|
||||
timeCreated: 1491415339
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,205 @@
|
|||
Shader "Unity/FrameRecorder/TestGrabberShader" {
|
||||
|
||||
Properties{
|
||||
}
|
||||
|
||||
CGINCLUDE
|
||||
#include "UnityCG.cginc"
|
||||
#pragma multi_compile ___ UNITY_HDR_ON
|
||||
#pragma multi_compile ___ OFFSCREEN
|
||||
|
||||
sampler2D _TmpFrameBuffer;
|
||||
sampler2D _CameraGBufferTexture0;
|
||||
sampler2D _CameraGBufferTexture1;
|
||||
sampler2D _CameraGBufferTexture2;
|
||||
sampler2D _CameraGBufferTexture3;
|
||||
sampler2D_float _CameraDepthTexture;
|
||||
sampler2D _TmpRenderTarget;
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 pos : POSITION;
|
||||
float4 spos : TEXCOORD0;
|
||||
};
|
||||
|
||||
v2f vert(appdata_img v)
|
||||
{
|
||||
v2f o;
|
||||
o.pos = o.spos = v.vertex;
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
float2 get_texcoord(v2f i)
|
||||
{
|
||||
float2 t = i.spos.xy * 0.5 + 0.5;
|
||||
return t;
|
||||
}
|
||||
|
||||
float2 get_texcoord_gb(v2f i)
|
||||
{
|
||||
float2 t = i.spos.xy * 0.5 + 0.5;
|
||||
#if !defined(UNITY_UV_STARTS_AT_TOP)
|
||||
t.y = 1.0 - t.y;
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
half4 copy_framebuffer(v2f I) : SV_Target
|
||||
{
|
||||
float2 t = get_texcoord(I);
|
||||
#if !defined(OFFSCREEN) || !defined(UNITY_UV_STARTS_AT_TOP)
|
||||
t.y = 1.0 - t.y;
|
||||
#endif
|
||||
half4 O = tex2D(_TmpFrameBuffer, t);
|
||||
O.a = 1.0;
|
||||
return O;
|
||||
}
|
||||
|
||||
|
||||
// g-buffer
|
||||
struct gbuffer_out
|
||||
{
|
||||
half4 diffuse : SV_Target0; // RT0: diffuse color (rgb), occlusion (a)
|
||||
half4 spec_smoothness : SV_Target1; // RT1: spec color (rgb), smoothness (a)
|
||||
half4 normal : SV_Target2; // RT2: normal (rgb), --unused, very low precision-- (a)
|
||||
half4 emission : SV_Target3; // RT3: emission (rgb), --unused-- (a)
|
||||
};
|
||||
gbuffer_out copy_gbuffer(v2f I)
|
||||
{
|
||||
float2 t = get_texcoord_gb(I);
|
||||
gbuffer_out O;
|
||||
O.diffuse = tex2D(_CameraGBufferTexture0, t);
|
||||
O.spec_smoothness = tex2D(_CameraGBufferTexture1, t);
|
||||
O.normal = tex2D(_CameraGBufferTexture2, t);
|
||||
O.emission = tex2D(_CameraGBufferTexture3, t);
|
||||
#ifndef UNITY_HDR_ON
|
||||
O.emission.rgb = -log2(O.emission.rgb);
|
||||
#endif
|
||||
return O;
|
||||
}
|
||||
|
||||
|
||||
// depth
|
||||
float4 copy_depth(v2f I) : SV_Target
|
||||
{
|
||||
float4 O = tex2D(_CameraDepthTexture, get_texcoord_gb(I)).rrrr;
|
||||
return O;
|
||||
}
|
||||
|
||||
|
||||
// render target (for offscreen-recorder)
|
||||
half4 copy_rendertarget(v2f I) : SV_Target
|
||||
{
|
||||
half4 O = tex2D(_TmpRenderTarget, get_texcoord_gb(I));
|
||||
return O;
|
||||
}
|
||||
|
||||
|
||||
// albedo, occlusion, specular, smoothness
|
||||
struct aoss_out
|
||||
{
|
||||
half4 albedo : SV_Target0;
|
||||
half4 occlusion : SV_Target1;
|
||||
half4 specular : SV_Target2;
|
||||
half4 smoothness : SV_Target3;
|
||||
};
|
||||
aoss_out copy_aoss(v2f I)
|
||||
{
|
||||
float2 t = get_texcoord_gb(I);
|
||||
half4 ao = tex2D(_CameraGBufferTexture0, t);
|
||||
half4 ss = tex2D(_CameraGBufferTexture1, t);
|
||||
|
||||
aoss_out O;
|
||||
O.albedo = half4(ao.rgb, 1.0);
|
||||
O.occlusion = ao.aaaa;
|
||||
O.specular = half4(ss.rgb, 1.0);
|
||||
O.smoothness = ss.aaaa;
|
||||
return O;
|
||||
}
|
||||
|
||||
|
||||
// normal, emission, depth
|
||||
struct ned_out
|
||||
{
|
||||
half4 normal : SV_Target0;
|
||||
half4 emission : SV_Target1;
|
||||
half4 depth : SV_Target2;
|
||||
};
|
||||
ned_out copy_ned(v2f I)
|
||||
{
|
||||
float2 t = get_texcoord_gb(I);
|
||||
half4 normal = tex2D(_CameraGBufferTexture2, t);
|
||||
half4 emission = tex2D(_CameraGBufferTexture3, t);
|
||||
half4 depth = tex2D(_CameraDepthTexture, get_texcoord_gb(I));
|
||||
|
||||
ned_out O;
|
||||
O.normal = half4(normal.rgb, 1.0);
|
||||
O.emission = half4(emission.rgb, 1.0);
|
||||
#ifndef UNITY_HDR_ON
|
||||
O.emission.rgb = -log2(O.emission.rgb);
|
||||
#endif
|
||||
O.depth = depth.rrrr;
|
||||
return O;
|
||||
}
|
||||
ENDCG
|
||||
|
||||
Subshader{
|
||||
// Pass 0: framebuffer
|
||||
Pass{
|
||||
Blend Off Cull Off ZTest Off ZWrite Off
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment copy_framebuffer
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// Pass 1: g-buffer
|
||||
Pass{
|
||||
Blend Off Cull Off ZTest Off ZWrite Off
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment copy_gbuffer
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// Pass 2: depth
|
||||
Pass{
|
||||
Blend Off Cull Off ZTest Off ZWrite Off
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment copy_depth
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// Pass 3: render target
|
||||
Pass{
|
||||
Blend Off Cull Off ZTest Off ZWrite Off
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment copy_rendertarget
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// Pass 4: albedo, occlusion, specular, smoothness
|
||||
Pass{
|
||||
Blend Off Cull Off ZTest Off ZWrite Off
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment copy_aoss
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// Pass 5: normal, emission, depth
|
||||
Pass{
|
||||
Blend Off Cull Off ZTest Off ZWrite Off
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment copy_ned
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
|
||||
Fallback off
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 55d39f733f4029f4cbc92b5c2279e15b
|
||||
timeCreated: 1491415345
|
||||
licenseType: Free
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Загрузка…
Ссылка в новой задаче