Фрактальное пламя — алгоритм построения

7b04ac6a87c841398f5e6f1bfb1293e3.pngФрактальное пламя (или фрактальные искры, англ. fractal flame) — алгоритм, предложенный Скоттом Дрейвсом (Scott Draves) и использующий для построения изображений системы итерируемых функций (СИФ). Благодаря разным значениям seed для генератора псевдослучайных чисел можно получить множество разнообразных «картин». Хотя фрактальность в них просматривается далеко не всегда, результаты получаются очень интересными.

Под катом — краткое описание основных моментов реализации алгоритма.Для начала, как и в обычных СИФ, нам понадобится узнать коэффициенты для каждого аффинного преобразования плоскости (их может быть несколько; каждое следующее будет вносить свои «мазки» на картину, а также изменять вклад предыдущих). В матричной форме это преобразование выглядит следующим образом:

a6a30d99bfe143428ac419c2171655fc.gif

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

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

32a9540c7eae472aad79623806006c62.gif78d8981a4f814f838c82e9b1c7f6cf1e.gif0a3f9dcf67a348e3900a4f5d6c2336c1.gif

Все это относится к коэффициентам, задающим линейное преобразование. Оставшиеся два, 466be38f400348adaf58450344726a6a.gif и 2bec1622a29549f7848bd142880bf544.gif, выполняют трансляцию — перемещение точки на некоторое расстояние. Желательно, чтобы 6da18de753ce4e2cb6240474c568d72c.gif, 68967adb55484926a0baa4235f81008b.gif, 7d22671101214e35886f49e4c6f3f0fe.gif и ce99c0021628462caec8c946ede58d23.gif находились на отрезке b36ebf5827d943fc8cdb02084ba306d5.gif или 9cc1f6c723c04e9887d5ccf6dd34adec.gif. Для 466be38f400348adaf58450344726a6a.gif и 2bec1622a29549f7848bd142880bf544.gif это необязательно, однако не стоит задавать слишком большой отрезок, иначе изображение получится разреженным.

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

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

координаты x и y; значения R, G и B; число попаданий. Далее приведены некоторые нелинейные преобразования, которые будут выполняться над значениями x и y, полученными после выполнения одного из аффинных преобразований: Синусоидальное: 57d968b0fbf34857893976ff088bbdbf.gif, 4e6c910b985a4484aaedbae4384cddca.gif; Сферическое: 79be9463be864f52b959e5fa36ae50aa.gif, 654d76f7136d4a0b90694e73ef3d3e6b.gif; Полярное: 61b07e48c682496aa1f16d7e755118db.gif, 38c92cc1bebf43db85b18e2db878349f.gif; Сердце: be6f0a2909134c65851b95c69d7a7e87.gif, 7477e969c04f4fa5af80c59d8e273288.gif; Диск: 54f8ded867174338ba56d632e2085188.gif, 04e9ae1216494c9eb2ba0784eb507dec.gif; В конце статьи — примеры изображений, полученных с использованием этих и некоторых других преобразований, а далее — псевдокод процедуры рендеринга: void render (int n, int eqCount, int it, int xRes, int yRes) { Генерируем eqCount аффинных преобразований со стартовыми цветами; for (int num=0; num=0 && newX∈[XMIN, XMAX] && newY∈[YMIN, YMAX]) { //Вычисляем координаты точки, а затем задаем цвет x1=xRes-Trunc (((XMAX-newX)/(XMAX-XMIN))*xRes); y1=yRes-Trunc (((YMAX-newY)/(YMAX-YMIN))*yRes); //Если точка попала в область изображения if (x1max) max = pixels[row][col].normal; } for (int row=0; rowb4fa908348414161825b1c6b97b9d0f1.png

Ну, а теперь обещанные изображения с различными нелинейными преобразованиями Синусоидальное4f31022d9ea347f4a74e134e56c07dc9.png

Сферическое

41614c64a2bc4fefb8a1ba5ef9486798.png

Полярное

bb43343d757d43b9ac745fe951452d05.png

Сердце

ab2648fa496d4875b10d39da02503016.png

Диск

b05b621551fc41e5aae6407c63494cb9.png

«Ракушка»

f82d596dc3794da99662e148c3c0a933.png

Гиперболическое

c91b8bfca2884d2ea8bbd3874b090530.png

Водоворот

5f305745bc034a279bdff932e850b05d.png

Волны

fd6c5b08f20549ee913640091574cafb.png

А что если применять не одно и то же нелинейное преобразование, а случайным образом выбирать из нескольких?

Исходный код Реализация алгоритма от Джеймса Маккарти на языке Си находится здесь, а статья Скотта Дрейвса на основе которой и создавался алгоритм — здесь.

© Habrahabr.ru