Pixel perfect: выбор правильной коррекции (OpenGL)

Я пытался рисовать растровые изображения с точностью до пикселя, используя квадроциклы в OpenGL... и, к моему удивлению, отсутствовал очень важный ряд пикселей: (зеленый - нормально, красный - плохо)

Размеры четырехугольников были 30x30 пикселей с красным 2x2 в верхнем левом углу.

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

  • Может кто-нибудь объяснить, что происходит?
  • Как OpenGL решает, куда поместить пиксели?
  • Какую коррекцию выбрать?

Текстура использует GL_NEAREST.

    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

Я не использую glViewport и glOrtho. Вместо этого я отправляю шейдерам размеры экрана через униформы:

uniform float cw;
uniform float ch;
...
gl_Position = vec4(     -1.0f + 2.0f*(in_pos.x + in_offset.x)/cw, 
                         1.0f - 2.0f*(in_pos.y + in_offset.y)/ch,
                         0.0f, 1.0f);

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

Хорошо, теперь я понимаю, что третий вариант тоже не работает:

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


person thehorseisbrown    schedule 17.11.2019    source источник
comment
Линия будет пропущена, только если вы уменьшите масштаб спрайта. Почему вы удивлены?   -  person Vlad    schedule 17.11.2019
comment
Что ты имеешь в виду? Я только масштабирую координаты вершин внутри шейдера. Координаты текстуры всегда (0,0),(1,1)... И данные растрового изображения постоянны для всех квадов и корректны.   -  person thehorseisbrown    schedule 17.11.2019
comment
Должен быть какой-то даунскейлинг. Сдвиг примерно на полпикселя или увеличение на полпикселя никогда не приведет к исчезновению линий. Если вы измените фильтрацию на линейную, вы должны увидеть эту линию, и это подтвердит наличие уменьшения масштаба.   -  person Vlad    schedule 17.11.2019
comment
Насколько вы уверены в этом утверждении? Можете ли вы доказать, что GL_NEAREST не может создать отсутствующую строку при соотношении 1:1? Я не делаю никакого масштабирования.   -  person thehorseisbrown    schedule 17.11.2019
comment
Да, я почти уверен в этом, хотя, скорее всего, не будет довольно формального доказательства :) В качестве дикой догадки проверьте, что вы передали правильный размер экрана. Если вы работаете в Windows, убедитесь, что вы использовали прямоугольную область клиента, а не весь размер окна.   -  person Vlad    schedule 17.11.2019
comment
Еще одна необходимая информация - размер вашего спрайта 30x30px. Вы используете прямоугольники текстур или ваши текстуры имеют размер 32x32? Это тоже будет источником снижения масштаба. Если вы используете текстуры горшков для спрайтов, не являющихся горшками, координаты вашей текстуры должны быть правильно пересчитаны, чтобы не произошло масштабирование.   -  person Vlad    schedule 17.11.2019
comment
Вы правильно догадались, GetWindowRect -> GetClientRect решил эту проблему, и это была проблема масштабирования. facepalm Спасибо! Что означает горшок? Я вообще не масштабирую текстуры. Я просто пишу пиксели с D2D. Если вы превратите это в ответ, я приму это :).   -  person thehorseisbrown    schedule 17.11.2019
comment
горшок означает (имеющий размер, равный a) power of two.   -  person HolyBlackCat    schedule 17.11.2019


Ответы (1)


Убедитесь, что вы передали правильный размер экрана в шейдер.

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

Таким образом, вы должны либо задать размер клиентской области с помощью GetClientRect(), либо найти "правильный" размер окна, вызвав AdjustWindowRect() перед созданием окна - это даст вам размер окна, в котором клиентская область будет иметь размер, который вы хотели изначально.

person Vlad    schedule 17.11.2019