@@ -283,9 +283,15 @@ void EditorTransformGizmoND::_update_gizmo_transform() {
283283 set_visible (false );
284284 } else {
285285 set_visible (true );
286+ sum_transform = sum_transform->divide_scalar (double (transform_count));
287+ if (!_is_use_local_rotation) {
288+ sum_transform->set_basis (BasisND::from_scale (sum_transform->get_global_scale_abs ()));
289+ }
286290 const int old_dimension = get_dimension ();
287- set_transform (sum_transform->divide_scalar (double (transform_count)));
288- if (old_dimension != get_dimension ()) {
291+ const int new_dimension = sum_transform->get_dimension ();
292+ sum_transform->set_dimension (new_dimension); // Force to be a square matrix.
293+ set_transform (sum_transform);
294+ if (old_dimension != new_dimension) {
289295 // The gizmo has changed dimensions, so we need to regenerate the meshes.
290296 _regenerate_gizmo_meshes ();
291297 _editor_main_screen->update_dimension ();
@@ -296,35 +302,28 @@ void EditorTransformGizmoND::_update_gizmo_transform() {
296302void EditorTransformGizmoND::_update_gizmo_mesh_transform (const CameraND *p_camera) {
297303 // We want to keep the gizmo the same size on the screen regardless of the camera's position.
298304 const Ref<TransformND> camera_transform = p_camera->get_global_transform ();
299- Ref<TransformND> global_transform;
300- global_transform.instantiate ();
301- if (_is_use_local_rotation) {
302- global_transform = get_transform ()->normalized ();
303- } else {
304- global_transform = TransformND::identity_basis (get_dimension ());
305- global_transform->set_origin (get_transform ()->get_origin ());
306- }
305+ const Ref<TransformND> gizmo_transform = get_transform ();
306+ const VectorN gizmo_scale_abs = gizmo_transform->get_scale_abs ();
307307 if (_is_stretch_enabled) {
308- const Ref<RectND> bounds = _get_rect_bounds_of_selection (global_transform->inverse ());
308+ const Ref<RectND> bounds = _get_rect_bounds_of_selection (gizmo_transform->inverse ());
309+ Ref<TransformND> global_transform = gizmo_transform->duplicate ();
309310 global_transform->translate_local (bounds->get_center ());
311+ global_transform->scale_local (VectorND::multiply_scalar (bounds->get_size (), 0 .5f ));
310312 const VectorN bounds_size = bounds->get_size ();
311- const bool zero_size = VectorND::is_zero_approx (bounds_size);
312- if (!zero_size) {
313- const VectorN scale = VectorND::multiply_scalar (bounds_size, 0.5 );
314- global_transform->scale_local (VectorND::with_dimension (scale, global_transform->get_basis_column_count ()));
315- }
316- _mesh_holder->set_visible (!zero_size);
313+ const double determinant = VectorND::multiply_components_together (bounds_size);
314+ set_visible (!Math::is_zero_approx (determinant));
315+ _mesh_holder->set_global_transform (global_transform);
316+ return ;
317+ }
318+ double scale;
319+ if (p_camera->get_projection_type () == CameraND::PROJECTION_ORTHOGRAPHIC) {
320+ scale = p_camera->get_orthographic_size () * 0.4 ;
317321 } else {
318- double scale;
319- if (p_camera->get_projection_type () == CameraND::PROJECTION_ORTHOGRAPHIC) {
320- scale = p_camera->get_orthographic_size () * 0 .4f ;
321- } else {
322- scale = VectorND::distance_to (global_transform->get_origin (), camera_transform->get_origin ()) * 0 .4f ;
323- }
324- global_transform->scale_uniform (scale);
325- _mesh_holder->set_visible (true );
322+ scale = VectorND::distance_to (gizmo_transform->get_origin (), camera_transform->get_origin ()) * 0.4 ;
326323 }
327- _mesh_holder->set_global_transform (global_transform);
324+ const VectorN scale_vector = VectorND::fill (get_dimension (), scale);
325+ const VectorN mesh_holder_scale = VectorND::divide_vector (scale_vector, gizmo_scale_abs);
326+ _mesh_holder->set_basis (BasisND::from_scale (mesh_holder_scale));
328327}
329328
330329Ref<RectND> EditorTransformGizmoND::_get_rect_bounds_of_selection (const Ref<TransformND> &p_inv_relative_to) const {
@@ -523,7 +522,8 @@ Variant EditorTransformGizmoND::_get_transform_raycast_value(const VectorN &p_lo
523522}
524523
525524void EditorTransformGizmoND::_begin_transformation (const VectorN &p_local_ray_origin, const VectorN &p_local_ray_direction) {
526- _old_transform = _mesh_holder->get_global_transform ();
525+ _old_gizmo_transform = get_transform ()->duplicate ();
526+ _old_mesh_holder_transform = _mesh_holder->get_transform ()->duplicate ();
527527 _transform_reference_value = _get_transform_raycast_value (p_local_ray_origin, p_local_ray_direction);
528528 _selected_top_node_old_transforms.resize (_selected_top_nodes.size ());
529529 for (int i = 0 ; i < _selected_top_nodes.size (); i++) {
@@ -551,7 +551,6 @@ void EditorTransformGizmoND::_end_transformation() {
551551 }
552552 _undo_redo->commit_action (false );
553553 // Clear out the transformation data and mark the scene as unsaved.
554- _old_transform = Ref<TransformND>();
555554 _transform_reference_value = Variant ();
556555 _current_transformation = TRANSFORM_NONE;
557556 EditorInterface::get_singleton ()->mark_scene_as_unsaved ();
@@ -577,7 +576,7 @@ void EditorTransformGizmoND::_process_transform(const VectorN &p_local_ray_origi
577576 ERR_FAIL_COND (casted_vec.size () <= _primary_axis);
578577 const double scale_factor = casted_vec[_primary_axis] / VectorN (_transform_reference_value)[_primary_axis];
579578 if (_keep_mode == KeepMode::CONFORMAL) {
580- const VectorN scale = VectorND::fill (scale_factor, get_dimension ());
579+ const VectorN scale = VectorND::fill (get_dimension (), scale_factor );
581580 transform_change = TransformND::from_scale (scale);
582581 } else {
583582 transform_change->set_basis_element (_primary_axis, _primary_axis, scale_factor);
@@ -594,7 +593,7 @@ void EditorTransformGizmoND::_process_transform(const VectorN &p_local_ray_origi
594593 case TRANSFORM_STRETCH_POS: {
595594 const double stretch = VectorN (casted)[_primary_axis] * 0 .5f ;
596595 if (_keep_mode == KeepMode::CONFORMAL) {
597- const VectorN scale = VectorND::fill (stretch + 0 .5f , get_dimension () );
596+ const VectorN scale = VectorND::fill (get_dimension (), stretch + 0 .5f );
598597 transform_change = TransformND::from_scale (scale);
599598 } else {
600599 transform_change->set_basis_element (_primary_axis, _primary_axis, stretch + 0 .5f );
@@ -604,7 +603,7 @@ void EditorTransformGizmoND::_process_transform(const VectorN &p_local_ray_origi
604603 case TRANSFORM_STRETCH_NEG: {
605604 const double stretch = VectorN (casted)[_primary_axis] * 0 .5f ;
606605 if (_keep_mode == KeepMode::CONFORMAL) {
607- const VectorN scale = VectorND::fill (-stretch + 0 .5f , get_dimension () );
606+ const VectorN scale = VectorND::fill (get_dimension (), -stretch + 0 .5f );
608607 transform_change = TransformND::from_scale (scale);
609608 } else {
610609 transform_change->set_basis_element (_primary_axis, _primary_axis, -stretch + 0 .5f );
@@ -615,11 +614,14 @@ void EditorTransformGizmoND::_process_transform(const VectorN &p_local_ray_origi
615614 ERR_FAIL_MSG (" Invalid transformation." );
616615 } break ;
617616 }
618- Ref<TransformND> new_transform = _old_transform->compose_square (transform_change);
617+ // The above position changes happen relative to the visual gizmo mesh holder, but
618+ // we want them relative to the gizmo itself. Scale/rotation should not be adjusted.
619+ transform_change->set_origin (_old_mesh_holder_transform->xform (transform_change->get_origin ()));
620+ Ref<TransformND> new_transform = _old_gizmo_transform->compose_square (transform_change);
619621 set_transform (new_transform);
620622 // We want the global diff so we can apply it from the left on the global transform of all selected nodes.
621623 // Without this, the transforms would be relative to each node (ex: moving on X moves on each node's X axis).
622- transform_change = _old_transform ->transform_to (new_transform);
624+ transform_change = _old_gizmo_transform ->transform_to (new_transform);
623625 for (int i = 0 ; i < _selected_top_nodes.size (); i++) {
624626 NodeND *node_nd = Object::cast_to<NodeND>(_selected_top_nodes[i]);
625627 if (node_nd != nullptr ) {
@@ -768,21 +770,23 @@ bool EditorTransformGizmoND::gizmo_mouse_input(const Ref<InputEventMouse> &p_mou
768770 const VectorN ray_origin = p_camera->viewport_to_world_ray_origin (mouse_position);
769771 const VectorN ray_direction = p_camera->viewport_to_world_ray_direction (mouse_position);
770772 if (_current_transformation == TRANSFORM_NONE) {
771- _old_transform = _mesh_holder->get_global_transform ();
773+ _old_gizmo_transform = get_transform ()->duplicate ();
774+ _old_mesh_holder_transform = _mesh_holder->get_transform ()->duplicate ();
772775 }
773- if (_old_transform ->get_basis_column_count () == 0 ) {
776+ if (_old_gizmo_transform ->get_basis_column_count () == 0 ) {
774777 // 0D, so nothing to do.
775778 set_visible (false );
776779 return false ;
777780 }
778- if (Math::is_zero_approx (_old_transform ->determinant ())) {
781+ if (Math::is_zero_approx (_old_gizmo_transform ->determinant ())) {
779782 // Something's wrong with our transform. Let's try to fix it.
780- set_transform (get_transform ()->orthonormalized ());
781- _mesh_holder->set_transform (_mesh_holder->get_transform ()->orthonormalized ());
782- _old_transform = _mesh_holder->get_global_transform ();
783- ERR_FAIL_COND_V_MSG (Math::is_zero_approx (_old_transform->determinant ()), false , " EditorTransformGizmoND: Gizmo transform is not valid." );
783+ _old_gizmo_transform = get_transform ()->orthonormalized ();
784+ _old_mesh_holder_transform = _mesh_holder->get_transform ()->orthonormalized ();
785+ set_transform (_old_gizmo_transform);
786+ _mesh_holder->set_transform (_old_mesh_holder_transform);
787+ ERR_FAIL_COND_V_MSG (Math::is_zero_approx (_old_gizmo_transform->determinant ()), false , " EditorTransformGizmoND: Gizmo transform is not valid." );
784788 }
785- const Ref<TransformND> global_to_local = _old_transform ->inverse ();
789+ const Ref<TransformND> global_to_local = _old_gizmo_transform-> compose_square (_old_mesh_holder_transform) ->inverse ();
786790 const VectorN local_ray_origin = global_to_local->xform (ray_origin);
787791 const VectorN local_ray_direction = global_to_local->xform_basis (ray_direction);
788792 return gizmo_mouse_raycast (p_mouse_event, local_ray_origin, local_ray_direction);
0 commit comments