Skip to main content

用ShaderToy实现牛顿迭代法分形图像

Feishiko
Author
Feishiko
Programming Avali
Table of Contents

牛顿迭代法
#

可用来收敛到一个点,通过不停的迭代,求方程的近似根。

这是一个简单的曲线,如果我们要用牛顿法求f(x) = 0,第一步:那么首先需要先随便在横坐标上确认一个点。

然后第二步:做垂直,与曲线有一个交点,然后第三步:做这个交点的切线,这个切线再与x轴有一个交点,重复第一步,这样就能无限趋近于f(x) = 0

于是我们可以得到这样一个公式,$x0$是第一步随便确认的点,$x1$是新的于x轴的交点

牛顿迭代公式: $x1 = x0 - \frac{f(x0)}{f’(x0)}$

Shader部分
#

const int iter = 100;//迭代次数

//复数乘法运算
vec2 cmul(vec2 c1, vec2 c2) {
    return vec2(c1.x*c2.x - c1.y*c2.y, c1.y*c2.x + c1.x*c2.y);
}

//复数除法运算
vec2 cdiv(vec2 c1, vec2 c2) {
    float d = dot(c2, c2);
    //考虑到分母为0的情况
    if(d == 0.) return c1;
    else return vec2((c1.x*c2.x + c1.y*c2.y)/d, (c1.y*c2.x - c1.x*c2.y)/d);
}

//迭代
int itt(vec2 x0) {
   for(int i = 0; i <= iter; i++) {
    //x1 = x0 - (x0^3 - 1)/3*x0, 也就是x1 = x0 - f(x)/f'(x)
       vec2 x1 = x0 - cdiv(cmul(cmul(x0, x0), x0) - 1., 3.*x0);
       //当x1与x0无限接近的时候,返回当前的迭代次数
       if(distance(x1, x0) < .0000001) {
           return i;
       }
       x0 = x1;
   }
   //不满足的话,返回最大的迭代次数
   return iter;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    //让uv坐标中心设置在中心
    vec2 uv = fragCoord/iResolution.xy - .5;
    
    //根据不同迭代次数显示灰度
    vec3 col = vec3(float(itt(uv))/float(iter));

    // Output to screen
    fragColor = vec4(col,1.0);
}

:我第一次写的时候在main里面写for,然后如果无限接近就break,但是这种方法貌似有一些问题,我最后得到的图像是二值化的。