След появата на графичните карти Nvidia RTX с хардуерна поддръжка на рейтрейсинга, технологията за трасиране на лъчите отново стана популярна. През последните няколко месеца моят Twitter се напълни са безкраен поток от сравнения на графиката с включен и изключен RTX.

След като се нарадвах на голямото количество красиви изображения, ми се прииска самостоятелно да опитам да комбинирам класическия проактивен рендер (forward renderer) с технологията за трасиране на лъчите.

Страдайки от синдрома за невъзприемане на чуждите разработки, аз създадох собствен хибриден рендиращ енджин, базиран на WebGL1, Всеки може да опита демото с нивата на Wolfenstein 3D, в които наслагах сфери за по-добро показване възможностите на трасирането на лъчите.

Прототипът

Започнах този интересен проект със създаването на прототипа, опитвайки се да пресъздам глобално осветяване с трасиране на лъчите на Metro Exodus.

Прототипът използва проактивен рендер, който пресъздава цялата геометрия на сцената. Шейдърът, използван за растеризацията на геометрията не само пресмята прякото осветяване, но и генерира случайни лъчи от повърхността на вече рендираната геометрия, за да може да се покаже дифузията.

На показаното по-горе изображение се вижда, как всичките сфери са коректно осветени само от непрякото осветяване (лъчите светлина се отразяват от стената зад камерата). Самият източник на светлина е скрит зад кафявата стена в горната част на изображението.

Wolfenstein 3D

В прототипа се използва съвсем опростена схема. В нея е поставен само един източник на светлина и се рендират само няколко сфери и кубове. Благодарение на това, кодът за трасирането на лъчите в шейдъра е съвсем опростен. Цикълът за цялостна проверка на пресичанията, в които лъчът се тества за пресичането с всички кубове и сфери в сцената, е достатъчно бърз и програмата го изпълнява в реално време.

След създаването на този прототип реших да направя нещо по-сложно, да добавя повече геометрия в сцената и повече източници на светлина.

Проблемът със сложните сцени е в това, че така или иначе трябва да имам възможност за трасиране на лъчите в реално време. Обикновено за ускоряването на рейтрейсинга се използва структурата bounding volume hierarchy (BVH), но решението да използвам WebGL1 не дава подобна възможност. Във WebGL1 е невъзможно зареждането на 16-битови данни в текстурите и в шейдърите не могат да се използват двоични операции. Това усложнява предварителните изчисления и използването на BVH във WebGL1 шейдърите.

Това е и причината за да използвам в това демо ниво от Wolfenstein 3D. През 2013 година направих в Shadertoy един WebGL шейдър, който не само рендира подобни на Wolfenstein нива, но и може да се използва като бърза и несложна структура за ускорение и с нейното използване трасирането на лъчите ще се изчислява и изпълнява много бързо.

По-горе е показан скрийншот на това демо, може да се опита и режима в цял екран.

Кратко описание

В демото се използва хибриден енджин за рендиране. За рендирането на всички полигони в кадъра енджинът използва традиционна растеризация, а след това комбинира получения резултат със сенките, дифузията и отраженията, които се създават чрез трасиране на лъчите.

Сенки
Плюс дифузия
И плюс отражение

Проактивното рендиране

Картите на Wolfenstein изцяло се записват в двуизмерна мрежа с размер 64х64. Карата използвана в демото се базира на първото ниво на Wolfenstein 3D.

При стартирането се създава цялата геометрия, необходима за работата на проактивното рендиране. Изображенията на стените се генерират от данните в картата. Създават се и плоскостите на пода и тавана, подава се информацията за източниците на светлина, разположението на вратите и поставените на случайни места сфери.

Всички текстури, използвани за стените и вратите са компресирани в един общ каталог на текстурите, като това дава възможност всички стени да се изобразят само само с един цикъл на изрисуването.

Сенки и осветяване

Директното осветяване се пресмята в шейдъра, който се използва за проактивното рендиране. Всеки фрагмент може да бъде осветен от максимум четири източника на светлина. За да се разбере, кои точно светлинни източници могат да окажат влияние на конкретен елемент в шейдъра, при стартирането на демото, текстурите се изчисляват предварително. Текстурата на стените е с размер 64 на 128 и кодирана в позициите на 4-те най-близки източници на светлина за всяка една позиция от мрежата на картата.

 

varying vec3 vWorldPos; varying vec3 vNormal;void main(void) {vec3 ro = vWorldPos;vec3 normal = normalize(vNormal);vec3 light = vec3(0);for (int i=0; i