Фрактальный шум SDF

Фрактальныйшумsdf

Введение


По мере того, как функции подписанного расстояния начинают использоваться в основных и коммерческих приложениях, важно найти замену или альтернативы обычным вещам, которые художники делали в стране полигонов. Одна из таких вещей – смещение как средство улучшения или добавления деталей к форме. Хотя многое из того, что я здесь скажу, применимо к любому типу паттерна смещения или «детального отображения» на основе SDF, я сосредоточусь на чистом стиле fBM смещение в этой статье, которое мы используем, например, для создания процедурных ландшафтов (вы также можете знать его как «Фрактальный шум»). И причина для поиска альтернативы в том, что традиционный способ построения и применения fBM (и смещения / детализации) плохо работает с SDF. Но я нашел альтернативу, которая, на мой взгляд, конкурентоспособна. Так что продолжайте читать!



Деталь fBM SDF ( не как обычное смещение fBM)

Проблема


По сути, проблема заключается в следующем: (обычное, арифметическое) сложение двух SDF не SDF. Кроме того, добавление SDF и некоторых других полей / функций (SDF или нет) также не является SDF (за исключением очень тщательно продуманных функций). Таким образом, при добавлении обычного fBM или синусоидальной волны или любой другой функции смещения к “хосту” SDF мы больше не получаем действительный SDF.

Это, конечно, не мешает нам продолжать попытки, и мы часто добавляем произвольные функции в наши SDF в надежде изменить их форму. Иногда это срабатывает, пока не сломается. Например, при рендеринге SDF через raymarcher добавление синусоидальной волны к сфере может работать для небольших амплитуд и частот, если raymarcher спроектирован так, чтобы допускать небольшие отклонения от истинных SDF. Однако он рано или поздно сломается, когда мы сделаем синусоидальную волну больше или ее длину короче (техническая причина в том, что градиент результирующего поля будет намного больше и меньше 1,0).

Но сказал, поскольку метод действительно работает в некоторой степени для небольших смещений, он все еще используется для вещей, которые традиционно решались с помощью смещения в полигональной земле, таких как фрактальные ландшафты, которые я упоминал в вступление; даже если они плохо работают или заставляют их работать, это имеет большие потери в производительности для рендерера.

Это прискорбно, потому что сигналы fBM очень популярны, ну понятны, широко применяются во всех видах программного обеспечения для моделирования, текстурирования и рисования и широко используются художниками. Очень жаль, что мы не можем просто использовать их с SDF надежным образом.

Или можем?

Решение


Ну, мы знаем сложение функций не работает с SDF, поэтому давайте попробуем обойти это, переопределив добавление, посмотрим, сможем ли мы перепрофилировать и сохранить fBM.

Самый важный аспект сложения в fBM или фрактальном процессе не является арифметическим аспектом или вычислением как таковым. Важно то, что волны разной амплитуды и длины волны аддитивно комбинируются вместе, то есть они располагаются друг над другом. Это соответствует тому, как формы в природе тоже организуются (отсюда успех fBM в процедурном моделировании и текстурировании). Итак, что нам нужно, так это определить новое “дополнение” SDF, которое позволит нам комбинировать формы вместе и наращивать их друг на друга.

” объединить часть нашего требования легко, и мы можем сделать это с помощью простой операции объединения или плавного объединения. Вероятно, это будет min () или smoothmin () . Другими словами, поскольку мы генерируем SDF все более и более коротких амплитуд и длин волн, мы можем комбинировать их с формой «хоста» и друг с другом с помощью обычных операций объединения SDF.

Часть добавления «поверх друг друга» может быть достигнута, если эти слои SDF (называемые «октавами» традиционно в стандартных / ванильных реализациях fBM) существуют только в непосредственной близости от предыдущего слоя. (или объект-хозяин, к которому мы применяем смещение fBM). Таким образом, только поверхность нашего объекта будет увеличена с более высокой детализацией, и никакие новые поверхности не будут созданы где-либо еще.

Один простой способ выполнить это путем обрезки слоев SDF относительно слегка раздутой версии «основного» SDF, в идеале посредством плавного пересечения, чтобы сохранить гладкость окончательной формы. В зависимости от формы слоев SDF у нас все еще могут быть эстакады (отдельные части поверхности), так что это не пуленепробиваемый метод, но он хорошо работает на практике.

Реализация


Итак, давайте объединим все эти идеи. Сначала нам нужен случайный и гладкий SDF для использования в качестве базовой функции для нашей fBM. Поскольку традиционный 3D-шум () не является функцией расстояния (это поле / функция со знаком, но не измеряет расстояния), мы не можем его использовать. Вместо этого мы будем использовать бесконечную, но простую сетку сфер случайного размера. Сферы имеют простые SDF, изотропны и поэтому кажутся естественными кандидатами. Сделать из них бесконечную сетку также легко с помощью некоторого базового повторения доменов . Если мы ограничим радиус наших случайных сфер меньшим, чем половина длины ребра сетки, то для данной точки в пространстве нам нужно только оценить SDF 8 сфер в углах ячейки сетки, которой принадлежит точка. to.

Приведенный ниже код представляет собой возможную реализацию такой sdBase (), а справа – ее прямая визуализация:

float sph (ivec3 i, vec3 f, ivec3 c) {float rad = 0.5 hash (i + c); длина возврата (f-vec3 (c)) – рад; } float sdBase (vec3 p) {ivec3 i = ivec3 (floor (p)); vec3 f = фракт (p); return min (min (min (sph (i, f, ivec3 (0,0,0)), sph (i, f, ivec3 (0,0,1))), min (sph (i, f, ivec3 ( 0,1,0)), sph (i, f, ivec3 (0,1,1)))), min (min (sph (i, f, ivec3 (1,0,0)), sph (i, f, ivec3 (1,0,1))), min (sph (i, f, ivec3 (1,1,0)), sph (i, f, ivec3 (1,1,1))))); }



sdBase (), бесконечная сетка сфер со случайным радиусом

Как только у нас есть sdBase (), мы можем начать использовать его в нашей аддитивной фрактальной конструкции fBM с переопределенным «сложением», определенным выше:

float sdFbm (в vec3 p, в float d) {float s = 1.0; для (int i = 0; i <20 ; я ++) {float n = s sdBase (p); n = smax (n, d-0,1 с, 0,3 с); d = smin (n, d, 0,3 с); p = mat3 (0. 04 , 1. 60, 1. 20, -1. 60, 0. 72, - 0. 96, -1. 45, - 0. 450, 1. 28 )*п; с = 0,5 с; } return d; }



sdFBM (), добавляя 20 октавы sdBase () вместе

Здесь мы добавляем 11 слоев sdBase (), каждый из которых имеет двойную частоту (половину длины волны) предыдущего. Коэффициент масштабирования 2,0 скрыт внутри матрицы 3×3, которая преобразует p в каждом итерация (определитель – 2). Из-за удвоения частоты для каждого дополнительного слоя мы называем эти слои «октавами», как в музыке (где расстояние между двумя гаммами – это удвоение высоты тона). Переменная s отслеживает этот коэффициент масштабирования и применяет его к sdBase (), чтобы привести расстояния к одному и тому же метрическому пространству. Наконец, поворот нужен для того, чтобы разбить очевидное выравнивание различных слоев sdBase ().

Пока что эта конструкция идентична построению базовый fBM. Однако вместо простого добавления каждого слоя n в «хост» SDF (передается в функцию как
d ), выполняем модифицированный “sdf добавление “, которое мы определили выше: сначала мы плавно зажимаем шум SDF n к надутой версии основной поверхности d . В этом случае коэффициент инфляции составляет 0,1 с, но, опять же, вы должны поиграть с этим. Только не забудьте сделать его пропорциональным s . Коэффициент гладкости 0,3 с также должен быть изменен, но, вероятно, неплохо сохранить его пропорциональным s , поэтому мы сохраняем детализацию фракталов во всех масштабах.

Вторая часть нашего «добавления sdf» заключается в объединении текущий слой n с “хостом” sdf d . Мы делаем это, как мы уже говорили, с помощью обычной операции smin () с определенным коэффициентом плавности, в нашем случае 0,3 с, с которым вам также следует поэкспериментировать и настроить в соответствии с желаемым видом.

На изображении справа от фрагмента кода вы можете увидеть, что добавление каждого из этих слоев sdBase () делает с “хостом” SDF. Как видите, процесс работает отлично, и, что наиболее важно, метод создает действительный SDF в пределах возможностей smin () и smax () для этого, что лучше подходит для raymarching, а также для методов освещения на основе расстояния ( окружающая окклюзия, мягкие тени) и обнаружение столкновений, чем наивное добавление fBM к “хосту” SDF.

А ниже – видео, показывающее fBM SDF конструкция, слегка измененная по косметическим причинам, вместе с некоторой визуализацией результирующих поверхностей:



SDF fBM в действии

А ниже представлена ​​его версия в Shadertoy в реальном времени, где вы можете увидеть эту технику в действии, которая поставляется со справочным кодом, чтобы вы могли изучать и изменять ее напрямую: https://www.shadertoy.com/view/3dGSWR

LOD


Как и в большинстве фрактальных конструкций. ионов, можно легко полосовой фильтр геометрию на время построения и отфильтровывать детали, которые не нужны для данного пикселя на экране (или конуса теневого луча). Чтобы реализовать что-то подобное, все, что нам нужно сделать, это измерить максимальный размер, который может внести следующий вызов sdBase (), который задается текущим масштабным коэффициентом s , и если он ниже заданного порога th , затем прервите цикл. Этот порог должен основываться на размере пикселя в мировом пространстве. в месте вызова fFM, который вы можете легко вычислить с помощью дифференциалов лучей . По сути,

float sdFbm (в vec3 p, в float d, в float th) {float s = 1.0; для (int i = 0; i <20 ; я ++) {float n = s sdBase (p); n = smax (n, d-0,1 с, 0,3 с); d = smin (n, d, 0,3 с); p = mat3 (0. 04 , 1. 60, 1. 20, -1. 60, 0. 72, - 0. 96, -1. 45, - 0. 450, 1. 28 )*п; с = 0,5 с; если (s лучше, чем в решетке для лучшей производительности. Или они могут быть даже какими-то совершенно другими примитивами, такими как кубы, тории или даже эллипсоиды, чтобы придать шуму некоторые анизотропные свойства, в стиле шума Габора.

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

Помимо вариаций sdBase (), сам fBM SDF также может иметь множество вариаций. . Например, в приведенном выше видео я немного смещал сетку на каждой итерации, что помогло увеличить количество вогнутостей в поле, которые выглядели как скалы. Конечно, коэффициент масштабирования 0. 60 также может быть функция самого SDF, или пространства, или их комбинации.

Естественно возможности и безграничны и ограничиваются только вашим воображением.

Проблемы


Хотя методика отлично работает и имеет большие преимущества перед добавлением традиционных fBM сигналы на “основную” поверхность, это тоже связано с некоторыми проблемами. Основная из них заключается в том, что иногда он может создавать «эстакады» – небольшие участки поверхности, которые отключены от «хоста» SDF. Это также происходит с традиционными 3D fBM, как только мы пытаемся создать обрывы, поэтому это не проблема, специфичная для fBM, предложенного в этой статье. Но, тем не менее, мы могли бы попытаться облегчить это. В некоторых случаях возможно гарантировать, что эстакады не будут созданы, но сделав шаги клипа (smax) и комбинирования (smin) более консервативными, за счет уменьшения количества деталей на поверхности.

Заключение


Насколько я могу судить, техника потрясающая, она давала прекрасные изображения с первого раза, когда я ее спроектировал и протестировал в в эксперименте с Shadertoy выше, и я планирую часто использовать его в будущем. Не только для ландшафта, но в целом для увеличения / перемещения любого типа деталей SDF поверх других SDF.