Skip to content

Commit

Permalink
Add ability to temporarily add a collision to a mesh behind the curso…
Browse files Browse the repository at this point in the history
…r to enable snapping/measuring functions
  • Loading branch information
ryevdokimov committed Dec 14, 2024
1 parent dc5f1b7 commit d2d1777
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 8 deletions.
125 changes: 117 additions & 8 deletions editor/plugins/node_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,32 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const {
continue;
}

Vector<Ref<Node3DGizmo>> gizmos = spat->get_gizmos();
Vector<Ref<Node3DGizmo>> gizmos = spat->get_gizmos().duplicate();

if (collision_reposition || preview_node->is_inside_tree()) {
Node3D *ignore_node = nullptr;
if (collision_reposition && !ruler->is_inside_tree()) {
List<Node *> &selection = editor_selection->get_selected_node_list();
if (selection.size() == 1) {
ignore_node = Object::cast_to<Node3D>(selection.front()->get());
}
} else if (preview_node->is_inside_tree()) {
ignore_node = Object::cast_to<Node3D>(preview_node);
}

Node *current = spat;
bool should_skip = false;
while (current != nullptr) {
if (current == ignore_node) {
should_skip = true;
break;
}
current = current->get_parent();
}
if (should_skip) {
continue;
}
}

for (int j = 0; j < gizmos.size(); j++) {
Ref<EditorNode3DGizmo> seg = gizmos[j];
Expand All @@ -845,7 +870,7 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const {

if (dist < closest_dist) {
item = Object::cast_to<Node>(spat);
if (item != edited_scene) {
if (item != edited_scene && !collision_reposition && !ruler->is_inside_tree() && !preview_node->is_inside_tree()) {
item = edited_scene->get_deepest_editable_node(item);
}

Expand Down Expand Up @@ -1659,7 +1684,7 @@ void Node3DEditorViewport::input(const Ref<InputEvent> &p_event) {
}

void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (previewing || get_viewport()->gui_get_drag_data()) {
if (previewing) {
return; //do NONE
}

Expand Down Expand Up @@ -1694,6 +1719,10 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> b = p_event;

if (b.is_valid()) {
if (get_viewport()->gui_get_drag_data()) {
return;
}

emit_signal(SNAME("clicked"));

ViewportNavMouseButton orbit_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/orbit_mouse_button").operator int();
Expand Down Expand Up @@ -2045,6 +2074,10 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (m.is_valid() && !_edit.instant) {
_edit.mouse_pos = m->get_position();

if (get_viewport()->gui_get_drag_data()) {
return;
}

if (spatial_editor->get_single_selected_node()) {
Vector<Ref<Node3DGizmo>> gizmos = spatial_editor->get_single_selected_node()->get_gizmos();

Expand Down Expand Up @@ -2236,6 +2269,15 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {

if (k.is_valid()) {
if (!k->is_pressed()) {
create_temp_collision = false;
return;
}

if (ED_IS_SHORTCUT("spatial_editor/create_temp_collision", p_event)) {
create_temp_collision = true;
}

if (get_viewport()->gui_get_drag_data()) {
return;
}

Expand Down Expand Up @@ -2882,6 +2924,19 @@ void Node3DEditorViewport::_project_settings_changed() {
viewport->set_texture_mipmap_bias(texture_mipmap_bias);
}

static void clear_old_collision(ObjectID target) {
if (target.is_valid()) {
MeshInstance3D *old_mesh = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(target));
if (old_mesh) {
Node *old_collision = old_mesh->get_node_or_null(String(old_mesh->get_name()) + "_col");
if (old_collision) {
old_mesh->remove_child(old_collision);
old_collision->queue_free();
}
}
}
}

void Node3DEditorViewport::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
Expand Down Expand Up @@ -3135,17 +3190,49 @@ void Node3DEditorViewport::_notification(int p_what) {
float locked_half_width = locked_label->get_size().width / 2.0f;
locked_label->set_anchor_and_offset(SIDE_LEFT, 0.5f, -locked_half_width);
}

if (create_temp_collision && (collision_reposition || ruler->is_inside_tree() || preview_node->is_inside_tree())) {
ObjectID target_temp = _select_ray(_edit.mouse_pos);

if (target_temp.is_valid()) {
if (target_temp != target) {
clear_old_collision(target);
MeshInstance3D *mesh = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(target_temp));
if (mesh && !has_collision(mesh)) {
mesh->create_trimesh_collision_internal();
}
target = target_temp;
}
} else {
clear_old_collision(target);
target = ObjectID();
}

if (ruler->is_inside_tree()) {
collision_checked = true;
}
} else {
if (!create_temp_collision && ruler->is_inside_tree()) {
collision_checked = true;
}
if (target != ObjectID()) {
clear_old_collision(target);
target = ObjectID();
}
}
} break;

case NOTIFICATION_PHYSICS_PROCESS: {
if (collision_reposition) {
Node3D *selected_node = nullptr;

if (ruler->is_inside_tree()) {
if (ruler_start_point->is_visible()) {
selected_node = ruler_end_point;
} else {
selected_node = ruler_start_point;
if (collision_checked) {
if (ruler_start_point->is_visible()) {
selected_node = ruler_end_point;
} else {
selected_node = ruler_start_point;
}
}
} else {
List<Node *> &selection = editor_selection->get_selected_node_list();
Expand All @@ -3171,9 +3258,11 @@ void Node3DEditorViewport::_notification(int p_what) {
ruler_label->set_visible(true);
}
}
} else {
collision_checked = false;
}

if (!update_preview_node) {
if (!update_preview_node && !create_temp_collision) {
return;
}
if (preview_node->is_inside_tree()) {
Expand Down Expand Up @@ -5658,6 +5747,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
ED_SHORTCUT("spatial_editor/instant_rotate", TTR("Begin Rotate Transformation"));
ED_SHORTCUT("spatial_editor/instant_scale", TTR("Begin Scale Transformation"));
ED_SHORTCUT("spatial_editor/collision_reposition", TTR("Reposition Using Collisions"), KeyModifierMask::SHIFT | Key::G);
ED_SHORTCUT("spatial_editor/create_temp_collision", TTR("Create Temporary Collisions"), Key::C);

preview_camera = memnew(CheckBox);
preview_camera->set_text(TTR("Preview"));
Expand Down Expand Up @@ -6452,6 +6542,25 @@ Dictionary Node3DEditor::get_state() const {
return d;
}

bool Node3DEditorViewport::has_collision(Node *node) {
if (!node) {
return false;
}

if (Object::cast_to<CollisionObject3D>(node)) {
return true;
}

for (int i = 0; i < node->get_child_count(); ++i) {
Node *child = node->get_child(i);
if (has_collision(child)) {
return true;
}
}

return false;
}

void Node3DEditor::set_state(const Dictionary &p_state) {
Dictionary d = p_state;

Expand Down
6 changes: 6 additions & 0 deletions editor/plugins/node_3d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ class Node3DEditorViewport : public Control {
Node *target_node = nullptr;
Point2 drop_pos;

ObjectID target;
bool collision_checked = false;
bool create_temp_collision = false;

EditorSelection *editor_selection = nullptr;

CheckBox *preview_camera = nullptr;
Expand Down Expand Up @@ -294,6 +298,8 @@ class Node3DEditorViewport : public Control {
_FORCE_INLINE_ bool operator<(const _RayResult &p_rr) const { return depth < p_rr.depth; }
};

bool has_collision(Node *node);

void _update_name();
void _compute_edit(const Point2 &p_point);
void _clear_selected();
Expand Down
12 changes: 12 additions & 0 deletions scene/3d/mesh_instance_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,18 @@ void MeshInstance3D::create_trimesh_collision() {
}
}

void MeshInstance3D::create_trimesh_collision_internal() {
StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_trimesh_collision_node());
ERR_FAIL_NULL(static_body);
static_body->set_name(String(get_name()) + "_col");
static_body->set_meta("_edit_lock_", true);

add_child(static_body);

CollisionShape3D *cshape = Object::cast_to<CollisionShape3D>(static_body->get_child(0));
cshape->set_meta("_edit_lock_", true);
}

Node *MeshInstance3D::create_convex_collision_node(bool p_clean, bool p_simplify) {
if (mesh.is_null()) {
return nullptr;
Expand Down
2 changes: 2 additions & 0 deletions scene/3d/mesh_instance_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class MeshInstance3D : public GeometryInstance3D {
Node *create_trimesh_collision_node();
void create_trimesh_collision();

void create_trimesh_collision_internal();

Node *create_convex_collision_node(bool p_clean = true, bool p_simplify = false);
void create_convex_collision(bool p_clean = true, bool p_simplify = false);

Expand Down

0 comments on commit d2d1777

Please sign in to comment.