1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-26 15:46:23 +00:00

Editor: Improve capsule gizmos

This commit is contained in:
HolonProduction
2025-02-01 16:34:03 +01:00
parent 4b36c0491e
commit 02eab5e2c4
4 changed files with 64 additions and 63 deletions

View File

@@ -115,7 +115,7 @@ String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g
} }
if (Object::cast_to<CapsuleShape3D>(*s)) { if (Object::cast_to<CapsuleShape3D>(*s)) {
return p_id == 0 ? "Radius" : "Height"; return helper->capsule_get_handle_name(p_id);
} }
if (Object::cast_to<CylinderShape3D>(*s)) { if (Object::cast_to<CylinderShape3D>(*s)) {
@@ -154,7 +154,7 @@ Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p
if (Object::cast_to<CylinderShape3D>(*s)) { if (Object::cast_to<CylinderShape3D>(*s)) {
Ref<CylinderShape3D> cs2 = s; Ref<CylinderShape3D> cs2 = s;
return p_id == 0 ? cs2->get_radius() : cs2->get_height(); return Vector2(cs2->get_radius(), cs2->get_height());
} }
if (Object::cast_to<SeparationRayShape3D>(*s)) { if (Object::cast_to<SeparationRayShape3D>(*s)) {
@@ -222,26 +222,15 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
} }
if (Object::cast_to<CapsuleShape3D>(*s)) { if (Object::cast_to<CapsuleShape3D>(*s)) {
Vector3 axis;
axis[p_id == 0 ? 0 : 1] = 1.0;
Ref<CapsuleShape3D> cs2 = s; Ref<CapsuleShape3D> cs2 = s;
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
if (Node3DEditor::get_singleton()->is_snap_enabled()) { real_t height = cs2->get_height();
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); real_t radius = cs2->get_radius();
} Vector3 position;
helper->capsule_set_handle(sg, p_id, height, radius, position);
if (d < 0.001) { cs2->set_height(height);
d = 0.001; cs2->set_radius(radius);
} cs->set_global_position(position);
if (p_id == 0) {
cs2->set_radius(d);
} else if (p_id == 1) {
cs2->set_height(d * 2.0);
}
} }
if (Object::cast_to<CylinderShape3D>(*s)) { if (Object::cast_to<CylinderShape3D>(*s)) {
@@ -285,26 +274,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
if (Object::cast_to<CapsuleShape3D>(*s)) { if (Object::cast_to<CapsuleShape3D>(*s)) {
Ref<CapsuleShape3D> ss = s; Ref<CapsuleShape3D> ss = s;
Vector2 values = p_restore; helper->cylinder_commit_handle(p_id, TTR("Change Capsule Shape Radius"), TTR("Change Capsule Shape Height"), p_cancel, cs, *ss, *ss);
if (p_cancel) {
ss->set_radius(values[0]);
ss->set_height(values[1]);
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Capsule Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
} else {
ur->create_action(TTR("Change Capsule Shape Height"));
ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
}
ur->add_undo_method(ss.ptr(), "set_radius", values[0]);
ur->add_undo_method(ss.ptr(), "set_height", values[1]);
ur->commit_action();
} }
if (Object::cast_to<CylinderShape3D>(*s)) { if (Object::cast_to<CylinderShape3D>(*s)) {
@@ -547,10 +517,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(points, material, false, collision_color); p_gizmo->add_lines(points, material, false, collision_color);
p_gizmo->add_collision_segments(points); p_gizmo->add_collision_segments(points);
Vector<Vector3> handles = { Vector<Vector3> handles = helper->capsule_get_handles(cs2->get_height(), cs2->get_radius());
Vector3(cs2->get_radius(), 0, 0),
Vector3(0, cs2->get_height() * 0.5, 0)
};
p_gizmo->add_handles(handles, handles_material); p_gizmo->add_handles(handles, handles_material);
} }

View File

@@ -156,7 +156,10 @@ String Gizmo3DHelper::cylinder_get_handle_name(int p_id) const {
} }
} }
void Gizmo3DHelper::cylinder_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position) { void Gizmo3DHelper::_cylinder_or_capsule_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position, bool p_is_capsule) {
real_t initial_radius = initial_value.operator Vector2().x;
real_t initial_height = initial_value.operator Vector2().y;
int sign = p_id == 2 ? -1 : 1; int sign = p_id == 2 ? -1 : 1;
int axis = p_id == 0 ? 0 : 1; int axis = p_id == 0 ? 0 : 1;
@@ -178,9 +181,13 @@ void Gizmo3DHelper::cylinder_set_handle(const Vector3 p_segment[2], int p_id, re
} }
r_radius = d; r_radius = d;
r_cylinder_position = initial_transform.get_origin(); r_cylinder_position = initial_transform.get_origin();
} else if (p_id == 1 || p_id == 2) {
real_t initial_height = initial_value;
if (p_is_capsule) {
r_height = MAX(initial_height, r_radius * 2.0);
} else {
r_height = initial_height;
}
} else if (p_id == 1 || p_id == 2) {
// Adjust height. // Adjust height.
if (Input::get_singleton()->is_key_pressed(Key::ALT)) { if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
r_height = d * 2.0; r_height = d * 2.0;
@@ -200,6 +207,12 @@ void Gizmo3DHelper::cylinder_set_handle(const Vector3 p_segment[2], int p_id, re
offset[axis] = (r_height - initial_height) * 0.5 * sign; offset[axis] = (r_height - initial_height) * 0.5 * sign;
r_cylinder_position = initial_transform.xform(offset); r_cylinder_position = initial_transform.xform(offset);
} }
if (p_is_capsule) {
r_radius = MIN(initial_radius, r_height / 2.0);
} else {
r_radius = initial_radius;
}
} }
} }
@@ -212,25 +225,19 @@ void Gizmo3DHelper::cylinder_commit_handle(int p_id, const String &p_radius_acti
} }
if (p_cancel) { if (p_cancel) {
if (p_id == 0) { p_radius_object->set(p_radius_property, initial_value.operator Vector2().x);
p_radius_object->set(p_radius_property, initial_value); p_height_object->set(p_height_property, initial_value.operator Vector2().y);
} else {
p_height_object->set(p_height_property, initial_value);
}
p_position_object->set(p_position_property, initial_transform.get_origin()); p_position_object->set(p_position_property, initial_transform.get_origin());
return; return;
} }
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(p_id == 0 ? p_radius_action_name : p_height_action_name); ur->create_action(p_id == 0 ? p_radius_action_name : p_height_action_name);
if (p_id == 0) { ur->add_do_property(p_radius_object, p_radius_property, p_radius_object->get(p_radius_property));
ur->add_do_property(p_radius_object, p_radius_property, p_radius_object->get(p_radius_property)); ur->add_undo_property(p_radius_object, p_radius_property, initial_value.operator Vector2().x);
ur->add_undo_property(p_radius_object, p_radius_property, initial_value); ur->add_do_property(p_height_object, p_height_property, p_height_object->get(p_height_property));
} else { ur->add_undo_property(p_height_object, p_height_property, initial_value.operator Vector2().y);
ur->add_do_property(p_height_object, p_height_property, p_height_object->get(p_height_property)); ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property));
ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property)); ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin());
ur->add_undo_property(p_height_object, p_height_property, initial_value);
ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin());
}
ur->commit_action(); ur->commit_action();
} }

View File

@@ -41,17 +41,44 @@ class Gizmo3DHelper : public RefCounted {
Variant initial_value; Variant initial_value;
Transform3D initial_transform; Transform3D initial_transform;
private:
void _cylinder_or_capsule_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position, bool p_is_capsule);
public: public:
/**
* Initializes a new action involving a handle.
*
* Depending on the type of gizmo that will be used, different formats for the `p_initial_value` are required:
* Box: The size of the box as `Vector3`
* Cylinder or Capsule: A `Vector2` of the form `Vector2(radius, height)`
*/
void initialize_handle_action(const Variant &p_initial_value, const Transform3D &p_initial_transform); void initialize_handle_action(const Variant &p_initial_value, const Transform3D &p_initial_transform);
void get_segment(Camera3D *p_camera, const Point2 &p_point, Vector3 *r_segment); void get_segment(Camera3D *p_camera, const Point2 &p_point, Vector3 *r_segment);
// Box
Vector<Vector3> box_get_handles(const Vector3 &p_box_size); Vector<Vector3> box_get_handles(const Vector3 &p_box_size);
String box_get_handle_name(int p_id) const; String box_get_handle_name(int p_id) const;
void box_set_handle(const Vector3 p_segment[2], int p_id, Vector3 &r_box_size, Vector3 &r_box_position); void box_set_handle(const Vector3 p_segment[2], int p_id, Vector3 &r_box_size, Vector3 &r_box_position);
void box_commit_handle(const String &p_action_name, bool p_cancel, Object *p_position_object, Object *p_size_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_size_property = "size"); void box_commit_handle(const String &p_action_name, bool p_cancel, Object *p_position_object, Object *p_size_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_size_property = "size");
// Cylinder
Vector<Vector3> cylinder_get_handles(real_t p_height, real_t p_radius); Vector<Vector3> cylinder_get_handles(real_t p_height, real_t p_radius);
String cylinder_get_handle_name(int p_id) const; String cylinder_get_handle_name(int p_id) const;
void cylinder_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position); _FORCE_INLINE_ void cylinder_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position) {
_cylinder_or_capsule_set_handle(p_segment, p_id, r_height, r_radius, r_cylinder_position, false);
}
void cylinder_commit_handle(int p_id, const String &p_radius_action_name, const String &p_height_action_name, bool p_cancel, Object *p_position_object, Object *p_height_object = nullptr, Object *p_radius_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_height_property = "height", const StringName &p_radius_property = "radius"); void cylinder_commit_handle(int p_id, const String &p_radius_action_name, const String &p_height_action_name, bool p_cancel, Object *p_position_object, Object *p_height_object = nullptr, Object *p_radius_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_height_property = "height", const StringName &p_radius_property = "radius");
// Capsule
_FORCE_INLINE_ Vector<Vector3> capsule_get_handles(real_t p_height, real_t p_radius) { return cylinder_get_handles(p_height, p_radius); }
_FORCE_INLINE_ String capsule_get_handle_name(int p_id) { return cylinder_get_handle_name(p_id); }
_FORCE_INLINE_ void capsule_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_capsule_position) {
_cylinder_or_capsule_set_handle(p_segment, p_id, r_height, r_radius, r_capsule_position, true);
}
_FORCE_INLINE_ void capsule_commit_handle(int p_id, const String &p_radius_action_name, const String &p_height_action_name, bool p_cancel, Object *p_position_object, Object *p_height_object = nullptr, Object *p_radius_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_height_property = "height", const StringName &p_radius_property = "radius") {
cylinder_commit_handle(p_id, p_radius_action_name, p_height_action_name, p_cancel, p_position_object, p_height_object, p_radius_object, p_position_property, p_height_property, p_radius_property);
}
}; };

View File

@@ -222,7 +222,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo
if (Object::cast_to<CSGCylinder3D>(cs)) { if (Object::cast_to<CSGCylinder3D>(cs)) {
CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs); CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs);
return p_id == 0 ? s->get_radius() : s->get_height(); return Vector2(s->get_radius(), s->get_height());
} }
if (Object::cast_to<CSGTorus3D>(cs)) { if (Object::cast_to<CSGTorus3D>(cs)) {