【问题标题】:Using WebGL Shader Language (GLSL) for arbitrary vector mathematics in JavaScript在 JavaScript 中使用 WebGL 着色器语言 (GLSL) 进行任意向量​​数学
【发布时间】:2011-07-21 19:58:57
【问题描述】:

WebGL 着色器语言 (GLSL) 是一个非常强大的多维矢量数学工具。

是否有可能使用 JavaScript(在 Web 浏览器中运行)的强大功能进行私人非 3D 计算?可以获取数据,但是在着色器计算完成后,有什么方法可以将数据输出到 JavaScript 中?

不需要实际绘图,只需要计算向量。 (我正在玩用 JavaScript 编写的硬件加速重力模拟器的想法。)

谢谢!


在新闻中:Khronos 似乎正在开发 WebCL,这将是 OpenCL 的 JavaScript 可访问版本。这正是我正在寻找的,但这需要一些时间......

【问题讨论】:

    标签: javascript math matrix glsl webgl


    【解决方案1】:

    据我所知,spec WebGL 支持帧缓冲对象和回读操作。这足以让您转换数据并将其返回到客户端空间。以下是一系列操作:

    1. 使用您需要存储结果的附件渲染缓冲区创建 FBO;绑定它
    2. 将所有输入数据上传到纹理中(相同大小)。
    3. 创建 GLSL 处理着色器,它将在片段部分内部进行演算,从纹理读取输入并将输出写入目标渲染缓冲区;绑定它
    4. 画一个四边形;通过glReadPixels 读回渲染缓冲区。

    【讨论】:

    • 太糟糕了,唯一的 supported format for readPixels 是 UNSIGNED_BYTE RGBA。浮点数据输入,整数数据输出。 OpenGL 支持 FLOAT 类型,但这似乎已从 WebGL 中移除。
    • @Tero Niemi。无论如何,您可能正在使用 RGBA8 渲染缓冲区,因此通过读取 UNSIGNED_BYTE 您不会丢失任何东西,但与 FLOAT 相比,带宽负载减少了 4 倍。
    • 实际上(如果你想知道血淋淋的细节)我使用 JavaScript 原生类型“数字”来表示行星位置(即等于 64 位浮点)。要在 GLSL 中获取数字,我必须将其截断为 32 位 FLOAT。这有点痛苦,但还好。接下来,我在 GLSL 中迭代行星位置。在那之后,我想要它们,但我只得到 8 位整数......用一点魔法,我可能可以将 FLOAT 切割并切割成 BYTE,并在 JavaScript 中重新切割成 FLOAT,但所有这些位级操作可能正在逐渐消失我从 GPU 获得的速度奖励。
    【解决方案2】:

    从浏览器的着色器中取出浮点数实际上非常简单,但约束是每像素 1 个浮点数。

    我们将 4 个 int 转换为 1 个 float (r: int, g: int, b: int, a: int) -> (rgba: float)。

    感谢 IEEE

    float random(vec2 seed) { 
        return fract(cos(mod(123456780., 1024. * dot(seed / time, vec2(23.1406926327792690, 2.6651441426902251))))); 
    }
    float shift_right(float v, float amt) { 
        v = floor(v) + 0.5; return floor(v / exp2(amt)); 
    }
    float shift_left(float v, float amt) { 
        return floor(v * exp2(amt) + 0.5); 
    }
    float mask_last(float v, float bits) { 
        return mod(v, shift_left(1.0, bits)); 
    }
    float extract_bits(float num, float from, float to) { 
        from = floor(from + 0.5); to = floor(to + 0.5); 
        return mask_last(shift_right(num, from), to - from); 
    }
    vec4 encode_float(float val) { 
        if (val == 0.0) return vec4(0, 0, 0, 0); 
        float sign = val > 0.0 ? 0.0 : 1.0; 
        val = abs(val); 
        float exponent = floor(log2(val)); 
        float biased_exponent = exponent + 127.0; 
        float fraction = ((val / exp2(exponent)) - 1.0) * 8388608.0; 
        float t = biased_exponent / 2.0; 
        float last_bit_of_biased_exponent = fract(t) * 2.0; 
        float remaining_bits_of_biased_exponent = floor(t); 
        float byte4 = extract_bits(fraction, 0.0, 8.0) / 255.0; 
        float byte3 = extract_bits(fraction, 8.0, 16.0) / 255.0; 
        float byte2 = (last_bit_of_biased_exponent * 128.0 + extract_bits(fraction, 16.0, 23.0)) / 255.0; 
        float byte1 = (sign * 128.0 + remaining_bits_of_biased_exponent) / 255.0; 
        return vec4(byte4, byte3, byte2, byte1); 
    }
    

    用法:

    着色器:

    outputcolor = encode_float(420.420f);
    

    JavaScript:

    // convert output to floats
    output = new Float32Array(output.buffer);
    

    【讨论】:

      【解决方案3】:

      是的,这是可行的——Aaron Babcock here 有一个旧的演示(可能需要一些调整才能使其在 1.0 WebGL 规范上工作)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-04-07
        • 2018-06-05
        • 2014-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多