26 September 2020

ShipBasher Development Log 10: PewPewPEWpewPewPEWpewPEWpewPewPewPEWpewPEWpewPew

Something I hope will be a draw for ShipBasher is the ability to marshal completely impractical ships that fire entirely unreasonable amounts of ammunition at each other, as I mentioned briefly in the last post.

In pursuit of this idea, I dusted off the GPU bullet system I had prototyped a while back and integrated it into the game over the course of one very late night. In so doing, I discovered that I'd more or less made my computer work with proverbially one hand tied behind its back.

See, like some kind of pro l33t h4x0r code sorcerer, I decided to use a compute shader for processing bullets. A persistent buffer of bullets is formed on the GPU, so that unlike in a normal shader, the results of computations made in one frame can carry over to the next frame - an essential feature when trying to use a GPU to simulate things moving over time.

But like a dumb idiot n00b, I was taking the buffer back from the GPU and sending it off to be made into a mesh object, making a redundant copy of it along the way, and then when it was time to render the frame having the mesh object get sent over to the GPU so that the poor thing could hold it in memory alongside the persistent buffer, essentially causing both my computations and memory usage to be doubled for no reason and, perhaps even worse, bottlenecking my performance by schlepping data back and forth every single frame. Basically the only useful thing the GPU cores were doing was moving each bullet forward a bit, which is such a trivial operation that I probably would get more performance out of skipping the compute shader business altogether and just calculating everything with the CPU like a normal person.

Of course once I noticed and apprehended the scale of this problem, I had to fix it immediately. I tinkered and fussed with my code until I had eliminated all the redundant data processing and made everything way more efficient. Unfortunately it didn't change much as far as the frame rate went, because it turns out that with my setup and its relatively weak GPU, my performance was limited by rendering speed anyway. Nevertheless it sure felt good to know my code was way less stupid than before.

I also made some tweaks to my weapons firing code so that turrets with extremely fast firing rates could fire multiple rounds per frame rather than being limited to one per frame as they had been before, and behold!

Yes I think I know what you're thinking.

 

In practice I doubt I'll include single turrets able to expend ammunition quite this fast (the last one is 20,000 rounds per second or 1.2 million rounds per minute) in the finished product, but the ability for many bullets to be released every frame by all the various turrets that I expect to be active at once is important.

Something else I hope gets noticed here is a big improvement I made to how the bullets get rendered. Now they stretch out along their velocity vectors, much like Unity's built-in Line Renderer, but unlike the built-in Line Renderer, they smoothly transition to point sprites if they are very far from the camera or are viewed from a very shallow angle to this vector, causing them to maintain a round, 3D appearance rather than give away their true nature as flat rectangles. It's not perfectly polished just yet, but I'm pretty proud of what I accomplished with it and think it makes for some nice screenshots (as you may have guessed).

The next problem to tackle is making these bullets actually do something. While it's amusing to watch fountains of bullets pour forth from my gun barrel, they simply float through space until their numbers come up in the pooling system and they start the cycle over again, never having any effect on the world, much like the test bullets not too long ago. This is a harder fish to fry, though: Unity's physics engine, PhysX, and all of the alternate physics engines available, do their processing using the CPU, using data sitting in RAM for all of the collidable objects and their locations - but this new bullet system operates on the GPU, which has its own memory that's separate from the RAM and is alien to the physics engine. I could write a whole collision detection algorithm in a compute shader, or I can find some inexpensive way to roughly predict collisions in there, hopefully for only a relatively small subset of bullets, and then extract some data about those back into the regular RAM so I can use it to tell the physics engine what's going on. It's just as complicated as it sounds, and thus the subject of at least one future blog post.

No comments:

Post a Comment

Sorry this isn't a real post :C

I've entered graduate school and, as I expected, suddenly become far busier than I had been before, leaving no time to maintain my blog,...