Движок, на котором работает Fractal Forge. В нём нет ни одного полигона: каждый пиксель — луч, который по формуле расстояния ищет поверхность фрактала. Всё считает ваша видеокарта, сервер только отдаёт файлы.
Квазар — ядро далёкой галактики, один из самых ярких объектов во Вселенной: его видно сквозь миллиарды световых лет. Лучи движка тоже идут сквозь бесконечную глубину и возвращаются со светом. Имя стоит в одном ряду с Apogee и Pulsar — другими системами avr.
11формул: бульбы, боксы, IFS, кватернионы и гибриды
33шейдерные программы, собираются из одного исходника
0зависимостей: ни three.js, ни GLFW, ни ImGui
10−12предел погружения в Windows-версии с fp64
57 / 57контрольных сидов дают одно и то же в вебе и в C++
700 КБвесь exe вместе с интерфейсом и шейдерами
01
Фрактал — это формула, а не модель
Точка пространства принадлежит фракталу, если итерация из неё не улетает в бесконечность. У Мандельбульба итерация — это «возведение в степень» в сферических координатах: радиус возводится в степень n, углы умножаются на n, и прибавляется исходная точка c.
r = |z|, θ = acos(zz / r), φ = atan(zy, zx)
z ← rⁿ · (sin nθ · cos nφ, sin nθ · sin nφ, cos nθ) + c
Для степени 8, самой частой, Quasar обходится без тригонометрии: z⁸ раскрыт в полином от координат, и шейдер не вызывает ни acos, ни pow. Остальные формулы устроены похоже. Мандельбокс складывает пространство кубом и сферой, KIFS отражает его плоскостями, как калейдоскоп, кватернион Жюлиа итерирует q² + c в четырёх измерениях. Гибрид чередует до четырёх разных формул внутри одной итерации.
02
Трассировка сферами
Поверхность фрактала нельзя пересечь с лучом аналитически. Зато можно оценить, насколько далеко до неё из любой точки, — это и есть оценка расстояния (distance estimator). Луч шагает ровно на эту величину: в шар такого радиуса фрактал не заходит, значит перепрыгнуть поверхность нельзя.
DE(c) = ½ · ln r · r / |dr|, dr ← n · rⁿ⁻¹ · dr + 1
Попробуйте сами. Это двумерный Мандельброт и та же самая формула. Перетащите звезду-камеру, кликните, куда светить. Круги — безопасные шаги луча. Возле границы они мельчают, и луч сходится к поверхности.
Шагов: —Перетащите звезду или кликните по полю
В 3D всё то же, только шагов до 320 на пиксель, и каждый шаг — десятки итераций формулы. Чтобы на неточной оценке луч не проскочил тонкую стенку, шаг умножается на запас: 0,9 для бульбов, 0,95 для боксов и 1,0 для IFS, у которых оценка точная.
03
Точность размером с пиксель
Когда остановиться? Если требовать фиксированную точность, вдали появится шум, а вблизи пропадут детали. Quasar считает, что луч попал, когда расстояние меньше половины пикселя на этой глубине: ε = 2·tan(fov/2) / H · t. Это конус пикселя: чем дальше, тем грубее, и рябь не появляется.
По той же причине число итераций растёт с зумом. Каждое двукратное приближение добавляет итерации по коэффициенту формулы: для IFS это около 1 / log₂(масштаба), то есть ровно столько, чтобы новая итерация давала детали размером в пиксель. Лишние итерации только добавили бы рябь.
04
Свет
Нормаль — по тетраэдру: четыре вызова DE вместо шести у центральных разностей.
Мягкие тени — второй марш к источнику света, полутень по ближайшему промаху луча (до 64 шагов, в движении 24).
Затенение (AO) — пять проб DE вдоль нормали: щели темнеют, как в жизни.
Глобальное освещение — в режиме «фото» луч отскакивает ещё раз в случайном направлении и приносит цвет соседних стенок.
Металл и иризация — отражения по Френелю и радужная плёнка, которая меняет цвет с углом взгляда.
Цвет — по «ловушке орбиты», следу, который итерация оставила по пути. Он переводится в цвет через палитру-текстуру 256×1.
Плёнка — HDR-буфер, блум в ¼ разрешения, тонмаппинг ACES и дизеринг против полос на градиентах.
05
Кадр, который дочищается сам
Один кадр — один луч на пиксель. Пока камера стоит, Quasar добавляет новые сэмплы со сдвигом внутри пикселя по последовательности Халтона (2, 3) и усредняет их в буфере RGBA16F: сглаживание, мягкие тени и глубина резкости появляются сами. Буферы чередуются по схеме ping-pong, и копируется только изменившийся прямоугольник.
В движении кадр смешивается с предыдущим на 55%, поэтому картинка не мерцает. Предварительный проход в ¼ разрешения конусом находит, где начинается поверхность, и основной луч стартует сразу оттуда. Это даёт от 6 до 17% скорости бесплатно.
06
Глубже, чем позволяет float
У float 24 бита мантиссы. На зуме около 10⁵ соседние пиксели получают одинаковые координаты, и картинка рассыпается на квадраты. В WebGL двойной точности нет, поэтому веб-версия останавливается там.
Windows-версия считает в double, но хитро. На игровых видеокартах double в 32–64 раза медленнее float, поэтому точность смешанная: double нужен, только пока орбита не «растянула» разницу между соседними пикселями (dr · ε > 10⁻⁴), дальше итерации досчитываются во float. На RTX 4060 кадр на ×10⁹ дочищается за 15–20 секунд; целиком в double это заняло бы в разы больше.
Тяжёлый кадр рисуется полосами по ~35 мс. Иначе Windows решила бы, что видеокарта зависла, и через 2 секунды сбросила бы драйвер (TDR). Предел — около 5·10⁻¹²: дальше кончается уже и double.
07
Сид — это вселенная
Название вроде iron_comet_sigma97 превращается в фрактал детерминированно: SHA-256 от строки даёт 32 байта, и каждый байт отвечает за свою ручку.
Этот код есть дважды: на JavaScript для веба и на C++ для Windows. Автотест прогоняет 57 контрольных сидов через обе реализации, и параметры совпадают все до одного. Поэтому пресет, ссылка или PNG из браузера открываются в Windows-версии тем же фракталом. Сам пресет зашит в PNG отдельным блоком iTXt, так что картинка — это и есть файл сохранения.
08
Генетика формул
Мутация сдвигает гены — степень, масштаб, константы Жюлиа, складки, повороты, палитру, металл — на гауссов шум. Генератор случайных чисел — mulberry32, зерно которого берётся из SHA-256 родителя, поэтому одна и та же мутация воспроизводима. Иногда случается большая мутация: фрактал получает вторую формулу и становится гибридом.
Скрещивание двух фракталов одного типа смешивает их числа. Если типы разные, потомок становится гибридом, и его звенья по шаблону AB, AAB, ABB или ABAB берутся по очереди от обоих родителей. Так Мандельбокс и Менгер дают существо, которого нет ни в одном каталоге.
09
Одни шейдеры — две программы
Веб
Windows
Графика
WebGL2, GLSL ES 3.0
OpenGL 4.3 core, свой загрузчик функций
Язык
JavaScript без сборщика
C++17, Win32 и WGL
Интерфейс
HTML и CSS в стиле avr
свой immediate-mode UI с атласом шрифта из GDI
Глубина
~10⁵
~10¹², fp64 со смешанной точностью
Экспорт
PNG до 4096², видео, меш OBJ и PLY
PNG до 8K через WIC
Особое
эволюция сеткой, музыка, VR, обои
заставка Windows, 0% нагрузки в покое
Шейдеры пишутся один раз, в веб-версии. При сборке Windows-версии скрипт вшивает их в exe, а при запуске заголовок #version 300 es меняется на #version 430 core. Исправление в формуле сразу попадает в обе программы.
Fractal Forge для Windows
Самая глубокая версия
Погружение до 10⁻¹², экспорт до 8K и заставка Windows. Архив 610 КБ, установка не нужна: распакуйте и запустите FractalForge.exe.
Windows 10 или 11, 64 бит
Видеокарта с OpenGL 4.3 — почти любая с 2012 года
Для fp64-погружения — double в шейдерах (GL_ARB_gpu_shader_fp64): NVIDIA или AMD