I hoped I would be finished with trees sooner rather than later for “True King,” but as I continued to place trees by hand, I realized my frame rate for this large open world was dropping bad before I had placed all of the forest. I noticed that the scene had a few million polygons, which is a big no-no (some sources online claim to target under 1 million polygons in Unity3D to avoid bad performance on most hardware). So I had to fix it…
As the above screenshot shows, an individual tree with a lot of polygons can easily slow down your system when building a forest, and those extra polygons really aren’t necessary. In fact, even on today’s most demanding games, tree leaves can look notoriously bad when seen up close. I don’t know why I didn’t model more carefully in the first place to avoid this issue, it ultimately wasted several days of time. But at least now, I think it’s about as good as I’ll make it, with about a 87% reduction in poly count, partly by using Blender3D’s built-in “Limited Dissolve” function to reduce polygons almost automatically, and partly by replacing Unity3D’s default spheres for the leave bushes with Blender3D’s icosphere for a good approximation.
I had assumed that replacing the tree fbx in my assets folder would automatically update all trees in the scene, but it turned out I was mistaken. And so it was required for me to replace all of the trees by hand again. From this point on, I have put each tree as a prefab object with predefined scripts and components, and tested that updating these prefabs will allow me to update the world’s forest much more easily.
This allowed me to have a few forests with a few thousand trees with reasonable frame rates… mostly. Near the end of me setting these trees, I noticed frame-rate issues again. The polygon count seemed acceptable, and things like lightmapping and static occlusion didn’t seem to improve any. It seemed reducing camera view-distance helped a bit, so I wondered if I still had too many objects on the screen.
I proceeded to start applying logic to replace far-away objects with 2D planes. Specifically for the trees, I replaced each leave bush with 2 quads (4 triangles total) to cover horizontal viewing angles, and did a few quads in a similar style for tree trunk and main branches. A script attached to every tree would check for camera distance to a tree to decide if the simpler model, using about 50 polygons instead of 1,500. For the most part, it looked good, and seemed worth the effort.
As I prepared this solution, it turned out Unity already had a built-in component for this: it’s called LOD (Level-Of-Detail), and Unity can allow me to define multiple versions of a model to simplify anything from a far distance. While my version of this saw slight improvements, Unity’s LOD was noticeably better, thanks mainly to its default to eventually turn OFF objects after a certain distance. With that, a big forest on the other end of the world would just be disabled until I got about half-way across the land. This is variable to quality settings set by the user when launching the game. I didn’t originally like this idea, but most of the scene on the other half of the world isn’t really visible anyway, and by the time it is (about the center of the world), the maximum amount of objects on the screen at once is basically cut in half.
So yes, now I have multiple forests that help fill the world. That took me far too long… oh, and about lightmapping: it fixed a lot of issues I had with distant objects flickering, but it also made my simplified trees disappear inexplicably. This seemed directly related to the material type I was using, called “Nature/Tree Soft Occulsion Leaves.” This is the only built-in shader that seemed to automatically render both sides of a quad with consistent unlit color, which was exactly what I needed, but that it is a “Occulsion” shader made it have a strange affect when set to static during lightmapping.
To fix this, I did my usual trick of only enabling (or setting static) specific objects I wanted before building lightmap. But at this point I had thousands of trees, I didn’t want to manually set the detailed trees to static and the simplified trees to not-static one-by-one! My solution was to study how to make “editor scripts,” which allow you to add new menu options in the editor to make your job easier. In my case, I made a script to automatically set objects to “static” or “not static” by defining which object names in the scene to search for with the following api:
And with that, I save a few hours of time with a single click.
Next, I’ll be focusing on small villages and the houses that make them up. They seem simple for now, and I’ll probably improve them a bit still, but my intention is to have different styles of houses in each town, and to make them simple enough that they or their textures can be combined programmably later… I’ll discuss that in more detail when I get that far.
I still don’t know exactly how other games manage to have tens of thousands of trees on screen with 60fps. I hope texture compression will help later to save RAM, and it also turned out the game build running outside of the editor seemed to double the frame rate anyway. Regardless, I’ll keep an eye out for other opportunities to improve this before I’m satisfied, I have a lot to learn still.