Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow CollisionObject3D to show collision shape meshes #45783

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions editor/node_3d_editor_gizmos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3505,6 +3505,57 @@ void LightmapProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {

////

CollisionObject3DGizmoPlugin::CollisionObject3DGizmoPlugin() {
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 CollisionObject3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<CollisionObject3D>(p_spatial) != nullptr;
}

String CollisionObject3DGizmoPlugin::get_gizmo_name() const {
return "CollisionObject3D";
}

int CollisionObject3DGizmoPlugin::get_priority() const {
return -1;
}

void CollisionObject3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
CollisionObject3D *co = Object::cast_to<CollisionObject3D>(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 CollisionShape3D and CollisionPolygon3D as they have their gizmo.
if (!Object::cast_to<CollisionShape3D>(owner) && !Object::cast_to<CollisionPolygon3D>(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<Shape3D> 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());
}
}
}
}

////

CollisionShape3DGizmoPlugin::CollisionShape3DGizmoPlugin() {
const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
create_material("shape_material", gizmo_color);
Expand Down
12 changes: 12 additions & 0 deletions editor/node_3d_editor_gizmos.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,18 @@ class LightmapProbeGizmoPlugin : public EditorNode3DGizmoPlugin {
LightmapProbeGizmoPlugin();
};

class CollisionObject3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(CollisionObject3DGizmoPlugin, EditorNode3DGizmoPlugin);

public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;

CollisionObject3DGizmoPlugin();
};

class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(CollisionShape3DGizmoPlugin, EditorNode3DGizmoPlugin);

Expand Down
1 change: 1 addition & 0 deletions editor/plugins/node_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6452,6 +6452,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
add_gizmo_plugin(Ref<BakedLightmapGizmoPlugin>(memnew(BakedLightmapGizmoPlugin)));
add_gizmo_plugin(Ref<LightmapProbeGizmoPlugin>(memnew(LightmapProbeGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionObject3DGizmoPlugin>(memnew(CollisionObject3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionShape3DGizmoPlugin>(memnew(CollisionShape3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionPolygon3DGizmoPlugin>(memnew(CollisionPolygon3DGizmoPlugin)));
add_gizmo_plugin(Ref<NavigationRegion3DGizmoPlugin>(memnew(NavigationRegion3DGizmoPlugin)));
Expand Down
53 changes: 52 additions & 1 deletion scene/3d/collision_object_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "collision_object_3d.h"

#include "mesh_instance_3d.h"
#include "scene/scene_string_names.h"
#include "servers/physics_server_3d.h"

Expand Down Expand Up @@ -110,6 +111,42 @@ void CollisionObject3D::_update_pickable() {
}
}

void CollisionObject3D::_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();
pouleyKetchoupp marked this conversation as resolved.
Show resolved Hide resolved
s.debug_shape = nullptr;
}
if (s.shape.is_null() || shapedata.disabled) {
continue;
}

Ref<Mesh> mesh = s.shape->get_debug_mesh();
MeshInstance3D *mi = memnew(MeshInstance3D);
mi->set_transform(shapedata.xform);
mi->set_mesh(mesh);
add_child(mi);
pouleyKetchoupp marked this conversation as resolved.
Show resolved Hide resolved
mi->force_update_transform();
s.debug_shape = mi;
}
}
}
debug_shapes_to_update.clear();
}

void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
if (debug_shapes_to_update.is_empty()) {
call_deferred("_update_debug_shapes");
}
debug_shapes_to_update.insert(p_owner);
}
}

void CollisionObject3D::set_ray_pickable(bool p_ray_pickable) {
ray_pickable = p_ray_pickable;
_update_pickable();
Expand Down Expand Up @@ -141,6 +178,8 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject3D::shape_owner_clear_shapes);
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner);

ClassDB::bind_method(D_METHOD("_update_debug_shapes"), &CollisionObject3D::_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")));

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")));
Expand Down Expand Up @@ -188,6 +227,7 @@ void CollisionObject3D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabl
PhysicsServer3D::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
}
}
_update_shape_data(p_owner);
}

bool CollisionObject3D::is_shape_owner_disabled(uint32_t p_owner) const {
Expand Down Expand Up @@ -223,6 +263,8 @@ void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transf
PhysicsServer3D::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform);
}
}

_update_shape_data(p_owner);
}

Transform CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const {
Expand All @@ -245,6 +287,7 @@ void CollisionObject3D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape3
ShapeData::ShapeBase s;
s.index = total_subshapes;
s.shape = p_shape;

if (area) {
PhysicsServer3D::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
} else {
Expand All @@ -253,6 +296,8 @@ void CollisionObject3D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape3
sd.shapes.push_back(s);

total_subshapes++;

_update_shape_data(p_owner);
}

int CollisionObject3D::shape_owner_get_shape_count(uint32_t p_owner) const {
Expand All @@ -279,13 +324,19 @@ void CollisionObject3D::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());

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) {
PhysicsServer3D::get_singleton()->area_remove_shape(rid, index_to_remove);
} else {
PhysicsServer3D::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);

for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
Expand Down
7 changes: 7 additions & 0 deletions scene/3d/collision_object_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class CollisionObject3D : public Node3D {
Object *owner = nullptr;
Transform xform;
struct ShapeBase {
Node *debug_shape = nullptr;
Ref<Shape3D> shape;
int index = 0;
};
Expand All @@ -60,8 +61,12 @@ class CollisionObject3D : public Node3D {
bool capture_input_on_drag = false;
bool ray_pickable = true;

Set<uint32_t> debug_shapes_to_update;

void _update_pickable();

void _update_shape_data(uint32_t p_owner);

protected:
CollisionObject3D(RID p_rid, bool p_area);

Expand All @@ -72,6 +77,8 @@ class CollisionObject3D : public Node3D {
virtual void _mouse_enter();
virtual void _mouse_exit();

void _update_debug_shapes();

public:
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
Expand Down
30 changes: 0 additions & 30 deletions scene/3d/collision_shape_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@ void CollisionShape3D::_notification(int p_what) {
if (parent) {
_update_in_shape_owner();
}
if (get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (parent) {
Expand Down Expand Up @@ -163,8 +160,6 @@ void CollisionShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_convex_from_siblings"), &CollisionShape3D::make_convex_from_siblings);
ClassDB::set_method_flags("CollisionShape3D", "make_convex_from_siblings", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);

ClassDB::bind_method(D_METHOD("_update_debug_shape"), &CollisionShape3D::_update_debug_shape);

ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
}
Expand Down Expand Up @@ -224,34 +219,9 @@ CollisionShape3D::~CollisionShape3D() {
//RenderingServer::get_singleton()->free(indicator);
}

void CollisionShape3D::_update_debug_shape() {
debug_shape_dirty = false;

if (debug_shape) {
debug_shape->queue_delete();
debug_shape = nullptr;
}

Ref<Shape3D> s = get_shape();
if (s.is_null()) {
return;
}

Ref<Mesh> mesh = s->get_debug_mesh();
MeshInstance3D *mi = memnew(MeshInstance3D);
mi->set_mesh(mesh);
add_child(mi);
debug_shape = mi;
}

void CollisionShape3D::_shape_changed() {
// If this is a heightfield shape our center may have changed
if (parent) {
_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");
}
}
4 changes: 0 additions & 4 deletions scene/3d/collision_shape_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,10 @@ class CollisionShape3D : public Node3D {
uint32_t owner_id = 0;
CollisionObject3D *parent = nullptr;

Node *debug_shape = nullptr;
bool debug_shape_dirty;

void resource_changed(RES res);
bool disabled = false;

protected:
void _update_debug_shape();
void _shape_changed();

void _update_in_shape_owner(bool p_xform_only = false);
Expand Down