Вращающиеся кватернионы на основе движения мыши (OpenGL и Java) - PullRequest
5 голосов
/ 21 октября 2011

Я пишу игру на 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.'вращение' - это кватернион, представляющий вращение объекта.«количество» - это количество, на которое я хочу повернуть кватернион (или количество, на которое была перемещена мышь).'rot' - это нормализованный вектор вдоль оси X со значением w суммы, преобразованной в радианы (я предполагаю, что цель здесь состоит в том, чтобы дать ему угол, скажем, 10 градусов, и заставить его вращать кватернион вдоль заданной оси наугол).Использование Quaternion.mul берет новый кватернион, умножает его на кватернион вращения, а затем сохраняет результат как кватернион вращения.Я не знаю, нужна ли нормализация, так как 'rot' является нормальным, а 'вращение' должно быть уже нормализовано.

Методы 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-приложений ... хотелось бы, чтобы кто-нибудь сказал мне об этом, прежде чем я потратил много времени на то, чтобы заставить их работать), но как только япереключился на кватернионы, я быстро набрал 1020 .Я провел последние несколько месяцев, просто играя с этим кодом и читая о кватернионах, пытаясь заставить его работать, но на самом деле я вообще ничего не получил: '(

Очень, очень расстраивает ...начинаю жалеть, пытаясь что-то сделать в 3D> _ <</p>

1 Ответ

8 голосов
/ 21 октября 2011
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 мирового пространства, вам нужно его умножить вправо.

...