29 October 2011
PVRTexTool version 3.23 vs. Unity version 3.4.2. . . click to view comparison QuickTime
This post is of a technical nature. If you’re not a game developer, please do be patient. Sin or Win is coming, soon!
There are three options for textures when developing for iOS in Unity: True colour, 16-bit* and PVRTC compressed images. True colour & 16-bit images are great for image fidelity, but swallow lots of memory. On a limited platform like iOS one can’t have many of them without running into memory issues. So most developers crush their images into PVRTC which tends to have a fraction of the memory requirements. I have avoided using PVRTC because the results were horribly poor. However, this week I’ve been optimising Sin or Win and investigating my texture options led to this PVRTexTool discovery.
Typically, Unity’s built-in PVRTC compression results in unacceptably blurred and smudgy results. Then I stumbled across a reference in Unity’s Optimising iOS Graphics Performance documentation on PVRTexTool from Imagination Tech - creators of the PVRT format. Use another tool, Unity suggests, if your PVRTC is poor quality. Doing so result in the image above. Click on the image for a QuickTime comparison.
Bizarrely, the newly released Unity 3.4.2 comes with an old version of PVRTexTool** (version 3.11). I’ve filed a bug report with Unity, requesting for better compression to come with Unity 3.5 (or Unity 3.4.3!).
In the meantime, here’s how you take advantage of better compression today.
Install PVRTexTool from Imagination Tech:
- Download PVRTexTool from Imagination Tech. You’ll have to create a username and password to do so. Once that’s done, Mac users download the PVRTexTool file with the yellow folder icon
- Unarchive the file and you’ll get a PVRTexTool folder in your Downloads. Drag this to your Applications folder
- Documentation is in the “Documentation” folder
- Most interesting is the command line application PVRTexTool. It’s found at /Applications/PVRTexTool/PVRTexToolCL/MacOS_x86/PVRTexTool. There is a GUI version of the tool, but it has an annoying Windows interface and is more time consuming to use. The command line tool can be wrapped into your pipeline tools for seamless integration
- From the Terminal change to the folder where your image is. PVRTexTool takes images in BMP, TGA, JPG, PNG, GIF, DDS. I use PNG
- Run /Applications/PVRTexTool/PVRTexToolCL/MacOS_x86/PVRTexTool -fPVRTC4 -pvrtcbest -yflip 1 -square -iPICTURE.PNG replacing the green PICTURE.PNG with the name of your image. PVRTexTool will then take it’s time, but it’ll create PICTURE.PVR, a high quality PVRTC compressed image you can drag to Unity. Also, ensure that you use “-pvrtcbest” otherwise you’ll just create PVRTC images as poorly as Unity already does
*Coming from film I was spoilt into thinking of 16-bits as 16-bits per colour channel. Really that’s known as 48-bit colour. 16-bit colour in Unity is a paltry 32,768 colours
**I couldn’t actually get PVRTexTool 3.11 to work, so definitely download the newest version from Imagination Tech
06 May 2011
I’ve been puzzling on how best to organise some code I need to write - the code that handles clouds. I’ve banged my head against the problem without coming up with a satisfactory solution, so I decided the best course of action was to take a break. Get away from the blank text editor that was taunting me.
I shuffled through my photographs of my last visit to the Caribbean, then painted some clouds based on the weather I had enjoyed. All very enjoyable procrastination - and then suddenly it stopped being procrastination as an epiphany struck my brain. So, a big “thank you” goes out to my subconscious for solving my coding problem while I enjoyed myself elsewhere.
26 February 2011
I’ve found it’s often the unexpected that takes time. Cuban customs agents, downloading in Canada, and bureaucracy in Norway. And so it has been with optimising my game for the iPad. Unity provides two useful pages to get one started on optimising; one for optimising scripts and one for optimising graphics. There are still further, and often simple, code changes that help squeeze more frames per second out of the iPad.
Use #pragma strict at the top of all your scripts. It’ll initially make component access more awkward but as you’ll cache those lookups it’s a one time hassle. So with #pragma strict: GetComponent(Rigidbody) would become GetComponent(Rigidbody) as Rigidbody.
Avoid Object.Instantiate() & Object.Destroy()
Instantiating is bad. Destroying is bad. Both require memory allocation changes and cause a hiccup in performance when an object is created or destroyed. So instead of creating and destroying objects when needed, I predetermine what is required and my SpawnManager class instantiates all required objects at the beginning of the game - causing one large hiccup when it can be hidden. Then it disables the spawn, but they’re kept waiting in memory. When they’re needed the game object is enabled and ready to go.
Cache Component Lookups
This is an optimisation recommended by Unity on their optimising scripts page, and I whole heartedly agree. I’ve found casual component lookups performed often enough cause a slow down.
Use iTween Sparingly
I hadn’t used iTween until midway through production, then after some positive encouragement I gave it a try. And it was awesome. Very easy to use and easy to chain together to create complex behaviours. I loved it, and I quickly incorporated it into my movement scripts. Then the performance hiccups followed.
A call to iTween typically happens midway through a game. An iTween component is instantiated, makes some expensive component lookups and then is destroyed. Each of these steps causes a performance hiccup, the worst being a substantial garbage collection on destruction. Instead of using iTween in my performance critical areas I now use my own easing and interpolation classes that slip into existing Update functions and can be called with cached nodes.
My SpawnManager class used to execute gameObject.SetActiveRecursively(true) on any node that was being spawned. The first disadvantage to this was sometimes I didn’t want all children to appear right away, so I’d hide them again. More performance offensive was that SetActiveRecursively performs several expensive component lookups.
To solve this I now cache the hierarchy in Awake for any game object that will be spawned by SpawnManager. SpawnManager then simply enables the top most node and the top node is responsible for enabling whichever children it needs. And because the children are cached in that initial Awake call, there is little to no performance hit during the game.
Use Builtin Arrays
Avoid String Comparison
Initially I had plenty of conditionals using tags to query objects. I’ve collided with you, are you tagged with “The Fancy Cliff Over Yonder”? Great, lets form a club. Lets also slow down the game, because the longer the tags, the longer it takes to compare against. This may seem trivial, and for a few tag comparisons here and there not really a problem. But in an Update function with several objects this suddenly becomes several hundred queries a second. So if(collision.gameObject.tag=="Cliffs") became if(collision.gameObject.layer==9) which isn’t as easy to read, but a few explanatory comments nearby and the problem is solved.
Avoid Vector3.magnitude & Vector3.Distance()
Every moment of my game I’m comparing the position of the finger to the position of the interactive characters. Several characters on screen at once and this starts to amount to an awful lot of Vector3.magnitude checks (Vector3.Distance uses .magnitude and is essentially the same). This becomes an awful lot of slow square roots calculations. So, wherever possible compare distances using Vector3.sqrMagnitude.
10 February 2011
Unity 3.2 is out! The most exciting new feature for me is the ability to profile standalone player builds directly in the Editor. Including iOS builds. Previously I optimised my code based on how my game ran in the Editor. But things on iOS often run differently than they do in OSX. Now I can play my game directly on my iPad while keeping an eye on the Unity Profiler.
But keeping one eye on the game and one eye on my monitor has proved awkward. By the time I can move my hand to the keyboard to pause XCode whatever caused the frame rate spikes has passed. Sure, I could scrub back in Unity to see the code, but my spikes are of a rendering nature - all lumped under a single time consuming line in the profiler. I need to go back in time to see on the iPad what visually changed to discover the cause of the spike. I need a time machine. And that time machine is my Nikon. It’s now set it up to film while I play, then I scrub through the resulting Quicktime to easily determine how to best optimise the game. The above is a screen shot from one of those quicktimes.
I still have lots of optimisation left, but with the help of the new profiler in 3.2 it’s a much more enjoyable job.