I mentioned earlier that the program is comprised of a bunch of different systems. There are three systems we’re interested in right now:
- Regions are abstract areas that have certain properties. Like, “stuff within these boundaries should be very hilly, moderately high, have bright green grass, etc”. It doesn’t contain any elevation or polygon data. It’s just an area of rules.
- Pages are blocks of elevation data. Right now, these are generated in one go. When a given page is requested, the program drops what it’s doing and generates it. This takes a while, leading to really annoying quarter-second lockups as you move around the world. Somebody should probably look into doing something about that.
- Terrains take the pages of data and make the polygons and textures.
Here is an overhead view:
I was careful to keep these systems independent of each other with regard to size. I can make regions tiny if I need to. It might be silly to have a sixteen-meter desert, but it’s good for testing.
I can make a page hold a lot of data, or a little. If I make them big, then I won’t need to generate them very often, but it will take a really long time when I do. If I make them small, they will be quick to create but I’ll need a lot of them, which might lead to sorting difficulties later when I need to figure out which of the hundreds of pages I should build first. I can experiment with different sizes for these systems by just changing a few variables.
In the above screenshot, we’re looking at a circle of terrains. I’ve put a red outline around a single terrain. You can also see the effect of regions, since each region has a different grass color. Eventually regions will represent different climates (a bit like Minecraft biomes) and so we’ll want them to feel kind of big. Here I’ve made regions 64 meters across, which is absurdly small, but it lets us see a lot of them at once.
I don’t think you’ll need to squint very hard to see the seams between the regions. What you’re seeing is the corner where four different regions meet, and each region has its own grass color. Right now these are just randomly chosen from a band of greens and yellows. Someday I’ll have them determined by climate, but for now it’s just a crapshoot.
This great big seam is obviously ugly. We can alleviate this by fading from one color to another.
That helps, but it also makes things a bit bland. If regions were normal sized (maybe four or eight times larger than they are now) the color changes would be so slight that you’d hardly see them. I don’t want to obliterate the region boundaries like this, I just want them to be less of a hard edge.
In my program I have a function to look up a region. “For the position x=63, y= 112, what region is that in and what does that region look like?” I just added a couple of lines of code to scatter these results. So, when you look up x=63, y= 112, you might actually get the results for x=52, y=100. These offsets are deterministic, meaning you’ll always get the same result for the same input numbers. They also follow a bell curve, giving a scatter of results with a few outliers. The result:
You can still see the region boundaries, which is good. It’s no good making unique areas and then blending them together in a big mush so that everything looks the same. So this is close to what I want. However, the scattered dots look a little ugly. They’re better than the seam, but let’s see what it looks like when we combine the scattering with the blending:
I like that. It keeps the “blocky” thing I’m going for, it breaks up that quilt-like grass texture, and preserves the variety between regions.
We’re nowhere near the point of being ready to optimize the program yet, but I do want to add a few basic things just to ease the development process. The program really chugs when I first start it up, and it shouldn’t need to. I hate having to wait ten or fifteen seconds to see the results every time I make a small change to the program. So let’s do some easy optimizations.
Right now I’m taking the polygons and throwing them at the graphics card every single frame. I’ve talked before about how monstrously slow that process can be.
Sending data to your graphics card is slow. (Relatively speaking.) Your graphics card is sort of like another computer. It has its own memory and its own processors. Your PC sends it a fat wad of data describing the position of the polygons in the world, and the GPU (your graphics card) has a jolly good think. When it's done, it sends back the finished image. (Basically.) The problem is: There's a limit to how fast data can be moved between the two. It's like two bustling cities with vast ten-lane highway systems, but between the two is just a dirt lane.
The answer for this problem is to use vertex buffers. You pack up the polygons and send them to live on the graphics card. It’s like having them move to the city so they don’t need to take that dirt road commute every frame. The cost is that this eats up a bit of graphics memory. Hang on, let me figure out how much…
Each vertex has an x, y, and z value. Each of those values takes up 4 bytes. Then each vertex has a normal to go with it, giving us another x, y, and z value. Then we need another pair of numbers to describe which part of the texture we’re using. Each terrain is 33×33 vertices. So 33 x 33 x (3 x 4 + 3 x 4 + 2 x 4) = 34,848 bytes. Thirty-four kilobytes of video memory. For contrast, the texture on several of these terrains is 3,145,728, or three megabytes. So, these vertex buffers are really, really trivial in size.
The speed increase is rather striking. The program still runs like a dog when it’s generating new pages, but at rest the framerate was around 50. Now it’s 350.
To give to a sense of scale, here is a shot from eye-level.
It’s still very barren, bit it’s a solid improvement over where were were last time around.
The Best of 2015
My picks for what was important, awesome, or worth talking about in 2015.
Best. Plot Twist. Ever.
Few people remember BioWare's Jade Empire, but it had a unique setting and a really well-executed plot twist.
Top 64 Videogames
Lists of 'best games ever' are dumb and annoying. But like a self-loathing hipster I made one anyway.
Push the Button!
Scenes from Half-Life 2:Episode 2, showing Gordon Freeman being a jerk.
Let's ruin everyone's fun by listing all the ways in which zombies can't work, couldn't happen, and don't make sense.