Can't find a way to color the Mandelbrot-set the way i'm aiming for

33
May 18, 2019, at 10:50 PM

I've been successful in coloring the Mandelbrot-set although I can't zoom in very far until it becomes "blurry" and the pattern stops. I fix this by increasing the max_iteration, this works but I get very few colors at *1 magnification and lot's of colors only appear when I zoom in. I understand why this happens since in a "true" Mandelbrot-set there are no colors and increasing the max_iterations just brings it closer to that. But my question is, is how do zooms such as on youtube have beautiful colors throughout the whole zooming process while still being able to zoom on for what feels like forever?

I've tried looking everywhere online but I can't find a solution and when I look in the descriptions of these youtube zooms they seem to provide barely anything on how they made that zoom.

Here is just the section of code which draws the Mandelbrot set. The code below is written in processing which is java with added visual libraries. You can find out more about the program here: https://processing.org/

//m is max_iterations
//mb is the function which calculates how many iterations each point took to escape to infinity. I won't be including the function since I know it works fine and it's quite messy.
//i'm using a HSB/HSV system to draw the mandelbrot
hue=(mb(x, y, m)*360)/m;
sat=255;
if (mb(x, y, m)<m) {
  val=255;
} 
else {
  val=0;
}
stroke(hue,sat,val);
point(x, y);

I understand why my problem is happening but I don't know how to solve it.

Here is an image with a low max_iterations and zoomed out, as you can see it's very colorful:

Here is an image with a low max_iterations and zoomed in slightly, as you can see it's boring and not very colorful:

Here is an image with a high max_iterations and zoomed out, as you can see it's not very colorful:

Here is an image with a high max_iterations and zoomed in, as you can see it's very colorful:

Answer 1

First take a look at this related QA:

  • Mandelbrot Set - Color Spectrum Suggestions?

The main idea is to use histogram to distribute the color gradients more effectively to used indexes instead of uniformly wasting many colors on unused indexes. Also it uses a specific visually pleasing gradient function:

  • RGB values of visible spectrum

Dynamic max iterations count suggested by others will only affect overall performance and details in zooms. However if you want nice colors without zoom then you need to compute floating point iterations count which is also called Mandelbrot Escape. There is a math way that can compute the iterations count fractional part from the last sub-results of the equation. For more info see:

  • Renormalizing the Mandelbrot Escape

However I never tried it so read this with prejudice: If I read it right what you want is to compute this equation:

mu = m + frac = n + 1 - log (log  |Z(n)|) / log 2

Where n is your iteration count, Z(n) is the complex domain sub-result of the equation you are iterating on. So now compute color from mu which is floating point now instead of from n...

[Edit1] I tried to implement it into my GLSL mandelbrot from link above

Here the resulting fragment shader:

// Fragment
#version 420 core
#define fract_esc
uniform vec2 p0=vec2(0.0,0.0);      // mouse position <-1,+1>
uniform float zoom=1.000;           // zoom [-]
uniform int  n=100;                 // iterations [-]
uniform int  multipass=0;           // multi pass?
in smooth vec2 p;
out vec4 col;
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;
    }
void main()
    {
    int i,j,N=n;
    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)
    #ifdef fract_esc
    N=(n>>5)-2;
    #endif
    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;
        }
    #ifdef fract_esc
    for (j=0;j<2;j++,i++)
        {
        q=xx-yy+pp.x;
        y=(2.0*x*y)+pp.y;
        x=q;
        xx=x*x;
        yy=y*y;
        }
    float mu=float(i)-log(log(sqrt(xx+yy))/log(2.0));
    mu*=32.0; i=int(mu);
    if (i>n) i=n;
    if (i<0) i=0;
    #endif
    if (multipass!=0)
        {
        // 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);
        }
    else{
        // RGB
        q=float(i)/float(n);
        q=pow(q,0.2);
        col=vec4(spectral_color(400.0+(300.0*q)),1.0);
        }
    }

I add 32 = 1<<5 accuracy fractional part, so do not forget to multiply n by it on the CPU side code too. The histogram approach is not working very good with this as it was not developed for it. However raw output looks much better now.

This is fractional escape n=100*32:

This is integer escape n=100:

As you can see the fractional escape is much better for the same number of iterations (100).

Some explanations:

n is max number of iteration passed from CPU side and N is actual integer max count (so the 5 bit fixed point precision fractional count still fits into n). The i is the actual counter of iterations. So the implementation of the fractional escape just change N so result is still in range <0,n> before the loop. After the loop I added 2 iterations to improve precision and computed the fractional escape according to formula in the link (the i+1 is in the loop itself) and lastly the floating escape is converted back to fixed point integer i.

Answer 2

As Daniel Williams said, you should make max-iterations dynamic and increase it with the zoom level.

READ ALSO
How can I get Spring&#39;s WebFlux to emit a response

How can I get Spring's WebFlux to emit a response

When I create a Spring-webflux webclient I'm not able to get it to go into the subscribe or doOnNext callbackI keep getting this error: java

22
How to prevent a jfxbutton from listening to keyboard

How to prevent a jfxbutton from listening to keyboard

I'm creating a login stage and setting a maximum number of attempts to login, so i don't want the login button to be activated without the user clicking it or pressing the enter keyThe problem is that if shift or any other key is touched the button triggers,...

33
How do i create a jar that can be used to encrypt columns in GRAILS and Springboot?

How do i create a jar that can be used to encrypt columns in GRAILS and Springboot?

We have several applications running in grails and other frameworks such as springbootWe need to create a custom jar that can be used to encrypt/decrypt columns in a database

45