Skip to content

Commit

Permalink
Use collision detection ray to reposition an object already in the scene
Browse files Browse the repository at this point in the history
  • Loading branch information
ryevdokimov committed Sep 10, 2024
1 parent d0dc389 commit 2919e2e
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 7 deletions.
68 changes: 62 additions & 6 deletions editor/plugins/node_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ void Node3DEditorViewport::cancel_transform() {
sp->set_global_transform(se->original);
}

collision_reposition = false;
finish_transform();
set_message(TTR("Transform Aborted."), 3);
}
Expand Down Expand Up @@ -1801,7 +1802,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (b->is_pressed()) {
clicked_wants_append = b->is_shift_pressed();

if (_edit.mode != TRANSFORM_NONE && _edit.instant) {
if (_edit.mode != TRANSFORM_NONE && (_edit.instant || collision_reposition)) {
commit_transform();
break; // just commit the edit, stop processing the event so we don't deselect the object
}
Expand Down Expand Up @@ -2400,30 +2401,43 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
cancel_transform();
}
if (!is_freelook_active() && !k->is_echo()) {
if (ED_IS_SHORTCUT("spatial_editor/instant_translate", p_event) && _edit.mode != TRANSFORM_TRANSLATE) {
if (ED_IS_SHORTCUT("spatial_editor/instant_translate", p_event) && (_edit.mode != TRANSFORM_TRANSLATE || collision_reposition)) {
if (_edit.mode == TRANSFORM_NONE) {
begin_transform(TRANSFORM_TRANSLATE, true);
} else if (_edit.instant) {
} else if (_edit.instant || collision_reposition) {
commit_transform();
begin_transform(TRANSFORM_TRANSLATE, true);
}
}
if (ED_IS_SHORTCUT("spatial_editor/instant_rotate", p_event) && _edit.mode != TRANSFORM_ROTATE) {
if (_edit.mode == TRANSFORM_NONE) {
begin_transform(TRANSFORM_ROTATE, true);
} else if (_edit.instant) {
} else if (_edit.instant || collision_reposition) {
commit_transform();
begin_transform(TRANSFORM_ROTATE, true);
}
}
if (ED_IS_SHORTCUT("spatial_editor/instant_scale", p_event) && _edit.mode != TRANSFORM_SCALE) {
if (_edit.mode == TRANSFORM_NONE) {
begin_transform(TRANSFORM_SCALE, true);
} else if (_edit.instant) {
} else if (_edit.instant || collision_reposition) {
commit_transform();
begin_transform(TRANSFORM_SCALE, true);
}
}
if (ED_IS_SHORTCUT("spatial_editor/collision_reposition", p_event) && editor_selection->get_selected_node_list().size() == 1 && !collision_reposition) {
if (_edit.mode == TRANSFORM_NONE || _edit.instant) {
if (_edit.mode == TRANSFORM_NONE) {
_compute_edit(_edit.mouse_pos);
} else {
commit_transform();
_compute_edit(_edit.mouse_pos);
}
_edit.mode = TRANSFORM_TRANSLATE;
collision_reposition = true;
}
}

}

// Freelook doesn't work in orthogonal mode.
Expand Down Expand Up @@ -3074,6 +3088,19 @@ void Node3DEditorViewport::_notification(int p_what) {
} break;

case NOTIFICATION_PHYSICS_PROCESS: {
if (collision_reposition) {
List<Node *> &selection = editor_selection->get_selected_node_list();

if (selection.size() == 1) {
Node3D *first_selected_node = Object::cast_to<Node3D>(selection.front()->get());
double snap = EDITOR_GET("interface/inspector/default_float_step");
int snap_step_decimals = Math::range_step_decimals(snap);
set_message(TTR("Translating:") + " (" + String::num(first_selected_node->get_global_position().x, snap_step_decimals) + ", " +
String::num(first_selected_node->get_global_position().y, snap_step_decimals) + ", " + String::num(first_selected_node->get_global_position().z, snap_step_decimals) + ")");
first_selected_node->set_global_position(spatial_editor->snap_point(_get_instance_position(_edit.mouse_pos)));
}
}

if (!update_preview_node) {
return;
}
Expand Down Expand Up @@ -3968,7 +3995,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
return;
}

bool show_gizmo = spatial_editor->is_gizmo_visible() && !_edit.instant && transform_gizmo_visible;
bool show_gizmo = spatial_editor->is_gizmo_visible() && !_edit.instant && transform_gizmo_visible && !collision_reposition;
for (int i = 0; i < 3; i++) {
Transform3D axis_angle;
if (xform.basis.get_column(i).normalized().dot(xform.basis.get_column((i + 1) % 3).normalized()) < 1.0) {
Expand Down Expand Up @@ -4243,6 +4270,18 @@ void Node3DEditorViewport::assign_pending_data_pointers(Node3D *p_preview_node,
accept = p_accept;
}

void _insert_rid_recursive(Node *node, HashSet<RID> &rids) {
CollisionObject3D *co = Object::cast_to<CollisionObject3D>(node);
if (co) {
rids.insert(co->get_rid());
}

for (int i = 0; i < node->get_child_count(); i++) {
Node *child = node->get_child(i);
_insert_rid_recursive(child, rids);
}
}

Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const {
const float MAX_DISTANCE = 50.0;
const float FALLBACK_DISTANCE = 5.0;
Expand All @@ -4252,7 +4291,22 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const

PhysicsDirectSpaceState3D *ss = get_tree()->get_root()->get_world_3d()->get_direct_space_state();

HashSet<RID> rids;

if (!preview_node->is_inside_tree()) {
List<Node *> &selection = editor_selection->get_selected_node_list();

Node3D *first_selected_node = Object::cast_to<Node3D>(selection.front()->get());

Array children = first_selected_node->get_children();

if (first_selected_node) {
_insert_rid_recursive(first_selected_node, rids);
}
}

PhysicsDirectSpaceState3D::RayParameters ray_params;
ray_params.exclude = rids;
ray_params.from = world_pos;
ray_params.to = world_pos + world_ray * camera->get_far();

Expand Down Expand Up @@ -4880,6 +4934,7 @@ void Node3DEditorViewport::commit_transform() {
}
undo_redo->commit_action();

collision_reposition = false;
finish_transform();
set_message("");
}
Expand Down Expand Up @@ -5477,6 +5532,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
ED_SHORTCUT("spatial_editor/instant_translate", TTR("Begin Translate Transformation"));
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"));

preview_camera = memnew(CheckBox);
preview_camera->set_text(TTR("Preview"));
Expand Down
2 changes: 1 addition & 1 deletion editor/plugins/node_3d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ class Node3DEditorViewport : public Control {
bool auto_orthogonal;
bool lock_rotation;
bool transform_gizmo_visible = true;
bool collision_reposition = false;
real_t gizmo_scale;

bool freelook_active;
Expand Down Expand Up @@ -338,7 +339,6 @@ class Node3DEditorViewport : public Control {
TRANSFORM_ROTATE,
TRANSFORM_TRANSLATE,
TRANSFORM_SCALE

};
enum TransformPlane {
TRANSFORM_VIEW,
Expand Down

0 comments on commit 2919e2e

Please sign in to comment.