1
\$\begingroup\$

I am trying to make a game where the whole world is consists of a very large amount of cubes (sort of a Minecraft / Trove clone), but I keep running into huge performance issues due to the large amount of objects / vertices being rendered at once.

Just to clarify, the problem appears to be caused by the rendering, not the instantiation. I think so based on the fact that when I look away from the cubes, the frame rate will return back to normal (>60).

Is there any way to optimize this? Many answers to similar questions suggest disabling colliders, but that does not really seem to make much of a difference for me. I have also tried making the prefab static, but the problem still remains.

Currently I keep getting ~40 FPS with 10000 cubes (just the built-in cube shape stored as a static prefab with a disabled collider). I believe there should be a way to have a larger amount of objects on screen without having such a performance drop.

Does Unity have any way of storing information about a prefab in graphics card memory that would allow it to mass-render its instances in a more performance-efficient way (much like modern OpenGL uses vertex buffers)?

\$\endgroup\$
14
  • 1
    \$\begingroup\$ In your title you ask about instatiating while in the body you ask rendering which are two separate concerns. Could you edit your question so that it is consistent? (what of the two are you actually interested in?) \$\endgroup\$
    – wondra
    Commented Sep 10, 2017 at 13:10
  • 3
    \$\begingroup\$ Yes, Unity supports instancing, but instancing won't save you here. Spawning gobs of prefabs is simply not the right solution to this problem. Most voxel-based games don't actually render a cube for every block in the world — they just look like they do. In reality, they render only the outermost surface — for example, a dynamically generated minimal mesh covering just the skin of the terrain. Search around here for voxel rendering and you'll find other questions about these types of optimization. \$\endgroup\$
    – DMGregory
    Commented Sep 10, 2017 at 13:23
  • \$\begingroup\$ I have ran into this issue, @wondra, but the only solution I found was to have the blocks of your grid already existing, then changing texture/collider runtime. Of coursr, this may not help if you want it to have infinite terrain. \$\endgroup\$ Commented Sep 10, 2017 at 13:46
  • 1
    \$\begingroup\$ As I mentioned, this has been asked before, so I recommend reading up on that material first, and refining your question based on that background. Other strategies you can research include dispensing with meshes altogether and using a form of raymarching or octree traversal to rasterize the voxels. \$\endgroup\$
    – DMGregory
    Commented Sep 10, 2017 at 15:08
  • 1
    \$\begingroup\$ Welcome to a stack exchange site! As a quick note, there is no such thing as necro-posting here, users are welcome to contribute at any time if it's still relevant to future visitors. If a user decides to answer in comments, there is a risk that those comments get deleted, and it's a perfectly acceptable behaviour for another user to post an answer out of those. Questions with answers are generally considered useful for future visitors; if you don't need it anymore, you're welcome to either delete the question, or leave it alone (don't accept, vote, etc.). \$\endgroup\$
    – Vaillancourt
    Commented Dec 10, 2018 at 12:22

2 Answers 2

3
\$\begingroup\$

Don't use thousands of GameObjects. Don't use the flyweight pattern. Do as Peter says: batch your vertices. You can learn the basics of procedural mesh construction here.

Between batching and instancing, you can do things with far better performance than by using thousands of GameObjects, which creates unnecessary overheads in such high-geometry tasks.

Golden Rule of voxel/cube terrain: NEVER use one object instance per tile, except possibly in exceptional circumstances.

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

It sounds to me like what you are looking for is Occlusion Culling.

Essentially if you are running a Minecraft like game, the renderer is going to try to render everything that is currently being seen by the camera even GameObjects that are obscured by other GameObjects. The problem occurs, because you what you actually want is to only render things that are actually showing, that is, only the GameObjects that are in view and not being blocked by other GameObjects.

Occlusion Culling to the rescue! Occlusion Culling fixes your problem by saying "Hey I know there is a ton of GameObjects in front of me, but can you only render the ones that the player is actually seeing, that is, not the ones that are being blocked by other GameObjects?"

Hopefully this makes sense!

Check this link for a nice guide from Unity that explains exactly what I'm talking about...much better then I did.

\$\endgroup\$
9
  • \$\begingroup\$ I am aware of culling, I have mentioned it in the comments, but it really doesn't solve the problem. Even with just a flat plane of 100x100 cubes (all cubes are in sight) the culling seems to have no effect. It appears that I will really have to convert the surface of all the blocks into a single mesh in order to speed up the rendering. I just wasn't familiar with the concept of voxels when asking the question. As I said, culling is not going to help, because I want to be able to have a 500x500 cubes flat plane and culling is not going to help me with that. \$\endgroup\$
    – natiiix
    Commented Sep 10, 2017 at 19:50
  • 1
    \$\begingroup\$ @user3043260 The solution is to render a flat plane instead of 25'000 cubes representing a flat plane. There are several ways of doing this, voxel is one keyword, and another band-aid is self-made batching. \$\endgroup\$
    – Peter
    Commented Sep 10, 2017 at 21:50
  • \$\begingroup\$ @Peter The surface of the world is obviously not supposed to be completely flat which makes it quites difficult to use basic shapes. Besides I've mentioned earlier that I have been doing the static batching and it didn't help, so I doubt doing it myself would yield any better result. \$\endgroup\$
    – natiiix
    Commented Sep 10, 2017 at 22:51
  • 1
    \$\begingroup\$ @Peter You do realize that these cubes must be independent of each other, right? I kinda said that in the comment you replied to, so I assume you are aware of that. Of course if I use a single large block instead of a large amount of small blocks, there will be a significantly lower amount of vertices to work with, thus making the rendering much easier. But that's really beside the point I was going for. \$\endgroup\$
    – natiiix
    Commented Sep 11, 2017 at 14:19
  • 2
    \$\begingroup\$ Peter is describing batching, where you put all the vertices and faces for a group of blocks into a single mesh. The total amount of vertices & triangles remains the same, but it can be submitted to the GPU in fewer draw calls, which can be a substantial savings. You don't necessarily lose independence of the blocks in this situation, you just re-generate the group mesh when some of its blocks need to change. Unity does a degree of this for you automatically though, so if it's still slow you might need to dig into more aggressive optimisations as discussed above. \$\endgroup\$
    – DMGregory
    Commented Sep 11, 2017 at 14:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .