I recently spent a few weeks porting a large and very well-tested game from Unity 3.5.7 to Unity 4.2.2. Since I know other Unity developers are still making the leap from 3.5.7 to 4.2.2, I wanted to document my experiences bringing a complex 3D Action RPG called The Shadow Sun into Unity 4.2.2.
The Shadow Sun
Upgrade Rationale
To be clear, Unity 4.2.2 does not offer any new features that I desperately need for this game. Instead, the reason for this upgrade is that Unity no longer supports version 3.5.7 so is not providing basic fixes for new targets such as iOS7. So Unity 3.5.7 iOS developers are faced with the difficult choice of either upgrading to Unity 4.2.2 and risking the instability of a new engine or hacking up their Xcode projects, installing plugins, and releasing without any real support from Unity. Very few professional developers would risk releasing a product without support from their engine provider. With this in mind, let’s see how well Unity 4.2.2 behaves.
Performance Observations
Unity 4.2.2 advertises memory reductions and performance improvements in a number of areas. For my game, I did see a small frame rate improvement of 1 or 2 frames per second in the more graphically dense scenes. Run-time memory consumption is also reduced by a small amount in all scenes. Since I’m building mobile games, every little bit helps!
Invisible Mesh
After the upgrade, I discovered that the mesh contained within many of my scenes rendered incorrectly in Unity 4. For example, large parts of the scene mesh were invisible, so the game characters were standing in a sea of black dotted with a few flickering torches. After many hours of investigation, I learned that static batching of materials that use reflective shaders usually fails in Unity 4.2.2. Since this was not an issue with Unity 3.5.7, I submitted a bug report to Unity. Your choice of workarounds: disable static batching on any object that uses a reflective shader, or avoid using reflective shaders. Note that I was able to reproduce the problem using my custom and highly-optimized reflective shaders as well as Unity’s slower stock reflective shaders. Note that this bug scrambles most of the scene and not just the reflective objects!
Missing Textures
After the upgrade, one of my scenes sometimes renders without any textures. Again, this was not an issue with Unity 3.5.7. This is a fairly simple scene where the textures are not dynamically loaded, so I suspect a failure in the Unity 4 rendering engine. Since the problem is not easily reproducible, I have not yet discovered a viable workaround.
Mesh Crashes
Unity 4 adds a “Read/Write Enabled” option in the Mesh Import settings. According to the manual, setting this flag off allows Unity to unload the mesh data from memory. Since my scene meshes are very large, I hoped that this might reduce my run-time memory usage on iOS. Unfortunately, setting this flag off always resulted in a crash deep in the bowels of Unity. Looking at the stack trace, it seems that the crash happens after one of my scripts performed a ray cast. I gather that once a mesh is unloaded from memory, it is no longer possible to perform ray casts against that mesh. This is odd because Unity must keep the collider mesh in memory. The work around is simple: just keep all of your scene meshes as “Read/Write Enabled.”
GPU Performance Warnings
After upgrading to Unity 4, I saw a new warning message in the Editor’s console:
Tiled GPU perf. warning: RenderTexture color surface (120x80) was not cleared/discarded, doing
I fixed this warning by adding a DiscardContents() call on my RenderTexture before invoking Graphics.Blit().
Active State Warnings
After building the game, I saw a few odd warning messages in the Editor’s console:
GameObject is active but a parent is inactive. Active state is now inherited. Change the parenting to get back the old behaviour!
Clicking on these messages won’t help you identify the source of the problem. Instead, open every scene in your game and click on the new message that appears. This will highlight the problematic object. Now fiddle with the active flags on all the children until the problem is fixed.
Active State Problems
The Unity Upgrade Guide provides a good explanation of how Active State has changed between Unity 3.5 and Unity 4.0. Following that guide, I converted all of my SetActiveRecursively() calls to SetActive() calls. During testing, I discovered dozens of spots in my game where SetActive(true) failed to activate the child objects within a hierarchy. The fix for this was to toggle the Active flag on in all children within those problematic hierarchies. I suspect that this problem was created when Unity converted the 3.5 game to 4.0 and attempted to maintain compatibility with the older Unity 3.5 model of active state.
Font Changes
After upgrading, some of my GUIs rendered slightly differently. After a quick investigation, I noticed that Unity 4.2.2 made some of the characters in my bitmap fonts a few pixels wider when compared to the Unity 3.5.7 generated bitmaps. If your GUI layouts are tight, you might look at Unity 4’s font import settings.
Trigger Events
From a scheduling perspective, Unity 4 sends the OnTriggerEnter and OnTriggerExit events a bit later than Unity 3. This particular problem involved triggered audio, so it might be that the audio in Unity 4 starts sooner than in Unity 3. Either way, I had to rewrite some code to get it working properly again.
Animation Blending
After upgrading, I noticed that a few of my legacy animations blend slightly more slowly towards the end of the blend. I think this change makes the blends look less smooth, but it’s a question of aesthetics, I suppose.