Air Battle of Midway - Blog Posts

Oct 23rd, 2019 - Anti-Aircraft Shell Blast Experiments

During the beginning of October, I mostly worked on my LineWars VR game, trying to get it to pass the technical review. A few days ago, I managed to get it to pass, so since then I again switched to working on ABoM. I wanted to experiment with some volumetric rendering, as I will need to have all sorts of smoke puffs, clouds, water splashes and such in this game. Doing ray marching is too expensive (performance-wise) on mobile VR (and I hope to be able to release my game also for mobile VR devices, especially for the Oculus Quest), so I was looking for alternatives. I have been studying various scientific articles about fast real-time cloud rendering, and found out that as early as in 1985 there were some experiments using textured ellipsoids as a basis for convincing cloud shapes. I decided to experiment with some volumetric ellipsoids, first for anti-aircraft shell blasts, as color-wise they are the simplest "clouds" to do (them being black).

As for the GameObjects, in LineWars VR I had good results with using a world-aligned mesh for all my lasers and bullets, and then updating the vertices of this object using an ASM plugin. I decided to keep using this architecture, so that all my ack blasts would be contained in a single mesh. Each blast would be a cube having 8 vertices (as I don't need vertex normals at all, so I don't need to have duplicated vertices in the corners). I could actually get by with just 6 vertices (as only up to three faces of the cube will be visible at one time), but decided to go with 8 for simplicity. Thus, with just 800 vertices in the mesh, I could handle 100 simultaneous anti-aircraft shell blasts. The actual code to start a new shell blast is below:

    private int freePos = 0;

    void Update ()
    {
        if (Random.value > 0.94f)
        {
            Vector3 pos;
            do
            {
                pos = new Vector3(Random.Range(-3f, 3f), Random.Range(-3f, 3f), (0.7f * Time.time) + Random.Range(1f, 20f));
            } while (Mathf.Abs(pos.x) < 1f && Mathf.Abs(pos.y) < 1f); // Don't let the blasts go into the camera
            for (int i = 0; i < 8; i++)
            {
                int vi = i + 8 * freePos;
                ackData[vi] = new Vector4(verts[vi].x + pos.x, verts[vi].y + pos.y, verts[vi].z + pos.z, Time.time);
            }
            mesh.SetUVs(0, ackData);
            if (++freePos == ACK_COUNT)
                freePos = 0;
        }
    }
As you can see from the above, the only thing the C# code needs to do to start a new shell blast is to set the position and the starting time for the new blast vertices (using the UV coordinates, to be able to use Vector4 values). Everything else is done by the vertex and fragment shaders.

The vertex shader reads the new vertex position (from the UV xyz coordinates instead of the vertex coordinates), and then uses a special data texture to animate the shell blast. The data texture has 512 columns (for 512 frames at 60 fps, which comes to around 8.5 seconds lifetime for a single blast) and 4 rows for each blast. The animation data texture rows are set up as follows:

  1. The first row contains the "core" ellipse shape (xyz scales) and origin Y coordinate within the box.
  2. The second row contains the "donut" ellipse shape (xyz scales) and origin Y coordinate within the box.
  3. The third row contains the "core" ellipse texture position (X), alpha value (Y) and color mix (Z, 1 = yellow, 0 = black).
  4. The fourth row contains the "donut" ellipse texture position (X) and alpha value (Y).
The vertices also have a vertex color value, which gives information about which blast shape to use (index into the data texture group of 4 rows), and also a dot product value for which of the smoke shape texture planes to use in the fragment shader. This allows me to have a lot of different smoke puff shapes, using different shapes in the animation data, and also mixing three different smoke shapes in various ways.

The fragment shader then performs ray-sphere intersections for these two ellipses (between the viewing ray and the non-uniformly scaled sphere). Based on the hit position coordinates, the data texture position (input in an interpolator from the vertex shader), and the texture plane mixture value, an alpha value is read from the smoke texture. This is then multiplied by the animated alpha value (again got from an interpolator) for the final fragment alpha value. The fragment color is based on the yellow..black value from the data texture, which is also in one interpolator channel.

It took me quite a bit of work and experiments to get rid of spilling in the fragment shader. Calculating the ray-sphere intersections for two ellipsoids uses so many temporary registers, that most of my attempts ended up spilling the register contents to memory and then loading them back later. This will pretty much kill the performance, so my first goal with any shaders is to get rid of register spilling. I finally managed to make a version of the fragment shader that did not use spilling. I got to 12.5 GPU cycles per fragment, which is a little bit on the high side for mobile fragment shader (my heaviest shader in LineWars VR took 12 arithmetic GPU cycles per fragment), but should still be usable.

  7 work registers used, 0 uniform registers used, spilling not used.

                          A       L/S     T       Bound
  Instructions Emitted:   24      6       4       A
  Shortest Path Cycles:   12.5    6       4       A
  Longest Path Cycles:    12.5    6       4       A

Here is a short YouTube video I uploaded about my experiments. These have only two different types of blasts (and even those are not very good texture-wise), but you can sort of see the general idea. The smoke blasts are fully volumetric, so as you move around them, they rotate convincingly, and they can be viewed from any direction without them rotating strangely or looking flat.

Oct 1st, 2019 - Visited the Local Aviation Museum for Brewster References

Today I went to my local aviation museum Finnish Air Force Museum to take some pictures and measurements of the Brewster cockpit. I wanted to have a reference point for the size of the cockpit when I get around to modeling it. According to the 3-way plans I had, the cockpit was around 80 cm wide. When I took the actual measurement, I found out that the inner width of the cockpit (around the canopy rim) was 79 cm, so the plans are pretty accurate! It is difficult to get down the 1 cm level using just the plan drawings, as the pen width is actually around that 1 cm when you zoom the drawings up to that scale. Here below is a collection of the measurement photos I took while visiting the museum.

Sep 29th, 2019 - Found a Good Reference for the Wright R-1820 Cyclone Engine

Since my last blog post I stumbled upon a very good 3D reference for the Wright R-1820 "Cyclone" engine as used by the Brewster Buffalo and also the Douglas SBD Dauntless. A 3D modeler called Witold Jaworski has been Recreating the Wright R-1820-52 in Blender. His model is super high-poly, so not directly usable for me, but it works as a very detailed reference for the engine. In the following image I am using his engine as a placeholder in my Brewster.

Sep 19th, 2019 - Bought Proper 3D Plans for a Brewster Buffalo

After spending a few days on my Brewster Buffalo 3D model, it began to look like the 3-way plans I had for the plane were not quite correct. I surfed the net for some better planes, and it looked like the 3-way drawings by Paul R. Matt were considered the most accurate available. I found these plans for sale by www.plans.aero site, and decided to purchase them. After a few days of work, I already had the fuselage somewhat modeled. The cockpit canopy uses the actual plans (with a blueish tint) as the texture, so you can see the plans even include rivet positions!

Sep 12th, 2019 - Work Started on My Next Game "Air Battle of Midway"!

I am still mostly working on my LineWars VR game, but as the work remaining in that game occasionally gets somewhat boring, I decided to take a little bit of time away from that, and start some preliminary work on my new game. My two main game interests are space games and flight simulators, so now that my space game is about done, I think I want to make a flight simulator next. It is of course quite a bit more ambitious project, as I want to include proper flight modeling. Also, there needs to be a proper environment to fly in, which will be much more difficult to create than just a simple space background. I would need to have a proper terrain, preferably some clouds to fly into, and such. Lots of new stuff to learn, which is quite exciting!

I spent some time figuring out what kind of a flight simulator I would want to do. I knew it would be a combat flight simulator, and I also like World War II era planes much more than modern jet fighters, so those two things were a given. After some thought I ended up using the Battle of Midway as the scene of my game. There are several reasons why I chose the Battle of Midway:

I started my work on "Air Battle of Midway" by modeling the Brewster Buffalo. I doubt I want to (or have time to) model all the planes and ships for my game myself, but I want to model at least a few of them myself, as I quite enjoy the modeling work.