Pracuję nad grą podobną do Megamana , w której muszę zmienić kolor niektórych pikseli w czasie wykonywania. Dla porównania : w Megaman, kiedy zmieniasz wybraną broń, wówczas zmienia się paleta głównego bohatera, aby odzwierciedlić wybraną broń. Nie wszystkie kolory duszka zmieniają się, tylko niektóre z nich się zmieniają .
Ten rodzaj efektu był powszechny i dość łatwy do zrobienia w NES, ponieważ programista miał dostęp do palety i logicznego mapowania między pikselami i indeksami palety. Jednak na nowoczesnym sprzęcie jest to nieco trudniejsze, ponieważ koncepcja palet nie jest taka sama.
Wszystkie moje tekstury są 32-bitowe i nie używam palet.
Znam dwa sposoby osiągnięcia pożądanego efektu, ale jestem ciekawy, czy istnieją lepsze sposoby na osiągnięcie tego efektu z łatwością. Dwie znane mi opcje to:
- Użyj modułu cieniującego i napisz GLSL, aby wykonać zachowanie „zamiany palet”.
- Jeśli moduły cieniujące nie są dostępne (powiedzmy, ponieważ karta graficzna ich nie obsługuje), możliwe jest sklonowanie „oryginalnych” tekstur i wygenerowanie różnych wersji ze wstępnie zastosowanymi zmianami kolorów.
Idealnie chciałbym użyć modułu cieniującego, ponieważ wydaje się prosty i wymaga niewiele dodatkowej pracy w przeciwieństwie do metody powielonej tekstury. Martwię się, że powielanie tekstur tylko w celu zmiany koloru marnuje pamięć VRAM - czy nie powinienem się tym przejmować?
Edycja : Skończyłem przy użyciu techniki przyjętej odpowiedzi i tutaj jest mój moduł cieniujący w celach informacyjnych.
uniform sampler2D texture;
uniform sampler2D colorTable;
uniform float paletteIndex;
void main()
{
vec2 pos = gl_TexCoord[0].xy;
vec4 color = texture2D(texture, pos);
vec2 index = vec2(color.r + paletteIndex, 0);
vec4 indexedColor = texture2D(colorTable, index);
gl_FragColor = indexedColor;
}
Obie tekstury są 32-bitowe, jedna jest używana jako tabela przeglądowa zawierająca kilka palet, które są tego samego rozmiaru (w moim przypadku 6 kolorów). Używam czerwonego kanału piksela źródłowego jako indeksu do tabeli kolorów. To zadziałało jak urok dla zamiany palet podobnych do Megamana!
Są dwa sposoby, aby to zrobić.
Sposób nr 1: GL_MODULATE
Możesz zrobić duszka w odcieniach szarości i
GL_MODULATE
tekstury, gdy jest rysowany jednym jednolitym kolorem.Na przykład,
Nie zapewnia to jednak dużej elastyczności, w zasadzie można tylko jaśniej i ciemniej o tym samym odcieniu.
Sposób 2:
if
Stwierdzenie (źle wpływa na wydajność)Inną rzeczą, którą możesz zrobić, jest pokolorowanie tekstur za pomocą kilku kluczowych wartości obejmujących R, G i B. Na przykład SO pierwszy kolor to (1,0,0), drugi kolor to (0,1,0), trzeci kolor to (0,0,1).
Deklarujesz kilka takich mundurków
Następnie w module cieniującym ostateczny kolor piksela jest podobny
color1
,color2
,color3
, Są mundury, więc mogą być ustawione przed tras cieniujących (w zależności od tego, co „garnitur” Megaman jest), wówczas shader prostu zrobi resztę.Możesz także użyć
if
instrukcji, jeśli potrzebujesz więcej kolorów, ale musiałbyś mieć pewność, że kontrole równości działają poprawnie (tekstury zwykle mają wartośćR8G8B8
od 0 do 255 każda w pliku tekstur, ale w module cieniującym masz zmiennoprzecinkowe rgba)Sposób nr 3: Po prostu nadmiarowo przechowuj różne kolorowe obrazy na mapie duszka
Może to być najłatwiejszy sposób, jeśli nie próbujesz szaleńczo oszczędzać pamięci
źródło
Używałbym shaderów. Jeśli nie chcesz ich używać (lub nie możesz), wybrałbym jedną teksturę (lub część tekstury) na kolor i używam tylko czystej bieli. Umożliwi to zabarwienie tekstury (np. Przez
glColor()
) bez martwienia się o tworzenie dodatkowych tekstur dla kolorów. Możesz nawet zamieniać kolory w biegu bez dodatkowej pracy z teksturami.źródło
„Nie wszystkie kolory duszka się zmieniają, tylko niektóre z nich się zmieniają”.
Stare gry wykonywały sztuczki z paletą, ponieważ to wszystko, co mieli. Obecnie możesz używać wielu tekstur i łączyć je na różne sposoby.
Możesz utworzyć osobną teksturę maski w skali szarości, za pomocą której zdecydujesz, które piksele zmienią kolor. Białe obszary tekstury otrzymują pełną modyfikację kolorów, a czarne obszary pozostają niezmienione.
W shader languague:
Lub możesz użyć funkcji teksturowania o stałej funkcji z różnymi trybami łączenia tekstur.
Istnieje oczywiście wiele różnych sposobów, w jaki można tego dokonać; możesz umieścić maski dla różnych kolorów w każdym z kanałów RGB lub modulować kolory poprzez przesunięcie odcienia w przestrzeni kolorów HSV.
Inną, być może prostszą opcją jest po prostu narysowanie duszka przy użyciu osobnej tekstury dla każdego elementu. Jedna tekstura na włosy, jedna na zbroję, jedna na buty itp. Każdy kolor można barwić osobno.
źródło
Po pierwsze, jest ogólnie określany jako jazda na rowerze (jazda na paletach), więc może to pomóc Twojemu Google-fu.
Będzie to zależeć od dokładnie tego, jakie efekty chcesz uzyskać, a jeśli masz do czynienia ze statyczną zawartością 2D lub dynamicznymi rzeczami 3D (tj. Czy chcesz po prostu poradzić sobie ze spite / teksturami, czy też renderować całą scenę 3D, a następnie zamień paletę). Także jeśli ograniczasz się do wielu kolorów lub używasz pełnego koloru.
Bardziej kompletnym podejściem, wykorzystującym shadery, byłoby rzeczywiście tworzenie obrazów z indeksami kolorów z teksturą palety. Stwórz teksturę, ale zamiast kolorów, miej kolor reprezentujący indeks do wyszukania, a następnie inną teksturę kolorów, którą jest płyta. Na przykład czerwony może być współrzędną tekstury, a zielony może być współrzędną. Wykonaj wyszukiwanie za pomocą modułu cieniującego. I animuj / modyfikuj kolory tekstury palety. Byłoby to dość zbliżone do efektu retro, ale działałoby tylko w przypadku statycznych treści 2D, takich jak duszki lub tekstury. Jeśli robisz prawdziwą grafikę retro, możesz być w stanie wygenerować sprite'y z indeksowanymi kolorami i napisać coś, co zaimportuje je i palety.
Będziesz także chciał poćwiczyć, jeśli zamierzasz używać palety „globalnej”. Podobnie jak stary sprzęt będzie działał, mniej pamięci na paletach, ponieważ potrzebujesz tylko jednej, ale trudniej jest stworzyć swoją grafikę, ponieważ musisz zsynchronizować paletę na wszystkich obrazach) lub nadać każdemu obrazowi własną paletę. Dałoby to większą elastyczność, ale zużywa więcej pamięci. Oczywiście możesz zrobić obie rzeczy, a także możesz używać palet tylko do rzeczy, które jeździsz kolorem. Sprawdź także, do jakiego stopnia nie chcesz ograniczać kolorów, na przykład stare gry używałyby 256 kolorów. Jeśli używasz tekstury, otrzymasz liczbę pikseli, więc 256 * 256 da ci
Jeśli chcesz po prostu taniego fałszywego efektu, takiego jak płynąca woda, możesz utworzyć drugą teksturę, która zawiera maskę w skali szarości w obszarze, który chcesz zmodyfikować, a następnie użyj tekstur z masterem, aby zmienić odcień / nasycenie / jasność o wartość w tekstura maski w skali szarości. Możesz być jeszcze bardziej leniwy i po prostu zmienić odcień / jasność / nasycenie czegokolwiek w zakresie kolorów.
Jeśli potrzebujesz go w pełnym 3D, możesz spróbować wygenerować indeksowany obraz w locie, ale byłby on wolny, ponieważ musiałbyś spojrzeć na paletę, prawdopodobnie byłbyś również ograniczony w zakresie kolorów.
W przeciwnym razie możesz po prostu sfałszować go w module cieniującym, jeśli color == zamień kolor, zamień go. Byłoby to powolne i działałoby tylko przy ograniczonej liczbie zamienianych kolorów, ale nie powinno obciążać żadnego dzisiejszego sprzętu, szczególnie jeśli masz do czynienia z grafiką 2D i zawsze możesz zaznaczyć, które duszki mają zamianę kolorów i użyć innego modułu cieniującego.
W przeciwnym razie naprawdę sfałszuj je, utwórz kilka animowanych tekstur dla każdego stanu.
Oto świetna prezentacja cyklu jazdy na paletach wykonana w HTML5 .
źródło
Uważam, że jeśli są wystarczająco szybkie, aby przestrzeń kolorów [0 ... 1] można było podzielić na dwie części:
W ten sposób wartości kolorów od 0 do 0,5 są zarezerwowane dla normalnych wartości kolorów; i 0,5 - 1,0 są zarezerwowane dla wartości „modulowanych”, gdzie 0,5..1,0 mapuje na dowolny zakres wybrany przez użytkownika.
Tylko rozdzielczość kolorów jest obcięta z 256 wartości na piksel do 128 wartości.
Prawdopodobnie można użyć wbudowanych funkcji, takich jak max (kolor-0,5f, 0,0f), aby całkowicie usunąć ifs (zamieniając je na mnożenie przez zero lub jeden ...).
źródło