Спиритові текстури аркуша, що підбирають краї сусідньої текстури


10

У мене є власна спрайт-процедура (openGL 2.0), яка використовує простий аркуш спрайту (мої текстури розташовані горизонтально поруч).

Наприклад, ось тестовий спрайт-лист з 2 простими текстурами:

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

Тепер, що я роблю при створенні свого об’єкта OpenGL спрайт, - це вказати загальну кількість кадрів у його атласі, а під час малювання вказати, який кадр я хочу намалювати.

Потім з'ясовується, звідки схопити текстуру:

Ділення необхідного номера кадру на загальну кількість кадрів (щоб отримати ліву координату)

А потім пірнаємо 1 за загальною кількістю кадрів і додаємо результат до лівої руки, обчисленої вище.

Це, здається, працює, але іноді у мене виникають проблеми. Скажімо, наприклад, я хочу намалювати Х нижче, і я отримаю ...........

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

Я чув про те, щоб розмістити "набивання" 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проведемо вибірку чотирьох найближчих сусідів, як показано на діаграмі вище, тому нам потрібна лише одна-тексельна межа. Можливо, вам знадобиться більш широка рамка текселя, якщо ви використовуєте анізотропну фільтрацію, оскільки вона збільшує розмір сусідства вибірки за певних умов.

Ось приклад текстури, яка більш наочно ілюструє рамку, хоча для своїх цілей ви можете зробити облямівку 1 текселем або 2 текстовими шириною.

  

(ПРИМІТКА. Межа, яку я маю на увазі, - це не чорний колір навколо всіх чотирьох країв зображення, а область, де шаблон шаблону перестає регулярно повторюватися)

Якщо вам було цікаво, ось чому я продовжую висувати анізотропну фільтрацію. Це змінює форму сусіднього зразка на основі кута і може спричинити використання більше 4 текстових тканин для фільтрації:

  http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg

Чим більший ступінь використання анізотропії, тим більше шансів на те, що вам доведеться мати справу з примірними районами, що містять більше 4 текстолів. Рамка з двома текселями повинна бути достатньою для більшості ситуацій з анізотропною фільтрацією.


І останнє, але не менш важливе, ось, як будувався би атлас текстур, який би повторював GL_CLAMP_TO_EDGEповедінку за наявності GL_LINEARтекстурного фільтра:

( Відніміть 1 від X і Y у чорних координатах, я не довів прочитати зображення перед публікацією. )   

Через обмежене зберігання для зберігання 4 текстур 256x256 в цьому атласі потрібна текстура розмірами 516x516. Межі кольором кодуються на основі того, як ви заповнили їх текстовими даними під час створення атласу:

  • Червоний = Замініть текселем прямо внизу
  • Жовтий = Замініть текселем прямо вгорі
  • Зелений = Замініть текселем прямо зліва
  • Синій = Замініть текселем прямо праворуч

Ефективно в цьому упакованому прикладі кожна текстура в атласі використовує область 258x258 атласу, але ви будете генерувати координати текстури, які відображають у видимій області 256x256. Окантовуючі текстилі використовуються лише коли фільтрування текстур робиться по краях фактур в атласі, і спосіб їх оформлення імітує GL_CLAMP_TO_EDGEповедінку.

Якщо вам було цікаво, ви можете реалізувати інші типи режимів обгортання, використовуючи аналогічний підхід - GL_REPEATце можна реалізувати шляхом обміну лівої / правої та верхньої / нижньої меж текстильної текстури в атласі текстури та трохи розумної математики координат текстури в шейдер. Це трохи складніше, тому зараз не турбуйтеся про це. Оскільки ви маєте справу лише з спрайтовими листами, обмежтесь GL_CLAMP_TO_EDGE:)


Дякую @AndonMColeman, чи не могли б ви показати межу на схемі, оскільки я все ще не впевнений, що я розумію, як це працює - чи це знову означатиме, що коли текстура буде застосована до мого об’єкта, вона буде містити межу? Я хочу, щоб фактична текстура йшла прямо до країв мого квадратика - вибачте, якщо я не розумію цього правильно - оціню ще кілька деталей - спасибі
BungleBonce

@ user22241 Безумовно, спосіб роботи цієї межі полягає в дублюванні текстолію на краю текстури.
Андон М. Коулман

@ user22241: Ні, ця межа не буде видимою за звичайних обставин. Ви вважатимете, що упаковані текстури мають однакові розміри для обчислення координат текстури, ви просто застосуєте до них зміщення, щоб пропустити межу кордону. Вся суть кордону полягає в тому, щоб запобігти лінійному відбору проб текстури від надмірного охоплення та відбору проб текстур, що належить до окремих зображень у вашому аркуші спрайту. Якщо ви використовуєте вибірку найближчого сусіда, нічого з цього не потрібно, але тоді ви отримуєте неприємні споріднені спрайти.
Андон М. Коулман

Блискуче детальна відповідь - дякую! Лише одне останнє, якби міг. Як я можу розробити "зміщення", щоб додати до моїх текстурних координат? Я прав, кажу, що це просто 1 / widthOfTexture?
BungleBonce

@ user22241: Так, початком текстурного зображення буде + 1 / widthOfTexture у напрямку X та + 1 / heightOfTexture у напрямку Y. У вас буде межа, яка проходить навколо кожної текстури. На той момент, коли ви хочете обчислити координати текстури для третьої горизонтальної текстури, упаковане місце для цієї текстури є фактично +5 текселями (+2 текселя для межі першої текстури, +2 для межі другої текстури та +1 для початку цієї текстури) крім ширини інших 2 текстур. Це здається складним просто його написання; Я можу скласти вам схему, якщо потрібно :)
Андон М. Коулман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.