Zanika w starszych grach. Potrzebujesz pomocy w ustaleniu, w jaki sposób uzyskano algorytm

12

Przepraszam, to pytanie jest nieco ezoteryczne, ale po prostu nie mogę tego z głowy wyrzucić!

Patrzę na algorytm zanikania używany w grze arkadowej DoDonPachi (jak również w wielu innych starszych grach):

wprowadź opis zdjęcia tutaj

Napisałem skrypt Pythona, aby wybrać kilka pikseli i śledzić je na czas zanikania. Oto reprezentatywna próbka wyników. Pierwszy rząd każdej grupy jest początkową wartością koloru, zaś każdy kolejny rząd stanowi różnicę między wartością koloru bieżącej ramki a wartością koloru poprzedniej ramki.

Starting Value: (132, 66, 189)
Frame 1:    [9, 9, 8]
Frame 2:    [8, 8, 8]
Frame 3:    [8, 8, 8]
Frame 4:    [8, 8, 9]
Frame 5:    [9, 9, 8]
Frame 6:    [8, 8, 8]
Frame 7:    [8, 8, 8]
Frame 8:    [8, 8, 9]
Frame 9:    [9, 0, 8]
Frame 10:   [8, 0, 8]
Frame 11:   [8, 0, 8]
Frame 12:   [8, 0, 9]
Frame 13:   [9, 0, 8]
Frame 14:   [8, 0, 8]
Frame 15:   [8, 0, 8]
Frame 16:   [8, 0, 9]
Frame 17:   [0, 0, 8]
Frame 18:   [0, 0, 8]
Frame 19:   [0, 0, 8]
Frame 20:   [0, 0, 9]
Frame 21:   [0, 0, 8]
Frame 22:   [0, 0, 8]
Frame 23:   [0, 0, 8]
Frame 24:   [0, 0, 0]
Frame 25:   [0, 0, 0]
Frame 26:   [0, 0, 0]
Frame 27:   [0, 0, 0]
Frame 28:   [0, 0, 0]
Frame 29:   [0, 0, 0]

Starting Value: (132, 0, 0)
Frame 1:    [9, 0, 0]
Frame 2:    [8, 0, 0]
Frame 3:    [8, 0, 0]
Frame 4:    [8, 0, 0]
Frame 5:    [9, 0, 0]
Frame 6:    [8, 0, 0]
Frame 7:    [8, 0, 0]
Frame 8:    [8, 0, 0]
Frame 9:    [9, 0, 0]
Frame 10:   [8, 0, 0]
Frame 11:   [8, 0, 0]
Frame 12:   [8, 0, 0]
Frame 13:   [9, 0, 0]
Frame 14:   [8, 0, 0]
Frame 15:   [8, 0, 0]
Frame 16:   [8, 0, 0]
Frame 17:   [0, 0, 0]
Frame 18:   [0, 0, 0]
Frame 19:   [0, 0, 0]
Frame 20:   [0, 0, 0]
Frame 21:   [0, 0, 0]
Frame 22:   [0, 0, 0]
Frame 23:   [0, 0, 0]
Frame 24:   [0, 0, 0]
Frame 25:   [0, 0, 0]
Frame 26:   [0, 0, 0]
Frame 27:   [0, 0, 0]
Frame 28:   [0, 0, 0]
Frame 29:   [0, 0, 0]

Starting Value: (165, 156, 222)
Frame 1:    [9, 8, 8]
Frame 2:    [8, 8, 8]
Frame 3:    [8, 8, 8]
Frame 4:    [8, 9, 9]
Frame 5:    [9, 8, 8]
Frame 6:    [8, 8, 8]
Frame 7:    [8, 8, 8]
Frame 8:    [8, 9, 9]
Frame 9:    [9, 8, 8]
Frame 10:   [8, 8, 8]
Frame 11:   [8, 8, 8]
Frame 12:   [8, 9, 9]
Frame 13:   [9, 8, 8]
Frame 14:   [8, 8, 8]
Frame 15:   [8, 8, 8]
Frame 16:   [8, 9, 9]
Frame 17:   [9, 8, 8]
Frame 18:   [8, 8, 8]
Frame 19:   [8, 8, 8]
Frame 20:   [8, 0, 9]
Frame 21:   [0, 0, 8]
Frame 22:   [0, 0, 8]
Frame 23:   [0, 0, 8]
Frame 24:   [0, 0, 9]
Frame 25:   [0, 0, 8]
Frame 26:   [0, 0, 8]
Frame 27:   [0, 0, 8]
Frame 28:   [0, 0, 0]
Frame 29:   [0, 0, 0]

Starting Value: (156, 90, 206)
Frame 1:    [8, 8, 8]
Frame 2:    [8, 8, 9]
Frame 3:    [8, 8, 8]
Frame 4:    [9, 9, 8]
Frame 5:    [8, 8, 8]
Frame 6:    [8, 8, 9]
Frame 7:    [8, 8, 8]
Frame 8:    [9, 9, 8]
Frame 9:    [8, 8, 8]
Frame 10:   [8, 8, 9]
Frame 11:   [8, 8, 8]
Frame 12:   [9, 0, 8]
Frame 13:   [8, 0, 8]
Frame 14:   [8, 0, 9]
Frame 15:   [8, 0, 8]
Frame 16:   [9, 0, 8]
Frame 17:   [8, 0, 8]
Frame 18:   [8, 0, 9]
Frame 19:   [8, 0, 8]
Frame 20:   [0, 0, 8]
Frame 21:   [0, 0, 8]
Frame 22:   [0, 0, 9]
Frame 23:   [0, 0, 8]
Frame 24:   [0, 0, 8]
Frame 25:   [0, 0, 8]
Frame 26:   [0, 0, 0]
Frame 27:   [0, 0, 0]
Frame 28:   [0, 0, 0]
Frame 29:   [0, 0, 0]

Jak widać, 8 lub 9 jest odejmowane od każdego składnika koloru w każdej ramce. Ponadto 9 zawsze pojawia się trzy klatki po 8, mimo że początkowa odejmowana wartość jest różna dla każdego komponentu koloru. Zauważ też, że każdy składnik koloru osiąga 0 (to znaczy czarny) z różnicą 8 lub 9, a nie jakąkolwiek pozostałą resztą. Oznacza to, że odejmowany cykl wartości 8,8,8,9 nigdy nie jest łamany! (Ten algorytm został prawdopodobnie napisany w celu zapewnienia, że ​​ostatnia klatka przejścia jest tak samo gładka jak inne).

To mnie zastanawia. Według moich obliczeń, jeśli odwrócisz proces - to znaczy weź 8,8,8,9 cyklu i zsumuj go, aby znaleźć wszystkie możliwe kombinacje w 29 klatkach - otrzymasz tylko 52 unikalne liczby. Ale tak się składa, że ​​każdy element koloru jest członkiem tego zestawu! Oznacza to, że albo kolory zostały wybrane specjalnie dla tego algorytmu przejścia (mało prawdopodobne), albo że algorytm przejścia został zaprojektowany wokół palety kolorów gry. Ale jak, u licha, ktoś mógł zorientować się, że jeśli weźmiesz 8,8,8,9, odpowiednio przesuniesz cykl i odejmujesz liczby z każdego składnika koloru w palecie, w końcu osiągniesz 0 dla każdego koloru? ! Musi być jakiś matematyczny trik, za którym tęsknię. Co to jest?

Archagon
źródło
2
Dlaczego nie po prostu grać z alfą? Tak robię w przypadku animacji pojawiania się / zanikania.
DogDog
Nie próbuję replikować algorytmu we własnym kodzie, próbuję tylko dowiedzieć się, w jaki sposób został uzyskany.
Archagon
Wydaje mi się, że to, co powiedziałeś, kolory zostały wybrane na podstawie sekwencji 8,8,8,9. Biorąc pod uwagę tę sekwencję, mogli wybierać spośród 52 * 52 * 52 kolorów. Ciekawa uwaga, jeśli zaczniesz od 0 i dodasz sekwencję 8,8,8,9, otrzymasz 255. To pozwala im używać czerni i bieli.
Luis Estrada,
@Apoc: Styl wyciszania różni się wyraźnie od zanikania alfa. Widzisz, jak każda wartość koloru spada o stałą liczbę (wzór liczbowy), a nie o procent jej początkowej wartości? Oznacza to, że istnieją okoliczności, w których wolisz używać go zamiast bardziej powszechnych metod. Na przykład w stylu retro.
AlbeyAmakiir

Odpowiedzi:

20

W rzeczywistości za wzorcem 8-8-8-9 kryje się prosta logika. Powstaje naturalnie, jeśli używasz tylko 32 poziomów intensywności (5 bitów na komponent), ale chcesz renderować to na 8-bitowym ekranie na komponent.

Zastanów się, czy masz 5-bitowy poziom intensywności i chcesz rozszerzyć go do 8 bitów. Najprostszą rzeczą jest przesunięcie w lewo i pozostawienie niskich trzech bitów zero. Problem w tym, że nie idzie to aż do czystej bieli. Najwyższy poziom intensywności, jaki można osiągnąć, to 11111000 lub 248. Zatem nie używasz pełnego zakresu intensywności 8-bitowego wyświetlacza.

Naprawdę chciałbyś wykonać takie obliczenia, jak intensity8 = round(intensity5 * 255.0 / 31.0)przeskalowanie zakresu [0, 31] na [0, 255]. Istnieje jednak fajna sztuczka, aby to osiągnąć bez matematyki zmiennoprzecinkowej lub dzielenia: ustaw niskie trzy bity na równe wysokie trzy bity. Oznacza to konwersję intensywności z 5-bitowej na 8-bitową

intensity8 = (intensity5 << 3) | (intensity5 >> 2);

Następnie intensywność 11111 zostanie odwzorowana na 11111111 (31 map na 255), a wyniki pośrednie również zrobią coś rozsądnego, np. 10000 -> 10000100 (16 -> 132).

Ten zestaw liczb jest dokładnie tym, co masz. Biorąc czerwony element pierwszego przykładu, masz:

132    10000100
123    01111011
115    01110011
107    01101011
 99    01100011
 90    01011010
 82    01010010
 74    01001010

Zauważ, że niskie trzy bity są zawsze równe trzem górnym bitom. Różnica 9 występuje, gdy zarówno bit 0, jak i bit 3 przerzucają jednocześnie.

Nie jestem pewien, dlaczego w tej sytuacji zastosowano 5-bitowe poziomy intensywności; może to był limit sprzętu maszyny zręcznościowej? Warto zauważyć, że 5-bitowa wartość RGB wynosi 15 bitów, co ładnie pasuje do 16-bitowego słowa. W każdym razie wyjaśnia to dziwny wzór 8–8–8–9.

Nathan Reed
źródło
1
16 bitów na piksel nazwano „High Color”. (To wszystko, co pamiętam) en.wikipedia.org/wiki/High_color
tugs
1
Po krótkiej podróży przez wikipedię, Sega Saturn ( en.wikipedia.org/wiki/Sega_Saturn#Video ) wspomina o 15-bitowym trybie wyświetlania kolorów, a także GameBoy Advance ( en.wikipedia.org/wiki/Game_Boy_Advance )
holowniki
1
To wspaniale! Teraz wszystko nabiera sensu. Dziękuję Ci!
Archagon
Gra musiała mieć 16-bitowy kolor, a artyści prawdopodobnie chcieli wycisnąć więcej kolorów ze swojej gry kosztem przezroczystości, dając schemat kolorów RGBA 5551.
Archagon,
0

Powinieneś zajrzeć do trybu 13h lub 256 zanikania palety kolorów. Wtedy miałeś tyle kolorów, a to, co robiłeś, powodowało bałagan z całą paletą, ponieważ nie mogłeś obliczyć nowych kolorów, których nie było.

Deleteman
źródło