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, ...”.

But
źródło
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!
David Van Brink
źródło
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.

MaKo
źródło
2
„poprawianie kroku w celu wpłynięcia na liczbę wierzchołków narysowanych dla koła” Super fajnie!
David van brink