If you've seen any recent screenshots of When Pigs Fly (it'd be hard not to if you've visited this site), you may have noticed the colors in the game changing. I've been using Unity's color correction image effect to bump up the saturation and slightly modify the green channel. I think it looks good enough that I was willing to take the 5-10 fps hit that the image effect caused. This morning I realized that I wasn't really using much of the power of color correction, so I set out to get the same effect in a simpler and hopefully less expensive way.
I'm going to be traveling on Sunday, so I'm going to count this post as my Sunday Experiment of the week. As When Pigs Fly has grown, the visual quality has not grown along with it. I like the low-poly style, but there are a bunch of areas where the graphics could be improved (mostly lighting related). This morning I tried several different things to quickly improve the look of the game.
Depth Perception Issues
One thing that has plagued flight sims forever is a sense of depth. It can be very difficult to gauge your altitude as you approach for landing. The easiest way to accurately judge the approach is to watch the shadow of your aircraft. The problem is that, depending on the light direction and camera position, the shadow isn't always visible. The problem is exacerbated in When Pigs Fly by the low poly terrain, with no detail or texture on the ground there.
I thought shading the edges of the polygons in the terrain might help. With a visible wireframe of the ground, the player could gauge altitude by the shape of the triangles. I wasn't sure how it would look though, so I didn't want to spend a ton of time writing an edge detection or wireframe shader. But since the terrain is procedurally generated and vertex colored, I was able to cheat and get the same effect with just six lines of code. I changed the terrain generation code to make the uvs of each triangle of the mesh to be (0,0), (1,0), and (0,1). I then modified the shader to mix a texture with the uv colors. With a simple black outline of a triangle for a texture, here was the result.
This turned out great for how little effort it required, and the edge lines do help with a sense of depth on landing, but I just don't like the way it looks. I'll still have to come up with another solution to the depth problem.
I've been fighting with the lighting in When Pigs Fly from the beginning. I never found a way to have everything lit like I wanted while maintaining the warmth of the colors. Now that Unity 5 has made all engine features free, I can use the color correction post effect. There's still some tweaking to do with the color curves, but its already way better.
Shading and Shadows
Unity's shadow system doesn't work particularly well on the planes in When Pigs Fly. With several objects so close together and sometimes overlapping, the shadows generally look horrible. So this morning I disabled shadows on the planes themselves (they still cast shadows on other objects). In my opinion, no shadows looks way better than bad shadows.
I also experimented with toon shading. The first experiments were great, and I was about ready to move on to the next task, but I had been looking at stationary objects. When I took a plane up and saw the toon shading in motion, there was an immediate problem. The low-poly look results in some pretty big faces in the model, and when they're moving a lot the lighting tends to "snap" from one light level to another. Here's what I mean.
After playing with the lighting ramp for quite a while, I think I've mostly solved this problem. The gradients from one "step" to the next have to be gradual, and its a pretty fine balance between light "snapping" and not really being toon shaded.
The last thing I did was add the crease shading post effect. It helps objects stand out, which is important because many objects in When Pigs Fly share the same colors. It also just looks cool.
I think I made some great improvements in just a couple hours time. The color correction has made the most drastic change. There is still a lot to improve though. The pig model needs to be redone pretty badly. It also really bothers me to see distant trees without shadows. I have some ideas on how to fix that last one, but I'll leave those to another post.
I'm a bit sick this morning, so this week's Sunday Experiment is a quicky. One of the things I want to improve in When Pigs Fly is the feeling of a live world around you. The first step in that direction is adding towns and roads. Also, as I start distributing more things to do around the map, its important to have some sort of system to guide players to those activities. I think roads are a nice, subtle method of directing players to new areas. For today's Sunday Experiment, I started laying the foundation for a system that generates roads procedurally, while still allowing me to control where certain roads end up.
People have been asking me if When Pigs Fly will ever come to mobile ever since the initial game jam release. I have always quickly dismissed the question, assuming that the performance would be too poor to be worthwhile. For my Sunday experiment this week, I decided I should confirm my doubts. The results were pretty surprising. In fact, on one device, the game ran better than it does on the laptop I use to develop it.
In the original version of When Pigs Fly, actually building a working airplane was pretty difficult. As a result, the map could be pretty small without worrying about running out of room to fly. As I improved the flight model, added better parts, and people generally got better at the game, the map quickly became too small. People were building planes fast enough to cross the map in under a minute. Eventually I replaced the map with a much larger one. This alleviated the problem a bit (it now takes 10 minutes or so to fly across the map in an average speed plane), but it didn't completely solve it.
Ever since that first map, I've been trying to decide what my solution is going to be. I've thought about making the world wrap around, so when you fly off one end of the map, you warp to the other side. I've thought about replacing the 'flat' map with a globe, so that you can actually fly around the world. Today, though, I wanted to experiment with endless terrains.
How it works
The terrain in When Pigs Fly has always been generated at runtime (using my WIP low poly terrain generator). But since I always use the same seed, the terrain is always the same and is static once generated. My terrain generator works by building a flat grid of triangles, then setting the height and color of each vertex based on a height map (procedurally generated or otherwise).
This morning, I replaced the height map with a very simple perlin noise implementation. I also added some code to the terrain system that monitors the position of the player. When the player moves past a certain distance, the terrain is recalculated with a new offset to remain under the player. Here is an exaggerated example.
Why this isn't a good solution
Terrains in when pigs fly are low-poly and vertex colored. The nature of this system means that when the terrain is recalculated, if the x and z values of a vertex aren't exactly the same, its height and color will change. I did a few things to fix this problem, but it still isn't perfect. I could do more to make sure the terrain respawns on an exact grid, but that still wouldn't fix the next problem.
The entire terrain mesh is regenerated every time, meaning that I am wasting resources rebuilding parts of a mesh that already exist. In my small scale tests this wasn't a huge problem, but I imagine it would become an issue in game.
What I'll probably end up doing
I think it would be better to generate new "chunks" of terrain as the player nears the edge of the map, and delete them as they get far away. This way there would be no time wasted generating things that already exist. It would also solve the issue with exactly matching vertices. It should be pretty easy to implement this system, as the current terrain is already split into chunks to stay under Unity's maximum mesh size. I think draw distance is really important in flying games, so I also want to experiment with an LOD system so that the terrain truly stretches to the horizon.
For this week's Sunday Experiment, I'm revisiting something I briefly attempted during the original jam dev session of When Pigs Fly. The first iteration of the map in When Pigs Fly had a lake, but I ended up removing it for a couple reasons. First, I simply didn't have time to add a buoyancy system. Second, the animated water I made was pretty resource hungry, and I didn't have time to optimize it.
Since the jam is over and I'm no longer restricted to always writing new code, I'm now able to take advantage of some of my previous work. This morning I grabbed the water system from my WIP low poly terrain generator and the buoyancy systems from Hoist and threw them in to WPF. An hour or so later I had a working sea-plane using blue barrels as floats.
The water object deforms its mesh based on Perlin noise. It has a public function called GetDepthAtPosition that takes a Vector3 position and returns a float depth. It works very simply by comparing the y value of position with the perlin value at the (x,z) values of position. We'll use this function later to calculate the buoyancy forces on the barrels.
Each barrel has a few child "Depth Checker" gameObjects. The positions of the children are fed into the Water.GetDepthAtPosition function to determine their depth. That value is then used to calculate the buoyancy force using archimedes principle. Doing it this way causes the barrels to react correctly to waves.
I then quickly threw together a particle system that emits when the average of a barrel's depth-checker children is greater than 0. It also sets the velocity and size of the particles based on the velocity of the rigidbody.
For the second week in a row, my Sunday Experiment has resulted in something that I really want to add to the game. This water system is too simplistic though, so it won't show up in v0.3 as is. In fact, I'll probably have to wait until I flesh out a couple other systems in the game before I can add this one. While it works in this example, I know that players would find a way to break it. Off the top of my head, I can think of people trying designs with rudders on the back of their floats. In the current system, they would act like they were normal rudders, moving through air rather than water. For this to work, I'll have to find some way to integrate the depth-checkers with the aerodynamics system.
Update: You've seen the Spruce Goose. Now meet the Plywood (and plastic) Pig!
I have a habit of spending my Sunday mornings messing around with experimental new features in my projects. For me, its a good way to clear my head. It kind of allows me to get away from the project while still actually working on it. Today, I played around with a feature I've been dreaming about since before I even started work on When Pigs Fly: banner towing. I have long wanted to have banners hidden around the map that you could swoop down and pick up. I even started implementing a system that would allow players to write custom messages on the banners, but today I figured I should actually get a banner towable before I waste too much time on that.