Skip to content

Commit

Permalink
Allow CollisionObject to show collision shape meshes
Browse files Browse the repository at this point in the history
Add an editor gizmo to CollisionObject.
CollisionShape no longer shows collision shapes directly.
  • Loading branch information
trollodel committed Feb 24, 2021
1 parent aa7c298 commit 2da6d82
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 34 deletions.
1 change: 1 addition & 0 deletions editor/plugins/spatial_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6206,6 +6206,7 @@ void SpatialEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
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<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin)));
add_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin)));
Expand Down
51 changes: 51 additions & 0 deletions editor/spatial_editor_gizmos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
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
13 changes: 13 additions & 0 deletions editor/spatial_editor_gizmos.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,19 @@ class BakedIndirectLightGizmoPlugin : public EditorSpatialGizmoPlugin {
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 {

GDCLASS(CollisionShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
Expand Down
54 changes: 53 additions & 1 deletion scene/3d/collision_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "collision_object.h"

#include "mesh_instance.h"
#include "scene/scene_string_names.h"
#include "servers/physics_server.h"

Expand Down Expand Up @@ -113,6 +114,43 @@ void CollisionObject::_update_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) {

ray_pickable = p_ray_pickable;
Expand Down Expand Up @@ -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_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")));

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 @@ -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);
}
}
_update_shape_data(p_owner);
}

bool CollisionObject::is_shape_owner_disabled(uint32_t p_owner) const {
Expand Down Expand Up @@ -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);
}
}

_update_shape_data(p_owner);
}
Transform CollisionObject::shape_owner_get_transform(uint32_t p_owner) const {

Expand All @@ -259,6 +302,7 @@ void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &
ShapeData::ShapeBase s;
s.index = total_subshapes;
s.shape = p_shape;

if (area) {
PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
} else {
Expand All @@ -267,6 +311,8 @@ void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &
sd.shapes.push_back(s);

total_subshapes++;

_update_shape_data(p_owner);
}
int CollisionObject::shape_owner_get_shape_count(uint32_t p_owner) const {

Expand Down Expand Up @@ -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_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) {
PhysicsServer::get_singleton()->area_remove_shape(rid, index_to_remove);
} else {
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);

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.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class CollisionObject : public Spatial {
Object *owner;
Transform xform;
struct ShapeBase {
Node *debug_shape = nullptr;
Ref<Shape> shape;
int index;
};
Expand All @@ -67,8 +68,12 @@ class CollisionObject : public Spatial {
bool capture_input_on_drag;
bool ray_pickable;

Set<uint32_t> debug_shapes_to_update;

void _update_pickable();

void _update_shape_data(uint32_t p_owner);

protected:
CollisionObject(RID p_rid, bool p_area);

Expand All @@ -79,6 +84,8 @@ class CollisionObject : public Spatial {
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
29 changes: 0 additions & 29 deletions scene/3d/collision_shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,6 @@ void CollisionShape::_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 @@ -162,7 +159,6 @@ void CollisionShape::_bind_methods() {
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("_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::BOOL, "disabled"), "set_disabled", "is_disabled");
Expand Down Expand Up @@ -217,7 +213,6 @@ CollisionShape::CollisionShape() {

//indicator = VisualServer::get_singleton()->mesh_create();
disabled = false;
debug_shape = NULL;
parent = NULL;
owner_id = 0;
set_notify_local_transform(true);
Expand All @@ -229,33 +224,9 @@ CollisionShape::~CollisionShape() {
//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() {
// 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.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,10 @@ class CollisionShape : public Spatial {
uint32_t owner_id;
CollisionObject *parent;

Node *debug_shape;
bool debug_shape_dirty;

void resource_changed(RES res);
bool disabled;

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

void _update_in_shape_owner(bool p_xform_only = false);
Expand Down

0 comments on commit 2da6d82

Please sign in to comment.