Як ви рухаєте спрайт з кроком до пікселя?


11

Пікселі ввімкнено або вимкнено. Мінімальна сума, яку можна перемістити спрайт - це один піксель. Отже, як змусити спрайт рухатися повільніше, ніж 1 піксель на кадр?

Я зробив це, щоб додати швидкість до змінної і перевірити, чи досягла вона 1 (або -1). Якби це сталося, я би перемістив спрайт і скинув змінну до 0, як-от так:

update(dt):
    temp_dx += speed * dt
    temp_dy += speed * dt

    if (temp_dx > 1)
        move sprite
        reset temp_dx to 0
    if (tempy_dy > 1)
        move sprite
        reset temp_dy to 0

Мені не подобався такий підхід, тому що він відчуває себе нерозумно і рух спрайта виглядає дуже ривком. Тож яким чином ви б реалізували рух пікселів?


Єдине, що ви могли зробити - це білінеарне фільтрування.
AturSams

Якщо ви рухаєтесь менше ніж 1 пікс на кадр, як це може виглядати ривком?

Відповіді:


17

Існує ряд варіантів:

  1. Робіть так, як і ви. Ви вже сказали, що це не виглядає гладко. Однак у вашому поточному методі є деякі недоліки. Для цього xви можете скористатися наступним:

    tempx += speed * dt
    
    while (tempx > 0.5)
      move sprite to x+1
      tempx -= 1
    while (tempx < -0.5)
      move sprite to x-1
      tempx += 1
    

    це має бути краще. Я переключив, якщо в statments використовується 0,5, так як коли вам передано 0,5, ви ближче до наступного значення, ніж попереднє. Я використовував цикл while, щоб дозволити переміщення більше 1 пікселя за час дії (це не найкращий спосіб зробити це, але це робить компактний і читабельний код). Для повільно переміщуваних об'єктів це все ще буде стрибковим, оскільки ми не вирішили основну проблему вирівнювання пікселів.

  2. Майте кілька графічних зображень для спрайту та використовуйте іншу, залежно від зміщення субпікселя. Наприклад, для згладжування субпікселів лише у x, наприклад, ви можете створити графіку для спрайту в x+0.5, а якщо позиція знаходиться між x+0.25і x+0.75, використовуйте цей спрайт замість оригіналу. Якщо ви хочете більш точного позиціонування, просто створіть більше графіків субпікселів. Якщо ви це зробите в, xі yваша кількість візуалізації може швидко розгорнутись, оскільки кількість масштабів з квадратом числа інтервалів: для інтервалу 0.5знадобиться 4 візуалізації, 0.25потрібно 16.

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

  4. Як запропонував Zehelvion , можливо, платформа, яку ви використовуєте, вже підтримує це. Якщо вам дозволено вказувати не цілі координати x і y, можливо, існують варіанти зміни фільтруючої текстури. Найближчий-сусід часто за замовчуванням, і це спричинить "ривковий" рух. Інша фільтрація (лінійна / кубічна) призведе до набагато плавнішого ефекту.

Вибір між 2. 3. та 4. залежить від того, наскільки реалізована ваша графіка. Стиль растрових графічних зображень підходить до попереднього відображення набагато краще, тоді як векторний стиль може відповідати спрайфувати спрайти. Якщо ваша система підтримує це, 4. цілком може бути шлях.


Навіщо замінити поріг на 0,5 в опти 1? Я також не розумію, чому ви перемістили заяви в цикл часу. Функції оновлення викликаються один раз за галочку.
bzzr

1
Хороше запитання - я уточнив відповідь на основі вашого коментаря.
Джерело

Суперсимплінг може бути "ледачим", але в багатьох випадках вартість продуктивності 2х або навіть 4-х разів перевиконання не буде особливою проблемою, особливо якщо це дозволило спростити інші аспекти візуалізації.
supercat

У іграх з великим бюджетом я зазвичай бачу 3 як опцію, перелічену в налаштуваннях графіки, як антизбудження.
Кевін

1
@Kevin: Ви насправді, мабуть, не так. У більшості ігор використовується мультисемплінг , який дещо відрізняється. Також широко використовуються інші варіанти, наприклад, із різним покриттям, а також зразками глибини. Суперзміцнення майже ніколи не робиться через витрати на виконання фрагмента шейдера.
imallett

14

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

Тобто, якщо ваш спрайт збирався рухати менше одного пікселя на кадр (або, особливо, якщо співвідношення пікселів / кадрів буде чимось дивним, як 2 пікселі в 3 кадрах), ви можете приховати ривка, зробивши n цикл анімації кадрів, який над цими n кадрами перемістив спрайт на кілька k < n пікселів.

Справа в тому, що, доки спрайт завжди певним чином рухається на кожному кадрі, ніколи не буде жодного єдиного кадру, де весь спрайт несподівано "смикнеться" вперед.


Я не міг знайти справжнього спрайту зі старої відеоігри, щоб проілюструвати це (хоча я думаю, що, наприклад, деякі анімаційні копання з Леммінга були такими), але виявляється, що «планер» візерунок з гри «Життя життя Конвея» робить дуже приємна ілюстрація:

введіть тут опис зображення
Анімація від Kieff / Wikimedia Commons , використовується під ліцензією CC-By-SA 3.0 .

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


2
Це відмінний підхід, якщо швидкість фіксована, або якщо вона менше 1/2 пікселя на кадр, або якщо анімація "достатньо велика" і досить швидка, щоб затемнити зміни в русі.
supercat

Це хороший підхід, хоча, якщо камера повинна дотримуватися спрайту, ви все одно матимете проблеми, оскільки вона не буде рухатися досить плавно.
Елден Абов

6

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

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


3

Єдине справжнє рішення тут - використовувати білінеарну фільтрацію. Ідея полягає в тому, щоб GPU обчислював значення кожного пікселя на основі чотирьох пікселів спрайта, які перетинаються з ним. Це звичайна і ефективна методика. Вам просто потрібно розмістити спрайт на 2-простій (білборді) як текстуру; потім використовуйте GPU для надання цих рівнин. Це добре працює, але сподівайтеся, що ви отримаєте дещо розмиті результати та втратите 8-бітний чи 16-бітний вигляд, якби ви прагнули цього.

плюси:

Вже впроваджене, дуже швидке, апаратне рішення.

мінуси:

Втрата 8-бітової / 16-бітової вірності.


1

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

Однак є й інший спосіб робити те, що ви зараз робите, але трохи менш ривковим: фіксована точка. 32-бітове значення позиції може представляти значення від 0 до 4 294 967 295, хоча ваш екран майже напевно має менше 4 к пікселів по будь-якій осі. Тому поставте фіксовану "двійкову точку" (за аналогією з десятковою точкою) в середину, і ви можете представити позиції пікселів від 0-65536 з ще 16 бітами роздільної здатності субпікселя. Потім ви можете додавати числа як звичайні, просто потрібно пам’ятати про перетворення шляхом правильного зміщення 16 біт під час переходу на екранний простір або коли ви множили два числа разом.

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


1

На додаток до інших відповідей тут ви можете певною мірою використовувати дистінг. Дірінг - це край пікселів об'єкта світліше / темнішого кольору, щоб відповідати фоновому малюнку для більш м'якого краю. Наприклад, скажіть, у вас був квадрат пікселів, який я оціню:

OO
OO

Якби ви переміщали цей 1/2 пікселя вправо, нічого насправді не рухалося б. Але з деяким дрижанням ви могли трохи зробити ілюзію руху. Розгляньте O як чорний, а o - сірий, так що ви можете зробити:

oOo
oOo

В одному кадрі і

 OO
 OO

У наступному. Справжній "квадрат" із сірим краєм фактично займе 3 пікселі, але оскільки вони світлішого сірого, ніж чорні, вони здаються меншими. Однак це може бути важко кодувати, і я не знаю нічого про те, що робить це зараз. З часом, коли вони почали використовувати тремтіння для вирішення речей, швидко стало краще, і не було такої великої потреби, крім випадків, як маніпулювання зображеннями.

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