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):
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?
Odpowiedzi:
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ą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:
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.
źródło
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.
źródło