Вы не авторизованы.

Fragmentarium-Distance Estimated часть 2

Продолжение первой части Fragmentarium-Distance Estimated часть 1

Рисование сферы

Оценка расстояния - не более чем функция, что для всех точек в пространстве возвращает длину меньшую (или равную) расстоянию до ближайшего объекта. Это означает, что мы можеи безопасно идти по крайней мере на эту длина шага, не задев ничего - и мы используем эту информацию, чтобы ускорить ширину шага луча (ray marching). Это довольно легко придумать с оценкой расстояния для большинства простых геометрических фигур. Например, давайте начнем со сферы. Вот три различных способа рассчитать расстояние от точки в пространстве, р, к сфере радиусом R:

(1) DE(p) = max(0.0, length(p)-R)  // solid sphere, zero interior

(2) DE(p) = length(p)-R // solid sphere, negative interior

(3) DE(p) = abs(length(p)-R)    // hollow sphere shell

 Со стороны все это похоже. Но (3) является полой сферой - мы сможем позиционировать камеру внутри нее, и она будет выглядеть иначе, если пересекается с другими объектами. А как насчет первых двух? Существует на самом деле тонкое различие: общим способом найти нормали к поверхности является сэмпл DE - функции близко к камере луча / поверхности пересечения. Но если точка пересечения расположена очень близко к поверхности (например, именно на ней), мы могли бы попробовать DE внутри сферы. И это приведет к артефактам в нормальном расчете вектора (1) и (3). Так что, если возможно, необходимо использование функции расстояния. Еще один способ избежать этого заключается в Backstep (обратном шаге) вдоль луча камеры, прежде чем вычислить нормали к поверхности (или добавить множитель лучей шагом менее 1,0).

Обратите внимание, что оценка расстояния только рассказывает о расстоянии от точки до объекта. Это отличие от классического метода трассировки лучей, которая всегда ищет расстояние от точки до заданного объекта вдоль линии. Формулы для Ray-объекта пересекаются в классической трассировке лучей таким образом, более сложные, например, пересечение Ray-сферы требуют решения квадратного уравнения. Недостатком оценки расстоянии является то, что необходимы несколько шагов луча, даже для простых объектов, таких как сфера.

 Объединение объектов

У разделенных полей есть некоторые интересные свойства. Например, можно объединить два разделенных поля с помощью простого минимума (а, б) оператора. В качестве примера мы могли бы сделать объединение двух сфер следующим образом:

DE(p) = min( length(p)-1.0 , length(p-vec3(2.0,0.0,0.0))-1.0 );

Это даст нам две сферы единичного радиуса, с центром одной в Origo, и другой в (2,0,0). Таким же образом можно вычислить пересечение двух объектов, принимая максимальное значение полей. Наконец, при использовании отмеченных функции расстояния, можно вычесть одну форму от другой путем инвертирования одного из полей, и вычисления пересечения (т.е. с макс (А,-В)).

Так что теперь у нас есть способ объединить объекты. И это также можно применять в локальных преобразованиях, чтобы получить интересные эффекты:

Это изображение было создано путем объединения DE плоскости и двух торов при применении деформация кручения тора

Это все хорошо, но даже если вы можете создавать интересные структуры, существуют некоторые ограничения. Описанный выше метод работает, но очень плохо в масштабах, когда число полей расстояния должны быть объединены. Создание сцены с 1000 сферами находящихся минимум в 1000 полях стало бы слишком медленно в реальном времени. На самом деле обычная трассировка лучей лучше масштабируется – использование ускорения пространственных структур делает это возможным для обычных трейсеров луча рисовать сцены с миллионами объектов, то, что далеко не возможно с помощью "поиска минимума всех полей объекта". Но фракталы – это детали и бесконечные сложности, так как мы можем продолжить? Оказывается, что есть несколько трюков, которые позволяют добавить сложность таким образом, чтобы фрактал лучше масштабировался. Во-первых, можно повторно использовать объекты с использованием, например, модуле-оператора. Взгляните на следующий DE:

float DE(vec3 z)
{
  z.xy = mod((z.xy),1.0)-vec3(0.5); // instance on xy-plane
  return length(z)-0.3;             // sphere DE
}

 Который генерирует это изображение:

Масса деталей практически без потерь в стоимости вычислений. Теперь нам нужно только сделать его более интересным!

 Реальный фрактал

Давайте продолжим с первым примером реального фрактала: рекурсивный тетраэдр.

Тетраэдр может быть описан как многогранник с вершинами (1,1,1), (-1, -1,1), (1, -1, -1), (-1,1, -1). Теперь для каждой точки пространства, позволяет нам масштабировать систему с коэффициентом 2,0 с помощью этой вершины, как центра, а затем, наконец, вернуться к расстоянию до точки, где мы закончили, после того, как эта операция повторится. Вот код:

float DE(vec3 z)
{
                vec3 a1 = vec3(1,1,1);
                vec3 a2 = vec3(-1,-1,1);
                vec3 a3 = vec3(1,-1,-1);
                vec3 a4 = vec3(-1,1,-1);
                vec3 c;
                int n = 0;
                float dist, d;
                while (n < Iterations) {
                                c = a1; dist = length(z-a1);
                        d = length(z-a2); if (d < dist) { c = a2; dist=d; }
                                d = length(z-a3); if (d < dist) { c = a3; dist=d; }
                                d = length(z-a4); if (d < dist) { c = a4; dist=d; }
                               z = Scale*z-c*(Scale-1.0);
                               n++;
                }
 
                return length(z) * pow(Scale, float(-n));
}

Результат на рисунке:

Наш первый фрактал! Даже если мы не имеем бесконечное число объектов, как и в приведенном выше примере, количество объектов растет в геометрической прогрессии, как мы задали максимум числа итераций. В самом деле, количество объектов равно 4^ итерации. Всего десять итераций приведет к более миллиона объектов - то, что легко выполнимо на GPU в реальном времени!

 Складные Пространства (Folding Space)

Но оказывается, что мы можем сделать еще лучше с помощью хитрого трюка с использованием симметрий тетраэдра. Теперь, вместо масштабирования от ближайших вершин, мы могли бы использовать зеркальные точки в плоскостях симметрии тетраэдра, чтобы убедиться, что мы приходим к тому же "Октанту" тетраэдра - и тогда постоянный масштаб от вершины он содержит. На следующем рисунке пытается визуализировать это:

Красная точка в верхней вершины масштабирования с центром в точке (1,1,1). Три плоскости симметрии тетраэдра были окрашены в красный, зеленый и синий. Отражая точки, если они не на той стороне (не-белые точки) плоскости, мы добьемся того, что они сопоставляются с белым "Октантом". Операция «зазеркаливания» точки, если она находится на одной стороне плоскости, называется «операция складывания" или fold. Вот код:

float DE(vec3 z)
{
    float r;
    int n = 0;
    while (n < Iterations) {
       if(z.x+z.y<0) z.xy = -z.yx; // fold 1
       if(z.x+z.z<0) z.xz = -z.zx; // fold 2
       if(z.y+z.z<0) z.zy = -z.yz; // fold 3    
       z = z*Scale - Offset*(Scale-1.0);
       n++;
    }
    return (length(z) ) * pow(Scale, -float(n));
}

Эти операции отображаются в нескольких фракталах. Складывание в общей плоскости с нормальным n может быть выражено как:

float t = dot(z,n1); if (t<0.0) { z-=2.0*t*n1; }

или в оптимизированной версии:

z-=2.0 * min(0.0, dot(z, n1)) * n1;

 Также заметьте, что складывание на XY, XZ, YZ –плоскостях  могут быть выражены с помощью 'abs' оператора. По-настоящему интересные вещи происходят, когда мы вносим вращения в систему. Это было впервые введено Knighty в калейдоскопической IFS. Вот несколько примеров форм, которые могут возникнуть в системах с симметрией икосаэдра:

Здесь икосаэдрическое происхождение может быть очевидным, но можно настроить эти структуры до неузнаваемости их происхождения. Вот еще несколько примеров:

Фракталы Knighty используют небольшой набор преобразований: масштабирование, переводы, плоскости отражения и вращения. Складывание, конечно, не ограничивается плоскостями симметрии Платоновых тел, это возможно во всех плоскостях. Упомянутые выше преобразования - все они принадлежат к группе конформных (с сохранением угла) преобразований. Иногда говорят, что для "истинного" фрактала преобразования должны быть конформными, так как не конформные преобразования, как правило, имеют тенденцию растягивать детали и создавать так называемый вид "взбитых сливок", который не поддается глубокому масштабированию. Интересно, что по теореме Лиувилля (Liouville's theorem ) есть не очень много возможных конформных преобразования в 3D.

Оцените материал
(0 голосов)
Прочитано 248 раз Последнее изменение Четверг, 07 Август 2014 17:25

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

Убедитесь, что вы вводите (*) необходимую информацию, где нужно
HTML-коды запрещены