Листовые текстуры спрайта, собирающие края смежной текстуры


10

У меня есть собственная подпрограмма спрайта (openGL 2.0), в которой используется простой лист спрайта (мои текстуры расположены горизонтально рядом друг с другом).

Так, например, вот тестовый спрайт с двумя простыми текстурами:

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

Теперь, когда я создаю свой спрайтовый объект openGL, я указываю общее количество кадров в его атласе, а при рисовании - какой кадр я хочу нарисовать.

Затем выясняется, откуда взять текстуру:

Деление требуемого номера кадра на общее количество кадров (чтобы получить левую координату)

И затем погружение 1 на общее количество кадров и добавление результата к левой координате, вычисленной выше.

Кажется, это работает, но иногда у меня возникают проблемы. Скажем, например, я хочу нарисовать X ниже, и я получаю ...........

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

Я слышал о размещении «отступа» в 1 пиксель между каждой текстурой, но кто-то может объяснить, как именно это работает? Я имею в виду, что если я сделаю это, то, безусловно, скинет вычисления для получения текстуры.

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

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


Вы используете GL_NEARESTили GL_LINEARдля рендеринга текстуры?
MichaelHouse

Я использую GL_Linear @ Byte56
BungleBonce

Ответы:


15

Проблема с использованием текстурных атласов и смежных утечек связана с тем, как работает линейная фильтрация текстур.

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

Вот хорошая визуализация проблемы:

  

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

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


Чтобы проиллюстрировать, что я имею в виду, используя границы по краям каждой текстуры, рассмотрим различные режимы обтекания, доступные в OpenGL. Обратите особое внимание на CLAMP TO EDGE.

  http://lucera-project.com/blog/wp-content/uploads/2010/06/wrap.png

Несмотря на то, что существует режим под названием «Зажим на границу», это на самом деле не то, что нас интересует. Этот режим позволяет вам определить один цвет для использования в качестве границы вокруг вашей текстуры для любых текстурных координат, которые выходят за пределы нормализованного [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:)


Спасибо @AndonMColeman, не могли бы вы показать границу на диаграмме, так как я все еще не уверен, что понимаю, как это работает - опять же это будет означать, что когда текстура будет применена к моему объекту, она будет включать границу? Я хочу, чтобы фактическая текстура шла прямо к краям моего четырехугольника - извините, если я не правильно понимаю это - был бы признателен за некоторые дополнительные детали - спасибо
BungleBonce

@ user22241 Конечно, эта граница работает, дублируя тексель на краю текстуры.
Андон М. Коулман

@ user22241: Нет, эта граница не будет видна при нормальных обстоятельствах. Вы будете рассматривать ваши упакованные текстуры как имеющие одинаковые размеры для расчета координат текстуры, вы просто применяете к ним смещение, чтобы пропустить границу. Весь смысл границы состоит в том, чтобы предотвратить чрезмерное превышение линейной выборки текстуры и выборку текселей, которые принадлежат отдельным изображениям в вашем листе спрайта. Если вы используете выборку ближайшего соседа, ничего из этого не требуется, но тогда вы получите неприятные спрайты с псевдонимами.
Andon M. Coleman

Блестяще подробный ответ - спасибо! Еще одна вещь, если бы я мог. Как бы я работал со смещением, чтобы добавить к моим координатам текстуры? Правильно ли я сказал, что это будет просто 1 / widthOfTexture?
BungleBonce

@ user22241: Да, начало текстурного изображения будет + 1 / widthOfTexture в направлении X и + 1 / heightOfTexture в направлении Y. У вас будет граница, которая проходит вокруг каждой текстуры. К тому времени, когда вы хотите вычислить координаты текстуры для 3-й горизонтальной текстуры, упакованное местоположение для этой текстуры на самом деле составляет +5 текселей (+2 текселя для границы первой текстуры, +2 для границы второй текстуры и +1 для начала этой текстуры) в дополнение к ширине двух других текстур. Кажется сложным просто написать это; Я могу нарисовать вам диаграмму, если это будет необходимо :)
Andon M. Coleman
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.