简体   繁体   English

Mandelbrot 平滑着色问题

[英]Issue with Mandelbrot smooth coloring

I implemented the regular algorithm to display the Mandelbrot set and colour it, and now I'm working on the smooth colouring features using a 255 colourmap.我实现了常规算法来显示 Mandelbrot 集并为其着色,现在我正在使用 255 色图处理平滑着色功能。

This part is already well documented online (and even on this forum) and I choose the most popular way with the renormalization of the escape:这部分已经在网上(甚至在这个论坛上)有很好的记录,我选择了最流行的转义重整化方式:

 function setup() { createCanvas(500, 500); background(0); pixelDensity(1); noLoop(); } function draw() { // Mandelbrot const A = [ [-2, 1], [-1.5, 1.5] ]; mandelbrot(A, 18, colormap); } /* ################## */ /* ### Mandelbrot ### */ /* ################## */ function mandelbrot(A, K, colormap) { loadPixels(); // Loop through all area point for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { // Get point coordinates const c = new Complex( map(x, 0, width, A[0][0], A[0][1]), map(y, 0, height, A[1][0], A[1][1]) ); let R = max(c.abs(), 2); let z = new Complex(0, 0); let ic = color(0); for (let i = 0; i < K; i++) { // Next sequence term z.pow2(); z.add(c); if (z.abs() > R) { // Anti-aliasing (smooth) color index from the map let mu = i - log(log(z.abs())) / log(R); let mapIndex = int(colormap.length * mu / K); // Retieve color from map ic = colormap[mapIndex]; break; } } // Color pixel const index = (x + y * width) * 4; pixels[index] = red(ic); pixels[index + 1] = green(ic); pixels[index + 2] = blue(ic); pixels[index + 3] = 255; } } updatePixels(); } /* ############### */ /* ### Complex ### */ /* ############### */ class Complex { constructor(r, im) { this.r = r; this.im = im; } add(c) { this.r += c.r; this.im += c.im; } pow2() { let r = this.r; let im = this.im; this.r = r ** 2 - im ** 2; this.im = 2 * r * im; } abs() { return sqrt(this.r ** 2 + this.im ** 2) } } /* ################ */ /* ### ColorMap ### */ /* ################ */ const colormap = [ [0, 0, 0], [96, 148, 140], [92, 140, 136], [92, 132, 128], [88, 124, 124], [88, 116, 116], [84, 112, 112], [84, 104, 104], [80, 96, 100], [80, 88, 92], [76, 80, 88], [76, 72, 80], [72, 64, 76], [68, 56, 68], [88, 60, 80], [112, 64, 96], [136, 68, 108], [160, 72, 124], [184, 76, 136], [208, 80, 152], [232, 88, 168], [216, 104, 176], [196, 124, 188], [180, 140, 196], [160, 160, 208], [140, 176, 220], [124, 196, 228], [104, 212, 240], [84, 232, 252], [88, 232, 248], [96, 232, 240], [104, 232, 232], [112, 232, 224], [120, 232, 216], [128, 232, 208], [136, 232, 200], [140, 232, 192], [148, 232, 184], [156, 232, 176], [164, 232, 168], [172, 232, 160], [180, 232, 152], [188, 232, 144], [176, 232, 152], [160, 232, 160], [144, 232, 168], [128, 232, 180], [124, 228, 176], [120, 220, 168], [112, 212, 160], [108, 204, 152], [104, 196, 144], [92, 168, 124], [76, 140, 104], [60, 112, 84], [48, 84, 64], [32, 56, 44], [16, 28, 24], [0, 0, 0], [0, 0, 0], [4, 4, 4], [4, 4, 4], [8, 8, 8], [8, 8, 8], [12, 12, 12], [12, 12, 12], [16, 16, 16], [16, 16, 16], [20, 20, 20], [20, 20, 20], [24, 24, 24], [24, 24, 24], [28, 28, 28], [28, 28, 28], [32, 32, 32], [32, 32, 32], [36, 36, 36], [36, 36, 36], [40, 40, 40], [40, 40, 40], [44, 44, 44], [44, 44, 44], [48, 48, 48], [48, 48, 48], [52, 52, 52], [52, 52, 52], [56, 56, 56], [56, 56, 56], [60, 60, 60], [60, 60, 60], [64, 64, 64], [64, 64, 64], [68, 68, 68], [68, 68, 68], [72, 72, 72], [72, 72, 72], [76, 76, 76], [76, 76, 76], [80, 80, 80], [84, 84, 84], [84, 84, 84], [88, 88, 88], [88, 88, 88], [92, 92, 92], [92, 92, 92], [96, 96, 96], [96, 96, 96], [100, 100, 100], [100, 100, 100], [104, 104, 104], [104, 104, 104], [108, 108, 108], [108, 108, 108], [112, 112, 112], [112, 112, 112], [116, 116, 116], [116, 116, 116], [120, 120, 120], [120, 120, 120], [124, 124, 124], [124, 124, 124], [128, 128, 128], [128, 128, 128], [132, 132, 132], [132, 132, 132], [136, 136, 136], [136, 136, 136], [140, 140, 140], [140, 140, 140], [144, 144, 144], [144, 144, 144], [148, 148, 148], [148, 148, 148], [152, 152, 152], [152, 152, 152], [156, 156, 156], [156, 156, 156], [160, 160, 160], [160, 160, 160], [164, 164, 164], [168, 168, 168], [168, 168, 168], [172, 172, 172], [172, 172, 172], [176, 176, 176], [176, 176, 176], [180, 180, 180], [180, 180, 180], [184, 184, 184], [184, 184, 184], [188, 188, 188], [188, 188, 188], [192, 192, 192], [192, 192, 192], [196, 196, 196], [196, 196, 196], [200, 200, 200], [200, 200, 200], [204, 204, 204], [204, 204, 204], [208, 208, 208], [208, 208, 208], [212, 212, 212], [212, 212, 212], [216, 216, 216], [216, 216, 216], [220, 220, 220], [220, 220, 220], [224, 224, 224], [224, 224, 224], [228, 228, 228], [228, 228, 228], [232, 232, 232], [232, 232, 232], [236, 236, 236], [236, 236, 236], [240, 240, 240], [240, 240, 240], [244, 244, 244], [244, 244, 244], [248, 248, 248], [252, 252, 252], [252, 252, 228], [252, 252, 204], [252, 252, 180], [252, 252, 152], [252, 252, 128], [252, 252, 104], [252, 252, 80], [252, 252, 52], [244, 240, 56], [236, 228, 60], [228, 212, 64], [220, 200, 72], [212, 184, 76], [204, 172, 80], [196, 160, 88], [188, 144, 92], [176, 132, 96], [168, 116, 100], [160, 104, 108], [152, 92, 112], [144, 76, 116], [136, 64, 124], [128, 48, 128], [120, 36, 132], [108, 20, 140], [196, 184, 220], [188, 176, 212], [180, 168, 204], [172, 160, 192], [160, 148, 184], [152, 140, 172], [144, 132, 164], [132, 120, 152], [124, 112, 144], [116, 104, 136], [104, 92, 124], [96, 84, 116], [88, 76, 104], [76, 64, 96], [68, 56, 84], [60, 48, 76], [48, 36, 64], [52, 36, 72], [60, 32, 84], [68, 32, 92], [76, 28, 104], [80, 28, 112], [88, 24, 124], [96, 20, 136], [104, 20, 144], [108, 16, 156], [116, 16, 164], [124, 12, 176], [132, 8, 188], [136, 8, 168], [140, 8, 144], [144, 8, 120], [148, 8, 96], [152, 8, 72], [156, 8, 48], [160, 4, 24], [156, 16, 36], [152, 32, 48], [144, 48, 60], [140, 60, 72], [136, 76, 84], [128, 92, 96], [124, 108, 108], [120, 120, 120], [112, 136, 132], [108, 152, 144], [100, 168, 156], [100, 164, 152], [96, 156, 148] ];
 <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

Despite this formula, I can still see the bands/gap of colours in the visualization and can't figure out where my issue come from.尽管有这个公式,我仍然可以在可视化中看到颜色的条带/间隙,并且无法弄清楚我的问题来自哪里。

PS: I removed the "+ 1" of the log formula the avoid out-of-bound when looking for the colour in the colourmap. PS:我删除了日志公式的“+ 1”,以避免在颜色图中查找颜色时越界。

There were two deviations from the linked algorithm that were causing issues:导致问题的链接算法有两个偏差:

  1. You were setting the escape radius to a low value (~2) in some cases在某些情况下,您将逃生半径设置为较低的值 (~2)
  2. You were dividing by the log(R) which was not correct.您除以不正确的log(R) You should divide by log(2)你应该除以log(2)

Additionally some of the banding was because you were still using a discrete color map.此外,一些条带是因为您仍在使用离散颜色 map。 You could use a continuous mapping of value -> hue, but if you want a particular cycle of colors, you can use lerpColor() to smoothly transition from one color and the next based on the difference between the continuous/smooth value and the current index.您可以使用值 -> 色调的连续映射,但如果您想要 colors 的特定循环,您可以使用lerpColor()根据连续/平滑值与当前值之间的差异从一种颜色平滑过渡到另一种颜色指数。

 function setup() { createCanvas(500, 500); background(0); pixelDensity(1); noLoop(); } function draw() { // Mandelbrot const A = [ [-2, 1], [-1.5, 1.5] ]; mandelbrot(A, 18, colormap); } /* ################## */ /* ### Mandelbrot ### */ /* ################## */ function mandelbrot(A, K, colormap) { loadPixels(); // Allowing the escape radius to be too small (ie 2) leads to bad results const R = 4; // Loop through all area point for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { // Get point coordinates const c = new Complex( map(x, 0, width, A[0][0], A[0][1]), map(y, 0, height, A[1][0], A[1][1]) ); // let R = max(c.abs(), 2); let z = new Complex(0, 0); let ic = color(0); for (let i = 0; i < K; i++) { // Next sequence term z.pow2(); z.add(c); if (z.abs() > R) { // Anti-aliasing (smooth) color index from the map // / log(R) is incorrect let mu = i - log(log(z.abs())) / log(2); let mapIndex = floor((colormap.length - 1) * mu / K); let interval = (colormap.length - 1) * mu / K - mapIndex; if (mapIndex < colormap.length - 1) { // lerp between the current color and the next color by interval ic = lerpColor(color(...colormap[mapIndex]), color(...colormap[mapIndex + 1]), interval); } else { // Retieve color from map ic = colormap[mapIndex]; } break; } } // Color pixel const index = (x + y * width) * 4; pixels[index] = red(ic); pixels[index + 1] = green(ic); pixels[index + 2] = blue(ic); pixels[index + 3] = 255; } } updatePixels(); } /* ############### */ /* ### Complex ### */ /* ############### */ class Complex { constructor(r, im) { this.r = r; this.im = im; } add(c) { this.r += c.r; this.im += c.im; } pow2() { let r = this.r; let im = this.im; this.r = r ** 2 - im ** 2; this.im = 2 * r * im; } abs() { return sqrt(this.r ** 2 + this.im ** 2) } } /* ################ */ /* ### ColorMap ### */ /* ################ */ const colormap = [ [96, 148, 140], [68, 56, 68], [232, 88, 168], [84, 232, 252], [0, 0, 0], [252, 252, 252], [252, 252, 52], [196, 184, 220], [48, 36, 64], [160, 4, 24], [96, 156, 148] ];
 <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM