Skuteczny sposób rysowania konturów wokół duszków

21

Używam XNA do programowania gry i eksperymentowałem z różnymi sposobami osiągnięcia „wybranego” efektu na moich duszkach. Problem, jaki mam, polega na tym, że każda klikalna linia rysowana w pakiecie jest rysowana przy użyciu więcej niż jednego duszka (każdy obiekt może składać się z maksymalnie 6 duszków).

Byłbym wdzięczny, gdyby ktoś mógł mi doradzić, w jaki sposób mogę osiągnąć dodanie konturu do moich duszków X pikseli (więc szerokość konturu może być różną liczbą pełnych pikseli).

Z góry dziękuję,

  • Greg.
Greg
źródło

Odpowiedzi:

20

Zdecydowanie najłatwiejszym sposobem na zrobienie tego (prawdopodobnie prawdopodobnie najlepszym, chyba że jesteś naprawdę przywiązany do wydajności) jest posiadanie dwóch kopii twoich duszków.

  • Zwykła wersja
  • „Gruba”, bezbarwna wersja - w zasadzie biała wersja twojego duszka X-wiele pikseli „grubsza” niż oryginał.

Narysuj cały obiekt za pomocą „grubej” wersji, a następnie narysuj zwykłą wersję na górze.

Zmieniając białą wersję „grubą”, można użyć wbudowanego przyciemniania kolorów SpriteBatch, aby dynamicznie zmieniać wybrany kolor.

Aby wygenerować „grubą” wersję, zalecam napisanie rozszerzenia potoku treści, który może automatycznie pobierać oryginalne duszki, czytać ich kanał alfa, tworzyć nowy kanał alfa, próbkując maksymalny kanał alfa z oryginalnego obrazu X-wiele pikseli wokół każdego piksela, i ustawienie RGB = (1,1,1).

Musisz upewnić się, że wszystkie duszki mają wystarczającą przezroczystą ramkę, aby dodać kontur (możesz to sprawdzić w procesorze treści - a nawet zrobić miejsce, jeśli to konieczne).

Jeśli masz tylko kilka duszków, możesz po prostu użyć dobrego edytora obrazów (GIMP, Photoshop) i zrobić to ręcznie: kanał alfa do wyboru, rozwinąć wybór, wybór do alfa, wypełnić kanały koloru białego.

Andrew Russell
źródło
4

Myślę, że najpierw musisz narysować wszystkie elementy, z których każdy jest przedmiotem, do jednego duszka. Więc myślę, że będziesz musiał napisać moduł cieniujący, aby wykryć krawędzie duszka i narysować piksel, gdziekolwiek znajdzie krawędź. Spodziewam się, że muszą być już dostępne jakieś shadery, które możesz użyć albo przenieść.

Iain
źródło
11
Słyszałem, że ten rodzaj shadera jest zaskakująco irytujący (używaliśmy go w jednej z naszych gier 3D i ciągle napawaliśmy się nieestetycznymi krawędziami). Jedną rzeczą, którą warto rozważyć, jest zakodowanie konturu bezpośrednio w teksturze duszka za pomocą określonego koloru, takiego jak (0, 255, 255, 0), i po prostu niech shader przekształci ten kolor po wybraniu duszka. Shader to trywialna zmiana kolorów, a Ty masz wysoki poziom kontroli nad konturem i dowolnymi szczegółami.
4

W zależności od wymagań, skuteczne może być również utworzenie konturu na żądanie dla duszka. Zakładam, że twoje duszki mają przezroczystość i mają nieregularny kształt, a nie tylko prostokąty (choć to by działało dobrze, prostokąty konturu powinny być Trywialne).

when selected:
   outline = new sprite canvas of appropriate size
   for sprite in object:
      # use larger numbers for thicker outlines
      for x in (-1, 0, 1) and y in (-1, 0, 1):
         render sprite mask into canvas at x,y with desired color

Zauważ, że nie musisz tego robić przy każdym losowaniu (chociaż przypuszczam, że mógłbyś), ale po prostu utwórz nowy kontur duszka podczas przełączania duszków.

dash-tom-bang
źródło
Tak, to też chciałem zasugerować. Renderuj zamaskowanego duszka 1 piksel w lewo, prawo, górę i dół oryginalnego duszka pod istniejącym duchem. Wiele gier używało tej metody do zarysu renderowanego tekstu lub tylko z 2 z 4 pozycji, aby utworzyć cień.
Kaj
1

Najprostszym podejściem z użyciem brutalnej siły jest zbudowanie dwóch kopii każdego duszka, normalnego i wyróżnionego. Następnie po prostu zamień je, gdy zostanie podświetlone.

Jeśli masz wolną pamięć, nie musisz się komplikować. Dodatkowo artyści mają całkowitą kontrolę nad wyglądem, gdy są podświetleni, dzięki czemu możesz wykonać kontur lub cokolwiek innego, co chcesz.

wkerslake
źródło
Myślę, że część problemu polega na tym, że OP mówi, że każdy obiekt może być złożony z wielu duszków. Sądzę więc, że kontur musi być konturem połączonego obiektu, zamiast mieć osobny kontur wokół każdego duszka komponentu.
Chris Howe
1
Chris, nie musi to być kontur połączonego obiektu i będzie działał dobrze dla obiektu złożonego z wielu duszków. Po prostu zrób dokładnie to, co powiedział wkerslake, ale pamiętaj, aby narysować podświetlone duszki za wszystkimi normalnymi duchami dla tego obiektu. W ten sposób, bez względu na to, z ilu obiektów jest zrobiony obiekt, podświetlenie zużyje tylko nieco ponad dwa razy więcej czasu rysowania dla tego obiektu, co powinno być o wiele krótsze niż generowanie konturów podczas renderowania z połączonymi duszkami.
AttackingHobo
1

Co powiesz na każdą duszkę, masz też inną duszkę, która jest konturem duszka podstawowego. Podczas rysowania obrysowanego obiektu narysuj duszki bazowe, a następnie utwórz maskę połączonego renderowania, a następnie narysuj duszki konturowe z wyłączeniem maski.

szary
źródło
2
Dlaczego nie narysuj najpierw duszków konspektu i narysuj nad nimi zwykłe duszki?
Chris Howe
Jednym z powodów, aby tego nie robić (lub sugestii Chrisa) jest to, że wykorzystuje ona dwukrotnie więcej pamięci tekstur; innym powodem jest to, że przepływ pracy artysty jest gówniany, ponieważ musisz aktualizować dwa pliki za każdym razem, gdy zmieniasz duszka.
2
Cóż, idealnie, nie miałbyś dwóch rzeczywistych zasobów duszka. Jeśli używasz testów alfa dla swoich duszków, możesz umieścić kontur w ikonce i nadać jej wartość alfa nieco wyższą niż przezroczyste obszary. Następnie kontrolując wartość odniesienia testu alfa, możesz kontrolować, czy kontur jest widoczny, czy nie. Powiedziałem tylko, że jeśli masz 2 wersje ikonek (niezależnie od tego, czy są to 2 zasoby, czy 2 stany tego samego zasobu), najpierw narysuj wersję konspektu, a następnie wersję normalną. W ten sposób nie potrzebujesz żadnych fantazyjnych shaderów, masek ani niczego.
Chris Howe
1
Pomysł Chrisa ma swoje zalety; ponadto można uniknąć aktualizacji przez artystę 2 plików (lub nawet tego samego zasobu), jeśli utworzysz narzędzie do generowania alfa dla duszków konspektu, które działają jako część twojego potoku / treści. Pamięć tekstur może, ale nie musi stanowić problemu, ale osobne duszki konturu powinny być wysoce kompresowalne DXT; prawdopodobnie 1/6 rozmiaru oryginalnej tekstury w pamięci wideo i bez utraty wierności.
jpaver
1

Kilka różnych rozwiązań z różnymi kompromisami.

Najłatwiej: Renderuj obiekt kilkakrotnie za pomocą płaskiego koloru i zniekształć pozycję (przesunięcie w lewo, w górę, w dół, w prawo itp.), Utworzy to konturową wersję tego, co na nim renderujesz, ale ma koszty wydajności i nie będzie pozwalają na tłuste obramowania bez wielu dodatkowych renderów. Obramowanie z jednym lub dwoma pikselami może być poprawne z 4x.

Najszybszy: Przetwarzaj teksturę i przygotuj kopię, która jest już obramowana lub jest tylko obramowaniem lub jest płaską 8-bitową maską w skali szarości, którą można pokolorować w module cieniującym. Będzie to prawdopodobnie szybkie kosztem pamięci.

Najlepsze: Moim zdaniem, ale najlepszym rozwiązaniem byłoby wygenerowanie reprezentacji pola podpisanego odległości (SDF) dla Twojego obiektu. Te tekstury mogą być znacznie mniejsze niż tekstura źródłowa i nadal przechwytywać przydatne dane. Zasadniczo każdy piksel koduje odległość od obiektu użytego do jego wygenerowania. Mając te dane w ręku, możesz pisać wszelkiego rodzaju efekty, od świecących do konturów. Obramowanie może zmienić rozmiar i kolor itp., I wciąż jest stosunkowo tanim shaderem i tylko jednym dodatkowym rysowaniem. Minusem jest oprzyrządowanie i przetwarzanie wstępne.

Aku
źródło
0

Nie jestem pewien skuteczności, ale najłatwiej widzę narysować większą wersję duszka w kolorze, który chcesz wybrać jako pierwszy. Narysuj na tym duszka. Zobaczysz tylko krawędź pierwszego duszka, dając efekt selekcji.

EDYCJA: Jednak, jak widać z komentarzy, nie jest to dobry pomysł.

Kaczka komunistyczna
źródło
1
Samo powiększenie duszka nie daje prawdziwego zarysu
Iain
2
Nie sądzę, by tak było, ale byłoby łatwo.
Kaczka komunistyczna
2
Wiele rzeczy jest łatwych, ale nie rozwiązują problemu. W przypadku duszków o dowolnej interesującej sylwetce powiększanie skali spowoduje absolutne śmieci.
Skalowanie będzie dobrze wyglądać tylko w przypadku kwadratowych lub okrągłych obiektów. Jeśli kształt jest naprawdę szeroki lub wysoki lub ma luki, będzie wyglądał naprawdę źle.
AttackingHobo
3
Zwiększanie skali da lepsze wyniki niż nic nie robienie i byłoby również przydatnym krokiem na drodze do „doskonałości”. Chociaż wyniki graficzne nie będą idealne, gdyby było to narzędzie wewnętrzne, może być wystarczająco dobre.
dash-tom-bang
0

Zgadzam się z powiększaniem duszka. Zdecydowanie najłatwiejsza droga, którą można zastosować do wyboru DOWOLNEGO duszka bez konieczności tworzenia dodatkowych duszek specjalnie do tego celu.

  • tj. spriteOutline.Scale = spriteOriginal.Scale * 0.1f; spriteOutline.Color = nowy kolor (255, 0, 0, 255);

źródło
0

Zamień kolor oryginalnego duszka na kolor konturu (lub nawet przyciemnij go, jeśli chcesz). Renderuj tę płasko sprasowaną lub przyciemnioną ikonkę cztery razy z przesunięciem 1 piksela: w x, y = (- 1, -1), następnie (+ 1, -1), następnie (-1, + 1), a następnie (+1 , +1). Powtórz dla wszystkich duszków, które tworzą obiekt.

Następnie renderuj oryginalne duszki w odpowiedniej kolejności na górze w (0,0).

Ilya Bossov
źródło