попробуйте использовать вычисленную палитру вместо текстуры
Например, это мое:
для более высокой детализации требуется большее число итераций
так сколько у вас итераций?Если я применяю # 1 и использую n=200
итераций это:
Я получил это:
Что более или менее напоминает ваш случай (кроме соотношения сторон, но все же не уверен, что у нас одинаковый набор ...).Количество итераций влияет не только на количество деталей, но и на общую яркость результата, поэтому будьте осторожны, не используйте слишком много или слишком мало.
zoom
Как только вы начнете масштабировать, детали начнут появляться гораздо глубже ... Это n=2000
и увеличит третью копию справа ...
Как вы можете видеть, есть много деталей, которые не видны на предыдущем изображении
дальнейшее улучшение
Вы можете использовать нелинейные масштабы для отображения от итерации к цвету.Итак, снова тот же масштаб, но с использованием t=pow(t,0.5);
в качестве параметра для цвета ...
Как вы можете видеть, результат выглядит лучше (более плавный)) ...
Последнее, что я могу придумать, это реализовать сортировку HDR ... поэтому вычислите первое базовое изображение с небольшим n
затем осмотрите его и найдите зоны с низким уровнем детализации (практически без изменения цвета) и выполните повторную визуализацию с более высокими значениями n
до тех пор, пока у вас не будет таких зон ... Для каждого n
вы можете немного настроить функцию разграничения параметров...
Также вы можете найти параметр min и max для всего результата и вычислить цвет только из этого диапазона, охватывающего весь спектр из этого ... как:
l = 400 + 300*(i-imin)/(imax-imin)
где l
- длина волны в [nm]
для цветового спектра, i
- конечная итерация, а imin,imax
- минимальное и максимальное значения для всего изображения ... к сожалению, я не могу попробовать это легко, так как мне нужно будет переписатьGLSL рендерит в два прохода рендерера.
Еще одна вещь, которую выможно использовать гистограмму вместо min max ... но это также многоходовая техника ...
[Edit1] match
Также, сравнивая с чужими изображениями, убедитесь, что они используют один и тот же набор ... в противном случае вы сравниваете апельсины с яблоками.Когда я посмотрел поближе, это стало очевидным, я получил тот же набор, но с другой шкалой на х ... и изображение увеличилось в определенной точке фрактала.После некоторой настройки наиболее близкое совпадение, которое я нашел, было таким:
[Edit2] гистограмма
После изменениямой код для поддержки многопроходного рендеринга я мог бы применить подход гистограммы ... Так что
рендер Мандельброта установлен на текстуру
, но вместо цветов рендерингиндекс итерации ...
вычисление гистограммы отрисованного материала
поиск диапазона индексов для перекраски
гистограмма будет иметь много записей с нулевым или малым количеством пикселей ... и затем будет группа более высоких значений (то есть диапазон, который вы ищете), и после этого будет небольшое илиснова нулевые значения ... Вдобавок ко всему этому последнее значение может содержать большое количество пикселей (то есть черная пустая область), и может быть одно или несколько более высоких значений, слишком независимых от основной группы.Если я использую 80% спектральных цветов для основной группы / диапазона и 10% для индексов до него и 10% для индексов после него, результат будет выглядеть следующим образом:
Здесь модифицированный код GLSL с восстановленным масштабом, масштабированием и переключением между однопроходным / многопроходным рендерингом:
// Vertex
#version 420 core
layout(location=0) in vec2 pos; // glVertex2f <-1,+1>
out smooth vec2 p; // texture end point <0,1>
void main()
{
p=pos;
gl_Position=vec4(pos,0.0,1.0);
}
// Fragment
#version 420 core
#define multi_pass
uniform vec2 p0=vec2(0.0,0.0); // mouse position <-1,+1>
uniform float zoom=1.000; // zoom [-]
uniform int n=4000; // iterations [-]
in smooth vec2 p;
out vec4 col;
#ifdef multi_pass
vec3 spectral_color(float l) // RGB <0,1> <- lambda l <400,700> [nm]
{
float t; vec3 c=vec3(0.0,0.0,0.0);
if ((l>=400.0)&&(l<410.0)) { t=(l-400.0)/(410.0-400.0); c.r= +(0.33*t)-(0.20*t*t); }
else if ((l>=410.0)&&(l<475.0)) { t=(l-410.0)/(475.0-410.0); c.r=0.14 -(0.13*t*t); }
else if ((l>=545.0)&&(l<595.0)) { t=(l-545.0)/(595.0-545.0); c.r= +(1.98*t)-( t*t); }
else if ((l>=595.0)&&(l<650.0)) { t=(l-595.0)/(650.0-595.0); c.r=0.98+(0.06*t)-(0.40*t*t); }
else if ((l>=650.0)&&(l<700.0)) { t=(l-650.0)/(700.0-650.0); c.r=0.65-(0.84*t)+(0.20*t*t); }
if ((l>=415.0)&&(l<475.0)) { t=(l-415.0)/(475.0-415.0); c.g= +(0.80*t*t); }
else if ((l>=475.0)&&(l<590.0)) { t=(l-475.0)/(590.0-475.0); c.g=0.8 +(0.76*t)-(0.80*t*t); }
else if ((l>=585.0)&&(l<639.0)) { t=(l-585.0)/(639.0-585.0); c.g=0.84-(0.84*t) ; }
if ((l>=400.0)&&(l<475.0)) { t=(l-400.0)/(475.0-400.0); c.b= +(2.20*t)-(1.50*t*t); }
else if ((l>=475.0)&&(l<560.0)) { t=(l-475.0)/(560.0-475.0); c.b=0.7 -( t)+(0.30*t*t); }
return c;
}
#endif
void main()
{
int i,j;
vec2 pp;
float x,y,q,xx,yy;
pp=(p/zoom)-p0; // y (-1.0, 1.0)
pp.x-=0.5; // x (-1.5, 0.5)
for (x=0.0,y=0.0,xx=0.0,yy=0.0,i=0;(i<n)&&(xx+yy<4.0);i++)
{
q=xx-yy+pp.x;
y=(2.0*x*y)+pp.y;
x=q;
xx=x*x;
yy=y*y;
}
#ifndef multi_pass
// RGB
q=float(i)/float(n);
q=pow(q,0.2);
col=vec4(spectral_color(400.0+(300.0*q)),1.0);
#else
// i
float r,g,b;
r= i &255; r/=255.0;
g=(i>> 8)&255; g/=255.0;
b=(i>>16)&255; b/=255.0;
col=vec4(r,g,b,255);
#endif
}
Изображениеберется за
n=4095; // max iterations
zoom=1763.0; // zoom [-]
p0.x=0.1483064; // center position
p0.y=0.3742866;
И второй проход рендеринга выглядит так:
// globals
const int N=4095; // this is the max count of iterations
OpenGLtexture txr;
// helper functions
DWORD spectral_color(float l) // RGB <0,1> <- lambda l <400,700> [nm]
{
float t; float r,g,b; DWORD c,x; r=0.0; g=0.0; b=0.0;
if ((l>=400.0)&&(l<410.0)) { t=(l-400.0)/(410.0-400.0); r= +(0.33*t)-(0.20*t*t); }
else if ((l>=410.0)&&(l<475.0)) { t=(l-410.0)/(475.0-410.0); r=0.14 -(0.13*t*t); }
else if ((l>=545.0)&&(l<595.0)) { t=(l-545.0)/(595.0-545.0); r= +(1.98*t)-( t*t); }
else if ((l>=595.0)&&(l<650.0)) { t=(l-595.0)/(650.0-595.0); r=0.98+(0.06*t)-(0.40*t*t); }
else if ((l>=650.0)&&(l<700.0)) { t=(l-650.0)/(700.0-650.0); r=0.65-(0.84*t)+(0.20*t*t); }
if ((l>=415.0)&&(l<475.0)) { t=(l-415.0)/(475.0-415.0); g= +(0.80*t*t); }
else if ((l>=475.0)&&(l<590.0)) { t=(l-475.0)/(590.0-475.0); g=0.8 +(0.76*t)-(0.80*t*t); }
else if ((l>=585.0)&&(l<639.0)) { t=(l-585.0)/(639.0-585.0); g=0.84-(0.84*t) ; }
if ((l>=400.0)&&(l<475.0)) { t=(l-400.0)/(475.0-400.0); b= +(2.20*t)-(1.50*t*t); }
else if ((l>=475.0)&&(l<560.0)) { t=(l-475.0)/(560.0-475.0); b=0.7 -( t)+(0.30*t*t); }
r*=255.0; g*=255.0; b*=255.0;
x=r; c =x;
x=g; c|=x<<8;
x=b; c|=x<<16;
return c;
}
...
// [multipass] this is executed after the shader renders its stuff
int hist[N+1],sz=txr.xs*txr.ys,i,i0,i1,a0,a1;
float t;
// get rendered image
glReadPixels(0,0,txr.xs,txr.ys,GL_RGBA,GL_UNSIGNED_BYTE,txr.txr);
// compute histogram
for (i=0;i<N;i++) hist[i]=0;
for (i=0;i<sz;i++) hist[txr.txr[i]&0x00FFFFFF]++;
// find the major used range
a0=txr.xs/4;
a1=txr.xs*4;
for (i0= 0;(i0<N)&&((hist[i0]<a0)||(hist[i0]>a1));i0++);
for (i1=N-1;(i1>0)&&((hist[i1]<a0)||(hist[i1]>a1));i1--);
// recolor it
for (i=0;i<sz;i++)
{
a0=txr.txr[i]&0x00FFFFFF;
if (a0<i0) t=(0.1*divide(a0 ,i0 ));
else if (a0>i1) t=(0.1*divide(a0-i1,N -i1))+0.9;
else t=(0.8*divide(a0-i0,i1-i0))+0.1;
txr.txr[i]=spectral_color(400.0+(300.0*t));
}
// render it back
scr.cls();
txr.bind();
glColor3f(1.0,1.0,1.0);
glBegin(GL_QUADS);
glTexCoord2f(0.0,1.0); glVertex2f(-1.0,+1.0);
glTexCoord2f(0.0,0.0); glVertex2f(-1.0,-1.0);
glTexCoord2f(1.0,0.0); glVertex2f(+1.0,-1.0);
glTexCoord2f(1.0,1.0); glVertex2f(+1.0,+1.0);
glEnd();
txr.unbind();
glDisable(GL_TEXTURE_2D);
Я знаю, что он использует много вещей, которыми я не поделился, но использование гистограммы достаточно просто, чтобы портировать его для ваших нужд ...
Так что теперь просто нужно найти правильную комбинацию n
и позиции / масштабирования.
[Edit3] Однако, если даже этого недостаточно
Затем вы можете реализовать дробный побег для получения дополнительной информации см .: