1
\$\begingroup\$

I'm currently working on taking an idea I've been toying with in C++ and bringing it into Unity, but I'm struggling to figure out how to make it performant and how to do things the "Unity way".

My world is made up of cubes and cube shaped tiles viewed from a fixed angle (à la Monument Valley). I've watched their behind the scenes video and seen that they have a step in their workflow that removes the unused faces from their cubes and combines them into quads. I want to achieve something similar.

Ideally I want to build up my world using a bunch of prefab cube objects (with different textures and components) and then run some kind of process over my scenes before I export/play to optimize them (otherwise I'm going to be doing potentially thousands of draw calls that I don't need to do and have lots of colliders I don't need).

My questions are as follows:

  • What hooks does Unity provide to do this sort of processing? Should I be using PostProcessSceneAttribute for this?
  • I understand that I can use Mesh.CombineMeshes to combine my cubes, but what about for their colliders?
  • How can I determine groups of cubes that are touching (for removing faces and combining colliders)? In my C++ project I keep all of the blocks in a 3D array and use that, but using the Unity editor to place the blocks means I don't have this available. Is there a way I could easily build one from my scene, or is there a more "Unity" way of doing this?
  • Is my approach sensible? Or should I drop the idea of placing individual cubes in the editor and take a different approach?
\$\endgroup\$
1
\$\begingroup\$

One of the biggest overheads for Unity in regards to CubeWorlds is that every single one of those cubes is an instance of something. Whereas Minecraft has a single class instance for every Block and Item and merely references them to figure out what they do (there are a few exceptions, but those are handled with TileEntities, which if you have enough of them, the overhead starts to lag the game). Minecraft constructs the level geometry manually by iterating over the chunk and figuring out which sides need to be drawn and with what texture, etc. and storing the result until something changes.

Mesh.CombineMeshes will sort of do this for you, but be aware that:

  • It does not cull hidden faces (that is, two cubes in adjacent positions will still use 24 triangles).
  • It has a vertex limit of 65535
  • Is treated as one object for the purposes of lights (only so many dynamic lights are rendered, depending on quality settings).

It will, however, maintain colliders. I forget if this is due to simply disabling the rendering of the original objects or by copying the colliders onto itself (it has been a few months since I last messed with this). For point 1, I created a custom cube object that would figure out if a given side needed to be rendered and disable it prior to being rendered.

\$\endgroup\$
0
\$\begingroup\$

I would highly recommend this tutorial series by 12pt on the Unity forums, which details how to do procedural voxel mesh generation in Unity.

I've used his tutorial to create my own voxel world for an isometric city simulator (series). In the first video of the series you can see that I quickly dropped using Cube prefabs, as viewing my 160x160 world from the max distance resulted in ~10fps. Once I'd swapped to procedural mesh generation (using chunks) I returned to ~1,300fps.

Obviously it's not quite what you're looking for, but it wouldn't be too hard to make a terrain editor script that allowed you to increase/decrease the high of any tile, and set the texture of said tile. Once that's complete you'd have to Serialize that data to load it again at a later date for editing (episode 2 of my series).

An alternative approach would be to use a height map, and pass this to a terrain GameObject. Hope this helped.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.