Hint Sharing : clean 2D sprites using GUITexture

Hello there :roll:

I’ve shared this idea in another topic, which was visibly appreciated, so I’m telling myself I could clearly make a topic about it for everyone to profit.

I didn’t find any topic about it anywhere, so please accept my apologies if somebody already shared it elsewhere.

This is not a full script package, which you can copy paste mindlessly in your game. This is just a working concept, and you will have to adapt it to your code.

So, let’s start :

The goal : to make 2D sprites with no pixel loss at all, no blur degradation, no Shader consuming the CPU, as fast as possible with no number limitation. And all that with the fewest possible drawcalls for iPhone usage.

The main tool : GUITexture + Texture2D.

How to :

Unity-side, make a GameObject with a GUITexture taking your screen as dimensions (480x320 for iPhone, as an example).

Resources-side, make one or more animation atlas image files (or Inspector objects, as you wish, but here I’ll use Resources). For example, you could put 10 frames of a walking man in a PNG. Each frame would be in a fixed bounding area (let’s say 64x64 rects), all aligned in an grid style.

And now it’s simple : in your Unity script, just declare as many pixel map Arrays as there are frames.
For ex :

private var _walkingMan_1 : Color[];
private var _walkingMan_2 : Color[];
private var _walkingMan_3 : Color[];

etc …

Then declare as many Texture2D variables as there are Atlases, like :

private var _walkingMan_Atlas : Texture2D;
private var _runningMan_Atlas : Texture2D;

etc…

Finally, declare your GUITexture GameObject :

private var _mainScreen : GameObject;

and its pixelmap, as guiTexture can’t directly afford a SetPixels transaction.

private var _screenPixelMap : Color[];

And then its Texture2D receiver :

private var _screenTexture : Texture2D;

Now make an Awake() function.
You will use it to build your sprites by transfering regions of your atlases to your pixel maps (which is the other name of a bitmap, which is the other name of a sprite, heh.).
We will use this awesome Texture2D functions which are GetPixels() and SetPixels() (thank you Unity guys, that’s really great implementation here).

First, instantiate your atlases :

_walkingMan_Atlas = Resources.Load("my_Assets/Resources_imageFile_name", Texture2D);

Each sprite creation code line would look like this :

_walkingMan_1 = _walkingMan_Atlas.GetPixels(0, 0, 64, 64);
// (x_origin, y_origin, width, height)

Repeat for each sprite.

At last, instantiate the screen texture receiver :

_screenTexture = new Texture2D(480, 320);

And now, what we wanted from scratch, the screen display. This would be done under Update() function, of course.

And this is where your work starts :smile:

I will not write the whole screen sprite display script, as I did not fully tested it, and don’t want to chew your own meat :wink:
But here is the idea … Each sprite var is a 2D Array (= Array[width*height]) of Color, which is
static function Color (r : float, g : float, b : float, a : float) : Color

So what you would have to do is putting each sprite array in _screenPixelMap var, detect Alpha pixels to replace by other sprites Solid pixels, and manage different sprite depths.
X and Y onScreen position of each sprite would be their array position.

This is not a hard level code, with a bunch of variables you will be able to manage all that parameters.

Nex step is to fill your screen texture receiver :

_screenTexture.SetPixels(_screenPixelMap);

At the end, it would be the final structure of the process, which we would use to draw the scene with this code :

_mainScreen = gameObject.Find("yourGUITexture_GO_name");

_mainScreen.guiTexture.texture = _screenTexture;

All loaded into memory, we can activate the visible screen :

_mainScreen.guiTexture.texture.Apply();

Job’s done, in 1 drawcall, with absolutely clean pixels.


Don’t hesitate to post some feedback about possible script errors in my code, or anything that would be wrong in everything I wrote. I will edit this post if needed.

I’ve tested this method only with one static sprite for now (for a HUD), without the _screenPixelMap creation we got here, and it works perfectly.

You can extend this concept to all kind of Texture2D, like 3D texture animation, Flash-like MovieClips, or whatever your imagination can do.

Have fun, and long life to videogames :smile:

Update : I wrote the whole script tonight, now it can add infinite images on the screen in a single drawcall, on the desired position, and can handle infinite alpha blendings(like in Photoshop).

It works perfectly, but …

… unfortunately, the image parser is way too slow to be used in an Update function. Limitation would only be in an Awake or Start.

I know the SetPixels(x,y,width,height) can handle 10x faster dynamic image loading, but it can’t handle alpha blendings :frowning:

So this “hint”, if we can call it this way, would only concern non-alpha image blocks, or non-layered alpha images superpositions.

Damn n0mad, thats pretty impressive. I’ve always wanted to do it this way, so I will have to check out your code later tonight.

You mentioned something about the alphas not working? Or was this only on Update()?

Ideally I would love to have a texture sheet of all the elements of my GUI, then on Start(), split it up and assign everything. But I would only need this on Start() correct?

Just trying to wrap my head around it before giving it a shot tonight when I get home.

Thanks for posting your findings!

Can you share ur GUITexture Sprite… really would like to see how it works…

Oh damn, another Scripting thread I wrote that I didn’t manage to back up :frowning:

Sorry guys, this forum section is so quickly overflooded by new threads that I can’t even see my own ones…

So back on topic :

@Fishypants : if you only want to split your atlasmap for sprite texture distribution, you need to do this before the game launches, yes (I guess).

@thetnswe : sorry amigo, I don’t have the code anymore (18 monthes old unused script ended in trashcan)

Plus, don’t bother with this method if you want to animate your GUI elements. Besides existing EZGUI solution, I found a much simpler way to handle my UI : Just model 3D quads in my 3D tool, texture them with one whole GUI texture, and import it in Unity. Then at runtime I’ll manage all my differents UI elements as GameObjects.

Now that Batching became mandatory and really efficient, this new solution fits ultra-well. Extensively, you can convert your imported unified 3D UI as separate prefabs, and therefore edit their precise positions.

Nice technique… i like it… will try it out… thanks!