Mam niestandardową procedurę sprite (openGL 2.0), która wykorzystuje prosty arkusz sprite (moje tekstury są ułożone poziomo obok siebie).
Oto przykładowy arkusz testowy z 2 prostymi teksturami:
Teraz, gdy robię mój obiekt sprite openGL, określam całkowitą liczbę ramek w jego atlasie, a podczas rysowania określ, którą ramkę chcę narysować.
Następnie sprawdza, skąd pobrać teksturę:
Dzielenie wymaganego numeru klatki przez całkowitą liczbę klatek (aby uzyskać lewą współrzędną)
A następnie nurkowanie 1 o całkowitą liczbę klatek i dodawanie wyniku do obliczonej powyżej współrzędnej lewej ręki.
To wydaje się działać, ale czasami mam problemy. Powiedzmy na przykład, że chcę narysować X poniżej i otrzymam ...........
Słyszałem o umieszczeniu „wypełnienia” 1 piksela między każdą teksturą, ale czy ktoś mógłby dokładnie wyjaśnić, jak to działa? Mam na myśli, że jeśli to zrobię, z pewnością odrzuci obliczenia dotyczące uzyskania tekstury.
Jeśli po prostu dołączę wypełnienie do wybranej tekstury (więc duszek zostanie narysowany z pustą ramką), to na pewno spowoduje to problem z wykrywaniem kolizji? (tzn. duszki mogą wydawać się kolidować podczas używania obwiedni, gdy kolidują przezroczyste części).
Byłbym wdzięczny, gdyby ktoś mógł wyjaśnić.
źródło
GL_NEAREST
lubGL_LINEAR
do renderowania tekstury?Odpowiedzi:
Problem z użyciem atlasów tekstur i przeciekania sąsiadujących tekstur ma związek ze sposobem liniowego filtrowania tekstur.
W przypadku dowolnego punktu tekstury, który nie jest próbkowany dokładnie w środku teksla, próbkowanie liniowe spróbuje pobrać 4 sąsiadujące tekseli i obliczyć wartość w zadanym miejscu jako średnią ważoną (na podstawie odległości od punktu próbkowania) średnią wszystkich 4 próbki.
Oto ładna wizualizacja problemu:
Ponieważ nie możesz użyć czegoś takiego
GL_CLAMP_TO_EDGE
w atlasie tekstur, należy utworzyć tekstury graniczne wokół krawędzi każdej tekstury. Te tekstury graniczne zapobiegną zmianie sąsiednich próbek z zupełnie różnych tekstur w atlasie poprzez ważoną interpolację wyjaśnioną powyżej.Pamiętaj, że podczas korzystania z filtrowania anizotropowego może być konieczne zwiększenie szerokości ramki. Wynika to z faktu, że filtrowanie anizotropowe zwiększy wielkość sąsiedztwa próbki pod ekstremalnymi kątami.
Aby zilustrować, co mam na myśli, używając obramowania wokół krawędzi każdej tekstury, rozważ różne tryby zawijania dostępne w OpenGL. Zwróć szczególną uwagę na
CLAMP TO EDGE
.Mimo że istnieje tryb o nazwie „Clamp to Border”, tak naprawdę nie jesteśmy tym zainteresowani. Ten tryb pozwala zdefiniować pojedynczy kolor, który będzie używany jako ramka wokół tekstury dla dowolnych współrzędnych tekstury, które nie mieszczą się w znormalizowanym [0.0 -1.0] zakres.
Chcemy odtworzyć zachowanie
CLAMP_TO_EDGE
, w którym dowolna współrzędna tekstury poza odpowiednim zakresem dla (pod-) tekstury otrzymuje wartość ostatniego środka texel w kierunku, w którym była poza granicami. Ponieważ masz prawie całkowitą kontrolę nad współrzędne tekstury w systemie atlasu, jedynym scenariuszem, w którym (skuteczne) współrzędne tekstury mogą odnosić się do lokalizacji poza teksturą, jest średni ważony etap filtrowania tekstury.Wiemy to
GL_LINEAR
będą próbkować 4 najbliższych sąsiadów, jak pokazano na powyższym schemacie, więc potrzebujemy tylko granicy 1-texel. Jeśli korzystasz z filtrowania anizotropowego, możesz potrzebować szerszej ramki tekstowej, ponieważ zwiększa ona wielkość sąsiedztwa próbki w określonych warunkach.Oto przykład tekstury, która lepiej ilustruje ramkę, chociaż dla twoich celów możesz zwiększyć szerokość 1 teksela lub 2 tekseli.
(UWAGA: obramowanie, o którym mówię, nie jest czarne wokół wszystkich czterech krawędzi obrazu, ale obszar, w którym wzór szachownicy przestaje się regularnie powtarzać)
Jeśli się zastanawiasz, oto dlaczego ciągle wspominam o filtrowaniu anizotropowym. Zmienia kształt sąsiedztwa próbki na podstawie kąta i może powodować użycie więcej niż 4 tekstur do filtrowania:
http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg
Im większy stopień anizotropii użyjesz, tym większe prawdopodobieństwo, że będziesz mieć do czynienia z okolicami próbnymi zawierającymi więcej niż 4 teksle. Obramowanie 2 tekstów powinno być odpowiednie w większości sytuacji filtrowania anizotropowego.
Last but not least, oto jak zbudowany jest spakowany atlas tekstur, który replikuje
GL_CLAMP_TO_EDGE
zachowanie w obecnościGL_LINEAR
filtra tekstury:( Odejmij 1 od X i Y we czarnych współrzędnych, nie poprawiłem odczytu obrazu przed wysłaniem. )
Ze względu na przechowywanie granic, przechowywanie 4 256 x 256 tekstur w tym atlasie wymaga tekstury o wymiarach 516 x 516. Ramki są oznaczone kolorami w oparciu o sposób wypełnienia ich danymi tekstowymi podczas tworzenia atlasu:
Skutecznie w tym upakowanym przykładzie każda tekstura w atlasie wykorzystuje region atlasu o wymiarach 258 x 258, ale wygenerowane zostaną współrzędne tekstury odwzorowane na widoczny region 256 x 256. Tekstury graniczne są zawsze używane tylko wtedy, gdy filtrowanie tekstur odbywa się na krawędziach tekstur w atlasie, a sposób, w jaki zostały zaprojektowane, naśladuje
GL_CLAMP_TO_EDGE
zachowanie.Jeśli zastanawiasz się, możesz zaimplementować inne typy trybów zawijania, stosując podobne podejście -
GL_REPEAT
można je zrealizować, wymieniając tekstury lewej / prawej i górnej / dolnej granicy w atlasie tekstur oraz odrobinę sprytnej matematyki współrzędnych tekstury w moduł cieniujący. To jest trochę bardziej skomplikowane, więc na razie się nie martw. Ponieważ masz do czynienia tylko z arkuszami sprite, ogranicz się doGL_CLAMP_TO_EDGE
:)źródło