- Home /
How does transparent sprites affect mobile performance?
I have a 2D platformer/runner game and I'm trying to optimize it so it runs fine on older devices. As one of several aspects, I'm currently investigating fill rate. As explained here by Robot Invader, fill rate issues occur when you write to a pixel many times. The more times you write the same pixel, the higher the performance cost. Transparent sprites causes pixels to be written to several times, since the engine can't tell if something behind that pixel should also be drawn. That is at least my understanding of it.
When we use sprites in our game, we use the SpriteRenderer component with the Sprites-Default shader. From the quote below (again, Robot Invader), it seems that the Sprites-Default shader would be highly inefficient for sprites that are opaque.
You pay for transparency anytime you render anything with a transparent shader, whether or not the texture you are rendering actually has an alpha channel. If it’s marked as a transparent object (i.e. put in Unity’s “Transparent” queue), it will be sorted back to front, and drawn with a shader that performs a multiplication of the current pixel value with the value of the computed color the shader is drawing (the actual math can be controlled using the Blend command in the shader’s pass). The way to think about this cost is in terms of the number of pixels that are touched by potentially-transparent things.
This tells me that anytime we use the Sprites-Default shader to render opaque sprites, and then render more sprites behind that sprite (i.e overdraw), those pixels will be drawn to several times because the Sprites-Default shader always calculates transparency. This eventually leads to poor performance on mobile devices because the fill rate skyrockets.
So what should I do about it? The obvious answer I come up with is to use another shader for sprites that are opaque. A shader that doesn't take transparency into account and thus doesn't draw stuff behind that opaque sprite. Yet when I google "Unity3D Sprites-Default Opaque" or something similar, I can't find a shader like that. Either it's really easy to do and being sucky at shaders, I don't know how, or this whole theory is wrong and Unity3D handles opaque sprites correctly anyway. In the latter case Robot Invader is wrong.
tl;dr: Is there a sprite shader for opaque sprites that is fill-rate efficient because it doesn't use the transparent queue?
Just for clarification, what version of Unity are you using?
This is just my paltry assessment (and thus not an answer) by taking a quick look at the sprite shader. I have Unity 5, but it's probably similar to 4.6. The default sprite shader indeed is always in the Transparent queue and turns Z Write off, so it will always be sorted. Now you could take the default shader (download from unity3d.com) and duplicate this, modifying it for opaque sprites, but you can't really modify the behavior of the sprite code, so I don't know what the behavior will be. I assume if you use a duplicate but opaque shader, the game engine will not sort it, but I'm not 100% sure. They could be perfor$$anonymous$$g sorting of all Sprites internally, although I'd have to think they'd just use the existing Transparent shader sorting to do that... The real problem I see is that Unity creates the atlases, and you'd need to mark those textures as opaque as well as "hope" that Unity would create separate atlases for the opaque and transparent materials. I don't even know if those atlases are available to you, could be auto generated out of sight.
If you still have performance issues, consider using a plugin from the Asset Store as you'll have more control over all aspects and can modify the code/shaders as you please. I do think this is an issue Unity needs to address though.
In my experience, some devices get bogged down with overdraw while other devices get bogged down with vertex count (especially Android where you are trying to support the lowest end devices anywhere), so the alternate solution of using a 3D model (really just a planar mesh that defines the alpha boundaries so you can use an opaque texture on it, but it simulates alpha by the fact that you only draw the texture on the visible parts of the mesh) is not always the best solution either. You just have to profile as much as you can and make adjustments to optimize everything, but you already knew that.
You could kind of trick the game engine into preventing overdraw by making anything that gets drawn on top of the 2D artwork a 3D object with an opaque shader, but you'd have to change the default sprite shader to enable z writing to get any benefit which means you'd also have to explicitly set the Z value of all sprites.
Could you post a screenshot showing the overdraw problems? $$anonymous$$aybe we can make suggestions to help.
Answer by sekari · May 26, 2017 at 12:43 PM
I know this is an old thread. But I would like to share what we have discovered in order to reduce overdraw.
Unity has Screen.SetResolution function which can update the current resolution of the device. If you lower the resolution, the amount of overdraw reduces.
this is called screen Up-Sampling you render whole screen at lower res... saves on rendering (and is very handy improvement... I suggest 75% of original screen width) . but it does not really reduce overdraw (layering of sprites)
Your answer
Follow this Question
Related Questions
How to render a sprite in the opaque pass 0 Answers
Sprite color invert 1 Answer
Optimise adding shadows in scene using Unity iPhone 2 Answers
Fixing fill rate issue on Android - best approach? 0 Answers
Reflect Fresnel Mobile VR 0 Answers