Я пытаюсь визуализировать набор Мандельброта в цвете и заставить его выглядеть хорошоЯ хочу скопировать изображение со страницы Википедии .Изображение из Википедии также включает файл параметров Ultra Fractal 3.
mandelZoom00MandelbrotSet {
fractal:
title="mandel zoom 00 mandelbrot set" width=2560 height=1920 layers=1
credits="WolfgangBeyer;8/21/2005"
layer:
method=multipass caption="Background" opacity=100
mapping:
center=-0.7/0 magn=1.3
formula:
maxiter=50000 filename="Standard.ufm" entry="Mandelbrot" p_start=0/0
p_power=2/0 p_bailout=10000
inside:
transfer=none
outside:
density=0.42 transfer=log filename="Standard.ucl" entry="Smooth"
p_power=2/0 p_bailout=128.0
gradient:
smooth=yes rotation=29 index=28 color=6555392 index=92 color=13331232
index=196 color=16777197 index=285 color=43775 index=371 color=3146289
opacity:
smooth=no index=0 opacity=255
}
Я пытался расшифровать этот файл и написать программу для воспроизведения изображения из Википедии.Это моя лучшая попытка:
Это часть рендерера.Это немного грязно, потому что я возился и переписывал большие куски, пытаясь разобраться в этом.
using real = double;
using integer = long long;
struct complex {
real r, i;
};
using grey = unsigned char;
struct color {
grey r, g, b;
};
struct real_color {
real r, g, b;
};
grey real_to_grey(real r) {
// converting to srgb didn't help much
return std::min(std::max(std::round(r), real(0.0)), real(255.0));
}
color real_to_grey(real_color c) {
return {real_to_grey(c.r), real_to_grey(c.g), real_to_grey(c.b)};
}
real lerp(real a, real b, real t) {
return std::min(std::max(t * (b - a) + a, real(0.0)), real(255.0));
}
real_color lerp(real_color a, real_color b, real t) {
return {lerp(a.r, b.r, t), lerp(a.g, b.g, t), lerp(a.b, b.b, t)};
}
complex plus(complex a, complex b) {
return {a.r + b.r, a.i + b.i};
}
complex square(complex n) {
return {n.r*n.r - n.i*n.i, real{2.0} * n.r * n.i};
}
complex next(complex z, complex c) {
return plus(square(z), c);
}
real magnitude2(complex n) {
return n.r*n.r + n.i*n.i;
}
real magnitude(complex n) {
return std::sqrt(magnitude2(n));
}
color lerp(real_color a, real_color b, real t) {
return real_to_grey(lerp(a, b, t));
}
struct result {
complex zn;
integer n;
};
result mandelbrot(complex c, integer iterations, real bailout) {
complex z = {real{0.0}, real{0.0}};
integer n = 0;
real bailout2 = bailout * bailout;
for (; n < iterations && magnitude2(z) <= bailout2; ++n) {
z = next(z, c);
}
return {z, n};
}
struct table_row {
real index;
real_color color;
};
real invlerp(real value, real min, real max) {
return (value - min) / (max - min);
}
color lerp(table_row a, table_row b, real index) {
return lerp(a.color, b.color, invlerp(index, a.index, b.index));
}
color mandelbrot_color(complex c, integer iterations, real bailout) {
const result res = mandelbrot(c, iterations, bailout);
if (res.n == iterations) {
// in the set
return {0, 0, 0};
} else {
table_row table[] = {
// colors and indicies from gradient section
{28.0*0.1, {0x00, 0x07, 0x64}},
{92.0*0.1, {0x20, 0x6B, 0xCB}},
{196.0*0.1, {0xED, 0xFF, 0xFF}},
{285.0*0.1, {0xFF, 0xAA, 0x00}},
{371.0*0.1, {0x31, 0x02, 0x30}},
// interpolate towards black as we approach points that are in the set
{real(iterations), {0, 0, 0}}
};
// it should be smooth, but it's not
const real smooth = res.n + real{1.0} - std::log(std::log2(magnitude(res.zn)));
// I know what a for-loop is, I promise
if (smooth < table[1].index) {
return lerp(table[0], table[1], smooth);
} else if (table[1].index <= smooth && smooth < table[2].index) {
return lerp(table[1], table[2], smooth);
} else if (table[2].index <= smooth && smooth < table[3].index) {
return lerp(table[2], table[3], smooth);
} else if (table[3].index <= smooth && smooth < table[4].index) {
return lerp(table[3], table[4], smooth);
} else {
return lerp(table[4], table[5], smooth);
}
}
}
Цвета из секции gradient
находятся в таблице в mandelbrot_color
.Индексы из секции gradient
также есть в таблице, но я умножил их на 0.1
.Цвета выглядят совершенно нечеткими, если я не умножу на 0.1
.
В секции formula
есть maxiter=50000
и p_bailout=10000
.Это iterations
и bailout
в коде.Я не знаю, что означает p_start=0/0 p_power=2/0
.Я не знаю, почему в разделе outside
упоминается другая помощь, и я не знаю, что означает density=0.42
, transfer=none
, transfer=log
.В разделе gradient
также упоминается rotation=29
, но я не понимаю, как можно повернуть градиент.
Причина, по которой я задаю этот вопрос, заключается в том, что мне не нравятся белые полосы вокруг моего изображения (Я бы предпочел плавное свечение, как на картинке из Википедии).Мне также не нравится темно-фиолетовая кожа, вызванная интерполяцией к черному (последняя строка в таблице mandelbrot_color
).Если мы удалим эту строку, мы получим темно-синий скин.
Я подозреваю, что существует какое-то соответствие между индексами в разделе gradient
и количеством итераций.Может быть, * 0.1
является приближением того отображения, которое иногда работает.Может иметь отношение к transfer
, density
или rotation
.Оставьте комментарий, если вы хотите, чтобы я опубликовал всю программу.Это зависит от stb_image_write
(библиотека для записи изображений с одним заголовком).
В качестве примечания я приведу этот код в порядок и очистил его, добавив фрагментный шейдер, скорее всего, он будет быстрее (вообще говоря)) чем работает многопоточный процессор?