The WebGL Shader Language (GLSL) is a very powerful tool for multidimensional vector mathematics.
WebGL着色器语言(GLSL)是一种用于多维向量数学的非常强大的工具。
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?
是否有可能使用JavaScript(在Web浏览器中运行)进行私有非3D计算?获取数据是可能的,但是在着色器计算完成后有没有办法将数据输出到JavaScript?
No actual drawing is necessary, only calculating vectors. (I am toying with an idea of hardware accelerated gravity simulator written in JavaScript.)
不需要实际绘图,只计算矢量。 (我正在研究用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...
在新闻中:Khronos似乎正在开发WebCL,它将是OpenCL的JavaScript可访问版本。这正是我想要的,但需要一些时间......
3 个解决方案
#1
17
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:
据我所知,WebGL支持framebuffer对象和回读操作。这足以让您转换数据并将其恢复到客户端空间。这是一系列操作:
- Create FBO with attachment render buffers that you need to store the result; bind it
- Upload all input data into textures (the same size).
- 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
- Draw a quad; read back the render buffers via
glReadPixels
.
创建具有附件渲染缓冲区的FBO,您需要存储结果;绑定它
将所有输入数据上传到纹理(相同大小)。
创建GLSL处理着色器,它将在片段部分内执行微积分,从纹理读取输入并将输出写入目标渲染缓冲区;绑定它
绘制四边形;通过glReadPixels读回渲染缓冲区。
#2
6
Getting floats out of a shader in the browser is actually pretty easy, the constraint being 1 float per pixel though.
在浏览器中从着色器中获取浮点实际上非常简单,但约束是每像素1浮点数。
We convert 4 ints to 1 float (r: int, g: int, b: int, a: int) -> (rgba: float).
我们将4个整数转换为1个浮点数(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);
#3
2
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.
是的,这是可行的 - Aaron Babcock在这里有一个旧的演示(可能需要一些调整才能让它在1.0 WebGL规范上工作)。
#1
17
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:
据我所知,WebGL支持framebuffer对象和回读操作。这足以让您转换数据并将其恢复到客户端空间。这是一系列操作:
- Create FBO with attachment render buffers that you need to store the result; bind it
- Upload all input data into textures (the same size).
- 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
- Draw a quad; read back the render buffers via
glReadPixels
.
创建具有附件渲染缓冲区的FBO,您需要存储结果;绑定它
将所有输入数据上传到纹理(相同大小)。
创建GLSL处理着色器,它将在片段部分内执行微积分,从纹理读取输入并将输出写入目标渲染缓冲区;绑定它
绘制四边形;通过glReadPixels读回渲染缓冲区。
#2
6
Getting floats out of a shader in the browser is actually pretty easy, the constraint being 1 float per pixel though.
在浏览器中从着色器中获取浮点实际上非常简单,但约束是每像素1浮点数。
We convert 4 ints to 1 float (r: int, g: int, b: int, a: int) -> (rgba: float).
我们将4个整数转换为1个浮点数(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);
#3
2
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.
是的,这是可行的 - Aaron Babcock在这里有一个旧的演示(可能需要一些调整才能让它在1.0 WebGL规范上工作)。