Gry 2D i nowoczesny OpenGL


10

Z góry

Ok, więc zebrałem do tej pory:

  • nie używaj stałego potoku (przestarzałe lub będzie przestarzałe)
  • vbos przechowują „modele obiektowe” (głównie n danych danych wierzchołków)
  • vaos opisują, jak układane są dane, aby rysowanie wywołań wiedziało, jaka część każdego vbo jest dla jakiego rodzaju informacji o wierzchołku (jedno vao może odnosić się do wielu vbos, przeciwnie jest trochę trudne)
  • każde wywołanie losowania wysyła również dane wierzchołków do shaderów

Jak widzę 3D (opcjonalnie)

Biorąc pod uwagę te informacje, widzę, jak rysowanie skomplikowanych obiektów 3D jest bardzo przyjemne w nowoczesnym OpenGL. Zasadniczo ładujesz kilka modeli obiektów (prawdopodobnie z Blendera lub innego podobnego oprogramowania) do VBO z lokalnymi współrzędnymi, a następnie po prostu podajesz dla każdego wystąpienia obiektu inny parametr shadera (przesunięcie), aby rysować w przestrzeni świata.

Problem / pytanie

W 2D problemy i priorytety są jednak zupełnie inne. Nie rysujesz zbyt skomplikowanych obiektów, nie potrzebujesz skomplikowanych matryc projekcyjnych, a whatnot i shadery są znacznie prostsze.

Jaki byłby najlepszy sposób rysowania często (naprawdę często, zasadniczo każdej ramki) zmieniającej się geometrii za pomocą nowoczesnego OpenGL?

W następnym akapicie możesz zobaczyć kilka pomysłów na problemy (problem z okręgiem i prostokątem), które lepiej identyfikują zmiany, którymi jestem zainteresowany.

Moje próby (opcjonalnie)

Zacząłem więc zastanawiać się, jak poradzić sobie z rysowaniem podstawowej geometrii 2D na ekranie:

  • kwadrat: załaduj [(1, 0), (1, 1), (0, 1), (0, 0)]VBO dla geometrii kwadratu w przestrzeni lokalnej, a następnie podaj modułowi cieniującemu rzeczywistą szerokość kwadratu oraz współrzędne świata i informacje o kolorze

chłodzi, wygląda łatwo. Przejdźmy do kręgu:

  • koło: wachlarz trójkąta z ... eh. ile precyzji (liczba wierzchołków)? dla małych kół precyzja musi być mała, a dla błędnych kół precyzja musi być wysoka. Wyraźne załadowanie 1 VBO prawdopodobnie nie pasuje do wszystkich przypadków. Co się stanie, jeśli będę musiał dodać precyzję, ponieważ rozmiar okręgu jest większy?

Mniej fajne. Przejdźmy do czegoś nieco prostszego, prostokąta:

  • prostokąt: eh. nie ma „ogólnej geometrii prostokąta”. Po prostu masz proporcje szerokość / wysokość i to wszystko, ale każdy prostokąt jest prawdopodobnie inny, jeśli zmienia się rozmiar.

Jak widać, stamtąd wszystko idzie w dół. Zwłaszcza ze złożonymi wielokątami i tak dalej.

Brak zasad kodu: P

Potrzebuję tylko przeglądu tego pomysłu, nie jest potrzebny żaden kod, zwłaszcza kod C lub C ++. Po prostu powiedz coś takiego: „utwórz VBO z tymi danymi wierzchołków, a następnie powiąż go, ...”.


Myślę, że rozumiem, o co pytasz, ale możesz nadać temu pytaniu nieco więcej kierunku. Nie jest jasne, o co się pyta - co jest właściwie bliskim powodem.
— Lysol,

@AidanMueller Nie jestem pewien, co masz na myśli, ale w razie potrzeby możesz podać więcej wskazówek.
— But

Najważniejsza odpowiedź zaczyna się od stwierdzenia „Wydaje się, że głównym pytaniem jest”. Oznacza to, że nie jest jasne, o co pytasz. Może na końcu pytania powinieneś podsumować to, czego nie potrzebujesz. W końcu to pytanie / odpowiedź, a nie dyskusja.
— Lysol,

@AidanMueller Nie w tym kontekście, jak sądzę. Mówi: „Twoim głównym pytaniem wydaje się być ...”, a następnie cytuje pytanie, które opublikowałem. Co faktycznie oznacza, że ​​jest wystarczająco jasny, aby go zacytować. Również to zdanie nie wskazuje na to, że moje pytanie jest niejasne, ale że istnieje pytanie główne i inne pytanie wtórne (które brzmi: jakie jest rozwiązanie konkretnych przypadków, które przedstawiłem). Naprawdę nie widzę problemu z moim obecnym pytaniem i najwyraźniej nawet nie odpowiedzieli na to pytanie, ponieważ obie odpowiedzi były bardzo przydatne i do rzeczy.
— But

Możesz narysować dokładny okrąg za pomocą shadera fragmentów.
— user253751,

Odpowiedzi:


5

Twoim głównym pytaniem wydaje się:

Jaki byłby najlepszy sposób rysowania często (naprawdę często, zasadniczo każdej ramki) zmieniającej się geometrii za pomocą nowoczesnego OpenGL?

W większości przypadków nie ma dużej różnicy między 2d a 3d OpenGL. Rurociąg graficzny ma jedną dodatkową współrzędną Z, która nie będzie używana tak często w 2D, ale o to chodzi.

Istnieje kilka sposobów zmiany geometrii przy każdym losowaniu.

  • Możesz przesuwać nowe wierzchołki dostarczone przez CPU w każdej ramce. (Zobacz /programming/14155615/opengl-updating-vertex-buffer-with-glbufferdata, aby uzyskać uwagi na temat ponownego użycia buforów.)

  • Możesz narysować różne części istniejącego bufora za pomocą glDrawArrays(mode, first, count). Jeśli animacja zapętla się, być może możesz umieścić wstępnie obliczone klatki z różnymi listami wierzchołków w jednym dużym buforze i narysować odpowiednią część bufora dla każdej klatki.

  • Możesz wpływać na listę wierzchołków za pomocą innych danych, takich jak jednolita tablica lub tekstura. W shaderze wierzchołków przeczytaj te dane i zastosuj je odpowiednio. To tylko inne idiomy do prezentacji danych na GPU i prawdopodobnie nie będą miały dużej różnicy w wydajności.

  • Jeśli masz wiele wystąpień o tej samej geometrii (prawdopodobnie pod wpływem atrybutów), glDrawElementsInstanced()może to być przydatne

  • Możesz algorytmicznie wpływać na listę wierzchołków w modułach cieniujących wierzchołki, geometrię lub teselację. Jeśli animację można opisać matematycznie, być może uda Ci się zachować tę samą listę wierzchołków i zmienić tylko kilka mundurów modułu cieniującego w każdej klatce.

Być może twoja animacja może być wyrażona jako czyste tekstury, a wszystkie animacje są wykonywane piksel po pikselu przez procesor lub wstępnie renderowane z dysku.

Ogólnie rzecz biorąc, powiedziałbym: „Komputery są szybkie, spraw, aby działało to najłatwiej, jak to możliwe, prawdopodobnie poprzez ustawienie w każdej klatce świeżych wierzchołków wykonanych przez procesor. Następnie sprawdź, czy to wystarcza. Profil użycia baterii / procesora po pierwsze, ślad po pamięci ”.

Twoje drugie pytanie , sparafrazowane: „Jaki jest dobry sposób rysowania okręgów i prostokątów?”

Koła

  • Z shaderów teselacji (lub shaderów geometrycznych), które mogłyby dokonać geometria dynamiczna.

  • Możesz rysować kwadraty, a w module cieniującym fragmenty tylko nieprzezroczyste (alfa = 1,0) w promieniu i przezroczyste (alfa = 0,0) poza promieniem. Wtedy za każdym razem jest idealnie pikselowy. (Ustaw kwadratowe wierzchołki od -1 do +1, a w shaderze fragmentów coś w stylu:. outColor.a = dot(coord.xy, coord.xy) < 1.0 ? 1.0 : 0.0;Może również nieco wygładzić krawędź, wyglądałby tam ładnie ...)

  • Zawsze możesz użyć, powiedzmy, wentylatora 120-trójkątnego. Prawdopodobnie wystarczająco dobry.

Prostokąty

  • Myślę, że odpowiedziałeś na własne pytanie w tej sprawie. To, co sugerujesz, zadziała dobrze!

Dzięki cieniowaniu fragmentów / promieniu jest całkiem fajnie. Jeśli chodzi o mnie, odpowiadając na moje pytanie, nie sądzę, że rozumiem, co masz na myśli.
— But

Och, tak jak w przypadku kwadratu, wspominasz o kontrolowaniu szerokości (zakładam, że w mundurze) i napisałeś: „Po prostu masz proporcję szerokość / wysokość i to wszystko, ale każdy prostokąt jest prawdopodobnie inny, jeśli zmienia się rozmiar” . Tak więc, dla prostokąta, zrób to samo co kwadrat, ale będziesz potrzebować 4 wartości (x, y, w, h) zamiast 3 (x, y, w). Lub podaj (xlow, xhigh, ylow, yhigh) jako cztery mundury. Dzięki wejściom (0,0) do (1,1) wystarczy, aby Vertex Shader mógł zrobić to, czego potrzebuje.
— David van brink

Och, rozumiem, to ma sens.
— But

Czy w nowoczesnym GL jest automatyczny wentylator taki jak GL_TRIANGLE_FAN z potoku funkcji stałej?
— John P.

5

Nie mogę powiedzieć, że jestem ekspertem w tej dziedzinie, aw swoich projektach gry bardziej skoncentrowałem się na stronie 3D, więc moja strona 2D jest dość prosta, ogólnie rzecz biorąc, używając rzeczy stworzonych dla strony 3D; i oczywiście moja perspektywa jest po stronie gier, więc moja grafika 2D bardziej dotyczy blitowania duszków niż geometrii. Z tej perspektywy

1) Kwadraty i prostokąty są dość łatwe. Mam tylko jedno pudełko 1x1 w VBO, którego używam do blitowania wszystkiego. Przekazuję macierze MVP do modułu cieniującego za pomocą tego „pola jednostki” i połączyłem go z dodatkowym skalowaniem, aby przeskalować pole do odpowiednich wymiarów - jak wiesz, możesz mieć inną skalę xiy.

Dla moich celów zastanawiałem się nad przejściem z „skrzynki jednostkowej” na silnik cząsteczek, aby połączyć duszki 2D, ale to już inna historia.

2) Nie pracowałem dużo z okręgami, po prostu używam stałych VBO z określoną liczbą wierzchołków. Ale mogłem sobie wyobrazić, że mógłbym zrobić pewne postępy, aby wpłynąć na liczbę wierzchołków narysowanych dla koła.

Podczas łączenia danych VBO z atrybutami modułu cieniującego używam glVertexAttribPointer. Ma parametr kroku przeznaczony do przeplatania danych (których używam). Ale może być możliwe użycie go w następujący sposób:

glVertexAttribPointer(..., n * sizeof(VERTEX_DATA), ...);

... aby wybrać co n-ty wierzchołek z bufora, wpływając w ten sposób na liczbę wierzchołków narysowanych dla koła. Mógłbym stworzyć kilka VAO o tym samym VBO z różnym krokiem wpływającym na liczbę wierzchołków narysowanych dla okręgu. Nie próbowałem tego, pomyślałem.

Ogólnie rzecz biorąc, tak, praca z VBO i takie sprawiają, że podkręcanie po stronie procesora jest nieco bardziej skomplikowane, dlatego badałem różne rzeczy, aby ulepszyć po stronie GPU (shadery). Jednak zgodnie z tym artykułem korzystanie z VBO jest bardziej wydajne na nowoczesnym sprzęcie, nawet jeśli potrzebujesz dużo „interwencji” po stronie procesora:

http://www.quelsolaar.com/opengl_performance.txt

Mam nadzieję, że to pomoże ci trochę zaprojektować i zdecydować o twoich kierunkach.


2
„poprawianie kroku w celu wpłynięcia na liczbę wierzchołków narysowanych dla koła” Super fajnie!
— David van brink
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.