Tworzę opartą na sprite grę 2D na platformy mobilne i używam OpenGL (właściwie Irrlicht) do renderowania grafiki. Najpierw zaimplementowałem renderowanie ikonek w prosty sposób: każdy obiekt gry jest renderowany jako quad z własnym wywołaniem losowania GPU, co oznacza, że gdybym miał 200 obiektów gry, wykonałem 200 wywołań losowania na ramkę. Oczywiście był to zły wybór, a moja gra była całkowicie związana z procesorem, ponieważ w każdym wywołaniu GPU występuje niewielki narzut procesora. GPU przez większość czasu pozostawała bezczynna.
Teraz pomyślałem, że mogę poprawić wydajność, gromadząc obiekty w duże partie i renderując te partie za pomocą zaledwie kilku wywołań losowania. Zaimplementowałem przetwarzanie wsadowe (aby każdy obiekt gry o tej samej teksturze był renderowany w tej samej partii) i pomyślałem, że moje problemy zniknęły ... tylko po to, aby dowiedzieć się, że moja częstotliwość klatek była jeszcze niższa niż wcześniej.
Dlaczego? Mam 200 (lub więcej) obiektów gry i są one aktualizowane 60 razy na sekundę. W każdej ramce muszę ponownie obliczyć nową pozycję (translację i obrót) dla wierzchołków w CPU (GPU na platformach mobilnych nie obsługuje instancji, więc nie mogę tego zrobić) i wykonując te obliczenia 48000 na sekundę (200 * 60 * 4 od czasu każdy duszek ma 4 wierzchołki) po prostu wydaje się być zbyt wolny.
Co mogę zrobić, aby poprawić wydajność? Wszystkie obiekty gry poruszają się / obracają (prawie) każdą klatkę, więc naprawdę muszę przeliczyć pozycje wierzchołków. Jedyną optymalizacją, o której mogłem pomyśleć, jest tabela przeglądowa dla obrotów, aby nie musiałem ich obliczać. Czy punktowe duszki by pomogły? Jakieś paskudne hacki? Coś jeszcze?
Dzięki.
źródło
Poleciłbym mieć VBO, z każdym wierzchołkiem zawierającym pozycję / obrót każdego renderowanego obiektu i grupowanie na podstawie tekstury, tak jak robisz. Nie jestem zbyt obeznany z ogl ES, więc nie jestem pewien, która wersja glsl obsługuje, ale możesz nawet być w stanie wsadować na podstawie zestawu tekstur i przechowywać, którą z 4 lub więcej tekstur przekazujesz w których będziesz używać wewnątrz wierzchołka. Punktowe duszki zdecydowanie poprawiłyby twoją wydajność, ponieważ drastycznie zmniejszyłyby ilość danych, które wysyłasz, a grupowanie nigdy nie powinno zmniejszać wydajności, jeśli robisz to poprawnie. Można również nieco poprawić wydajność, obliczając obrót na module cieniującym i przekazując tylko wartość int / float do parametrów lub do samego wierzchołka. (parametry byłyby szybsze,
źródło
Wspominasz platformy mobilne, które nie mają instancji. Ale nadal masz shadery wierzchołków, prawda?
W takim przypadku możesz nadal wykonywać pseudo instancje, co jest również bardzo szybkie. Zrób VBO (GL_STATIC_DRAW) z punktami narożnymi (względem punktu środkowego duszka, np. -1 / -1, 1 / -1, 1/1, -1/1) i dowolnymi potrzebnymi współrzędnymi tekstury, w nim .
Następnie ustaw jeden z ogólnych atrybutów wierzchołków dla każdego wywołania rysowania do punktu centralnego duszka i narysuj dwa trójkąty z ograniczeniem bufora. W module cieniującym wierzchołków przeczytaj ogólny atrybut wierzchołka i dodaj współrzędne wierzchołka.
Pozwoli to zaoszczędzić na blokowaniu transferu danych dla każdego duszka i powinno być znacznie szybsze. Rzeczywista liczba losowań nie jest tak bardzo ważna, blokowanie / przeciąganie pomiędzy nimi jest.
źródło
Problem tkwi w ilości danych wysyłanych do GPU w każdej ramce. Wystarczy utworzyć VBO dla każdej partii i wypełnić ją jeden raz, a następnie zastosować odpowiednie macierze transformacji (poprzez glMultMatrix lub moduł cieniujący, jeśli używasz ES 2.0) podczas rysowania partii.
źródło