World generation and crafting…

Hey everyone! This is my first official Zombox update in a long, long time.

Since Jungle Moose is out, and Bean Boy is 99% done, I’ve been back working on Zombox.

I left off in March, having finished modelling most of the craftable structures in the game. But one big thing was looming pretty far over my head….

If any of you are game developers yourselves, you’ll know that ‘draw calls’ are the bane of many developers existences (especially those targeting mobile platforms). A draw call is basically an instruction sent to a device’s video card, that tells it to render some geometry to the screen. So, for example, if you have five separate objects you’d like to render, then that will require five separate draw calls (assuming the game engine doesn’t implement any type of batching system). Draw calls are ‘expensive’, which means that they take a lot of processing time to send to the graphics card, and for that reason you always want as few draw calls as possible.

Unity’s rendering pipeline includes a batching system, that can group objects and send them together as a single draw call. The batching system has many quirks, the biggest one being that it can only attach a very small amount of geometry together for each ‘batch’. Up until now it was what I was relying on to render the Zombox world.

However, with the addition of the crafting system into Zombox….I was presented with a pretty major problem: if the user is able to create objects anywhere in the world, then there is nothing stopping them from creating tons of different objects on screen in the same area. Typically, any location within the city in Zombox (where the user hasn’t crafted anything) takes about 30-40 draw calls to render (that’s excluding draw calls for the GUI). That’s already pretty heavy….but if the user were to craft a bunch of objects in that area, that number could increase way past what most mobile devices could handle at an acceptable framerate (even with built-in batching). We’re talking possibly over a hundred draw calls just to render the scene geometry alone! That’s not including zombies or NPCs or even the main character! That’s totally unacceptable and has been a major roadblock in the game’s development.

Earlier in the year I attended a Unity meetup in Toronto where Jim McGinley spoke about procedural generation in his game Endlight. He presented a novel solution for quickly updating meshes in Unity with thousands of changing vertices and arbitrary vertex counts (a process that is normally very slow when vertex counts change): at the start of the game, he generated a separate mesh for each possible vertex count, up to a max vertex count (so if he knew his biggest mesh would have 1000 vertices, he generated 1000 meshes and set their vertex counts from 1 to 1000, respectively). Then when he quickly needed to generate a mesh with, say, 874 vertices, he would grab the pre-generated mesh with 874 vertices, pop his new vertices into it, and hide all the other meshes. This prevented him from having to re-send new meshes to the GPU each frame because all of those pre-generated meshes were already in the GPU, just waiting for their vertex lists to be updated. And the whole thing would only take 1 draw call to render.

Now, that solution worked great for him, but it is also quite memory intensive — and Zombox needs to conserve memory to make room for all of the other procedural content that gets loaded. So generating 1000 meshes isn’t a viable option for me….but it did lead me to come up with the solution I’m using now. Here’s how my current solution works:

  • The scene geometry is imported with a custom tool to automatically cache all base city meshes for quick reading of their vertex/triangle lists
  • When the game starts, I generate about a dozen meshes in a mesh pool, each with a few thousand triangles/verts. The lower the vertex count of each mesh, the less processing time required to update it. However, the more meshes in the pool, the higher the resulting draw call count will be. So, setting the total triangle/vert count to a few thousand is a good balance.
  • Each of the triangles in the mesh are added to a pool of “free” triangles
  • When the city begins to load, instead of displaying each object with an individual MeshRenderer component (which would then be batched and sent to the GPU when it’s time to render), each object instead grabs however many triangles it needs from the pool, and positions the vertices of those triangles to match all of the vertices in its cached mesh. It does the same for its texture verts (UVs). Any triangles used to generate the object are then removed from the “free” triangle pool
  • If, at any point, the “free” triangle pool ever gets used up before all base city meshes are displayed, I simply add a new mesh to the mesh pool and pop its triangles into the triangle pool, and keep going. No matter how many objects a user crafts on-screen, I’ll never need more than about 20 pooled meshes to draw them all, considering that on-screen vertex counts can only ever get so high before there’s no more room to craft things in screen-space
  • Any time an object is unloaded from the game, its pool triangles are added back to the “free” triangle pool, and all of the verts that were used are set to be degenerate (which causes them not to render anymore)
  • Any time an object is updated, I cycle through its pool triangles and just update their vertex locations

Now, that’s a pretty big mouthful of information — what does it entail? Well it means that I can render the entire Zombox world, no matter how many objects the user crafts, in about 12-20 draw calls….which is pretty amazing!

That said, there is a performance hit that occurs by doing all my custom batching/pooling operations. But, by spreading those operations out over a few frames and not doing all of the geometry calculations at once, the hit is small enough that it doesn’t affect the game’s framerate. So it’s a pretty great solution to a pretty massive problem! Caching all of my mesh data beforehand also means that I don’t need to do any allocations per frame in order to read mesh triangle/vertex data. The downside to caching is that it means you have to create a duplicate of your mesh data in memory, on top of what Unity already caches under the hood. My solution to that was to scrap FBX import of the city geometry all together and write my own mesh import system, which means I’m only ever holding 1 copy of each city mesh in memory at once, and I still don’t need to do any extra allocations to read geometry data.

So, as you can see, I’ve been busy despite my silence! But the results have been worth it.

Not everything I’ve been working on has been under the hood, though. I’ve also been working on the crafting interface and getting all the new craftable structures implemented into the game! The crafting interface (that allows you to place and rotate objects you want to craft) is still a work in progress, but you can see a result of some construction in the image at the top of this post.

Thanks to everyone for you continued support, and look forward to more Zombox updates soon!

20 Responses to “World generation and crafting…”

  1. Geta-Ve says:

    Wow, this is all pretty dang great man. Incredibly brilliant solutions to very big problems.

    I hope Bean Boy does great. It will be an instant buy from me for sure.

  2. Spracky says:

    Sounds great man, keep up the good work!

    Cant wait for some sort of beta or gameplay!!!

  3. Tyonn says:

    DUDE CANNOT WAIT FOR u to complete it but it takes time to creat a masterpiece so hope all the best if there is a beta let us know

  4. you know who i am says:

    wow the zombox came back!!
    plzzz keep the good work always waiting for this^^

  5. Terry Stone says:

    Good to see you back on Zombox Tyson.

    Just think about the possibility of releasing the game with just
    enough core elements to make the game fun.

    You can always add more crafting and other game play features
    in future updates.

    From what I can see, you have tons of fun features already on the go.
    Just polish what you have to a brilliant shine. You can always dig
    up new ones, as time permits ,with the next update.

  6. Anonymous says:

    Wait you mean 7 months “soon” or 3 years “soon”? I´ve been quite confused with that term on these last posts…

  7. Anonymous says:

    Waiting..

  8. Fadi98n says:

    Nice to see a new Zombox update, it’s been a while
    good luck with Bean Boy I’m downlodaing that the second it comes out :)

  9. George says:

    So this is coming to Steam too, right?

  10. Josh says:

    Can you put this on Android when it comes out? I would love to play this on my Samsung Galaxy Tablet

  11. Anonymous says:

    Pleas make this game for pc! I would play that so much more!

  12. Johnny says:

    12 total comments. That’s a far cry from what these threads used to get. Now I’m not saying rush the game out but people are losing interest man.

    • Spracky says:

      Yeah, even if its just a closed beta. Testflight is an easy beta testing application for ios devices that you could look into. From my experience, you will get a lot more done and find more bugs in a closed beta than an open one. If it’s closed, the testers feel obligated to actually try to find bugs since they are personally hand-picked. Testflight has worked great for me when I’ve tested games. If you ever start a closed beta, count me in. Hey, i was here when you made one of your first posts!

  13. Anonymous says:

    At least he could tweet more often…

  14. Anonymous says:

    Happy new year, you inactive little dev!

  15. Jason says:

    Awesome solution I never thought of.

    But how did you exactly do the soft-body effects in Bean Boy ?

    • Tyson Ibele says:

      There are no actual soft body effects in Bean Boy. It’s all keyframed animation blended together based on whichever action bean boy is currently performing.

Log in or Register

Leave a Reply

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

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>