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

时间:2021-02-01 14:56:46

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对象和回读操作。这足以让您转换数据并将其恢复到客户端空间。这是一系列操作:

  1. Create FBO with attachment render buffers that you need to store the result; bind it
  2. 创建具有附件渲染缓冲区的FBO,您需要存储结果;绑定它

  3. Upload all input data into textures (the same size).
  4. 将所有输入数据上传到纹理(相同大小)。

  5. 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
  6. 创建GLSL处理着色器,它将在片段部分内执行微积分,从纹理读取输入并将输出写入目标渲染缓冲区;绑定它

  7. Draw a quad; read back the render buffers via glReadPixels.
  8. 绘制四边形;通过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对象和回读操作。这足以让您转换数据并将其恢复到客户端空间。这是一系列操作:

  1. Create FBO with attachment render buffers that you need to store the result; bind it
  2. 创建具有附件渲染缓冲区的FBO,您需要存储结果;绑定它

  3. Upload all input data into textures (the same size).
  4. 将所有输入数据上传到纹理(相同大小)。

  5. 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
  6. 创建GLSL处理着色器,它将在片段部分内执行微积分,从纹理读取输入并将输出写入目标渲染缓冲区;绑定它

  7. Draw a quad; read back the render buffers via glReadPixels.
  8. 绘制四边形;通过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规范上工作)。