소스 검색

Revamped screenshot manager

Bepis 6 년 전
부모
커밋
5d7ac5cdd2
4개의 변경된 파일392개의 추가작업 그리고 51개의 파일을 삭제
  1. 142 0
      Plugins/Screencap/AlphaShot.cs
  2. 74 0
      Plugins/Screencap/LegacyRenderer.cs
  3. 2 0
      Plugins/Screencap/Screencap.csproj
  4. 174 51
      Plugins/Screencap/ScreenshotManager.cs

+ 142 - 0
Plugins/Screencap/AlphaShot.cs

@@ -0,0 +1,142 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace alphaShot
+{
+    //code from essu and Kenzato
+    public static class AlphaShot
+    {
+        public static byte[] Capture(int ResolutionX, int ResolutionY, int DownscalingRate, int AntiAliasing)
+        {
+            //File.WriteAllLines(GameObject.FindObjectsOfType<SkinnedMeshRenderer>().Select(x => x.material.shader.name).Distinct().OrderBy(x => x).ToArray();
+            var c = Camera.main;
+
+            var t1 = PerformCapture(true, ResolutionX * DownscalingRate, ResolutionY * DownscalingRate, AntiAliasing);
+            var t2 = PerformCapture(false, ResolutionX * DownscalingRate, ResolutionY * DownscalingRate, AntiAliasing);
+
+
+            var p1 = t1.GetPixels();
+            var p2 = t2.GetPixels();
+
+            for (int i = 0; i < p1.Length; i++)
+            {
+                var pp1 = p1[i];
+                var pp2 = p2[i];
+
+                var pp1a = pp1.a;
+                var pp2a = pp2.a;
+
+                pp1.a = 1.0f;
+                pp2.a = 1.0f;
+                p1[i] = Color.Lerp(pp1, pp2, pp2a);
+                p1[i].a = Mathf.Clamp01(pp2a * 4);
+            }
+            t1.SetPixels(p1);
+            t1.Apply();
+
+            TextureScale.Bilinear(t1, ResolutionX, ResolutionY);
+
+            byte[] output = t1.EncodeToPNG();
+
+            GameObject.Destroy(t1);
+            GameObject.Destroy(t2);
+
+            return output;
+        }
+
+        public static Texture2D PerformCapture(bool captureAlphaOnly, int ResolutionX, int ResolutionY, int AntiAliasing)
+        {
+            var go = new GameObject();
+            Camera RenderCam = go.AddComponent<Camera>();
+            RenderCam.CopyFrom(Camera.main);
+            CopyComponents(Camera.main.gameObject, RenderCam.gameObject);
+            
+            var backRenderTexture = RenderCam.targetTexture;
+            var backRect = RenderCam.rect;
+
+            var oldBackground = RenderCam.backgroundColor;
+            var oldFlags = RenderCam.clearFlags;
+
+            var width = ResolutionX;
+            var height = ResolutionY;
+            var tex = new Texture2D(width, height, TextureFormat.ARGB32, false);
+
+            var rt = RenderTexture.GetTemporary(width, height, 32, RenderTextureFormat.Default, RenderTextureReadWrite.Default, AntiAliasing);
+
+            var lst = new List<SkinnedMeshRenderer>();
+            if (captureAlphaOnly)
+            {
+                Graphics.SetRenderTarget(rt);
+                GL.Clear(true, true, Color.clear);
+                Graphics.SetRenderTarget(null);
+            }
+            else
+            {
+                foreach (var smr in GameObject.FindObjectsOfType<SkinnedMeshRenderer>())
+                    if (smr.enabled)
+                    {
+                        //if (smr.material.renderQueue > 2500 || smr.material.renderQueue == -1 && smr.material.shader.renderQueue > 2500)
+                        if (smr.material.shader.name == "Shader Forge/PBRsp_alpha" ||
+                            smr.material.shader.name == "Shader Forge/PBRsp_alpha_culloff" ||
+                            smr.material.shader.name == "Shader Forge/PBRsp_texture_alpha" ||
+                            smr.material.shader.name == "Shader Forge/PBRsp_texture_alpha_culloff" ||
+                            smr.material.shader.name == "Unlit/Transparent")
+                        {
+                            lst.Add(smr);
+                            smr.enabled = false;
+                        }
+                    }
+            }
+
+            RenderCam.backgroundColor = new Color(0f, 0f, 0f, 0f);
+            RenderCam.clearFlags = captureAlphaOnly ? CameraClearFlags.Depth : CameraClearFlags.Color;
+            RenderCam.targetTexture = rt;
+            RenderCam.rect = new Rect(0, 0, 1f, 1f);
+            RenderCam.Render();
+            RenderCam.targetTexture = backRenderTexture;
+            RenderCam.rect = backRect;
+            RenderTexture.active = rt;
+            tex.ReadPixels(new Rect(0f, 0f, width, height), 0, 0);
+            tex.Apply();
+            RenderTexture.active = null;
+
+            RenderCam.backgroundColor = oldBackground;
+            RenderCam.clearFlags = oldFlags;
+
+            RenderTexture.ReleaseTemporary(rt);
+
+            foreach (var smr in lst)
+                smr.enabled = true;
+            return tex;
+        }
+
+        static void CopyComponents(GameObject original, GameObject target)
+        {
+            foreach (Component component in original.GetComponents<Component>())
+            {
+                var newComponent = CopyComponent(component, target);
+
+                if (component is MonoBehaviour)
+                {
+                    var behavior = (MonoBehaviour)component;
+
+                    (newComponent as MonoBehaviour).enabled = behavior.enabled;
+                }
+            }
+        }
+
+        //https://answers.unity.com/questions/458207/copy-a-component-at-runtime.html
+        static Component CopyComponent(Component original, GameObject destination)
+        {
+            System.Type type = original.GetType();
+            Component copy = destination.AddComponent(type);
+            // Copied fields can be restricted with BindingFlags
+            System.Reflection.FieldInfo[] fields = type.GetFields();
+            foreach (System.Reflection.FieldInfo field in fields)
+            {
+                field.SetValue(copy, field.GetValue(original));
+            }
+            return copy;
+        }
+    }
+}

+ 74 - 0
Plugins/Screencap/LegacyRenderer.cs

@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+
+namespace Screencap
+{
+    public static class LegacyRenderer
+    {
+        public static byte[] RenderCamera(int ResolutionX, int ResolutionY, int DownscalingRate, int AntiAliasing)
+        {
+            var go = new GameObject();
+            Camera renderCam = go.AddComponent<Camera>();
+            renderCam.CopyFrom(Camera.main);
+            CopyComponents(Camera.main.gameObject, renderCam.gameObject);
+
+            renderCam.targetTexture = new RenderTexture(ResolutionX * DownscalingRate, ResolutionY * DownscalingRate, 32); //((int)cam.pixelRect.width, (int)cam.pixelRect.height, 32);
+            renderCam.aspect = renderCam.targetTexture.width / (float)renderCam.targetTexture.height;
+            renderCam.targetTexture.antiAliasing = AntiAliasing;
+
+            RenderTexture currentRT = RenderTexture.active;
+            RenderTexture.active = renderCam.targetTexture;
+
+            renderCam.clearFlags = CameraClearFlags.Skybox;
+
+            renderCam.Render();
+            Texture2D image = new Texture2D(ResolutionX * DownscalingRate, ResolutionY * DownscalingRate);
+            image.ReadPixels(new Rect(0, 0, ResolutionX * DownscalingRate, ResolutionY * DownscalingRate), 0, 0);
+
+            TextureScale.Bilinear(image, ResolutionX, ResolutionY);
+
+            image.Apply();
+            RenderTexture.active = currentRT;
+            GameObject.Destroy(renderCam.targetTexture);
+            GameObject.Destroy(renderCam);
+
+            byte[] result = image.EncodeToPNG();
+
+            GameObject.Destroy(image);
+
+            return result;
+        }
+
+        static void CopyComponents(GameObject original, GameObject target)
+        {
+            foreach (Component component in original.GetComponents<Component>())
+            {
+                var newComponent = CopyComponent(component, target);
+
+                if (component is MonoBehaviour)
+                {
+                    var behavior = (MonoBehaviour)component;
+
+                    (newComponent as MonoBehaviour).enabled = behavior.enabled;
+                }
+            }
+        }
+
+        //https://answers.unity.com/questions/458207/copy-a-component-at-runtime.html
+        static Component CopyComponent(Component original, GameObject destination)
+        {
+            System.Type type = original.GetType();
+            Component copy = destination.AddComponent(type);
+            // Copied fields can be restricted with BindingFlags
+            System.Reflection.FieldInfo[] fields = type.GetFields();
+            foreach (System.Reflection.FieldInfo field in fields)
+            {
+                field.SetValue(copy, field.GetValue(original));
+            }
+            return copy;
+        }
+    }
+}

+ 2 - 0
Plugins/Screencap/Screencap.csproj

@@ -46,6 +46,8 @@
     </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="AlphaShot.cs" />
+    <Compile Include="LegacyRenderer.cs" />
     <Compile Include="ScreenshotManager.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>

+ 174 - 51
Plugins/Screencap/ScreenshotManager.cs

@@ -1,37 +1,78 @@
-using BepInEx;
+using alphaShot;
+using BepInEx;
 using BepInEx.Common;
 using Illusion.Game;
 using System;
 using System.Collections;
-using System.Collections.Generic;
 using System.IO;
-using System.Linq;
-using System.Text;
 using UnityEngine;
 
 namespace Screencap
 {
     public class ScreenshotManager : BaseUnityPlugin
     {
+        public override string ID => "screenshotmanager";
         public override string Name => "Screenshot Manager";
-        Event ScreenKeyEvent;
-        Event CharacterKeyEvent;
+        public override Version Version => new Version("2.0");
+
+        Event ScreenKeyEvent = Event.KeyboardEvent("f9");
+        Event CharacterKeyEvent = Event.KeyboardEvent("f11");
+        Event CharacterSettingsKeyEvent = Event.KeyboardEvent("#f11");
+
+
 
         private string screenshotDir = Utility.CombinePaths(Utility.ExecutingDirectory, "UserData", "cap");
 
+        #region Config properties
+
+        private int ResolutionX
+        {
+            get => int.Parse(BepInEx.Config.GetEntry("screenshotrenderer-resolution-x", "1024"));
+            set => BepInEx.Config.SetEntry("screenshotrenderer-resolution-x", value.ToString());
+        }
+
+        private int ResolutionY
+        {
+            get => int.Parse(BepInEx.Config.GetEntry("screenshotrenderer-resolution-y", "1024"));
+            set => BepInEx.Config.SetEntry("screenshotrenderer-resolution-y", value.ToString());
+        }
+        
+        private int AntiAliasing
+        {
+            get => int.Parse(BepInEx.Config.GetEntry("screenshotrenderer-antialiasing", "4"));
+            set => BepInEx.Config.SetEntry("screenshotrenderer-antialiasing", value.ToString());
+        }
+
+        private int DownscalingRate
+        {
+            get => int.Parse(BepInEx.Config.GetEntry("screenshotrenderer-downscalerate", "1"));
+            set => BepInEx.Config.SetEntry("screenshotrenderer-downscalerate", value.ToString());
+        }
+
+        private int RenderMethod
+        {
+            get => int.Parse(BepInEx.Config.GetEntry("screenshotrenderer-rendermethod", "1"));
+            set => BepInEx.Config.SetEntry("screenshotrenderer-rendermethod", value.ToString());
+        }
+
+        #endregion
+
+
         public ScreenshotManager()
         {
-            ScreenKeyEvent = Event.KeyboardEvent("f9");
-            CharacterKeyEvent = Event.KeyboardEvent("f11");
             if (!Directory.Exists(screenshotDir))
                 Directory.CreateDirectory(screenshotDir);
         }
 
-        void LateUpdate()
+        void Update()
         {
-            if (UnityEngine.Event.current.Equals(ScreenKeyEvent))
+            if (UnityEngine.Event.current.Equals(CharacterSettingsKeyEvent))
+            {
+                showingUI = !showingUI;
+            }
+            else if (UnityEngine.Event.current.Equals(ScreenKeyEvent))
             {
-                string filename = Path.Combine(screenshotDir, $"Koikatsu-{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss")}.png");
+                string filename = Path.Combine(screenshotDir, $"Koikatsu -{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss")}.png");
                 StartCoroutine(TakeScreenshot(filename));
             }
             else if (UnityEngine.Event.current.Equals(CharacterKeyEvent))
@@ -41,6 +82,7 @@ namespace Screencap
             }
         }
 
+
         IEnumerator TakeScreenshot(string filename)
         {
             Application.CaptureScreenshot(filename);
@@ -55,62 +97,143 @@ namespace Screencap
         void TakeCharScreenshot(string filename)
         {
             Camera.main.backgroundColor = Color.clear;
-            var tex = RenderCamera(Camera.main);
-            File.WriteAllBytes(filename, tex.EncodeToPNG());
-            Destroy(tex);
+
+            switch (RenderMethod)
+            {
+                case 0: //legacy
+                default:
+                    File.WriteAllBytes(filename, LegacyRenderer.RenderCamera(ResolutionX, ResolutionY, DownscalingRate, AntiAliasing));
+                    break;
+                case 1: //alphashot
+                    File.WriteAllBytes(filename, AlphaShot.Capture(ResolutionX, ResolutionY, DownscalingRate, AntiAliasing));
+                    break;
+            }
+
             Illusion.Game.Utils.Sound.Play(SystemSE.photo);
             BepInLogger.Log($"Character screenshot saved to {filename}", true);
         }
 
-        Texture2D RenderCamera(Camera cam)
+
+        #region UI
+        private Rect UI = new Rect(20, 20, 160, 250);
+        private bool showingUI = false;
+
+        void OnGUI()
         {
-            var go = new GameObject();
-            Camera renderCam = go.AddComponent<Camera>();
-            renderCam.CopyFrom(Camera.main);
-            CopyComponents(Camera.main.gameObject, renderCam.gameObject);
-
-            renderCam.targetTexture = new RenderTexture(2048, 2048, 32); //((int)cam.pixelRect.width, (int)cam.pixelRect.height, 32);
-            renderCam.aspect = renderCam.targetTexture.width / (float)renderCam.targetTexture.height;
-            RenderTexture currentRT = RenderTexture.active;
-            RenderTexture.active = renderCam.targetTexture;
-
-            renderCam.Render();
-            Texture2D image = new Texture2D(renderCam.targetTexture.width, renderCam.targetTexture.height);
-            image.ReadPixels(new Rect(0, 0, renderCam.targetTexture.width, renderCam.targetTexture.height), 0, 0);
-            image.Apply();
-            RenderTexture.active = currentRT;
-            Destroy(renderCam.targetTexture);
-            Destroy(renderCam);
-            return image;
+            if (showingUI)
+                UI = GUI.Window(Name.GetHashCode() + 0, UI, WindowFunction, "Rendering settings");
         }
 
-        void CopyComponents(GameObject original, GameObject target)
+        void WindowFunction(int windowID)
         {
-            foreach (Component component in original.GetComponents<Component>())
+            GUI.Label(new Rect(0, 20, 160, 20), "Output resolution", new GUIStyle
             {
-                var newComponent = CopyComponent(component, target);
+                alignment = TextAnchor.MiddleCenter,
+                normal = new GUIStyleState
+                {
+                    textColor = Color.white
+                }
+            });
 
-                if (component is MonoBehaviour)
+            GUI.Label(new Rect(0, 40, 160, 20), "x", new GUIStyle
+            {
+                alignment = TextAnchor.MiddleCenter,
+                normal = new GUIStyleState
                 {
-                    var behavior = (MonoBehaviour)component;
+                    textColor = Color.white
+                }
+            });
+
+            string resX = GUI.TextField(new Rect(10, 40, 60, 20), ResolutionX.ToString());
 
-                    (newComponent as MonoBehaviour).enabled = behavior.enabled;
+            string resY = GUI.TextField(new Rect(90, 40, 60, 20), ResolutionY.ToString());
+
+            bool screenSize = GUI.Button(new Rect(10, 65, 140, 20), "Set to screen size");
+
+
+            GUI.Label(new Rect(0, 90, 160, 20), "Downscaling rate", new GUIStyle
+            {
+                alignment = TextAnchor.MiddleCenter,
+                normal = new GUIStyleState
+                {
+                    textColor = Color.white
                 }
-            }
-        }
+            });
 
-        //https://answers.unity.com/questions/458207/copy-a-component-at-runtime.html
-        Component CopyComponent(Component original, GameObject destination)
-        {
-            System.Type type = original.GetType();
-            Component copy = destination.AddComponent(type);
-            // Copied fields can be restricted with BindingFlags
-            System.Reflection.FieldInfo[] fields = type.GetFields();
-            foreach (System.Reflection.FieldInfo field in fields)
+
+            int downscale = (int)Math.Round(GUI.HorizontalSlider(new Rect(10, 113, 120, 20), DownscalingRate, 1, 4));
+
+            GUI.Label(new Rect(0, 110, 150, 20), $"{downscale}x", new GUIStyle
             {
-                field.SetValue(copy, field.GetValue(original));
+                alignment = TextAnchor.UpperRight,
+                normal = new GUIStyleState
+                {
+                    textColor = Color.white
+                }
+            });
+
+
+            GUI.Label(new Rect(0, 130, 160, 20), "Antialiasing", new GUIStyle
+            {
+                alignment = TextAnchor.MiddleCenter,
+                normal = new GUIStyleState
+                {
+                    textColor = Color.white
+                }
+            });
+
+
+            int antia = (int)Math.Round(GUI.HorizontalSlider(new Rect(10, 153, 120, 20), AntiAliasing, 1, 16));
+
+            GUI.Label(new Rect(0, 150, 154, 20), $"{antia}x", new GUIStyle
+            {
+                alignment = TextAnchor.UpperRight,
+                normal = new GUIStyleState
+                {
+                    textColor = Color.white
+                }
+            });
+
+
+            GUI.Label(new Rect(0, 170, 160, 20), "Render method", new GUIStyle
+            {
+                alignment = TextAnchor.MiddleCenter,
+                normal = new GUIStyleState
+                {
+                    textColor = Color.white
+                }
+            });
+
+            int renderMethod = GUI.SelectionGrid(new Rect(10, 190, 140, 50), RenderMethod, new[] { "Legacy", "AlphaShot" }, 1);
+
+
+
+            if (GUI.changed)
+            {
+                BepInEx.Config.SaveOnConfigSet = false;
+
+                if (int.TryParse(resX, out int x))
+                    ResolutionX = Mathf.Clamp(x, 2, 4096);
+
+                if (int.TryParse(resY, out int y))
+                    ResolutionY = Mathf.Clamp(y, 2, 4096);
+
+                if (screenSize)
+                {
+                    ResolutionX = Screen.width;
+                    ResolutionY = Screen.height;
+                }
+
+                DownscalingRate = downscale;
+                AntiAliasing = antia;
+                RenderMethod = renderMethod;
+
+                BepInEx.Config.SaveOnConfigSet = true;
+                BepInEx.Config.SaveConfig();
             }
-            return copy;
+
+            GUI.DragWindow();
         }
+        #endregion
     }
 }