Skip to content

Commit 91434a0

Browse files
committed
Cleanup gizmo mesh holder transform separation
1 parent 44f5d36 commit 91434a0

File tree

8 files changed

+92
-54
lines changed

8 files changed

+92
-54
lines changed

editor/viewport/editor_transform_gizmo_nd.cpp

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -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() {
296302
void 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

330329
Ref<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

525524
void 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);

editor/viewport/editor_transform_gizmo_nd.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ class EditorTransformGizmoND : public NodeND {
5555
int _primary_axis = -1;
5656
int _secondary_axis = -1;
5757

58-
Ref<TransformND> _old_transform;
58+
Ref<TransformND> _old_gizmo_transform;
59+
Ref<TransformND> _old_mesh_holder_transform;
5960
Variant _transform_reference_value = Variant();
6061
TypedArray<Node> _selected_top_nodes;
6162
Vector<Ref<TransformND>> _selected_top_node_old_transforms;

math/basis_nd.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,16 @@ Ref<BasisND> BasisND::inverse_transposed() const {
522522

523523
// Scale methods.
524524

525+
VectorN BasisND::get_global_scale_abs() const {
526+
const int row_count = get_row_count();
527+
VectorN scale;
528+
scale.resize(row_count);
529+
for (int i = 0; i < row_count; i++) {
530+
scale.set(i, VectorND::length(get_row(i)));
531+
}
532+
return scale;
533+
}
534+
525535
VectorN BasisND::get_scale_abs() const {
526536
const int column_count = _columns.size();
527537
VectorN scale;

math/basis_nd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class BasisND : public RefCounted {
6969
Ref<BasisND> inverse_transposed() const;
7070

7171
// Scale methods.
72+
VectorN get_global_scale_abs() const;
7273
VectorN get_scale_abs() const;
7374
void set_scale_abs(const VectorN &p_scale);
7475
double get_uniform_scale() const;

math/transform_nd.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,16 @@ Ref<TransformND> TransformND::inverse_transposed() const {
616616

617617
// Scale methods.
618618

619+
VectorN TransformND::get_global_scale_abs() const {
620+
const int row_count = get_basis_row_count();
621+
VectorN scale;
622+
scale.resize(row_count);
623+
for (int i = 0; i < row_count; i++) {
624+
scale.set(i, VectorND::length(get_basis_row(i)));
625+
}
626+
return scale;
627+
}
628+
619629
VectorN TransformND::get_scale_abs() const {
620630
const int column_count = _columns.size();
621631
VectorN scale;
@@ -1123,7 +1133,7 @@ Ref<TransformND> TransformND::identity_basis(const int p_dimension) {
11231133

11241134
Ref<TransformND> TransformND::identity_transform(const int p_dimension) {
11251135
Ref<TransformND> ret = identity_basis(p_dimension);
1126-
ret->set_origin(VectorND::fill(0.0, p_dimension));
1136+
ret->set_origin(VectorND::zero(p_dimension));
11271137
return ret;
11281138
}
11291139

math/transform_nd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class TransformND : public RefCounted {
9090
Ref<TransformND> inverse_transposed() const;
9191

9292
// Scale methods.
93+
VectorN get_global_scale_abs() const;
9394
VectorN get_scale_abs() const;
9495
void set_scale_abs(const VectorN &p_scale);
9596
double get_uniform_scale() const;

math/vector_nd.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ VectorN VectorND::duplicate(const VectorN &p_vector) {
338338
return duplicate_vector;
339339
}
340340

341-
VectorN VectorND::fill(const double p_value, const int64_t p_dimension) {
341+
VectorN VectorND::fill(const int64_t p_dimension, const double p_value) {
342342
VectorN filled_vector;
343343
filled_vector.resize(p_dimension);
344344
for (int64_t i = 0; i < p_dimension; i++) {
@@ -347,7 +347,7 @@ VectorN VectorND::fill(const double p_value, const int64_t p_dimension) {
347347
return filled_vector;
348348
}
349349

350-
Vector<VectorN> VectorND::fill_array(const double p_value, const int64_t p_vector_amount, const int64_t p_dimension) {
350+
Vector<VectorN> VectorND::fill_array(const int64_t p_dimension, const int64_t p_vector_amount, const double p_value) {
351351
Vector<VectorN> filled_array;
352352
filled_array.resize(p_vector_amount);
353353
const VectorN filled_vector = fill(p_value, p_dimension);
@@ -357,8 +357,8 @@ Vector<VectorN> VectorND::fill_array(const double p_value, const int64_t p_vecto
357357
return filled_array;
358358
}
359359

360-
TypedArray<VectorN> VectorND::fill_array_bind(const double p_value, const int64_t p_vector_amount, const int64_t p_dimension) {
361-
Vector<VectorN> filled_array = VectorND::fill_array(p_value, p_vector_amount, p_dimension);
360+
TypedArray<VectorN> VectorND::fill_array_bind(const int64_t p_dimension, const int64_t p_vector_amount, const double p_value) {
361+
Vector<VectorN> filled_array = VectorND::fill_array(p_dimension, p_vector_amount, p_value);
362362
TypedArray<VectorN> filled_array_variant;
363363
filled_array_variant.resize(p_vector_amount);
364364
for (int64_t i = 0; i < p_vector_amount; i++) {
@@ -510,6 +510,15 @@ int64_t VectorND::min_axis_index(const VectorN &p_vector) {
510510
return min_index;
511511
}
512512

513+
double VectorND::multiply_components_together(const VectorN &p_vector) {
514+
const int64_t dimension = p_vector.size();
515+
double product = 1.0;
516+
for (int64_t i = 0; i < dimension; i++) {
517+
product *= p_vector[i];
518+
}
519+
return product;
520+
}
521+
513522
VectorN VectorND::multiply_vector(const VectorN &p_a, const VectorN &p_b, const bool p_expand) {
514523
const int64_t dimension = p_expand ? MAX(p_a.size(), p_b.size()) : MIN(p_a.size(), p_b.size());
515524
VectorN product;
@@ -598,9 +607,9 @@ VectorN VectorND::perpendicular(const Vector<VectorN> &p_input_vectors) {
598607
WARN_PRINT("VectorND.perpendicular: Calculating a perpendicular vector in " + itos(dimension) + "-dimensional space will be very slow.");
599608
}
600609
// Allocate the result vector and a matrix to perform the intermediate calculations.
601-
VectorN result = VectorND::fill(0.0, dimension);
610+
VectorN result = VectorND::zero(dimension);
602611
const int64_t sub_size = count; // == dimension - 1
603-
Vector<VectorN> sub_matrix = VectorND::fill_array(0.0, sub_size, sub_size);
612+
Vector<VectorN> sub_matrix = VectorND::fill_array(sub_size, sub_size, 0.0);
604613
// Flip the entire result if dimension is even.
605614
const bool global_parity = (dimension % 2 == 0);
606615
// This algorithm was found by ChatGPT and manually tweaked. It is likely suboptimal.
@@ -944,8 +953,8 @@ void VectorND::_bind_methods() {
944953
ClassDB::bind_static_method("VectorND", D_METHOD("dot", "a", "b"), &VectorND::dot);
945954
ClassDB::bind_static_method("VectorND", D_METHOD("drop_first_dimensions", "vector", "dimensions"), &VectorND::drop_first_dimensions);
946955
ClassDB::bind_static_method("VectorND", D_METHOD("duplicate", "vector"), &VectorND::duplicate);
947-
ClassDB::bind_static_method("VectorND", D_METHOD("fill", "value", "dimension"), &VectorND::fill);
948-
ClassDB::bind_static_method("VectorND", D_METHOD("fill_array", "value", "vector_amount", "dimension"), &VectorND::fill_array_bind);
956+
ClassDB::bind_static_method("VectorND", D_METHOD("fill", "dimension", "value"), &VectorND::fill);
957+
ClassDB::bind_static_method("VectorND", D_METHOD("fill_array", "dimension", "vector_amount", "value"), &VectorND::fill_array_bind);
949958
ClassDB::bind_static_method("VectorND", D_METHOD("floor", "vector"), &VectorND::floor);
950959
ClassDB::bind_static_method("VectorND", D_METHOD("inverse", "vector"), &VectorND::inverse);
951960
ClassDB::bind_static_method("VectorND", D_METHOD("is_equal_approx", "a", "b"), &VectorND::is_equal_approx);
@@ -959,6 +968,7 @@ void VectorND::_bind_methods() {
959968
ClassDB::bind_static_method("VectorND", D_METHOD("max_absolute_axis_index", "vector"), &VectorND::max_absolute_axis_index);
960969
ClassDB::bind_static_method("VectorND", D_METHOD("max_axis_index", "vector"), &VectorND::max_axis_index);
961970
ClassDB::bind_static_method("VectorND", D_METHOD("min_axis_index", "vector"), &VectorND::min_axis_index);
971+
ClassDB::bind_static_method("VectorND", D_METHOD("multiply_components_together", "vector"), &VectorND::multiply_components_together);
962972
ClassDB::bind_static_method("VectorND", D_METHOD("multiply_vector", "a", "b", "expand"), &VectorND::multiply_vector, DEFVAL(false));
963973
ClassDB::bind_static_method("VectorND", D_METHOD("multiply_scalar", "vector", "scalar"), &VectorND::multiply_scalar);
964974
ClassDB::bind_static_method("VectorND", D_METHOD("negate", "vector"), &VectorND::negate);

math/vector_nd.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ class VectorND : public Object {
7070
static double dot(const VectorN &p_a, const VectorN &p_b);
7171
static VectorN drop_first_dimensions(const VectorN &p_vector, const int64_t p_dimensions);
7272
static VectorN duplicate(const VectorN &p_vector);
73-
static VectorN fill(const double p_value, const int64_t p_dimension);
74-
static Vector<VectorN> fill_array(const double p_value, const int64_t p_vector_amount, const int64_t p_dimension);
75-
static TypedArray<VectorN> fill_array_bind(const double p_value, const int64_t p_vector_amount, const int64_t p_dimension);
73+
static VectorN fill(const int64_t p_dimension, const double p_value);
74+
static Vector<VectorN> fill_array(const int64_t p_dimension, const int64_t p_vector_amount, const double p_value);
75+
static TypedArray<VectorN> fill_array_bind(const int64_t p_dimension, const int64_t p_vector_amount, const double p_value);
7676
static VectorN floor(const VectorN &p_vector);
7777
static VectorN inverse(const VectorN &p_vector);
7878
static bool is_equal_approx(const VectorN &p_a, const VectorN &p_b);
@@ -86,6 +86,7 @@ class VectorND : public Object {
8686
static int64_t max_absolute_axis_index(const VectorN &p_vector);
8787
static int64_t max_axis_index(const VectorN &p_vector);
8888
static int64_t min_axis_index(const VectorN &p_vector);
89+
static double multiply_components_together(const VectorN &p_vector);
8990
static VectorN multiply_vector(const VectorN &p_a, const VectorN &p_b, const bool p_expand = false);
9091
static VectorN multiply_scalar(const VectorN &p_vector, const double p_scalar);
9192
static void multiply_scalar_and_add_in_place(const VectorN &p_vector, const double p_scalar, VectorN &r_result);

0 commit comments

Comments
 (0)