unity framedebug数据获取

大纲

  • 背景
  • 当前帧【event】数据获取
    • 获取FrameDebug Window
    • 获取FrameDebug中选中的Event数据
  • 一次debug的所有数据
    • 切换Event Index
    • 获取FrameEventData的数据
  • play状态下的问题
    • update的问题
    • 数据获取不到

背景

项目前期,基于人力和项目复杂度的情形下,我将项目使用的shader variant的采集搞成了ci化; 但是到了项目中后期,由于项目越来越复杂,ci采样的问题越发突出了!(而且由于不同项目使用的规则也有所不同。)

所以计划在年后更换方案;

但是现在有些bug,那就是运行时,有些场景中的某个物体不能正确渲染;

因为物体在不同的坏境下,都有可能导致使用的变体不一样!

因为ci已经跑了一轮比较泛的采样了,所以就只补充了一下在遇到渲染不一致的问题的时候,只需要项目组的成员在FrameDebug中找到渲染异常的物体后,保存该变体就可以!

当前帧【event】数据获取

想要获取unity当前帧要渲染的数据,肯定离不开FrameDebug的;但是FrameDebug是各种internal;想要获取数据就变得有点麻烦了~

获取FrameDebug Window

直接看看FrameDebug是怎么打开和Enable

var assembly = typeof(AnimationUtility).Assembly;
var FrameDebugWindows_Type = assembly.GetType("UnityEditor.FrameDebuggerWindow");


public static EditorWindow OpenAndEnableFrameDebug()
{
            // 强行开启framedebug
    EditorWindow frameDebuggerWindow = EditorWindow.GetWindow(FrameDebugWindows_Type);
    FrameDebugWindows_Type.GetMethod("EnableIfNeeded", BindingFlags.Instance | BindingFlags.Public).Invoke(frameDebuggerWindow, null);
    return frameDebuggerWindow;
}

通过反射的方式,我们获取到了FrameDebuggerWindow,并使得它Enable

获取FrameDebug中选中的Event数据

这里获取当前Event的渲染数据有两种方式,但是这里就说其中一种,另外一种在下面说明!

var DataEvent_FieldInfo = FrameDebugWindows_Type.GetField("m_CurEventData", BindingFlags.NonPublic | BindingFlags.Instance);
var FrameDebug_FrameDebuggerEventData_Type = assembly.GetType("UnityEditorInternal.FrameDebuggerEventData");


var data = DataEvent_FieldInfo.GetValue(frameDebuggerWindow);
var pi = FrameDebug_FrameDebuggerEventData_Type.GetField("shaderName");
var shadername = pi.GetValue(data) as string;
pi = FrameDebug_FrameDebuggerEventData_Type.GetField("passLightMode");
var passLightMode = pi.GetValue(data) as string;
            
data = DataEvent_FieldInfo.GetValue(frameDebuggerWindow);
pi = FrameDebug_FrameDebuggerEventData_Type.GetField("shaderKeywords");
var keyworlds = pi.GetValue(data) as string;

上面是直接反射了FrameDebuggerWindow中的m_CurEventData字段,因为FrameDebuggerWindow的展示中使用的也是这个字段中的内容,所以如果是获取选中的内容,直接反射界面中的内容即可!

获取到了shadername passLightMode keyworlds这三个后,就能将其加入到shadervariantcollection中了!

一次debug的所有数据

完成了上面的步骤后,放置在项目中使用的时候,项目成员不能很好把控哪个才是渲染不正确的,所以如果是需要选中指定的Event后在去获取shadervariant,那么容易导致有遗漏!于是就有后续——能一次性把当前帧的渲染变体都保存下来!

前文已经说了怎么启动FrameDebugWindowEnable了,我们在FrameDebugWindow的界面中能看到所有的Events和当前是处于哪个Event Index

方法一:切换Event Index后,使用当前帧【event】数据获取 的方式去获取数据

这里我们就说说方法二,该获取数据的方法也可以用在 当前帧【event】数据获取 中!

切换Event Index

var FrameDebuggerUtility_Type = assembly.GetType("UnityEditorInternal.FrameDebuggerUtility");
var FrameDebuggerUtility_limit = FrameDebuggerUtility_Type.GetProperty("limit", BindingFlags.Public | BindingFlags.Static);
var FrameDebuggerWindow_RepaintOnLimitChange = FrameDebugWindows_Type.GetMethod("RepaintOnLimitChange", BindingFlags.Instance | BindingFlags.NonPublic);


public static bool ChangeEventIndex(EditorWindow window, int index)
{

    int i = (int)FrameDebuggerUtility_limit.GetValue(null);
    if (i == index+1)
    {
        return false;
    }

    FrameDebuggerWindow_ChangeFrameEventLimit.Invoke(window, new object[] { index+1 });
    FrameDebuggerWindow_RepaintOnLimitChange.Invoke(window, null);
    return true;
}

利用反射,设置FrameDebuggerUtility的数据,这里是直接使用FrameDebuggerWindow:ChangeFrameEventLimitFrameDebuggerWindow:RepaintOnLimitChange去切换的

获取FrameEventData的数据

FrameDebuggerUtility:GetFrameEventData方法可以获取指定的EventIndex数据;但是需要先创建一个UnityEditorInternal.FrameDebuggerEventData对象;

var FrameDebuggerEventData_Type = assembly.GetType("UnityEditorInternal.FrameDebuggerEventData");

var frameEventData = Activator.CreateInstance(FrameDebuggerEventData_Type);

通过FrameDebuggerUtility:GetFrameEventData获取数据

var FrameDebuggerUtility_GetFrameEventData = FrameDebuggerUtility_Type.GetMethod("GetFrameEventData", BindingFlags.Static | BindingFlags.Public);
            
var flag = FrameDebuggerUtility_GetFrameEventData.Invoke(null, new object[]{index, frameEventData});

获取到的frameEventData对象后,就可以获取其内部的shadername passLightMode keyworlds!!

play状态下的问题

update的问题

由于Play的状态下,导致inspector的更新没有那么频繁,所以需要将界面不断设置为dirty才可以!

数据获取不到

因为获取数据是异步(可能吧,同步获取我偶尔也会获取不到!)所以最好是自己在Update中每次切换EventIndex的时候等一会!