Merge pull request #108608 from ryevdokimov/camera-view-axis-rotation

Make rotation gizmo white outline a 4th handle that rotates around the camera's view-axis
This commit is contained in:
Thaddeus Crews 2025-11-17 19:36:17 -06:00
commit d9333131d0
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
2 changed files with 356 additions and 286 deletions

View file

@ -112,6 +112,7 @@ constexpr real_t GIZMO_RING_HALF_WIDTH = 0.1;
constexpr real_t GIZMO_PLANE_SIZE = 0.2;
constexpr real_t GIZMO_PLANE_DST = 0.3;
constexpr real_t GIZMO_CIRCLE_SIZE = 1.1;
constexpr real_t GIZMO_VIEW_ROTATION_SIZE = 1.25;
constexpr real_t GIZMO_SCALE_OFFSET = GIZMO_CIRCLE_SIZE + 0.3;
constexpr real_t GIZMO_ARROW_OFFSET = GIZMO_CIRCLE_SIZE + 0.3;
@ -1381,6 +1382,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
int col_axis = -1;
bool view_rotation_selected = false;
Vector3 hit_position;
Vector3 hit_normal;
@ -1420,11 +1422,39 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
}
}
if (col_axis != -1) {
if (col_axis == -1) {
Vector3 ray_to_center = gt.origin - ray_pos;
real_t ray_length_to_center = ray_to_center.dot(ray);
Vector3 closest_point_on_ray = ray_pos + ray * ray_length_to_center;
real_t distance_ray_to_center = closest_point_on_ray.distance_to(gt.origin);
real_t view_rotation_radius = gizmo_scale * GIZMO_VIEW_ROTATION_SIZE;
real_t circumference_tolerance = gizmo_scale * GIZMO_RING_HALF_WIDTH;
if (Math::abs(distance_ray_to_center - view_rotation_radius) < circumference_tolerance &&
ray_length_to_center > 0) {
view_rotation_selected = true;
}
}
if (view_rotation_selected) {
if (p_highlight_only) {
spatial_editor->select_gizmo_highlight_axis(15);
} else {
_edit.mode = TRANSFORM_ROTATE;
_compute_edit(p_screenpos);
_edit.plane = TRANSFORM_VIEW;
_edit.accumulated_rotation_angle = 0.0;
_edit.rotation_axis = _get_camera_normal();
_edit.view_axis_local = spatial_editor->get_gizmo_transform().basis.xform_inv(_get_camera_normal()).normalized();
_edit.gizmo_initiated = true;
}
return true;
} else if (col_axis != -1) {
if (p_highlight_only) {
spatial_editor->select_gizmo_highlight_axis(col_axis + 3);
} else {
//handle rotate
//handle axis-specific rotate
_edit.mode = TRANSFORM_ROTATE;
_compute_edit(p_screenpos);
_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis);
@ -1521,7 +1551,7 @@ void Node3DEditorViewport::_transform_gizmo_apply(Node3D *p_node, const Transfor
}
}
Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local, bool p_orthogonal) {
Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local, bool p_orthogonal, bool p_view_axis) {
switch (p_mode) {
case TRANSFORM_SCALE: {
if (_edit.snap || spatial_editor->is_snap_enabled()) {
@ -1558,14 +1588,20 @@ Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const
case TRANSFORM_ROTATE: {
Transform3D r;
Basis parent_global_basis = p_original.basis * p_original_local.basis.inverse();
Vector3 axis;
if (p_local && !p_view_axis) {
axis = p_original_local.basis.xform(p_motion);
} else {
axis = parent_global_basis.xform_inv(p_motion);
}
if (p_local) {
Vector3 axis = p_original_local.basis.xform(p_motion);
r.basis = Basis(axis.normalized(), p_extra) * p_original_local.basis;
r.origin = p_original_local.origin;
} else {
Basis local = p_original.basis * p_original_local.basis.inverse();
Vector3 axis = local.xform_inv(p_motion);
r.basis = local * Basis(axis.normalized(), p_extra) * p_original_local.basis;
r.basis = parent_global_basis * Basis(axis.normalized(), p_extra) * p_original_local.basis;
r.origin = Basis(p_motion, p_extra).xform(p_original.origin - _edit.center) + _edit.center;
}
@ -3672,6 +3708,9 @@ void Node3DEditorViewport::_draw() {
Color handle_color;
switch (_edit.plane) {
case TRANSFORM_VIEW:
handle_color = Color(1.0, 1.0, 1.0, 1.0);
break;
case TRANSFORM_X_AXIS:
handle_color = get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor));
break;
@ -3694,16 +3733,18 @@ void Node3DEditorViewport::_draw() {
right.normalize();
Vector3 forward = up.cross(right);
real_t rotation_radius = (_edit.plane == TRANSFORM_VIEW) ? GIZMO_VIEW_ROTATION_SIZE : GIZMO_CIRCLE_SIZE;
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));
Vector3 point_3d = _edit.center + gizmo_scale * rotation_radius * (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);
Color circle_color = (_edit.plane == TRANSFORM_VIEW) ? Color(1.0, 1.0, 1.0, 0.8) : 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,
@ -3739,8 +3780,8 @@ void Node3DEditorViewport::_draw() {
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));
Vector3 point1_3d = _edit.center + gizmo_scale * rotation_radius * (right * Math::cos(angle1) + forward * Math::sin(angle1));
Vector3 point2_3d = _edit.center + gizmo_scale * rotation_radius * (right * Math::cos(angle2) + forward * Math::sin(angle2));
Point2 center_2d = center;
Point2 point1_2d = point_to_screen(point1_3d);
@ -3759,9 +3800,9 @@ void Node3DEditorViewport::_draw() {
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);
Color edge_color = (_edit.plane == TRANSFORM_VIEW) ? Color(1.0, 1.0, 1.0, 0.7) : 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;
Vector3 start_point_3d = _edit.center + gizmo_scale * rotation_radius * right;
Point2 start_point_2d = point_to_screen(start_point_3d);
RenderingServer::get_singleton()->canvas_item_add_line(
ci,
@ -3770,7 +3811,7 @@ void Node3DEditorViewport::_draw() {
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));
Vector3 end_point_3d = _edit.center + gizmo_scale * rotation_radius * (right * Math::cos(_edit.accumulated_rotation_angle) + forward * Math::sin(_edit.accumulated_rotation_angle));
Point2 end_point_2d = point_to_screen(end_point_3d);
RenderingServer::get_singleton()->canvas_item_add_line(
ci,
@ -4350,15 +4391,6 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_geometry_set_flag(move_plane_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
RS::get_singleton()->instance_geometry_set_flag(move_plane_gizmo_instance[i], RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
rotate_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid());
RS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer);
RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i], RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
scale_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid());
RS::get_singleton()->instance_set_scenario(scale_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario());
@ -4378,6 +4410,9 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_geometry_set_flag(scale_plane_gizmo_instance[i], RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
axis_gizmo_instance[i] = RS::get_singleton()->instance_create();
}
for (int i = 0; i < 3; i++) {
RS::get_singleton()->instance_set_base(axis_gizmo_instance[i], spatial_editor->get_axis_gizmo(i)->get_rid());
RS::get_singleton()->instance_set_scenario(axis_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_visible(axis_gizmo_instance[i], true);
@ -4387,15 +4422,16 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_geometry_set_flag(axis_gizmo_instance[i], RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
}
// Rotation white outline
rotate_gizmo_instance[3] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(rotate_gizmo_instance[3], spatial_editor->get_rotate_gizmo(3)->get_rid());
RS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[3], get_tree()->get_root()->get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[3], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[3], layer);
RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[3], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[3], RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
for (int i = 0; i < 4; i++) {
rotate_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid());
RS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer);
RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i], RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
}
}
void Node3DEditorViewport::_finish_gizmo_instances() {
@ -4507,7 +4543,6 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
RenderingServer::get_singleton()->instance_set_visible(axis_gizmo_instance[i], false);
}
// Rotation white outline
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false);
return;
}
@ -4540,7 +4575,6 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
}
// Rotation white outline
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false);
return;
}
@ -4548,6 +4582,8 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
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;
bool show_rotate_gizmo = show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE);
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) {
@ -4560,7 +4596,6 @@ 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);
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));
@ -4569,18 +4604,17 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
RenderingServer::get_singleton()->instance_set_transform(axis_gizmo_instance[i], xform);
}
Transform3D view_rotation_xform = xform;
view_rotation_xform.orthonormalize();
view_rotation_xform.basis.scale(scale);
RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], view_rotation_xform);
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], show_rotate_gizmo);
bool show_axes = spatial_editor->is_gizmo_visible() && _edit.mode != TRANSFORM_NONE;
RenderingServer *rs = RenderingServer::get_singleton();
rs->instance_set_visible(axis_gizmo_instance[0], show_axes && (_edit.plane == TRANSFORM_X_AXIS || _edit.plane == TRANSFORM_XY || _edit.plane == TRANSFORM_XZ));
rs->instance_set_visible(axis_gizmo_instance[1], show_axes && (_edit.plane == TRANSFORM_Y_AXIS || _edit.plane == TRANSFORM_XY || _edit.plane == TRANSFORM_YZ));
rs->instance_set_visible(axis_gizmo_instance[2], show_axes && (_edit.plane == TRANSFORM_Z_AXIS || _edit.plane == TRANSFORM_XZ || _edit.plane == TRANSFORM_YZ));
// Rotation white outline
xform.orthonormalize();
xform.basis.scale(scale);
RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform);
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) {
@ -5558,7 +5592,13 @@ void Node3DEditorViewport::commit_transform() {
}
void Node3DEditorViewport::apply_transform(Vector3 p_motion, double p_snap) {
bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
// View-plane translate/scale always uses global coords; rotation and axis operations respect local/global preference.
bool local_coords = spatial_editor->are_local_coords_enabled() &&
!(_edit.plane == TRANSFORM_VIEW && _edit.mode != TRANSFORM_ROTATE);
bool is_global_view_plane = (_edit.plane == TRANSFORM_VIEW) &&
((_edit.mode != TRANSFORM_ROTATE) || !spatial_editor->are_local_coords_enabled());
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (Node *E : selection) {
Node3D *sp = Object::cast_to<Node3D>(E);
@ -5578,14 +5618,14 @@ void Node3DEditorViewport::apply_transform(Vector3 p_motion, double p_snap) {
if (se->gizmo.is_valid()) {
for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
Transform3D xform = GE.value;
Transform3D new_xform = _compute_transform(_edit.mode, se->original * xform, xform, p_motion, p_snap, local_coords, _edit.plane != TRANSFORM_VIEW); // Force orthogonal with subgizmo.
Transform3D new_xform = _compute_transform(_edit.mode, se->original * xform, xform, p_motion, p_snap, local_coords, _edit.plane != TRANSFORM_VIEW, is_global_view_plane); // Force orthogonal with subgizmo.
if (!local_coords) {
new_xform = se->original.affine_inverse() * new_xform;
}
se->gizmo->set_subgizmo_transform(GE.key, new_xform);
}
} else {
Transform3D new_xform = _compute_transform(_edit.mode, se->original, se->original_local, p_motion, p_snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS && _edit.plane != TRANSFORM_VIEW);
Transform3D new_xform = _compute_transform(_edit.mode, se->original, se->original_local, p_motion, p_snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS && _edit.plane != TRANSFORM_VIEW, is_global_view_plane);
_transform_gizmo_apply(se->sp, new_xform, local_coords);
}
}
@ -5601,6 +5641,10 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
double snap = EDITOR_GET("interface/inspector/default_float_step");
int snap_step_decimals = Math::range_step_decimals(snap);
// View-plane translate/scale always uses global coords; rotation and axis operations respect local/global preference.
bool local_coords = spatial_editor->are_local_coords_enabled() &&
!(_edit.plane == TRANSFORM_VIEW && _edit.mode != TRANSFORM_ROTATE);
switch (_edit.mode) {
case TRANSFORM_SCALE: {
Vector3 motion_mask;
@ -5676,9 +5720,6 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
motion /= click.distance_to(_edit.center);
// Disable local transformation for TRANSFORM_VIEW
bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
if (_edit.snap || spatial_editor->is_snap_enabled()) {
snap = spatial_editor->get_scale_snap() / 100;
}
@ -5748,9 +5789,6 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
}
}
// Disable local transformation for TRANSFORM_VIEW
bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
if (_edit.snap || spatial_editor->is_snap_enabled()) {
snap = spatial_editor->get_translate_snap();
}
@ -5783,8 +5821,8 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
Vector3 global_axis;
switch (_edit.plane) {
case TRANSFORM_VIEW:
// local_axis unused
global_axis = plane.normal;
local_axis = _edit.view_axis_local;
global_axis = _get_camera_normal();
break;
case TRANSFORM_X_AXIS:
local_axis = Vector3(1, 0, 0);
@ -5857,8 +5895,6 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
angle = Math::deg_to_rad(angle);
bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
Vector3 compute_axis = local_coords ? local_axis : global_axis;
apply_transform(compute_axis, angle);
} break;
@ -5876,7 +5912,7 @@ void Node3DEditorViewport::update_transform_numeric() {
motion = Vector3(1, 0, 0);
break;
case TRANSFORM_ROTATE:
motion = spatial_editor->get_gizmo_transform().basis.xform_inv(_get_camera_normal()).normalized();
motion = _edit.view_axis_local;
break;
case TRANSFORM_SCALE:
motion = Vector3(1, 1, 1);
@ -6741,10 +6777,19 @@ void Node3DEditor::select_gizmo_highlight_axis(int p_axis) {
for (int i = 0; i < 3; i++) {
move_gizmo[i]->surface_set_material(0, i == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? rotate_gizmo_color_hl[i] : rotate_gizmo_color[i]);
scale_gizmo[i]->surface_set_material(0, (i + 9) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
scale_plane_gizmo[i]->surface_set_material(0, (i + 12) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
}
for (int i = 0; i < 4; i++) {
bool highlight;
if (i == 3) {
highlight = (p_axis == 15);
} else {
highlight = (i + 3) == p_axis;
}
rotate_gizmo[i]->surface_set_material(0, highlight ? rotate_gizmo_color_hl[i] : rotate_gizmo_color[i]);
}
}
void Node3DEditor::update_transform_gizmo() {
@ -7728,7 +7773,7 @@ void fragment() {
Vector3 ivec2 = Vector3(-1, 0, 0);
Vector3 ivec3 = Vector3(0, -1, 0);
for (int i = 0; i < 3; i++) {
for (int i = 0; i < 4; i++) {
Color col;
switch (i) {
case 0:
@ -7740,124 +7785,146 @@ void fragment() {
case 2:
col = get_theme_color(SNAME("axis_z_color"), EditorStringName(Editor));
break;
case 3:
col = Color(0.75, 0.75, 0.75, 1.0);
break;
default:
col = Color();
break;
}
col.a = EDITOR_GET("editors/3d/manipulator_gizmo_opacity");
if (i < 3) {
col.a = EDITOR_GET("editors/3d/manipulator_gizmo_opacity");
}
if (i < 3) {
move_gizmo[i].instantiate();
move_plane_gizmo[i].instantiate();
scale_gizmo[i].instantiate();
scale_plane_gizmo[i].instantiate();
axis_gizmo[i].instantiate();
}
move_gizmo[i].instantiate();
move_plane_gizmo[i].instantiate();
rotate_gizmo[i].instantiate();
scale_gizmo[i].instantiate();
scale_plane_gizmo[i].instantiate();
axis_gizmo[i].instantiate();
Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
mat->set_on_top_of_alpha();
mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
mat->set_albedo(col);
gizmo_color[i] = mat;
Ref<StandardMaterial3D> mat_hl = mat->duplicate();
const Color albedo = col.from_hsv(col.get_h(), 0.25, 1.0, 1);
mat_hl->set_albedo(albedo);
gizmo_color_hl[i] = mat_hl;
//translate
{
Ref<SurfaceTool> surftool = memnew(SurfaceTool);
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
Ref<StandardMaterial3D> mat;
Ref<StandardMaterial3D> mat_hl;
// Arrow profile
const int arrow_points = 5;
Vector3 arrow[5] = {
nivec * 0.0 + ivec * 0.0,
nivec * 0.01 + ivec * 0.0,
nivec * 0.01 + ivec * GIZMO_ARROW_OFFSET,
nivec * 0.065 + ivec * GIZMO_ARROW_OFFSET,
nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE),
};
if (i < 3) {
// Only create standard materials for X, Y, Z axes (move/scale gizmos).
mat.instantiate();
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
mat->set_on_top_of_alpha();
mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
mat->set_albedo(col);
gizmo_color[i] = mat;
int arrow_sides = 16;
mat_hl = mat->duplicate();
mat_hl->set_albedo(albedo);
gizmo_color_hl[i] = mat_hl;
}
const real_t arrow_sides_step = Math::TAU / arrow_sides;
for (int k = 0; k < arrow_sides; k++) {
Basis ma(ivec, k * arrow_sides_step);
Basis mb(ivec, (k + 1) * arrow_sides_step);
// Only create translate gizmo for X, Y, Z axes (not view rotation).
if (i < 3) {
//translate
{
Ref<SurfaceTool> surftool;
surftool.instantiate();
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
for (int j = 0; j < arrow_points - 1; j++) {
Vector3 points[4] = {
ma.xform(arrow[j]),
mb.xform(arrow[j]),
mb.xform(arrow[j + 1]),
ma.xform(arrow[j + 1]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
// Arrow profile
const int arrow_points = 5;
Vector3 arrow[5] = {
nivec * 0.0 + ivec * 0.0,
nivec * 0.01 + ivec * 0.0,
nivec * 0.01 + ivec * GIZMO_ARROW_OFFSET,
nivec * 0.065 + ivec * GIZMO_ARROW_OFFSET,
nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
int arrow_sides = 16;
const real_t arrow_sides_step = Math::TAU / arrow_sides;
for (int k = 0; k < arrow_sides; k++) {
Basis ma(ivec, k * arrow_sides_step);
Basis mb(ivec, (k + 1) * arrow_sides_step);
for (int j = 0; j < arrow_points - 1; j++) {
Vector3 points[4] = {
ma.xform(arrow[j]),
mb.xform(arrow[j]),
mb.xform(arrow[j + 1]),
ma.xform(arrow[j + 1]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
}
}
surftool->set_material(mat);
surftool->commit(move_gizmo[i]);
}
surftool->set_material(mat);
surftool->commit(move_gizmo[i]);
// Plane Translation
{
Ref<SurfaceTool> surftool;
surftool.instantiate();
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
Vector3 vec = ivec2 - ivec3;
Vector3 plane[4] = {
vec * GIZMO_PLANE_DST,
vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
};
Basis ma(ivec, Math::PI / 2);
Vector3 points[4] = {
ma.xform(plane[0]),
ma.xform(plane[1]),
ma.xform(plane[2]),
ma.xform(plane[3]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
Ref<StandardMaterial3D> plane_mat;
plane_mat.instantiate();
plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
plane_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
plane_mat->set_on_top_of_alpha();
plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
plane_mat->set_albedo(col);
plane_gizmo_color[i] = plane_mat; // Needed, so we can draw planes from both sides.
surftool->set_material(plane_mat);
surftool->commit(move_plane_gizmo[i]);
Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
plane_mat_hl->set_albedo(albedo);
plane_gizmo_color_hl[i] = plane_mat_hl; // Needed, so we can draw planes from both sides.
}
}
// Plane Translation
// Rotate - for all 4 indices (X, Y, Z, and view rotation).
{
Ref<SurfaceTool> surftool = memnew(SurfaceTool);
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
Vector3 vec = ivec2 - ivec3;
Vector3 plane[4] = {
vec * GIZMO_PLANE_DST,
vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
};
Basis ma(ivec, Math::PI / 2);
Vector3 points[4] = {
ma.xform(plane[0]),
ma.xform(plane[1]),
ma.xform(plane[2]),
ma.xform(plane[3]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
Ref<StandardMaterial3D> plane_mat = memnew(StandardMaterial3D);
plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
plane_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
plane_mat->set_on_top_of_alpha();
plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
plane_mat->set_albedo(col);
plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides
surftool->set_material(plane_mat);
surftool->commit(move_plane_gizmo[i]);
Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
plane_mat_hl->set_albedo(albedo);
plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
}
// Rotate
{
Ref<SurfaceTool> surftool = memnew(SurfaceTool);
Ref<SurfaceTool> surftool;
surftool.instantiate();
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
int n = 128; // number of circle segments
@ -7867,7 +7934,8 @@ void fragment() {
for (int j = 0; j < n; ++j) {
Basis basis = Basis(ivec, j * step);
Vector3 vertex = basis.xform(ivec2 * GIZMO_CIRCLE_SIZE);
real_t circle_size = (i == 3) ? GIZMO_VIEW_ROTATION_SIZE : GIZMO_CIRCLE_SIZE;
Vector3 vertex = basis.xform(ivec2 * circle_size);
for (int k = 0; k < m; ++k) {
Vector2 ofs = Vector2(Math::cos((Math::TAU * k) / m), Math::sin((Math::TAU * k) / m));
@ -7897,8 +7965,9 @@ void fragment() {
Ref<Shader> rotate_shader = memnew(Shader);
rotate_shader->set_code(R"(
// 3D editor rotation manipulator gizmo shader.
// Use special shader for view rotation (index 3) with camera-relative transformation.
if (i == 3) {
rotate_shader->set_code(R"(
shader_type spatial;
@ -7916,11 +7985,12 @@ mat3 orthonormalize(mat3 m) {
void vertex() {
mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX));
vec3 n = mv * VERTEX;
float orientation = dot(vec3(0.0, 0.0, -1.0), n);
if (orientation <= 0.005) {
VERTEX += NORMAL * 0.02;
}
mv = inverse(mv);
VERTEX += NORMAL * 0.008;
vec3 camera_dir_local = mv * vec3(0.0, 0.0, 1.0);
vec3 camera_up_local = mv * vec3(0.0, 1.0, 0.0);
mat3 rotation_matrix = mat3(cross(camera_dir_local, camera_up_local), camera_up_local, camera_dir_local);
VERTEX = rotation_matrix * VERTEX;
}
void fragment() {
@ -7928,27 +7998,10 @@ void fragment() {
ALPHA = albedo.a;
}
)");
Ref<ShaderMaterial> rotate_mat = memnew(ShaderMaterial);
rotate_mat->set_render_priority(Material::RENDER_PRIORITY_MAX);
rotate_mat->set_shader(rotate_shader);
rotate_mat->set_shader_parameter("albedo", col);
rotate_gizmo_color[i] = rotate_mat;
Array arrays = surftool->commit_to_arrays();
rotate_gizmo[i]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
rotate_gizmo[i]->surface_set_material(0, rotate_mat);
Ref<ShaderMaterial> rotate_mat_hl = rotate_mat->duplicate();
rotate_mat_hl->set_shader_parameter("albedo", albedo);
rotate_gizmo_color_hl[i] = rotate_mat_hl;
if (i == 2) { // Rotation white outline
Ref<ShaderMaterial> border_mat = rotate_mat->duplicate();
Ref<Shader> border_shader = memnew(Shader);
border_shader->set_code(R"(
// 3D editor rotation manipulator gizmo shader (white outline).
} else {
// Standard shader for X, Y, Z rotation gizmos.
rotate_shader->set_code(R"(
// 3D editor rotation manipulator gizmo shader.
shader_type spatial;
@ -7966,12 +8019,11 @@ mat3 orthonormalize(mat3 m) {
void vertex() {
mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX));
mv = inverse(mv);
VERTEX += NORMAL * 0.008;
vec3 camera_dir_local = mv * vec3(0.0, 0.0, 1.0);
vec3 camera_up_local = mv * vec3(0.0, 1.0, 0.0);
mat3 rotation_matrix = mat3(cross(camera_dir_local, camera_up_local), camera_up_local, camera_dir_local);
VERTEX = rotation_matrix * VERTEX;
vec3 n = mv * VERTEX;
float orientation = dot(vec3(0.0, 0.0, -1.0), n);
if (orientation <= 0.005) {
VERTEX += NORMAL * 0.02;
}
}
void fragment() {
@ -7979,119 +8031,136 @@ void fragment() {
ALPHA = albedo.a;
}
)");
border_mat->set_shader(border_shader);
border_mat->set_shader_parameter("albedo", Color(0.75, 0.75, 0.75, col.a / 3.0));
rotate_gizmo[3].instantiate();
rotate_gizmo[3]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
rotate_gizmo[3]->surface_set_material(0, border_mat);
}
Ref<ShaderMaterial> rotate_mat;
rotate_mat.instantiate();
rotate_mat->set_render_priority(Material::RENDER_PRIORITY_MAX);
rotate_mat->set_shader(rotate_shader);
rotate_mat->set_shader_parameter("albedo", col);
rotate_gizmo_color[i] = rotate_mat;
Array arrays = surftool->commit_to_arrays();
rotate_gizmo[i]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
rotate_gizmo[i]->surface_set_material(0, rotate_mat);
Ref<ShaderMaterial> rotate_mat_hl = rotate_mat->duplicate();
// For view rotation, use bright white; for axes, use highlight color.
Color highlight_color = (i == 3) ? Color(1.0, 1.0, 1.0, 1.0) : albedo;
rotate_mat_hl->set_shader_parameter("albedo", highlight_color);
rotate_gizmo_color_hl[i] = rotate_mat_hl;
}
// Scale
{
Ref<SurfaceTool> surftool = memnew(SurfaceTool);
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
// Only create scale gizmo for X, Y, Z axes (not view rotation).
if (i < 3) {
// Scale.
{
Ref<SurfaceTool> surftool;
surftool.instantiate();
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
// Cube arrow profile
const int arrow_points = 6;
Vector3 arrow[6] = {
nivec * 0.0 + ivec * 0.0,
nivec * 0.01 + ivec * 0.0,
nivec * 0.01 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
nivec * 0.07 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
nivec * 0.07 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
nivec * 0.0 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
};
// Cube arrow profile.
const int arrow_points = 6;
Vector3 arrow[6] = {
nivec * 0.0 + ivec * 0.0,
nivec * 0.01 + ivec * 0.0,
nivec * 0.01 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
nivec * 0.07 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
nivec * 0.07 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
nivec * 0.0 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
};
int arrow_sides = 4;
int arrow_sides = 4;
const real_t arrow_sides_step = Math::TAU / arrow_sides;
for (int k = 0; k < 4; k++) {
Basis ma(ivec, k * arrow_sides_step);
Basis mb(ivec, (k + 1) * arrow_sides_step);
const real_t arrow_sides_step = Math::TAU / arrow_sides;
for (int k = 0; k < 4; k++) {
Basis ma(ivec, k * arrow_sides_step);
Basis mb(ivec, (k + 1) * arrow_sides_step);
for (int j = 0; j < arrow_points - 1; j++) {
Vector3 points[4] = {
ma.xform(arrow[j]),
mb.xform(arrow[j]),
mb.xform(arrow[j + 1]),
ma.xform(arrow[j + 1]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
for (int j = 0; j < arrow_points - 1; j++) {
Vector3 points[4] = {
ma.xform(arrow[j]),
mb.xform(arrow[j]),
mb.xform(arrow[j + 1]),
ma.xform(arrow[j + 1]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
}
}
surftool->set_material(mat);
surftool->commit(scale_gizmo[i]);
}
surftool->set_material(mat);
surftool->commit(scale_gizmo[i]);
}
// Plane Scale.
{
Ref<SurfaceTool> surftool;
surftool.instantiate();
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
// Plane Scale
{
Ref<SurfaceTool> surftool = memnew(SurfaceTool);
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
Vector3 vec = ivec2 - ivec3;
Vector3 plane[4] = {
vec * GIZMO_PLANE_DST,
vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
};
Vector3 vec = ivec2 - ivec3;
Vector3 plane[4] = {
vec * GIZMO_PLANE_DST,
vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
};
Basis ma(ivec, Math::PI / 2);
Basis ma(ivec, Math::PI / 2);
Vector3 points[4] = {
ma.xform(plane[0]),
ma.xform(plane[1]),
ma.xform(plane[2]),
ma.xform(plane[3]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
Vector3 points[4] = {
ma.xform(plane[0]),
ma.xform(plane[1]),
ma.xform(plane[2]),
ma.xform(plane[3]),
};
surftool->add_vertex(points[0]);
surftool->add_vertex(points[1]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
surftool->add_vertex(points[0]);
surftool->add_vertex(points[2]);
surftool->add_vertex(points[3]);
Ref<StandardMaterial3D> plane_mat;
plane_mat.instantiate();
plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
plane_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
plane_mat->set_on_top_of_alpha();
plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
plane_mat->set_albedo(col);
plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides.
surftool->set_material(plane_mat);
surftool->commit(scale_plane_gizmo[i]);
Ref<StandardMaterial3D> plane_mat = memnew(StandardMaterial3D);
plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
plane_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
plane_mat->set_on_top_of_alpha();
plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
plane_mat->set_albedo(col);
plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides
surftool->set_material(plane_mat);
surftool->commit(scale_plane_gizmo[i]);
Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
plane_mat_hl->set_albedo(col.from_hsv(col.get_h(), 0.25, 1.0, 1));
plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides.
}
Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
plane_mat_hl->set_albedo(col.from_hsv(col.get_h(), 0.25, 1.0, 1));
plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
}
// Lines to visualize transforms locked to an axis/plane.
{
Ref<SurfaceTool> surftool;
surftool.instantiate();
surftool->begin(Mesh::PRIMITIVE_LINE_STRIP);
// Lines to visualize transforms locked to an axis/plane
{
Ref<SurfaceTool> surftool = memnew(SurfaceTool);
surftool->begin(Mesh::PRIMITIVE_LINE_STRIP);
Vector3 vec;
vec[i] = 1;
Vector3 vec;
vec[i] = 1;
// line extending through infinity(ish)
surftool->add_vertex(vec * -1048576);
surftool->add_vertex(Vector3());
surftool->add_vertex(vec * 1048576);
surftool->set_material(mat_hl);
surftool->commit(axis_gizmo[i]);
// Line extending through like infinity.
surftool->add_vertex(vec * -1048576);
surftool->add_vertex(Vector3());
surftool->add_vertex(vec * 1048576);
surftool->set_material(mat_hl);
surftool->commit(axis_gizmo[i]);
}
}
}
}

View file

@ -399,6 +399,7 @@ private:
int numeric_next_decimal = 0;
Vector3 rotation_axis;
Vector3 view_axis_local;
double accumulated_rotation_angle = 0.0;
double display_rotation_angle = 0.0;
Vector3 initial_click_vector;
@ -530,7 +531,7 @@ private:
void _project_settings_changed();
Transform3D _compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local, bool p_orthogonal);
Transform3D _compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local, bool p_orthogonal, bool p_view_axis = false);
void _reset_transform(TransformType p_type);
@ -708,10 +709,10 @@ private:
Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3], axis_gizmo[3];
Ref<StandardMaterial3D> gizmo_color[3];
Ref<StandardMaterial3D> plane_gizmo_color[3];
Ref<ShaderMaterial> rotate_gizmo_color[3];
Ref<ShaderMaterial> rotate_gizmo_color[4];
Ref<StandardMaterial3D> gizmo_color_hl[3];
Ref<StandardMaterial3D> plane_gizmo_color_hl[3];
Ref<ShaderMaterial> rotate_gizmo_color_hl[3];
Ref<ShaderMaterial> rotate_gizmo_color_hl[4];
Ref<Node3DGizmo> current_hover_gizmo;
int current_hover_gizmo_handle;