using_multimesh.rst 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. :article_outdated: True
  2. .. _doc_using_multimesh:
  3. Optimization using MultiMeshes
  4. ==============================
  5. For large amount of instances (in the thousands), that need to be constantly processed
  6. (and certain amount of control needs to be retained),
  7. :ref:`using servers directly <doc_using_servers>` is the recommended optimization.
  8. When the amount of objects reach the hundreds of thousands or millions,
  9. none of these approaches are efficient anymore. Still, depending on the requirements, there
  10. is one more optimization possible.
  11. MultiMeshes
  12. -----------
  13. A :ref:`MultiMesh<class_MultiMesh>` is a single draw primitive that can draw up to millions
  14. of objects in one go. It's extremely efficient because it uses the GPU hardware to do this.
  15. The only drawback is that there is no *screen* or *frustum* culling possible for individual instances.
  16. This means, that millions of objects will be *always* or *never* drawn, depending on the visibility
  17. of the whole MultiMesh. It is possible to provide a custom visibility rect for them, but it will always
  18. be *all-or-none* visibility.
  19. If the objects are simple enough (just a couple of vertices), this is generally not much of a problem
  20. as most modern GPUs are optimized for this use case. A workaround is to create several MultiMeshes
  21. for different areas of the world.
  22. It is also possible to execute some logic inside the vertex shader (using the ``INSTANCE_ID`` or
  23. ``INSTANCE_CUSTOM`` built-in constants). For an example of animating thousands of objects in a MultiMesh,
  24. see the :ref:`Animating thousands of fish <doc_animating_thousands_of_fish>` tutorial. Information
  25. to the shader can be provided via textures (there are floating-point :ref:`Image<class_Image>` formats
  26. which are ideal for this).
  27. Another alternative is to use a GDExtension and C++, which should be extremely efficient (it's possible
  28. to set the entire state for all objects using linear memory via the
  29. :ref:`RenderingServer.multimesh_set_buffer() <class_RenderingServer_method_multimesh_set_buffer>`
  30. function). This way, the array can be created with multiple threads, then set in one call, providing
  31. high cache efficiency.
  32. Finally, it's not required to have all MultiMesh instances visible. The amount of visible ones can be
  33. controlled with the :ref:`MultiMesh.visible_instance_count <class_MultiMesh_property_visible_instance_count>`
  34. property. The typical workflow is to allocate the maximum amount of instances that will be used,
  35. then change the amount visible depending on how many are currently needed.
  36. Multimesh example
  37. -----------------
  38. Here is an example of using a MultiMesh from code. Languages other than GDScript may be more
  39. efficient for millions of objects, but for a few thousands, GDScript should be fine.
  40. .. tabs::
  41. .. code-tab:: gdscript GDScript
  42. extends MultiMeshInstance3D
  43. func _ready():
  44. # Create the multimesh.
  45. multimesh = MultiMesh.new()
  46. # Set the format first.
  47. multimesh.transform_format = MultiMesh.TRANSFORM_3D
  48. # Then resize (otherwise, changing the format is not allowed).
  49. multimesh.instance_count = 10000
  50. # Maybe not all of them should be visible at first.
  51. multimesh.visible_instance_count = 1000
  52. # Set the transform of the instances.
  53. for i in multimesh.visible_instance_count:
  54. multimesh.set_instance_transform(i, Transform3D(Basis(), Vector3(i * 20, 0, 0)))
  55. .. code-tab:: csharp C#
  56. using Godot;
  57. public partial class MyMultiMeshInstance3D : MultiMeshInstance3D
  58. {
  59. public override void _Ready()
  60. {
  61. // Create the multimesh.
  62. Multimesh = new MultiMesh();
  63. // Set the format first.
  64. Multimesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D;
  65. // Then resize (otherwise, changing the format is not allowed)
  66. Multimesh.InstanceCount = 1000;
  67. // Maybe not all of them should be visible at first.
  68. Multimesh.VisibleInstanceCount = 1000;
  69. // Set the transform of the instances.
  70. for (int i = 0; i < Multimesh.VisibleInstanceCount; i++)
  71. {
  72. Multimesh.SetInstanceTransform(i, new Transform3D(Basis.Identity, new Vector3(i * 20, 0, 0)));
  73. }
  74. }
  75. }