@@ -116,6 +116,13 @@ constexpr real_t GIZMO_VIEW_ROTATION_SIZE = 1.25;
116116constexpr real_t GIZMO_SCALE_OFFSET = GIZMO_CIRCLE_SIZE + 0.3 ;
117117constexpr real_t GIZMO_ARROW_OFFSET = GIZMO_CIRCLE_SIZE + 0.3 ;
118118
119+ constexpr real_t TRACKBALL_SENSITIVITY = 0.005 ;
120+ constexpr int TRACKBALL_SPHERE_RINGS = 16 ;
121+ constexpr int TRACKBALL_SPHERE_SECTORS = 32 ;
122+ constexpr real_t TRACKBALL_HIGHLIGHT_ALPHA = 0.01 ;
123+ constexpr int GIZMO_HIGHLIGHT_AXIS_VIEW_ROTATION = 15 ;
124+ constexpr int GIZMO_HIGHLIGHT_AXIS_TRACKBALL = 16 ;
125+
119126constexpr real_t ZOOM_FREELOOK_MIN = 0.01 ;
120127constexpr real_t ZOOM_FREELOOK_MULTIPLIER = 1.08 ;
121128constexpr real_t ZOOM_FREELOOK_INDICATOR_DELAY_S = 1.5 ;
@@ -1383,6 +1390,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
13831390 if (spatial_editor->get_tool_mode () == Node3DEditor::TOOL_MODE_TRANSFORM || spatial_editor->get_tool_mode () == Node3DEditor::TOOL_MODE_ROTATE) {
13841391 int col_axis = -1 ;
13851392 bool view_rotation_selected = false ;
1393+ bool trackball_selected = false ;
13861394
13871395 Vector3 hit_position;
13881396 Vector3 hit_normal;
@@ -1434,12 +1442,14 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
14341442 if (Math::abs (distance_ray_to_center - view_rotation_radius) < circumference_tolerance &&
14351443 ray_length_to_center > 0 ) {
14361444 view_rotation_selected = true ;
1445+ } else if (distance_ray_to_center < gizmo_scale * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && ray_length_to_center > 0 ) {
1446+ trackball_selected = true ;
14371447 }
14381448 }
14391449
14401450 if (view_rotation_selected) {
14411451 if (p_highlight_only) {
1442- spatial_editor->select_gizmo_highlight_axis (15 );
1452+ spatial_editor->select_gizmo_highlight_axis (GIZMO_HIGHLIGHT_AXIS_VIEW_ROTATION );
14431453 } else {
14441454 _edit.mode = TRANSFORM_ROTATE;
14451455 _compute_edit (p_screenpos);
@@ -1450,6 +1460,21 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
14501460 _edit.gizmo_initiated = true ;
14511461 }
14521462 return true ;
1463+ } else if (trackball_selected) {
1464+ if (p_highlight_only) {
1465+ spatial_editor->select_gizmo_highlight_axis (GIZMO_HIGHLIGHT_AXIS_TRACKBALL);
1466+ } else {
1467+ _edit.mode = TRANSFORM_ROTATE;
1468+ _compute_edit (p_screenpos);
1469+ _edit.plane = TRANSFORM_VIEW;
1470+ _edit.is_trackball = true ;
1471+ _edit.show_rotation_line = false ;
1472+ _edit.accumulated_rotation_angle = 0.0 ;
1473+ _edit.rotation_axis = _get_camera_normal ();
1474+ _edit.gizmo_initiated = true ;
1475+ spatial_editor->select_gizmo_highlight_axis (-1 );
1476+ }
1477+ return true ;
14531478 } else if (col_axis != -1 ) {
14541479 if (p_highlight_only) {
14551480 spatial_editor->select_gizmo_highlight_axis (col_axis + 3 );
@@ -3725,7 +3750,7 @@ void Node3DEditorViewport::_draw() {
37253750 break ;
37263751 }
37273752
3728- if (_is_rotation_arc_visible () && !_edit.initial_click_vector .is_zero_approx ()) {
3753+ if (!_edit. is_trackball && _is_rotation_arc_visible () && !_edit.initial_click_vector .is_zero_approx ()) {
37293754 Vector3 up = _edit.rotation_axis ;
37303755 Vector3 right = _edit.initial_click_vector ;
37313756
@@ -4432,6 +4457,16 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
44324457 RS::get_singleton ()->instance_geometry_set_flag (rotate_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true );
44334458 RS::get_singleton ()->instance_geometry_set_flag (rotate_gizmo_instance[i], RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false );
44344459 }
4460+
4461+ // Create trackball sphere instance
4462+ trackball_sphere_instance = RS::get_singleton ()->instance_create ();
4463+ RS::get_singleton ()->instance_set_base (trackball_sphere_instance, spatial_editor->get_trackball_sphere_gizmo ()->get_rid ());
4464+ RS::get_singleton ()->instance_set_scenario (trackball_sphere_instance, get_tree ()->get_root ()->get_world_3d ()->get_scenario ());
4465+ RS::get_singleton ()->instance_set_visible (trackball_sphere_instance, false );
4466+ RS::get_singleton ()->instance_geometry_set_cast_shadows_setting (trackball_sphere_instance, RS::SHADOW_CASTING_SETTING_OFF);
4467+ RS::get_singleton ()->instance_set_layer_mask (trackball_sphere_instance, layer);
4468+ RS::get_singleton ()->instance_geometry_set_flag (trackball_sphere_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true );
4469+ RS::get_singleton ()->instance_geometry_set_flag (trackball_sphere_instance, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false );
44354470}
44364471
44374472void Node3DEditorViewport::_finish_gizmo_instances () {
@@ -4446,6 +4481,8 @@ void Node3DEditorViewport::_finish_gizmo_instances() {
44464481 }
44474482 // Rotation white outline
44484483 RS::get_singleton ()->free_rid (rotate_gizmo_instance[3 ]);
4484+
4485+ RS::get_singleton ()->free_rid (trackball_sphere_instance);
44494486}
44504487
44514488void Node3DEditorViewport::_toggle_camera_preview (bool p_activate) {
@@ -4580,8 +4617,9 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
45804617 }
45814618
45824619 bool hide_during_rotation = _is_rotation_arc_visible ();
4620+ bool hide_during_trackball = (_edit.mode == TRANSFORM_ROTATE && _edit.is_trackball );
45834621
4584- bool show_gizmo = spatial_editor->is_gizmo_visible () && !_edit.instant && transform_gizmo_visible && !collision_reposition && !hide_during_rotation;
4622+ bool show_gizmo = spatial_editor->is_gizmo_visible () && !_edit.instant && transform_gizmo_visible && !collision_reposition && !hide_during_rotation && !hide_during_trackball ;
45854623 bool show_rotate_gizmo = show_gizmo && (spatial_editor->get_tool_mode () == Node3DEditor::TOOL_MODE_TRANSFORM || spatial_editor->get_tool_mode () == Node3DEditor::TOOL_MODE_ROTATE);
45864624
45874625 for (int i = 0 ; i < 3 ; i++) {
@@ -4610,7 +4648,12 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
46104648 RenderingServer::get_singleton ()->instance_set_transform (rotate_gizmo_instance[3 ], view_rotation_xform);
46114649 RenderingServer::get_singleton ()->instance_set_visible (rotate_gizmo_instance[3 ], show_rotate_gizmo);
46124650
4613- bool show_axes = spatial_editor->is_gizmo_visible () && _edit.mode != TRANSFORM_NONE;
4651+ bool can_show_trackball = spatial_editor->is_gizmo_visible () && !_edit.instant && transform_gizmo_visible && !collision_reposition && !hide_during_rotation;
4652+ bool show_trackball_sphere = can_show_trackball && (spatial_editor->get_tool_mode () == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode () == Node3DEditor::TOOL_MODE_ROTATE) && !hide_during_trackball;
4653+ RenderingServer::get_singleton ()->instance_set_transform (trackball_sphere_instance, view_rotation_xform);
4654+ RenderingServer::get_singleton ()->instance_set_visible (trackball_sphere_instance, show_trackball_sphere);
4655+
4656+ bool show_axes = spatial_editor->is_gizmo_visible () && _edit.mode != TRANSFORM_NONE && !hide_during_trackball;
46144657 RenderingServer *rs = RenderingServer::get_singleton ();
46154658 rs->instance_set_visible (axis_gizmo_instance[0 ], show_axes && (_edit.plane == TRANSFORM_X_AXIS || _edit.plane == TRANSFORM_XY || _edit.plane == TRANSFORM_XZ));
46164659 rs->instance_set_visible (axis_gizmo_instance[1 ], show_axes && (_edit.plane == TRANSFORM_Y_AXIS || _edit.plane == TRANSFORM_XY || _edit.plane == TRANSFORM_YZ));
@@ -5817,6 +5860,36 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
58175860 plane = Plane (_get_camera_normal (), _edit.center );
58185861 }
58195862
5863+ if (_edit.is_trackball ) {
5864+ Vector2 motion_delta = _edit.mouse_pos - _edit.original_mouse_pos ;
5865+ real_t sensitivity = TRACKBALL_SENSITIVITY * EDSCALE;
5866+ Vector2 rotation_input = motion_delta * sensitivity;
5867+
5868+ Transform3D cam_transform = to_camera_transform (cursor);
5869+ Vector3 cam_right = cam_transform.basis .get_column (0 ).normalized ();
5870+ Vector3 cam_up = cam_transform.basis .get_column (1 ).normalized ();
5871+ Vector3 rotation_axis = cam_up * rotation_input.x + cam_right * rotation_input.y ;
5872+
5873+ real_t rotation_angle = rotation_axis.length ();
5874+ if (rotation_angle > 0 .0f ) {
5875+ rotation_axis /= rotation_angle;
5876+
5877+ bool snapping = _edit.snap || spatial_editor->is_snap_enabled ();
5878+ if (snapping) {
5879+ double snap_step = spatial_editor->get_rotate_snap ();
5880+ double angle_deg = Math::rad_to_deg (rotation_angle);
5881+ angle_deg = Math::snapped (angle_deg, snap_step);
5882+ rotation_angle = Math::deg_to_rad (angle_deg);
5883+ }
5884+
5885+ double angle_deg = Math::rad_to_deg (rotation_angle);
5886+ set_message (vformat (TTR (" Rotating %s degrees." ), String::num (angle_deg, 2 )));
5887+
5888+ apply_transform (rotation_axis, rotation_angle);
5889+ }
5890+ break ;
5891+ }
5892+
58205893 Vector3 local_axis;
58215894 Vector3 global_axis;
58225895 switch (_edit.plane ) {
@@ -5973,6 +6046,7 @@ void Node3DEditorViewport::finish_transform() {
59736046 _edit.numeric_input = 0 ;
59746047 _edit.numeric_next_decimal = 0 ;
59756048 _edit.numeric_negate = false ;
6049+ _edit.is_trackball = false ;
59766050 _edit.initial_click_vector = Vector3 ();
59776051 _edit.previous_rotation_vector = Vector3 ();
59786052 _edit.accumulated_rotation_angle = 0.0 ;
@@ -6784,12 +6858,15 @@ void Node3DEditor::select_gizmo_highlight_axis(int p_axis) {
67846858 for (int i = 0 ; i < 4 ; i++) {
67856859 bool highlight;
67866860 if (i == 3 ) {
6787- highlight = (p_axis == 15 );
6861+ highlight = (p_axis == GIZMO_HIGHLIGHT_AXIS_VIEW_ROTATION );
67886862 } else {
67896863 highlight = (i + 3 ) == p_axis;
67906864 }
67916865 rotate_gizmo[i]->surface_set_material (0 , highlight ? rotate_gizmo_color_hl[i] : rotate_gizmo_color[i]);
67926866 }
6867+
6868+ bool highlight_trackball = (p_axis == GIZMO_HIGHLIGHT_AXIS_TRACKBALL);
6869+ trackball_sphere_gizmo->surface_set_material (0 , highlight_trackball ? trackball_sphere_material_hl : trackball_sphere_material);
67936870}
67946871
67956872void Node3DEditor::update_transform_gizmo () {
@@ -8166,6 +8243,62 @@ void fragment() {
81668243 }
81678244 }
81688245
8246+ // Create trackball sphere
8247+ {
8248+ trackball_sphere_gizmo.instantiate ();
8249+ Ref<SurfaceTool> surftool;
8250+ surftool.instantiate ();
8251+ surftool->begin (Mesh::PRIMITIVE_TRIANGLES);
8252+
8253+ const int sphere_rings = TRACKBALL_SPHERE_RINGS;
8254+ const int sphere_sectors = TRACKBALL_SPHERE_SECTORS;
8255+ const real_t sphere_radius = GIZMO_CIRCLE_SIZE;
8256+
8257+ for (int r = 0 ; r <= sphere_rings; ++r) {
8258+ for (int s = 0 ; s <= sphere_sectors; ++s) {
8259+ real_t ring_angle = Math::PI * r / sphere_rings;
8260+ real_t sector_angle = 2.0 * Math::PI * s / sphere_sectors;
8261+
8262+ Vector3 vertex (
8263+ sphere_radius * Math::sin (ring_angle) * Math::cos (sector_angle),
8264+ sphere_radius * Math::cos (ring_angle),
8265+ sphere_radius * Math::sin (ring_angle) * Math::sin (sector_angle));
8266+
8267+ surftool->set_normal (vertex.normalized ());
8268+ surftool->add_vertex (vertex);
8269+ }
8270+ }
8271+
8272+ for (int r = 0 ; r < sphere_rings; ++r) {
8273+ for (int s = 0 ; s < sphere_sectors; ++s) {
8274+ int current = r * (sphere_sectors + 1 ) + s;
8275+ int next = current + sphere_sectors + 1 ;
8276+
8277+ surftool->add_index (current);
8278+ surftool->add_index (next);
8279+ surftool->add_index (current + 1 );
8280+
8281+ surftool->add_index (current + 1 );
8282+ surftool->add_index (next);
8283+ surftool->add_index (next + 1 );
8284+ }
8285+ }
8286+
8287+ trackball_sphere_material.instantiate ();
8288+ trackball_sphere_material->set_shading_mode (StandardMaterial3D::SHADING_MODE_UNSHADED);
8289+ trackball_sphere_material->set_flag (StandardMaterial3D::FLAG_DISABLE_FOG, true );
8290+ trackball_sphere_material->set_transparency (StandardMaterial3D::TRANSPARENCY_ALPHA);
8291+ trackball_sphere_material->set_cull_mode (StandardMaterial3D::CULL_DISABLED);
8292+ trackball_sphere_material->set_albedo (Color (1.0 , 1.0 , 1.0 , 0.0 ));
8293+ trackball_sphere_material->set_flag (StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true );
8294+
8295+ trackball_sphere_material_hl = trackball_sphere_material->duplicate ();
8296+ trackball_sphere_material_hl->set_albedo (Color (1.0 , 1.0 , 1.0 , TRACKBALL_HIGHLIGHT_ALPHA));
8297+
8298+ surftool->set_material (trackball_sphere_material);
8299+ surftool->commit (trackball_sphere_gizmo);
8300+ }
8301+
81698302 _generate_selection_boxes ();
81708303}
81718304
0 commit comments