Batch Visualization

Hi all,

I’m looking to implement a tool to visualize batches. Imagine a new option in the Scene View Control Bar under “Mipmaps” called “Batches”.

When a user selects this mode they will be shown the boundaries of each batch. E.g. if we have a scene with 4 statically batched trees these trees will be colored Red (or whatever color). Essentially each unique color defines a batch.

How could I implement this?

I’m aware about the frame debugger also but I wanted to see if this idea is possible.

Thanks,

Avinash.

This has several problems which are “hard” up to “not possible”:

  • First of all the rendermode dropdown field is hardcoded into the editor GUI of the sceneview. The modes are defined by an enum (DrawCameraMode) and each SceneView has a field(“m_RenderMode”) which defines the current rendermode.
  • The actual implementation of each rendermode is actually done in the engine’s core. So the render system itself handles the actual specialized rendering.

Even if you provide your own way of handling this you will face other problems:

  • You can’t really determine how many batches there are and what objects belong to which batch. Without that information it’s getting really difficult to get an accurate result.
  • If you implement your own custom rendering to show the batches, it will mess up the actual stats since your special rendering will change the number of batches and how they actually batch.

Like @tanoshimi said such a feature involves way too many low level interaction with the engine itself. So it’s way easier for Unity Technologies to implement such feature as they have access to the actual batches. All they have to do is render each batch with a replacement shader with a distinct color. It might sound a bit too easy, but it’s still easier for them to implement something like that than for us.

You can use this code to colorize batch groups at runtime

public static class BatchesViewer
{
    private const string CombinedMeshNamePrefix = "Combined Mesh";

    public static void Show()
    {
        var batchedGroups = GetAllBatchedMeshFilters()
            .GroupBy(mf => mf.mesh.name)
            .ToDictionary(group => group.Key, group => group.ToList());
        
        var textures = GenerateColorTextures(batchedGroups.Count);
        var id = 0;
        foreach (var (_, meshFilters) in batchedGroups)
        {
            var texture = textures[id++];
            foreach (var meshFilter in meshFilters)
            {
                var renderer = meshFilter.GetComponent<Renderer>();
                if(renderer == null)
                    continue;
                foreach (var material in renderer.materials)
                {
                    material.mainTexture = texture;
                }
            }
        }
    }

    private static IEnumerable<MeshFilter> GetAllBatchedMeshFilters()
    {
        return Object
            .FindObjectsByType<MeshFilter>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)
            .Where(mf => mf.mesh.name.StartsWith(CombinedMeshNamePrefix))
            .ToList();
    }

    private static IList<Texture> GenerateColorTextures(int count)
    {
        var textures = new List<Texture>();
        for (var i = 0; i < count; i++)
        {
            var color = GetRandomColor();
            var texture = GenerateColorTexture(color);
            textures.Add(texture);
        }
        return textures;
    }

    private static Color GetRandomColor()
    {
        return Random.ColorHSV(0, 1, 1, 1, 1, 1);
    }
    
    private static Texture GenerateColorTexture(Color color)
    {
        var texture = new Texture2D(1, 1);
        texture.SetPixel(0, 0, color);
        texture.Apply();
        return texture;
    }
}