I’ve spent the last several weeks working on major performance improvements for Logic World update 0.91. The primary goal of these improvements is to enable much bigger builds by shortening loading times, increasing framerates, and lowering RAM usage for worlds with a very high number of components.
I’m finally at the stage where I can demo these performance improvements in-game! Here’s a video showing off a test save that contains 1,000,000 inverters and 10,000 wires – something that would be completely impractical in 0.90.
I was almost at this point last week, but I ran into two major roadblocks, the tales of which I will presently regale you with.
Annoying roadblock #1: shadows not working properly
I spent forever getting my instancing shader to render shadows, as I showed off last time. Imagine my dismay when I integrated the shader with Logic World and the shadows broke. After extensive investigation, the issue turned out to be with using multiple meshes. Instancing a single mesh many times, as I was doing in my demo scene where I developed the shader, would result in correct shadows. However, as soon as you introduced a second instancer with a different mesh, the shadows would break.
This made no sense and was extremely confusing. I’m still new to working with shaders & general graphics tech, so trying to fix a bug this outrageous was a daunting task. Nevertheless, I took the plunge; I read up on how shadowmaps work and tried everything I could think of to make them look normal again. After three days of this I had eliminated dozens of potential solutions, but was no closer to understanding the cause of the issue. Then, on a whim, I updated Unity to the latest patch release… and the bug was fixed!!!
ALL ALONG IT WAS A UNITY BUG AND NOT A JIMMY BUG. Three days trying to fix it when it was completely out of my hands, and all I had to do was press “update”. Well, lesson learned: in the future, when my code doesn’t work, I’ll be much quicker to blame someone else.
Annoying roadblock #2: invisible thumbnail renders
Logic World renders thumbnails for the items on your hotbar. This thumbnail-rendering system broke when I made the switch to GPU instancing. The world renders itself using Unity’s Graphics.DrawMeshInstancedIndirect function, but this unfortunately is incompatible with Camera.Render, which is what we were using to render the thumbnails. Camera.Render executes in the middle of a frame, but DrawMeshInstancedIndirect only actually instances the meshes at the end of a frame. Therefore, those instances couldn’t be seen by Camera.Render, and all the thumbnails were empty images.
I did some reading, and I figured out that I should be able to instance the mesh during Camera.Render using something called camera command buffers. I wrote the code to do this, but it didn’t work. I did some more reading, and it turns out that camera command buffers are not compatible with Unity’s Scriptable Render Pipeline, which Logic World uses.
So instead I started mucking around with Scriptable Render Features, which as far as I can tell are the only way of executing command buffers during Camera.Render in SRP. I did get the mesh instancing to work with this, but I couldn’t figure out how to make it work with any lighting, so all the thumbnail renders were dark and ugly.
Finally I gave up on doing things in a good clean way and implemented a crappy hacky solution. The only way I have of properly rendering the objects is with Graphics.DrawMeshInstancedIndirect, but that doesn’t work until the end of the frame. So, we’ll simply wait until the end of the frame to render the thumbnail. This unfortunately means that there will be one frame of delay between when we request a thumbnail and when it gets rendered; it also means that we can only render one thumbnail per frame, as otherwise the two items would overlap in the render. However, I believe I can mostly work around these issues by beginning thumbnail renders as soon as the game starts, so that every thumbnail you need is already rendered by the time you load into a world.
Overall it took about two days to fix all the issues with thumbnail renders. Bleh. While I was there, though, I took the opportunity to up the quality: thumbnail renders are now anti-aliased. It’s a subtle change, but a nice one. You might be able to notice the difference in the above video; the edges are much softer and less jagged.
After I’d finished with the above two issues, it’s thankfully been relatively smooth sailing to integrate the new rendering tech with Logic World. I’ve carefully checked everything, and all the visuals in 0.91 are now identical to the visuals in 0.90, down to every channel of every pixel. Objects look exactly the same, but they’re much faster to render in large-world scenarios.
I’ve still got a few more things to finish up with the optimizations, but I’m finally almost done with them. Once they’re finished, I’ll do a hefty round of bugfixing, and then I finally get to work on new features again!
The hardest part of 0.91 is finished, and the update will be in your hands soon.