Чи є спосіб використовувати довільну кількість вогнів у фрагменті шейдера?


19

Чи є спосіб пропустити довільну кількість світлих розташувань (і кольорів) для фрагмента шейдера і провести петлю над ними в шейдері?

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


Я не працював з WebGL, але у OpenGL у вас є 8 джерел світла. На мою думку, якщо ви хочете пропустити більше, вам доведеться використовувати, наприклад, єдині змінні.
zacharmarz

Старий метод полягав у тому, щоб завжди пропускати всі світильники, невикористані світильники були встановлені на 0 яскравість, а тому не впливатимуть на сцену. Напевно, більше не використовується ;-)
Патрік Х'юз

7
Коли ви такі речі в Google, не використовуйте термін "WebGL" - ця технологія занадто молода, щоб люди мали можливість хоч би й підходити до цих проблем. Візьмемо для прикладу цей пошук : "Мені пощастило" працювало б. Пам'ятайте, що проблема WebGL повинна добре відповідати тій самій проблемі OpenGL.
Джонатан Дікінсон

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

Відповіді:


29

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

Передача вперед

Показуйте кожен предмет один раз на кожне світло, яке на нього впливає. Сюди входить навколишнє світло. Ви використовуєте режим добавки суміші ( glBlendFunc(GL_ONE, GL_ONE)), тому внески кожного світла додаються один до одного. Оскільки внесок різних вогнів є сумарним, то фреймбуфер зрештою отримує цінність

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

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

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

Відкладена візуалізація

Відкладене відображення трохи складніше.

Рівняння освітлення, яке ви використовуєте для обчислення світла для точки на поверхні, використовує такі параметри поверхні:

  • Поверхневе положення
  • Поверхневі норми
  • Поверхневий дифузний колір
  • Колір окулярів поверхні
  • Поверхнева дзеркальна блиск
  • Можливо інші параметри поверхні (залежно від складності рівняння освітлення)

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

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

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

Отже, тепер, коли ці текстури містять по суті всю поверхневу інформацію для кожного видимого пікселя в сцені, ми починаємо візуалізацію повноекранних квадроциклів. Кожне світло отримує повноекранний квадрокоптер. Ми відбираємо текстури параметрів поверхні (і відновлюємо положення), а потім просто використовуємо їх для обчислення внеску цього світла. Це додається (знову glBlendFunc(GL_ONE, GL_ONE)) до зображення. Ми продовжуємо це робити, поки не закінчиться світло.

Знову HDR - це крок після процесу.

Найбільшим недоліком відкладеної візуалізації є антиалізинг. Для належної антиалії потрібно трохи більше роботи.

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

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

Легкий попередній прохід

Це свого роду варіація відкладеної візуалізації, яка має цікаві компроміси.

Так само, як і при відкладеному візуалізації, ви надаєте параметри поверхні набір буферів. Однак у вас є скорочені поверхневі дані; Єдині поверхневі дані, які вам цікаві в цей час, - це значення глибини буфера (для відновлення положення), нормальне та блискуча блиск.

Потім для кожного світла ви обчислюєте лише результати освітлення. Ні множення з кольорами поверхні, нічого. Просто крапка (N, L) та окулярний термін, повністю без кольорів поверхні. Морські та дифузні терміни повинні зберігатися в окремих буферах. Моркові та дифузні умови для кожного світла підсумовуються у межах двох буферів.

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

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

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

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


-1: невизначення LPP / PPL. -1 відкладено: візуалізація - це миттєвий виграш на будь-якому апаратному забезпеченні DX9.0 (так, навіть на моєму бізнес-ноутбуку) - що є базовими вимогами приблизно в 2009 році. Якщо ви не орієнтуєтесь на DX8.0 (що не може зробити Deferred / LPP) За замовчуванням відкладено / LPP . Нарешті, «велика пропускна здатність пам’яті» є божевільною - ми, як правило, ще навіть не насичуємо PCI-X x4. Крім того, LPP значно зменшує пропускну здатність пам’яті. Нарешті, -1 для вашого коментаря; петлі, як це ОК? Ви знаєте, що ці петлі відбуваються 2073600 разів за кадр, правда? Навіть при паррелізмі відеокарти це погано.
Джонатан Дікінсон

1
@JonathanDickinson Я думаю, що його суть полягала в тому, що пропускна здатність пам’яті для відкладеного / легкого попереднього проходу, як правило, в кілька разів більше, ніж для прямого візуалізації. Це не скасовує відкладений підхід; це просто щось врахувати при виборі. BTW: ваші відкладені буфери повинні знаходитись у відеопам'яті, тому пропускна здатність PCI-X не має значення; важлива внутрішня пропускна здатність GPU. Довгі піксельні шейдери, наприклад, з розкрученим циклом, нічого не змушують, якщо вони роблять корисну роботу. І з трюком z-буфера немає нічого поганого; це чудово працює.
Натан Рід

3
@JonathanDickinson: Мова йде про WebGL, тому будь-яке обговорення "моделей шейдерів" не має значення. І який вид використання не є "релігійною темою": це просто питання того, яке обладнання ви працюєте. Вбудований графічний процесор, де "відеопам'ять" є просто звичайною оперативною пам'яттю, буде дуже погано працювати з відкладеною візуалізацією. На мобільному рендері на основі плитки це ще гірше . Відкладене надання не є "миттєвою виграшю" незалежно від обладнання; вона має свої компроміси, як і будь-яке обладнання.
Нікол Болас

2
@JonathanDickinson: "Також за допомогою трюку попереднього проходження z-буфера ви збираєтеся боротися за усунення z-бойових дій з об'єктами, які слід намалювати". Це тотальна нісенітниця. Ви надаєте ті самі об'єкти з однаковими матрицями перетворення та тим же вершинним шейдером. Мультипас-рендерінг був зроблений у Voodoo 1 день; це вирішена проблема. Накопичувальне освітлення нічого не змінює.
Нікол Болас

8
@JonathanDickinson: Але ми не говоримо про надання каркасної форми, чи не так? Ми говоримо про надання тих же трикутників, як і раніше. OpenGL гарантує інваріантність того ж об’єкта, що виноситься (якщо ви, звичайно, використовуєте той самий вершинний шейдер, і навіть тоді, є invariantключове слово, яке гарантує його в інших випадках).
Нікол Болас

4

Потрібно використовувати відкладене відтворення або попереднє просвітлення . Деякі старі трубопроводи з фіксованою функцією (читай: немає шейдерів) підтримують до 16 або 24 вогнів - але це все . Відкладене відображення виключає межу світла; але ціною значно складнішої системи візуалізації.

Мабуть, WebGL підтримує MRT, який абсолютно необхідний для будь-якої форми відкладеної візуалізації - так це може бути здійснено; Я просто не впевнений, наскільки це правдоподібно.

Крім того, ви можете дослідити Unity 5 - який відклав візуалізацію прямо з поля.

Ще один простий спосіб вирішити це - просто розставити пріоритети вогням (можливо, виходячи з відстані від гравця та того, чи є вони в камері) і лише включити топ-8. Дуже багато назв AAA вдалося зробити це без особливого впливу про якість виходу (наприклад, Far Cry 1).

Ви також можете розглянути попередньо розраховані світлові карти . Такі ігри, як Quake 1, отримали багато пробігу від них - і вони можуть бути зовсім невеликими (білінеарна фільтрація досить добре пом'якшує розтягнуті світлодіоди). На жаль, попередньо розрахований виключає поняття 100% динамічного світла, але воно справді виглядає чудово . Ви можете поєднати це з обмеженням у 8 вогнів, так, наприклад, справжнє світло матиметь лише ракети або такі - але вогники на стіні чи такі були б світлові карти.

Бічна примітка: Ви не хочете перебирати їх у шейдері? Попрощайтеся зі своєю виставою. Графічний процесор не є процесором і не призначений для роботи так само, як, наприклад, JavaScript. Пам’ятайте, що кожен піксель, який ви рендеруєте (якщо навіть він перезаписаний), повинен виконувати цикл - тому якщо ви працюєте в 1920x1080 та простий цикл, який працює в 16 разів, ви ефективно запускаєте все, що знаходиться в цьому циклі 33177600 разів. You відеокарти буде працювати багато цих фрагменти паралельно, але ці петлі будуть по- , як і раніше є старе обладнання.


-1: "Вам потрібно використовувати відкладене відображення" Це зовсім не так. Відкладене відображення, безумовно, це спосіб зробити це, але це не єдиний спосіб. Також петлі не є такими поганими щодо продуктивності, особливо якщо вони засновані на однакових значеннях (тобто: кожен фрагмент не має різної довжини циклу).
Нікол Болас

1
Прочитайте, будь ласка, 4-й абзац.
Джонатан Дікінсон

2

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

Це основна ідея. Звичайно, існує багато оптимізацій, необхідних для того, щоб зробити це досить швидко для розумного розміру сцени. Не малюйте всіх вогнів, а лише видимі (фрустум та оклюзія); насправді не малюйте всю сцену кожного проходу, а лише об'єкти, що знаходяться в межах діапазону вогнів; є кілька версій шейдера, які підтримують різну кількість вогнів (1, 2, 3, ...), так що ви не витрачаєте час на оцінку більшої кількості вогнів, ніж потрібно.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.