diff --git a/Moments Recorder/Demo/Demo.unity b/Moments Recorder/Demo/Demo.unity index 53cc13f..1147a5a 100644 Binary files a/Moments Recorder/Demo/Demo.unity and b/Moments Recorder/Demo/Demo.unity differ diff --git a/Moments Recorder/Demo/DemoSettings.lighting b/Moments Recorder/Demo/DemoSettings.lighting new file mode 100644 index 0000000..696445d --- /dev/null +++ b/Moments Recorder/Demo/DemoSettings.lighting @@ -0,0 +1,65 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!850595691 &4890085278179872738 +LightingSettings: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: DemoSettings + serializedVersion: 5 + m_GIWorkflowMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 1 + m_RealtimeEnvironmentLighting: 1 + m_BounceScale: 1 + m_AlbedoBoost: 1 + m_IndirectOutputScale: 1 + m_UsingShadowmask: 0 + m_BakeBackend: 0 + m_LightmapMaxSize: 1024 + m_BakeResolution: 40 + m_Padding: 2 + m_LightmapCompression: 3 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 0 + m_CompAOExponentDirect: 0 + m_ExtractAO: 0 + m_MixedBakeMode: 1 + m_LightmapsBakeMode: 1 + m_FilterMode: 1 + m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_RealtimeResolution: 2 + m_ForceWhiteAlbedo: 0 + m_ForceUpdates: 0 + m_FinalGather: 0 + m_FinalGatherRayCount: 1024 + m_FinalGatherFiltering: 1 + m_PVRCulling: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVREnvironmentSampleCount: 512 + m_PVREnvironmentReferencePointCount: 2048 + m_LightProbeSampleCountMultiplier: 4 + m_PVRBounces: 2 + m_PVRMinBounces: 2 + m_PVREnvironmentImportanceSampling: 0 + m_PVRFilteringMode: 0 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_PVRTiledBaking: 0 + m_NumRaysToShootPerTexel: -1 diff --git a/Moments Recorder/Demo/DemoSettings.lighting.meta b/Moments Recorder/Demo/DemoSettings.lighting.meta new file mode 100644 index 0000000..d27b0eb --- /dev/null +++ b/Moments Recorder/Demo/DemoSettings.lighting.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 37c82be223856c44789e727d38474cbb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 4890085278179872738 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Moments Recorder/Demo/Materials/Cube.mat b/Moments Recorder/Demo/Materials/Cube.mat index 832199d..acb4616 100644 Binary files a/Moments Recorder/Demo/Materials/Cube.mat and b/Moments Recorder/Demo/Materials/Cube.mat differ diff --git a/Moments Recorder/Demo/Materials/Floor.mat b/Moments Recorder/Demo/Materials/Floor.mat index e5030a8..7e95537 100644 Binary files a/Moments Recorder/Demo/Materials/Floor.mat and b/Moments Recorder/Demo/Materials/Floor.mat differ diff --git a/Moments Recorder/Demo/Prefabs/Cube.prefab b/Moments Recorder/Demo/Prefabs/Cube.prefab index 718eebf..331f76a 100644 Binary files a/Moments Recorder/Demo/Prefabs/Cube.prefab and b/Moments Recorder/Demo/Prefabs/Cube.prefab differ diff --git a/Moments Recorder/Scripts/Editor/MinDrawer.cs b/Moments Recorder/Scripts/Editor/MinDrawer.cs index 6bf6c8e..aa6f906 100644 --- a/Moments Recorder/Scripts/Editor/MinDrawer.cs +++ b/Moments Recorder/Scripts/Editor/MinDrawer.cs @@ -27,12 +27,12 @@ namespace MomentsEditor { - [CustomPropertyDrawer(typeof(MinAttribute))] + [CustomPropertyDrawer(typeof(Moments.MinAttribute))] internal sealed class MinDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - MinAttribute attribute = (MinAttribute)base.attribute; + Moments.MinAttribute attribute = (Moments.MinAttribute)base.attribute; if (property.propertyType == SerializedPropertyType.Integer) { diff --git a/Moments Recorder/Scripts/Recorder.cs b/Moments Recorder/Scripts/Recorder.cs index 86d210b..b0849d9 100644 --- a/Moments Recorder/Scripts/Recorder.cs +++ b/Moments Recorder/Scripts/Recorder.cs @@ -23,8 +23,10 @@ using UnityEngine; using System; +using System.IO; using System.Collections; using System.Collections.Generic; +using UnityEngine.Rendering; using Moments.Encoder; using ThreadPriority = System.Threading.ThreadPriority; @@ -191,6 +193,8 @@ public void Pause() return; } + RenderPipelineManager.endCameraRendering -= OnEndCameraRendering; + State = RecorderState.Paused; } @@ -205,6 +209,8 @@ public void Record() return; } + RenderPipelineManager.endCameraRendering += OnEndCameraRendering; + State = RecorderState.Recording; } @@ -227,8 +233,9 @@ public void FlushMemory() if (m_Frames == null) return; - foreach (RenderTexture rt in m_Frames) + foreach (RenderTexture rt in m_Frames){ Flush(rt); + } m_Frames.Clear(); } @@ -289,6 +296,17 @@ void OnDestroy() FlushMemory(); } + void OnEndCameraRendering(ScriptableRenderContext context, Camera cam) + { + if (cam != Camera.main) + return; + + if (State == RecorderState.Recording) + { + OnRenderImage(cam.activeTexture, cam.targetTexture); + } + } + void OnRenderImage(RenderTexture source, RenderTexture destination) { if (State != RecorderState.Recording) @@ -320,6 +338,7 @@ void OnRenderImage(RenderTexture source, RenderTexture destination) } Graphics.Blit(source, rt); + m_Frames.Enqueue(rt); } @@ -381,7 +400,7 @@ string GenerateFileName() // Pre-processing coroutine to extract frame data and send everything to a separate worker thread IEnumerator PreProcess(string filename) { - string filepath = SaveFolder + "/" + filename + ".gif"; + string filepath = SaveFolder + Path.DirectorySeparatorChar + filename + ".gif"; List frames = new List(m_Frames.Count); // Get a temporary texture to read RenderTexture data @@ -412,6 +431,7 @@ IEnumerator PreProcess(string filename) // Setup a worker thread and let it do its magic GifEncoder encoder = new GifEncoder(m_Repeat, m_Quality); encoder.SetDelay(Mathf.RoundToInt(m_TimePerFrame * 1000f)); + Worker worker = new Worker(WorkerPriority) { m_Encoder = encoder, @@ -429,6 +449,9 @@ GifFrame ToGifFrame(RenderTexture source, Texture2D target) { RenderTexture.active = source; target.ReadPixels(new Rect(0, 0, source.width, source.height), 0, 0); + + // Renders come through upside down for some reason... + target = Utils.FlipTextureVertically(target); target.Apply(); RenderTexture.active = null; diff --git a/Moments Recorder/Scripts/Utils.cs b/Moments Recorder/Scripts/Utils.cs new file mode 100644 index 0000000..361d24d --- /dev/null +++ b/Moments Recorder/Scripts/Utils.cs @@ -0,0 +1,59 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Moments +{ + public class Utils + { + public static Texture2D FlipTextureVertically(Texture2D original) + { + Texture2D newTex = original; + + var originalPixels = newTex.GetPixels(); + + var newPixels = new Color[originalPixels.Length]; + + var width = newTex.width; + var rows = newTex.height; + + for (var x = 0; x < width; x++) + { + for (var y = 0; y < rows; y++) + { + newPixels[x + y * width] = originalPixels[x + (rows - y -1) * width]; + } + } + + newTex.SetPixels(newPixels); + newTex.Apply(); + + return newTex; + } + + public static Texture2D FlipTextureHorizontally(Texture2D original) + { + Texture2D newTex = original; + + var originalPixels = newTex.GetPixels(); + + var newPixels = new Color[originalPixels.Length]; + + var width = newTex.width; + var rows = newTex.height; + + for (var x = 0; x < width; x++) + { + for (var y = 0; y < rows; y++) + { + newPixels[x + y * width] = originalPixels[(width - x - 1) + y * width]; + } + } + + newTex.SetPixels(newPixels); + newTex.Apply(); + + return newTex; + } + } +} \ No newline at end of file diff --git a/Moments Recorder/Scripts/Utils.cs.meta b/Moments Recorder/Scripts/Utils.cs.meta new file mode 100644 index 0000000..e9af165 --- /dev/null +++ b/Moments Recorder/Scripts/Utils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b9eb86086fb77f49b301c34c3eb896d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md index 1d59888..b96ca8b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -# Moments +# Unity-Moments -**Moments** is a quick GIF replay recorder for Unity3D. It automatically records the last few seconds of gameplay and lets you save to a GIF file on demand, like the game [TowerFall Ascension](http://www.towerfall-game.com/) does. +Updated version of the following repository by [Chman](https://github.com/Chman/Moments) -Tested with Unity 4.6. The demo requires Unity 5+ (Personal or Pro). +**Moments** is a quick GIF replay recorder for Unity. It automatically records the last few seconds of gameplay and lets you save to a GIF file on demand. + +Tested with Unity 2022.1. The demo requires use of the Universal or High Definition Render Pipelines. ## Instructions