0
\$\begingroup\$

In my project, there are large numbers (think 4-digit numbers) of 3D meshes that are created or modified one by one, or in groups, at runtime (based upon user interaction). These meshes have the following properties:

  • They are rather "simple" (usually comprising less than 20, or even 10, triangles).
  • Barely any two meshes will be exactly the same, as their geometry (e.g. location and number of vertices) varies based upon their environment/the location of other meshes in ways that cannot be described as a general geometric transformation (such as scaling).
  • The concrete shape of the meshes adheres to a general "pattern" (for instance, all meshes range from a "start point" at (0, 0, 0) to an end point at (0, 0, length)), although the concrete shape will be determined per mesh (based upon an external configuration, or supplied by plugin code, etc.).
  • The meshes will be oriented in different ways in the scene. The code that generates the meshes does not need to know about this, though.

All of these are no problems as such. The straightforward way I had thought of was to create a GameObject for each mesh, with a MonoBehaviour subclass attached that generates vertices, normals, and so on for the Mesh object of a MeshFilter component. The Transform of each GameObject can then conveniently be set according to the desired orientation of the mesh.

However, I have read various worrying reports that Unity does not cope well with large numbers of GameObject instances in the scene. For instance:

Based upon these resources, I figure I have various ways to proceed (that are not mutually exclusive):

  • I continue as described above, but do not activate all the GameObject instances with my meshes, so they only serve as mesh geometry containers that a transformation can be applied to. This sounds actually exactly like what I want (my objects do not need any self-controlled behavior), but a brief test indicates disabling actually shuts down drawing of the object, as well. As my players might zoom out far enough to see all objects at a time, this does not really solve my issue.
  • I do not store my meshes as individual GameObject instances with meshes, but I combine several of them into one large mesh. I think it's well feasible to group a few hundred meshes and combine their geometry into a single Mesh object. I'd lose the individual GameObject Transform features, but I could of course apply the appropriate transformation on all the vectors returned for any given object myself. The possible issue I'm seeing here is that if one of my objects changes, I may have to recreate all the vertex, normal, color, etc. arrays for the entire chunk of hundreds of objects.
  • I figure out which meshes are actually visible at any given time, and only generate GameObject instances for these meshes. Well, my objects are going to be spread across a map, and one will be able to see at least a very simple (outline) version of each of them when zooming all the way out. I might then create a combined low-res version of those objects that are farther away, but ultimately, this leaves me with the same issues as above, with the combined mesh.

Thus, my question is: Is using chunks of combined meshes (as one actual Mesh object per chunk, possibly split into several sub-meshes to support different textures) a viable way to go in my situation, despite the outlined issues with updating individual "inner" meshes?

\$\endgroup\$
3
\$\begingroup\$

You may want to take a look at Graphics.DrawMesh. It lets you draw individual meshes without individual GameObjects.

\$\endgroup\$
  • \$\begingroup\$ Wow, this looks promising. There are even some overloads that take all of the rotation and translation info that I'd put into the Transform otherwise. So the idea would be to just store as many individual Mesh instances as I like in memory, but invoke DrawMesh just for the meshes that are currently visible? Just to be sure - this works in all Unity editions, right? Can't wait to try this later :) \$\endgroup\$ – O. R. Mapper Jul 1 '18 at 14:45
  • \$\begingroup\$ Although ... threads like this one on Unity Answers do make me wonder whether DrawMesh will be any better than having many GameObject instances in the end - that thread being from 2013, though. \$\endgroup\$ – O. R. Mapper Jul 1 '18 at 14:48
  • \$\begingroup\$ You wouldn’t be getting the benefits of dynamic batching anyway, because you’re drawing all different meshes. From what I understand, view frustum culling is still applied, so even if you draw the ones off screen, it won’t incur a huge penalty. As for compatibility, this method has been around for several versions now. I don’t have the history memorized, but it goes at least back to Unity 5, and probably 4. \$\endgroup\$ – Ed Marty Jul 1 '18 at 18:23
  • \$\begingroup\$ I'm still experimenting with this solution. Unfortunately, already drawing only 1000 very simple meshes (consisting of just two quads each) takes a noticeable hit on the FPS. Going to try some more variations. \$\endgroup\$ – O. R. Mapper Feb 3 at 22:35
  • \$\begingroup\$ Have you looked at DrawMeshInstanced, or possibly manually batch them and send them to the graphics card as fewer, large meshes? \$\endgroup\$ – Ed Marty Feb 4 at 0:55

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.