实现 Mandelbrot 集的平滑着色
Implementing smooth coloring of Mandelbrot set
重新创建我为 Mandelbrot 集着色的方式我很难在 JavaScript 中实现它。我目前使用的是常见的"escape time"算法:
for(px = 0; px < a; px+=scale){
for(py = 0; py < b; py+=scale){
x0 = panX + px/zm;
y0 = panY + py/zm;
var x = 0;
var y = 0;
var i = 0;
var xtemp;
var xSquare = x*x;
var ySquare = y*y;
while (x*x + y*y <= 4 && i < maxI) {
xtemp = x*x - y*y + x0
y = 2*x*y + y0
x = xtemp
i += 1;
}
//coloring
var shade = pallete.colourAt(i);
c.fillStyle = "#"+shade;
c.fillRect(px,py,scale, scale);
}
}
这是 full code. I want to implement the part above to this pseudo code found at Wikipedia。
For each pixel (Px, Py) on the screen, do: { x0 = scaled x coordinate
of pixel (scaled to lie in the Mandelbrot X scale (-2.5, 1)) y0 =
scaled y coordinate of pixel (scaled to lie in the Mandelbrot Y scale
(-1, 1)) x = 0.0 y = 0.0 iteration = 0 max_iteration = 1000 // Here
N=2^8 is chosen as a reasonable bailout radius. while ( xx + yy <=
(1 << 16) AND iteration < max_iteration ) { xtemp = xx - yy + x0 y =
2*xy + y0 x = xtemp iteration = iteration + 1 } // Used to avoid
floating point issues with points inside the set. if ( iteration <
max_iteration ) { // sqrt of inner term removed using log
simplification rules. log_zn = log( xx + y*y ) / 2 nu = log( log_zn /
log(2) ) / log(2) // Rearranging the potential function. // Dividing
log_zn by log(2) instead of log(N = 1<<8) // because we want the
entire palette to range from the // center to radius 2, NOT our
bailout radius. iteration = iteration + 1 - nu } color1 =
palette[floor(iteration)] color2 = palette[floor(iteration) + 1] //
iteration % 1 = fractional part of iteration. color =
linear_interpolate(color1, color2, iteration % 1) plot(Px, Py, color)
}
为此:
for(px = 0; px < a; px+=scale){
for(py = 0; py < b; py+=scale){
//zoom factors
x0 = panX + px/zm;
y0 = panY + py/zm;
var x = 0;
var y = 0;
var i = 0;
var xtemp;
var xSquare = x*x;
var ySquare = y*y;
while (x*x + y*y <= 4 && i < maxI) {
/*ticks++
xtemp = x*x - y*y + x0
y = 2*x*y + y0
x = xtemp
i = i + 1*/
y = x*y;
y += y;
y += y0;
x = xSquare - ySquare + x0;
xSquare = Math.pow(x,2);
ySquare = Math.pow(y,2);
i += 1;
}
if ( i < maxI ) {
log_zn = Math.log( x*x + y*y ) / 2
nu = Math.log( log_zn / Math.log(2) ) / Math.log(2)
i += 1 - nu
}
color1 = palette.colourAt(Math.floor(i))
color2 = palette.colourAt(Math.floor(i) + 1)
/*****************
I dont know how to implement this.....
color = linear_interpolate(color1, color2, iteration % 1)
*****************/
c.fillStyle = color
c.fillRect(px,py,scale, scale);
}
}
但是不知道这部分伪代码如何实现:
color1 = palette[floor(iteration)]
color2 = palette[floor(iteration) + 1]
// iteration % 1 = fractional part of iteration.
color = linear_interpolate(color1, color2, iteration % 1)
plot(Px, Py, color)
有人可以帮助我理解并提供实现方法吗?
linear_interpolate 函数应该根据线性函数 y = mx + b 计算两种颜色之间的颜色。
要将线性函数应用于颜色,y 是输出颜色,m 是两种颜色之间的差异,b 是起始颜色,x 是介于 0 和 1 之间的值。
当 x 为 0 时,此函数输出起始颜色。当x为1时,该函数输出结束颜色。
要进行此计算,我们需要三个数字形式的颜色。如果您需要使用十六进制字符串,则必须将它们拆分并将每两个字符解析为 16 位数字。我将使用已经是数字形式的调色板,因为它更容易。
这是我的三种调色板。我不建议你使用这些颜色,它只是为了演示:
let palette = [{r:255,g:0,b:0},{r:0,g:255,b:0},{r:0,g:0,b:0}]
第一个函数接受迭代,它可能不是整数,可能大于1。它接受迭代的底数,把它变成数组索引必须是的整数。然后用迭代的余数除以 1 得到 0 到 1 之间的数字。
function interpolation(iteration) {
let color1 = palette[Math.floor(iteration)];
let color2 = palette[Math.floor(iteration) + 1];
return linear_interpolate(color1, color2, iteration % 1);
}
现在我们需要创建线性插值函数,它必须将线性函数应用于每个颜色通道,并使用 floor 将它们变成一个整数。我让它在 rgb() 中返回 css 颜色,但您可以将其转换为十六进制。
function linear_interpolate(color1, color2, ratio) {
let r = Math.floor((color2.r - color1.r) * ratio + color1.r);
let g = Math.floor((color2.g - color1.g) * ratio + color1.g);
let b = Math.floor((color2.b - color1.b) * ratio + color1.b);
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
这是代码阴影矩形:https://jsfiddle.net/q7kLszud/
重新创建我为 Mandelbrot 集着色的方式我很难在 JavaScript 中实现它。我目前使用的是常见的"escape time"算法:
for(px = 0; px < a; px+=scale){
for(py = 0; py < b; py+=scale){
x0 = panX + px/zm;
y0 = panY + py/zm;
var x = 0;
var y = 0;
var i = 0;
var xtemp;
var xSquare = x*x;
var ySquare = y*y;
while (x*x + y*y <= 4 && i < maxI) {
xtemp = x*x - y*y + x0
y = 2*x*y + y0
x = xtemp
i += 1;
}
//coloring
var shade = pallete.colourAt(i);
c.fillStyle = "#"+shade;
c.fillRect(px,py,scale, scale);
}
}
这是 full code. I want to implement the part above to this pseudo code found at Wikipedia。
For each pixel (Px, Py) on the screen, do: { x0 = scaled x coordinate of pixel (scaled to lie in the Mandelbrot X scale (-2.5, 1)) y0 = scaled y coordinate of pixel (scaled to lie in the Mandelbrot Y scale (-1, 1)) x = 0.0 y = 0.0 iteration = 0 max_iteration = 1000 // Here N=2^8 is chosen as a reasonable bailout radius. while ( xx + yy <= (1 << 16) AND iteration < max_iteration ) { xtemp = xx - yy + x0 y = 2*xy + y0 x = xtemp iteration = iteration + 1 } // Used to avoid floating point issues with points inside the set. if ( iteration < max_iteration ) { // sqrt of inner term removed using log simplification rules. log_zn = log( xx + y*y ) / 2 nu = log( log_zn / log(2) ) / log(2) // Rearranging the potential function. // Dividing log_zn by log(2) instead of log(N = 1<<8) // because we want the entire palette to range from the // center to radius 2, NOT our bailout radius. iteration = iteration + 1 - nu } color1 = palette[floor(iteration)] color2 = palette[floor(iteration) + 1] // iteration % 1 = fractional part of iteration. color = linear_interpolate(color1, color2, iteration % 1) plot(Px, Py, color) }
为此:
for(px = 0; px < a; px+=scale){
for(py = 0; py < b; py+=scale){
//zoom factors
x0 = panX + px/zm;
y0 = panY + py/zm;
var x = 0;
var y = 0;
var i = 0;
var xtemp;
var xSquare = x*x;
var ySquare = y*y;
while (x*x + y*y <= 4 && i < maxI) {
/*ticks++
xtemp = x*x - y*y + x0
y = 2*x*y + y0
x = xtemp
i = i + 1*/
y = x*y;
y += y;
y += y0;
x = xSquare - ySquare + x0;
xSquare = Math.pow(x,2);
ySquare = Math.pow(y,2);
i += 1;
}
if ( i < maxI ) {
log_zn = Math.log( x*x + y*y ) / 2
nu = Math.log( log_zn / Math.log(2) ) / Math.log(2)
i += 1 - nu
}
color1 = palette.colourAt(Math.floor(i))
color2 = palette.colourAt(Math.floor(i) + 1)
/*****************
I dont know how to implement this.....
color = linear_interpolate(color1, color2, iteration % 1)
*****************/
c.fillStyle = color
c.fillRect(px,py,scale, scale);
}
}
但是不知道这部分伪代码如何实现:
color1 = palette[floor(iteration)]
color2 = palette[floor(iteration) + 1]
// iteration % 1 = fractional part of iteration.
color = linear_interpolate(color1, color2, iteration % 1)
plot(Px, Py, color)
有人可以帮助我理解并提供实现方法吗?
linear_interpolate 函数应该根据线性函数 y = mx + b 计算两种颜色之间的颜色。 要将线性函数应用于颜色,y 是输出颜色,m 是两种颜色之间的差异,b 是起始颜色,x 是介于 0 和 1 之间的值。 当 x 为 0 时,此函数输出起始颜色。当x为1时,该函数输出结束颜色。
要进行此计算,我们需要三个数字形式的颜色。如果您需要使用十六进制字符串,则必须将它们拆分并将每两个字符解析为 16 位数字。我将使用已经是数字形式的调色板,因为它更容易。
这是我的三种调色板。我不建议你使用这些颜色,它只是为了演示:
let palette = [{r:255,g:0,b:0},{r:0,g:255,b:0},{r:0,g:0,b:0}]
第一个函数接受迭代,它可能不是整数,可能大于1。它接受迭代的底数,把它变成数组索引必须是的整数。然后用迭代的余数除以 1 得到 0 到 1 之间的数字。
function interpolation(iteration) {
let color1 = palette[Math.floor(iteration)];
let color2 = palette[Math.floor(iteration) + 1];
return linear_interpolate(color1, color2, iteration % 1);
}
现在我们需要创建线性插值函数,它必须将线性函数应用于每个颜色通道,并使用 floor 将它们变成一个整数。我让它在 rgb() 中返回 css 颜色,但您可以将其转换为十六进制。
function linear_interpolate(color1, color2, ratio) {
let r = Math.floor((color2.r - color1.r) * ratio + color1.r);
let g = Math.floor((color2.g - color1.g) * ratio + color1.g);
let b = Math.floor((color2.b - color1.b) * ratio + color1.b);
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
这是代码阴影矩形:https://jsfiddle.net/q7kLszud/