【问题标题】:basic fractal coloring problems基本分形着色问题
【发布时间】:2018-04-05 16:29:22
【问题描述】:

我正在努力让分形着色背后的数学变得更加舒适,并更好地理解着色算法。我是以下论文:

http://jussiharkonen.com/files/on_fractal_coloring_techniques%28lo-res%29.pdf

论文给出了每个函数的具体参数,但是当我使用相同的参数时,我的结果并不完全正确。我不知道会发生什么。

我正在使用迭代计数着色算法启动并使用以下 julia 集:

c = 0.5 + 0.25i and p = 2 

使用着色算法:

The coloring function simply returns the number of
elements in the truncated orbit divided by 20

还有调色板功能:

I(u) = k(u − u0),
where k = 2.5 and u0 = 0, was used.

调色板在 0 和 1 处为白色,并在中间插入黑色。

并遵循这个算法:

  1. 设置z0对应复平面中像素的位置。
  2. 通过迭代公式 zn = f(zn−1) 开始计算截断轨道 从 z0 直到 • |zn| > M,或 • n = Nmax, 其中 Nmax 是最大迭代次数。
  3. 使用着色和颜色索引函数,映射生成的截断 轨道到颜色索引值。
  4. 使用调色板函数确定像素的 RGB 颜色

使用这个我的代码如下所示:

float izoom = pow(1.001, zoom );

vec2 z = focusPoint + (uv * 4.0 - 2.0)  * 1.0 / izoom;

vec2 c = vec2(0.5f, 0.25f) ;


const float B = 2.0;
float l;

for( int i=0; i<100; i++ )
{
     z = vec2( z.x*z.x - z.y*z.y, 2.0*z.x*z.y ) + c;

     if( length(z)>10.0) break;
     l++;

}
float ind = basicindex(l);
vec4 col = color(ind);

并具有以下索引和着色功能:

float basicindex(float val){
    return val / 20.0;
}

vec4 color(float index){

    float r  = 2.5 * index;
    float g = r; 
    float b = g;
    vec3 v = 0.5 - 0.5 *  sin(3.14/2.0 + 3.14 * vec3(r, g, b));
    return vec4(1.0 - v, 1.0) ;

}

论文提供了以下图片: https://imgur.com/YIZMhaa

虽然我的代码生成: https://imgur.com/OrxdMsN

我通过使用 k = 1.0 而不是 2.5 得到了正确的结果,但是我更愿意了解为什么我的结果不正确。当将此扩展到平滑着色算法时,我的结果仍然不正确,所以我想先弄清楚这一点。

如果这不是此类问题的正确位置,请告诉我,我可以将其移至数学堆栈交换。我不确定哪个地方更合适。

【问题讨论】:

  • 两张图片在视觉上是相同的...
  • 另外,如果您了解您使用的语言,那就太好了。我不知道长度(z)是什么意思,复数半径?
  • 拍摄,对于“我的图像”,上传了 4 张图像。右边的那个是从白色到黑色,然后又变回白色的那个。将在几分钟内更新。
  • 这也是 glsl。长度只是向量 (sqrt(x * x +y * y)) 的大小,其中 x 是实部,y 是虚部。我相信这是复杂的半径
  • 是的,似乎需要进一步澄清。我几乎无法辨认出透视代码并识别它,更不用说语言了。但是,我对 Julia 集的摆弄得出的结论是,有无数种方法可以为它们着色,其中一些可能看起来很整洁。

标签: graphics glsl fractals


【解决方案1】:

您的图像完美地实现了论文中的图 3.3。您发布的另一张图片使用了不同的例程。

您的人物似乎在顶部有那一点透视代码,但删除它,它们应该是相同的。

如果您的反对意见是您使用代码的“0.5 - 0.5 * ...”部分设置的颜色极端。这使得最暗的黑色最初为 0.5,而在示例图像中,您尝试复制最暗的黑色应该是 1,最亮的白色应该是 0。

您正在使白度等于距 0.5 的距离


如果你忽略了分形,你会得到一堆可以在 0 和 1 之间归一化的值,并且你会以某些特定的方式为它们着色。显然,您要复制的图像在 0 和 1 之间是线性的,因此将黑色设置为 0.5 是不正确的。

o = {
    length : 500,
    width : 500,
    c : [.5, .25], // c = x + iy will be [x, y]
    maxIterate : 100,
    canvas : null
}

function point(pos, color){
    var c = 255 - Math.round((1 + Math.log(color)/Math.log(o.maxIterate)) * 255);
    c = c.toString(16);
    
    if (c.length == 1) c = '0'+c;
    o.canvas.fillStyle="#"+c+c+c;
    o.canvas.fillRect(pos[0], pos[1], 1, 1);
}

function conversion(x, y, R){
    var m = R / o.width;
    var x1 = m * (2 * x - o.width);
    var y2 = m * (o.width - 2 * y);
    return [x1, y2];
}

function f(z, c){
    return [z[0]*z[0] - z[1] * z[1] + c[0], 2 * z[0] * z[1] + c[1]];
}

function abs(z){
    return Math.sqrt(z[0]*z[0] + z[1]*z[1]);
}

function init(){
    var R = (1 + Math.sqrt(1+4*abs(o.c))) / 2,
        z, x, y, i;

    o.canvas = document.getElementById('a').getContext("2d");
    for (x = 0; x < o.width; x++){
        for (y = 0; y < o.length; y++){
            i = 0;
            z = conversion(x, y, R);
            while (i < o.maxIterate && abs(z) < R){
                z = f(z, o.c);
                if (abs(z) > R) break;
                i++;
            }
            

            if (i) point([x, y], i / o.maxIterate);
        }
    }
}

init();
&lt;canvas id="a" width="500" height="500"&gt;&lt;/canvas&gt;

通过:http://jsfiddle.net/3fnB6/29/

【讨论】:

  • 感谢您的评论。尽管它们非常接近,但这完全是一种不同的算法。该算法是朝着平滑着色迈出的一步,而不是原始迭代计数算法。正如您在我的图片中看到的那样,有明确定义的条带,而在您发布的图片中,条带要柔和得多。
  • 更具体地说,是“连续迭代计数”而不是“迭代计数”算法。这将影响输出的范围,这将对绘制的颜色产生影响。如果我使用这个算法,我的结果就不再像这张图片了。
  • 那么问题是你在哪里反弹值。那个 0.5 - 0.5 * ... 位将使两个极端都变白。所以你的 0 是白色的,你的 1 是白色的。正如您使黑色通常相等。
  • 是的,这就是我想要的。因为论文中使用的口感正是如此。
  • 哦,是的,这是有道理的。每次迭代都是一个离散值,因此它等于边界的点最终将是一个分数。因此,与其说是 22 次迭代,不如说它可能需要 21.x 来获得边界。但是由于公式的离散性,这些信息丢失了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多