Путаница по поводу GLViewport

9

Я надеюсь, что кто-то может помочь мне понять GLViewport и что произойдет, когда мы изменим его размер

Это проиллюстрирует мою путаницу ....

введите описание изображения здесь

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

  • Разрешение устройства, 2560 х 1600
  • Разрешение области просмотра 2560 x 1600
  • Квадратный размер 200 х 200 (Обратите внимание, что изображение выше не в масштабе !!! :-))
  • Квадратная форма, выглядит как квадрат

Теперь для второй (правой руки) картинки ...

  • Разрешение устройства, 2560 х 1600
  • Разрешение области просмотра 2560 x 1200 (по центру по вертикали)
  • Квадратный размер (200, 200)
  • Четырехугольная форма, выглядит как прямоугольник

Мой вопрос: почему квад теперь отображается в виде прямоугольника, а не квадрата? В журнале я подтвердил, что мой квадроцикл имеет размер 200 x 200 пикселей - конечно, размер физических пикселей остается неизменным? Они не могут измениться. и так, что здесь происходит?

Я думал (явно неправильно), что когда я масштабировал область просмотра, она буквально отсекала пиксели.

Был бы признателен, если бы кто-то мог объяснить, как это работает.

редактировать

В настоящее время я настраиваю свой видовой экран следующим образом:

width = (int) Math.min(deviceWidth, deviceHeight * 1.702127659574468);    
height = (int) Math.min(deviceHeight, deviceWidth / 1.702127659574468);

ratio = width / height;
GLES20.glViewport(offsetX, offsetY, width, height);

Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

offsetX и offsetY таковы, что при наличии почтовых ящиков область просмотра центрируется.

BungleBonce
источник
Изменили ли вы матрицу проекции, а также окно просмотра при переходе с 1600 на 1200 пикселей по вертикали? (вам нужно)
bcrist
Привет @bcrist, пожалуйста, посмотрите мои изменения, чтобы показать, как я настраиваю свой видовой экран. Все, что я рисую с равным количеством пикселей (скажем, 50 x 50 или 100 x 100), рисует «растянуто» - есть идеи ?!
BungleBonce
Кстати, если вы используете glScissorвместо этого glViewport, он будет просто обрезать пиксели, не меняя, где что-либо отображается. glViewportведет себя больше как изменение исходного изображения, а не как его обрезка; вот почему это раздавливает вашу коробку.
Натан Рид
Спасибо @NathanReed, я все еще в замешательстве. То, что у меня есть, это: окно просмотра, которое занимает весь экран. Ящик для ножниц, который масштабируется для сохранения соотношения исходного устройства (чтобы я мог отобразить игру в поле для ножниц и нарисовать что-то вне этого для наполнителя), все выглядит растянутым (по вертикали), поэтому оно длиннее, чем оно широко. Что я делаю неправильно?
BungleBonce
Хм. Прямоугольник ножниц не должен ничего менять относительно соотношения сторон или масштабирования изображения. Если это выглядит правильно без ножниц, то просто включение ножниц - с сохранением того же вида, матрицы проекции и т. Д. - должно просто обрезать изображение.
Натан Рид

Ответы:

11

Чтобы понять, что происходит, вы должны понять конвейер рендеринга:

Ваша геометрия (квад) изначально определена в мировом пространстве, представьте это как некоторую глобальную систему координат. Внутри вершинного шейдера они преобразуются в нормализованные координаты устройства (NDC), виртуальную систему координат, определенную так, что все от -1 до 1 будет отображаться на экране. Обратите внимание, что значение NDC составляет от -1 до 1 в X и Y, и оно полностью не зависит от соотношения сторон и разрешения устройства. Это преобразование из мирового пространства в НДЦ осуществляется с помощью модели, матрицы представления и проекции (в простой форме, для начала была задана всего одна матрица для всего или геометрия в НДЦ!).

Модуль растеризации должен знать, где и как велик растр, и это то, что вы определяете с помощью вызова glViewport: с чего начать - первые два параметра, а размер - вторые два. Аппаратные средства затем преобразуют из NDC в пиксельные координаты простым масштабом и смещением - и это то, что вы видите в своем примере: масштаб по оси Y.

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

Роберт
источник
Привет @ Роберт, большое спасибо за это, у меня возникли некоторые трудности при попытке реализовать это, не могли бы вы привести пример настройки матрицы проекции в своем ответе? Спасибо!
BungleBonce
4
Здравствуйте, user22241, для этого нет команд OpenGL, вам нужно определить матрицу самостоятельно (массив с плавающей точкой 4 на 4) и предоставить их вашему вершинному шейдеру как униформу. Какая проекция вам нужна (перспективная, ортогональная) зависит от того, что вы хотите сделать. Если математические концепции трехмерных проекций являются новыми для вас, вы можете обратиться к учебным пособиям по OpenGL, в которых описывается основной профиль, который работает в этом отношении так же, как и OpenGL ES.
Роберт
@BungleBonce, хотя в профиле ядра нет команд OpenGL для этого, вы всегда можете посмотреть документацию по устаревшим командам, таким как glFrustumсписок точной матрицы, которая создается этими функциями. Другая распространенная матрица проекций, которую вы, возможно, захотите, была создана glOrtho. В то время как все эти команды устарели, документы по ним являются отличным источником некоторых предварительно полученных математических данных.
Руслан
0

При вызове glViewport вы указываете меньше пикселей по ширине и высоте. Ваша матрица проекции определяется в пикселях. Вот почему вам придется вычислять новую матрицу проекции после вызова glViewport.

bogglez
источник
Привет @bogglez, спасибо за ваш ответ. Я отредактировал свой вопрос, чтобы показать (в конце), какой код я использую для моего окна просмотра. Все, что я использую, это glViewPort - это неправильный способ сделать это? Пожалуйста, не могли бы вы показать пример того, что вы имеете в виду в своем ответе? Спасибо.
BungleBonce
Прочитайте это: songho.ca/opengl/gl_projectionmatrix.html Для 2D вам нужна матрица ортогональной проекции, для 3D вы, вероятно, хотите матрицу перспективы. Если вы используете современный OpenGL, вы поставите матрицу для шейдера. Если вы используете устаревший OpenGL с фиксированным графическим конвейером, вы будете использовать такие функции, как glLoadMatrix, glFrustum и т. Д. Для расчета матрицы проекции. В служебной библиотеке GLU есть функция gluPerspective ( opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml ) и gluOrtho2D ( opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml ), которая поможет вам в этом.
Богглез
0

Для первой картинки:

  1. Мы создаем проекционную матрицу. Например, используются следующие параметры: Left1, Right1, Bottom1, Top1, Near1, Far1. Здесь Aspect_Ratio_1A = (справа1 - слева1) / (сверху1 - снизу1);

  2. Затем мы делаем преобразование порта просмотра. Например, используются следующие параметры: Ширина1, Высота1. (Я не упоминаю параметры сдвига для простоты). Здесь Aspect_Ratio_1B = Ширина1 / Высота1;

Для второй картинки:

  1. Мы создаем ту же матрицу проекции с теми же параметрами, что и раньше. Итак: Aspect_Ratio_2A = Aspect_Ratio_1A;

  2. На этот раз преобразование порта просмотра имеет разные параметры: ширина2 и высота2. Здесь Aspect_Ratio_2B = Ширина2 / Высота2.

Отметим, что Aspect_Ratio_1B и Aspect_Ratio_2B различны. В частности, они являются:

Aspect_Ratio_1B = 2560/1600 = 1.6 Aspect_Ratio_2B = 2560/1200 = 2.13

Итак, если мы суммируем, что мы делаем для второго случая:

Мы проецируем изображение на плоскость с помощью Aspect_Ratio_2A и, прежде чем показать его пользователю, мы масштабируем его до Aspect_Ratio_2B. Другие пользователи просят нас исправить нашу матрицу проекции таким образом, чтобы Aspect_Ratio_2A = Aspect_Ratio_2B.

Мы также можем прочитать комментарии Роберта пару раз, чтобы лучше понять.

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

Джамиль
источник