Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
128 changes: 118 additions & 10 deletions editor/scene/3d/path_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,29 @@ void Path3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camera, con
Vector3 inters;
// Special case for primary handle, the handle id equals control point 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.
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
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 (Node3DEditor::get_singleton()->is_snap_enabled()) {
float snap = Node3DEditor::get_singleton()->get_translate_snap();
Expand Down Expand Up @@ -417,6 +440,8 @@ void Path3DGizmo::redraw() {

_secondary_handles_info.resize(c->get_point_count() * 3);

const float disk_size = EDITOR_GET("editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size");

for (int idx = 0; idx < c->get_point_count(); idx++) {
// Collect primary-handles.
const Vector3 pos = c->get_point_position(idx);
Expand Down Expand Up @@ -547,9 +572,8 @@ void Path3DGizmo::_update_transform_gizmo() {
Node3DEditor::get_singleton()->update_transform_gizmo();
}

Path3DGizmo::Path3DGizmo(Path3D *p_path, float p_disk_size) {
Path3DGizmo::Path3DGizmo(Path3D *p_path) {
path = p_path;
disk_size = p_disk_size;
set_node_3d(p_path);
orig_in_length = 0;
orig_out_length = 0;
Expand Down Expand Up @@ -676,10 +700,21 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
} else {
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_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;
Comment thread
Arctis-Fireblight marked this conversation as resolved.
}

Plane p(p_camera->get_transform().basis.get_column(2), origin);

Vector3 inters;
if (p.intersects_ray(ray_from, ray_dir, &inters)) {
ur->create_action(TTR("Add Point to Curve"));
Expand All @@ -693,6 +728,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
}

} else if (mb->is_pressed() && ((mb->get_button_index() == MouseButton::LEFT && curve_del->is_pressed()) || (mb->get_button_index() == MouseButton::RIGHT && curve_edit->is_pressed()))) {
const float disk_size = EDITOR_GET("editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size");
for (int i = 0; i < c->get_point_count(); i++) {
real_t dist_to_p = viewport->point_to_screen(gt.xform(c->get_point_position(i))).distance_to(mbpos);
real_t dist_to_p_out = viewport->point_to_screen(gt.xform(c->get_point_position(i) + c->get_point_out(i))).distance_to(mbpos);
Expand Down Expand Up @@ -755,7 +791,7 @@ void Path3DEditorPlugin::edit(Object *p_object) {
}

update_overlays();
//collision_polygon_editor->edit(Object::cast_to<Node>(p_object));
// collision_polygon_editor->edit(Object::cast_to<Node>(p_object));
}

bool Path3DEditorPlugin::handles(Object *p_object) const {
Expand All @@ -776,6 +812,8 @@ void Path3DEditorPlugin::make_visible(bool p_visible) {
}
}
}

set_physics_process(p_visible);
}

void Path3DEditorPlugin::_mode_changed(int p_mode) {
Expand Down Expand Up @@ -819,6 +857,11 @@ void Path3DEditorPlugin::_handle_option_pressed(int p_option) {
mirror_handle_length = !is_checked;
pm->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
} 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;
}
}

Expand Down Expand Up @@ -905,14 +948,78 @@ void Path3DEditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("_restore_curve_points"), &Path3DEditorPlugin::_restore_curve_points);
}

void Path3DEditorPlugin::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
if (!path) {
return;
}

if (!EditorSettings::get_singleton()->check_changed_settings_in_group("editors/3d_gizmos/gizmo_settings")) {
return;
}

path->update_gizmos();
} 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;
}
}
}
}

Path3DEditorPlugin::Path3DEditorPlugin() {
singleton = this;
mirror_handle_angle = true;
mirror_handle_length = true;

disk_size = EDITOR_GET("editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size");

Ref<Path3DGizmoPlugin> gizmo_plugin = memnew(Path3DGizmoPlugin(disk_size));
Ref<Path3DGizmoPlugin> gizmo_plugin;
gizmo_plugin.instantiate();
Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
path_3d_gizmo_plugin = gizmo_plugin;

Expand Down Expand Up @@ -1002,6 +1109,8 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
menu->add_check_item(TTR("Mirror Handle Lengths"));
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));

curve_edit->set_pressed_no_signal(true);
Expand All @@ -1015,7 +1124,7 @@ Ref<EditorNode3DGizmo> Path3DGizmoPlugin::create_gizmo(Node3D *p_spatial) {

Path3D *path = Object::cast_to<Path3D>(p_spatial);
if (path) {
ref.instantiate(path, disk_size);
ref.instantiate(path);
}

return ref;
Expand Down Expand Up @@ -1193,10 +1302,9 @@ int Path3DGizmoPlugin::get_priority() const {
return -1;
}

Path3DGizmoPlugin::Path3DGizmoPlugin(float p_disk_size) {
Path3DGizmoPlugin::Path3DGizmoPlugin() {
Color path_color = SceneTree::get_singleton()->get_debug_paths_color();
Color path_tilt_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/path_tilt");
disk_size = p_disk_size;

create_material("path_material", path_color);
create_material("path_thin_material", Color(0.6, 0.6, 0.6));
Expand Down
30 changes: 22 additions & 8 deletions editor/scene/3d/path_3d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ class Path3DGizmo : public EditorNode3DGizmo {
mutable Vector3 original;
mutable float orig_in_length;
mutable float orig_out_length;
mutable float disk_size = 0.8;

/// Index that should have swapped control points for achieving an outwards curve.
int swapped_control_points_idx = -1;
Expand All @@ -85,14 +84,12 @@ class Path3DGizmo : public EditorNode3DGizmo {
virtual void commit_handle(int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;

virtual void redraw() override;
Path3DGizmo(Path3D *p_path = nullptr, float p_disk_size = 0.8);
Path3DGizmo(Path3D *p_path = nullptr);
};

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

float disk_size = 0.8;

/// Locking basis is meant to ensure a predictable behavior during translation of the curve points in "local space transform mode".
/// Without the locking, the gizmo/point, in "local space transform mode", wouldn't follow a straight path and would curve and twitch in an unpredictable way.
HashMap<int, Basis> transformation_locked_basis;
Expand All @@ -113,7 +110,7 @@ class Path3DGizmoPlugin : public EditorNode3DGizmoPlugin {
virtual void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel = false) override;

int get_priority() const override;
Path3DGizmoPlugin(float p_disk_size);
Path3DGizmoPlugin();
};

class Path3DEditorPlugin : public EditorPlugin {
Expand All @@ -139,8 +136,6 @@ class Path3DEditorPlugin : public EditorPlugin {
Button *create_curve_button = nullptr;
ConfirmationDialog *clear_points_dialog = nullptr;

float disk_size = 0.8;

enum Mode {
MODE_CREATE,
MODE_EDIT,
Expand All @@ -161,6 +156,7 @@ class Path3DEditorPlugin : public EditorPlugin {
bool handle_clicked = false;
bool mirror_handle_angle = true;
bool mirror_handle_length = true;
bool snap_to_collider = true;

void _create_curve();
void _confirm_clear_points();
Expand All @@ -170,10 +166,12 @@ class Path3DEditorPlugin : public EditorPlugin {

enum HandleOption {
HANDLE_OPTION_ANGLE,
HANDLE_OPTION_LENGTH
HANDLE_OPTION_LENGTH,
HANDLE_OPTION_SNAP_COLLIDER,
};

protected:
virtual void _notification(int p_what);
static void _bind_methods();

public:
Expand All @@ -194,4 +192,20 @@ class Path3DEditorPlugin : public EditorPlugin {
void set_handle_clicked(bool clicked) { handle_clicked = clicked; }

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;
};
2 changes: 1 addition & 1 deletion editor/settings/editor_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/ik_chain", Color(0.6, 0.9, 0.8), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
_initial_set("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.1);
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d_gizmos/gizmo_settings/bone_shape", 1, "Wire,Octahedron");
EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size", 0.8, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size", 0.8, "", PROPERTY_USAGE_DEFAULT)
EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d_gizmos/gizmo_settings/lightmap_gi_probe_size", 0.4, "0.0,1.0,0.001,or_greater", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)

// If a line is a multiple of this, it uses the primary grid color.
Expand Down
Loading