Вопрос или проблема
В Godot я получаю ошибку “Неверное присвоение ключа или свойства ‘basis’ со значением типа ‘Quaternion’ на базовом объекте типа ‘Transform3D’.” из следующей функции:
func _orient_character_to_direction(direction: Vector3, delta: float) -> void:
var left_axis = -local_gravity.cross(direction)
var rotation_basis := Basis(left_axis, -local_gravity, direction).orthonormalized()
_model.transform.basis = _model.transform.basis.get_rotation_quaternion().slerp(rotation_basis, delta * rotation_speed)
Я следую “уроку”, сделанному для более старой версии Godot, и некоторые вещи не передаются точно. Тем не менее, я не уверен, почему возникает эта конкретная ошибка, и никто другой, похоже, с ней не сталкивается.
К своему удивлению, несмотря на то что этот код написан на GDScript, я получаю эту ошибку:
E 0:00:00:0458 testplayer.gd:50 @ _orient_character_to_direction(): Basis [X: (0, 0, 0), Y: (0, 0, 0), Z: (0, 0, 0)] должен быть нормализован, чтобы его можно было привести к Quaternion. Используйте get_rotation_quaternion() или вызовите orthonormalized(), если Basis содержит линейно независимые векторы.
<C++ Ошибка> Условие “!is_rotation()” истинно. Возвращение: Quaternion()
<C++ Исходный код> core/math/basis.cpp:725 @ get_quaternion()
testplayer.gd:50 @ _orient_character_to_direction()
testplayer.gd:25 @ _integrate_forces()
В соответствии с этой ошибкой я попытался вызвать orthonormalized()
с обеих сторон присвоения _model.transform.basis = _model.transform.basis.get_rotation_quaternion().slerp(rotation_basis, delta * rotation_speed)
, но это было либо неверный вызов (использовать его после кватерниона), либо ничего не давало, и ошибка сохранялась, в зависимости от того, где я его вызывал (я пробовал везде, даже в тех местах, где это не имело смысла). Я также пытался вызвать normalized()
на кватернионе, но безуспешно.
Урок, который я смотрю, можно найти здесь, а конкретная функция с ошибкой на 2:49.
Примечание: Я не силен в математике, и это мой первый раз с кватернионами, так что если это очень простая ошибка, прошу прощения.
Ответ или решение
Ошибка "Invalid assignment of key or property ‘basis’ with a value of type ‘Quaternion’ on a base object of type ‘Transform3D’" в Godot при попытке присвоения кватерниона
Вы столкнулись с распространенной ошибкой, касающейся работы с кватернионами и базами в Godot. Это достаточно распространенный вопрос, особенно для пользователей, переходящих от более старых версий движка. Давайте разберем вашу проблему подробно, чтобы выяснить, почему возникает данная ошибка и как её устранить.
Анализ кода
Ваш код выглядит следующим образом:
func _orient_character_to_direction(direction: Vector3, delta: float) -> void:
var left_axis = -local_gravity.cross(direction)
var rotation_basis := Basis(left_axis, -local_gravity, direction).orthonormalized()
_model.transform.basis = _model.transform.basis.get_rotation_quaternion().slerp(rotation_basis, delta * rotation_speed)
-
Ошибка присвоения: Сообщение об ошибке указывает на то, что вы пытаетесь присвоить кватернион (в результате вызова
slerp
) свойствуbasis
, которое ожидаетBasis
, а неQuaternion
. -
Объект
Basis
: В Godot классBasis
представляет собой 3D вращение, состоящее из трех векторов (векторы осей координат). Чтобы присвоить новыйBasis
, вы должны обеспечить корректное преобразование из кватерниона. -
Нормализация: Когда векторная база становится вырожденной (линейно зависимой), метод
get_rotation_quaternion()
не может вернуть корректный кватернион. Это означает, что вектора вBasis
должны быть взаимно перпендикулярными и нормализованными.
Решение проблемы
Вот более правильный способ реализации вашей функции:
func _orient_character_to_direction(direction: Vector3, delta: float) -> void:
var left_axis = -local_gravity.cross(direction).normalized()
var rotation_basis = Basis(left_axis, -local_gravity.normalized(), direction.normalized()).orthonormalized()
# Получаем текущий кватернион.
var current_quaternion = _model.transform.basis.get_rotation_quaternion()
# Смешиваем кватернионы и преобразуем обратно в Basis.
var target_quaternion = current_quaternion.slerp(rotation_basis.get_rotation_quaternion(), delta * rotation_speed)
# Присваиваем Basis, полученное из кватерниона.
_model.transform.basis = Basis(target_quaternion)
Объяснение изменений
-
Нормализация векторов: Векторы, используемые для создания
Basis
, нормализуются. Это критически важно для того, чтобы избежать проблем с вырожденной базой. -
Смешивание кватернионов: Корректно получать кватернион от
rotation_basis
перед смешиванием с текущим кватернионом и преобразовать результат обратно вBasis
. В этом процессе важно, чтобы оба кватерниона были корректны. -
Корректное присвоение: В конце присваиваем новое значение
basis
, основанное на полученном кватернионе.
Заключительные рекомендации
Переход от одной версии Godot к другой может вызвать трудности из-за изменений в API и поведения классов. Рекомендуется проверять документацию на официальном сайте Godot для актуальных версий, иногда наличие устаревшего кода может приводить к непредсказуемым ошибкам.
Кроме того, попробуйте отладить ваш код, добавляя вывод значений в процессе выполнения, это поможет лучше понять, что именно происходит на каждом этапе. Удачи в вашей разработке!