Smooth spectrum for Mandelbrot Set rendering

后端 未结 7 1942
梦毁少年i
梦毁少年i 2020-11-28 04:40

I\'m currently writing a program to generate really enormous (65536x65536 pixels and above) Mandelbrot images, and I\'d like to devise a spectrum and coloring scheme that do

相关标签:
7条回答
  • 2020-11-28 05:10

    here you can find a version with javascript

    usage :

    var rgbcol = [] ;
    var rgbcol = MapColor ( Iteration , Zy2,Zx2 ) ;
    point ( ctx , iX, iY ,rgbcol[0],rgbcol[1],rgbcol[2] );  
    

    function

    /*
     * The Mandelbrot Set, in HTML5 canvas and javascript.
     * https://github.com/cslarsen/mandelbrot-js
     *
     * Copyright (C) 2012 Christian Stigen Larsen
    */
    
    /*
     * Convert hue-saturation-value/luminosity to RGB.
     *
     * Input ranges:
     *   H =   [0, 360] (integer degrees)
     *   S = [0.0, 1.0] (float)
     *   V = [0.0, 1.0] (float)
     */
    function hsv_to_rgb(h, s, v)
    {
      if ( v > 1.0 ) v = 1.0;
      var hp = h/60.0;
      var c = v * s;
      var x = c*(1 - Math.abs((hp % 2) - 1));
      var rgb = [0,0,0];
    
      if ( 0<=hp && hp<1 ) rgb = [c, x, 0];
      if ( 1<=hp && hp<2 ) rgb = [x, c, 0];
      if ( 2<=hp && hp<3 ) rgb = [0, c, x];
      if ( 3<=hp && hp<4 ) rgb = [0, x, c];
      if ( 4<=hp && hp<5 ) rgb = [x, 0, c];
      if ( 5<=hp && hp<6 ) rgb = [c, 0, x];
    
      var m = v - c;
      rgb[0] += m;
      rgb[1] += m;
      rgb[2] += m;
    
      rgb[0] *= 255;
      rgb[1] *= 255;
      rgb[2] *= 255;
    
      rgb[0] = parseInt ( rgb[0] ); 
      rgb[1] = parseInt ( rgb[1] );
      rgb[2] = parseInt ( rgb[2] );  
    
      return rgb;
    }
    
    // http://stackoverflow.com/questions/369438/smooth-spectrum-for-mandelbrot-set-rendering
    // alex russel : http://stackoverflow.com/users/2146829/alex-russell
    
    function MapColor(i,r,c)
    {
        var di= i;
        var zn;
        var hue;
    
            zn = Math.sqrt(r + c);
            hue = di + 1.0 - Math.log(Math.log(Math.abs(zn))) / Math.log(2.0);  // 2 is escape radius
            hue = 0.95 + 20.0 * hue; // adjust to make it prettier
            // the hsv function expects values from 0 to 360
            while (hue > 360.0)
                hue -= 360.0;
            while (hue < 0.0)
                hue += 360.0;
    
            return hsv_to_rgb(hue, 0.8, 1.0);
    }
    
    0 讨论(0)
  • 2020-11-28 05:24

    This is the smooth color algorithm:

    Lets say you start with the complex number z0 and iterate n times until it escapes. Let the end point be zn.

    A smooth value would be

    nsmooth := n + 1 - Math.log(Math.log(zn.abs()))/Math.log(2)
    

    This only works for mandelbrot, if you want to compute a smooth function for julia sets, then use

    Complex z = new Complex(x,y);
    double smoothcolor = Math.exp(-z.abs());
    
    for(i=0;i<max_iter && z.abs() < 30;i++) {
        z = f(z);
        smoothcolor += Math.exp(-z.abs());
    }
    

    Then smoothcolor is in the interval (0,max_iter).

    Divide smoothcolor with max_iter to get a value between 0 and 1.

    To get a smooth color from the value:

    This can be called, for example (in Java):

    Color.HSBtoRGB(0.95f + 10 * smoothcolor ,0.6f,1.0f);
    

    since the first value in HSB color parameters is used to define the color from the color circle.

    0 讨论(0)
  • 2020-11-28 05:29

    Use the smooth coloring algorithm to calculate all of the values within the viewport, then map your palette from the lowest to highest value. Thus, as you zoom in and the higher values are no longer visible, the palette will scale down as well. With the same constants for n and B you will end up with a range of 0.0 to 1.0 for a fully zoomed out set, but at deeper zooms the dynamic range will shrink, to say 0.0 to 0.1 at 200% zoom, 0.0 to 0.0001 at 20000% zoom, etc.

    0 讨论(0)
  • 2020-11-28 05:30

    What's going on with the color mapping in that image is that it's using a 'log transfer function' on the index (according to documentation). How exactly it's doing it I still haven't figured out yet. The program that produced it uses a palette of 400 colors, so index ranges [0,399), wrapping around if needed. I've managed to get pretty close to matching it's behavior. I use an index range of [0,1) and map it like so:

        double value = Math.log(0.021 * (iteration + delta + 60)) + 0.72;
        value = value - Math.floor(value);
    

    It's kind of odd that I have to use these special constants in there to get my results to match, since I doubt they do any of that. But whatever works in the end, right?

    0 讨论(0)
  • 2020-11-28 05:31

    Seems simple to do by trial and error. Assume you can define HSV1 and HSV2 (hue, saturation, value) of the endpoint colors you wish to use (black and white; blue and yellow; dark red and light green; etc.), and assume you have an algorithm to assign a value P between 0.0 and 1.0 to each of your pixels. Then that pixel's color becomes

    (H2 - H1) * P + H1 = HP
    (S2 - S1) * P + S1 = SP
    (V2 - V1) * P + V1 = VP
    

    With that done, just observe the results and see how you like them. If the algorithm to assign P is continuous, then the gradient should be smooth as well.

    0 讨论(0)
  • 2020-11-28 05:33

    My eventual solution was to create a nice looking (and fairly large) palette and store it as a constant array in the source, then interpolate between indexes in it using the smooth coloring algorithm. The palette wraps (and is designed to be continuous), but this doesn't appear to matter much.

    0 讨论(0)
提交回复
热议问题