Подтвердить что ты не робот

Предельная высота камеры

Как я могу эффективно ограничить шаг камеры, когда у меня есть только кватернион камеры? Должен ли я преобразовать в углы Эйлера, а затем вернуться к кватерниону или есть ли другой способ?

4b9b3361

Ответ 1

Если у камеры никогда нет рулона (как это принято во многих играх, таких как шутеры от первого лица), тогда решение прост. Если есть рулон, то есть дополнительный шаг. Я начну с того, что делать, если нет рулона, и обобщите решение, что делать, если есть.

Пусть qc - вращение камеры. Пусть qy - вращение с тем же углом, что и qc, но с нулевым шагом. Если нет рулона, вращение камеры - это поворот рыскания, за которым следует поворот шага:

qc = qp * qy

Мы можем восстановить поворот тангажа qp как поворот от qy до qc:

qp = qc * qy^-1

Таким образом, трюк заключается в построении qy, поэтому мы можем подключить его к указанному выше уравнению для решения для qp. Пусть vc - единичный вектор, указывающий на объектив камеры, или "передний вектор". Пусть vy - один и тот же вектор, но проецируемый в горизонтальную плоскость и нормированный. Наконец, пусть v0 - вектор вперед, когда поворот камеры qc является тождественным вращением. Вращением, вращающим v0 в vy, является поворот рыскания. Угол может быть задан как:

yaw = asin(Norm(cross(v0, vy)))

Соответствующее вращение поворота:

qy = { cos(yaw/2), up * sin(yaw/2) }

Где "вверх" - это единичный вектор в направлении вверх, а также ось для поворота рыскания. Подключите это к qp = qy ^ -1 * qc выше, чтобы получить кватернион тона qp. Наконец, получите угол тангажа от qp как:

pitch = 2*asin(Dot(right, [qp[1], qp[2], qp[3]]))

Если "правый" - это единичный вектор в правильном направлении, то есть ось для поворота шага.

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

qc = qr * qp * qy

Мы можем определить переменную qx как комбинированные повороты шага и валка:

qx = qr * qp

Теперь мы можем написать qc как:

qc = qx * qy

Мы уже знаем, как решить для qx в этой форме, путем повторения шагов, которые мы использовали выше, для решения для qp. Переупорядочив определение для qx, получим:

qp = qr^-1 * qx

Мы просто решили для qx, поэтому для решения поворота шага qp нам нужен только рулон qr. Мы можем построить его с помощью векторов, как это было ранее. Пусть vc - вектор вперед. Рулон будет вращаться вокруг этого вектора. Пусть vu - вектор камеры вверх (в мировых координатах), vu0 - вектор камеры с нулевым рулоном. Мы можем построить vu0, проецируя глобальный вектор вверх на плоскость, перпендикулярную vc, затем нормализуя. Вращение ролика qr является затем вращением от vu0 до vu. Ось этого вращения является прямым вектором vc. Угол рулона

roll = asin(Dot(vc, cross(vu0, vu)))

Соответствующий кватернион равен:

qr = { cos(roll/2), forward * sin(roll/2) }

Если "вперед" - ось вращения валков.

Ответ 2

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

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

Как я вижу, основной темой кватернионов является то, что вам не нужно беспокоиться о таких ограничениях. Все просто работает без каких-либо особенностей. Почему именно вы хотите ограничить высоту тона?

Ответ 3

Кватернионы вращения камеры можно определить как:

vector A = [x, y, z] 
Q.x = A.x * sin(theta/2)
Q.y = A.y * sin(theta/2)
Q.z = A.z * sin(theta/2)
Q.w = cos(theta/2)

Где A - позиция, а theta - угол, который вы хотите повернуть камеру (отрегулируйте высоту тона).

Итак, если у вас есть доступный кватернион, вы можете ограничить угол тона, проверяя каждый раз, если угол поворота плюс/минус фактический угол в порядке.

Я думаю, вы можете избежать конверсии, если вы установили лимиты как

+cos(supLim/2) < (Q.w + P.w) < -cos(infLim/2)

Поскольку косинус является непрерывной функцией, это должно работать.

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

Ответ 4

Возможно, я немного опоздал на вечеринку, но я решил это:

        // "Up" = local vector -> rotation * Vector3.UnitY
        // "Forward" = local vector -> rotation * Vector3.UnitZ
        // "Right" = local vector -> rotation * Vector3.UnitX

    public void Rotate(Vector3 axis, float angle)
    {
        if (LerpRotation)
        {
            RotationTarget *= Quaternion.FromAxisAngle(axis, angle);
        }
        else
        {
            Rotation *= Quaternion.FromAxisAngle(axis, angle);
        }
        //Locking the Pitch in 180°
        float a = Vector3.CalculateAngle(Vector3.UnitY, Up);
        float sign = Math.Sign(Forward.Y);
        float delta = (float)Math.PI / 2 - a;
        if(delta < 0)
            Rotation *= Quaternion.FromAxisAngle(Right, delta * sign);
    }