Unity URP Overdraw相关记录

2024/06 25 14:06

一、官方URP提供了RenderingDebugger功能,可以在Game视图绘制出Overdraw的内容; 但是所有涉及的Shader都需要修改

二、在Scene视图,仍然可以通过SceneView的SetSceneViewShaderReplace,达到在Scene视图中,渲染自定义Shader

做法:

public class SceneDebugViews
{
private static readonly Dictionary<SceneView, SceneView.CameraMode> PreviousCameraMode = new();

[InitializeOnLoadMethod]
public static void HookIntoSceneView()
{
    EditorApplication.delayCall += () =>
    {
        SceneView.ClearUserDefinedCameraModes();

        foreach(var ddm in SceneDebugViewsAsset.Instance.DebugDrawModes)
        {
            if ( !string.IsNullOrEmpty(ddm.name) && !string.IsNullOrEmpty(ddm.category))
            {
                SceneView.AddCameraMode(ddm.name, ddm.category);
            }
        }

        EditorApplication.update += () =>
        {
            foreach (SceneView view in SceneView.sceneViews)
            {
                if (!PreviousCameraMode.ContainsKey(view) || PreviousCameraMode[view] != view.cameraMode)
                {
                    view.SetSceneViewShaderReplace(GetDrawModeShader(view.cameraMode), "");
                }

                PreviousCameraMode[view] = view.cameraMode;
            }
        };
    };
}

private static Shader GetDrawModeShader(SceneView.CameraMode mode)
{
    foreach(var ddm in SceneDebugViewsAsset.Instance.DebugDrawModes)
    {
        if (string.IsNullOrEmpty(ddm.name) || mode.name != ddm.name)
        {
            continue;
        }

        Shader shader = ddm.shader;
        if (shader != null)
        {
            return shader;
        }
    }

    return null;
}

[MenuItem("GameObject/SceneCamera/Follow", false)]
public static void FollowCamera()
{
    var obj = Selection.activeObject as GameObject;
    if ( obj == null)
    {
        return;
    }
    SetSceneCamTransformData(obj.transform.position, obj.transform.rotation);
}

static public void SetSceneCamTransformData(Vector3 position, Quaternion rotation)
{
    var scene_view = UnityEditor.SceneView.lastActiveSceneView;
    scene_view.rotation = rotation;
    scene_view.pivot = position + rotation * new Vector3(0, 0, scene_view.cameraDistance);
    scene_view.Repaint();
}

[CreateAssetMenu(fileName = "SceneDebugViews.asset", menuName = "ASG/SceneDebugViewsAsset")]
public class SceneDebugViewsAsset : ScriptableObject
{
    [Serializable]
    public struct CustomDrawMode
    {
        public string name;
        public string category;
        public Shader shader;
    }

    public List<CustomDrawMode> DebugDrawModes;

    private static SceneDebugViewsAsset cachedInstance;


    public static SceneDebugViewsAsset Instance
    {
        get
        {
            if (cachedInstance == null)
            {
                cachedInstance = AssetDatabase.LoadAssetAtPath<SceneDebugViewsAsset>(
                        "SceneDebugViews.asset");
            }

            return cachedInstance;
        }
    }
}

Shader只输出透明颜色就行了

Shader "Hidden/DebugView/Overdraw"
{
    SubShader
    {
        Tags
        {
            "Queue"="Transparent" "RenderType"="Transparent"
        }
        Pass
        {
            ZWrite Off
            ZTest Always
            Blend One One

            CGPROGRAM           
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
            };
            struct v2f
            {
                float4 vertex : SV_POSITION;
            };
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            float4 frag() : SV_TARGET 
            {
                return fixed4(0.1, 0.04, 0.02, 1);
            }
            ENDCG
        }
    }
}