portal_renderer.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /*************************************************************************/
  2. /* portal_renderer.h */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #ifndef PORTAL_RENDERER_H
  31. #define PORTAL_RENDERER_H
  32. #include "core/math/plane.h"
  33. #include "core/pooled_list.h"
  34. #include "core/vector.h"
  35. #include "portal_gameplay_monitor.h"
  36. #include "portal_pvs.h"
  37. #include "portal_rooms_bsp.h"
  38. #include "portal_tracer.h"
  39. #include "portal_types.h"
  40. class Transform;
  41. struct VSStatic {
  42. // the lifetime of statics is not strictly monitored like moving objects
  43. // therefore we store a RID which could return NULL if the object has been deleted
  44. RID instance;
  45. AABB aabb;
  46. // statics are placed in a room, but they can optionally sprawl to other rooms
  47. // if large (like lights)
  48. uint32_t source_room_id;
  49. // dynamics will request their AABB each frame
  50. // from the visual server in case they have moved.
  51. // But they will NOT update the rooms they are in...
  52. // so this works well for e.g. moving platforms, but not for objects
  53. // that will move between rooms.
  54. uint32_t dynamic;
  55. };
  56. // static / dynamic visibility notifiers.
  57. // ghost objects are not culled, but are present in rooms
  58. // and expect to receive gameplay notifications
  59. struct VSStaticGhost {
  60. ObjectID object_id;
  61. uint32_t last_tick_hit = 0;
  62. uint32_t last_room_tick_hit = 0;
  63. };
  64. class PortalRenderer {
  65. public:
  66. // use most significant bit to store whether an instance is being used in the room system
  67. // in which case, deleting such an instance should deactivate the portal system to prevent
  68. // crashes due to dangling references to instances.
  69. static const uint32_t OCCLUSION_HANDLE_ROOM_BIT = 1 << 31;
  70. static bool use_occlusion_culling;
  71. struct MovingBase {
  72. // when the rooms_and_portals_clear message is sent,
  73. // we want to remove all references to old rooms in the moving
  74. // objects, to prevent dangling references.
  75. void rooms_and_portals_clear() { destroy(); }
  76. void destroy() {
  77. _rooms.clear();
  78. room_id = -1;
  79. last_tick_hit = 0;
  80. last_gameplay_tick_hit = 0;
  81. }
  82. // the expanded aabb allows objects to move on most frames
  83. // without needing to determine a change of room
  84. AABB expanded_aabb;
  85. // exact aabb of the object should be used for culling
  86. AABB exact_aabb;
  87. // which is the primary room this moving object is in
  88. // (it may sprawl into multiple rooms)
  89. int32_t room_id;
  90. // id in the allocation pool
  91. uint32_t pool_id;
  92. uint32_t last_tick_hit = 0;
  93. uint32_t last_gameplay_tick_hit = 0;
  94. // room ids of rooms this moving object is sprawled into
  95. LocalVector<uint32_t, int32_t> _rooms;
  96. };
  97. struct Moving : public MovingBase {
  98. // either roaming or global
  99. bool global;
  100. // in _moving_lists .. not the same as pool ID (handle)
  101. uint32_t list_id;
  102. // a void pointer, but this is ultimately a pointer to a VisualServerScene::Instance
  103. // (can't have direct pointer because it is a nested class...)
  104. VSInstance *instance;
  105. #ifdef PORTAL_RENDERER_STORE_MOVING_RIDS
  106. // primarily for testing
  107. RID instance_rid;
  108. #endif
  109. };
  110. // So far the only roaming ghosts are VisibilityNotifiers.
  111. // this will always be roaming... statics and dynamics are handled separately,
  112. // and global ghosts do not get created.
  113. struct RGhost : public MovingBase {
  114. ObjectID object_id;
  115. };
  116. PortalHandle portal_create();
  117. void portal_destroy(PortalHandle p_portal);
  118. void portal_set_geometry(PortalHandle p_portal, const Vector<Vector3> &p_points, real_t p_margin);
  119. void portal_link(PortalHandle p_portal, RoomHandle p_room_from, RoomHandle p_room_to, bool p_two_way);
  120. void portal_set_active(PortalHandle p_portal, bool p_active);
  121. RoomGroupHandle roomgroup_create();
  122. void roomgroup_prepare(RoomGroupHandle p_roomgroup, ObjectID p_roomgroup_object_id);
  123. void roomgroup_destroy(RoomGroupHandle p_roomgroup);
  124. void roomgroup_add_room(RoomGroupHandle p_roomgroup, RoomHandle p_room);
  125. // Rooms
  126. RoomHandle room_create();
  127. void room_destroy(RoomHandle p_room);
  128. OcclusionHandle room_add_instance(RoomHandle p_room, RID p_instance, const AABB &p_aabb, bool p_dynamic, const Vector<Vector3> &p_object_pts);
  129. OcclusionHandle room_add_ghost(RoomHandle p_room, ObjectID p_object_id, const AABB &p_aabb);
  130. void room_set_bound(RoomHandle p_room, ObjectID p_room_object_id, const Vector<Plane> &p_convex, const AABB &p_aabb, const Vector<Vector3> &p_verts);
  131. void room_prepare(RoomHandle p_room, int32_t p_priority);
  132. void rooms_and_portals_clear();
  133. void rooms_finalize(bool p_generate_pvs, bool p_cull_using_pvs, bool p_use_secondary_pvs, bool p_use_signals, String p_pvs_filename, bool p_use_simple_pvs, bool p_log_pvs_generation);
  134. void rooms_override_camera(bool p_override, const Vector3 &p_point, const Vector<Plane> *p_convex);
  135. void rooms_set_active(bool p_active) { _active = p_active; }
  136. void rooms_set_params(int p_portal_depth_limit, real_t p_roaming_expansion_margin) {
  137. _tracer.set_depth_limit(p_portal_depth_limit);
  138. _roaming_expansion_margin = p_roaming_expansion_margin;
  139. }
  140. void rooms_set_cull_using_pvs(bool p_enable) { _cull_using_pvs = p_enable; }
  141. void rooms_update_gameplay_monitor(const Vector<Vector3> &p_camera_positions);
  142. // for use in the editor only, to allow a cheap way of turning off portals
  143. // if there has been a change, e.g. moving a room etc.
  144. void rooms_unload(String p_reason) { _ensure_unloaded(p_reason); }
  145. bool rooms_is_loaded() const { return _loaded; }
  146. // debugging
  147. void set_debug_sprawl(bool p_active) { _debug_sprawl = p_active; }
  148. // this section handles moving objects - roaming (change rooms) and globals (not in any room)
  149. OcclusionHandle instance_moving_create(VSInstance *p_instance, RID p_instance_rid, bool p_global, AABB p_aabb);
  150. void instance_moving_update(OcclusionHandle p_handle, const AABB &p_aabb, bool p_force_reinsert = false);
  151. void instance_moving_destroy(OcclusionHandle p_handle);
  152. // spatial derived roamers (non VisualInstances that still need to be portal culled, especially VisibilityNotifiers)
  153. RGhostHandle rghost_create(ObjectID p_object_id, const AABB &p_aabb);
  154. void rghost_update(RGhostHandle p_handle, const AABB &p_aabb, bool p_force_reinsert = false);
  155. void rghost_destroy(RGhostHandle p_handle);
  156. // occluders
  157. OccluderHandle occluder_create(VSOccluder::Type p_type);
  158. void occluder_update_spheres(OccluderHandle p_handle, const Vector<Plane> &p_spheres);
  159. void occluder_set_transform(OccluderHandle p_handle, const Transform &p_xform);
  160. void occluder_set_active(OccluderHandle p_handle, bool p_active);
  161. void occluder_destroy(OccluderHandle p_handle);
  162. // note that this relies on a 'frustum' type cull, from a point, and that the planes are specified as in
  163. // CameraMatrix, i.e.
  164. // order PLANE_NEAR,PLANE_FAR,PLANE_LEFT,PLANE_TOP,PLANE_RIGHT,PLANE_BOTTOM
  165. int cull_convex(const Vector3 &p_point, const Vector<Plane> &p_convex, VSInstance **p_result_array, int p_result_max, uint32_t p_mask, int32_t &r_previous_room_id_hint) {
  166. if (!_override_camera)
  167. return cull_convex_implementation(p_point, p_convex, p_result_array, p_result_max, p_mask, r_previous_room_id_hint);
  168. return cull_convex_implementation(_override_camera_pos, _override_camera_planes, p_result_array, p_result_max, p_mask, r_previous_room_id_hint);
  169. }
  170. int cull_convex_implementation(const Vector3 &p_point, const Vector<Plane> &p_convex, VSInstance **p_result_array, int p_result_max, uint32_t p_mask, int32_t &r_previous_room_id_hint);
  171. // special function for occlusion culling only that does not use portals / rooms,
  172. // but allows using occluders with the main scene
  173. int occlusion_cull(const Vector3 &p_point, const Vector<Plane> &p_convex, VSInstance **p_result_array, int p_num_results) {
  174. // inactive?
  175. if (!_occluder_pool.active_size() || !use_occlusion_culling) {
  176. return p_num_results;
  177. }
  178. return _tracer.occlusion_cull(*this, p_point, p_convex, p_result_array, p_num_results);
  179. }
  180. bool is_active() const { return _active && _loaded; }
  181. VSStatic &get_static(int p_id) { return _statics[p_id]; }
  182. const VSStatic &get_static(int p_id) const { return _statics[p_id]; }
  183. int32_t get_num_rooms() const { return _room_pool_ids.size(); }
  184. VSRoom &get_room(int p_id) { return _room_pool[_room_pool_ids[p_id]]; }
  185. const VSRoom &get_room(int p_id) const { return _room_pool[_room_pool_ids[p_id]]; }
  186. int32_t get_num_portals() const { return _portal_pool_ids.size(); }
  187. VSPortal &get_portal(int p_id) { return _portal_pool[_portal_pool_ids[p_id]]; }
  188. const VSPortal &get_portal(int p_id) const { return _portal_pool[_portal_pool_ids[p_id]]; }
  189. int32_t get_num_moving_globals() const { return _moving_list_global.size(); }
  190. const Moving &get_moving_global(uint32_t p_id) const { return _moving_pool[_moving_list_global[p_id]]; }
  191. Moving &get_pool_moving(uint32_t p_pool_id) { return _moving_pool[p_pool_id]; }
  192. const Moving &get_pool_moving(uint32_t p_pool_id) const { return _moving_pool[p_pool_id]; }
  193. RGhost &get_pool_rghost(uint32_t p_pool_id) { return _rghost_pool[p_pool_id]; }
  194. const RGhost &get_pool_rghost(uint32_t p_pool_id) const { return _rghost_pool[p_pool_id]; }
  195. const VSOccluder &get_pool_occluder(uint32_t p_pool_id) const { return _occluder_pool[p_pool_id]; }
  196. VSOccluder &get_pool_occluder(uint32_t p_pool_id) { return _occluder_pool[p_pool_id]; }
  197. const VSOccluder_Sphere &get_pool_occluder_sphere(uint32_t p_pool_id) const { return _occluder_sphere_pool[p_pool_id]; }
  198. const LocalVector<uint32_t, uint32_t> &get_occluders_active_list() const { return _occluder_pool.get_active_list(); }
  199. VSStaticGhost &get_static_ghost(uint32_t p_id) { return _static_ghosts[p_id]; }
  200. VSRoomGroup &get_roomgroup(uint32_t p_pool_id) { return _roomgroup_pool[p_pool_id]; }
  201. PVS &get_pvs() { return _pvs; }
  202. const PVS &get_pvs() const { return _pvs; }
  203. bool get_cull_using_pvs() const { return _cull_using_pvs; }
  204. private:
  205. int find_room_within(const Vector3 &p_pos, int p_previous_room_id = -1) {
  206. return _rooms_lookup_bsp.find_room_within(*this, p_pos, p_previous_room_id);
  207. }
  208. bool sprawl_static(int p_static_id, const VSStatic &p_static, int p_room_id);
  209. bool sprawl_static_geometry(int p_static_id, const VSStatic &p_static, int p_room_id, const Vector<Vector3> &p_object_pts);
  210. bool sprawl_static_ghost(int p_ghost_id, const AABB &p_aabb, int p_room_id);
  211. void _load_finalize_roaming();
  212. void sprawl_roaming(uint32_t p_mover_pool_id, MovingBase &r_moving, int p_room_id, bool p_moving_or_ghost);
  213. void _moving_remove_from_rooms(uint32_t p_moving_pool_id);
  214. void _rghost_remove_from_rooms(uint32_t p_pool_id);
  215. void _occluder_remove_from_rooms(uint32_t p_pool_id);
  216. void _ensure_unloaded(String p_reason = String());
  217. void _rooms_add_portals_to_convex_hulls();
  218. void _add_portal_to_convex_hull(LocalVector<Plane, int32_t> &p_planes, const Plane &p);
  219. void _debug_print_global_list();
  220. bool _occlusion_handle_is_in_room(OcclusionHandle p_h) const {
  221. return p_h == OCCLUSION_HANDLE_ROOM_BIT;
  222. }
  223. void _log(String p_string, int p_priority = 0);
  224. // note this is vulnerable to crashes, we must monitor for deletion of rooms
  225. LocalVector<uint32_t, int32_t> _room_pool_ids;
  226. LocalVector<uint32_t, int32_t> _portal_pool_ids;
  227. LocalVector<VSStatic, int32_t> _statics;
  228. LocalVector<VSStaticGhost, int32_t> _static_ghosts;
  229. // all rooms and portals are allocated from pools.
  230. PooledList<VSPortal> _portal_pool;
  231. PooledList<VSRoom> _room_pool;
  232. PooledList<VSRoomGroup> _roomgroup_pool;
  233. // moving objects, global and roaming
  234. PooledList<Moving> _moving_pool;
  235. TrackedPooledList<RGhost> _rghost_pool;
  236. LocalVector<uint32_t, int32_t> _moving_list_global;
  237. LocalVector<uint32_t, int32_t> _moving_list_roaming;
  238. // occluders
  239. TrackedPooledList<VSOccluder> _occluder_pool;
  240. TrackedPooledList<VSOccluder_Sphere> _occluder_sphere_pool;
  241. PVS _pvs;
  242. bool _active = true;
  243. bool _loaded = false;
  244. bool _debug_sprawl = false;
  245. // if the pvs is generated, we can either cull using dynamic portals or PVS
  246. bool _cull_using_pvs = false;
  247. PortalTracer _tracer;
  248. PortalTracer::TraceResult _trace_results;
  249. PortalRoomsBSP _rooms_lookup_bsp;
  250. PortalGameplayMonitor _gameplay_monitor;
  251. // when moving roaming objects, we expand their bound
  252. // to prevent too many updates.
  253. real_t _roaming_expansion_margin = 1.0;
  254. // a bitfield to indicate which rooms have been
  255. // visited already in sprawling, to prevent visiting rooms multiple times
  256. BitFieldDynamic _bitfield_rooms;
  257. bool _override_camera = false;
  258. Vector3 _override_camera_pos;
  259. LocalVector<Plane, int32_t> _override_camera_planes;
  260. public:
  261. static String _rid_to_string(RID p_rid);
  262. static String _addr_to_string(const void *p_addr);
  263. void occluder_ensure_up_to_date_sphere(VSOccluder &r_occluder);
  264. void occluder_refresh_room_within(uint32_t p_occluder_pool_id);
  265. };
  266. inline void PortalRenderer::occluder_ensure_up_to_date_sphere(VSOccluder &r_occluder) {
  267. if (!r_occluder.dirty) {
  268. return;
  269. }
  270. r_occluder.dirty = false;
  271. const Transform &tr = r_occluder.xform;
  272. Vector3 scale3 = tr.basis.get_scale_abs();
  273. real_t scale = (scale3.x + scale3.y + scale3.z) / 3.0;
  274. // update the AABB
  275. Vector3 bb_min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
  276. Vector3 bb_max = Vector3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
  277. // transform spheres
  278. for (int n = 0; n < r_occluder.list_ids.size(); n++) {
  279. uint32_t pool_id = r_occluder.list_ids[n];
  280. VSOccluder_Sphere &osphere = _occluder_sphere_pool[pool_id];
  281. // transform position and radius
  282. osphere.world.pos = tr.xform(osphere.local.pos);
  283. osphere.world.radius = osphere.local.radius * scale;
  284. Vector3 bradius = Vector3(osphere.world.radius, osphere.world.radius, osphere.world.radius);
  285. Vector3 bmin = osphere.world.pos - bradius;
  286. Vector3 bmax = osphere.world.pos + bradius;
  287. bb_min.x = MIN(bb_min.x, bmin.x);
  288. bb_min.y = MIN(bb_min.y, bmin.y);
  289. bb_min.z = MIN(bb_min.z, bmin.z);
  290. bb_max.x = MAX(bb_max.x, bmax.x);
  291. bb_max.y = MAX(bb_max.y, bmax.y);
  292. bb_max.z = MAX(bb_max.z, bmax.z);
  293. }
  294. r_occluder.aabb.position = bb_min;
  295. r_occluder.aabb.size = bb_max - bb_min;
  296. }
  297. #endif