Need design advice for top down space shooter effects on mobile

Hi,
I will be designing an effects pack for top down space shooter game and need some advice. This topic is not new for me. I’ve written shaders before and know the graphics pipeline fairly well, I think. Mostly I’ve written stuff for desktop, but I’ve also optimized shaders for mobile devices. I’m aware of mobile device limitations, like draw calls, fill rate, alpha blending and testing, texture lookups to name the main ones. For mobile, everything must be very tight. This is why I’m asking advice. Maybe something I’m thinking about trying out is just not worth the effort. Maybe you have some neat idea to share.

Specs:

  • Target is mobile phones and tablets, iOS and Android
  • No need to support lower end devices (iPad 4th generation and up, Samsung Galaxy SIII, Samsung Galaxy Tab 2, Google Nexus 7 first generation, etc. About a year old decent tablet or phone should be able to run it)
  • Effects will be almost all 2D
  • There will be a lot of them simultaneously on screen
  • OpenGL ES 2
  • using Unity Pro

My first concern is alpha blending. That’s a tough one. My current idea is to separate “local” blend effects like laser hit sparks from “global” blend effects like tinting some portion of the screen (fog, energy field, etc). The “global” effect would use one relatively low resolution texture, that is updated on CPU side, so that the fragment shader would be as small as possible. I hope it’ll amortize the cost of larger effects on high dpi screens. “Local” blend effects would use as few pixels as possible, but still, when there are many of them on screen the blending cost will become problematic, but I don’t see what I could do here.

Texture lookups are more costly than a few more fragment shaders ops on desktop. Is it true for mobile too? Maybe it’s better to compute a texture on the fly in fragment shader (would use UV and some other parameters). A forcefield around a ship is symmetric enough for this. Is it worth to try it out?

What would be a texture memory footprint I should aim for? I know, the smaller the better, but realistically, how far up I can go, before I get into trouble.

How to pass meshes to the graphics pipeline? Is the regular way of using meshes and relaying on dynamic batching a good way to go? Maybe I should try to build things around API calls like Graphics DrawMesh and GL class methods?

Should I try using builtin particle system or should I write small optimized scripts that animate mesh vertices or mesh instances on it’s own? I guess the particle system is well optimized, but it may also be too bloated, idk.

Anything else I haven’t thought about, but really should?

Great thanks to you guys who take time to read it and replay :smile:

Lots of these issues I think will come down to testing on your target devices, and the answers might be different depending on the underlying hardware. And whether a texture lookup is for expensive than a few fragment ops probably also depends on your shader. If you aren’t doing many texture lookups yet, the hardware can probably prefetch it with little additional cost. But you do one fetch too many, and it needs to do two trips to get all the texture data our frame rate will tank.

In general, I think procedural textures will be more expensive than texture fetches unless you have very, very simple algorithms for your textures. A hybrid approach would probably be fastest–use a small RGBA texture will a different type of seamless noise in each channel, calculate a custom weighting vector (based on distance from center, a time variable, thresholding, etc.), and then colormap the result (either with a small gradient texture or in code). You could probably design some very convincing shield/smoke/explosion effects using very little texture data and some simple shader code.

One huge thing to keep in mind is to trim your particles as much as possible. Find or build a particle trimming tool like this one (Humus). The fastest pixel is the one you don’t have to shade. If you create a custom mesh for each particle type you can really save on performance. For any procedural textures a simple circle would probably suffice.

Mobile does tend to benefit from lower-precision data types like half or fixed instead of full floats, so use the minimal precision that you need.

Reading textures is indeed a source of slowdown. You do get more bang for buck if you can read multiple textures within one shader and combine them somehow to produce a single output, provided the combining is not too complicated.

Definitely compressed textures can be read faster than uncompressed.

Removing the 32-bit backbuffer and using 24-bit only does help speed also provided you don’t need destination alpha channel.

Blending does use additional performance so consider whether its a good idea or not. For example if an object is mostly solid and only has alphablending needed around its perimeter it may be faster to do object interiors separately. Also don’t forget fillrate is important so making the geometry fit tightly to the shape of the object saves having to check/process lots of empty fragments - but this is all done at the geometry level.

Keep the shaders as simple as possible… complicated shaders do slow things down a lot. So write highly optimized non-sloppy code.