Browse Source

Allow CollisionObject to show collision shape meshes

Add an editor gizmo to CollisionObject.
CollisionShape no longer shows collision shapes directly.
trollodel 4 years ago
parent
commit
2da6d82f3b

+ 1 - 0
editor/plugins/spatial_editor_plugin.cpp

@@ -6206,6 +6206,7 @@ void SpatialEditor::_register_all_gizmos() {
 	add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
 	add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
 	add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
 	add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
 	add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));
 	add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));
+	add_gizmo_plugin(Ref<CollisionObjectGizmoPlugin>(memnew(CollisionObjectGizmoPlugin)));
 	add_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin)));
 	add_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin)));
 	add_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin)));
 	add_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin)));
 	add_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin)));
 	add_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin)));

+ 51 - 0
editor/spatial_editor_gizmos.cpp

@@ -3029,6 +3029,57 @@ void BakedIndirectLightGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
 
 
 ////
 ////
 
 
+CollisionObjectGizmoPlugin::CollisionObjectGizmoPlugin() {
+	const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+	create_material("shape_material", gizmo_color);
+	const float gizmo_value = gizmo_color.get_v();
+	const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65);
+	create_material("shape_material_disabled", gizmo_color_disabled);
+}
+
+bool CollisionObjectGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+	return Object::cast_to<CollisionObject>(p_spatial) != nullptr;
+}
+
+String CollisionObjectGizmoPlugin::get_name() const {
+	return "CollisionObject";
+}
+
+int CollisionObjectGizmoPlugin::get_priority() const {
+	return -1;
+}
+
+void CollisionObjectGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+	CollisionObject *co = Object::cast_to<CollisionObject>(p_gizmo->get_spatial_node());
+
+	p_gizmo->clear();
+
+	List<uint32_t> owners;
+	co->get_shape_owners(&owners);
+	for (List<uint32_t>::Element *E = owners.front(); E; E = E->next()) {
+		uint32_t owner_id = E->get();
+		Transform xform = co->shape_owner_get_transform(owner_id);
+		Object *owner = co->shape_owner_get_owner(owner_id);
+		// Exclude CollisionShape and CollisionPolygon as they have their gizmo.
+		if (!Object::cast_to<CollisionShape>(owner) && !Object::cast_to<CollisionPolygon>(owner)) {
+			Ref<Material> material = get_material(!co->is_shape_owner_disabled(owner_id) ? "shape_material" : "shape_material_disabled", p_gizmo);
+			for (int shape_id = 0; shape_id < co->shape_owner_get_shape_count(owner_id); shape_id++) {
+				Ref<Shape> s = co->shape_owner_get_shape(owner_id, shape_id);
+				if (s.is_null()) {
+					continue;
+				}
+				SurfaceTool st;
+				st.append_from(s->get_debug_mesh(), 0, xform);
+
+				p_gizmo->add_mesh(st.commit(), false, Ref<SkinReference>(), material);
+				p_gizmo->add_collision_segments(s->get_debug_mesh_lines());
+			}
+		}
+	}
+}
+
+////
+
 CollisionShapeSpatialGizmoPlugin::CollisionShapeSpatialGizmoPlugin() {
 CollisionShapeSpatialGizmoPlugin::CollisionShapeSpatialGizmoPlugin() {
 	const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
 	const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
 	create_material("shape_material", gizmo_color);
 	create_material("shape_material", gizmo_color);

+ 13 - 0
editor/spatial_editor_gizmos.h

@@ -321,6 +321,19 @@ public:
 	BakedIndirectLightGizmoPlugin();
 	BakedIndirectLightGizmoPlugin();
 };
 };
 
 
+class CollisionObjectGizmoPlugin : public EditorSpatialGizmoPlugin {
+
+	GDCLASS(CollisionObjectGizmoPlugin, EditorSpatialGizmoPlugin);
+
+public:
+	bool has_gizmo(Spatial *p_spatial);
+	String get_name() const;
+	int get_priority() const;
+	void redraw(EditorSpatialGizmo *p_gizmo);
+
+	CollisionObjectGizmoPlugin();
+};
+
 class CollisionShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
 class CollisionShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
 
 
 	GDCLASS(CollisionShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
 	GDCLASS(CollisionShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin);

+ 53 - 1
scene/3d/collision_object.cpp

@@ -30,6 +30,7 @@
 
 
 #include "collision_object.h"
 #include "collision_object.h"
 
 
+#include "mesh_instance.h"
 #include "scene/scene_string_names.h"
 #include "scene/scene_string_names.h"
 #include "servers/physics_server.h"
 #include "servers/physics_server.h"
 
 
@@ -113,6 +114,43 @@ void CollisionObject::_update_pickable() {
 		PhysicsServer::get_singleton()->body_set_ray_pickable(rid, pickable);
 		PhysicsServer::get_singleton()->body_set_ray_pickable(rid, pickable);
 }
 }
 
 
+void CollisionObject::_update_debug_shapes() {
+	for (Set<uint32_t>::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) {
+		if (shapes.has(shapedata_idx->get())) {
+			ShapeData &shapedata = shapes[shapedata_idx->get()];
+			for (int i = 0; i < shapedata.shapes.size(); i++) {
+				ShapeData::ShapeBase &s = shapedata.shapes.write[i];
+				if (s.debug_shape) {
+					s.debug_shape->queue_delete();
+					s.debug_shape = nullptr;
+				}
+				if (s.shape.is_null() || shapedata.disabled) {
+					continue;
+				}
+
+				Ref<Mesh> 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_shapes_to_update.clear();
+}
+
+void CollisionObject::_update_shape_data(uint32_t p_owner) {
+	if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
+		if (debug_shapes_to_update.empty()) {
+			call_deferred("_update_debug_shapes");
+		}
+		debug_shapes_to_update.insert(p_owner);
+	}
+}
+
 void CollisionObject::set_ray_pickable(bool p_ray_pickable) {
 void CollisionObject::set_ray_pickable(bool p_ray_pickable) {
 
 
 	ray_pickable = p_ray_pickable;
 	ray_pickable = p_ray_pickable;
@@ -147,6 +185,8 @@ void CollisionObject::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject::shape_owner_clear_shapes);
 	ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject::shape_owner_clear_shapes);
 	ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject::shape_find_owner);
 	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);
+
 	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")));
 	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")));
 
 
 	ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx")));
 	ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx")));
@@ -196,6 +236,7 @@ void CollisionObject::shape_owner_set_disabled(uint32_t p_owner, bool p_disabled
 			PhysicsServer::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
 			PhysicsServer::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
 		}
 		}
 	}
 	}
+	_update_shape_data(p_owner);
 }
 }
 
 
 bool CollisionObject::is_shape_owner_disabled(uint32_t p_owner) const {
 bool CollisionObject::is_shape_owner_disabled(uint32_t p_owner) const {
@@ -235,6 +276,8 @@ void CollisionObject::shape_owner_set_transform(uint32_t p_owner, const Transfor
 			PhysicsServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform);
 			PhysicsServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform);
 		}
 		}
 	}
 	}
+
+	_update_shape_data(p_owner);
 }
 }
 Transform CollisionObject::shape_owner_get_transform(uint32_t p_owner) const {
 Transform CollisionObject::shape_owner_get_transform(uint32_t p_owner) const {
 
 
@@ -259,6 +302,7 @@ void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &
 	ShapeData::ShapeBase s;
 	ShapeData::ShapeBase s;
 	s.index = total_subshapes;
 	s.index = total_subshapes;
 	s.shape = p_shape;
 	s.shape = p_shape;
+
 	if (area) {
 	if (area) {
 		PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
 		PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
 	} else {
 	} else {
@@ -267,6 +311,8 @@ void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &
 	sd.shapes.push_back(s);
 	sd.shapes.push_back(s);
 
 
 	total_subshapes++;
 	total_subshapes++;
+
+	_update_shape_data(p_owner);
 }
 }
 int CollisionObject::shape_owner_get_shape_count(uint32_t p_owner) const {
 int CollisionObject::shape_owner_get_shape_count(uint32_t p_owner) const {
 
 
@@ -294,13 +340,19 @@ void CollisionObject::shape_owner_remove_shape(uint32_t p_owner, int p_shape) {
 	ERR_FAIL_COND(!shapes.has(p_owner));
 	ERR_FAIL_COND(!shapes.has(p_owner));
 	ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size());
 	ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size());
 
 
-	int index_to_remove = shapes[p_owner].shapes[p_shape].index;
+	const ShapeData::ShapeBase &s = shapes[p_owner].shapes[p_shape];
+	int index_to_remove = s.index;
+
 	if (area) {
 	if (area) {
 		PhysicsServer::get_singleton()->area_remove_shape(rid, index_to_remove);
 		PhysicsServer::get_singleton()->area_remove_shape(rid, index_to_remove);
 	} else {
 	} else {
 		PhysicsServer::get_singleton()->body_remove_shape(rid, index_to_remove);
 		PhysicsServer::get_singleton()->body_remove_shape(rid, index_to_remove);
 	}
 	}
 
 
+	if (s.debug_shape) {
+		s.debug_shape->queue_delete();
+	}
+
 	shapes[p_owner].shapes.remove(p_shape);
 	shapes[p_owner].shapes.remove(p_shape);
 
 
 	for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
 	for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {

+ 7 - 0
scene/3d/collision_object.h

@@ -47,6 +47,7 @@ class CollisionObject : public Spatial {
 		Object *owner;
 		Object *owner;
 		Transform xform;
 		Transform xform;
 		struct ShapeBase {
 		struct ShapeBase {
+			Node *debug_shape = nullptr;
 			Ref<Shape> shape;
 			Ref<Shape> shape;
 			int index;
 			int index;
 		};
 		};
@@ -67,8 +68,12 @@ class CollisionObject : public Spatial {
 	bool capture_input_on_drag;
 	bool capture_input_on_drag;
 	bool ray_pickable;
 	bool ray_pickable;
 
 
+	Set<uint32_t> debug_shapes_to_update;
+
 	void _update_pickable();
 	void _update_pickable();
 
 
+	void _update_shape_data(uint32_t p_owner);
+
 protected:
 protected:
 	CollisionObject(RID p_rid, bool p_area);
 	CollisionObject(RID p_rid, bool p_area);
 
 
@@ -79,6 +84,8 @@ protected:
 	virtual void _mouse_enter();
 	virtual void _mouse_enter();
 	virtual void _mouse_exit();
 	virtual void _mouse_exit();
 
 
+	void _update_debug_shapes();
+
 public:
 public:
 	uint32_t create_shape_owner(Object *p_owner);
 	uint32_t create_shape_owner(Object *p_owner);
 	void remove_shape_owner(uint32_t owner);
 	void remove_shape_owner(uint32_t owner);

+ 0 - 29
scene/3d/collision_shape.cpp

@@ -89,9 +89,6 @@ void CollisionShape::_notification(int p_what) {
 			if (parent) {
 			if (parent) {
 				_update_in_shape_owner();
 				_update_in_shape_owner();
 			}
 			}
-			if (get_tree()->is_debugging_collisions_hint()) {
-				_update_debug_shape();
-			}
 		} break;
 		} break;
 		case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
 		case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
 			if (parent) {
 			if (parent) {
@@ -162,7 +159,6 @@ void CollisionShape::_bind_methods() {
 	ClassDB::set_method_flags("CollisionShape", "make_convex_from_brothers", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
 	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);
 	ClassDB::bind_method(D_METHOD("_shape_changed"), &CollisionShape::_shape_changed);
-	ClassDB::bind_method(D_METHOD("_update_debug_shape"), &CollisionShape::_update_debug_shape);
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape");
 	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");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
@@ -217,7 +213,6 @@ CollisionShape::CollisionShape() {
 
 
 	//indicator = VisualServer::get_singleton()->mesh_create();
 	//indicator = VisualServer::get_singleton()->mesh_create();
 	disabled = false;
 	disabled = false;
-	debug_shape = NULL;
 	parent = NULL;
 	parent = NULL;
 	owner_id = 0;
 	owner_id = 0;
 	set_notify_local_transform(true);
 	set_notify_local_transform(true);
@@ -229,33 +224,9 @@ CollisionShape::~CollisionShape() {
 	//VisualServer::get_singleton()->free(indicator);
 	//VisualServer::get_singleton()->free(indicator);
 }
 }
 
 
-void CollisionShape::_update_debug_shape() {
-	debug_shape_dirty = false;
-
-	if (debug_shape) {
-		debug_shape->queue_delete();
-		debug_shape = NULL;
-	}
-
-	Ref<Shape> s = get_shape();
-	if (s.is_null())
-		return;
-
-	Ref<Mesh> mesh = s->get_debug_mesh();
-	MeshInstance *mi = memnew(MeshInstance);
-	mi->set_mesh(mesh);
-	add_child(mi);
-	debug_shape = mi;
-}
-
 void CollisionShape::_shape_changed() {
 void CollisionShape::_shape_changed() {
 	// If this is a heightfield shape our center may have changed
 	// If this is a heightfield shape our center may have changed
 	if (parent) {
 	if (parent) {
 		_update_in_shape_owner(true);
 		_update_in_shape_owner(true);
 	}
 	}
-
-	if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !debug_shape_dirty) {
-		debug_shape_dirty = true;
-		call_deferred("_update_debug_shape");
-	}
 }
 }

+ 0 - 4
scene/3d/collision_shape.h

@@ -44,14 +44,10 @@ class CollisionShape : public Spatial {
 	uint32_t owner_id;
 	uint32_t owner_id;
 	CollisionObject *parent;
 	CollisionObject *parent;
 
 
-	Node *debug_shape;
-	bool debug_shape_dirty;
-
 	void resource_changed(RES res);
 	void resource_changed(RES res);
 	bool disabled;
 	bool disabled;
 
 
 protected:
 protected:
-	void _update_debug_shape();
 	void _shape_changed();
 	void _shape_changed();
 
 
 	void _update_in_shape_owner(bool p_xform_only = false);
 	void _update_in_shape_owner(bool p_xform_only = false);