mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 07:53:26 +00:00
Merge pull request #108576 from ryevdokimov/gizmo-rotation-arc
Create a rotation arc showing accumulated rotation when using transform gizmo
This commit is contained in:
commit
70b6fa1525
2 changed files with 157 additions and 14 deletions
|
@ -541,6 +541,10 @@ void Node3DEditorViewport::_update_navigation_controls_visibility() {
|
|||
look_control->set_visible(show_viewport_navigation_gizmo);
|
||||
}
|
||||
|
||||
bool Node3DEditorViewport::_is_rotation_arc_visible() const {
|
||||
return _edit.mode == TRANSFORM_ROTATE && _edit.accumulated_rotation_angle != 0.0 && _edit.gizmo_initiated;
|
||||
}
|
||||
|
||||
void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
|
||||
bool is_orthogonal = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL;
|
||||
|
||||
|
@ -1420,6 +1424,9 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
|
|||
_edit.mode = TRANSFORM_ROTATE;
|
||||
_compute_edit(p_screenpos);
|
||||
_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis);
|
||||
_edit.accumulated_rotation_angle = 0.0;
|
||||
_edit.rotation_axis = gt.basis.get_column(col_axis).normalized();
|
||||
_edit.gizmo_initiated = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -3535,7 +3542,7 @@ void Node3DEditorViewport::_draw() {
|
|||
font->draw_string(ci, msgpos, message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
if (_edit.mode == TRANSFORM_ROTATE && _edit.show_rotation_line) {
|
||||
if (_edit.mode == TRANSFORM_ROTATE) {
|
||||
Point2 center = point_to_screen(_edit.center);
|
||||
|
||||
Color handle_color;
|
||||
|
@ -3553,14 +3560,110 @@ void Node3DEditorViewport::_draw() {
|
|||
handle_color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
|
||||
break;
|
||||
}
|
||||
handle_color = handle_color.from_hsv(handle_color.get_h(), 0.25, 1.0, 1);
|
||||
|
||||
RenderingServer::get_singleton()->canvas_item_add_line(
|
||||
ci,
|
||||
_edit.mouse_pos,
|
||||
center,
|
||||
handle_color,
|
||||
Math::round(2 * EDSCALE));
|
||||
if (_is_rotation_arc_visible() && !_edit.initial_click_vector.is_zero_approx()) {
|
||||
Vector3 up = _edit.rotation_axis;
|
||||
Vector3 right = _edit.initial_click_vector;
|
||||
|
||||
right = right - up * up.dot(right);
|
||||
right.normalize();
|
||||
Vector3 forward = up.cross(right);
|
||||
|
||||
const int circle_segments = 64;
|
||||
Vector<Point2> circle_points;
|
||||
for (int i = 0; i <= circle_segments; i++) {
|
||||
float angle = (float(i) / float(circle_segments)) * Math::TAU;
|
||||
Vector3 point_3d = _edit.center + gizmo_scale * GIZMO_CIRCLE_SIZE * (right * Math::cos(angle) + forward * Math::sin(angle));
|
||||
Point2 point_2d = point_to_screen(point_3d);
|
||||
circle_points.push_back(point_2d);
|
||||
}
|
||||
|
||||
Color circle_color = handle_color.from_hsv(handle_color.get_h(), 0.6, 1.0, 0.8);
|
||||
for (int i = 0; i < circle_points.size() - 1; i++) {
|
||||
RenderingServer::get_singleton()->canvas_item_add_line(
|
||||
ci,
|
||||
circle_points[i],
|
||||
circle_points[i + 1],
|
||||
circle_color,
|
||||
Math::round(2 * EDSCALE));
|
||||
}
|
||||
|
||||
const int segments = 64;
|
||||
float display_angle = _edit.display_rotation_angle;
|
||||
|
||||
float abs_angle = Math::abs(display_angle);
|
||||
if (abs_angle > Math::TAU) {
|
||||
float remainder = Math::fmod((double)abs_angle, Math::TAU);
|
||||
remainder = remainder < 0.01 ? Math::TAU : remainder;
|
||||
display_angle = SIGN(display_angle) * remainder;
|
||||
abs_angle = remainder;
|
||||
}
|
||||
|
||||
int num_segments = MAX(8, int(abs_angle / (Math::TAU / segments) * segments));
|
||||
num_segments = MIN(num_segments, segments);
|
||||
|
||||
Color fill_color = Color(1.0, 1.0, 1.0, 0.2);
|
||||
|
||||
bool is_counterclockwise = display_angle > 0;
|
||||
float start_angle = is_counterclockwise ? 0.0f : display_angle;
|
||||
float end_angle = is_counterclockwise ? display_angle : 0.0f;
|
||||
|
||||
for (int i = 0; i < num_segments; i++) {
|
||||
float t1 = float(i) / float(num_segments);
|
||||
float t2 = float(i + 1) / float(num_segments);
|
||||
float angle1 = Math::lerp(start_angle, end_angle, t1);
|
||||
float angle2 = Math::lerp(start_angle, end_angle, t2);
|
||||
|
||||
Vector3 point1_3d = _edit.center + gizmo_scale * GIZMO_CIRCLE_SIZE * (right * Math::cos(angle1) + forward * Math::sin(angle1));
|
||||
Vector3 point2_3d = _edit.center + gizmo_scale * GIZMO_CIRCLE_SIZE * (right * Math::cos(angle2) + forward * Math::sin(angle2));
|
||||
|
||||
Point2 center_2d = center;
|
||||
Point2 point1_2d = point_to_screen(point1_3d);
|
||||
Point2 point2_2d = point_to_screen(point2_3d);
|
||||
|
||||
Vector<Point2> triangle_points;
|
||||
triangle_points.push_back(center_2d);
|
||||
triangle_points.push_back(point1_2d);
|
||||
triangle_points.push_back(point2_2d);
|
||||
|
||||
Vector<Color> triangle_colors;
|
||||
triangle_colors.push_back(fill_color);
|
||||
triangle_colors.push_back(fill_color);
|
||||
triangle_colors.push_back(fill_color);
|
||||
|
||||
RenderingServer::get_singleton()->canvas_item_add_polygon(ci, triangle_points, triangle_colors);
|
||||
}
|
||||
|
||||
Color edge_color = handle_color.from_hsv(handle_color.get_h(), 0.8, 1.0, 0.7);
|
||||
|
||||
Vector3 start_point_3d = _edit.center + gizmo_scale * GIZMO_CIRCLE_SIZE * right;
|
||||
Point2 start_point_2d = point_to_screen(start_point_3d);
|
||||
RenderingServer::get_singleton()->canvas_item_add_line(
|
||||
ci,
|
||||
center,
|
||||
start_point_2d,
|
||||
edge_color,
|
||||
Math::round(2 * EDSCALE));
|
||||
|
||||
Vector3 end_point_3d = _edit.center + gizmo_scale * GIZMO_CIRCLE_SIZE * (right * Math::cos(display_angle) + forward * Math::sin(display_angle));
|
||||
Point2 end_point_2d = point_to_screen(end_point_3d);
|
||||
RenderingServer::get_singleton()->canvas_item_add_line(
|
||||
ci,
|
||||
center,
|
||||
end_point_2d,
|
||||
edge_color,
|
||||
Math::round(2 * EDSCALE));
|
||||
}
|
||||
|
||||
if (_edit.show_rotation_line) {
|
||||
handle_color = handle_color.from_hsv(handle_color.get_h(), 0.25, 1.0, 1);
|
||||
RenderingServer::get_singleton()->canvas_item_add_line(
|
||||
ci,
|
||||
_edit.mouse_pos,
|
||||
center,
|
||||
handle_color,
|
||||
Math::round(2 * EDSCALE));
|
||||
}
|
||||
}
|
||||
if (previewing) {
|
||||
Size2 ss = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
|
||||
|
@ -4298,7 +4401,9 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
|
|||
return;
|
||||
}
|
||||
|
||||
bool show_gizmo = spatial_editor->is_gizmo_visible() && !_edit.instant && transform_gizmo_visible && !collision_reposition;
|
||||
bool hide_during_rotation = _is_rotation_arc_visible();
|
||||
|
||||
bool show_gizmo = spatial_editor->is_gizmo_visible() && !_edit.instant && transform_gizmo_visible && !collision_reposition && !hide_during_rotation;
|
||||
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) {
|
||||
|
@ -4311,7 +4416,8 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
|
|||
RenderingServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], axis_angle);
|
||||
RenderingServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE));
|
||||
RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], axis_angle);
|
||||
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE));
|
||||
bool show_rotate_gizmo = show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE);
|
||||
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], show_rotate_gizmo);
|
||||
RenderingServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], axis_angle);
|
||||
RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE));
|
||||
RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], axis_angle);
|
||||
|
@ -4329,7 +4435,8 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
|
|||
xform.orthonormalize();
|
||||
xform.basis.scale(scale);
|
||||
RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform);
|
||||
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && !_edit.instant && transform_gizmo_visible && !collision_reposition && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE));
|
||||
bool show_white_outline = spatial_editor->is_gizmo_visible() && !_edit.instant && transform_gizmo_visible && !collision_reposition && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE);
|
||||
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], show_white_outline && !hide_during_rotation);
|
||||
}
|
||||
|
||||
void Node3DEditorViewport::set_state(const Dictionary &p_state) {
|
||||
|
@ -5257,6 +5364,11 @@ void Node3DEditorViewport::begin_transform(TransformMode p_mode, bool instant) {
|
|||
_compute_edit(_edit.mouse_pos);
|
||||
_edit.instant = instant;
|
||||
_edit.snap = spatial_editor->is_snap_enabled();
|
||||
_edit.initial_click_vector = Vector3();
|
||||
_edit.previous_rotation_vector = Vector3();
|
||||
_edit.accumulated_rotation_angle = 0.0;
|
||||
_edit.display_rotation_angle = 0.0;
|
||||
_edit.gizmo_initiated = false;
|
||||
update_transform_gizmo_view();
|
||||
set_process_input(instant);
|
||||
}
|
||||
|
@ -5556,6 +5668,15 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
|
|||
break;
|
||||
}
|
||||
|
||||
Vector3 current_rotation_vector = (intersection - _edit.center).normalized();
|
||||
|
||||
if (_edit.initial_click_vector == Vector3()) {
|
||||
_edit.initial_click_vector = (click - _edit.center).normalized();
|
||||
_edit.previous_rotation_vector = current_rotation_vector;
|
||||
_edit.accumulated_rotation_angle = 0.0;
|
||||
_edit.display_rotation_angle = 0.0;
|
||||
}
|
||||
|
||||
static const float orthogonal_threshold = Math::cos(Math::deg_to_rad(85.0f));
|
||||
bool axis_is_orthogonal = Math::abs(plane.normal.dot(global_axis)) < orthogonal_threshold;
|
||||
|
||||
|
@ -5569,12 +5690,21 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
|
|||
} else {
|
||||
_edit.show_rotation_line = true;
|
||||
Vector3 click_axis = (click - _edit.center).normalized();
|
||||
Vector3 current_axis = (intersection - _edit.center).normalized();
|
||||
angle = click_axis.signed_angle_to(current_axis, global_axis);
|
||||
angle = click_axis.signed_angle_to(current_rotation_vector, global_axis);
|
||||
}
|
||||
|
||||
if (_edit.snap || spatial_editor->is_snap_enabled()) {
|
||||
if (_edit.previous_rotation_vector != Vector3()) {
|
||||
double delta_angle = _edit.previous_rotation_vector.signed_angle_to(current_rotation_vector, global_axis);
|
||||
_edit.accumulated_rotation_angle += delta_angle;
|
||||
}
|
||||
_edit.previous_rotation_vector = current_rotation_vector;
|
||||
|
||||
bool snapping = _edit.snap || spatial_editor->is_snap_enabled();
|
||||
if (snapping) {
|
||||
snap = spatial_editor->get_rotate_snap();
|
||||
_edit.display_rotation_angle = Math::deg_to_rad(Math::snapped(Math::rad_to_deg(_edit.accumulated_rotation_angle), snap));
|
||||
} else {
|
||||
_edit.display_rotation_angle = _edit.accumulated_rotation_angle;
|
||||
}
|
||||
angle = Math::snapped(Math::rad_to_deg(angle), snap);
|
||||
set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
|
||||
|
@ -5660,6 +5790,11 @@ void Node3DEditorViewport::finish_transform() {
|
|||
_edit.numeric_input = 0;
|
||||
_edit.numeric_next_decimal = 0;
|
||||
_edit.numeric_negate = false;
|
||||
_edit.initial_click_vector = Vector3();
|
||||
_edit.previous_rotation_vector = Vector3();
|
||||
_edit.accumulated_rotation_angle = 0.0;
|
||||
_edit.display_rotation_angle = 0.0;
|
||||
_edit.gizmo_initiated = false;
|
||||
spatial_editor->set_local_coords_enabled(_edit.original_local);
|
||||
spatial_editor->update_transform_gizmo();
|
||||
surface->queue_redraw();
|
||||
|
|
|
@ -296,6 +296,7 @@ private:
|
|||
void _update_name();
|
||||
void _compute_edit(const Point2 &p_point);
|
||||
void _clear_selected();
|
||||
bool _is_rotation_arc_visible() const;
|
||||
void _select_clicked(bool p_allow_locked);
|
||||
ObjectID _select_ray(const Point2 &p_pos) const;
|
||||
void _find_items_at_pos(const Point2 &p_pos, Vector<_RayResult> &r_results, bool p_include_locked);
|
||||
|
@ -390,6 +391,13 @@ private:
|
|||
double numeric_input = 0.0;
|
||||
bool numeric_negate = false;
|
||||
int numeric_next_decimal = 0;
|
||||
|
||||
Vector3 rotation_axis;
|
||||
double accumulated_rotation_angle = 0.0;
|
||||
double display_rotation_angle = 0.0;
|
||||
Vector3 initial_click_vector;
|
||||
Vector3 previous_rotation_vector;
|
||||
bool gizmo_initiated = false;
|
||||
} _edit;
|
||||
|
||||
struct Cursor {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue