So I had this grand plan to use 3D objects in my game’s UI. I wanted to escape all the woes of having to create icons, and recreate them every time I fiddled with a design.
Like most of my dreams of course, it was never going to work.
It didn’t really pan out because of a few annoying practicalities.
- The actual UI and the 3D objects didn’t truly coexist; the UI and its parts had to be placed in the actual level.
- I couldn’t work out how to cut geometry that exceeded the icon area.
- The 3D objects fir the UI refused to be lit by the right lights, they kept getting illuminated by the level lights or nothing at all.
So I had to admit defeat and start again from scratch.
So, resigning myself to using flat, 2D icons that would at least properly inhabit the UI (and unlock all the flexibility that a self-contained UI brings), I had to attack all of my problems from a new angle.
Harking back to my work in Warcraft III, icon generation was one of the most annoying parts of modding. First, you have to pose the object in the editor, then you have to make sure the lighting is right, then you have to time your screenshot so it’s not playing one of its rare idle animation at the wrong moment.
It would be bad enough if that was the whole process; there’s far too much inconsistency already baked into that. But no, that leaves you with a desktop-sized image, which must then be cropped and resized… and then you have to apply standard icon borders — AT LEAST TWICE (normal icon, disabled icon; then possibly passive and disabled passive too). Finally, import each of the variations to the correct (different) paths. Sigh.
The solution is, as with most annoying processes in life, automation. What if I could get Unity to take screenshots in a perfectly controlled environment, then crop them and put them in the right folders by itself? If I changed a model, all I’d need to do would be to run the generator again.
Unity couldn’t make life easy on me, of course. Taking screenshots is easy enough (Application.TakeScreenshot will do the trick), but taking screenshots with transparent backgrounds is quite a lot harder. After trawling various old forum threads for answers, none of them quite worked — I had to cobble this monstrosity together from a slew of similar-but-not-quite implementation examples before I got my working answer…
// Ensure any background guff that was previously rendered is cleared. Camera.clearFlags = CameraClearFlags.Color; Camera.backgroundColor = Color.clear; RenderTexture icon = new RenderTexture(Width, Height, 32); RenderTexture currentRT = RenderTexture.active; RenderTexture.active = icon; GameObject target = RDZ.Factories.ItemFactory.SpawnItem(PrefabsToScreenshot[ScreenshotItemIndex], Side.Right, transform); Camera.targetTexture = icon; Camera.Render(); Camera.targetTexture = null; Texture2D screenShot = new Texture2D(Width, Height, TextureFormat.ARGB32, false); screenShot.ReadPixels(new Rect(0, 0, Width, Height), 0, 0); screenShot.Apply(); RenderTexture.active = currentRT; Destroy(icon); byte bytes = screenShot.EncodeToPNG(); String fileName = ResourcesDirectory + target.GetComponent<EquipmentItem>().IconPath + ".png"; File.WriteAllBytes(fileName, bytes); Destroy(target);
I’ll be honest with you; I haven’t the faintest idea how it works, why it works, or even what it’s doing. It’s something along the lines of hijacking the game camera, forcing it to draw what’s in front of it onto something else instead of the screen, and then… copying that into a texture?
Ach, I don’t really care — the important thing is that it does work. I press Play on my IconScreenshotter scene and it spits out all my icons, straight into the correct paths for each item in the list. Job done!
Then all I had to do was unwind all the awful gubbins I was doing to create and destroy the icon objects, and replace it with a single image object that is updated as necessary. Success!