使用两个浮点数的 Webgl 双精度模拟没有效果

Max*_*ari 6 javascript opengl double mandelbrot webgl

在玩弄一代时Mandelbrot setWebGl我不可避免地发现了OpenGl32 位的小精度float然而,当我发现这篇很棒的文章时,新的希望诞生了。
我小心翼翼地从上述源代码中获取了函数,并double 在 JS 端添加了解构。

据我了解,JSdoubles对于浮点数有 64 位,所以我的想法是在 JS 端计算一些准备数据,将其作为浮点数对发送到 GPU,然后继续进行 mandelbrot 循环。

可悲的是,最后我看到结果图像的差异几乎为零,而且我真的不知道我的失败点在哪里。

JS:

function doubleToFloat(d) {
  return new Float32Array([d])[0];
};
function splitDouble(dbl) { //splits JS number to array of 2 32bit floats
    var arr = [];
    arr[0] = doubleToFloat(dbl);
    arr[1] = doubleToFloat(dbl - arr[0]);
    //console.log(dbl, arr);
    arr = new Float32Array(arr);
    dlog(dbl,arr);
    return arr;
};

///Somewhere inside rendering function - binding data to webGl

var planeH = 4/settings.magnification;
var planeMult = planeH/canvasH; //screen to complex plane dimensions multiplier
var planeW = canvasW*planeMult;
var planeWOffset = planeW/2; //offset to align plane's 0:0 at screen's center
var planeHOffset = planeH/2;
bindUniforms(program, {
    WIDTH: canvasW,
    HEIGHT: canvasH,
    CENTER_X: {value:splitDouble(settings.centerX),type:"2fv"},
    CENTER_Y: {value:splitDouble(settings.centerY),type:"2fv"},
    MAGNIFICATION: settings.magnification,
    PLANE_W_OFFSET: {value:splitDouble(planeWOffset),type:"2fv"},
    PLANE_H_OFFSET: {value:splitDouble(planeHOffset),type:"2fv"}, 
    PLANE_MULT: {value:splitDouble(planeMult),type:"2fv"},                           
    uSampler: {value:texIndex,type:"1i"}
});

--> sent to webGL
Run Code Online (Sandbox Code Playgroud)

WebGL(片段着色器):

#ifdef GL_FRAGMENT_PRECISION_HIGH
   precision highp float;
#else
   precision mediump float;
#endif
   precision mediump int;

const int ITER_LIMIT = <%=iterLimit%>;
uniform float MAGNIFICATION;
uniform vec2 CENTER_X;
uniform vec2 CENTER_Y;
uniform float WIDTH;
uniform float HEIGHT;
uniform vec2 PLANE_W_OFFSET;
uniform vec2 PLANE_H_OFFSET;
uniform vec2 PLANE_MULT;
uniform sampler2D uSampler;
const float threshold = 10.0;

///Double emulation functions///////////////
vec2 ds(float a) {
    vec2 z;
    z.x = a;
    z.y = 0.0;
    return z;
}

vec2 ds_add(vec2 dsa, vec2 dsb) {
    vec2 dsc;
    float t1, t2, e;

    t1 = dsa.x + dsb.x;
    e = t1 - dsa.x;
    t2 = ((dsb.x - e) + (dsa.x - (t1 - e))) + dsa.y + dsb.y;

    dsc.x = t1 + t2;
    dsc.y = t2 - (dsc.x - t1);
    return dsc;
}



vec2 ds_mult(vec2 dsa, vec2 dsb) {
    vec2 dsc;
    float c11, c21, c2, e, t1, t2;
    float a1, a2, b1, b2, cona, conb, split = 8193.;

    cona = dsa.x * split;
    conb = dsb.x * split;
    a1 = cona - (cona - dsa.x);
    b1 = conb - (conb - dsb.x);
    a2 = dsa.x - a1;
    b2 = dsb.x - b1;

    c11 = dsa.x * dsb.x;
    c21 = a2 * b2 + (a2 * b1 + (a1 * b2 + (a1 * b1 - c11)));

    c2 = dsa.x * dsb.y + dsa.y * dsb.x;

    t1 = c11 + c2;
    e = t1 - c11;
    t2 = dsa.y * dsb.y + ((c2 - e) + (c11 - (t1 - e))) + c21;

    dsc.x = t1 + t2;
    dsc.y = t2 - (dsc.x - t1);

    return dsc;
}

vec2 ds_sub(vec2 dsa, vec2 dsb) {
    return ds_add(dsa, ds_mult(ds(-1.0),dsb));
}
///End of Double emulation functions/////////

///Inside main()////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

float sqThreshold = threshold*threshold;

vec2 X = ds_mult(ds(gl_FragCoord.x),PLANE_MULT);
vec2 Y = ds_mult(ds(gl_FragCoord.y),PLANE_MULT); 

vec2 planeX = ds_add(ds_sub(X,PLANE_W_OFFSET),CENTER_X);
vec2 planeY = ds_sub(ds_sub(Y,PLANE_H_OFFSET),CENTER_Y);

vec4 outcome = vec4(ds(0.0),ds(0.0));   
vec4 C = vec4(planeX,planeY);
int iters = 0;

for (int i = 0; i < ITER_LIMIT; i++) {
    iters = i;
    vec2 sqRe = ds_mult(outcome.xy,outcome.xy);
    vec2 sqIm = ds_mult(outcome.zw,outcome.zw);     
    vec4 Zsq = vec4(
        ds_sub(sqRe,sqIm),  
        ds_mult(ds(2.0),ds_mult(outcome.xy,outcome.zw))
    );                         
    outcome.xy = ds_add(Zsq.xy,C.xy);
    outcome.zw = ds_add(Zsq.zw,C.zw);       

    vec2 sqSumm = ds_add(ds_mult(outcome.xy,outcome.xy),ds_mult(outcome.zw,outcome.zw));
    if (sqSumm.x > sqThreshold) break;      

};  

--> Proceed to coloring
Run Code Online (Sandbox Code Playgroud)

结果(右侧的位置/放大率数据):在此输入图像描述 无需双重仿真即可渲染相同图像的零差异。

感谢您阅读这面文字和代码墙,有什么提示和/或想法吗?