Проблема с использованием текстурных атласов и смежных утечек связана с тем, как работает линейная фильтрация текстур.
Для любой точки в текстуре, которая не дискретизирована точно в центре текселя, линейная выборка будет производить выборку из 4 смежных текселей и вычислять значение в указанном вами месте как средневзвешенное (на основе расстояния от точки отбора) среднее значение для всех 4 образцы.
Вот хорошая визуализация проблемы:
Так как вы не можете использовать что-то похожее GL_CLAMP_TO_EDGE
на текстурный атлас, вам нужно создать текстуру границ по краям каждой текстуры. Эти граничные тексели не позволят соседним образцам с совершенно разными текстурами в атласе изменять изображение посредством взвешенной интерполяции, описанной выше.
Обратите внимание, что при использовании анизотропной фильтрации может потребоваться увеличить ширину границы. Это связано с тем, что анизотропная фильтрация увеличивает размер окрестности образца под крайними углами.
Чтобы проиллюстрировать, что я имею в виду, используя границы по краям каждой текстуры, рассмотрим различные режимы обтекания, доступные в OpenGL. Обратите особое внимание на CLAMP TO EDGE
.
Несмотря на то, что существует режим под названием «Зажим на границу», это на самом деле не то, что нас интересует. Этот режим позволяет вам определить один цвет для использования в качестве границы вокруг вашей текстуры для любых текстурных координат, которые выходят за пределы нормализованного [0.0 -1.0] диапазон.
Нам нужно воспроизвести поведение, при CLAMP_TO_EDGE
котором любая текстурная координата вне надлежащего диапазона (суб) текстуры получает значение последнего центра текселя в том направлении, в котором она находилась за пределами. Так как вы почти полностью контролируете координаты текстуры в системе атласа, единственный сценарий, в котором (эффективные) координаты текстуры могут относиться к местоположению вне вашей текстуры, - это шаг взвешенной средней фильтрации текстур.
Мы знаем, что это GL_LINEAR
будет выборка из 4 ближайших соседей, как показано на диаграмме выше, поэтому нам нужна только граница в 1 тексель. Возможно, вам понадобится более широкая граница текселей, если вы используете анизотропную фильтрацию, потому что это увеличивает размер окрестности выборки при определенных условиях.
Вот пример текстуры, которая более четко иллюстрирует границу, хотя для ваших целей вы можете сделать границу шириной 1 тексель или 2 текселя.
(ПРИМЕЧАНИЕ. Граница, на которую я ссылаюсь, - это не черный цвет вокруг всех четырех краев изображения, а область, где рисунок шахматной доски перестает регулярно повторяться)
Если вам интересно, вот почему я продолжаю поднимать анизотропную фильтрацию. Он изменяет форму окрестности образца на основе угла и может привести к тому, что для фильтрации будет использовано более 4 текселей:
http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg
Чем выше степень анизотропии, которую вы используете, тем больше вероятность того, что вам придется иметь дело с выборочными окрестностями, содержащими более 4 текселей. Граница в 2 текселя должна быть достаточной для большинства ситуаций анизотропной фильтрации.
И последнее, но не менее важное: вот как будет построен упакованный текстурный атлас, который будет воспроизводить GL_CLAMP_TO_EDGE
поведение в присутствии GL_LINEAR
текстурного фильтра:
( Вычтите 1 из X и Y в черных координатах, я не проверял прочитанное изображение перед публикацией. )
Из-за хранения границ для хранения 4 256x256 текстур в этом атласе требуется текстура с размерами 516x516. Границы имеют цветовую кодировку в зависимости от того, как вы будете заполнять их данными texel при создании атласа:
- Красный = заменить на тексель прямо под
- Желтый = заменить текстовым прямо над
- Зеленый = заменить на texel прямо влево
- Синий = заменить на texel прямо справа
Фактически в этом упакованном примере каждая текстура в атласе использует область атласа 258x258, но вы создадите координаты текстуры, которые отображаются в видимой области 256x256. Ограничивающие тексели используются только тогда, когда фильтрация текстур выполняется по краям текстур в атласе, а способ их построения имитирует GL_CLAMP_TO_EDGE
поведение.
Если вам интересно, вы можете реализовать другие типы режимов обтекания, используя аналогичный подход - GL_REPEAT
это можно реализовать, заменив левый / правый и верхний / нижний граничные тексели в текстурном атласе и немного умной текстурной координаты в шейдер. Это немного сложнее, так что пока не беспокойтесь об этом. Поскольку вы имеете дело только со спрайт-листами, ограничьтесь GL_CLAMP_TO_EDGE
:)
GL_NEAREST
илиGL_LINEAR
для рендеринга текстуры?