Appendix: On Unity
The following sections describe some of my frustrations, obstacles and general observations I experienced while working with Unity. Instead of adding this information to a separate blog post, I am including it here as an appendix.
You can end your read here if this does not interest you. The main content was about the game and that was concluded in the previous sections.
Lighten it up a bit
In Unity, shadows and lighting effects are either calculated in real-time or pre-calculated in a process known as “baking”. The advantage of baking a shadow is that it requires less resources to render when running the game, but the disadvantage is that baked shadows only work for static objects, i.e. objects that do not move.
Ohhh, the fun I had with shadows…
First, there was the weird light leakage. The light seemed to “pass through” the photo exhibit where the “canvas” meets the wall.1 This problem disappeared when using baked lighting, but that gave rise to two other problems: Dark colors and fuzzy shadows. The three issues are illustrated in the image below.
The right photo exhibit in the screenshot above has soft/fuzzy shadows. This actually shows the final result, because I used baked shadows for most models. Before getting there, the shadow was almost invisible on the ground and had to be tweaked by increasing the size of the terrain in the shadow map (a special texture that holds information about all baked shadows in the scene). The documentation for this was not great.
The worst problem was the darkness. On most objects, the side facing away from the sun became almost completely black when rendered with baked lighting, especially for darker colors. This effect is already somewhat visible in the screenshot above, but it gets worse with certain colors.
I used a green color for the walls with the exhibit text and this green was dramatically different when viewed on the sunny and shady side. The final solution was to add an extra light to the scene as a kind-of artificial sun shining in the opposite direction of the real sun. This felt like a hack, but it provided a bit of extra lighting, as can be seen on the right screenshot below.
Besides the extra light source, I also tried increasing ambient lighting, but this resulted in objects being overexposed, if they were in the sun. I do not know how many hours I spent trying to tweak the lighting settings, and in the end, I could never get the result I really wanted.
My biggest gripe with the way Unity handled the baked shadows was that objects seemed to almost lose their color when being in the shade. This is not really how shadows work in real life. I started paying more attention to shadows when going on walks, taking note of how different materials (walls, tree bark, pavement etc.) change appearance when they are in the shade — and they do not seem to lose their color :-)
But of course, a game is just a simulation.
I might be missing something obvious, and I might be wrong about my observations on shading. It is also possible that with the right amount of tweaking, the result could be better, but I will save that for another time.
Code is everywhere
Before starting out with Unity, I got the impression that it would not take long before I had to start writing some code. However, I was a bit surprised how quickly this turned out to be true.
For example, I needed a simple mechanism for showing/hiding a game object when the player is within a certain distance of the object, and there did not seem to be a way to do this without writing a bit of code.
Considering that Unity is supposed to be easy to learn but difficult to master, it seemed a bit weird that I had to write code (although it was almost just a one-liner) to do something as simple as showing/hiding an object based on proximity. I would have assumed this could be handled with a drag-and-drop state machine.2
Unity has two main render pipelines: The “built-in render pipeline” and the “universal render pipeline” (URP). URP seems to have been pushed by Unity for several years by now (under a different name), promising performance improvements and uniquely available features such as the Visual Effects (VFX) Graph. So I naturally thought it would make sense to use URP.
This was probably a bad idea.
I previously mentioned the tree creator. This was one of the built-in tools that initially impressed me a lot, and I had fun creating random trees (using the built-in renderer) when initially testing out Unity.
Unfortunately, the tree creator does not work well with URP. Digging into this a bit, I found that the tree creator is probably, maybe deprecated, but the manual page for the tree creator mentions nothing about deprecation. Either way, it works fine in the built-in renderer but not in URP, so this was a bit of a bummer.3 It is a real disappointment when a feature mentioned in the manual is not actually working.
The same story repeated itself with the TextMesh Pro package which is a verified package for creating rich text in Unity. Support for URP is apparently in the works, so I had to make do with simple text rendering without any fancy shading. This was ok for my use case, but it was a disappointing experience anyway.
Besides the lacking compatibility and documentation, the package manager has a lot of “preview” packages, i.e. packages that are not “production ready”, i.e. there is a risk they are unstable and unsupported.
The aforementioned VFX graph was actually a preview package until recently, even though it is mentioned as a major feature of URP for at least a year. A sub-feature called VFX Shader Graph is still in preview, and another interesting “Terrain Tools” package is also still in preview. This is a common thread.
It is unclear when packages become verified packages, so one has a choice between taking the risk of using a preview package (and getting the latest features) or use only verified packages (and sticking with slightly older features).
It is clear that Unity is a powerful and full-featured platform for creating games, and it even has a lot of extra tools to help with e.g. distribution and monetization of the games. Many popular games have been made with Unity, so it is clearly possible to be successful with their platform.
But there is something about Unity that leaves me with a slightly bad taste in my mouth. It is the same feeling I get when I look at spaghetti code (usually my own). Something is off, something is smelly, it is not beautiful. But it gets the job done.
I do not want to hate on Unity, but I am not in love with their product either. And I do not think I should have this feeling already. After all, my “game” is pretty simple. Just a basic environment with some grass and trees as well as basic shapes and downloaded 3D models thrown into the mix.
Yet I found myself hitting my head (lightly) against a wall quite often. I managed to fix or work around these obstacles in most cases, but I wonder how my experience would have been if my game had been larger in scope.
Throughout the project, I also used Blender a bit, and using them side by side, I think they are good examples of the difference between good software and great software.
Blender is beautiful, unlike Unity, and although it has a very steep learning curve, Blender feels more solid, complete and well-designed.
A final word
My rant above is slightly melodramatic. It is highly likely that I will continue using Unity, because it has a lot going for it. It is easy to use, user-friendly for the most part, and I also quite enjoy writing code in C#.
However, I am determined to at least give Unreal and/or Godot a more serious try for my next project, whenever that will happen and whatever it might be.
Thank you for reading!
- Rendering both the front and back of the exhibit’s wall material fixed the light leakage for real-time shadows, but I still cannot understand why the leakage occurred in the first place.
- It is my understanding that this is something Unreal’s Blueprints could handle, but I have not tried it out.
- I managed to get around the issue by just using the generated tree mesh and then manually adding materials.