как вращать по глобальным осям Ursina Python

Вращаю объект с помощью команды 'rotation_z', но при это также воращаются все оси этого объекта. Как предотвратить вращение осей? Есть команда 'world_rotation_z', но не совсем понятно как она работает. Документация умалчивает.

from ursina import *
app = Ursina()
cube_1 = Entity(model='cube')
delta=0
def update():
    global delta
    delta = delta + 0.1
    cube_1.rotation_z = delta
app.run() 

Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Вы хотите вращать объект вокруг осей X, Y, Z независимо друг от друга. Оси фиксированы в пространстве. Для вращения используем присвоение значений свойствам rotation_x, rotation_y, rotation_z.

Например начнем с нулевых поворотов и повернем сперва по X, потом по Y:

rotation_x = 0  rot X  rotation_x = 90  rot Y   rotation_x = 90 
rotation_y = 0 ------> rotation_y =  0 ------>  rotation_y = 90 
rotation_z = 0         rotation_z =  0          rotation_z =  0 

Тоже начальное положение, сперва по Y, потом по X:

rotation_x = 0  rot X  rotation_x =  0  rot Y   rotation_x = 90 
rotation_y = 0 ------> rotation_y = 90 ------>  rotation_y = 90 
rotation_z = 0         rotation_z =  0          rotation_z =  0 

В обоих случаях результат одинаков. Действительно, какая разница в каком порядке присваивать значения свойствам объекта.

Но вращения по разным осям в пространстве не могут быть переставлены с сохранением результата. Вращения не коммутируют. В наших двух примерах должны были получится разные результаты.

Противоречие заключается в том что вы не можете вращать объект вокруг разных осей просто присваивая значения каким-то свойствам. Сам способ присваивания порождает схему в которой операции перестановочны, а они не могут быть таковыми.

Ursina в этом не виновата.

Я, наверно, объясняю непонятно. Попытайтесь поиграть с программой ниже. Она реализует нужную вам логику и показывает получившиеся углы. Клавиши q/a вращают по X, w/s по Y, e/d по Z. Чтобы всё работало как ожидается, требуется идти на хитрости с изменением иерархии сцены. Хочу вас успокоить, на такие хитрости идут все кто разрабатывает интерфейсы для поворотов в пространстве в любых трехмерных пакетах.

NB: Переключение предков в иерархии соответствует операциям на матрицах вращения - обращениям и произведениям матриц. Если вы знакомы с линейной алгеброй и тем как матрицы связаны с поворотами, вы можете по программе выписать матричные операции для поворотов вокруг фиксированных осей. И наоборот, по формулам составить требуемую последовательность операций ("смена папы-поворот-смена папы").

from ursina import *


app = Ursina()

origin = Entity(model='cube', scale=(0.2, 0.2, 0.2))

Entity(model='cube', parent=origin, color=color.red  , position=(5, 0, 0), scale=(10, 0.5, 0.5))
Entity(model='cube', parent=origin, color=color.green, position=(0, 5, 0), scale=(0.5, 10, 0.5))
Entity(model='cube', parent=origin, color=color.blue , position=(0, 0, 5), scale=(0.5, 0.5, 10))

x_handle = Entity()
y_handle = Entity()
z_handle = Entity()


def switch_parent(entity, parent):
    old_world_rotation = entity.world_rotation
    entity.parent = parent
    entity.world_rotation = old_world_rotation


def update():
    old_parent = origin.parent
    switch_parent(origin, x_handle)
    x_handle.rotation_x += held_keys['q'] * 50 * time.dt
    x_handle.rotation_x -= held_keys['a'] * 50 * time.dt

    switch_parent(origin, y_handle)
    y_handle.rotation_y += held_keys['w'] * 50 * time.dt
    y_handle.rotation_y -= held_keys['s'] * 50 * time.dt

    switch_parent(origin, z_handle)
    z_handle.rotation_z += held_keys['e'] * 50 * time.dt
    z_handle.rotation_z -= held_keys['d'] * 50 * time.dt

    switch_parent(origin, old_parent)


app.run() 
→ Ссылка