Development of mobile applications
Game development
February 2013 3

Hor+vert+ FOV, или адаптивное поле обзора

From Sandbox


Привет всем!

Сегодня, когда я тестировал свой порт Quake на планшете, я заметил, что в портретной ориентации смотреть демки не очень приятно из-за узкого поля обзора.

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

И назвал я это Hor+vert+ FOV.


В чём была проблема


Так как у моего десктопа широкоформатный монитор, я изначально решил использовать Hor+ FOV вместо Vert-, несмотря на то, что в Quake используется Vert-, поскольку казалось, что я смотрю на мир через увеличительное стекло.

Quake с Vert- FOV на широкоформатном мониторе.


Hor+ работал нормально до тех пор, пока у меня не появился планшет. Всё выглядело отлично в пейзажной ориентации, но в портретной было уже не приближение, а просто тесно.

Quake с Hor+ FOV в портретной ориентации.


Решение


А решение оказалось простейшим.

Вместо того, чтобы использовать какой-либо из двух типов FOV, я решил совместить эти два типа.

Так как Quake был разработан для мониторов с соотношением сторон 4:3, я стал использовать это соотношение как базовое для переключения между двумя режимами.

Если соотношение сторон больше 4:3 (экран широкий) — используется Hor+.
Если соотношение сторон меньше или равно 4:3 (экран узкий или близок к квадратному) — используется Vert-.


Но так как задачей было подогнать FOV под узкие экраны, то это значит, что чем уже экран, тем больше должно быть видно. Поэтому для нас Vert- фактически превратился в Vert+.

Реализация такого способа занимает одну-единственную проверку на условие.

Приведу весь код реализации данного способа из WebQuake.
if ((vrect.width * 0.75) <= vrect.height)
{
	R.refdef.fov_x = SCR.fov.value;
	R.refdef.fov_y = Math.atan(vrect.height / (vrect.width / Math.tan(SCR.fov.value * Math.PI / 360.0))) * 360.0 / Math.PI;
}
else
{
	R.refdef.fov_x = Math.atan(vrect.width / (vrect.height / Math.tan(SCR.fov.value * 0.82 * Math.PI / 360.0))) * 360.0 / Math.PI;
	R.refdef.fov_y = SCR.fov.value * 0.82;
}


Пояснение:
  • SCR.fov — консольная переменная, обозначающая горизонтальный FOV при соотношении сторон 4:3 (идеальном соотношении сторон для Quake).
  • Если соотношение сторон меньше или равно 4:3, используем Vert+. Если нет, используем Vert-.
  • В случае с Vert+, берем горизонтальный FOV из консольной переменной, а вертикальный — рассчитываем по известному алгоритму.
  • В случае с Hor+, берем вертикальный FOV из консольной переменной, а горизонтальный — рассчитываем.
  • 0.82 — отношение вертикального FOV к горизонтальному при соотношении 4:3. Чтобы получить вертикальный FOV из консольной переменной, умножаем значение переменной на эту константу.


Что из этого получилось:
Пейзажная ориентация — используется Hor+.

Портретная ориентация — используется Vert+.


Как вы видите, и приближения здесь нет, и обзор хороший.

Но есть одна маленькая проблема.

Ошибка и её решение


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

Данная проблема присутствует только в том случае, когда используется Vert+ — в Hor+ такой эффект не наблюдается.

Так как модель оружия в Quake рисуется отдельно от остальных моделей, ничто не мешает нам переключиться с Vert+ на Hor+ перед тем, как рисовать оружие, а после этого — обратно.

Мир рисуется в Vert+, а оружие — в Hor+.


Ошибка исправлена.

Итог и заключение


В итоге получилось так, как на первом скриншоте в этом посте.



Может быть, данная техника и не нова (хотя я пока ещё не встречал ни одной игры, использующей что-то подобное), но она имеет большое значение. Использование адаптивного FOV очень важно в эпоху веб-приложений и мобильных устройств, так как окно браузера может иметь любую прямоугольную форму, а смартфоны и планшеты работают как в горизонтальной, так и в вертикальной ориентации.

Спасибо за прочтение.

+57
26.1k 55
Comments 31