Вращение кватернионов на основе движения мыши (OpenGL и Java)

#java #opengl #lwjgl #quaternions

#java #opengl #lwjgl #кватернионы

Вопрос:

Я пишу игру на Java, используя OpenGL (точнее, привязку LWJGL). Каждый объект, включая камеру, имеет кватернион, который представляет его вращение. Я выяснил, как применить кватернион к текущей матрице OpenGL, и все вращается просто отлично. Проблема, с которой я сталкиваюсь, заключается в том, что камера поворачивается с помощью мыши.

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

     public void rotateX(float amount){
        Quaternion rot = new Quaternion(1.0f, 0.0f, 0.0f, (float)Math.toRadians(amount));
        Quaternion.mul(rot, rotation, rotation);
        rotation.normalise();
    }
  

Предполагается, что этот метод вращает кватернион вокруг оси X. «вращение» — это кватернион, представляющий вращение объекта. ‘amount’ — это величина, на которую я хочу повернуть кватернион (иначе говоря, величина, на которую была перемещена мышь). ‘rot’ — это нормализованный вектор вдоль оси X со значением w, равным сумме, преобразованной в радианы (я предполагаю, что цель здесь — задать ему угол — скажем, 10 градусов — и заставить его повернуть кватернион вдоль заданной оси на этот угол). Использование Quaternion.mul принимает новый кватернион, умножает его на кватернион вращения, а затем сохраняет результат как кватернион вращения. Я не знаю, необходима ли нормализация, поскольку «вращение» является нормальным, а «вращение» уже должно быть нормализовано.

Методы rotateY и rotateZ делают то же самое, за исключением изменения вектора для ‘rot’ (0.0, 1.0, 0.0 для y и 0.0, 0.0, 1.0 для z).

Кажется, что код работает нормально, когда игра запускается, и камера смотрит вниз по отрицательной оси Z. Вы можете вращаться до упора по оси Y или до упора по оси X. Но как только вы пытаетесь повернуть камеру, не глядя вниз по оси Z, все становится действительно странным (я даже не могу это описать, она вращается очень странно).

Моя конечная цель здесь — иметь что-то, что можно использовать для управления кораблем в пространстве без вектора вверх. Поэтому, когда вы перемещаете мышь по оси Y, независимо от того, под каким углом находится корабль, это изменяет высоту корабля (вращение вдоль оси X). Аналогично, когда вы перемещаете мышь по оси X, она изменяет рыскание (вращение вдоль оси Y). Возможно, я делаю это неправильно, и мне, вероятно, просто нужно подтолкнуть (или толкнуть) в правильном направлении.

Если вам нужна более подробная информация о чем-либо (как выполняется мой рендеринг, любая другая математика, которую я пытаюсь выполнить), просто спросите, и я выложу это. Я все понял, когда использовал углы Эйлера (которые, по-видимому, являются большим запретом для разработки 3D-приложений … хотелось бы, чтобы кто-нибудь сказал мне об этом до того, как я потратил много времени на то, чтобы заставить их работать), но как только я переключился на кватернионы, я действительно быстро справился. Я провел последние несколько месяцев, просто играя с этим кодом и читая о кватернионах, пытаясь заставить его работать, но на самом деле я вообще ничего не добился :'(

Очень, очень расстраивает … начинаю сожалеть о попытке создать что-то в 3D >_<

Комментарии:

1. Вы хотите вращаться вокруг оси X. По какой оси X? Мировое пространство? Камера-пространство?

Ответ №1:

 Quaternion rot = new Quaternion(1.0f, 0.0f, 0.0f, (float)Math.toRadians(amount));
  

Хорошо, это абсолютно неверно.

Конструктор, который принимает четыре числа с плавающей точкой, предполагает, что они представляют фактический кватернион. То, что вы даете этому конструктору, не является кватернионом; это ось vec3 и угол, вокруг которого вы ожидаете повернуть.

Вы не можете поместить их в класс кватернионов и ожидать, что получите из него законный кватернион.

Ваш класс кватернионов должен иметь конструктор или какое-либо другое средство создания кватерниона из угла и оси вращения. Но, согласно документации, на которую вы ссылались, это не так. Поэтому вы должны сделать это самостоятельно.

Кватернион не является осью vec3 с четвертым значением, которое является углом. Единичный кватернион, представляющий изменение ориентации, представляет собой vec3, который является осью вращения *, синусом половины угла поворота и скалярной составляющей, которая является косинусом половины угла поворота. Это предполагает, что угол поворота ограничен диапазоном [-pi / 2, pi /2].

Следовательно, то, что вы хотите, это:

 float radHalfAngle = ... / 2.0; //See below
float sinVal = Math.Sin(radHalfAngle);
float cosVal = Math.Cos(radHalfAngle);
float xVal = 1.0f * sinVal;
float yVal = 0.0f * sinVal;  //Here for completeness.
float zVal = 0.0f * sinVal;  //Here for completeness.
Quaternion rot = new Quaternion(xVal, yVal, zVal, cosVal);
  

Кроме того, прямое преобразование amount в радианы не имеет смысла, особенно если amount это просто дельта пиксельной координаты, которую переместила мышь. Вам нужна какая-то шкала преобразования между расстоянием, на которое перемещается мышь, и тем, насколько вы хотите повернуть. И toRadians это не тот масштаб, который вам нужен.

Еще одна вещь. Умножение налево rot , как вы делаете здесь, приведет к вращению вокруг оси X в пространстве камеры. Если вы хотите вращение вокруг оси X мирового пространства, вам нужно умножить его вправо.

Комментарии:

1. На самом деле я использую класс кватернионов, входящий в состав LWJGL . Кватернион, созданный в этой строке, используется только для умножения на текущий кватернион вращения, он больше нигде не используется. Таким образом, в основном это создает кватернион, который движется только по оси x под углом w, а затем умножает его на текущее вращение.

2. ВАУ , я не могу отблагодарить вас за помощь! Сработало как шарм! Вы многое прояснили для меня. Хотя в конечном итоге я использовал toRadians для amount, потому что amount передавался методу rotation в качестве угла поворота на этой оси (масштабирование дельты мыши выполняется до того, как оно передается методу — вероятно, следовало изменить ‘amount’ на ‘angle’ : P)

3. Кстати, кватернион может быть установлен из Maxisangle, который делает все это за вас. Просто внимание!