Краткая версия:
Есть ли общий подход в OpenGL, который позволит создавать 2D-чертежи текстур из идеального пикселя из атласа при рисовании в собственном размере (включая краевые пиксели) и масштабирование хорошего качества при фильтрации на неродный размер?
Подробнее о проблеме:
Предположим, вы пишете какую-то систему для рисования спрайтов из атласа текстуры, чтобы пользователь мог указать спрайт, а также размер и местоположение, в которое он должен быть нарисован. Кроме того, они могут захотеть только нарисовать суб-прямоугольник спрайта.
Например, здесь находится шахматная доска размером 64x64:
... и один в своем атласе текстуры:
Примечание. Предположим, что окно просмотра настроено для отображения 1:1 на пиксели устройства.
Подходы
Изменить для ясности: обратите внимание, что первые 2 подхода ниже не дают желаемого результата, и там конкретно указано, что не работает.
1. Чтобы нарисовать спрайт в собственном размере, просто используйте GL_NEAREST
- установить OpenGL для использования фильтрации MIN/mag GL_NEAREST
- чтобы нарисовать в позиции (x, y), поместите вершины из (x, y) в (x + 64, y + 64)
- использовать координаты текстуры (0,0) → (64/atlas_size, 64/atlas_size)
Это хорошо для рисования в собственном размере, но фильтрация NEAREST дает плохие результаты, когда пользователь рисует объект размером не 64x64. Это также заставляет тексели выравниваться с сеткой пикселей, что дает плохие результаты, когда объект рисуется в нецелочисленных расположениях пикселей:
2. Включить GL_LINEAR
- С линейной фильтрацией нам нужно сдвинуть наши uv-координаты на центр текселей:
(0.5/atlas_size,0.5/atlas_size)
до(63.5/atlas_size,63.5/atlas_size)
. В противном случае для самых отдаленных пикселей линейная фильтрация будет отображать соседние спрайты в атласе. - Затем нам нужно изменить наши вершины, так как продолжение использования вершин из (0,0) в (64,64) будет растягивать текстуру на 1px в обоих направлениях, например:
- поэтому нам нужно использовать вершины из (0,5,0,5) - (63,5,63,5). Как правило, когда текстура рисуется в соотношении ее собственного размера (a, b), мы должны будем поместить наши вершины "внутрь", по-моему, (a/2, b/2). Результат дает (на фиолетовом фоне):
Обратите внимание, что мы получаем точный чертеж пикселя, за исключением краевых пикселей, которые смешиваются с фоном, так как граница вершины падает на полпути между пикселями.
Изменить: также обратите внимание, что это также зависит от того, включено ли сглаживание. Если нет, предыдущий подход действительно дает идеальный рендеринг пикселя, но не обеспечивает хороший переход, когда спрайт перемещается от положения пикселя к подпиксельной позиции. Плюс антиалиасинг является обязательным во многих случаях.
3. Pad спрайты в атласе текстуры
Два очевидных решения проблемы краевого пикселя включают заполнение края спрайта с помощью границы 1px в атласе текстуры. Вы можете:
- с 1 слоем прозрачных пикселей и развернуть вершины (0.5a, 0.5b), а не сжимать их
- со второй копией внешних ярлыков спрайта и вернитесь к выборке текстуры от (0,0) до (64/atlas_size, 64/atlas_size).
Это в основном дает нам точный чертеж с линейным масштабированием. Однако, если мы затем разрешим пользователю рисовать только субрекцию спрайта, любой из этих подходов выходит из строя, потому что субректура, очевидно, не имеет требуемого дополнения.
Я что-то пропустил? Существует ли общее решение этой проблемы?