Unity – Simple Static Batcher


This is a simple static batcher script (C#) that you can use in your Unity games. All items should normally use the same material. To use this script, attach it to an empty game object that will be the parent of batched children. It should create a MeshRenderer. Select the material that is used for the child objects. When Start is triggered the mesh’s contained in the children will be collected and created into one shared mesh attached to the empty parent object. Each of the child renderers is disabled but other components such as colliders are left alone.

This isn’t a phenomenal script or anything, its just really easy to use.

Four sets of spikes arranged around a floating block. Its a pretty safe bet that they are usually all visible at the same time. Note you don’t want to batch together lots of objects that won’t be in view at the same time together. Doing so destroys the performance gains of view frustum culling.
Screen Shot 2013-04-07 at 7.13.58 PM

Paused at runtime you can see the mesh created.
Screen Shot 2013-04-07 at 7.24.01 PM

using UnityEngine;
using System.Collections;
using System.Diagnostics;
// the mesh renderer must have the proper material for all combining meshes
[RequireComponent (typeof (MeshRenderer))]
public class StaticBatcher : MonoBehaviour {
    public float batchTimeMillis = 0;//you can view this in the editor or display through OnGUI

    void Start () {
        MeshFilter[] meshFilters = GetComponentsInChildren();

        var stopWatch = new Stopwatch();
        stopWatch.Start();
        CombineInstance[] combine = new CombineInstance[meshFilters.Length];

        for (int i = 0; i < meshFilters.Length; i++) {
            combine[i].mesh = meshFilters[i].sharedMesh;

            var curTransform = meshFilters[i].transform;

            var matrix = Matrix4x4.TRS(
                curTransform.localPosition, 
                curTransform.localRotation, 
                curTransform.localScale);

            curTransform = curTransform.parent;
            // calculate transformation for each mesh in terms of this game object (the batcher)
            // so that even children of children etc are transformed properly
            while(curTransform != null && curTransform != transform){
                matrix = Matrix4x4.TRS(
                    curTransform.localPosition, 
                    curTransform.localRotation, 
                    curTransform.localScale) * matrix;
                curTransform = curTransform.parent;
            }
            combine[i].transform = matrix;
            // turn off render of child component but leave the rest active, 
            // ie, colliders, scripts, etc
            meshFilters[i].gameObject.GetComponent().enabled = false;
        }

        if(gameObject.GetComponent() == null){
            gameObject.AddComponent();
            transform.GetComponent().mesh = new Mesh();
        }

        transform.GetComponent().mesh.CombineMeshes(combine);
        transform.gameObject.active = true;
        stopWatch.Stop();
        batchTimeMillis = 1000f*stopWatch.ElapsedTicks / Stopwatch.Frequency;
    }

    void OnGUI(){
        // an example of how you can view batch time
        //GUI.Box(new Rect( 0, 200, 150, 50), ""+batchTimeMillis);
    }
}

3 Comments.

  1. Thanx A lot! I was looking for this just yesterday as my game needs as much fps increase as I can get.

  2. does this work with occlusion culling?

    • I wouldn’t know, don’t use the pro version. If you have pro you may as well try using static batching instead of this though.