From 140cf0f2cb7b51d7866e63aba1aa6d8029cf540b Mon Sep 17 00:00:00 2001 From: trollodel <33117082+trollodel@users.noreply.github.com> Date: Tue, 27 Apr 2021 11:23:08 +0200 Subject: [PATCH] Create CollisionObject debug shapes using VS (cherry picked from commit 60ee8c9639d5abacdc6dfb7bd96b0c51d337ad43) --- scene/3d/collision_object.cpp | 121 +++++++++++++++++++++++++--------- scene/3d/collision_object.h | 12 ++-- scene/3d/collision_shape.cpp | 17 ++--- scene/3d/collision_shape.h | 2 - scene/3d/physics_body.cpp | 2 + 5 files changed, 103 insertions(+), 51 deletions(-) diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 5331a06008..25ad315fd8 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -38,6 +38,21 @@ void CollisionObject::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (_are_collision_shapes_visible()) { + debug_shape_old_transform = get_global_transform(); + for (Map::Element *E = shapes.front(); E; E = E->next()) { + debug_shapes_to_update.insert(E->key()); + } + _update_debug_shapes(); + } + } break; + + case NOTIFICATION_EXIT_TREE: { + if (debug_shapes_count > 0) { + _clear_debug_shapes(); + } + } break; case NOTIFICATION_ENTER_WORLD: { @@ -63,6 +78,8 @@ void CollisionObject::_notification(int p_what) { else PhysicsServer::get_singleton()->body_set_state(rid, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform()); + _on_transform_changed(); + } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -77,11 +94,6 @@ void CollisionObject::_notification(int p_what) { PhysicsServer::get_singleton()->body_set_space(rid, RID()); } break; - case NOTIFICATION_PREDELETE: { - if (debug_shape_count > 0) { - _clear_debug_shapes(); - } - } break; } } @@ -120,6 +132,33 @@ void CollisionObject::_update_pickable() { PhysicsServer::get_singleton()->body_set_ray_pickable(rid, pickable); } +bool CollisionObject::_are_collision_shapes_visible() { + return is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint(); +} + +void CollisionObject::_update_shape_data(uint32_t p_owner) { + if (_are_collision_shapes_visible()) { + if (debug_shapes_to_update.empty()) { + call_deferred("_update_debug_shapes"); + } + debug_shapes_to_update.insert(p_owner); + } +} + +void CollisionObject::_shape_changed(const Ref &p_shape) { + for (Map::Element *E = shapes.front(); E; E = E->next()) { + ShapeData &shapedata = E->get(); + ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw(); + for (int i = 0; i < shapedata.shapes.size(); i++) { + ShapeData::ShapeBase &s = shapes[i]; + if (s.shape == p_shape && s.debug_shape.is_valid()) { + Ref mesh = s.shape->get_debug_mesh(); + VS::get_singleton()->instance_set_base(s.debug_shape, mesh->get_rid()); + } + } + } +} + void CollisionObject::_update_debug_shapes() { for (Set::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) { if (shapes.has(shapedata_idx->get())) { @@ -127,24 +166,27 @@ void CollisionObject::_update_debug_shapes() { ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw(); for (int i = 0; i < shapedata.shapes.size(); i++) { ShapeData::ShapeBase &s = shapes[i]; - if (s.debug_shape) { - s.debug_shape->queue_delete(); - s.debug_shape = nullptr; - --debug_shape_count; - } if (s.shape.is_null() || shapedata.disabled) { - continue; + if (s.debug_shape.is_valid()) { + VS::get_singleton()->free(s.debug_shape); + s.debug_shape = RID(); + --debug_shapes_count; + } + } + if (!s.debug_shape.is_valid()) { + s.debug_shape = VS::get_singleton()->instance_create(); + VS::get_singleton()->instance_set_scenario(s.debug_shape, get_world()->get_scenario()); + + if (!s.shape->is_connected("changed", this, "_shape_changed")) { + s.shape->connect("changed", this, "_shape_changed", varray(s.shape), CONNECT_DEFERRED); + } + + ++debug_shapes_count; } Ref mesh = s.shape->get_debug_mesh(); - MeshInstance *mi = memnew(MeshInstance); - mi->set_transform(shapedata.xform); - mi->set_mesh(mesh); - add_child(mi); - - mi->force_update_transform(); - s.debug_shape = mi; - ++debug_shape_count; + VS::get_singleton()->instance_set_base(s.debug_shape, mesh->get_rid()); + VS::get_singleton()->instance_set_transform(s.debug_shape, get_global_transform() * shapedata.xform); } } } @@ -157,22 +199,29 @@ void CollisionObject::_clear_debug_shapes() { ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw(); for (int i = 0; i < shapedata.shapes.size(); i++) { ShapeData::ShapeBase &s = shapes[i]; - if (s.debug_shape) { - s.debug_shape->queue_delete(); - s.debug_shape = nullptr; + if (s.debug_shape.is_valid()) { + VS::get_singleton()->free(s.debug_shape); + s.debug_shape = RID(); + if (s.shape.is_valid() && s.shape->is_connected("changed", this, "_shape_changed")) { + s.shape->disconnect("changed", this, "_shape_changed"); + } } } } - debug_shape_count = 0; + debug_shapes_count = 0; } -void CollisionObject::_update_shape_data(uint32_t p_owner) { - if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint()) { - if (debug_shapes_to_update.empty()) { - call_deferred("_update_debug_shapes"); +void CollisionObject::_on_transform_changed() { + if (debug_shapes_count > 0 && !debug_shape_old_transform.is_equal_approx(get_global_transform())) { + debug_shape_old_transform = get_global_transform(); + for (Map::Element *E = shapes.front(); E; E = E->next()) { + ShapeData &shapedata = E->get(); + const ShapeData::ShapeBase *shapes = shapedata.shapes.ptr(); + for (int i = 0; i < shapedata.shapes.size(); i++) { + VS::get_singleton()->instance_set_transform(shapes[i].debug_shape, debug_shape_old_transform * shapedata.xform); + } } - debug_shapes_to_update.insert(p_owner); } } @@ -211,6 +260,7 @@ void CollisionObject::_bind_methods() { ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject::shape_find_owner); ClassDB::bind_method(D_METHOD("_update_debug_shapes"), &CollisionObject::_update_debug_shapes); + ClassDB::bind_method(D_METHOD("_shape_changed", "shape"), &CollisionObject::_shape_changed); BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); @@ -253,7 +303,11 @@ void CollisionObject::shape_owner_set_disabled(uint32_t p_owner, bool p_disabled ERR_FAIL_COND(!shapes.has(p_owner)); ShapeData &sd = shapes[p_owner]; + if (sd.disabled == p_disabled) { + return; + } sd.disabled = p_disabled; + for (int i = 0; i < sd.shapes.size(); i++) { if (area) { PhysicsServer::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled); @@ -365,7 +419,7 @@ void CollisionObject::shape_owner_remove_shape(uint32_t p_owner, int p_shape) { ERR_FAIL_COND(!shapes.has(p_owner)); ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size()); - const ShapeData::ShapeBase &s = shapes[p_owner].shapes[p_shape]; + ShapeData::ShapeBase &s = shapes[p_owner].shapes.write[p_shape]; int index_to_remove = s.index; if (area) { @@ -374,9 +428,12 @@ void CollisionObject::shape_owner_remove_shape(uint32_t p_owner, int p_shape) { PhysicsServer::get_singleton()->body_remove_shape(rid, index_to_remove); } - if (s.debug_shape) { - s.debug_shape->queue_delete(); - --debug_shape_count; + if (s.debug_shape.is_valid()) { + VS::get_singleton()->free(s.debug_shape); + if (s.shape.is_valid() && s.shape->is_connected("changed", this, "_shape_changed")) { + s.shape->disconnect("changed", this, "_shape_changed"); + } + --debug_shapes_count; } shapes[p_owner].shapes.remove(p_shape); diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h index 02f5c8bef9..f8bf8d4470 100644 --- a/scene/3d/collision_object.h +++ b/scene/3d/collision_object.h @@ -47,7 +47,7 @@ class CollisionObject : public Spatial { Object *owner; Transform xform; struct ShapeBase { - Node *debug_shape = nullptr; + RID debug_shape; Ref shape; int index; }; @@ -69,11 +69,16 @@ class CollisionObject : public Spatial { bool ray_pickable; Set debug_shapes_to_update; - int debug_shape_count = 0; + int debug_shapes_count = 0; + Transform debug_shape_old_transform; void _update_pickable(); + bool _are_collision_shapes_visible(); void _update_shape_data(uint32_t p_owner); + void _shape_changed(const Ref &p_shape); + void _update_debug_shapes(); + void _clear_debug_shapes(); protected: CollisionObject(RID p_rid, bool p_area); @@ -85,8 +90,7 @@ protected: virtual void _mouse_enter(); virtual void _mouse_exit(); - void _update_debug_shapes(); - void _clear_debug_shapes(); + void _on_transform_changed(); public: uint32_t create_shape_owner(Object *p_owner); diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp index 63c9a03739..09b785dcdb 100644 --- a/scene/3d/collision_shape.cpp +++ b/scene/3d/collision_shape.cpp @@ -158,8 +158,6 @@ void CollisionShape::_bind_methods() { ClassDB::bind_method(D_METHOD("make_convex_from_brothers"), &CollisionShape::make_convex_from_brothers); ClassDB::set_method_flags("CollisionShape", "make_convex_from_brothers", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); - ClassDB::bind_method(D_METHOD("_shape_changed"), &CollisionShape::_shape_changed); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); } @@ -170,12 +168,10 @@ void CollisionShape::set_shape(const Ref &p_shape) { } if (!shape.is_null()) { shape->unregister_owner(this); - shape->disconnect("changed", this, "_shape_changed"); } shape = p_shape; if (!shape.is_null()) { shape->register_owner(this); - shape->connect("changed", this, "_shape_changed"); } update_gizmo(); if (parent) { @@ -185,8 +181,10 @@ void CollisionShape::set_shape(const Ref &p_shape) { } } - if (is_inside_tree()) - _shape_changed(); + if (is_inside_tree() && parent) { + // If this is a heightfield shape our center may have changed + _update_in_shape_owner(true); + } update_configuration_warning(); } @@ -223,10 +221,3 @@ CollisionShape::~CollisionShape() { shape->unregister_owner(this); //VisualServer::get_singleton()->free(indicator); } - -void CollisionShape::_shape_changed() { - // If this is a heightfield shape our center may have changed - if (parent) { - _update_in_shape_owner(true); - } -} diff --git a/scene/3d/collision_shape.h b/scene/3d/collision_shape.h index fc331315d2..5f265389cc 100644 --- a/scene/3d/collision_shape.h +++ b/scene/3d/collision_shape.h @@ -48,8 +48,6 @@ class CollisionShape : public Spatial { bool disabled; protected: - void _shape_changed(); - void _update_in_shape_owner(bool p_xform_only = false); protected: diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 0d21fbe1b6..03cf645e38 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -457,6 +457,7 @@ void RigidBody::_direct_state_changed(Object *p_state) { if (get_script_instance()) get_script_instance()->call("_integrate_forces", state); set_ignore_transform_notification(false); + _on_transform_changed(); if (contact_monitor) { @@ -2224,6 +2225,7 @@ void PhysicalBone::_direct_state_changed(Object *p_state) { set_ignore_transform_notification(true); set_global_transform(global_transform); set_ignore_transform_notification(false); + _on_transform_changed(); // Update skeleton if (parent_skeleton) {