diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp index 08eac14b76d6..eb2fa2d86565 100644 --- a/core/math/quaternion.cpp +++ b/core/math/quaternion.cpp @@ -83,7 +83,7 @@ Quaternion Quaternion::normalized() const { } bool Quaternion::is_normalized() const { - return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); //use less epsilon + return Math::is_equal_approx(length(), 1, (real_t)UNIT_EPSILON); //use less epsilon } Quaternion Quaternion::inverse() const { diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index c5a35e466c91..9b04fbc215e5 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1941,6 +1941,30 @@ void EditorPropertyQuaternion::_set_read_only(bool p_read_only) { } } +void EditorPropertyQuaternion::_edit_normalize_quaternion_value() { + if (normalize_quaternion_bttn->is_pressed()) { + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action("Quaternion Normalized"); + + Quaternion temp; + for (int i = 0; i < 4; i++) { + temp[i] = (real_t)spin[i]->get_value(); + + //undo_redo->add_undo_property(spin[i], "Un-Normalize Quaternion", spin[i]); + undo_redo->add_undo_property(get_edited_object(), get_edited_property(), spin[i]); + } + temp = temp.normalized(); + for (int i = 0; i < 4; i++) { + spin[i]->set_value_no_signal((double)temp[i]); + + undo_redo->add_undo_property(get_edited_object(), get_edited_property(), temp[i]); + //undo_redo->add_do_property(spin[i], "Re-Normalize Quaternion", temp[i]); + } + _value_changed(-1, ""); + undo_redo->commit_action(); + } +} + void EditorPropertyQuaternion::_edit_custom_value() { if (edit_button->is_pressed()) { edit_custom_bc->show(); @@ -2065,6 +2089,7 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() { VBoxContainer *bc = memnew(VBoxContainer); edit_custom_bc = memnew(VBoxContainer); + normalize_quaternion = memnew(VBoxContainer); BoxContainer *edit_custom_layout; if (horizontal) { default_layout = memnew(HBoxContainer); @@ -2076,10 +2101,12 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() { } edit_custom_bc->hide(); add_child(bc); + normalize_quaternion->set_h_size_flags(SIZE_EXPAND_FILL); edit_custom_bc->set_h_size_flags(SIZE_EXPAND_FILL); default_layout->set_h_size_flags(SIZE_EXPAND_FILL); edit_custom_layout->set_h_size_flags(SIZE_EXPAND_FILL); bc->add_child(default_layout); + bc->add_child(normalize_quaternion); bc->add_child(edit_custom_bc); static const char *desc[4] = { "x", "y", "z", "w" }; @@ -2095,6 +2122,12 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() { } } + normalize_quaternion_bttn = memnew(Button); + normalize_quaternion_bttn->set_text("Normalize"); + normalize_quaternion_bttn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyQuaternion::_edit_normalize_quaternion_value)); + add_focusable(normalize_quaternion_bttn); + normalize_quaternion->add_child(normalize_quaternion_bttn); + warning = memnew(Button); warning->set_text(TTR("Temporary Euler may be changed implicitly!")); warning->set_clip_text(true); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 004630da3e22..897e2104158b 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -487,14 +487,17 @@ class EditorPropertyQuaternion : public EditorProperty { AcceptDialog *warning_dialog = nullptr; Label *euler_label = nullptr; + VBoxContainer *normalize_quaternion = nullptr; VBoxContainer *edit_custom_bc = nullptr; EditorSpinSlider *euler[3]; Button *edit_button = nullptr; + Button *normalize_quaternion_bttn = nullptr; Vector3 edit_euler; void _value_changed(double p_val, const String &p_name); void _edit_custom_value(); + void _edit_normalize_quaternion_value(); void _custom_value_changed(double p_val); void _warning_pressed(); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 9e4c9b183266..521c8ff38a9c 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -865,6 +865,10 @@ void Skeleton3D::set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation const int bone_size = bones.size(); ERR_FAIL_INDEX(p_bone, bone_size); + if (!p_rotation.is_normalized()) { + WARN_PRINT_ED("The quaternion bone " + get_bone_name(p_bone) + " pose rotation must be normalized."); + } + bones[p_bone].pose_rotation = p_rotation; bones[p_bone].pose_cache_dirty = true; if (is_inside_tree()) {