Here’s a quick glimpse of the forest covering about a quarter of Hairlock’s tiny world. You bet the large flowers that you see at the bottom are generated/cloned on the fly.
How much plant growth can I afford within frame rate? Probably not as much as I’d like, but little is better than nothing and at least the ground recipe is set. Here’s a quick summary:
- I define growth per material. So if the terrain has grass, something can grow on the grass, and so forth.
- Growth isn’t just random. It uses random sources, then randomizes plant locations within (it could be anything. Bones? Bones grow in the desert, right?) and their density. This helps a little because plants aren’t just there to decorate. Pseudo-random distributions also help the player orient themselves a little, acting as landmarks in the landscape.
- It’s not too hard to hit the roof on how many decorations can be added to a 3D scene. If you double the definition of a 3D model, you don’t double the number of pixels rendered for that model. On the other hand, if I double the number of flowers in a scene, you really draw twice as many pixels over.
- Better news, there’s no practical limit to how many species of plants you might throw in your game. In this scene, I have only a couple of species (water lillies lost in the fog on the left) but that’s not a rendering limitation – from a design point of view, the trick is not to throw everything in at the same time: if we get our players to find stuff less often, we’re surprising them more often.
- A side effect of having to pack geometry together (well yea… we can’t call glDrawElements once per flower, right?) is that it’s probably OK to vary the size, shape and color of each element. Haven’t tried yet.
Putting this up has been a little troublesome. as I’ve just mentioned, we can’t just draw each element on the fly, which makes things a little harder
- For a given terrain (a piece of the 3D world), sources for growth are evaluated the first time the terrain is rendered. Each source will contain many instances of the same decoration, but we don’t evaluate anything at this point.
- Sources pass a test to make sure they’re in-bound. The first time a source passes the test, memory is allocated for all flowers (or whatever) within that source. Then the terrain is intersected to find the insertion point of each element.
- For each source, geometry for each element has to be duplicated (remember, we’re trying to call glDrawElements less often). This means the allocation for each source is… sizable. Surely we don’t want to evaluate each rendered source every time. So we cache the sources. So we quickly arrive at a point where the memory is filled with, wow, bouquets of low poly models (here, roughly 30 triangles each).
- In a first approach, I release geometry for sources that haven’t been drawn for a while.
The trees in the pic are also randomized. But these are large enough (and the geometry is much heavier) so I just use gl operations to transform and render each tree.
By the way these trees have been around for at least a month, time to change them for something better I guess :) The decorator module wasn’t really hard to write – just a little more than an evening’s job.