diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 9b9644093fe..300108ff779 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3702,7 +3702,7 @@ - + Represents the size of the [enum InstanceType] enum. diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 96d63b27ad4..292be34a0de 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -179,13 +179,6 @@ - - - - - Forces update of the 2D and 3D worlds. - - diff --git a/doc/classes/VisibilityEnabler3D.xml b/doc/classes/VisibilityEnabler3D.xml index d78ebb55f29..4614859a448 100644 --- a/doc/classes/VisibilityEnabler3D.xml +++ b/doc/classes/VisibilityEnabler3D.xml @@ -12,44 +12,19 @@ - - - - - - - Returns whether the enabler identified by given [enum Enabler] constant is active. - - - - - - - - - - - Sets active state of the enabler identified by given [enum Enabler] constant. - - - - If [code]true[/code], [RigidBody3D] nodes will be paused. + - - If [code]true[/code], [AnimationPlayer] nodes will be paused. + - - This enabler will pause [AnimationPlayer] nodes. + - - This enabler will freeze [RigidBody3D] nodes. + - - Represents the size of the [enum Enabler] enum. + diff --git a/doc/classes/VisibilityNotifier3D.xml b/doc/classes/VisibilityNotifier3D.xml index e5d3116612f..bd6c03ea20a 100644 --- a/doc/classes/VisibilityNotifier3D.xml +++ b/doc/classes/VisibilityNotifier3D.xml @@ -1,5 +1,5 @@ - + Detects approximately when the node is visible on screen. @@ -26,20 +26,6 @@ - - - - - Emitted when the VisibilityNotifier3D enters a [Camera3D]'s view. - - - - - - - Emitted when the VisibilityNotifier3D exits a [Camera3D]'s view. - - Emitted when the VisibilityNotifier3D enters the screen. diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index cad4330c174..96400430317 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -404,10 +404,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { break; } - List cameras; - world_3d->get_camera_list(&cameras); - - for (List::Element *E = cameras.front(); E; E = E->next()) { + for (const Set::Element *E = world_3d->get_cameras().front(); E; E = E->next()) { Camera3D *camera = E->get(); Viewport *vp = camera->get_viewport(); if (!vp->is_audio_listener()) { diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 6b8851b4f82..62bbebe6e76 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -93,10 +93,6 @@ void Camera3D::_update_camera() { } get_viewport()->_camera_transform_changed_notify(); - - if (get_world_3d().is_valid()) { - get_world_3d()->_update_camera(this); - } } void Camera3D::_notification(int p_what) { diff --git a/scene/3d/visibility_notifier_3d.cpp b/scene/3d/visibility_notifier_3d.cpp index b230cb2fd7d..39b17d195b5 100644 --- a/scene/3d/visibility_notifier_3d.cpp +++ b/scene/3d/visibility_notifier_3d.cpp @@ -36,27 +36,23 @@ #include "scene/animation/animation_player.h" #include "scene/scene_string_names.h" -void VisibilityNotifier3D::_enter_camera(Camera3D *p_camera) { - ERR_FAIL_COND(cameras.has(p_camera)); - cameras.insert(p_camera); - if (cameras.size() == 1) { - emit_signal(SceneStringNames::get_singleton()->screen_entered); - _screen_enter(); +void VisibilityNotifier3D::_visibility_enter() { + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { + return; } - emit_signal(SceneStringNames::get_singleton()->camera_entered, p_camera); + on_screen = true; + emit_signal(SceneStringNames::get_singleton()->screen_entered); + _screen_enter(); } - -void VisibilityNotifier3D::_exit_camera(Camera3D *p_camera) { - ERR_FAIL_COND(!cameras.has(p_camera)); - cameras.erase(p_camera); - - emit_signal(SceneStringNames::get_singleton()->camera_exited, p_camera); - if (cameras.size() == 0) { - emit_signal(SceneStringNames::get_singleton()->screen_exited); - - _screen_exit(); +void VisibilityNotifier3D::_visibility_exit() { + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { + return; } + + on_screen = false; + emit_signal(SceneStringNames::get_singleton()->screen_exited); + _screen_exit(); } void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) { @@ -65,9 +61,7 @@ void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) { } aabb = p_aabb; - if (is_inside_world()) { - get_world_3d()->_update_notifier(this, get_global_transform().xform(aabb)); - } + RS::get_singleton()->visibility_notifier_set_aabb(get_base(), aabb); update_gizmo(); } @@ -76,178 +70,129 @@ AABB VisibilityNotifier3D::get_aabb() const { return aabb; } -void VisibilityNotifier3D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_WORLD: { - world = get_world_3d(); - ERR_FAIL_COND(!world.is_valid()); - world->_register_notifier(this, get_global_transform().xform(aabb)); - } break; - case NOTIFICATION_TRANSFORM_CHANGED: { - world->_update_notifier(this, get_global_transform().xform(aabb)); - } break; - case NOTIFICATION_EXIT_WORLD: { - ERR_FAIL_COND(!world.is_valid()); - world->_remove_notifier(this); - } break; - } +bool VisibilityNotifier3D::is_on_screen() const { + return on_screen; } -bool VisibilityNotifier3D::is_on_screen() const { - return cameras.size() != 0; +void VisibilityNotifier3D::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_EXIT_TREE) { + on_screen = false; + } } void VisibilityNotifier3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_aabb", "rect"), &VisibilityNotifier3D::set_aabb); - ClassDB::bind_method(D_METHOD("get_aabb"), &VisibilityNotifier3D::get_aabb); ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibilityNotifier3D::is_on_screen); ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb"), "set_aabb", "get_aabb"); - ADD_SIGNAL(MethodInfo("camera_entered", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"))); - ADD_SIGNAL(MethodInfo("camera_exited", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"))); ADD_SIGNAL(MethodInfo("screen_entered")); ADD_SIGNAL(MethodInfo("screen_exited")); } +Vector VisibilityNotifier3D::get_faces(uint32_t p_usage_flags) const { + return Vector(); +} + VisibilityNotifier3D::VisibilityNotifier3D() { - set_notify_transform(true); + RID notifier = RS::get_singleton()->visibility_notifier_create(); + RS::get_singleton()->visibility_notifier_set_aabb(notifier, aabb); + RS::get_singleton()->visibility_notifier_set_callbacks(notifier, callable_mp(this, &VisibilityNotifier3D::_visibility_enter), callable_mp(this, &VisibilityNotifier3D::_visibility_exit)); + set_base(notifier); } ////////////////////////////////////// void VisibilityEnabler3D::_screen_enter() { - for (Map::Element *E = nodes.front(); E; E = E->next()) { - _change_node_state(E->key(), true); - } - - visible = true; + _update_enable_mode(true); } void VisibilityEnabler3D::_screen_exit() { - for (Map::Element *E = nodes.front(); E; E = E->next()) { - _change_node_state(E->key(), false); - } - - visible = false; + _update_enable_mode(false); } -void VisibilityEnabler3D::_find_nodes(Node *p_node) { - bool add = false; - Variant meta; - - { - RigidBody3D *rb = Object::cast_to(p_node); - if (rb && ((rb->get_mode() == RigidBody3D::MODE_DYNAMIC || rb->get_mode() == RigidBody3D::MODE_DYNAMIC_LOCKED))) { - add = true; - meta = rb->get_mode(); - } - } - - { - AnimationPlayer *ap = Object::cast_to(p_node); - if (ap) { - add = true; - } - } - - if (add) { - p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler3D::_node_removed), varray(p_node), CONNECT_ONESHOT); - nodes[p_node] = meta; - _change_node_state(p_node, false); - } - - for (int i = 0; i < p_node->get_child_count(); i++) { - Node *c = p_node->get_child(i); - if (c->get_filename() != String()) { - continue; //skip, instance - } - - _find_nodes(c); +void VisibilityEnabler3D::set_enable_mode(EnableMode p_mode) { + enable_mode = p_mode; + if (is_inside_tree()) { + _update_enable_mode(is_on_screen()); } } +VisibilityEnabler3D::EnableMode VisibilityEnabler3D::get_enable_mode() { + return enable_mode; +} +void VisibilityEnabler3D::set_enable_node_path(NodePath p_path) { + if (enable_node_path == p_path) { + return; + } + enable_node_path = p_path; + if (is_inside_tree()) { + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + _update_enable_mode(is_on_screen()); + } + } +} +NodePath VisibilityEnabler3D::get_enable_node_path() { + return enable_node_path; +} + +void VisibilityEnabler3D::_update_enable_mode(bool p_enable) { + Node *node = static_cast(ObjectDB::get_instance(node_id)); + if (node) { + if (p_enable) { + switch (enable_mode) { + case ENABLE_MODE_INHERIT: { + node->set_process_mode(PROCESS_MODE_INHERIT); + } break; + case ENABLE_MODE_ALWAYS: { + node->set_process_mode(PROCESS_MODE_ALWAYS); + } break; + case ENABLE_MODE_WHEN_PAUSED: { + node->set_process_mode(PROCESS_MODE_WHEN_PAUSED); + } break; + } + } else { + node->set_process_mode(PROCESS_MODE_DISABLED); + } + } +} void VisibilityEnabler3D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { if (Engine::get_singleton()->is_editor_hint()) { return; } - Node *from = this; - //find where current scene starts - while (from->get_parent() && from->get_filename() == String()) { - from = from->get_parent(); + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + node->set_process_mode(PROCESS_MODE_DISABLED); } - - _find_nodes(from); } if (p_what == NOTIFICATION_EXIT_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } - - for (Map::Element *E = nodes.front(); E; E = E->next()) { - if (!visible) { - _change_node_state(E->key(), true); - } - E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler3D::_node_removed)); - } - - nodes.clear(); + node_id = ObjectID(); } } -void VisibilityEnabler3D::_change_node_state(Node *p_node, bool p_enabled) { - ERR_FAIL_COND(!nodes.has(p_node)); - - if (enabler[ENABLER_FREEZE_BODIES]) { - RigidBody3D *rb = Object::cast_to(p_node); - if (rb) { - rb->set_sleeping(!p_enabled); - } - } - - if (enabler[ENABLER_PAUSE_ANIMATIONS]) { - AnimationPlayer *ap = Object::cast_to(p_node); - - if (ap) { - ap->set_active(p_enabled); - } - } -} - -void VisibilityEnabler3D::_node_removed(Node *p_node) { - if (!visible) { - _change_node_state(p_node, true); - } - nodes.erase(p_node); -} - void VisibilityEnabler3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler3D::set_enabler); - ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler3D::is_enabler_enabled); + ClassDB::bind_method(D_METHOD("set_enable_mode", "mode"), &VisibilityEnabler3D::set_enable_mode); + ClassDB::bind_method(D_METHOD("get_enable_mode"), &VisibilityEnabler3D::get_enable_mode); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animations"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATIONS); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "freeze_bodies"), "set_enabler", "is_enabler_enabled", ENABLER_FREEZE_BODIES); + ClassDB::bind_method(D_METHOD("set_enable_node_path", "path"), &VisibilityEnabler3D::set_enable_node_path); + ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibilityEnabler3D::get_enable_node_path); - BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS); - BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES); - BIND_ENUM_CONSTANT(ENABLER_MAX); -} + ADD_GROUP("Enabling", "enable_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path"); -void VisibilityEnabler3D::set_enabler(Enabler p_enabler, bool p_enable) { - ERR_FAIL_INDEX(p_enabler, ENABLER_MAX); - enabler[p_enabler] = p_enable; -} - -bool VisibilityEnabler3D::is_enabler_enabled(Enabler p_enabler) const { - ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false); - return enabler[p_enabler]; + BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT); + BIND_ENUM_CONSTANT(ENABLE_MODE_ALWAYS); + BIND_ENUM_CONSTANT(ENABLE_MODE_WHEN_PAUSED); } VisibilityEnabler3D::VisibilityEnabler3D() { - for (int i = 0; i < ENABLER_MAX; i++) { - enabler[i] = true; - } } diff --git a/scene/3d/visibility_notifier_3d.h b/scene/3d/visibility_notifier_3d.h index 9f7705067f4..878c97e35ef 100644 --- a/scene/3d/visibility_notifier_3d.h +++ b/scene/3d/visibility_notifier_3d.h @@ -31,34 +31,34 @@ #ifndef VISIBILITY_NOTIFIER_H #define VISIBILITY_NOTIFIER_H -#include "scene/3d/node_3d.h" +#include "scene/3d/visual_instance_3d.h" class World3D; class Camera3D; -class VisibilityNotifier3D : public Node3D { - GDCLASS(VisibilityNotifier3D, Node3D); - - Ref world; - Set cameras; +class VisibilityNotifier3D : public VisualInstance3D { + GDCLASS(VisibilityNotifier3D, VisualInstance3D); AABB aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2)); +private: + bool on_screen = false; + void _visibility_enter(); + void _visibility_exit(); + protected: virtual void _screen_enter() {} virtual void _screen_exit() {} void _notification(int p_what); static void _bind_methods(); - friend struct SpatialIndexer; - - void _enter_camera(Camera3D *p_camera); - void _exit_camera(Camera3D *p_camera); public: void set_aabb(const AABB &p_aabb); - AABB get_aabb() const; + virtual AABB get_aabb() const override; bool is_on_screen() const; + virtual Vector get_faces(uint32_t p_usage_flags) const override; + VisibilityNotifier3D(); }; @@ -66,36 +66,35 @@ class VisibilityEnabler3D : public VisibilityNotifier3D { GDCLASS(VisibilityEnabler3D, VisibilityNotifier3D); public: - enum Enabler { - ENABLER_PAUSE_ANIMATIONS, - ENABLER_FREEZE_BODIES, - ENABLER_MAX + enum EnableMode { + ENABLE_MODE_INHERIT, + ENABLE_MODE_ALWAYS, + ENABLE_MODE_WHEN_PAUSED, }; protected: + ObjectID node_id; virtual void _screen_enter() override; virtual void _screen_exit() override; - bool visible = false; - - void _find_nodes(Node *p_node); - - Map nodes; - void _node_removed(Node *p_node); - bool enabler[ENABLER_MAX]; - - void _change_node_state(Node *p_node, bool p_enabled); + EnableMode enable_mode = ENABLE_MODE_INHERIT; + NodePath enable_node_path = NodePath(".."); void _notification(int p_what); static void _bind_methods(); + void _update_enable_mode(bool p_enable); + public: - void set_enabler(Enabler p_enabler, bool p_enable); - bool is_enabler_enabled(Enabler p_enabler) const; + void set_enable_mode(EnableMode p_mode); + EnableMode get_enable_mode(); + + void set_enable_node_path(NodePath p_path); + NodePath get_enable_node_path(); VisibilityEnabler3D(); }; -VARIANT_ENUM_CAST(VisibilityEnabler3D::Enabler); +VARIANT_ENUM_CAST(VisibilityEnabler3D::EnableMode); #endif // VISIBILITY_NOTIFIER_H diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index e4ba93feec8..f588e000f9d 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -413,7 +413,6 @@ bool SceneTree::physics_process(float p_time) { _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack flush_transform_notifications(); - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); root_lock--; _flush_delete_queue(); @@ -445,7 +444,6 @@ bool SceneTree::process(float p_time) { _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); root_lock--; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 425fbf0d6a2..59ec0e63458 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -183,14 +183,6 @@ public: ///////////////////////////////////// -void Viewport::update_worlds() { - if (!is_inside_tree()) { - return; - } - - find_world_3d()->_update(get_tree()->get_frame()); -} - void Viewport::_collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) { Transform3D object_transform = p_object->get_global_transform(); Transform3D camera_transform = p_camera->get_global_transform(); @@ -3513,8 +3505,6 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("input", "event", "in_local_coords"), &Viewport::input, DEFVAL(false)); ClassDB::bind_method(D_METHOD("unhandled_input", "event", "in_local_coords"), &Viewport::unhandled_input, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("update_worlds"), &Viewport::update_worlds); - ClassDB::bind_method(D_METHOD("set_use_own_world_3d", "enable"), &Viewport::set_use_own_world_3d); ClassDB::bind_method(D_METHOD("is_using_own_world_3d"), &Viewport::is_using_own_world_3d); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 2d7f5101c29..d905e44a828 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -397,8 +397,6 @@ private: void _gui_input_event(Ref p_event); - void update_worlds(); - _FORCE_INLINE_ Transform2D _get_input_pre_xform() const; Ref _make_input_local(const Ref &ev); diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index e811cbf57ae..a85bd8fdbab 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -37,206 +37,15 @@ #include "scene/scene_string_names.h" #include "servers/navigation_server_3d.h" -struct SpatialIndexer { - Octree octree; - - struct NotifierData { - AABB aabb; - OctreeElementID id; - }; - - Map notifiers; - struct CameraData { - Map notifiers; - }; - - Map cameras; - - enum { - VISIBILITY_CULL_MAX = 32768 - }; - - Vector cull; - - bool changed; - uint64_t pass; - uint64_t last_frame; - - void _notifier_add(VisibilityNotifier3D *p_notifier, const AABB &p_rect) { - ERR_FAIL_COND(notifiers.has(p_notifier)); - notifiers[p_notifier].aabb = p_rect; - notifiers[p_notifier].id = octree.create(p_notifier, p_rect); - changed = true; - } - - void _notifier_update(VisibilityNotifier3D *p_notifier, const AABB &p_rect) { - Map::Element *E = notifiers.find(p_notifier); - ERR_FAIL_COND(!E); - if (E->get().aabb == p_rect) { - return; - } - - E->get().aabb = p_rect; - octree.move(E->get().id, E->get().aabb); - changed = true; - } - - void _notifier_remove(VisibilityNotifier3D *p_notifier) { - Map::Element *E = notifiers.find(p_notifier); - ERR_FAIL_COND(!E); - - octree.erase(E->get().id); - notifiers.erase(p_notifier); - - List removed; - for (Map::Element *F = cameras.front(); F; F = F->next()) { - Map::Element *G = F->get().notifiers.find(p_notifier); - - if (G) { - F->get().notifiers.erase(G); - removed.push_back(F->key()); - } - } - - while (!removed.is_empty()) { - p_notifier->_exit_camera(removed.front()->get()); - removed.pop_front(); - } - - changed = true; - } - - void _add_camera(Camera3D *p_camera) { - ERR_FAIL_COND(cameras.has(p_camera)); - CameraData vd; - cameras[p_camera] = vd; - changed = true; - } - - void _update_camera(Camera3D *p_camera) { - Map::Element *E = cameras.find(p_camera); - ERR_FAIL_COND(!E); - changed = true; - } - - void _remove_camera(Camera3D *p_camera) { - ERR_FAIL_COND(!cameras.has(p_camera)); - List removed; - for (Map::Element *E = cameras[p_camera].notifiers.front(); E; E = E->next()) { - removed.push_back(E->key()); - } - - while (!removed.is_empty()) { - removed.front()->get()->_exit_camera(p_camera); - removed.pop_front(); - } - - cameras.erase(p_camera); - } - - void _update(uint64_t p_frame) { - if (p_frame == last_frame) { - return; - } - last_frame = p_frame; - - if (!changed) { - return; - } - - for (Map::Element *E = cameras.front(); E; E = E->next()) { - pass++; - - Camera3D *c = E->key(); - - Vector planes = c->get_frustum(); - - int culled = octree.cull_convex(planes, cull.ptrw(), cull.size()); - - VisibilityNotifier3D **ptr = cull.ptrw(); - - List added; - List removed; - - for (int i = 0; i < culled; i++) { - //notifiers in frustum - - Map::Element *H = E->get().notifiers.find(ptr[i]); - if (!H) { - E->get().notifiers.insert(ptr[i], pass); - added.push_back(ptr[i]); - } else { - H->get() = pass; - } - } - - for (Map::Element *F = E->get().notifiers.front(); F; F = F->next()) { - if (F->get() != pass) { - removed.push_back(F->key()); - } - } - - while (!added.is_empty()) { - added.front()->get()->_enter_camera(E->key()); - added.pop_front(); - } - - while (!removed.is_empty()) { - E->get().notifiers.erase(removed.front()->get()); - removed.front()->get()->_exit_camera(E->key()); - removed.pop_front(); - } - } - changed = false; - } - - SpatialIndexer() { - pass = 0; - last_frame = 0; - changed = false; - cull.resize(VISIBILITY_CULL_MAX); - } -}; - void World3D::_register_camera(Camera3D *p_camera) { #ifndef _3D_DISABLED - indexer->_add_camera(p_camera); -#endif -} - -void World3D::_update_camera(Camera3D *p_camera) { -#ifndef _3D_DISABLED - indexer->_update_camera(p_camera); + cameras.insert(p_camera); #endif } void World3D::_remove_camera(Camera3D *p_camera) { #ifndef _3D_DISABLED - indexer->_remove_camera(p_camera); -#endif -} - -void World3D::_register_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect) { -#ifndef _3D_DISABLED - indexer->_notifier_add(p_notifier, p_rect); -#endif -} - -void World3D::_update_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect) { -#ifndef _3D_DISABLED - indexer->_notifier_update(p_notifier, p_rect); -#endif -} - -void World3D::_remove_notifier(VisibilityNotifier3D *p_notifier) { -#ifndef _3D_DISABLED - indexer->_notifier_remove(p_notifier); -#endif -} - -void World3D::_update(uint64_t p_frame) { -#ifndef _3D_DISABLED - indexer->_update(p_frame); + cameras.erase(p_camera); #endif } @@ -307,12 +116,6 @@ PhysicsDirectSpaceState3D *World3D::get_direct_space_state() { return PhysicsServer3D::get_singleton()->space_get_direct_state(space); } -void World3D::get_camera_list(List *r_cameras) { - for (Map::Element *E = indexer->cameras.front(); E; E = E->next()) { - r_cameras->push_back(E->key()); - } -} - void World3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_space"), &World3D::get_space); ClassDB::bind_method(D_METHOD("get_navigation_map"), &World3D::get_navigation_map); @@ -349,20 +152,10 @@ World3D::World3D() { NavigationServer3D::get_singleton()->map_set_active(navigation_map, true); NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3)); NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.3)); - -#ifdef _3D_DISABLED - indexer = nullptr; -#else - indexer = memnew(SpatialIndexer); -#endif } World3D::~World3D() { PhysicsServer3D::get_singleton()->free(space); RenderingServer::get_singleton()->free(scenario); NavigationServer3D::get_singleton()->free(navigation_map); - -#ifndef _3D_DISABLED - memdelete(indexer); -#endif } diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h index 4e2717a2bbb..da5ed486b0a 100644 --- a/scene/resources/world_3d.h +++ b/scene/resources/world_3d.h @@ -48,27 +48,21 @@ private: RID space; RID navigation_map; RID scenario; - SpatialIndexer *indexer; + Ref environment; Ref fallback_environment; Ref camera_effects; + Set cameras; + protected: static void _bind_methods(); friend class Camera3D; - friend class VisibilityNotifier3D; void _register_camera(Camera3D *p_camera); - void _update_camera(Camera3D *p_camera); void _remove_camera(Camera3D *p_camera); - void _register_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect); - void _update_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect); - void _remove_notifier(VisibilityNotifier3D *p_notifier); - friend class Viewport; - void _update(uint64_t p_frame); - public: RID get_space() const; RID get_navigation_map() const; @@ -83,7 +77,7 @@ public: void set_camera_effects(const Ref &p_camera_effects); Ref get_camera_effects() const; - void get_camera_list(List *r_cameras); + _FORCE_INLINE_ const Set &get_cameras() const { return cameras; } PhysicsDirectSpaceState3D *get_direct_space_state(); diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index b44088e822a..d4c25b62534 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -621,9 +621,18 @@ public: bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; } RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override { return RID(); } - RID particles_collision_instance_create(RID p_collision) override { return RID(); }; - void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override{}; - void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override{}; + RID particles_collision_instance_create(RID p_collision) override { return RID(); } + void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override {} + void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override {} + + /* VISIBILITY NOTIFIER */ + virtual RID visibility_notifier_allocate() override { return RID(); } + virtual void visibility_notifier_initialize(RID p_notifier) override {} + virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override {} + virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override {} + + virtual AABB visibility_notifier_get_aabb(RID p_notifier) const override { return AABB(); } + virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) override {} /* GLOBAL VARIABLES */ diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 64be54115f0..246b5f0e4c8 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -5535,6 +5535,59 @@ void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_ pci->active = p_active; } +/* VISIBILITY NOTIFIER */ + +RID RendererStorageRD::visibility_notifier_allocate() { + return visibility_notifier_owner.allocate_rid(); +} +void RendererStorageRD::visibility_notifier_initialize(RID p_notifier) { + visibility_notifier_owner.initialize_rid(p_notifier, VisibilityNotifier()); +} +void RendererStorageRD::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + ERR_FAIL_COND(!vn); + vn->aabb = p_aabb; + vn->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); +} +void RendererStorageRD::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + ERR_FAIL_COND(!vn); + vn->enter_callback = p_enter_callbable; + vn->exit_callback = p_exit_callable; +} + +AABB RendererStorageRD::visibility_notifier_get_aabb(RID p_notifier) const { + const VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + ERR_FAIL_COND_V(!vn, AABB()); + return vn->aabb; +} +void RendererStorageRD::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + ERR_FAIL_COND(!vn); + + if (p_enter) { + if (!vn->enter_callback.is_null()) { + if (p_deferred) { + vn->enter_callback.call_deferred(nullptr, 0); + } else { + Variant r; + Callable::CallError ce; + vn->enter_callback.call(nullptr, 0, r, ce); + } + } + } else { + if (!vn->exit_callback.is_null()) { + if (p_deferred) { + vn->exit_callback.call_deferred(nullptr, 0); + } else { + Variant r; + Callable::CallError ce; + vn->exit_callback.call(nullptr, 0, r, ce); + } + } + } +} + /* SKELETON API */ RID RendererStorageRD::skeleton_allocate() { @@ -7590,6 +7643,9 @@ void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_ } else if (particles_collision_owner.owns(p_base)) { ParticlesCollision *pc = particles_collision_owner.getornull(p_base); p_instance->update_dependency(&pc->dependency); + } else if (visibility_notifier_owner.owns(p_base)) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_base); + p_instance->update_dependency(&vn->dependency); } } @@ -7628,6 +7684,9 @@ RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const { if (particles_collision_owner.owns(p_rid)) { return RS::INSTANCE_PARTICLES_COLLISION; } + if (visibility_notifier_owner.owns(p_rid)) { + return RS::INSTANCE_VISIBLITY_NOTIFIER; + } return RS::INSTANCE_NONE; } @@ -8704,6 +8763,10 @@ bool RendererStorageRD::free(RID p_rid) { } particles_collision->dependency.deleted_notify(p_rid); particles_collision_owner.free(p_rid); + } else if (visibility_notifier_owner.owns(p_rid)) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_rid); + vn->dependency.deleted_notify(p_rid); + visibility_notifier_owner.free(p_rid); } else if (particles_collision_instance_owner.owns(p_rid)) { particles_collision_instance_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 28a1044705a..ab470cb3a6a 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -947,6 +947,17 @@ private: mutable RID_Owner particles_collision_instance_owner; + /* visibility_notifier */ + + struct VisibilityNotifier { + AABB aabb; + Callable enter_callback; + Callable exit_callback; + Dependency dependency; + }; + + mutable RID_Owner visibility_notifier_owner; + /* Skeleton */ struct Skeleton { @@ -2253,6 +2264,14 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const; RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const; + virtual RID visibility_notifier_allocate(); + virtual void visibility_notifier_initialize(RID p_notifier); + virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb); + virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable); + + virtual AABB visibility_notifier_get_aabb(RID p_notifier) const; + virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred); + //used from 2D and 3D virtual RID particles_collision_instance_create(RID p_collision); virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform); diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index 3b25498ed86..d71425f465d 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -207,6 +207,7 @@ public: virtual void update() = 0; virtual void render_probes() = 0; + virtual void update_visibility_notifiers() = 0; virtual bool free(RID p_rid) = 0; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 2c66b22089e..60c7dbf3b7e 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -506,6 +506,9 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { InstanceParticlesCollisionData *collision = static_cast(instance->base_data); RSG::storage->free(collision->instance); } break; + case RS::INSTANCE_VISIBLITY_NOTIFIER: { + //none + } break; case RS::INSTANCE_REFLECTION_PROBE: { InstanceReflectionProbeData *reflection_probe = static_cast(instance->base_data); scene_render->free(reflection_probe->instance); @@ -615,6 +618,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible); instance->base_data = collision; } break; + case RS::INSTANCE_VISIBLITY_NOTIFIER: { + InstanceVisibilityNotifierData *vnd = memnew(InstanceVisibilityNotifierData); + vnd->base = p_base; + instance->base_data = vnd; + } break; case RS::INSTANCE_REFLECTION_PROBE: { InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData); reflection_probe->owner = instance; @@ -1549,6 +1557,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { case RS::INSTANCE_VOXEL_GI: { idata.instance_data_rid = static_cast(p_instance->base_data)->probe_instance.get_id(); } break; + case RS::INSTANCE_VISIBLITY_NOTIFIER: { + idata.visibility_notifier = static_cast(p_instance->base_data); + } break; default: { } } @@ -1758,6 +1769,9 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base); } break; + case RenderingServer::INSTANCE_VISIBLITY_NOTIFIER: { + new_aabb = RSG::storage->visibility_notifier_get_aabb(p_instance->base); + } break; case RenderingServer::INSTANCE_LIGHT: { new_aabb = RSG::storage->light_get_aabb(p_instance->base); @@ -2613,6 +2627,15 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } else if (base_type == RS::INSTANCE_LIGHTMAP) { cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid)); + } else if (base_type == RS::INSTANCE_VISIBLITY_NOTIFIER) { + InstanceVisibilityNotifierData *vnd = idata.visibility_notifier; + if (!vnd->list_element.in_list()) { + visible_notifier_list_lock.lock(); + visible_notifier_list.add(&vnd->list_element); + visible_notifier_list_lock.unlock(); + vnd->just_visible = true; + } + vnd->visible_in_frame = RSG::rasterizer->get_frame_number(); } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { bool keep = true; @@ -3849,6 +3872,28 @@ TypedArray RendererSceneCull::bake_render_uv2(RID p_base, const Vectorbake_render_uv2(p_base, p_material_overrides, p_image_size); } +void RendererSceneCull::update_visibility_notifiers() { + SelfList *E = visible_notifier_list.first(); + while (E) { + SelfList *N = E->next(); + + InstanceVisibilityNotifierData *visibility_notifier = E->self(); + if (visibility_notifier->just_visible) { + visibility_notifier->just_visible = false; + + RSG::storage->visibility_notifier_call(visibility_notifier->base, true, RSG::threaded); + } else { + if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) { + visible_notifier_list.remove(E); + + RSG::storage->visibility_notifier_call(visibility_notifier->base, false, RSG::threaded); + } + } + + E = N; + } +} + /*******************************/ /* Passthrough to Scene Render */ /*******************************/ diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index bdfbea95a26..d9466d8b041 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -118,6 +118,8 @@ public: virtual void occluder_initialize(RID p_occluder); virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices); + /* VISIBILITY NOTIFIER API */ + RendererSceneOcclusionCull *dummy_occlusion_culling; /* SCENARIO API */ @@ -243,6 +245,8 @@ public: } }; + struct InstanceVisibilityNotifierData; + struct InstanceData { // Store instance pointer as well as common instance processing information, // to make processing more cache friendly. @@ -271,6 +275,7 @@ public: union { uint64_t instance_data_rid; RendererSceneRender::GeometryInstance *instance_geometry; + InstanceVisibilityNotifierData *visibility_notifier; }; Instance *instance = nullptr; int32_t parent_array_index = -1; @@ -611,6 +616,18 @@ public: RID instance; }; + struct InstanceVisibilityNotifierData : public InstanceBaseData { + bool just_visible = false; + uint64_t visible_in_frame = 0; + RID base; + SelfList list_element; + InstanceVisibilityNotifierData() : + list_element(this) {} + }; + + SpinLock visible_notifier_list_lock; + SelfList::List visible_notifier_list; + struct InstanceLightData : public InstanceBaseData { RID instance; uint64_t last_version; @@ -1123,6 +1140,8 @@ public: void set_scene_render(RendererSceneRender *p_scene_render); + virtual void update_visibility_notifiers(); + RendererSceneCull(); virtual ~RendererSceneCull(); }; diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h index e6b9ac15ffc..f22c582f48f 100644 --- a/servers/rendering/renderer_storage.h +++ b/servers/rendering/renderer_storage.h @@ -557,6 +557,14 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0; + virtual RID visibility_notifier_allocate() = 0; + virtual void visibility_notifier_initialize(RID p_notifier) = 0; + virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) = 0; + virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0; + + virtual AABB visibility_notifier_get_aabb(RID p_notifier) const = 0; + virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) = 0; + //used from 2D and 3D virtual RID particles_collision_instance_create(RID p_collision) = 0; virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) = 0; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 95aa05f6b36..629d212b694 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -118,6 +118,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { RSG::rasterizer->end_frame(p_swap_buffers); RSG::canvas->update_visibility_notifiers(); + RSG::scene->update_visibility_notifiers(); while (frame_drawn_callbacks.front()) { Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 73373c97bb9..94043742876 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -529,6 +529,12 @@ public: FUNC1(particles_collision_height_field_update, RID) FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution) + /* VISIBILITY_NOTIFIER */ + + FUNCRIDSPLIT(visibility_notifier) + FUNC2(visibility_notifier_set_aabb, RID, const AABB &) + FUNC3(visibility_notifier_set_callbacks, RID, const Callable &, const Callable &) + #undef server_name #undef ServerName //from now on, calls forwarded to this singleton @@ -549,7 +555,7 @@ public: /* OCCLUDER */ FUNCRIDSPLIT(occluder) - FUNC3(occluder_set_mesh, RID, const PackedVector3Array &, const PackedInt32Array &); + FUNC3(occluder_set_mesh, RID, const PackedVector3Array &, const PackedInt32Array &) #undef server_name #undef ServerName diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 0cb765ef567..ac6b0a4d1a0 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -722,6 +722,17 @@ public: virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field + /* VISIBILITY NOTIFIER API */ + + virtual RID visibility_notifier_create() = 0; + virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) = 0; + virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0; + + /* OCCLUDER API */ + + virtual RID occluder_create() = 0; + virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0; + /* CAMERA API */ virtual RID camera_create() = 0; @@ -734,11 +745,6 @@ public: virtual void camera_set_camera_effects(RID p_camera, RID p_camera_effects) = 0; virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0; - /* OCCLUDER API */ - - virtual RID occluder_create() = 0; - virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0; - /* VIEWPORT TARGET API */ enum CanvasItemTextureFilter { @@ -1148,6 +1154,7 @@ public: INSTANCE_VOXEL_GI, INSTANCE_LIGHTMAP, INSTANCE_OCCLUDER, + INSTANCE_VISIBLITY_NOTIFIER, INSTANCE_MAX, INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) | (1 << INSTANCE_PARTICLES)