Я думаю, что я понимаю основы полевого луча с маршевым движением. Вы моделируете свою сцену с помощью набора полей расстояния (таких как: http://iquilezles.org/www/articles/distfunctions/distfunctions.htm ), а затем для каждого пикселя, который вы отбрасываете луч, начинайте с начала луча. найдите расстояние до ближайшего объекта в этой точке и увеличивайте точку на ближайшее расстояние, пока вы не нажмете что-нибудь. Мне удалось сделать простой рендер, и на этом большинство описаний техники заканчиваются.
Это оставляет меня с некоторыми вопросами о том, как SDF Ray Marching может быть использован в реальном сценарии:
Вопрос 1: В реальной игре сцена, как правило, сложная и загружается в ЦП со многими динамическими объектами. Я понимаю базовую выборку окклюзии (например, октодерево), и при многоугольном рендеринге я бы создал список (на процессоре) элементов в представлении просмотра для визуализации.
Итак, представьте, что у меня очень сложная сцена с множеством персонажей и динамических объектов, движущихся по экрану, управляемая процессором. Как бы я передавал объекты, которые хочу рендерить, в GPU каждый кадр? В каждом примере сцена жестко запрограммирована в GLSL. Может кто-нибудь поделиться примером динамического потока уровня в шейдер?
Вопрос 2: Как объекты могут иметь несколько цветов? Функции расстояния только возвращают расстояние, но как реализации обычно передают цвет обратно? (Например, вы попали в красную сферу, а не в синий куб.) Если бы это была реализация ЦП, я мог бы вызвать глобальную функцию внутри функции расстояния, когда это удар, чтобы завершить маркер луча, и который также мог бы передать объект попадания текстура / цвет. Но как бы вы вернули цвет или текстуру элемента в GLSL?
Спасибо.
В настоящее время я разрабатываю игровой движок, который использует поля расстояний со знаком в качестве метода рендеринга для отображения плавной процедурной геометрии (генерируемой с помощью простых примитивов, подобных тем, которые есть в вашей ссылке на данный момент, с целью реализации фракталов Джулии и IFS в будущем). Так как мой движок сфокусирован на процедурном генерировании и должен определять фигуры таким образом, чтобы они были удобны для лучников, я думаю, что у меня есть подходящее место, чтобы ответить на этот вопрос: P.
Что касается потоковой передачи, простое решение состоит в том, чтобы использовать какой-либо типизированный буфер и выбрасывать его в графический процессор, когда вы хотите выполнить марширование лучей. Каждый элемент буфера является сложным типом (например, структура в C / C ++), и каждый тип содержит элементы, определяющие, какую функцию вы должны использовать для его представления, его положение, поворот, масштаб и т. Д., А также средний цвет. Затем процесс упрощается до:
Что касается цвета фигур, помните, что шейдеры позволяют вам определять сложные типы, а также примитивы;). Это позволяет вам бросить все в структуру в стиле C, а затем передать эти структуры обратно из вашей функции расстояния.
В моем движке каждая структура содержит расстояние, цвет и идентификатор, который связывает его с соответствующим определением фигуры во входном буфере. Каждый идентификатор выводится из окружающего контекста соответствующей функции расстояния (поскольку моя функция отображения проходит через входной буфер, чтобы найти ближайшую цифру к каждому лучу для каждого шага, я могу смело обрабатывать значение счетчика цикла при вызове каждого SDF в качестве идентификатора фигуры для этой функции), в то время как значения расстояния определяются с использованием произвольной базовой SDF (например,
point - figure.pos
для сферы), а цвета определяются либо по среднему цвету соответствующего элемента в буфере рисунка (следовательно, поэтому полезно хранить идентификатор фигуры рядом), либо по процедурному цвету, взвешенному по отношению к сохраненному среднему значению (одним примером может быть счетчик итераций для некоторой точки на Мандельбульбе, отображающий ваш «средний цвет» из цветового пространства FP в целочисленное цветовое пространство, а затем использующий сопоставленный цвет в качестве палитры, XOR (сопоставляя его с счетчиком итераций).Процедурные текстуры - другой подход, но я никогда не использовал их сам. iq провел довольно много исследований в этой области и опубликовал несколько интересных демонстраций по Shadertoy, так что это может быть одним из способов сбора дополнительной информации.
Независимо от того, является ли ваш цвет статичным для каждой фигуры, процедурно сгенерированным или волшебным образом отобранным из процедурной текстуры, основная логика одинакова: абстрактные фигуры в некоторый вид промежуточного сложного типа (например, в структуру) сохраняют как локальное расстояние, так и локальное цвет в экземпляре этого типа, затем передайте сложный тип как возвращаемое значение из вашей функции расстояния. В зависимости от вашей реализации, выходной цвет может затем напрямую переходить на экран или следовать точке столкновения в ваш код освещения.
Я не знаю, было ли вышеупомянутое достаточно ясным или нет, так что не беспокойтесь о том, что что-то не имеет смысла. Я не могу привести примеры кода GLSL / пиксельного затенения, так как я работаю с HLSL и вычисляю затенение, но я счастлив попробовать все, что я сначала не написал правильно :).
источник