Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Сложный поворот тела с помошью кватернионов (6 стр)

Сложный поворот тела с помошью кватернионов (6 стр)

Страницы: 1 2 3 4 5 6 7 Следующая »
AlerrПостоялецwww29 авг. 201615:59#75
> Ну так проверь: при выкидывании пункта 2 должно получаться то, что было изначально.
Так и получается.

Да, подумал, нарисовал все на листочке и понял что неправильно переводил...

Quaternion nearestRot(Quaternion cubeRot){
    // Получение обратного кватерниона вращения игрока:
    Quaternion inversRotation = player.GetRightLeftRotationAngle ();
    inversRotation.x *= -1f;
    inversRotation.y *= -1f;
    inversRotation.z *= -1f;

    // To playerSpace:
    Quaternion playerSpaceRotation = cubeRot * inversRotation;

    int maxIndex = 0;
    float maxDot = Quaternion.Dot(playerSpaceRotation, rot[0]);
    for (int i = 1; i < rot.Length; ++i) {
      float dot = Quaternion.Dot(playerSpaceRotation, rot[i]);// Mathf.Abs( 
      if (dot > maxDot) {
        maxDot = dot;
        maxIndex = i;
      }
    }

    // Return to WorldSpace player.GetRightLeftRotationAngle ()*
    return player.GetRightLeftRotationAngle () * rot [maxIndex];
  }

Вот это вообщем-то работает и делает то же самое, что и предыдущая попытка с player.GetRightLeftRotationAngle() *rot
Но у обоих решений почему-то 1 беда: начинаю пытаться перекрутить куб к любому другому углу, который кратен 90, но куб возвращается на исходную. Есть подозрение, что беда тут:

public Quaternion GetRightLeftRotationAngle(){
    return Quaternion.AngleAxis (rightLeftRotation, Vector3.up);
  }

AlerrПостоялецwww29 авг. 201616:05#76
Заменил:
public Quaternion GetRightLeftRotationAngle(){
    return myRigidbody.rotation;//Quaternion.AngleAxis (rightLeftRotation, Vector3.up);
  }
Все равно куб выкручивает на не ту позицию
AlerrПостоялецwww29 авг. 201618:17#77
Метод получения угла вращения персонажа по Y оставил как был:
public Quaternion GetRightLeftRotationAngle(){
    return Quaternion.AngleAxis (rightLeftRotation, Vector3.up);
  }

Вот это самое лучшее, что получилось:

Quaternion nearestRot(Quaternion cubeRot){
    // Получение обратного кватерниона вращения игрока:
    Quaternion inversRotation = player.GetRightLeftRotationAngle ();
    inversRotation.x *= -1f;
    inversRotation.y *= -1f;
    inversRotation.z *= -1f;

    // Перевод куба в пространство игрока:
   cubeRot *= inversRotation;// cubeRot теперь в пространстве игрока

    int maxIndex = 0;
    float maxDot = Quaternion.Dot(cubeRot, rot[0]);
    for (int i = 1; i < rot.Length; ++i) {
      float dot = Quaternion.Dot(cubeRot, rot[i]);// Mathf.Abs( 
      if (dot > maxDot) {
        maxDot = dot;
        maxIndex = i;
      }
    }

    // Return to WorldSpace
    return  rot [maxIndex] * player.GetRightLeftRotationAngle ();
  }

Но это работает до тех пор пока оси OX или OZ куба не отклонятся от соответствующих мировых осей не более чем на 45 градусов.
Как только ось куба смещается начинается странное поведение.
Если оси куба OX и OY меняются местами, то вот это cubeRot *= player.GetRightLeftRotationAngle () продолжает влиять на локальную ось куба OY? Вот видео, надеюсь по нему можно понять что происходит: https://yadi.sk/i/PjHg-FJ1uaR9v

Насчет правилности получения обратного кватерниона я точно не уверен. На глаза попадалась информация про инверсныый кватернион.
Обратный кватернион позволяет, как я понял, обнулить вращение: если повернуть на 10 градусов воокруг оси OY, а потом получить обратное вращение( путем смены знака вектора), то вращения как такогого не будет; Вот цитата:
Обратный кватернион
  Для поворота вектора кватернионом требуется уметь делать обратный разворот и правильно выполнять операцию умножения кватернионов. Под обратным разворотом я имею ввиду обратный кватернион, т. е. тот, который вращает в обратную сторону.
  Чтобы получить обратный кватернион от заданного, достаточно развернуть вектор оси в другую сторону и при необходимости нормализовать кватернион. Нормализация кватерниона так же как и в векторах, это просто приведение к длине = 1.

И про инверсный как я понял то же самое делает. Но выглядят они по разному; Вот цитата:
Инверсный (inverse) кватернион.
Существует такой кватернион, при умножении на который произведение дает нулевое вращение и соответствующее тождественному кватерниону (identity quaternion), и определяется как...

Попробовал сделать так:

// Получение обратного кватерниона вращения игрока:
    Quaternion inversRotation = Quaternion.Inverse( player.GetRightLeftRotationAngle() );
    //inversRotation.x *= -1f;
    //inversRotation.y *= -1f;
    //inversRotation.z *= -1f;
То же какая-то ерунда. Я не понимаю с какого момента начинаю ошибаться.

}:+()___ [Smile]Постоялецwww29 авг. 201619:00#78
Alerr
Ты уже пробовал менять порядок умножения?
Умножение кватернионов некоммутативно, т. е. A * B != B * A.
В зависимости от движка A * B может значить как "применить вращение A, а потом B", так и наоборот.
AlerrПостоялецwww29 авг. 201619:07#79
Да, вот:
Quaternion nearestRot(Quaternion cubeRot){
    // Получение обратного кватерниона вращения игрока:
    Quaternion backRotation = player.GetRightLeftRotationAngle();
    backRotation.x *= -1f;
    backRotation.y *= -1f;
    backRotation.z *= -1f;

    // To playerSpace:
    cubeRot = backRotation * cubeRot;//<< Поменял

    int maxIndex = 0;
    float maxDot = Quaternion.Dot(cubeRot, rot[0]);
    for (int i = 1; i < rot.Length; ++i) {
      float dot = Quaternion.Dot(cubeRot, rot[i]);// Mathf.Abs( 
      if (dot > maxDot) {
        maxDot = dot;
        maxIndex = i;
      }
    }

    // Return to WorldSpace player.GetRightLeftRotationAngle ()*
    return  player.GetRightLeftRotationAngle () * rot [maxIndex];//<< Поменял
  }

void FixedUpdate () {
// Это не трогаю:
    rigidBody.rotation = Quaternion.Slerp(rigidBody.rotation, 
        newRotation*Quaternion.AngleAxis(delta,playerRotationAxis),
        5f*Time.fixedDeltaTime);
  }
Результат разный дает, но и там и там не работает.
MrShoorУчастникwww29 авг. 201619:10#80
Интересно, кто первый сдастся. Smile или Alerr.
AlerrПостоялецwww29 авг. 201620:01#81
Хмммм, вот это cubeRot *=cubeRot и cubeRot = backRotation * cubeRot; - у меня дают разные результаты.
Вообщем да... Тут был косяк и я все время считал что  *= работает по-другому.
AlerrПостоялецwww29 авг. 201620:13#82
Осталось оптимизировать поиск нужного кватерниона для снапинга. На самом 1 игрок почти что не тратит ресурс компа. 10 игроков тоже не много едят, комп у меня из-за Debug.Log ранее тормозил... Но все же нудно бы ускорить то что можно ускорить. 0.5% cpu тоже много)

}:+()___ [Smile]
Вы говорили:
>Можно оставить 11 вариантов с положительными компонентами и сравнивать с модулями, а знаки потом скопировать из исходного >кватерниона.
Какие 11? Я перебрал все элементы, если знаки убрать, то разных кватернионов там вроде 8.
>Еще сам список надо сделать линейным в памяти (в C# это, вроде, struct вместо class).
А массив? У меня все кватернионы в массиве. + тип Quaternion представлен как struct.

}:+()___ [Smile]Постоялецwww29 авг. 201621:29#83
Alerr
> Какие 11?
4 единицы в разных местах, корень из половины на двух позициях из четырех (6 вариантов), и половина во все поля.

> А массив? У меня все кватернионы в массиве. + тип Quaternion представлен как struct.
Я не в курсе, как в C# заставить класть все данные последовательно, скорее всего придется отказаться от типа Quaternion в таблице.

> Но все же нудно бы ускорить то что можно ускорить. 0.5% cpu тоже много)
Это называется антипаттерн "преждевременная оптимизация".

Кстати, у тебя в Slerp какой-то ужас стоит, я хз, что ты пытаешься там сделать.

AlerrПостоялецwww29 авг. 201622:02#84
> Кстати, у тебя в Slerp какой-то ужас стоит, я хз, что ты пытаешься там сделать.
Лерпить пытаюсь от A к B. Что там ужасного?

А с уменьшенным массивом все получилось)

AlerrПостоялецwww30 авг. 20160:44#85
А что с лерпом-то не так?
IsaevПостоялецwww12 июля 20181:44#86
}:+()___ [Smile]
> Вот полный набор:
Что-то у меня не получается такая таблица) Похожая, но не такая
Quat[0] = (1,000, 0,000, 0,000, 0,000)
Quat[1] = (0,707, 0,000, 0,707, 0,000)
Quat[2] = (0,707, 0,000, -0,707, 0,000)
Quat[3] = (0,707, -0,707, 0,000, 0,000)
Quat[4] = (0,707, 0,707, 0,000, 0,000)
Quat[5] = (0,000, 1,000, 0,000, 0,000)
Quat[6] = (0,707, 0,000, 0,000, 0,707)
Quat[7] = (0,500, 0,500, 0,500, 0,500)
Quat[8] = (0,500, -0,500, -0,500, 0,500)
Quat[9] = (0,500, -0,500, 0,500, 0,500)
Quat[10] = (0,500, 0,500, -0,500, 0,500)
Quat[11] = (0,000, 0,707, -0,707, 0,000)
Quat[12] = (0,000, 0,000, 0,000, 1,000)
Quat[13] = (0,000, 0,707, 0,000, 0,707)
Quat[14] = (0,000, -0,707, 0,000, 0,707)
Quat[15] = (0,000, 0,000, 0,707, 0,707)
Quat[16] = (0,000, 0,000, -0,707, 0,707)
Quat[17] = (0,000, 0,000, -1,000, 0,000)
Quat[18] = (-0,707, 0,000, 0,000, 0,707)
Quat[19] = (-0,500, 0,500, -0,500, 0,500)
Quat[20] = (-0,500, -0,500, 0,500, 0,500)
Quat[21] = (-0,500, 0,500, 0,500, 0,500)
Quat[22] = (-0,500, -0,500, -0,500, 0,500)
Quat[23] = (0,000, -0,707, -0,707, 0,000)
Где-то косяк ?
AlerrПостоялецwww12 июля 20188:51#87
Isaev
В ближайшее время не смогу точно проверить таблицу, но вроде как таблица была верная. Возможно были опечатки, но это пустяки. Можешь в сети поискать эту таблицу, она, кстати, встречается на других форумах/сайтах.
IsaevПостоялецwww12 июля 201810:43#88
я в общем генерил по приведённой выше схеме
Procedure TfMain.Test;
Var
  Arr: Array[0..23] Of TQuaternion;
  Q1: Array[0..5] Of  TQuaternion;
  Q2: Array[0..3] Of  TQuaternion;
  vUp, vRight, vFront: TVector;
  I: Integer;
Begin
  vRight := TVector.Init([1, 0, 0]);
  vUp    := TVector.Init([0, 1, 0]);
  vFront := TVector.Init([0, 0, 1]);

  Q1[0].Create(0, vUp);
  Q1[1].Create(90, vUp);
  Q1[2].Create(-90, vUp);
  Q1[3].Create(-90, vRight);
  Q1[4].Create(90, vRight);
  Q1[5].Create(180, vRight);

  Q2[0].Create(0, vFront);
  Q2[1].Create(90, vFront);
  Q2[2].Create(180, vFront);
  Q2[3].Create(270, vFront);

  For I := 0 To 23 Do Begin
    Arr[I] := Q1[I Mod Length(Q1)] * Q2[I Div Length(Q1)];
    mLog.Lines.Append(Format('Quat[%d] = (%2.3f, %2.3f, %2.3f, %2.3f)', [I, Arr[I].W, Arr[I].X, Arr[I].Y, Arr[I].Z]));
  End;
End;
Единственное только что классы только созданные, не обкатанные, могут чудить
Может кто на стабильной системе проверит что выдаёт

Правка: 12 июля 2018 10:44

IsaevПостоялецwww12 июля 201813:52#89
Alerr
> Можешь в сети поискать эту таблицу, она, кстати, встречается на других
> форумах/сайтах.
пытался... нигде ничего не нашёл
Страницы: 1 2 3 4 5 6 7 Следующая »

/ Форум / Программирование игр / Физика

2001—2018 © GameDev.ru — Разработка игр