在 JavaScript 中使用 WebGL 着色器语言 (GLSL) 进行任意向量​​数学计算

发布于 2024-10-25 06:31:36 字数 476 浏览 8 评论 0原文

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

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

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

谢谢!


新闻报道:Khronos 似乎正在开发 WebCL,这将是 OpenCL。这正是我正在寻找的,但这需要一些时间......

The WebGL Shader Language (GLSL) is a very powerful tool for multidimensional vector mathematics.

Is there any possibility to use that power from JavaScript (running in web browser) for private non-3D calculations? Getting data in is possible, but is there any way to get data out to JavaScript after shader calculations are done?

No actual drawing is necessary, only calculating vectors.
(I am toying with an idea of hardware accelerated gravity simulator written in JavaScript.)

Thank You!


In the news: Khronos seems to be developing WebCL which will be a JavaScript accessible version of OpenCL. That is exactly what I am looking for, but it will take some time...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

请止步禁区 2024-11-01 06:31:37

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

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

As far as I can see from the spec WebGL supports framebuffer objects and read-back operations. This is sufficient for you to transform the data and get it back into client space. Here is a sequence of operations:

  1. Create FBO with attachment render buffers that you need to store the result; bind it
  2. Upload all input data into textures (the same size).
  3. Create the GLSL processing shader that will do the calculus inside the fragment part, reading the input from textures and writing the output into destination renderbuffers; bind it
  4. Draw a quad; read back the render buffers via glReadPixels.
各空 2024-11-01 06:31:37

从浏览器中的着色器中获取浮点实际上非常容易,但限制是每个像素 1 个浮点。

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

感谢 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);

Getting floats out of a shader in the browser is actually pretty easy, the constraint being 1 float per pixel though.

We convert 4 ints to 1 float (r: int, g: int, b: int, a: int) -> (rgba: float).

Thanks 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); 
}

Usage:

Shader:

outputcolor = encode_float(420.420f);

JavaScript:

// convert output to floats
output = new Float32Array(output.buffer);
不知所踪 2024-11-01 06:31:37

是的,这是可行的——Aaron Babcock 这里

Yes, it's doable -- there's an old demo (might require some tweaks to get it to work on the 1.0 WebGL specification) by Aaron Babcock here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文