具有一般指数的 OpenGL ES GLSL Mandelbrot

Posted

技术标签:

【中文标题】具有一般指数的 OpenGL ES GLSL Mandelbrot【英文标题】:OpenGL ES GLSL Mandelbrot with general exponent 【发布时间】:2019-03-19 05:47:42 【问题描述】:

我已经成功地在 GLSL(OpenGL ES) 上实现了几个分形,但我似乎对指数为任意正数的 Mandelbrot 集的变化一无所获。

我在复极坐标中进行幂运算,但算法在某处有问题,因为 exponent = 2 出现了经典 Mandelbrot 集以外的其他东西。

目前的代码如下:

precision mediump float;

uniform sampler2D palette;
uniform float centerX;
uniform float centerY;
uniform float scale;
uniform float iterations;
uniform vec2 resolution;
uniform float exponent;
#define maxiter 65535

vec2 cplx_polar(vec2 z) 
    return vec2(length(z), atan(z.y,z.x));


vec2 cplx_polar_add(vec2 z1, vec2 z2) 
    //https://math.stackexchange.com/a/1365938
    return vec2(sqrt(z1.x*z1.x + z2.x*z2.x + 2.*z1.x*z2.x*cos(z2.y-z1.y)),
    z1.y+atan(z2.x*sin(z2.y-z1.y),(z1.x+z2.x*cos(z2.y-z1.y))));


vec2 exponentiate(vec2 z) 
    return pow(z.x, exponent)* vec2(cos(z.y), sin(z.y));


void main() 
    vec2 center = vec2(centerX, centerY);
    vec2 coord = vec2(gl_FragCoord.x, gl_FragCoord.y) / resolution;
    vec2 c = cplx_polar((coord - center) / scale);
    int j = 0;
    vec2 z = c;
    for(int i = 0; i<maxiter; i++) 
        if (float(i) >= iterations) break;
        j++;
        vec2 znew = cplx_polar_add(exponentiate(z), c);
        if(znew.x > 2.0) break;
        z = znew;
    
    gl_FragColor = texture2D(palette, vec2((j == int(iterations) ? 0.0 : float(j)) / iterations, 0.5));

main 函数中一定有一个错误,因为没有极坐标的简单 z = z ^ 2 + c 基本相同。为指数 = 2 生成的图像看起来像

虽然它应该看起来像

我很茫然。这可能是一件微不足道的事情。如有任何建议,我将不胜感激。

【问题讨论】:

【参考方案1】:

我不确定是否将极坐标计算用于如此简单的交互计算,这对我来说似乎有点矫枉过正。这是一个使用来自我的 FractalCanvas 应用程序的笛卡尔数学的解决方案。

Java 中的简单表达式是 pow(double f) return log().times(f).exp(); 。

我不认识您使用的语言,但这可以提供一些想法。

public vec2 pow(vec2 z, double f) 
    // log()
    double d = Math.log(Math.sqrt(z.x * z.x + z.y * z.y));
    z.x = Math.atan2(z.y, z.x);
    z.y = d;
    // times(f)
    z.x *= f;
    z.y *= f;
    // exp()
    double exp = Math.exp(z.x);
    z.x = Math.cos(z.y) * exp;
    z.y = Math.sin(z.y) * exp;
    return z;

顺便说一句,我强烈建议您不要在迭代循环的中间创建对象。创建和销毁它们需要有限的时间,并且循环可能会运行数十亿次来计算图像。当我从我的应用程序中删除此类创作时,我注意到了显着的加速。

【讨论】:

谢谢!该语言是 GLSL(用于直接 GPU 计算),polar 背后的想法是模糊地记住复杂指数最好使用极坐标中的 de Moivre 公式。这实际上也在这里使用,但更简单,并且不执行极坐标中的其他计算。

以上是关于具有一般指数的 OpenGL ES GLSL Mandelbrot的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL ES 学习 -- 渲染模式和GLSL

OPENGL ES 2.0 知识串讲 ——GLSL 语法(II)

OPENGL ES 2.0 知识串讲 ——OPENGL ES 详解I(绑定 SHADER)

OPENGL ES 2.0 知识串讲 ——GLSL 语法(III)

OPENGL ES 2.0 知识串讲 ——GLSL 语法(III)

OPENGL ES 2.0 知识串讲 ——GLSL 语法(II)