Mandelbrot套装-色谱建议? [英] Mandelbrot Set - Color Spectrum Suggestions?

查看:73
本文介绍了Mandelbrot套装-色谱建议?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我开始制作Mandelbrot套装,但是我找不到合适的色谱.这是我的结果

Recently I started making Mandelbrot set, but I wasn't able to find a good color spectrum. Here's my result

但是我想创建这样的东西:

But I want to create something like this:

有什么建议吗?谢谢!

推荐答案

  1. 尝试使用计算的调色板而不是纹理

例如,这是我的:

更多细节需要更多迭代次数

那么您获得了多少次迭代?如果我应用#1 并使用n=200迭代,则:

so how many iterations you got? If I apply #1 and use n=200 iterations this:

我知道了:

或多或少与您的情况类似(除了长宽比,但仍不确定我们有相同的设置...).迭代次数不仅会影响细节数量,还会影响结果的整体亮度,因此请注意不要使用过多或过少.

Which more or less resembles your case (apart the aspect ratio, but still not sure we have the same set...). The number of iterations not only affect the details count but also the owerall brightness of the result so be careful not to use too much or too less.

缩放

开始缩放后,详细信息将开始出现在更深的位置...这是n=2000,并从右侧缩放了第三份副本...

Once you start zooming the details will start appearing in much more depth ... This is n=2000 and zoomed the third copy from the right ...

如您所见,有很多细节在上一张图像中不可见

as yo can see there is a lot of details that aren't visible in the previous image

进一步的改进

您可以使用非线性比例从迭代到颜色进行映射.因此再次进行相同的缩放,但是使用t=pow(t,0.5);作为颜色的参数...

you can use non linear scales to map from iteration to color. So again the same zoom but with using t=pow(t,0.5); as parameter for color...

如您所见,结果看起来更好(更平滑)...

As you can see the result looks better (more smooth)...

我最后想到的是实现某种HDR ...,因此先用较小的n计算第一张基本图像,然后对其进行检查并找到细节较低(几乎没有颜色变化)的区域,然后使用更高的n直到没有这样的区域...对于每个n,您可以稍微调整参数去线性化功能...

Last thing that I can think of is to implement sort of HDR ... so compute first base image with small n then inspect it and find zones with low detail (almost no color change) and re-render them with higher n until you got no such zones... For each n you can tweak the parameter delinearization function a bit ...

您还可以找到整个结果的min和max参数,并仅从覆盖该光谱的整个光谱范围内计算颜色,例如:

Also you can find the min and max parameter for the whole result and compute the color from only that range covering whole spectrum from that ... like:

l = 400 + 300*(i-imin)/(imax-imin)

其中,l是色谱图的[nm]中的波长,i是最终迭代,而imin,imax是整个图像的最小值和最大值.需要将GLSL渲染重写为两遍渲染器.

where l is wavelength in [nm] for the color spectrum , i is the final iteration and imin,imax are the min and max values for whole image ... sadly I can not try it easily as I would need to rewrite the GLSL render to two pass renderer.

您可以做的另一件事是使用直方图代替min max ...但这也是多遍技术...

Another thing you can do is use histogram instead of min max ... but this is also multi pass technique ...

[Edit1]匹配

此外,在与外来图像进行比较时,请确保它们使用相同的图像集...否则,您将桔子与苹果进行比较.当我仔细观察它的明显点时,我得到了相同的集合,只是x的比例不同,并且视图放大了分形的特定点.经过一些调整后,我发现最匹配的是:

Also while comparing to foreign images make sure they use the same set ... otherwise you are comparing oranges with apples. When I took closer look its obvious I got the same set just different scale on x ... and the view is zoomed on specific point of the fractal. After some tweaking the closest match I found was this:

[Edit2]直方图

修改代码以支持多遍渲染后,我可以应用直方图方法...所以

After modifying my code to support multipass rendering I could apply histogram approach... So

  1. 将Mandelbrot设置为纹理

但是代替颜色呈现迭代索引...

but instead of colors render the iteration index ...

计算渲染内容的直方图

找到要重新着色的索引范围

直方图将包含许多像素数为零或较小的条目...然后将出现一组较高的值(即您要查找的范围),之后将再次出现较小或为零的值...最重要的是,最后一个值可能包含大量像素(即黑色空白区域),并且可能存在一个或多个非常高的值,这些值过于独立于主要组.如果我将80%的光谱颜色用于主要组/范围,将10%用于其之前的索引,并将10%用于其之后的索引,则结果如下:

the histogram will have many entries with zero or small pixel count... and then there will be group of higher values (that is the range you are seeking) and after that there will be small or zero values again... On top of all this the last value can contain a large amount of pixels (thats the black empty area) and there might be one or some more very high values too independent of the major group. If I use 80% of the spectral colors for the main group/range and 10% for indexes before it and 10% for indexes after it the result looks like this:

以下是修改后的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);

我知道它使用了很多我没有分享的东西,但是直方图的用法很简单,足以将其移植到您的需求中...

I know its use a lot of stuff I did not share but the histogram usage is straightforward enough to port it to your needs...

因此,现在只需找到n和位置/缩放的正确组合即可.

So now its just a matter of finding the correct combination of n and position/zoom.

[Edit3]但是,即使这还不够

然后,您可以实施小数转义,有关更多信息,请参见:

Then you can implement fractional escape for more info see:

这篇关于Mandelbrot套装-色谱建议?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆