Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/math/quaternion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

@TokageItLab TokageItLab May 22, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return Math::is_equal_approx(length(), 1, (real_t)UNIT_EPSILON); //use less epsilon
return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); //use less epsilon

Since this issue depends on the accuracy of the inspector, the correct fix is to do it in the inspector, as in #106352.

If the accuracy of Quaternion's input in the inspector is increased by #106352, this line change is not necessary.

}

Quaternion Quaternion::inverse() const {
Expand Down
33 changes: 33 additions & 0 deletions editor/editor_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Comment on lines +1946 to +1964

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If property's set_value() remains in the history, then I assume undo/redo may be enabled without add_undo_property(). In other words, maybe we should consider a way to avoid the need for the EditorUndoRedoManager here.

}
}

void EditorPropertyQuaternion::_edit_custom_value() {
if (edit_button->is_pressed()) {
edit_custom_bc->show();
Expand Down Expand Up @@ -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);
Expand All @@ -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" };
Expand All @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions editor/editor_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -487,14 +487,17 @@ class EditorPropertyQuaternion : public EditorProperty {
AcceptDialog *warning_dialog = nullptr;

Label *euler_label = nullptr;
VBoxContainer *normalize_quaternion = nullptr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
VBoxContainer *normalize_quaternion = nullptr;
VBoxContainer *normalize_quaternion_btn_container = nullptr;

The name should be clearer.

@TokageItLab TokageItLab May 22, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I felt that the normalization button is overemphasized.

So how about making the letters “Nrm” or “1.0” into icons and placing them to the right of the SpinBox?

Then, it will conflicts with EulerEdit, so I think it would be smartest way is making it function as Nrm button when is_normalized() is false, and as EulerEdit button when is_normalized() is true since EulerEdit shouldn't be used for non-normalized quaternions.

In other words, it places only one button to the right of the SpinBox, whose icon changes depending on the state of is_normalized().

VBoxContainer *edit_custom_bc = nullptr;
EditorSpinSlider *euler[3];
Button *edit_button = nullptr;
Button *normalize_quaternion_bttn = nullptr;
Comment thread
TokageItLab marked this conversation as resolved.

@TokageItLab TokageItLab May 22, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Button *normalize_quaternion_bttn = nullptr;
Button *normalize_quaternion_btn = nullptr;

Nitpick for consistency with other classes.


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();

Expand Down
4 changes: 4 additions & 0 deletions scene/3d/skeleton_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down