воскресенье, 25 января 2015 г.

Vectorized Ray-Bounding Intersection

В прошлый раз я уже описывал идею векторизации в тесте пересечении луча и треугольника. В этот раз я решил пойти дальше и применить векторизацию в тесте луча и ограничивающих объёмов: сферы и прямоугольника. Дело в том, что в классических функциях, написанных с расчётом на выполнение на обычном CPU, есть скалярные операции, и это неэффективно ложится на HLSL. Так, например, для сферы необходимо 6 dxasm инструкций, а для прямоугольника - 13, чтобы найти бинарный ответ пересекает-да/нет. Вроде неплохо, но желательно сократить длину процедуры поиска пересечений до минимума.

Для примера возьмём сцену с BVH, где корень имеет несколько дочерних узлов-боксов. Или, например, модель юнита описана сферами вокруг головы, тела и конечностей, в которых в свою очередь подсферами или боксами описываются кластеры треугольников. В этом случае может быть быстрее искать пересечение с чётвёрками узлов за раз и избавиться от скалярных операций.

Я написал две тестовые HLSL функции для сферы и прямоугольника: ray_intersects_vectorized. Промерив кол-во dxasm инструкций на выхлопе, получаем 3 для сферы и ~6 для прямоугольника, или 12 и 25 для их чётвёрок.

 Рис. 1. Vectorized ray-sphere test

Рис. 2. Vectorized ray-box test

Недостатком оптимизации является то, что у нас в BVH или любой другой структуре не всегда под рукой может быть 4 ограничивающих объёма - их может быть 3, или 5, и тогда придётся "подбивать" структуры пустыми данными и тратить на них вычислительные ресурсы. Если же иерархическая структура настроена на поставку четвёрок объёмов за раз, то данный подход представляется оптимальным.

Если взглянуть на функцию пересечения с прямоугольником, можно отметить что выражения
(lo-o)*inv_dir 
(hi-o)*inv_dir

ложатся на dxadm как add+mul, при этом превратить их в mad не представляется возможным из-за порядка операторов. Однако, если мы делаем трассировку лучей в ортографической проекции или от направленного источника света (Солнца), мы можем переписать это в виде
lo*inv_dir-o*inv_dir
hi*inv_dir-o*inv_dir 

где (lo/dir, hi/dir) предвычисляются заранее. Это возможно сделать по той причине, что все лучи имеют одинаковое направление, и рассчитывать деления отдельно для каждого луча не имеет смысла. После этого связки add+mul могут быть заменены на mad (или FMA в новых архитектурах) и функция сократится ещё на шесть инструкций, всего до 19 или ~5 на один примитив.

Рис. 3. Пересечение луча с 4-мя прямоугольниками в ортографической проекции, приблизительно 19 dxasm инструкций. 

Комментариев нет:

Отправить комментарий