mirror of
https://github.com/godotengine/godot.git
synced 2026-02-07 19:32:36 +00:00
Merge pull request #102085 from GustJc/path3d_snap_collider
Add option for `Path3D` to snap to colliders
This commit is contained in:
@@ -114,6 +114,29 @@ void Path3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camera, con
|
|||||||
Vector3 inters;
|
Vector3 inters;
|
||||||
// Special case for primary handle, the handle id equals control point id.
|
// Special case for primary handle, the handle id equals control point id.
|
||||||
const int idx = p_id;
|
const int idx = p_id;
|
||||||
|
if (!Path3DEditorPlugin::singleton->_edit.waiting_handle_physics || !Path3DEditorPlugin::singleton->_edit.in_physics_frame) {
|
||||||
|
Path3DEditorPlugin::singleton->_edit.waiting_handle_physics = true;
|
||||||
|
Path3DEditorPlugin::singleton->_edit.gizmo_handle = p_id;
|
||||||
|
Path3DEditorPlugin::singleton->_edit.gizmo_handle_secondary = p_secondary;
|
||||||
|
Path3DEditorPlugin::singleton->_edit.gizmo_camera = p_camera;
|
||||||
|
Path3DEditorPlugin::singleton->_edit.mouse_pos = p_point;
|
||||||
|
return;
|
||||||
|
// Only continue if inside physics frame and waiting for physics.
|
||||||
|
}
|
||||||
|
if (Path3DEditorPlugin::singleton->snap_to_collider) {
|
||||||
|
PhysicsDirectSpaceState3D *ss = p_camera->get_world_3d()->get_direct_space_state();
|
||||||
|
|
||||||
|
PhysicsDirectSpaceState3D::RayParameters ray_params;
|
||||||
|
ray_params.from = ray_from;
|
||||||
|
ray_params.to = ray_from + ray_dir * p_camera->get_far();
|
||||||
|
PhysicsDirectSpaceState3D::RayResult result;
|
||||||
|
if (ss->intersect_ray(ray_params, result)) {
|
||||||
|
Vector3 local = gi.xform(result.position);
|
||||||
|
c->set_point_position(idx, local);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Will continue and do the plane intersect_ray if doesn't hit anything.
|
||||||
|
}
|
||||||
if (p.intersects_ray(ray_from, ray_dir, &inters)) {
|
if (p.intersects_ray(ray_from, ray_dir, &inters)) {
|
||||||
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
|
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
|
||||||
float snap = Node3DEditor::get_singleton()->get_translate_snap();
|
float snap = Node3DEditor::get_singleton()->get_translate_snap();
|
||||||
@@ -669,10 +692,21 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
|
|||||||
} else {
|
} else {
|
||||||
origin = gt.xform(c->get_point_position(c->get_point_count() - 1));
|
origin = gt.xform(c->get_point_position(c->get_point_count() - 1));
|
||||||
}
|
}
|
||||||
Plane p(p_camera->get_transform().basis.get_column(2), origin);
|
|
||||||
Vector3 ray_from = viewport->get_ray_pos(mbpos);
|
Vector3 ray_from = viewport->get_ray_pos(mbpos);
|
||||||
Vector3 ray_dir = viewport->get_ray(mbpos);
|
Vector3 ray_dir = viewport->get_ray(mbpos);
|
||||||
|
|
||||||
|
if (snap_to_collider) {
|
||||||
|
_edit.click_ray_pos = ray_from;
|
||||||
|
_edit.click_ray_dir = ray_dir * p_camera->get_far();
|
||||||
|
_edit.gizmo_camera = p_camera;
|
||||||
|
_edit.origin = origin;
|
||||||
|
_edit.waiting_point_physics = true;
|
||||||
|
return EditorPlugin::AFTER_GUI_INPUT_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
Plane p(p_camera->get_transform().basis.get_column(2), origin);
|
||||||
|
|
||||||
Vector3 inters;
|
Vector3 inters;
|
||||||
if (p.intersects_ray(ray_from, ray_dir, &inters)) {
|
if (p.intersects_ray(ray_from, ray_dir, &inters)) {
|
||||||
ur->create_action(TTR("Add Point to Curve"));
|
ur->create_action(TTR("Add Point to Curve"));
|
||||||
@@ -748,6 +782,7 @@ void Path3DEditorPlugin::make_visible(bool p_visible) {
|
|||||||
topmenu_bar->hide();
|
topmenu_bar->hide();
|
||||||
path = nullptr;
|
path = nullptr;
|
||||||
}
|
}
|
||||||
|
set_physics_process(p_visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Path3DEditorPlugin::_mode_changed(int p_mode) {
|
void Path3DEditorPlugin::_mode_changed(int p_mode) {
|
||||||
@@ -791,6 +826,11 @@ void Path3DEditorPlugin::_handle_option_pressed(int p_option) {
|
|||||||
mirror_handle_length = !is_checked;
|
mirror_handle_length = !is_checked;
|
||||||
pm->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
|
pm->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
|
||||||
} break;
|
} break;
|
||||||
|
case HANDLE_OPTION_SNAP_COLLIDER: {
|
||||||
|
bool is_checked = pm->is_item_checked(HANDLE_OPTION_SNAP_COLLIDER);
|
||||||
|
snap_to_collider = !is_checked;
|
||||||
|
pm->set_item_checked(HANDLE_OPTION_SNAP_COLLIDER, snap_to_collider);
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -884,6 +924,55 @@ void Path3DEditorPlugin::_notification(int p_what) {
|
|||||||
|
|
||||||
path->update_gizmos();
|
path->update_gizmos();
|
||||||
} break;
|
} break;
|
||||||
|
case NOTIFICATION_PHYSICS_PROCESS: {
|
||||||
|
if (_edit.waiting_point_physics) {
|
||||||
|
_edit.waiting_point_physics = false;
|
||||||
|
const Transform3D gt = path->get_global_transform();
|
||||||
|
const Transform3D it = gt.affine_inverse();
|
||||||
|
Ref<Curve3D> c = path->get_curve();
|
||||||
|
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
|
||||||
|
PhysicsDirectSpaceState3D *ss = get_tree()->get_root()->get_world_3d()->get_direct_space_state();
|
||||||
|
if (ss) {
|
||||||
|
PhysicsDirectSpaceState3D::RayParameters ray_params;
|
||||||
|
PhysicsDirectSpaceState3D::RayResult result;
|
||||||
|
ray_params.from = _edit.click_ray_pos;
|
||||||
|
ray_params.to = ray_params.from + _edit.click_ray_dir;
|
||||||
|
bool hit_something = false;
|
||||||
|
Vector3 inters;
|
||||||
|
if (ss->intersect_ray(ray_params, result)) {
|
||||||
|
inters = result.position;
|
||||||
|
hit_something = true;
|
||||||
|
} else {
|
||||||
|
Plane p(_edit.gizmo_camera->get_transform().basis.get_column(2), _edit.origin);
|
||||||
|
if (p.intersects_ray(ray_params.from, _edit.click_ray_dir, &inters)) {
|
||||||
|
hit_something = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hit_something) {
|
||||||
|
ur->create_action(TTR("Add Point to Curve"));
|
||||||
|
ur->add_do_method(c.ptr(), "add_point", it.xform(inters), Vector3(), Vector3(), -1);
|
||||||
|
ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
|
||||||
|
ur->commit_action();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_edit.waiting_handle_physics) {
|
||||||
|
_edit.in_physics_frame = true;
|
||||||
|
|
||||||
|
// Find gizmo reference.
|
||||||
|
Vector<Ref<Node3DGizmo>> gizmos = path->get_gizmos();
|
||||||
|
for (Ref<EditorNode3DGizmo> seg : gizmos) {
|
||||||
|
if (seg.is_valid()) {
|
||||||
|
_edit.gizmo = seg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_edit.gizmo->set_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_camera, _edit.mouse_pos);
|
||||||
|
_edit.in_physics_frame = false;
|
||||||
|
_edit.waiting_handle_physics = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -989,6 +1078,8 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
|
|||||||
menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
|
menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
|
||||||
menu->add_check_item(TTR("Mirror Handle Lengths"));
|
menu->add_check_item(TTR("Mirror Handle Lengths"));
|
||||||
menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
|
menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
|
||||||
|
menu->add_check_item(TTR("Snap to Colliders"));
|
||||||
|
menu->set_item_checked(HANDLE_OPTION_SNAP_COLLIDER, snap_to_collider);
|
||||||
menu->connect(SceneStringName(id_pressed), callable_mp(this, &Path3DEditorPlugin::_handle_option_pressed));
|
menu->connect(SceneStringName(id_pressed), callable_mp(this, &Path3DEditorPlugin::_handle_option_pressed));
|
||||||
|
|
||||||
curve_edit->set_pressed_no_signal(true);
|
curve_edit->set_pressed_no_signal(true);
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ class Path3DEditorPlugin : public EditorPlugin {
|
|||||||
bool handle_clicked = false;
|
bool handle_clicked = false;
|
||||||
bool mirror_handle_angle = true;
|
bool mirror_handle_angle = true;
|
||||||
bool mirror_handle_length = true;
|
bool mirror_handle_length = true;
|
||||||
|
bool snap_to_collider = true;
|
||||||
|
|
||||||
void _create_curve();
|
void _create_curve();
|
||||||
void _confirm_clear_points();
|
void _confirm_clear_points();
|
||||||
@@ -157,7 +158,8 @@ class Path3DEditorPlugin : public EditorPlugin {
|
|||||||
|
|
||||||
enum HandleOption {
|
enum HandleOption {
|
||||||
HANDLE_OPTION_ANGLE,
|
HANDLE_OPTION_ANGLE,
|
||||||
HANDLE_OPTION_LENGTH
|
HANDLE_OPTION_LENGTH,
|
||||||
|
HANDLE_OPTION_SNAP_COLLIDER,
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -182,4 +184,20 @@ public:
|
|||||||
void set_handle_clicked(bool clicked) { handle_clicked = clicked; }
|
void set_handle_clicked(bool clicked) { handle_clicked = clicked; }
|
||||||
|
|
||||||
Path3DEditorPlugin();
|
Path3DEditorPlugin();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct EditData {
|
||||||
|
Vector3 click_ray_dir;
|
||||||
|
Vector3 click_ray_pos;
|
||||||
|
Vector3 origin;
|
||||||
|
Point2 mouse_pos;
|
||||||
|
bool show_rotation_line = false;
|
||||||
|
Ref<Path3DGizmo> gizmo;
|
||||||
|
int gizmo_handle = 0;
|
||||||
|
bool gizmo_handle_secondary = false;
|
||||||
|
Camera3D *gizmo_camera;
|
||||||
|
bool waiting_point_physics = false;
|
||||||
|
bool waiting_handle_physics = false;
|
||||||
|
bool in_physics_frame = false;
|
||||||
|
} _edit;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user