КІЛЬКА СЛІВ ПРО ОПТИМІЗАЦІЇ ІГРОВИЙ ГРАФІКИ

ОБОЖНЮЮ ОПТИМІЗАЦІЯ з тієї простої причини, ЩО ПІД ЧАС ПРОФІЛІЗАЦІЇ КОДА ДОВОДИТЬСЯ СЕРЙОЗНО напружувати мізки І ШУКАТИ ЦІКАВІ РІШЕННЯ ЗНАЙОМИХ ЗАВДАНЬ. При програмуванні ІГОР Мені приносить велике ЗАДОВОЛЕННЯ НЕ СТВОРЕННЯ ІГРИ, А СТВОРЕННЯ ЕФЕКТІВ І ПРОЦЕС ОПТИМІЗАЦІЇ. САМЕ ТУТ ДОСЯГАЄТЬСЯ ІСТИННИЙ ОРГАЗМ:). МОЖЕ БУТИ, ТОМУ Я ЩЕ НЕ СТВОРИВ ЖОДНОЇ ІГРИ, ХОЧА З графіком товаришую вже ДАВНО? ПОГОВОРИМО ПРО ОПТИМІЗАЦІЇ ГРАФІЧНИХ ПРОГРАМ, У ТОМУ ЧИСЛІ ІГОР

Що будемо розглядати в цій статті? Нас цікавить графіка, а значить, будемо говорити про ті питання, які пов'язані з графікою і іграми. Оптимізувати відображення стандартного вікна з настройками ігри ми не будемо. Опускатися до такої вульгарності:), як асемблер, теж не будемо, тому що якщо опуститися туди, то можна буде писати цілу книгу. Тут краще за мене розповість Касперски або інші поважні специ по цій мові. Я знаю асемблер, але не в такій мірі, щоб займатися оптимізацією, хоча, навіть якщо просто переписати якусь функцію C + + на асемблері, то код може працювати швидше. «Може», але не обов'язково, тому не будемо чіпати цю тему.

компілятор

Не секрет, що левова частка ігор створюється на С + +, і найчастіше для компіляції використовується компілятор від Microsoft. Цей стандарт визнаний, і хто оптимізує програму для роботи в Windows краще, ніж сам виробник ОС? Проте чи потрібна ця оптимізація відносно Windows настільки сильно? З повною упевненістю кажу, що не потрібна! Чому? Про це читай буквально в наступному абзаці.

Завжди дивуюся тим паразитам, які розробляють програми (в тому числі ігри) з мінімальними вимогами в Pentium IV, причому компілюють за допомогою Visual C + + 6.0 без патчів і оновлень. Що тут дивного? Те, що Visual Studio 6.0 без патчів не знає про існування Pentium IV, він навіть MMX-команди за замовчуванням не використовує. Чому б не використати те, що є в мінімальних вимогах? Одні тільки команди MMX можуть підвищити продуктивність, а якщо включити і SIMD, то виграєш в продуктивності до 20%, не вносячи ні краплі змін в код.

Так чому ж не потрібна оптимізація під ОС Windows? Ігри використовують можливості ОС мінімально, тобто більше DirectX і процесора, а хто знає архітектуру процесорів краще, ніж сама Intel? За деякими тестів, одна зміна компілятора може підвищити продуктивність програми на 10-15%, особливо в програмах, інтенсивно розраховують графіком. Дійсно, такі показники бачиш не дуже часто, а може трапитися і уповільнення роботи, але 10% – цілком реальна цифра, причому абсолютно без будь-яких втручань в код. Головне – використовувати процесор по максимуму і задіяти всі можливості.

профілятор-турбулятор

Коли гра готова, запускаємо її і шукаємо саме слабке місце. Я завжди шукав його на-віч (в принципі, в ігровому движку не так вже складно визначити слабке місце), але нещодавно познайомився з програмою Intel VTune Performance Analyzer. Ця утиліта призначена для аналізу швидкості виконання програми. Налаштовуємо VTune, запускаємо програму і через якийсь час дивимося, які виміри зробив VTune. Головне, що нас цікавить, – яка функція працює довше за всіх. Оптимізацією саме такої функції потрібно займатися надалі.

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

Крім того, потрібно враховувати кількість викликів. Наприклад, одна функція може виконуватися достатньо швидко, але викликатися дуже часто. Проаналізуй: якщо виклик відбувається з одного або двох місць, то, може, краще ти зробиш її inline, тобто позбудешся від неї зовсім і зекономиш зайвий перехід, повернення, передачу параметрів і т.д. У цілому економія складе приблизно три і більше команд (залежно від кількості параметрів), але якщо помножити це значення на кількість викликів функції, то економія стає істотною. Наприклад, якщо за секунду сталося 1000 викликів функції, то позбавлення від неї дасть економію в 3000 команд в секунду – не так погано!

До речі, в іграх взагалі не повинно бути маленьких функцій, які виконують від одного до трьох простих дій. Саме вони найчастіше викликаються за сотні разів і з'їдають дорогоцінні такти.

секрети від Intel

Корпорація Intel піклується про розробників, в тому числі про розробників ігор. На intel.com є багато корисної інформації про різні методи оптимізації та ефективні способи щодо використання можливостей сучасних процесорів. Зараз можна знайти безліч документів з використання Hyper-Threading в іграх, а двоядерні процесори дійсно можуть підвищити продуктивність на порядок. Якщо для гри два ядра є мінімумом, то чому не скористатися ними для своїх потреб?

На сайті є інформація і російською мовою. Так, її набагато менше, ніж на англійській, але основні і останні документи перекладаються. Раджу заглянути на наступну сторінку: www.intel.com / cd / ids / developer / emea / rus / dc / games / index.htm.

Запам'ятати цю адресу важкувато, тому спалю їх усіх в «Вибраному».

ati та nvidia

Компанії ATI і NVidia є законодавцями моди на ринку домашніх відеоприскорювачів і так само, як Intel, піклуються про розробників. На їх сайтах можна знайти тонни інформації про розробку графічних ефектів, ігор і використанні максимальних можливостей останніх відеочіпів.

Чим сильніше ти навантажити відеочіп, тим швидше буде працювати програма. Чому? Найчастіше відеоприскорювачі виконують завдання швидше, ніж центральний процесор, тому що вони спеціально заточені для графічних обчислень, матриць, векторів і т.д. Деякі завдання можуть виконуватися паралельно з обчисленнями центральним процесором, що також підвищить продуктивність.

Якщо ти вирішив використовувати якусь інформацію з сайтів www.ati.com або www.nvidia.com, то виявляй обережність. Деякі функції можуть працювати на відеочіпі одного виробника, але викликати серйозні проблеми на чіпі іншого виробника. У цьому випадку можна втратити більшу частину потенційних користувачів, а якщо проект комерційний, то й покупців. Щоб вирішити проблему, спробуй створити дві складання виконуваних файлів: одна для чіпа ATI, друга – для чіпа NVidia. Здійснюється не так складно. Створюєш дві функції для різних SDK і підключаєш їх залежно від збірки, що виконується в даний момент. Так, ускладнюється налагодження, але прямий виклик функцій драйвера відеокарти краще.

якість – продуктивність

Оптимізація графіки – це досить цікавий процес, тому що тут, крім загальних принципів оптимізації програм, застосовується безліч інших прийомів. Наприклад, щоб оптимізувати розмір картинки, її стискають класичним архіватором. Розмір файлу зменшиться, але коефіцієнт стиснення залежить від самої картинки. Наприклад, фотографії з великою кількістю квітів стискуються дуже погано.

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

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

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

Припустимо, у нас є картинка розміром 100×100 пікселів. Якщо використовується глибина кольору в один байт, для зберігання зображення знадобиться 10 000 байт пам'яті. Така картинка може містити максимум 256 кольорів (що дуже мало), і тому бажано використовувати мінімум два байти, коли кількість квітів дорівнюватиме 65 535. Виходить достатньо для зберігання більш якісного зображення, але знадобиться 20 000 байт пам'яті, що в два рази більше, відповідно, і копіювання даних буде вимагати від процесора в два рази більше ресурсів.

Якщо ж вибрати глибину кольору в 24 біта, то тут вже знадобиться в три рази більше ресурсів, хоча кількість квітів буде обчислюватися 16777216. Ось і думай після такого, що вибрати: якість або швидкість. Наше завдання – вибрати оптимальний варіант, який дозволить отримати краще співвідношення швидкості і якості.

Розмір зображень також грає важливу роль. Якщо ми вибрали дозвіл екрану в 800×600 пікселів при 16-бітному кольорі, то для зберігання поверхні знадобиться 800 * 600 * 2 = 960 000 байт пам'яті. Майже 1 Мб! А якщо зображення буде 1024×768, то обсяг необхідної поверхні пам'яті складе 1572864 байт. Знову збільшення ресурсів в два рази, отже, ми отримуємо падіння продуктивності в час копіювання вмісту поверхонь.

Оптимізація графіки на початковому етапі – це боротьба якості і швидкості, вибір між ними. Сучасним стандартом стали ЖК-монітори з діагоналлю 15 дюймів. Щоб картинка на них виглядала прийнятно, необхідно використовувати дозвіл 800×600, а краще 1024×768.

Проте непогано було б передбачити можливість вибирати необхідний дозвіл. Наприклад, у мене широкоформатний ноутбук, і для нього ідеально дозвіл 1280×800, а дозволу 800×600 і 1024×768 виглядають розтягнуто, що дуже незручно. Ось чому в даному випадку можна запропонувати користувачеві самостійно вибирати необхідний дозвіл в залежності від наявних ресурсів.

Як глибини кольору найчастіше використовується 16 біт, тому що так ми добиваємося прийнятної якості при мінімумі витрат. Менше вже не можна, а більше в основному надлишково. Можна запропонувати користувачеві вибирати і глибину кольору, але тоді доведеться писати дуже універсальний код, який знизить продуктивність. Щоб не втрачати швидкість, краще все-таки прив'язатися до певної глибини екрану.

не дай собі засохнути

Двовимірна графіка може формуватися двома способами: математичних і спрайтові. У випадку з математичним способом поверхню заповнюється через прямий доступ за певним алгоритмом. Деякі з алгоритмів створення ефектів я розгляну в четвертому розділі. При використанні «математики» швидкість формування сцени, крім глибини кольору та дозволи, дуже сильно залежить від використовуваного алгоритму.

При спрайтові формуванні сцени додатковим чинником гальмування є кількість спрайтів, оскільки для виведення кожного з них необхідно виконати операцію Blt або BltFast (я маю на увазі функції DirectDraw). Чим більше звернень, тим більше втрата, тому що тут виявляється ефект циклу: доводиться багато разів викликати одну й ту ж функцію, під час виклику кілька разів параметри піднімаються в стеку (а у Blt їх чимало) і відбувається виклик віддаленої функції, а також купа зайвих перевірок з усіма витікаючими наслідками. Іноді функцію Blt навіть краще замінити копіюванням даних через прямий доступ до пам'яті і WinAPI-функцію memcpy.

Втрати даних при спрайтові виведення можуть бути і невиправданими. Припустимо, у нас в розпорядженні знаходиться екран розміром в 800×600 пікселів, як показано на рис. 3.1. Все, що закрашено чорним кольором, – це оборка, яка статична і не змінюється, а в білій області дані формуються динамічно, причому повністю. Це завдання вирішується ось так: перед формуванням кадру вивести на екран зображення 800×600 з воланом, потім сформувати середню частину. Стоп. Навіщо робити це, якщо оборка статична? Чи не краще один раз вивести оборку, а потім перефарбовувати тільки центральну частину, що змінюється? Звичайно ж, краще. Таким чином ми зекономимо цілу операцію Blt, якій доводиться копіювати великий обсяг інформації.

Якщо екран програми кожного разу формується повністю, то і не варто кожного разу перед формуванням сцени очищати його. Все одно кожен піксель буде зафарбований, і від нашої заливки нічого не залишиться. Інше справа, коли малюється рух зірок на чорному небі. Тут дійсно зручніше зафарбувати екран чорним, а потім поверх неба намалювати зірки. Але якщо на екрані присутнє поверхню землі (наприклад, з 600 пікселів у висоту: нижні 200 – це земля, а верхні 400 – чорне небо), то потрібно зафарбовувати тільки ту частину, де є небо. Немає сенсу очищати весь екран!

алгоритм

Найголовніше, що визначає швидкість роботи гри, – це алгоритм. Хороший алгоритм не вимагає додаткової оптимізації. Не можу запропонувати однозначне рішення, але деякі рекомендації щодо оптимізації є.

Ігрові сцени найчастіше характеризуються значним безліччю об'єктів. Давай згадаємо знамениту гру Command & Conquer (або, простіше, C & C). На полі бою одночасно може перебувати тисячі об'єктів. Одних тільки солдатиків можна наробити пару тисяч, плюс будівлі, дерева, мости і т.д. Тепер уявімо, що станеться, якщо цикл відображення сцени буде виглядати наступним чином:

for (int i=0; i<OBJECT_COUNT; i++)

{

if (об'єкт бачимо)

Показати об'єкт

}

Якщо значення OBJECT_COUNT одно 2 000, то для відображення сцени доведеться виконати 2 000 кроків циклу і на кожному з них зробити перевірку видимості, яка може складатися з чотирьох операцій if. Божевільні витрати! Не під силу навіть сучасного комп'ютера, якщо не оптимізувати код. Що ж можна зробити тут? Як скоротити кількість циклів?

Карта ігри C & C велика, і в певний момент часу видно не більше 10% її. Можна розбити карту на 10-20 квадратів і прив'язувати об'єкти саме до якогось квадрату на карті. У результаті цикл відображення буде таким:

for (int i=0; i<QUAD_COUNT; i++)

{

if (квадрат бачимо)

{

Запустити цикл перевірки видимості і

відображення об'єктів даного квадрата на карті.

}

}

Тепер будуть перевірятися не всі об'єкти, а тільки ті, які знаходяться на квадраті, видимому в даний момент. Єдине, що потрібно зробити додатково, – після переміщення об'єкта перевірити, вийшов Чи він за межі свого квадрата, і якщо вийшов, то приєднати об'єкт до нового квадрату, на площину якого потрапив об'єкт. Такі об'єкти, як дерева і будівлі, не переміщуються, тому для них проводити перевірку не потрібно.

сортування

Наступний спосіб прискорення відображення – сортування. Бажано відсортувати всі об'єкти за певною осі і відображати їх у цьому ж порядку. Зауважу, що якщо черговий об'єкт вийшов із зони видимості по відсортованої осі, то інші з ще більшою ймовірністю вийшли і подальша перевірка об'єктів безглузда – цикл можна переривати. Відповідно, ми знову економимо цикл, а саме цикли є найслабшим місцем, особливо в іграх, де дуже багато об'єктів.

У складі DirectX SDK є дуже хороший приклад малювання дерев на поверхні ландшафту (DXSDKSamplesC + + Direct3DBillboard). Дерев дуже багато, і щоб не перебирати їх все, під час відображення використовується сортування. Спробуй прибрати сортування і проводити перевірку всіх дерев при кожному формуванні сцени – продуктивність прикладу помітно впаде.

оптимізація 3d

При створенні фігури за допомогою Direct3D використовуй мінімально необхідні розміри. Наприклад, при створенні буфера індексів IDirect3DIndexBuffer9 кожен елемент масиву може бути 16 – або 32-бітовим. Якщо кількість індексів не перевищує 65 535, то слід використовувати 16-бітний масив. У даному випадку перехід на 32 біта буде невиправданим і принесе зайві витрати пам'яті, якої ніколи не буває багато.

У Direct3D ми формуємо сцену з допомогою вершин і трикутників. Чим їх більше, тим більше часу движок і відеокарта витрачають на формування сцени. І знову ми вибираємо між кількістю і якістю! Подивися на малюнок, де показана сфера, створена з 32-х сегментів. Сфера виходить гладкою, але кількість необхідних трикутників занадто велике.

Можна скоротити кількість сегментів до 16-ти, тобто зменшити його в два рази. У результаті скорочується кількість ресурсів, необхідних для відпрацювання фігури, але сфера виходить незграбною. Я думаю, таке стан справ влаштує далеко не багатьох.

Якщо ж нам потрібні згладжені поверхні, то доводиться вибирати між гладкістю і швидкістю. У більшості ігор розробники намагаються використовувати прямокутні поверхні – для створення чотирикутної площині достатньо всього лише двох трикутників.

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

З іншого боку, якщо створити сферу зі ста сегментів, то ми отримаємо явну надмірність, особливо якщо ця сфера в сцені буде знаходитися дуже далеко від глядача і виглядати дрібної. Користувач просто не зможе побачити дрібні деталі, які ти захочеш передати. Якщо у тебе є 3D-редактор, що дозволяє контролювати кількість сегментів (наприклад 3D Studio Max), то спробуй зараз створити сферу розміром на весь екран. Для нормального відображення та отримання гладкої поверхні необхідно не менше 30-ти сегментів. Якщо ж віддалити сферу як можна далі (щоб в діаметрі вона здавалася не більше десяти- монети), то буде досить і 12-ти сегментів.

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

Подивися на малюнок, де показані сфери різного розміру. Найбільша сфера створена з 32-х сегментів, а решта – з 12-ти. Зверни увагу на те, що найменша сфера виглядає цілком гладкої, хоча на сферах побільше добре видно незграбності. Використовувати безліч сегментів на маленьких об'єктах – зайва розтрата ресурсів.

Те ж стосується і текстур. Чим ближче об'єкт, тим краще видно кожна деталь на текстурі. На найбільшій сфері можна побачити, що текстура є, але на найдальшої сфері зазвичай не розгледиш нічого. Вона настільки мала, що здається пофарбованої в один колір. Тоді навіщо використовувати текстуру? Чи не краще просто пофарбувати сферу в потрібний колір? Користувач нічого не помітить, особливо якщо сфера буде знаходитися в русі.

Щоб підвищити швидкість роботи з текстурами, пропоную діяти наступним чином:

? ЗОВСІМ НЕ використовувати текстуру ДЛЯ САМИХ ДАЛЬНІХ (ВІД ГЛЯДАЧА) ОБ'ЄКТІВ, тільки фарбувати ЇХ КОЛЬОРОМ, МЕЖАХ ВІДПОВІДНИМ КОЛЬОРУ Текстур.

? У міру наближення ОБ'ЄКТА натягнутої на нього ТЕКСТУРА невеликого розміру, наприклад 16X16. ОСЬ МИ ЗАЗДАЛЕГІДЬ масштабуючи БІТОВ ФАЙЛ, полегшить життя відеокарти.

? ДЛЯ ВЕЛИКИХ ОБ'ЄКТІВ, що знаходяться поблизу, використовувати більш якісний Текстур.

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

разом

Я міг би ще довго розповідати про оптимізацію в іграх, але ця тема дуже широка і вимагає окремої книги, над чим я зараз і працюю. Прошу до мене на сайт www.vr-online.ru – вже до моменту виходу цього номера я постараюся викласти що-небудь нове по оптимізації і графіку.

Удачи! І не бійся експериментувати і обманювати користувача (вони це люблять)

ПРИ ВИКОРИСТАННІ DIRECTDRAW НІКОЛИ НЕ застосовувати функції GDI: ВОНИ гальмують програму. Користуйся лише Прямий доступ до ПОВЕРХНІ І ЗАВАНТАЖЕННЯМ ПОВЕРХОНЬ

Для заливки DIRECTDRAW ПОВЕРХНІ МОЖНА ВИКОРИСТОВУВАТИ ФУНКЦІЮ BLT, АЛЕ НАБАГАТО ШВИДШЕ БУДЕ ЧЕРЕЗ ПРЯМОЇ ДОСТУП залити ПОВЕРХНЮ ПЕВНИМ КОЛЬОРОМ ФУНКЦІЄЮ FILLMEMORY

ІНТЕРФЕЙС IDIRECTDRAWCLIPPER ДОСИТЬ ненажерливий. ТРОХИ старання – І ТИ ЗМОЖЕШ НАПИСАТИ ПЕРЕВІРКУ ВИХОДУ ЗА МЕЖІ ПОВЕРХНІ САМОСТІЙНО, ВІДПОВІДНО, МЕЖАХ ОПТІМІЗІРУЕШЬ ЦЕЙ КОД

Оптимальну глибину кольору ДЛЯ СУЧАСНОЇ ІГРИ – 16 БІТ. ЯКЩО ЗРОБИТИ 24, ТО ВИТРАТИ ОПЕРАТИВНОЇ і відеопам'яті Невиправдано ВИРОСТУТЬ, А РІЗНИЦЮ В ЯКОСТІ в динамічних сценах не помітив навіть ПИЛЬНЕ ГЛАЗ ОРЛА


Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*