Зазвичай існує два методи боротьби з цим. У наш час їх називають прямою рендерінгом і відкладеною візуалізацією. Є два варіанти цих двох, про які я розповім нижче.
Передача вперед
Показуйте кожен предмет один раз на кожне світло, яке на нього впливає. Сюди входить навколишнє світло. Ви використовуєте режим добавки суміші ( glBlendFunc(GL_ONE, GL_ONE)
), тому внески кожного світла додаються один до одного. Оскільки внесок різних вогнів є сумарним, то фреймбуфер зрештою отримує цінність
Ви можете отримати HDR, надавши кадр з плаваючою комою. Потім ви приймаєте остаточний прохід над сценою, щоб зменшити значення освітлення HDR до видимого діапазону; це також буде місце, де ви реалізуєте цвітіння та інші пост-ефекти.
Поширене підвищення продуктивності для цієї техніки (якщо в сцені багато об'єктів) - це використання "попереднього проходу", де ви візуалізуєте всі об'єкти, нічого не малюючи до кольорового кадру (використовуйте glColorMask
для вимкнення написання кольорів). Це просто заповнює буфер глибини. Таким чином, якщо ви надаєте об'єкт, який знаходиться за іншим, GPU може швидко пропустити ці фрагменти. Він все ще повинен запустити вершинний шейдер, але він може пропустити типово більш дорогі обчислення шейдерних фрагментів.
Це простіше кодувати і простіше уявити. А на деяких апаратних засобах (переважно мобільних та вбудованих графічних процесорах) це може бути ефективніше, ніж альтернатива. Але на апаратному забезпеченні вищого класу альтернатива, як правило, виграє для сцен з великою кількістю світла.
Відкладена візуалізація
Відкладене відображення трохи складніше.
Рівняння освітлення, яке ви використовуєте для обчислення світла для точки на поверхні, використовує такі параметри поверхні:
- Поверхневе положення
- Поверхневі норми
- Поверхневий дифузний колір
- Колір окулярів поверхні
- Поверхнева дзеркальна блиск
- Можливо інші параметри поверхні (залежно від складності рівняння освітлення)
При передачі вперед ці параметри потрапляють до функції освітлення фрагмента шейдера або шляхом передачі безпосередньо з вершинного шейдера, витягування з текстур (зазвичай через координати текстури, переданої від вершинного шейдера), або генерованого з цілої тканини в шейдері фрагмента на основі інші параметри. Дифузний колір можна обчислити, поєднуючи кольори вершини з текстурою, комбінуючи кілька текстур, будь-що.
Під час відкладеного візуалізації ми робимо це все явно. У перший пропуск ми виводимо всі об'єкти. Але кольори ми не рендеруємо . Замість цього ми надаємо параметри поверхні . Отже, кожен піксель на екрані має набір параметрів поверхні. Це робиться за допомогою рендерингу на текстури, що перебувають на екрані. Одна текстура зберігала б дифузний колір як його RGB, а можливо, дзеркальна блиск як альфа. Інша текстура зберігала б окульозний колір. Третина зберігає нормальне. І так далі.
Зазвичай позиція не зберігається. Натомість він відновлюється у другому проході математикою, що занадто складно, щоб потрапити сюди. Досить сказати, що ми використовуємо буфер глибини та фрагмент екранного простору як вхід, щоб визначити положення місця-камери точки на поверхні.
Отже, тепер, коли ці текстури містять по суті всю поверхневу інформацію для кожного видимого пікселя в сцені, ми починаємо візуалізацію повноекранних квадроциклів. Кожне світло отримує повноекранний квадрокоптер. Ми відбираємо текстури параметрів поверхні (і відновлюємо положення), а потім просто використовуємо їх для обчислення внеску цього світла. Це додається (знову glBlendFunc(GL_ONE, GL_ONE)
) до зображення. Ми продовжуємо це робити, поки не закінчиться світло.
Знову HDR - це крок після процесу.
Найбільшим недоліком відкладеної візуалізації є антиалізинг. Для належної антиалії потрібно трохи більше роботи.
Найбільша перевага, якщо ваш графічний процесор має багато пропускної здатності пам'яті, - це продуктивність. Ми реалізуємо фактичну геометрію лише один раз (або 1 + 1 на світло, що має тіні, якщо ми робимо тіньове картографування). Ми ніколи не витрачаємо часу на приховані пікселі чи геометрію, які не видно після цього. Весь час проходження освітлення витрачається на речі, які фактично видно.
Якщо ваш графічний процесор не має великої пропускної здатності пам’яті, то світловий прохід дійсно може почати боліти. Перетягування від 3-5 текстур на піксель екрану не приємно.
Легкий попередній прохід
Це свого роду варіація відкладеної візуалізації, яка має цікаві компроміси.
Так само, як і при відкладеному візуалізації, ви надаєте параметри поверхні набір буферів. Однак у вас є скорочені поверхневі дані; Єдині поверхневі дані, які вам цікаві в цей час, - це значення глибини буфера (для відновлення положення), нормальне та блискуча блиск.
Потім для кожного світла ви обчислюєте лише результати освітлення. Ні множення з кольорами поверхні, нічого. Просто крапка (N, L) та окулярний термін, повністю без кольорів поверхні. Морські та дифузні терміни повинні зберігатися в окремих буферах. Моркові та дифузні умови для кожного світла підсумовуються у межах двох буферів.
Потім ви повторно рендеруєте геометрію, використовуючи загальні дзеркальні та дифузні освітлювальні обчислення, щоб зробити остаточну комбінацію з кольором поверхні, таким чином виробляючи загальний коефіцієнт відбиття.
Насамперед, це те, що ви повертаєтеся до багатосезонної обробки (принаймні, простіше, ніж із відкладеним). Ви робите менше візуалізації за об'єктом, ніж візуалізація вперед. Але головне над відкладеним, що це забезпечує - простіший час мати різні рівняння освітлення для різних поверхонь.
За допомогою відкладеного візуалізації ви зазвичай малюєте всю сцену одним і тим же шейдером на світло. Тому кожен об'єкт повинен використовувати однакові параметри матеріалу. За допомогою попереднього проходу світла ви можете надати кожному об'єкту різний шейдер, щоб він міг зробити останній крок освітлення самостійно.
Це не забезпечує стільки свободи, як справа прямого надання. Але це все-таки швидше, якщо у вас є запас смуги текстури.