So, what have I been doing the last couple of weeks? Firstly, the disco modifier!
The spotlights sway back and forth, the colours cycle, and the little dot lights spin around. (I want to show a gif of it, but the file-size is enormous. :() My current plan is to have it be pretty rare, but once you’ve seen it once,it unlocks as a secret option on the main menu, so you can enjoy it in all its glory whenever you want!
I had to learn a bunch of new shader tricks to get any of this to work. I was pretty happy, and then I tried it out on my Nexus 10 tablet and it ran at 11 frames per second, which is pants. Once I’d added an FPS counter, I discovered that even with only the subtle water ripples it was running at 55FPS, and the night shader at 33. So, a lot of time was spent trying to make these things faster. The end result is that with just the ripply water, 56FPS; the night shader at 48; and the disco shader at 20. (Disco reached 24, but then I added the player-light-circle because it was hard to see where you were, which dropped it to 20.) Optimising shaders was… interesting, as I barely know enough to make them work at all, and shader performance is almost a dark art. Simple things like using if statements to avoid doing work can be slower than just doing the unnecessary calculations. Someone explained somewhere that operations don’t really have a time cost: if a sin() takes 4 cycles, and a matrix operation takes 4 cycles, sometimes both together also take 4 cycles. So, my method was almost entirely trial and error.
You can save a bunch of time by doing calculations in the vertex rather than fragment shader, but the interpolation it does isn’t always what you want. For example, the weird blue lines on the water in the above screenshot are supposed to follow the spotlights, but the in-between values it calculates are wonky. You can see where the background is composed on two triangles from where the sharp bend is. In the end, I decided to leave it like this as, after all, it’s supposed to be a disco so goofy lighting is appropriate.
20 frames per second is not really good enough. I wouldn’t be happy unless the entire game always ran at 60. But, it seems the high-resolution on my tablet combined with mobile GPUs not being great might mean it’s impossible. I’m not trying to make excuses – I genuinely don’t know whether it can be any faster, or whether the hardware prevents that. On my desktop PC, with a graphics card that was OK in 2007, it’s fine. I’d love to be able to make it better, but ultimately I have to ship the game, and it’s not the end of the world. The 48/55 fps aren’t noticeable unless you’re looking, and 20 isn’t as awful as it sounds. I’ll have to see how it performs on other hardware.
I had one last idea for speeding the game up: using the depth buffer. To explain briefly, OpenGL can store a number for each pixel on screen, representing how near what’s drawn on that pixel is to the camera. Then, it only draws pixels that are closer than what’s already drawn. This way, you can avoid drawing on the same pixels over and over, wasting time. Now, currently the game draws back-to-front: first a fat blue rectangle is drawn, then fish, then the water’s surface, then the ground, then the player and plants, and finally the score and pause menu and such. Using the above screenshot as an example, this means that some of the pixels are drawn five times: behind the word “Score” is a tree, some grass, the water surface, and the blue background, and each of these is drawn onto those pixels. With the depth buffer, I could instead draw front-to-back, with “Score” being drawn first, and then skipping the tree, grass, etc. as they’re behind. (Not exactly, as semi-transparent things need to be drawn after what’s seen through them, but it would definitely cut out a lot of wasted work.)
So, why didn’t I do this? Because I discovered that the 2d-rendering parts of LibGDX are incompatible with the 3d rendering parts, so that I couldn’t swap things out, but would have to rewrite a significant portion of the library before I would know if this rewrite would make any difference. Unfortunately, I can’t devote that amount of time to this. Especially as this multi-week patch was supposed to be a minor fix to the Lake of the Day being stuck on a single game mode! I’m susceptible to feature creep, but not quite to that extent.
So, current plans: I have a few things left to clear-up before the next F!shing release, and then onto all the other projects I’m supposed to be doing! Some improvements to Quick Quote Professional are planned, to help with managing large numbers of quotable items, and multiple devices. Then, the business app that I barely started before F!shing distracted me. Once that’s done, I’m not sure, as I’ll probably have changed my mind multiple times before I get to it.
I’m also in the process of writing-up my month’s worth of shader experiences, things learnt and mistakes made. Not because I’m an expert, because I’m not, but because it’s such a confusing topic and I’d like to help other people be less confused. I’d been wanting to try writing shaders for ages before I finally dived in.