侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

Unity3D研究院之获取FrameDebugger每帧颜色数据

2023-01-17 星期二 / 0 评论 / 0 点赞 / 140 阅读 / 26039 字

最近一直在思考如何能更好的做优化渲染,本篇文章只是另一种实现的思路,其实我也没完全想好怎么应用到实际游戏中来统计,希望各位看官多多提宝贵意见。 1.本例Unity的版本是Unity2019.3.

.

           


最近一直在思考如何能更好的做优化渲染,本篇文章只是另一种实现的思路,其实我也没完全想好怎么应用到实际游戏中来统计,希望各位看官多多提宝贵意见。


1.本例Unity的版本是Unity2019.3.1.4


2.采用URP渲染管线,老的渲染管线没有试过,大家可以试试看。


3.FrameDebugger会将每一这数据存入RT中,名字对应如下。



实际代码中就可以这样取到它的Texture了


            Texture texture = Shader.GetGlobalTexture("_CameraColorTexture");            if (!texture)            {                texture = Shader.GetGlobalTexture("_CameraOpaqueTexture");            }


并非所有都能取,比如shadowmap的RT,这名字是没有意义的,如果真想取,那就用C#反射吧。但其实有上面两个基本已经够用了。



4.为了让代码更快的比较两帧图片的颜色,我采用了Burst编译比暴力的for循环快的可不是一点点。


5.为了让工具更加方便,不得不在代码中做了很多反射FrameDebugger的代码。


工具使用之前,大家可以先用FrameDebugger看一下自己需要截那些帧的数据。接着运行Unity,填入开始和结束帧的索引后,点击开始截取按钮即可。



截取完毕后,左边会保存每帧截取的图片,最后还会生成一张第1张和最后一张的中像素变化的图片(红色的区域就表示变化)还会输出最终像素数,重复像素数,总渲染顶点数。



在回到优化上来


1.重复像素数越多,其实就是半透明overdraw比较多。


2.最终像素数表示,光栅化后mesh最终呈现的颜色数。


3.总渲染顶点数,这个数值就很重要的。比如模型参与渲染了好几万个顶点,然而结果最终只贡献给屏幕20个像素,那这显然就不太合理了。


一些问题


1.如果摄像机会移动,那么就会造成有时候离模型近,有时候离的远,这样统计就不准确的。


2.如果使用RenderDoc能看到的信息会更多,我也比较推荐用Renderdoc,这篇文章只是开放一下思路。


上代码


using System;using System.Collections;using System.IO;using System.Reflection;using UnityEditor;using UnityEngine;using Unity.EditorCoroutines.Editor;using Unity.Collections;using Unity.Burst;using Unity.Jobs;using Unity.Mathematics;public class FrameDebugExamplle : EditorWindow{     static Type s_frameDebugType = Type.GetType("UnityEditorInternal.FrameDebuggerUtility,UnityEditor");    static Type s_frameDebugWindowsType = Type.GetType("UnityEditor.FrameDebuggerWindow,UnityEditor");    static bool s_HasLatSample;    static NativeArray<Color> s_LastSample2DColor;    static NativeArray<Color> s_FirstSample2DColor;    static int s_FinalPixel = 0;    static int s_ProcessPixel = 0;    static int s_VertexCount = 0;    static int s_StartDC;    static int s_EndDC;    static string s_Result;    static string DirectoryPath = "Assets/采样";    static EditorWindow s_FrameDebugWindows;     [MenuItem("Example/开始")]     public static void ShowWindow()    {        OpenAndEnableFrameDebugger();    }     void OnGUI()    {        int count = (int)s_frameDebugType.GetProperty("count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static).GetValue(null);        if (count == 0)        {                        OpenAndEnableFrameDebugger();        }        GUILayout.Label(string.Format($"DC区间 0 - {count}"));        s_StartDC = Mathf.Clamp(EditorGUILayout.IntField("开始", s_StartDC),0,count - 1);        s_EndDC = Mathf.Max(Mathf.Clamp(EditorGUILayout.IntField("结束", s_EndDC),0,count), s_StartDC);                   if (GUILayout.Button($"开始截取: {s_StartDC}DC-{s_EndDC}DC", GUILayout.Width(200), GUILayout.Height(50)))        {            OpenAndEnableFrameDebugger();            EditorCoroutineUtility.StartCoroutineOwnerless(StartGetData());        }        GUILayout.Label(s_Result);    }         IEnumerator WaitFive(int count)    {        for (int i = 0; i < count; i++)        {            yield return null;        }    }        IEnumerator StartGetData()    {        s_VertexCount = 0;        s_ProcessPixel = 0;        s_FinalPixel = 0;        s_Result = string.Empty;        s_HasLatSample = false;        FileUtil.DeleteFileOrDirectory(DirectoryPath);        Directory.CreateDirectory(DirectoryPath);         for (int i = s_StartDC; i <= s_EndDC; i++)        {            s_frameDebugType.GetProperty("limit", BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static).SetValue(null, i);            yield return WaitFive(1);             RefreshFrameDebuggerWindows();            yield return WaitFive(1);                         Texture2D textureSample = TextureSample();            Color[] colorBuffer = textureSample.GetPixels();            if (textureSample)            {                File.WriteAllBytes($"{DirectoryPath}/开始{i}.jpg", textureSample.EncodeToJPG());                if (!s_FirstSample2DColor.IsCreated)                {                    s_FirstSample2DColor = new NativeArray<Color>(colorBuffer, Allocator.Persistent);                }                if (s_HasLatSample)                {                                        var Job = new JobDiff                    {                        result = new NativeArray<int>(1, Allocator.TempJob),                        current = new NativeArray<Color>(colorBuffer, Allocator.TempJob),                        last = s_LastSample2DColor,                    };                    Job.Schedule(s_LastSample2DColor.Length, new JobHandle()).Complete();                    s_ProcessPixel += Job.result[0];                    Job.current.Dispose();                    Job.result.Dispose();                    s_LastSample2DColor.Dispose();                                        EditorWindow windows = EditorWindow.GetWindow(s_frameDebugWindowsType);                    FieldInfo info = windows.GetType().GetField("m_CurEventData", BindingFlags.Instance | BindingFlags.NonPublic);                     object FrameDebuggerEventData = info.GetValue(windows);                    if (FrameDebuggerEventData != null)                    {                        s_VertexCount +=   (int)FrameDebuggerEventData.GetType().GetField("vertexCount", BindingFlags.Instance | BindingFlags.Public).GetValue(FrameDebuggerEventData);                    }                }                if (i != s_EndDC)                {                    s_HasLatSample = true;                    s_LastSample2DColor = new NativeArray<Color>(colorBuffer, Allocator.Persistent);                }                else                {                                        Texture2D diff = textureSample;                    var Job = new JobFinalDiff                    {                        result = new NativeArray<int>(1, Allocator.TempJob),                        first = s_FirstSample2DColor,                        end = new NativeArray<Color>(colorBuffer, Allocator.TempJob),                    };                    Job.Schedule(s_FirstSample2DColor.Length, new JobHandle()).Complete();                    s_FinalPixel = Job.result[0];                    diff.SetPixels(Job.end.ToArray());                    Job.end.Dispose();                    Job.result.Dispose();                    s_FirstSample2DColor.Dispose();                    File.WriteAllBytes($"{DirectoryPath}/变化.jpg", diff.EncodeToJPG());                }            }        }        int pixelSqrt = (int)Mathf.Sqrt((s_ProcessPixel - s_FinalPixel));        int finalPixelSqrt = (int)Mathf.Sqrt(s_FinalPixel);        s_Result = $"最终像素 {finalPixelSqrt} X {finalPixelSqrt} 重复像素 {pixelSqrt} x {pixelSqrt} 总渲染顶点数 {s_VertexCount}";        AssetDatabase.Refresh();    }    static Texture2D TextureSample()    {        try        {            Texture texture = Shader.GetGlobalTexture("_CameraColorTexture");            if (!texture)            {                texture = Shader.GetGlobalTexture("_CameraOpaqueTexture");            }            if (!texture)            {                Debug.LogError("没有截到图输出错误");            }            if (texture)            {                var width = texture.width;                var height = texture.height;                RenderTexture previous = RenderTexture.active;                RenderTexture tmp = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.sRGB);                Graphics.Blit(texture, tmp);                RenderTexture.active = tmp;                Texture2D @new = new Texture2D(width, height);                @new.ReadPixels(new Rect(0, 0, width, height), 0, 0);                @new.Apply();                RenderTexture.active = previous;                return @new;            }        }        catch (Exception e)        {            Debug.LogError("没有截到图输出错误: " + e);        }        return null;    }     static void OpenAndEnableFrameDebugger()    {        EditorWindow.GetWindow(typeof(FrameDebugExamplle), true, "标题", true);                s_FrameDebugWindows = EditorWindow.GetWindow(s_frameDebugWindowsType);        s_frameDebugWindowsType.GetMethod("EnableIfNeeded", BindingFlags.Instance | BindingFlags.Public).Invoke(s_FrameDebugWindows, null);    }     static void RefreshFrameDebuggerWindows()    {        Type windowsType = Type.GetType("UnityEditor.FrameDebuggerWindow,UnityEditor");        var windows = EditorWindow.GetWindow(windowsType);        windowsType.GetMethod("RepaintOnLimitChange", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(windows, null);    }      [BurstCompile]    struct JobDiff : IJobFor    {        [ReadOnly] public NativeArray<Color> current;        [ReadOnly] public NativeArray<Color> last;        public NativeArray<int> result;         public void Execute(int index)        {                        result[0] += math.select(0, 1, current[index] != last[index]);        }    }    [BurstCompile]    struct JobFinalDiff : IJobFor    {        [ReadOnly] public NativeArray<Color> first;        public NativeArray<Color> end;        public NativeArray<int> result;        public void Execute(int index)        {            if(end[index] != first[index])            {                end[index] = Color.red;                result[0]++;            }        }    }}

       



往期精选

Unity3D游戏开发中100+效果的实现和源码大全 - 收藏起来肯定用得着

Shader学习应该如何切入?


喵的Unity游戏开发之路 - 从入门到精通的学习线路和全教程



声明:发布此文是出于传递更多知识以供交流学习之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与我们联系,我们将及时更正、删除,谢谢。

作者:雨松MOMO

原文:https://www.xuanyusong.com/archives/4745



More:【微信公众号】 u3dnotes



.

本文分享自微信公众号 - Unity3D游戏开发精华教程干货(u3dnotes)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

广告 广告

评论区