Generate many (32k) GameObjects approach

Here is the project in question. There are a bunch of scripts, but the one we’re concerned with is “GenerateMap.cs”, it’s in the Assets/Scripts folder.

This project loads unmodified Quake 1 maps, and recreates them in Unity, just like it says on the tin. Parsing the maps themselves into C# objects is very fast. Even massive (by Quake 1 standards) maps are fully parsed into ready to use C# objects in less than a second. The issue is when it’s time to make GameObjects for them.

Currently I’m making every surface in the map (called faces in .bsp lingo) into its own GameObject. On small deathmatch maps this results in about 3k objects, startup time of around a second, and 100fps. Great. On the massive maps, I end up with 32k GameObjects. It takes around 20 seconds to start, though performance isn’t too bad once it’s loaded, considering.

I’m not so concerned about the performance once the game is running, as I can implement the “vis” data from the .bsp and turn off the renderer on gameobjects that aren’t visible, but how can I speed up the generation of the GameObjects? Or is there a better way?

Each object has the following:

  • A mesh filter and renderer
  • A mesh collider
  • A texture that is generated at runtime from the .bsp itself

In case you can’t be bothered to look at the code, the basic process I’m using is this. Foreach face, create a gameobject, calculate the verts and tris for the mesh, calculate the uvs for the mesh, add components I need, add the verts, tris, and uvs to the mesh, recalculate normals, mark the object as static, done and onto the next face.

It’s very simple, but with so many objects, it’s slow to start up on the big maps. I don’t have Unity Pro, so I can’t use the profiler. Is there a valgrind/cachegrind type inspection I can perform somehow? Anyone have any tips on how I can speed this process up?

Some of the slowest things you can do in unity are creating gameobjects and creating meshes. The more stuff you can do before creating an object or assigning a mesh to it, the better.

I’m not convinced that you have to have every face as its own gameobject. Objects can have multiple materials - I think that’s controlled by submeshes. Pretty sure. Haven’t really touched them apart from directly copying them, though.

What I’d do is keep a dictionary of < Texture, Mesh > for face-textures to sub-meshes:

if ( dictionary.ContainsKey(currentFaceTexture) ) {
    targetSubmesh = dictionary[currentFaceTexture];
} else {
    targetSubmesh = new Mesh();
    dictionary.Add(currentFaceTexture, targetSubmesh);
}
targetSubmesh.AddVerticesAndUVsAndStuff(faceInfo); // this function probably doesn't exist

You’ll probably do well to generate chunks rather than a single massive object (one chunk per leaf is probably a good size). So build all your submeshes (remembering that the vertices have to be offset by the face’s position now, since they’re not each their own gameobject), then assign them to your main mesh, then assign that mesh to the chunk’s game object.