/// <summary>
    /// inspect gui
    /// </summary>
    public override void OnInspectorGUI()
    {
        DrawCallRecorder dcr = target as DrawCallRecorder;

        base.OnInspectorGUI();

        if (GUILayout.Button("Calc Render Groups"))
        {
            CalcRenderGroups();
            debugColor = new Color[dcr.renderGroup.Count];
            for (int i = 0; i < dcr.renderGroup.Count; i++)
            {
                debugColor[i] = Random.ColorHSV();
            }
        }

        if (dcr.drawDebugBounds)
        {
            for (int i = 0; i < dcr.renderGroup?.Count; i++)
            {
                DrawBox(dcr.renderGroup[i].bound, debugColor[i]);
                for (int j = 0; j < dcr.renderGroup[i].renderers.Count; j++)
                {
                    DrawBox(dcr.renderGroup[i].renderers[j].bounds, debugColor[i]);
                }
            }
        }
    }
    void SplitRendererGroup()
    {
        DrawCallRecorder dcr = target as DrawCallRecorder;

        dcr.renderGroup.Clear();

        // sort along x-axis
        sceneRenderers.Sort((x1, x2) => (x1.bounds.min.x < x2.bounds.min.x) ? -1 : 1);

        // sort again along z-axis
        sceneRenderers.Sort((z1, z2) => (z1.bounds.min.z < z2.bounds.min.z) ? -1 : 1);

        // assign renderer to group
        int numRendererInGroup = (sceneRenderers.Count / dcr.groupUpperLimit) + 1;

        for (int i = 0; i < dcr.groupUpperLimit; i++)
        {
            DrawCallRecorder.RenderGroup rg = new DrawCallRecorder.RenderGroup();
            rg.renderers = new List <Renderer>();

            // add renderer to group
            for (int j = i * numRendererInGroup; j < i * numRendererInGroup + numRendererInGroup; j++)
            {
                if (j >= sceneRenderers.Count)
                {
                    break;
                }

                // ignore large bound object
                if (sceneRenderers[j].bounds.size.x * sceneRenderers[j].bounds.size.z > dcr.boundLimit)
                {
                    continue;
                }

                rg.renderers.Add(sceneRenderers[j]);
            }

            // calc renderer bounds
            rg.bound = CalcNewBounds(rg.renderers);

            dcr.renderGroup.Add(rg);
        }

        //// split bounds
        //SplitBounds(sceneRenderers, dcr.sceneBounds, 0);
        //rendererBounds.Clear();

        // total renderer
        int cnt = 0;

        for (int i = 0; i < dcr.renderGroup.Count; i++)
        {
            cnt += dcr.renderGroup[i].renderers.Count;
        }
        Debug.Log("Renderer Count: " + cnt);
    }
    void OnSceneGUI()
    {
        DrawCallRecorder dcr = target as DrawCallRecorder;

        if (dcr.drawDebugBounds)
        {
            gUIStyle.normal.textColor = Color.green;
            for (int i = 0; i < dcr.renderGroup?.Count; i++)
            {
                Handles.Label(dcr.renderGroup[i].bound.center, "Group " + i, gUIStyle);
            }
        }
    }
    void CalcRenderGroups()
    {
        Bounds           bounds = new Bounds();
        DrawCallRecorder dcr    = target as DrawCallRecorder;

        Renderer[] renderers = dcr.GetComponentsInChildren <Renderer>();
        rendererBounds = new List <Bounds>();
        sceneRenderers = new List <Renderer>();

        int processCount = 0;

        for (int i = 0; i < renderers.Length; i++)
        {
            MeshFilter mf = renderers[i].GetComponent <MeshFilter>();
            if (!mf)
            {
                continue;
            }

            if (MeshByte(mf.sharedMesh) != 56)
            {
                continue;
            }

            if (HasTransparent(renderers[i]))
            {
                continue;
            }

            Bounds b = renderers[i].bounds;
            bounds.Encapsulate(b);
            processCount++;
            rendererBounds.Add(b);
            sceneRenderers.Add(renderers[i]);
        }

        SplitRendererGroup();
        bounds.center   = (bounds.min + bounds.max) * 0.5f;
        dcr.sceneBounds = bounds;

        EditorSceneManager.MarkSceneDirty(dcr.gameObject.scene);
    }