Як покращити ефективність дозування


9

Я розвиваю спрайтову 2D гру для мобільних платформ (платформ) і використовую OpenGL (ну, власне, Irrlicht) для візуалізації графіки. Спочатку я здійснив спрайт-рендерінг простим способом: кожен ігровий об’єкт відображається як квадратик із власним графічним викликом GPU, тобто, якщо у мене було 200 ігрових об'єктів, я робив 200 дзвінків на кадр. Звичайно, це був поганий вибір, і моя гра була повністю пов'язана з процесором, тому що в кожному розіграші GPU притягується невелика кількість центральних процесорів. GPU залишався бездіяльним більшість часу.

Тепер я подумав, що міг би покращити продуктивність, збираючи предмети у великі партії та надаючи ці партії лише кількома дзвінками. Я реалізував пакетну групування (щоб кожен ігровий об'єкт, що ділився однією і тією ж текстурою, відображався в одній партії) і подумав, що моїх проблем немає ... лише для того, щоб дізнатися, що частота кадрів була меншою, ніж раніше.

Чому? Ну, у мене є 200 (і більше) ігрових об’єктів, і вони оновлюються 60 разів за секунду. Кожен кадр я повинен перерахувати нове положення (переклад та обертання) для вершин у процесорі (GPU на мобільних платформах не підтримує екземпляри, тому я не можу це зробити там), і роблю цей розрахунок 48000 в секунду (200 * 60 * 4, оскільки кожен спрайт має 4 вершини) просто здається занадто повільним.

Що я міг би зробити для покращення продуктивності? Всі ігрові об’єкти рухаються / обертаються (майже) кожен кадр, тому мені дійсно доведеться перерахувати вершинні позиції. Єдина оптимізація, яку я міг би придумати, - це оглядова таблиця поворотів, щоб мені не довелося їх обчислювати. Чи допоможуть точкові спрайти? Будь-які неприємні хаки? Ще щось?

Дякую.

Відповіді:


5

Ви використовували мій порт irrlicht для андроїда? Для 2-х спрайтів на Android та iphone я використовую ті самі хитрощі, що і ви: дозування. Я пробую багато рішень у OpenGL ES 1.x та 2.x:

  • сортуйте за z (паралакс) та за текстурою, зробіть перетворення на процесорі та зателефонуйте glDrawArrays або glDrawElements (найшвидший спосіб). Використовуйте одну велику текстуру, якщо можете.
  • той самий трюк з VBO, не швидше, тому що для кожного кадру ви оновлюєте всю інформацію. Це може бути корисно для спрайтів статики.
  • використовувати OpenGL ES 2.x і використовувати шейдер Vertex для обчислення позицій (повільніше)
  • використовуйте PointSprites (жодного рішення, якщо це не квадрат, а занадто багато прозорих пікселів вбивають фільтрат)
  • використовувати розширення gldrawtexoes ...
  • використовувати зворотний виклик для кожного спрайту (найповільніший метод)

Отже, як і ви, всі перетворення виконуються процесором для OGLES 1.x або OGLES 2.x. Якщо у вас є неонові інструкції, ви можете використовувати їх для прискорення обчислень.

Ps: на пристроях iphone або android я не обмежений процесором, але швидкість заповнення обмежена. Тому дуже важливо обмежити перевитрату.


Відмінно, це те, що я шукав. Мені не було відомо про ваш порт Irrlicht, але у мене вже є версія для Irrlicht, що працює на iOS. Ви кажете, що ви не обмежені процесором - скільки спрайтів ви малюєте? А які у вас кадри, скажімо, на 100 спрайтів на iPhone? Якщо у мене є 200 об'єктів, я закінчую 48000 обчислень в секунду. Ваша думка про фултрат хороша.
user4241

Статичні спрати (фон) знаходяться у VBO. Я використовую один VBO за паралакс. Інакше у мене від 100 до 200 спрайтів на Moblox. На всіх iphone, включаючи 3G, у мене більше 30 кадрів в секунду (наскільки я пам’ятаю). Але великі спрайти коштують дуже дорого (проблема заповнення) ....
Елліс

Я працюю над двигуном частинок, в якому я можу використовувати до 20 000 деталей з усіма обчисленнями позицій на процесорі, і у мене є 10 кадрів в секунду з екстремальними налаштуваннями (на 3GS та iPhone4). Отже, на 3GS або iPhone4 повинно бути доступно 1000 спрайтів з хорошим кадром.
Елліс

Дякую, дуже корисно! Як ви реалізуєте свій двигун з частинками? Я думаю, ти граєш з шейдерами?
user4241

Я використовую шейдери, тому що мені потрібен gl_PointSize для налаштування кожного розміру частинок. Я більше не працюю з OGLES 1.x, оскільки старі телефони не є моєю ціллю. Спочатку весь мій код був OGLES 1.x, потім OGLES 1.x та OGLES 2.x (поліпшення продуктивності), а тепер OGLES 2.x (покращення надання).
Елліс

1

Я б рекомендував мати VBO, при цьому кожна вершина містить положення / обертання кожного виведеного об'єкта та групування на основі текстури, як ви робите. Я не дуже знайомий з ogl ES, тому я не впевнений, яку версію glsl він підтримує, але ви, можливо, навіть зможете складати пакетну групу на основі набору текстур і зберігати, яку з 4-х текстур ви передаєте Ви б використовували всередині вершини. Точкові спрайти, безумовно, покращать вашу ефективність, оскільки це зменшить кількість даних, які ви надсилаєте, різко, і пакетне використання не повинно ніколи знижувати продуктивність, якщо ви робите це правильно. Крім того, ви можете трохи покращити продуктивність, обчисливши обертання на шейдері і лише передавши значення int / float в парами або всередині самої вершини. (парами були б швидшими,


Спасибі за вашу відповідь. Ваша пропозиція щодо обчислення обертання в шейдері є досконалою, але, на жаль, я використовую OpenGL ES 1, який не підтримує шейдери, тому я застряг із фіксованим конвеєром. Я спробую точкові спрайти, але я не можу їх використовувати у всіх випадках, тому що для їх розмірів є верхня межа. Я все ще трохи песимістичний щодо VBO, якщо я перераховую положення кожної вершини в кожному кадрі, як VBO допомагає?
user4241

це дозволяє вашим вершинним даним залишатися на gpu, що зменшує кількість даних, які вам доведеться пересилати в gpu кожен кадр. вам не потрібні шейдери, щоб скористатися цим тхо, вам взагалі не потрібно змінювати дані вершин, якщо у вас є базове положення (наприклад, походження) для кожного спрайту, ви можете просто змінити матрицю світу за допомогою це перетворення перед викликом нічиї. однак це може бути важко при дозуванні. використовуючи фіксовану функцію, можливо, було б вигідніше просто переключитися на VBO та покинути принаймні поки що випуск пакету, що, безумовно, дасть вам імпульс.
sringer

Я бачу вашу думку. Отже, ви вже не говорите про випробування, а просто використовуєте один дзвінок для малювання, щоб намалювати один ігровий об’єкт. Я обов'язково перевіряю, як VBO без дозування впливає на FPS в моїй грі, але все одно 200 дзвінків на кадр звучать занадто велико ... але я думаю, що мені доведеться з цим жити. Я прийму вашу відповідь, якщо жодна інша відповідь не з’явиться.
user4241

1

Ви згадуєте мобільні платформи, які не мають інстанцій. Але у вас все ще є вершинні шейдери, чи не так?

У такому випадку ви все ще можете зробити псевдоінстанціювання, що теж дуже швидко. Зробіть VBO (GL_STATIC_DRAW) з кутовими точками (щодо центральної точки спрайта, наприклад, -1 / -1, 1 / -1, 1/1, -1/1) та будь-якими потрібними текстурними координатами. .
Потім встановіть один із загальних атрибутів вершини для кожного виклику малювання до центральної точки спрайта та намалюйте два трикутники зв'язаним буфером. Всередині вершинного шейдера прочитайте загальний атрибут вершини та додайте координати вершини.

Це дозволить вам заощадити блокування при передачі даних для кожного спрайту і повинно бути набагато швидшим. Фактична кількість розіграшів дзвінків не настільки важлива, блокування / зупинка між ними є.


Це добре рішення для OpenGL ES 2.0. На жаль, я використовую ES 1, який взагалі не має шейдерів.
user4241

0

Проблема полягає в кількості даних, які ви надсилаєте в GPU кожен кадр. Просто створіть VBO для кожної партії та заповніть її один раз, а потім застосуйте відповідні матриці перетворення (через glMultMatrix або шейдер, якщо ви використовуєте ES 2.0), коли малюєте партії.


Я не розумію, як це допомагає, коли у мене є 200 окремих ігрових об’єктів з унікальними перетвореннями? Використання glMultMatrix застосує те саме перетворення до всіх об'єктів, що не є тим, що я хочу. Крім того, надсилання даних в GPU не є вузьким місцем; якщо я видаляю перетворення на стороні процесора, перфоманс дуже хороший.
user4241

Так, але VBO все ж може покращити продуктивність, якщо застосовувати його правильно. Як ви зараз рендеруєте свої 200 об’єктів? Використовуєте glBegin / glEnd?
TheBuzzSaw

1
Я використовую двигун Irrlicht 3D з користувацьким вузлом сцени, тому я не використовую OpenGL безпосередньо (але я вважаю, що в цьому випадку використовується простий glBegin / glEnd). Чи дійсно допоможе VBO, оскільки мені доведеться змінювати весь буфер кожен кадр? Крім того, це не вирішує принципову проблему щодо пов'язаності з процесором через обчислення вершинної трансформації. Але дякую за відповіді все одно!
user4241
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.