Thursday, July 19, 2012

About Fractal Combat 1.2

We recently released Fractal Combat 1.2 with drastically improved graphics for the environment.


For most terrains, I dropped my simple "plasma" generator and instead had Max create them with World Machine.

What's the tech angle on that ? ..it's the shift from procedural to compression. Two things that are in fact closer than they may seem. They are both about synthesizing data from a given source.
Procedural generated data is generally intended to come from a relatively small set of parameters, while decompression, which is more generic, starts off a much larger data set generated by the compression phase, which itself comes from an original.

So, these new terrains (still 2048x2048), had to be compressed.
The color data was easy: just JPEG.
The heightfield instead needed 16 bits per sample, but JPEG is limited to 8 bits. PNG supports 16 bits but it's a lossless format. There's no loss of quality, but the compression ratio is just too low on natural-looking images (or natural-looking heightfields in this case).
The solution was to make a new format which, at its core, uses the DCT transform like for JPEG, but that works with 16 bits samples.
That worked well and I got a decent compression ratio that kept the game at about 30 MB (including 2 new sound tracks added for the update).
The overall size of the game was previously less than 14 MB. It was important to keep below 20 MB so that people could download the game over 3G connections but, recently, that limit has been raised to 50 MB by Apple and so 30 is still small enough for downloading on-the-move.

I sometimes wonder how much are games really compressing their data. Some mobile games have very large data sets.. but I bet that they could be smaller with some extra effort.
Some users praise mobile games that take little space on their devices. But, on the other hand, I wonder if some other users aren't instead attracted by the prospect of a game with a big payload of data .."if it's big, it's got to be good !" 8)
Another thing that I did for the terrains is shadow baking.The baking is done in-house, because, firstly, I don't like the idea of another program doing the baking for me (!), secondly it's just more convenient.
With my own baking, I can change the light source and redo the baking quickly on the development PC.. (although the mobile devices are too slow for that and they simply get the baked data).

Another reason is that, for the future, I could export not simply the baking color but also the shadow volumes to be used to cast shadows on models in real-time.. even if just to roughly detect if a model is in shadow or not.

Baking took advantage of the fact that terrains are heightfields. So, samples are on a regular grid and one can   cast rays by simply (virtually) rasterizing a 3D line projected onto this 2048x2048 heightfield bitmap !
For each terrain cell to check, I rasterize a line from that sample to the light source and see if in that path there is another terrain cell whose height intersects the ray.

I also added bloom from the Sun itself during the game. Bloom is light scattered in the eye, so it's something that needs to be rendered of top of every 3D object, as long as any portion of that light source is visible.
I ended up casting the ray from the Sun to the eye point, checking if it intersects the ship.
If it does, then the Sun is not visible and no bloom at all should happen (obviously simplifying thigs a lot here as the Sun really isn't just a point !).

For that raycasting I used a generic voxel structure. In this case, the ray is converted from world-space to the local-space of the object/voxel and again, a 3D line is (virtually) rasterized to select the voxel cells that contain polygons that may be hit.
(I wish Blogger had a way to make quick sketches and insert them in a post.. but it doesn't so there's no visualization this time 8)

I put this voxel generation and line checking code online.. it depends on my code base, but most things are easily replaced with STL and an alternative float3/vec3 of choice.
It's probably quite buggy, so I wouldn't rely on it too much. Also the line checking method is a big hacky.. it uses local persistent storage for the result and it collects all of the cells of the voxel touched by the line, at once.
A better implementation would allow to iterate so that one could stop early.
Another drawback is that polygon IDs may be referred in multiple voxel cells. So, blindly checking every polygon in every cell selected, may lead to duplicate checks. But it's something that can be avoided if it turns out to be a bottleneck.

so.. woooo.. that was a lot of text compared to Twitter 8)
See the video ! -> https://vimeo.com/45743006