It’s been a really productive week!

It’s a huge changelog for the week, so I’ve sorted it by heading.

Architecture

  • Re-enabled some missing options in Architecture mode – stairs (up/down/both), ramps, and bridges. They mostly work, but fixing them is on next week’s board. In particular, selection needs to be a bit smarter to handle pre-planning 3D structures and placing future floors/stairs.

Mining

  • Fixed the Mining hotkey (D-M), it was firing up Harvest mode due to a copy-paste error.
  • Finished single layer designation mode. This is mostly for mining, but can be useful elsewhere. Rather than render a glorious 3D chunk (super optimized and with hidden cells taken out), it renders a single z-layer with hidden tiles rendered as “unknown” tiles. That lets you designate a large mining job, including areas that you have yet to reveal.
  • Mining cursors are working in 3D. You can designate a large mining job and still have a frame of reference for the placement of stairs and similar. The tooltips are too forgiving right now, telling you all about areas that you haven’t revealed yet (fixing that is on next week’s list).
  • Mining AI is functional, but buggy (it tends to have problems with getting stuck when it finishes). Despite this, you can mine out an area and see what’s going on.

Art Assets

  • Added initial voxel models for oil, powder, ore, boulders, etc. These aren’t colored in yet, but they are sufficient to let me test that they are spawning correctly from mining.
  • Added stonecutter and smelter models.
  • Created initial voxel models for deer, badger, armadillo (looks awful!) and horses. Ensured that they are spawning properly in the Wildlife Management system.
  • Added a texture for plasteel floors; the bottom of the ship had turned pink (my “you forgot a texture!” graphic is neon pink).
  • Added some normal adjustments to plasteel girders, to make them less boring.
  • I managed to squeeze out voxel models for loom, glass furnace, distillery, kiln and charcoal burner workshops.

Code Improvements

  • Refactor spree, removing unused variables this time.
  • Fixed an entertaining bug that wildlife would never move, it would just drop poop. I truly have no recollection of adding pooping animals to the game, but it’s there. It even has some initial systems for gathering dung, extracting ammonia/fertilizer and making bombs.
  • Fixed an issue that settlers wouldn’t fire their pistols, preferring instead to hit creatures with them. Lost several settlers to charging at a horse and attempting to beat it to death because they were hungry. It turns out that non-moving critters weren’t resetting their initiative properly either, and would insta-kill anyone who approached in a flurry of stomping.
  • Did some memory management cleanup. In particular, terrain chunks weren’t clearing an intermediate buffer after use (and weren’t shrinking the buffer after clearing). Memory usage is now a stable 2 Gb throughout play in my testing, although it can grow as you make the world more complicated.
  • Moved the lighting pass shader to a class, and cached uniform IDs for a small speed-up (and a surprisingly big speedup on Intel graphics).
  • Distance maps (basically Dijkstra maps, but with varied heuristics for some map types) now use the in-built thread-pool to update in the background. This gave a surprisingly big performance improvement, since it no longer creates/detaches/destroys threads during play.
  • Did some heavy profiling, and found that my use of vector<bool> was biting me in the bum. In particular, calls to std::fill were performing terribly; clearing the visibile tile list (prior to rebuilding it) was eating nearly 5% of my frame cycle time! The assembly showed that instead of a memset it was doing it the hard way on Visual Studio (Clang/GCC didn’t have this problem). I first tried moving to a sparse map/unordered_map/flat_map structure, but performance actually worsened. Replaced them with a vector<char> (and accepted the additional memory usage with a sigh), and suddenly it’s down to 0.01% of frame CPU time – and a single memset is taking care of it. This broke save compatibility, which isn’t really a big deal at this stage.
  • Distance maps now pre-allocate some space in the open node list prior to running, which shaved off a bunch of CPU time being wasted on allocation.
  • The shadow buffer now includes voxels models.
  • Fixed a crash bug that occasionally hit when building the instance-render VBO for voxel models. It turns out that I’m bad at arithmetic, and my size was off.

Render Engine

  • Found a problem with my normals; they were going into an RGB8 buffer in the gbuffer (deferred render stage), and weren’t being consistently transformed into positive numbers before storage (and then converted back). Switched to an RGB16F buffer, which handles negatives just fine and everything looked better.
  • Screen Space Ambient Occlusion. I was a little skeptical of the value of SSAO, having seen some of the “SSAO abominations” pages people have put up. I was also worried about my framerate. Despite this, I had exactly the problem that SSAO is meant to fix: muddy pictures with poor differentiation between edges. After a bunch of trying different things, I realized I could simplify the process quite a bit. It takes 64 random triplets in as a uniform (I only set them once), and then for each pixel it takes the SCREEN position and randomly hits a neighbor offset by the random numbers (scaled so as to keep it local). I then read the depth texture for each hit, and if it is closer than the depth of the current pixel – it adds an occlusion. The occlusion weight is total occlusions divided by kernel size (and then inverted, so unoccluded is white). The results are spectacular – see the screenshots below. Now it’s in, I can’t believe I didn’t have it before.
  • Environmental ambient lighting. A lot of PBR toolchains calculate the ambient component by sampling an environment map for each pixel. These are typically pre-calculated, which I can’t do in a dynamic environment (the map can completely change). Since I was already running a sampling kernel, I simply sample the color of neighboring ocluders as well – and average it into the ambient light color.

I also did a bunch of optimizing of my regular game loop per-frame. It’s too big to list here, so here is a graphic showing the flow

. Hopefully, this can be of some use to someone else crazy enough to build their own engine… this is mostly for my use, but it may be useful to someone.

Screenshots

  • . Notice that the colors are more uniform, there’s less stippling and the edges of trees are more clearly defined so it’s a lot easier to see what’s going on.
  • Where SSAO really shines is when you zoom in
  • . The detail on the Cordex and Replicator models is really visible now. It’s also highlighting a geometry bug I have to fix on rear-facing walls (they are missing a triangle!). You can also see the effects of ambient light on the floor – the subtle grey reflection around Cordex.
  • Designating some trees for chopping. Again, SSAO has really brought out the detail of the selection, it’s much crisper/clearer and less muddy.
  • We’ve built a lumber camp, consisting of 3 tents, a nuclear camp fire (it’s a nuclear-powered fire for camping trips with an automated marshmallow replicator), and a sawmill. The sawmill has a particle effect firing as it finishes cutting some wood. Note that auto-beamdown is in a deliberately crazy mode (new settlers every 24 hours of game time!), I wanted to stress-test the render engine.
  • We go into Architecture mode, and designate some wallsfor construction. The game crashed so I did it again and construction of walls began

Pre-SSAO

The SSAO layer

With SSAO

Zoomed out to see the crisp edges on forests.

SSAO really shines when you zoom in to see details.

A plethora of workshops