Jakich technik renderowania użyłbym do narysowania efektu cienia dla kart w grze karcianej?

13

Jakiego rodzaju algorytmu cieniowania można użyć do tworzenia takich cieni? wprowadź opis zdjęcia tutaj

ten, który tworzę, jest podobny, ale wszystko odbywa się za pomocą interfejsu API rysowania 2D opartego na OpenGL, więc nie ma współrzędnej Z.

Ponadto, dla samej ręki, naprawdę chciałbym uzyskać zacienione odczucie, jak tutaj: wprowadź opis zdjęcia tutaj

Po prostu nie jestem pewien, jak uzyskać zacieniony wygląd.

Liczba kart musi się zmienić, a karty zostaną rzucone na stół, więc nie mogę użyć żadnego rodzaju lekkiej mapy.

Jakiego rodzaju algorytmów powinienem szukać (oprócz rozmycia, które wiem, że muszę zrobić?)

Dzięki

Aktualizacja

Tworzę grę karcianą 2D. Chcę dodać przesunięcie cienia w stosunku do kart, trochę jak:

wprowadź opis zdjęcia tutaj

Myślę o tym:

  • Zachowaj teksturę tego samego rozmiaru co bufor buforowy.
  • Narysuj ciemne prostokąty jako prowizoryczne karty do tej tekstury.

  • Rozmyj tę teksturę.

  • Narysuj moje karty do tej tekstury.
  • Zrób dodatkowe oświetlenie kart.
  • Narysuj tę teksturę na backbufferze.

Moje pytania to:

  • Czy to właściwy sposób, aby to zrobić?

  • Czy istnieje sposób, aby to zrobić bez renderowania do tekstury (utrzymanie bitmapy
    tak dużej jak backbuffer)?

  • Czy można bezpiecznie założyć, że maksymalny rozmiar tekstury nie zostanie
    przekroczony przez rozmiar bufora tylnego? (Mam na myśli to, że jeśli backbuffer
    ma wymiary 2000 x 3000 , to spokojnie można powiedzieć, że mogę utworzyć teksturę w
    pamięci wideo o tym rozmiarze?

Dzięki

jmasterx
źródło
1
Punkt estetyczny drugiego problemu: nie jest to naprawdę możliwe, jeśli faktycznie trzymasz te karty w ręku. Przyciśnięte obok siebie karty nie rzucają się w oczy. Nie, chyba że masz ich dużo . Naprawdę nie możesz trzymać kart tak, jak są one przedstawione na tym obrazie; te karty wyglądają, jakby były oddzielone o kilka milimetrów; nie są sobie płascy. Po prostu nie martwiłbym się tym.
Nicol Bolas,

Odpowiedzi:

18

Myślę, że wszyscy dają zbyt skomplikowane rozwiązania tego problemu ...

wprowadź opis zdjęcia tutaj

Najpierw mamy kartę (lub cokolwiek, co chcesz narysować), przedstawione tutaj przez (a). Następnie bierzemy kopię, wypełniamy ją na czarno i uruchamiamy na niej rozmycie gaussowskie (b). Wszystko to dzieje się w Photoshopie lub dowolnym ulubionym narzędziu artystycznym.

Następnie, w grze, gdy chcemy narysować kartę, najpierw narysuj zamazany czarny obraz z mieszanką multiplikatywną (lub alfa), przesunąć nieco w pewnym kierunku, a następnie narysuj kartę na nim. Voilá.

Aby uzyskać więcej sztuczek, możesz przełączać się między renderowaniem cieni i kart, aby uzyskać efekt, jak (d), lub najpierw narysuj wszystkie cienie, a następnie karty, jak w (e) (pokolorowałem karty w przypadku (e), aby pokazać, że nadal są osobni =)

Najlepiej też nie używać czystej czerni (lub pełnej alfa) do tworzenia cieni w celu uzyskania bardziej subtelnych, przezroczystych cieni.

Jari Komppa
źródło
2
+1 za robienie cieni poza grą. Możesz także pójść o krok dalej i zmodyfikować położenie cienia, jeśli na scenie jest światło.
FrenchyNZ,
+1, ładna ilustracja. Ponadto w przypadku E można użyć renderowania ciemnych cieni na stole i półjaśnych na kartach z szablonem. Będzie to bardziej skomplikowane, ale efekt będzie jeszcze ładniejszy :)
Kromster,
2

Pierwszy nie jest zbyt trudny. Jeśli renderujesz kanał alfa dla ręki kart (która może być tak prosta jak czerń dla piksela z kartą i biała dla przezroczystości), możesz wykonać dowolne rozmycie, tylko na kanale alfa, i następnie przesuń go i użyj tego do sterowania oświetleniem stołu. (Prawdopodobnie, jeśli nie masz bufora Z, najpierw musisz wyrenderować gdzieś kanał alfa poza ekranem, a następnie zrobić tabelę z maską, a następnie renderować rzeczywiste karty.)

Drugi wygląda trochę jak SSAO (okluzja otoczenia w przestrzeni ekranu). Ta technika wymaga współrzędnej Z. Jeśli jednak nie masz różnych kątów między kartami (co zgaduję, jeśli nie masz bufora Z), prawdopodobnie możesz zrobić całkiem dobre przybliżenie, renderując cień (jak pierwszy) dla każdej karty karta. Wydajność może być jednak trochę trudna - każdy samolot potrzebowałby niewyraźnego kanału alfa dla wszystkich samolotów nad nim, a jeśli na stole znajduje się wiązka kart, może to być kilka pasaży renderowania.

John Calsbeek
źródło
SSAO to przesada =) Bardzo trudno jest powiedzieć, jaką technikę cieniowania stosuje się bez animacji przykładu. Gdyby karty zawsze układały się w tej kolejności i układały jeden na drugim, najłatwiej byłoby po prostu wstępnie wyrenderować cienie, ale nigdy nie wiadomo, czy gra jest w akcji.
Patrick Hughes,
0

Czy nie możesz zrobić mapy cienia? Renderuj scenę do fbo. Zapisz tylko wartości głębokości i sprawdź normalną wartość głębokości w module cieniującym, aby sprawdzić, czy cień powinien być renderowany, czy nie.

Joey Green
źródło
Nie używam bufora Z, nie ma „głębi”.
jmasterx
0

Poniższy proces nie wymaga docelowego renderowania poza ekranem. W ten sposób uzyskuje się jednak wymóg, aby najpierw narysować tabelę . Przynajmniej piksele nie zostaną narysowane przed rysowaniem tabeli. Wymaga również, aby sam stół był jednym, pojedynczym, nie nakładającym się elementem: obrazem.

Ponadto bufor ramki wymaga komponentu alfa.

  1. Uzyskaj obraz w skali szarości karty. Spraw, aby był niewyraźny wokół krawędzi, prawdopodobnie zwiększając jego rozmiar. To jest twój obraz karty cienia. Pamiętaj, że jest to obraz jednokanałowy. Gdy uzyskasz dostęp do tej tekstury w module cieniującym, upewnij się, że umieściłeś pojedynczą wartość w składniku alfa. Można to zrobić w shaderze lub w innym miejscu.

    Wartość 0,0 na obrazie oznacza, że ​​nie ma cienia. Wartość 1,0 na obrazie oznacza całkowity cień . To znaczy, zupełnie czarna. Prawdopodobnie chcesz mieć wartość około 0,5 jako swój najciemniejszy kolor.

  2. Wyczyść ekran tak, aby alfa było ustawione na zero .

  3. Przed renderowaniem czegokolwiek (lub przynajmniej czegokolwiek, co będzie renderowane „pod” stołem), dla każdej karty, render rozmytą teksturę, przesunięcie względem rzeczywistej pozycji karty (ale z tą samą orientacją). Kolor wyjściowy modułu cieniującego powinien mieć następującą konfigurację mieszania (w języku OpenGL):

    glBlendEquation(GL_MAX);

    Ten tryb mieszania służy do tego, aby nakładające się cienie nie stawały się coraz ciemniejsze lub jaśniejsze. Po prostu przyjmuje najciemniejszą wartość zapisaną na tym pikselu. Powinno dobrze wyglądać.

    Powinieneś również użyć maski zapisu kolorów, aby wyłączyć zapisywanie kolorów.

  4. Renderuj stół. W takim przypadku mieszanie należy skonfigurować w następujący sposób:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);

Jeśli ograniczenia są dla ciebie zbyt restrykcyjne, musisz użyć celu renderowania. Odbywa się to w następujący sposób:

  1. Utwórz obraz karty cienia jak poprzednio.

  2. Najpierw renderuj cienie. Powiąż bufor cieniowania ramki (który musi być tylko obrazem jednokanałowym, jeśli twój sprzęt może renderować do jednego z nich). Wyczyść jego wartość do zera.

  3. Dla każdej karty renderuj obraz karty cienia z przesunięciem jak poprzednio. Twój moduł cieniujący powinien zapisać tę samą wartość do wszystkich czterech składników koloru wyjściowego. Tryb mieszania powinien być ponownie glBlendEquation(GL_MAX).

  4. Wróć do zwykłego bufora ramki. Narysuj wszystko, co chcesz ukryć.

  5. Teraz narysuj kwadrat na pełnym ekranie z renderowanym przez nas obrazem cienia. Moduł cieniujący powinien przechowywać tekst pobrany z obrazu cienia w alfa wyniku; RGB nie ma znaczenia. Tryb mieszania powinien być:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
Nicol Bolas
źródło
W pierwszej metodzie myślę, że zapomniałeś kroku 5: wyłącz miksowanie i renderuj karty. Warto również zauważyć, że pierwsza metoda nie pozwala uzyskać cieni między kartami, jak widać na drugim zrzucie ekranu PO.
Nathan Reed,
@NathanReed: Uznałem, że sam wie, jak to wyłączyć. Ponadto „cienie między kartami” nie mają żadnego sensu, jak wskazałem w moim komentarzu do pytania.
Nicol Bolas,
1
Może nie odzwierciedlać realistycznie sposobu posiadania kart, ale wygląda świetnie! Tak naprawdę nie ma sensu, aby karty unosiły się nad stołem, tak jak robią to w pierwszym ujęciu, albo ...
Nathan Reed,
0

Użyłbym bufora szablonów. Wyczyść to do 1 (najlepiej w tym samym czasie, gdy wyczyścisz głębokość), narysuj swój stół. Następnie włącz test szablonu, narysuj cienie za pomocą rozmytej tekstury prostokąta, zwiększając, jeśli szablon i głębokość przejdą, nie robiąc nic, jeśli szablon się nie powiedzie, nic, jeśli głębokość się nie powiedzie, i ustaw func szablonu na GL_EQUAL (ref 1, maska ​​0xff), wyłącz test szablonu . (Nie przetestowałem tego w pełni, ale pochodzi on z kodu, który działa podobnie i powinien działać dobrze; być może trzeba będzie poprawić parametry). Następnie narysuj wszystko inne.

Połączenia będą:

glEnable (GL_STENCIL_TEST);
glStencilFunc (GL_EQUAL, 1, 2);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);

// draw shadow textures

glDisable (GL_STENCIL_TEST);

Jedyny raz może to powodować problemy, jeśli masz dwie rozmyte krawędzie, które lekko się pokrywają; w przeciwnym razie nie potrzebuje nic szczególnego poza podstawową ofertą OpenGL 1.1 i będzie działał na każdym sprzęcie (spodziewaj się być może starych kart 3DFX, które zakładam, że tak naprawdę nie martwisz się o wsparcie ...)

Drugą alternatywą, która powinna działać bardzo dobrze w grze niekrytycznej pod względem wydajności, jest glCopyTexSubImage2D. Działa to również z teksturą mniejszą niż backbuffer i jest również dobrze obsługiwany na wszystkich urządzeniach (jest to część OpenGL 1.1 i Doom 3 go używało, więc możesz oczekiwać, że wsparcie będzie bardzo dobre).

Podstawowa konfiguracja wyglądałaby następująco:

  • Przejrzysty kolor na czarny.
  • Wyłącz zapis głębokości (chociaż ta metoda nie wymaga bufora głębokości, więc możesz zignorować tę część, ponieważ nie używasz jej).
  • Ustaw rzutnię o takich samych wymiarach jak tekstura.
  • Dobierz karty jako białe wypełnione geometrie.
  • glCopyTexSubImage2D do tekstury.
  • Przełącz widok z powrotem do pełnego rozmiaru okna.
  • Narysuj stół jak zwykle.
  • Narysuj teksturę jako pełnoekranowy poczwórny quad, używając shadera, aby go rozmyć i odwrócić kolor.
  • Narysuj wszystko inne.

Powinno to również działać bardzo dobrze, jest nieco bardziej intensywne w GPU niż metoda bufora matrycowego, ale poprawnie obsługuje nakładającą się obudowę i - jak powiedziałem - myślę, że gra taka jak Twoja będzie miała moc GPU do wypalenia, nawet na niskim poziomie karta.

Maximus Minimus
źródło