OpenGL: изменение размера дисплея и glOrtho / glViewport

16

Я исследовал этот вопрос из нескольких источников и до сих пор не нашел четкого ответа, говорящего, что «да, это правильное мышление» или «нет, вот как это делается».

Я пытаюсь обеспечить независимость разрешения с помощью рендеринга OpenGL. То, как я думаю, я должен пойти по этому пути, это создать проекцию, используя glOrthoто, что я хочу, чтобы координаты мира были. Например, glOrtho(-50.0, 50.0, -50.0, 50.0, 1.0, -1.0). Затем установите область просмотра на разрешение экрана , то есть - glViewport(0, 0, 800, 600). Наконец, всякий раз, когда размер окна изменяется, звоните glViewportс обновленным разрешением экрана. Это будет масштабировать ваши цифры.

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

Мысли?

Крис Хендерсон
источник

Ответы:

20

То, что вы описали, вполне адекватно и уместно для обеспечения независимости решения. Все, что вы рисуете, всегда будет занимать одинаковую пропорцию вашего окна.

Однако, если вы не сделаете ничего больше, у вас будут проблемы с соотношением сторон . Например, учитывая числа, которые вы написали, если вы нарисуете круг, он будет сдавлен - шире, чем высокий, потому что ваш горизонтальный масштаб 800 / (50 + 50) = 8, а ваш вертикальный масштаб 600 / (50+ 50) = 6.

Там не может быть никакого автоматического решения этой проблемы ; вам нужно будет выбрать, какой графический результат вы хотите, и учитывать его влияние на игровой процесс. Некоторые общие примеры:

  • В 3D-игре с перспективной проекцией без HUD обычное простое решение (доступно в OpenGL как часть gluPerspective) состоит в том, чтобы зафиксировать поле зрения проекции относительно вертикального размера . Это означает, что в такой игре, если вы измените размер окна по горизонтали, вы увидите более или менее сцену, а средняя часть изображения не изменится вообще.

    Та же идея может быть применена и к 2D / 2.5D виду.

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

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

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

  • Если у вас есть HUD поверх другой графики, вы можете решить, что каждый элемент HUD прикреплен к части окна (вверху слева, внизу по центру и т. Д.) И вычислить его координаты; «растяжение» изменяющихся соотношений сторон поглощается «белым пространством» между элементами HUD.

Что касается конкретных математики вопроса, учитывая , что вы делаете резолюцию независимость, все , что вам нужно , чтобы начать с этим соотношением сторон, единственным число: width / height. Например, если окно квадратное, оно будет равно 1; если это 800 на 600, это будет 800/600 = 4/3 = 1.333̅.

Например, предположим, что вы хотите, чтобы написанная вами орфографическая проекция получила дополнительное пространство слева и справа, если окно будет расширено. Вы можете сделать это так:

float aspect = width / height;
glViewport(0, 0, width, height);
glOrtho(-50.0 * aspect, 50.0 * aspect, -50.0, 50.0, 1.0, -1.0);

Это гарантирует, что для окон, по крайней мере таких же широких, как и их высота, все, что вы рисуете с координатами x и y в пределах от -50 до 50, будет видно.

С другой стороны, если окно уже, чем оно высокое, диапазон от -50 до 50 будет отрезан. Допустим, вы хотели убедиться, что он всегда виден (так что ваш контент имеет максимальный размер, если окно квадратное, но в противном случае меньше); в этом случае вы просто делаете то же самое для высоты вместо ширины.

float aspect = width / height;
glViewport(0, 0, width, height);
if (aspect >= 1.0)
  glOrtho(-50.0 * aspect, 50.0 * aspect, -50.0, 50.0, 1.0, -1.0);
else
  glOrtho(-50.0, 50.0, -50.0 / aspect, 50.0 / aspect, 1.0, -1.0);

Обратите внимание, что во втором случае мы делим, а не умножаем. Это просто потому , что мы рассчитали соотношение сторон , как , width / heightа не height / width; Возьмите ответ, если вам будет легче понять этот путь.

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

Кевин Рид
источник
Спасибо за ОЧЕНЬ проницательный ответ. Ответил на мой вопрос достаточно далеко.
Крис Хендерсон