Объединить 3 оси вращения в одну локальную систему координат

Программирование на Юнити.

Объединить 3 оси вращения в одну локальную систему координат

Сообщение Sandirk 25 май 2020, 12:37

Здравствуйте.

Разрабатывал несколько режимов управления для транспортного средства. Суть управления в том, чтобы вращать тело по трём осям. В первом режиме вращение не ограниченно, просто указал всем трём осям Space.World и проблем не возникло.

Первый режим управления. Всё работает как надо. ( Var a, Var b, Var c просто числа связанные с осями управления (Input Axis)).

Синтаксис:
Используется csharp
transform.Rotate(c * transform.right * RollSensitivity, Space.World);
transform.Rotate(b * transform.up * YawSensitivity, Space.World);
transform.Rotate(a * transform.forward * PitchSensitivity, Space.World);
 


Однако во втором режиме углы наклона транспортного средства ограниченны в осях X и Z. Человек с этого форума подсказал, что подобное ограничение можно сделать через углы Эйлера (eulerAngles). Проблема заключается в том, что наклоны в одних осях происходят независимо от наклонов в других осях.

Второй режим управления. Проблема с локальной системой угловых координат. ( Var a, Var b, Var c просто числа связанные с осями управления (Input Axis)).

Синтаксис:
Используется csharp
// Неограниченная ось вращения Y.
transform.Rotate(b * transform.up * YawSensitivity * 0.2f, Space.World);

// Ограниченные оси вращения X и Z.
var ea = RigBody.transform.eulerAngles;
ea.x = c * 230f;   // Ось X.
ea.z = a * 230f;   // Ось Z.
RigBody.transform.eulerAngles = ea;
 


Есть предположение, что исправить положение можно приписав подобие Space.World к осям X и Z (Как именно это сделать я не знаю).
Пробовал менять eulerAngles на localEulerAngles и, честно говоря, разницы вообще не увидел.

Главная задача: связать оси второго режима управления в одну локальную систему. Управление получится такое же как в первом режиме, но с ограниченными углами наклона в осях X и Z.

Также прикрепляю видео, где, по моему мнению, наглядно демонстрируется результат, которого пытаюсь добиться я. (На видео оси X и Z не ограниченны, однако само вращение абсолютно правильное).

Таймкод: 1.22



(В первом режиме управления движения в точности такие же, как и на видео)

Искренне буду благодарен за любую помощь.
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение Sandirk 26 май 2020, 00:24

Значит я понял в чём проблема. Проблема в углах Эйлера и в их специфике.

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

Надеюсь, что кто-то всё же решится написать что-то в этой теме по этому поводу. Потратил целый день, а скрипт так и не написал.
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение 1max1 26 май 2020, 08:09

Никто наверное не понял что ты хочешь. Заклемпить углы? http://answers.unity.com/answers/1455566/view.html
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение Sandirk 26 май 2020, 11:30

1max1 писал(а):Никто наверное не понял что ты хочешь. Заклемпить углы? http://answers.unity.com/answers/1455566/view.html


Я сам теряюсь в догадках, в чём может заключаться моя проблема.

С одной стороны из-за углов эйлера возникает эффект Gimbal lock. Это когда две оси вращения в момент времени совпадают и вращение становится некорректным. На сколько я понял это происходит именно из-за углов эйлера.

С другой стороны использование углов эйлера для ограничения наклона не совсем правильное, так как в этом случае даже минимальное превышение максимально возможного угла вращение по одной оси (которое должно возникать из за поворота другой оси) становится невозможным.

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

В моём коде эта стабилизация жёсткая так как мы задаём угол наклона напрямую из входного значения джойстика (Input). Скорее всего наклон должен стремиться к заданному углу, а не быть с ним жёстко связанным.

Всё это дело очень трудно описать, проще показать то, что я пытаюсь достичь в конечном итоге.
(Мне неудобно немного, ведь я по сути выпрашиваю у вас скрипт, дико извиняюсь.)

В конечном итоге должно получиться управление как у вертолёта в любой игре из серии GTA. (Просто это самый явный пример, я не делаю очередную гта, и по сути не делаю вертолёт). В игре ось вращения вокруг вертикальной оси ИМЕННО ТРАНСПОРТНОГО СРЕДСТВА, А НЕ МИРОВОЙ не ограничена, в то время как наклон по оставшимся двум осям пропорционален отклонению джойстика геймпада.



Если есть идеи о том, как это реализовать, то поделитесь пожалуйста. (Просить готовый код с объяснениями язык не поворачивается)

В любом случае спасибо.
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение 1max1 26 май 2020, 12:01

Я все еще не понимаю твою цель))
Создай пустышку, под нее кинь свой объект, пустышку будешь крутить по осям X, Z, которые будешь клемпить, а сам объект крути только по локальной Y.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение Sandirk 26 май 2020, 12:46

1max1 писал(а):Я все еще не понимаю твою цель))
Создай пустышку, под нее кинь свой объект, пустышку будешь крутить по осям X, Z, которые будешь клемпить, а сам объект крути только по локальной Y.


Тут логическая ошибка. От того, что я поверну дочерний объект, основной объект не повернётся.
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение 1max1 26 май 2020, 13:01

Основной и есть дочерний))
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение Sandirk 26 май 2020, 13:05

1max1 писал(а):Основной и есть дочерний))

Разве дочерний это не тот, что находится ниже основного?
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение 1max1 26 май 2020, 13:16

Тот. Тогда в чем логическая ошибка я не понимаю. Ты крутишь по X и Z пустышку, в месте с ней вращается дочерний, лока не происходит потому что там всего 2 оси. А дочерний ты крутишь по локальной Y оси. Где ошибка? Может я не угадал что ты хочешь сделать...
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение Sandirk 26 май 2020, 13:22

1max1 писал(а):Тот. Тогда в чем логическая ошибка я не понимаю. Ты крутишь по X и Z пустышку, в месте с ней вращается дочерний, лока не происходит потому что там всего 2 оси. А дочерний ты крутишь по локальной Y оси. Где ошибка? Может я не угадал что ты хочешь сделать...


Если мы наклоняем пустышку вперёд по оси X, вместе с ней вперёд наклонится дочерний объект. Однако же если мы сначала повернём дочерний объект на, предположим, 180 градусов и уже после этого захотим наклониться вперёд по оси X, дочерний объект наклонится назад по оси X тк саму пустышку мы не вращали.

А вращать и пустышку и дочерний объект одновременно не вариант, ибо оси начнут расползаться.
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение 1max1 26 май 2020, 14:03

Пустышку крути по Y, дочерний по X, Z. Но в таком случае ось Y будет глобальной, а как я понял ты хочешь крутить в локальном пространстве?
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение Sandirk 26 май 2020, 15:19

1max1 писал(а):Пустышку крути по Y, дочерний по X, Z. Но в таком случае ось Y будет глобальной, а как я понял ты хочешь крутить в локальном пространстве?


Ладно, думается, мы не придём тут к рабочему результату, слишком много непонимания.
Если смогу реализовать задумку, напишу сюда.

Спасибо за помощь
Аватара пользователя
Sandirk
UNITрон
 
Сообщения: 150
Зарегистрирован: 04 фев 2019, 21:48

Re: Объединить 3 оси вращения в одну локальную систему координат

Сообщение samana 27 май 2020, 22:02

Я не уверен, что следующий способ является хорошим, но идея такая.
Попробовать сделать некий накопитель-ограничитель для каждой оси. То-есть каждый раз добавляем/убавляем значение конкретной оси у конкретного накопителя для этой оси. Допустим для лимита в 45 градусов: например каждый кадр ось выдаёт 1, и каждый кадр складываем эти значения вместе. До тех пор, пока накопившееся значения оси не будет меньше -45 или больше 45 - возвращаем 1, но если результате когда нибудь это значение станет 45 или -45 и тогда текущее значение оси обнуляем.
Что-то мне сложно объяснить идею, возможно код немного объяснит мои мысли.
Повторюсь, возможно это плохой вариант, который покажет непредвиденные мною проблемы в реализации.
Синтаксис:
Используется csharp
using UnityEngine;

public class RotateClamp : MonoBehaviour
{
    private float _pitchGather = 0; // сюда накапливаем значения оси pitch
    private float _rollGather = 0; // а сюда оси roll
   
    void Update()
    {
        // ограничиваем поворот по оси Z (Pitch) на 30 градусов
        float a = getLimitAxis(ref _pitchGather, 30, "Pitch");

        // поворот вокруг оси Y не ограничиваем
        float b = Input.GetAxis("Yaw");

        // ограничиваем поворот по оси Х (Roll) на 45 градусов
        float c = getLimitAxis(ref _rollGather, 45, "Roll");

        // поворачиваем объект по скорректированным значениям
        transform.Rotate(a * transform.forward, Space.World);
        transform.Rotate(b * transform.up, Space.World);
        transform.Rotate(c * transform.right, Space.World);

    }

    // метод принимает ссылку на "скопление" значений некой оси ref float axisGather,
    // так же принимает положительное значение ограничения оси (в градусах вроде) float axisLimit,
    // и имя оси
    // Возвращает значение активной оси, если оно не превзошло свой лимит, либо возвращает 0, если значение вышло за пределы лимита
    private float getLimitAxis(ref float axisGather, float axisLimit, string axis)
    {
        float axisValue = Input.GetAxis(axis);
        axisGather += axisValue;
        if (axisGather < -axisLimit || axisGather > axisLimit)
        {
            axisGather = Mathf.Clamp(axisGather, -axisLimit, axisLimit);
            axisValue = 0;
        }

        return axisValue;
    }

}
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15