using_servers.rst 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. .. _doc_using_servers:
  2. Optimization using Servers
  3. ==========================
  4. Engines like Godot provide increased ease of use thanks to their high-level
  5. constructs and features. Most of them are accessed and used via the
  6. :ref:`scene system <doc_scene_tree>`. Using nodes and resources simplifies
  7. project organization and asset management in complex games.
  8. There are several drawbacks to this:
  9. - There is an extra layer of complexity.
  10. - Performance is lower than when using simple APIs directly.
  11. - It is not possible to :ref:`use multiple threads <doc_using_multiple_threads>`
  12. to control them.
  13. - More memory is needed.
  14. In most cases, this is not really a problem. Godot is well-optimized, and most
  15. operations are handled with signals, which means no polling is required. Still,
  16. sometimes, we want to extract better performance from the hardware when other
  17. avenues of optimization have been exhausted. For example, dealing with tens of
  18. thousands of instances for something that needs to be processed every frame can
  19. be a bottleneck.
  20. This type of situation makes programmers regret they are using a game engine and
  21. wish they could go back to a more handcrafted, low-level implementation of game
  22. code.
  23. Still, Godot is designed to work around this problem.
  24. .. seealso::
  25. You can see how using low-level servers works in action using the
  26. `Bullet Shower demo project <https://github.com/godotengine/godot-demo-projects/tree/master/2d/bullet_shower>`__.
  27. Servers
  28. -------
  29. One of the most interesting design decisions for Godot is the fact that the
  30. whole scene system is *optional*. While it is not possible to compile it out, it
  31. can be completely bypassed.
  32. At the core, Godot uses the concept of Servers. They are low-level APIs to
  33. control rendering, physics, sound, etc. The scene system is built on top of them
  34. and uses them directly. The most common servers are:
  35. * :ref:`class_RenderingServer`: Handles everything related to graphics.
  36. * :ref:`class_PhysicsServer3D`: Handles everything related to 3D physics.
  37. * :ref:`class_PhysicsServer2D`: Handles everything related to 2D physics.
  38. * :ref:`class_AudioServer`: Handles everything related to audio.
  39. Explore their APIs, and you will realize that all the functions provided are
  40. low-level implementations of everything Godot allows you to do using nodes.
  41. RIDs
  42. ----
  43. The key to using servers is understanding Resource ID (:ref:`RID <class_RID>`)
  44. objects. These are opaque handles to the server implementation. They are
  45. allocated and freed manually. Almost every function in the servers requires RIDs
  46. to access the actual resource.
  47. Most Godot nodes and resources contain these RIDs from the servers internally,
  48. and they can be obtained with different functions. In fact, anything that
  49. inherits :ref:`Resource <class_Resource>` can be directly casted to an RID. Not
  50. all resources contain an RID, though: in such cases, the RID will be empty. The
  51. resource can then be passed to server APIs as an RID.
  52. .. warning::
  53. Resources are reference-counted (see :ref:`RefCounted <class_RefCounted>`),
  54. and references to a resource's RID are *not* counted when determining whether
  55. the resource is still in use. Make sure to **keep a reference** to the resource
  56. outside the server. Otherwise, both the resource and its RID will be erased.
  57. For nodes, there are many functions available:
  58. - For CanvasItem, the :ref:`CanvasItem.get_canvas_item() <class_CanvasItem_method_get_canvas_item>`
  59. method will return the canvas item RID in the server.
  60. - For CanvasLayer, the :ref:`CanvasLayer.get_canvas() <class_CanvasLayer_method_get_canvas>`
  61. method will return the canvas RID in the server.
  62. - For Viewport, the :ref:`Viewport.get_viewport_rid() <class_Viewport_method_get_viewport_rid>`
  63. method will return the viewport RID in the server.
  64. - For 2D, the :ref:`class_World2D` resource (obtainable in the :ref:`class_Viewport`
  65. and :ref:`CanvasItem <class_CanvasItem>` nodes)
  66. contains functions to get the *RenderingServer Canvas*, and the *PhysicsServer2D Space*. This
  67. allows creating 2D objects directly with the server API and using them.
  68. - For 3D, the :ref:`class_World3D` resource (obtainable in the :ref:`class_Viewport`
  69. and :ref:`class_Node3D` nodes)
  70. contains functions to get the *RenderingServer Scenario*, and the *PhysicsServer Space*. This
  71. allows creating 3D objects directly with the server API and using them.
  72. - The :ref:`class_VisualInstance3D` class, allows getting the scenario *instance* and
  73. *instance base* via the :ref:`VisualInstance3D.get_instance() <class_VisualInstance3D_method_get_instance>`
  74. and :ref:`VisualInstance3D.get_base() <class_VisualInstance3D_method_get_base>` respectively.
  75. Try exploring the nodes and resources you are familiar with and find the functions to obtain the server *RIDs*.
  76. It is not advised to control RIDs from objects that already have a node associated. Instead, server
  77. functions should always be used for creating and controlling new ones and interacting with the existing ones.
  78. Creating a sprite
  79. -----------------
  80. This is an example of how to create a sprite from code and move it using the low-level
  81. :ref:`class_CanvasItem` API.
  82. .. note::
  83. When creating canvas items using the RenderingServer, you should reset physics
  84. interpolation on the first frame using
  85. :ref:`RenderingServer.canvas_item_reset_physics_interpolation() <class_RenderingServer_method_canvas_item_reset_physics_interpolation>`.
  86. This ensures proper synchronization between the rendering and physics systems.
  87. If this is not done, the canvas item may appear to teleport in when the
  88. scene is loaded, rather than appearing directly at its intended location.
  89. .. tabs::
  90. .. code-tab:: gdscript GDScript
  91. extends Node2D
  92. # RenderingServer expects references to be kept around.
  93. var texture
  94. func _ready():
  95. # Create a canvas item, child of this node.
  96. var ci_rid = RenderingServer.canvas_item_create()
  97. # Make this node the parent.
  98. RenderingServer.canvas_item_set_parent(ci_rid, get_canvas_item())
  99. # Draw a texture on it.
  100. # Remember to keep this reference.
  101. texture = load("res://my_texture.png")
  102. # Add it, centered.
  103. RenderingServer.canvas_item_add_texture_rect(ci_rid, Rect2(-texture.get_size() / 2, texture.get_size()), texture)
  104. # Add the item, rotated 45 degrees and translated.
  105. var xform = Transform2D().rotated(deg_to_rad(45)).translated(Vector2(20, 30))
  106. RenderingServer.canvas_item_set_transform(ci_rid, xform)
  107. # Reset physics interpolation for this item.
  108. RenderingServer.canvas_item_reset_physics_interpolation(ci_rid)
  109. .. code-tab:: csharp
  110. public partial class MyNode2D : Node2D
  111. {
  112. // RenderingServer expects references to be kept around.
  113. private Texture2D _texture;
  114. public override void _Ready()
  115. {
  116. // Create a canvas item, child of this node.
  117. Rid ciRid = RenderingServer.CanvasItemCreate();
  118. // Make this node the parent.
  119. RenderingServer.CanvasItemSetParent(ciRid, GetCanvasItem());
  120. // Draw a texture on it.
  121. // Remember to keep this reference.
  122. _texture = ResourceLoader.Load<Texture2D>("res://my_texture.png");
  123. // Add it, centered.
  124. RenderingServer.CanvasItemAddTextureRect(ciRid, new Rect2(-_texture.GetSize() / 2, _texture.GetSize()), _texture.GetRid());
  125. // Add the item, rotated 45 degrees and translated.
  126. Transform2D xform = Transform2D.Identity.Rotated(Mathf.DegToRad(45)).Translated(new Vector2(20, 30));
  127. RenderingServer.CanvasItemSetTransform(ciRid, xform);
  128. // Reset physics interpolation for this item.
  129. RenderingServer.CanvasItemResetPhysicsInterpolation(ciRid);
  130. }
  131. }
  132. The Canvas Item API in the server allows you to add draw primitives to it. Once
  133. added, they can't be modified. The Item needs to be cleared and the primitives
  134. re-added. This is not the case for setting the transform, which can be done as
  135. many times as desired.
  136. Primitives are cleared this way:
  137. .. tabs::
  138. .. code-tab:: gdscript GDScript
  139. RenderingServer.canvas_item_clear(ci_rid)
  140. .. code-tab:: csharp
  141. RenderingServer.CanvasItemClear(ciRid);
  142. Instantiating a Mesh into 3D space
  143. ----------------------------------
  144. The 3D APIs are different from the 2D ones, so the instantiation API must be used.
  145. .. tabs::
  146. .. code-tab:: gdscript GDScript
  147. extends Node3D
  148. # RenderingServer expects references to be kept around.
  149. var mesh
  150. func _ready():
  151. # Create a visual instance (for 3D).
  152. var instance = RenderingServer.instance_create()
  153. # Set the scenario from the world. This ensures it
  154. # appears with the same objects as the scene.
  155. var scenario = get_world_3d().scenario
  156. RenderingServer.instance_set_scenario(instance, scenario)
  157. # Add a mesh to it.
  158. # Remember to keep this reference.
  159. mesh = load("res://my_mesh.obj")
  160. RenderingServer.instance_set_base(instance, mesh)
  161. # Move the mesh around.
  162. var xform = Transform3D(Basis(), Vector3(2, 3, 0))
  163. RenderingServer.instance_set_transform(instance, xform)
  164. .. code-tab:: csharp
  165. public partial class MyNode3D : Node3D
  166. {
  167. // RenderingServer expects references to be kept around.
  168. private Mesh _mesh;
  169. public override void _Ready()
  170. {
  171. // Create a visual instance (for 3D).
  172. Rid instance = RenderingServer.InstanceCreate();
  173. // Set the scenario from the world. This ensures it
  174. // appears with the same objects as the scene.
  175. Rid scenario = GetWorld3D().Scenario;
  176. RenderingServer.InstanceSetScenario(instance, scenario);
  177. // Add a mesh to it.
  178. // Remember to keep this reference.
  179. _mesh = ResourceLoader.Load<Mesh>("res://my_mesh.obj");
  180. RenderingServer.InstanceSetBase(instance, _mesh.GetRid());
  181. // Move the mesh around.
  182. Transform3D xform = new Transform3D(Basis.Identity, new Vector3(2, 3, 0));
  183. RenderingServer.InstanceSetTransform(instance, xform);
  184. }
  185. }
  186. Creating a 2D RigidBody and moving a sprite with it
  187. ---------------------------------------------------
  188. This creates a :ref:`class_RigidBody2D` using the :ref:`class_PhysicsServer2D` API,
  189. and moves a :ref:`class_CanvasItem` when the body moves.
  190. .. tabs::
  191. .. code-tab:: gdscript GDScript
  192. # PhysicsServer2D expects references to be kept around.
  193. var body
  194. var shape
  195. func _body_moved(state, index):
  196. # Created your own canvas item; use it here.
  197. # `ci_rid` from the sprite example above needs to be moved to a
  198. # member variable (instead of within `_ready()`) so it can be referenced here.
  199. RenderingServer.canvas_item_set_transform(ci_rid, state.transform)
  200. func _ready():
  201. # Create the body.
  202. body = PhysicsServer2D.body_create()
  203. PhysicsServer2D.body_set_mode(body, PhysicsServer2D.BODY_MODE_RIGID)
  204. # Add a shape.
  205. shape = PhysicsServer2D.rectangle_shape_create()
  206. # Set rectangle extents.
  207. PhysicsServer2D.shape_set_data(shape, Vector2(10, 10))
  208. # Make sure to keep the shape reference!
  209. PhysicsServer2D.body_add_shape(body, shape)
  210. # Set space, so it collides in the same space as current scene.
  211. PhysicsServer2D.body_set_space(body, get_world_2d().space)
  212. # Move initial position.
  213. PhysicsServer2D.body_set_state(body, PhysicsServer2D.BODY_STATE_TRANSFORM, Transform2D(0, Vector2(10, 20)))
  214. # Add the transform callback, when body moves
  215. # The last parameter is optional, can be used as index
  216. # if you have many bodies and a single callback.
  217. PhysicsServer2D.body_set_force_integration_callback(body, self, "_body_moved", 0)
  218. # Also create a sprite using RenderingServer here.
  219. # See the section above on creating a sprite.
  220. # ...
  221. .. code-tab:: csharp
  222. using Godot;
  223. public partial class MyNode2D : Node2D
  224. {
  225. private Rid _canvasItem;
  226. private void BodyMoved(PhysicsDirectBodyState2D state, int index)
  227. {
  228. // Created your own canvas item; use it here.
  229. // `ciRid` from the sprite example above needs to be moved to a
  230. // member variable (instead of within `_Ready()`) so it can be referenced here.
  231. RenderingServer.CanvasItemSetTransform(_canvasItem, state.Transform);
  232. }
  233. public override void _Ready()
  234. {
  235. // Create the body.
  236. var body = PhysicsServer2D.BodyCreate();
  237. PhysicsServer2D.BodySetMode(body, PhysicsServer2D.BodyMode.Rigid);
  238. // Add a shape.
  239. var shape = PhysicsServer2D.RectangleShapeCreate();
  240. // Set rectangle extents.
  241. PhysicsServer2D.ShapeSetData(shape, new Vector2(10, 10));
  242. // Make sure to keep the shape reference!
  243. PhysicsServer2D.BodyAddShape(body, shape);
  244. // Set space, so it collides in the same space as current scene.
  245. PhysicsServer2D.BodySetSpace(body, GetWorld2D().Space);
  246. // Move initial position.
  247. PhysicsServer2D.BodySetState(body, PhysicsServer2D.BodyState.Transform, new Transform2D(0, new Vector2(10, 20)));
  248. // Add the transform callback, when body moves
  249. // The last parameter is optional, can be used as index
  250. // if you have many bodies and a single callback.
  251. PhysicsServer2D.BodySetForceIntegrationCallback(body, new Callable(this, MethodName.BodyMoved), 0);
  252. // Also create a sprite using RenderingServer here.
  253. // See the section above on creating a sprite.
  254. // ...
  255. }
  256. }
  257. The 3D version should be very similar, as the 2D and 3D physics servers are
  258. identical (using :ref:`class_RigidBody3D` and :ref:`class_PhysicsServer3D`
  259. respectively).
  260. Getting data from the servers
  261. -----------------------------
  262. Try to **never** request any information from :ref:`class_RenderingServer`,
  263. :ref:`class_PhysicsServer2D`, or :ref:`class_PhysicsServer3D` by calling
  264. functions unless you know what you are doing. These servers will often run
  265. asynchronously for performance and calling any function that returns a value
  266. will stall them and force them to process anything pending until the function is
  267. actually called. This will severely decrease performance if you call them every
  268. frame (and it won't be obvious why).
  269. Because of this, most APIs in such servers are designed so it's not even possible to request information
  270. back, until it's actual data that can be saved.