Project DevBlog, March 2021 – Finishing

Image

Well, I’m done with the sprite shader project – sort of! As you may have noticed, I haven’t announced its release on the Unity Asset Store or, indeed, anywhere. This is because while I did indeed finish the project itself (mostly), I have not yet quite finished all the secondary materials such as tutorials, trailers, documentation, and the store page. All this likely won’t take too long to make, but as soon as the month ticked over to April it all went on the backburner – for reasons I’ll get into in a bit.

First, I addressed a problem that had been sneakily sabotaging me for months – that of normal facing. In case you’re unfamiliar with the terminology, the “normal” is the vector directly perpendicular to a surface – so, for instance, on a perfect sphere every normal on its surface would point directly away from the center. Since sprites typically face the camera directly, their normal would usually be pointed directly at the camera – or, from the camera’s perspective, the vector (0, 0, -1). Of course, it also doesn’t matter much what a standard sprite’s normal is, because it never uses that information for anything – normal information is mostly used in lighting calculations, and standard sprites are unlit.

My sprite shaders, however, are not unlit – one might say they are indeed quite lit. This meant I needed the normal, which is easy to access in the shader – but not, it turns out, in an entirely consistent fashion. All my shaders can do is interpret what a renderer is sending them – and, unfortunately, the way Unity’s built-in 2d renderer types such as SpriteRenderer, SpriteShapeRenderer, ParticleSystemRenderer, and TilemapRenderer choose to do this is not entirely consistent! Some of them cleverly face the normal towards the camera regardless of their orientation – which would be great if it were consistent, but it’s not. Because of this, I need all sorts of special case code to flip normals around if they’re facing in the wrong direction, and all of these require trial and error to determine because Unity’s renderers are basically black boxes. These values are only made more unpredictable once you start including variants for GPU instancing and support for Unity’s other rendering pipelines, all of which can also change how renderers handle normal facing!

I also discovered while testing that my code for expanding the vertices of the sprite to accommodate becomes very unreliable among many circumstances I hadn’t thought to test for. Here, as well, the differences between 2D renderer types become tricky, and when combined with the challenges of GPU instancing and alternate pipelines becomes downright unmanageable. For the above reasons, to cut down on excess complexity while I get the core of the shaders stable, I’ve decided to disable instancing and URP support until after release. This is a little disappointing since I’ve put so much work into getting these working, but it should make for a fast and impressive 1.01 patch a few weeks post-release, and I gather an asset that gets patched frequently is one that is more appealing in the store anyway.

I also realized fairly late on that I’d carelessly only been testing using square or near-square sprites. This was effectively simplifying all of my rotation calculations – and thereby covering up erroneous assumptions I’d made. After realizing my mistake, it took me a couple of days to figure out how to adjust the aspect ratio of the rotation – and, once I did, I also lost several days in a highly characteristic manner, getting sidetracked trying to further improve that rotation code in consistency and efficiency.

The final major improvement I made on the code side came when I realized that I had included several prefab objects using the shaders to help people get started, but that the interface for the sprite settings script didn’t actually handle prefabs well at all. While Unity’s editor is pretty good at handling direct changes to properties, I am using a custom editor to add and remove values to and from a hidden list – that is to say, the displayed values didn’t exist as far as Unity understood, so it had no way to relate them to the values contained in the prefab the object was instantiated from. In order to fix this, I had to recreate much of Unity’s prefab-handling behavior from scratch – something I was annoyed to need to do, but quite proud to find myself readily capable of doing.

It was nearing the end of the month at this point, and there was still much left to be done – and, as I said, much of it is still undone now, a little ways into April. However, while I may not have these tasks done, I did make progress on most of them: The documentation is written and converted to html, ready for uploading but for a few edits for aesthetics and clarity – and having a website ready to upload it to that won’t change its formatting. There are no tutorials made yet, but I have finished the demo museum scene, which shows a comparison of all the different draw modes of the sprite along with six demo effects and brief descriptions of their implementation – since the tutorials will all be on recreating these effects, this actually is a sort of progress on that task. Finally, even though I have yet to even start building the store page or the trailer, these will likely be largely sourced from the documentation and tutorials respectively – so, all in all, I’m not as far away as it may at first seem.

I’m so close to completion! Yet I haven’t worked on the project for a week now, because all of my attention – and I do mean all of my attention – has been taken by game jamming. A year and change ago now I was in a similar situation, participating in the last ever Idle Thumbs community game jam, Wizard Jam 10. Since then, one of the alumni of that illustrious pod has continued to stream on Twitch, and now the community around those streams, of which I am also a part, has started a new annual spiritual successor jam.

This is kind of a perfect storm for me, coming at a time when I feel creatively frustrated, have a new asset I need to test in a live environment, and have a bunch of complicated collision and map logic I need to write for my main project – giving me a much more immediately interesting way to pursue all these things and explore some interesting ideas. The premise of the jam is to base each project on a line from this channel trailer – I’ve chosen “Join us for the madness” and am creating a horror Metroidvania whose scope already threatens to get way out of control. I will obviously write about this project much more for the next DevBlog – for now, I’ll just leave you with a screenshot demoing an effect I’ve already been inspired to add to the sprite shaders: Dithered Lighting.

Leave a Reply

Your email address will not be published. Required fields are marked *