首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用LOVE2d在GLSL中通过着色器设置Mandelbrot呈现一个圆,而不是分形

用LOVE2d在GLSL中通过着色器设置Mandelbrot呈现一个圆,而不是分形
EN

Stack Overflow用户
提问于 2016-01-07 16:08:30
回答 2查看 582关注 0票数 1

我试着用GLSL渲染一个Mandelbrot集,但我得到的只是一个完整的圆圈.我已经检查了很多数学,我根本找不到错误,所以我想可能是语义问题。

有人能看出是怎么回事吗?

还有,有人能给我关于组织、结构等方面的见解吗?我正在努力学习正确的编码,但很难找到关于造型的材料。

这个着色器可以应用在任何图像上。

这个想法很简单(你可以跳过这个):

  • 如果z没有发散,checkConvergence返回true (即abs(z) <4 )
    • sumSquare返回复乘法(z.r,z.i)*(z.r,z.i) - (c.r,c.i),其中K.r = Re(K)和K.i = Im(K)
    • 迭代是实际的算法:它保持z的平方,直到它发散或达到最大迭代次数(tol)。
    • clr是参数化函数,它返回依赖于n的RGB数组。
    • 最后,效果是魔术应该发生的地方,通过做两件事:
      • 它获取像素的坐标(GLSL归一化为间隔(0,1),并将其规范化为Mandelbrot集大小(-2 )。
      • 它对坐标进行迭代,调用clr。

代码语言:javascript
复制
GLSLShader = love.graphics.newShader[[
    vec2 c = vec2(1.0, 0.0);
    int tol = 100;

    vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
    vec4 white = vec4(1.0, 1.0, 1.0, 1.0);

    bool checkConvergence(vec2 z) {
      return (z[0]*z[0] + z[1]*z[1] < 4);
    }

    vec2 sumSquare(vec2 z) {
      return vec2(z[0]*z[0] - z[1]*z[1] - c[0], 2 * z[0] * z[1] - c[1]);
    }

    int iterate(vec2 z) {
      int n = 0;
      while (checkConvergence(z) && (n < tol)) {
        vec2 z =  sumSquare(z);
        n = n + 1;
      }
      return n;
    }

    vec4 clr(int n){
      if(n == tol){return vec4(0.0,0.0,0.0,1.0);}

      int r, g, b;
      r = int(255*n + 47*(1-n));
      g = int(180*n + 136*(1-n));
      b = int(38*n + 255*(1-n));

      if (r > 255) {r = 255;}
      else{ 
        if(r<0){r = 0;}
      }

      if (g > 255) {g = 255;}
      else{
        if(g<0){g = 0;}
      }

      if (b > 255) {b = 255;}
      else{
        if(b<0){b = 0;}
      }

      return vec4(r, g, b, 1.0);

    }

    vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords){
      vec2 z = vec2(texture_coords.x*4-2, texture_coords.y*4-2);

      return clr(iterate(z));
    }
  ]]

更新

我试过一些来自“风向标”的建议:

  • 添加C,而不是减去它;
  • 开始z为(0.0,0.0),并将迭代的起点以C形式传递;

但一切都无济于事,我还是有一个圆圈。我也尝试使用更多的迭代。

我尽量简化编码,而不做太多改变。

我在clr函数中添加了一个条件,如果n小于0或大于1,则返回绿色。奇怪的是,圆圈是黑色的,屏幕的其余部分是白色的,但我看不出白色的来源(因为clr从不返回0

代码语言:javascript
复制
    vec2 c = vec2(0.0, 0.0);
    int tol = 1000;

    vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
    vec4 white = vec4(1.0, 1.0, 1.0, 1.0);
    vec4 green = vec4(0.0, 1.0, 0.0, 1.0);

    int iterate(vec2 z) {
      int n = 0;

      while ( (z[0]*z[0] + z[1]*z[1] < 4) && (n < tol) ) {
        vec2 z =  vec2( z[0]*z[0] - z[1]*z[1]  + c[0], 2 * z[0] * z[1] + c[1] );
        n = n + 1;
      }

      return n;
    }

    vec4 clr(int n){
        n = n / tol;

        if(n == 1){return black;}
        if(n > 1 || n < 0){return green;}

        int r, g, b;
        r = int(255*n + 47*(1-n));
        g = int(180*n + 136*(1-n));
        b = int(38*n + 255*(1-n));

        return vec4(r, g, b, 1.0);

      }

    vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords){
      vec2 z = vec2(texture_coords.x*4-2, texture_coords.y*4-2);

      return clr(iterate(z));
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-01-07 16:37:13

迭代的起点应该作为向量c传递,而z从{0.0.0.0}开始。

正如您在set中所发现的

复数c是Mandelbrot集的一部分,如果当开始于z=0并反复应用迭代z=z 2+c时,z的绝对值无论得到多大,都是有界的。

您对颜色使用vec4,但不是使用浮点数,而是在代码中使用整数值计算RGB组件。您应该将每个组件的浮动和规范化转换为(0.01.0)范围。我试图更正您的代码,但恐怕我不太了解lua或love2d,也不能使用texture_coords,所以我使用了screen_coords。我所能做的就是:

代码语言:javascript
复制
function love.load()
    GLSLShader = love.graphics.newShader[[

        vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
        vec4 white = vec4(1.0, 1.0, 1.0, 1.0);
        int max_iter = 1024;

        vec4 clr(int n){
            if(n == max_iter){return black;}

            float m = float(n)/float(max_iter);
            float r = float(mod(n,256))/32;
            float g = float(128 - mod(n+64,127))/255;
            float b = float(127 + mod(n,64))/255;

            if (r > 1.0) {r = 1.0;}
            else{ 
                if(r<0){r = 0;}
            }

            if (g > 1.0) {g = 1.0;}
            else{
                if(g<0){g = 0;}
            }

            if (b > 1.0) {b = 1.0;}
            else{
                if(b<0){b = 0;}
            }
            return vec4(r, g, b, 1.0);
        }

        vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords){

            vec2 c = vec2((screen_coords[0]-500)/200,(screen_coords[1]-300)/200);
            vec2 z = vec2(0.0,0.0);
            vec2 zn = vec2(0.0,0.0);
            int n_iter = 0;
            while ( (z[0]*z[0] + z[1]*z[1] < 4) &&  (n_iter < max_iter) ) {
                zn[0] = z[0]*z[0] - z[1]*z[1] + c[0];
                zn[1] = 2*z[0]*z[1] + c[1];
                z[0] = zn[0];
                z[1] = zn[1];
                n_iter++;
            }
            return clr(n_iter);
        }
    ]]
end

function love.draw()

    love.graphics.setShader(GLSLShader)
    love.graphics.rectangle('fill', 0,0,800,600)
    love.graphics.setShader()
end

这给了我这个输出:

票数 2
EN

Stack Overflow用户

发布于 2020-01-09 03:03:01

代码语言:javascript
复制
while ( ... ) {
    vec2 z = ...
}

去掉vec2,您将在每次迭代中声明一个新变量。此外,遵循@Bob__的一些建议(即迭代(Vec2 c))。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34659850

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档