Ефективний спосіб нанесення обрисів навколо спрайтів


21

Я використовую XNA для програмування гри і експериментую з різними способами, щоб досягти "обраного" ефекту на моїх спрайтах. Проблема, яку я маю, полягає в тому, що кожен клік, який намальований в spritebatch, малюється за допомогою більш ніж одного спрайту (кожен об'єкт може складатися з до 6 спрайтів).

Буду вдячний, якби хтось міг порадити мені, як я можу досягти додавання контуру до моїх спрайтів із пікселів X (тому ширина контуру може бути різною кількістю цілих пікселів).

Спасибі заздалегідь,

  • Грег.

Відповіді:


20

На сьогодні найпростіший спосіб зробити це (тому, мабуть, найкращий спосіб, якщо ви насправді не прив'язуєтесь до продуктивності) - це мати дві копії своїх спрайтів.

  • Регулярна версія
  • "Жирна", безбарвна версія - в основному біла версія вашого спрайту X-багато пікселів "жирніше", ніж оригінал.

Намалюйте весь об’єкт, використовуючи версію "жиру", а потім намалюйте звичайну версію зверху.

Зробивши «жирну» версію білою, ви можете використовувати вбудовану кольорову тону SpriteBatch, щоб змінити колір вибору динамічно.

Для створення "жирного" версону я рекомендую написати розширення контентного конвеєра, яке може автоматично приймати оригінальні спрайти, читати їх альфа-канал, створювати новий альфа-канал, відбираючи максимальний альфа-канал у вихідному зображенні X-багато пікселів навколо кожного пікселя, і встановлення RGB = (1,1,1).

Вам потрібно буде переконатися, що у всіх у спрайтів є достатня прозора рамка, щоб додати контур (ви можете перевірити це в процесорі вмісту - і навіть звільнити місце, якщо потрібно).

Якщо у вас є лише кілька спрайтів, ви можете просто скористатися хорошим редактором зображень (GIMP, Photoshop) і зробити це вручну: Альфа-канал до вибору, розширення вибору, виділення до альфа, заповнення кольорових каналів білим.


4

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


11
Цей шейдер напрочуд дратує написання, я чув (ми використовували його в одній із наших 3D-ігор і продовжували працювати в непривабливих випадках). Одне, що ви можете розглянути, - це кодування контуру прямо в текстуру спрайта з певним кольором, таким як (0, 255, 255, 0), і просто мати шейдер перетворити цей колір при виборі спрайта. Тоді шейдер - це банальна зміна кольору, і ви маєте високий рівень виконавця контролю над контуром та будь-якими потрібними деталями.

4

Залежно від вимог, що також може бути ефективним - це просто створити контур на вимогу спрайту. Я припускаю, що ваші спрайти мають прозорість і мають неправильну форму, а не просто прямокутники (хоча це буде добре для цього, контури прямокутників мають бути тривіальними).

when selected:
   outline = new sprite canvas of appropriate size
   for sprite in object:
      # use larger numbers for thicker outlines
      for x in (-1, 0, 1) and y in (-1, 0, 1):
         render sprite mask into canvas at x,y with desired color

Зауважте, що вам не потрібно робити це кожен розіграш (хоча, мабуть, ви могли), а просто створити новий спрайт під час перемикання спрайтів.


Так, саме це я хотів запропонувати. Виведіть маскований спрайт 1 пікселем зліва, справа, вгорі та внизу від оригінального спрайта під існуючим спрайтом. Багато ігор використовували цей метод для окреслення виведеного тексту або лише з 2-х з 4-х позицій для створення тіні.
Кай

1

Найпростіший підхід грубої сили - це складання двох примірників кожного спрайту, звичайного та виділеного. Потім просто поміняйте їх, коли вони виділені.

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


Я думаю, що проблема полягає в тому, що ОП говорить, що кожен об'єкт може бути зроблений з декількох спрайтів. Тому я думаю, що контур повинен бути контуром об’єднаного об'єкта, а не окремим контуром навколо кожного компонента спрайту.
Кріс Хоу

1
Кріс, це не повинно бути контуром об'єднаного об'єкта, і він буде добре працювати для об'єкта, виготовленого з декількох спрайтів. Просто виконайте саме те, що сказав wkerslake, але переконайтеся, що ви намалювали виділені спрайти за всіма нормальними спрайтами для цього об’єкта. Таким чином, незалежно від того, з якої кількості спрайтів зроблено об'єкт, підсвітка використовує лише трохи більше, ніж удвічі більше часу для малювання для цього об’єкта, що має бути набагато менше, ніж генерувати контури під час рендерингу за допомогою комбінованих спрайтів.
AttackingHobo

1

Як щодо кожного спрайту, також є ще один спрайт, який є контуром базового спрайта. Малюючи окреслений об’єкт, намалюйте основні спрайти, потім зробіть маску комбінованого візуалізації, потім намалюйте контурні спрайти, виключаючи маску.


2
Чому б просто не намалювати спочатку обриси і намалювати звичайні спрайти над ними?
Кріс Хоу

Одна з причин цього не робити (або пропозиція Кріса) полягає в тому, що він використовує вдвічі більше текстурної пам'яті; Ще одна причина полягає в тому, що робочий процес виконавця є лайно, тому що вам потрібно оновлювати два файли щоразу, коли ви змінюєте спрайт.

2
Ну так, в ідеалі не було б двох фактичних спрайтів. Якщо ви використовуєте альфа-тестування для своїх спрайтів, ви можете поставити контур у спрайт і надати йому альфа трохи вище, ніж прозорі області. Тоді, керуючи еталонним значенням тесту альфа, ви можете контролювати, чи видно контур чи ні. Все, що я говорив, - це те, що якщо у вас є 2 версії спрайтів (чи це два активи або 2 стану одного активу), слід спершу скласти контурну версію, а потім звичайну версію. Таким чином, вам не потрібні будь-які модні шейдери, маски тощо.
Кріс Хоу

1
Ідея Кріса має заслугу; окрім того, щоб оновити виконавця 2 файли (або навіть той самий актив) можна уникнути, якщо створити інструмент для генерації альфа для контурних спрайтів, який працює як частина вашого конвеєра ресурсів / вмісту. Пам'ять текстури може бути або не бути проблемою, але окремі контури структури повинні бути дуже стислими для DXT; можливо, на 1/6 розмір оригінальної текстури у відеопам'яті і без втрати вірності.
jpaver

1

Кілька різних рішень з різними компромісами.

Найпростіше: візуалізуйте об'єкт, використовуючи плоскі кольори кілька разів, і поворушіть позицію (зміщення ліворуч, вгору, вниз, вправо тощо), це створить контурну версію того, що ви робите поверх нього, але має витрати на продуктивність і не буде дозволяють жирові межі без великої кількості зайвих рендерів. Один або два піксельні межі можуть бути в порядку з 4x.

Швидше: попередньо обробіть текстуру та отримайте копію, яка вже є межею, або це лише рамка, або це плоска сіра 8-бітова маска, яку можна розфарбувати в шейдері. Це, швидше за все, буде швидко за рахунок пам'яті.

Найкраще: На мою думку, але генерування представленого вами об'єкта представленого поля з підписом (SDF) може бути найкращим рішенням. Ці текстури можуть бути набагато меншими, ніж вихідні текстури, та все ж захоплюють корисні дані. По суті, кожен піксель кодує, наскільки він віддалений від об'єкта, який використовується для його створення. Маючи ці дані в руці, ви можете записувати всі види ефектів від світіння до контурів. Облямка може змінюватись за розміром і кольором і т. Д., І досі це порівняно дешевий шейдер і лише один додатковий малюнок. Нижня сторона - це інструментальне та попереднє оброблення.


0

Я не впевнений у ефективності, але найпростішим способом, який я бачу, було б намалювати більшу версію спрайту в кольорі, який ви хочете обрати першим. Зверху намалюйте спрайт. Ви побачите лише край першого спрайту, даючи ефект відбору.

EDIT: Однак, як ви бачите з коментарів, це не дуже гарна ідея.


1
Просто масштабування спрайту не дає справжнього контуру
Ієн

2
Я не думаю, що це буде, але це було б легко.
Качка комуністична

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

Масштабування буде добре виглядати лише для твердих квадратних або круглих предметів. Якщо форма дійсно широка, або висока, або має прогалини, вона буде виглядати дуже погано.
AttackingHobo

3
Масштабування дасть кращі результати, ніж нічого не робити, а також стане корисним кроком на шляху до "досконалості". Хоча графічні результати не будуть ідеальними, якби це був внутрішній інструмент, можливо, це буде достатньо.
dash-tom-bang

0

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

  • тобто spriteOutline.Scale = spriteOriginal.Scale * 0.1f; spriteOutline.Color = новий колір (255, 0, 0, 255);

0

Замініть колір оригінального спрайту кольором контуру (або навіть відтініть його, якщо вам подобається). Візьміть цей плоский затінений або тонований спрайт чотири рази зі зміщенням в 1 піксель: при х, у = (- 1, -1), потім (+ 1, -1), потім (-1, + 1), потім (+1 , +1). Повторіть для всіх спрайтів, що складають об’єкт.

Після цього наведіть оригінальні спрайти в належному порядку зверху (0,0).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.