Ошибка недопустимого присвоения в Godot при попытке присвоить кватернион?

Вопрос или проблема

В 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)
  1. Ошибка присвоения: Сообщение об ошибке указывает на то, что вы пытаетесь присвоить кватернион (в результате вызова slerp) свойству basis, которое ожидает Basis, а не Quaternion.

  2. Объект Basis: В Godot класс Basis представляет собой 3D вращение, состоящее из трех векторов (векторы осей координат). Чтобы присвоить новый Basis, вы должны обеспечить корректное преобразование из кватерниона.

  3. Нормализация: Когда векторная база становится вырожденной (линейно зависимой), метод 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)

Объяснение изменений

  1. Нормализация векторов: Векторы, используемые для создания Basis, нормализуются. Это критически важно для того, чтобы избежать проблем с вырожденной базой.

  2. Смешивание кватернионов: Корректно получать кватернион от rotation_basis перед смешиванием с текущим кватернионом и преобразовать результат обратно в Basis. В этом процессе важно, чтобы оба кватерниона были корректны.

  3. Корректное присвоение: В конце присваиваем новое значение basis, основанное на полученном кватернионе.

Заключительные рекомендации

Переход от одной версии Godot к другой может вызвать трудности из-за изменений в API и поведения классов. Рекомендуется проверять документацию на официальном сайте Godot для актуальных версий, иногда наличие устаревшего кода может приводить к непредсказуемым ошибкам.

Кроме того, попробуйте отладить ваш код, добавляя вывод значений в процессе выполнения, это поможет лучше понять, что именно происходит на каждом этапе. Удачи в вашей разработке!

Оцените материал
Добавить комментарий

Капча загружается...