javascript - 如何在 WebGL 上的着色器内保存变量,以及如何从 JavaScript 程序读取其值?

标签 javascript browser opengl-es webgl

我正在尝试在 WebGL 上使用纹理来执行并行数组折叠操作。问题是我不知道如何将着色器上执行的计算结果保存在 GPU 本身上。我也不知道计算完成后如何从 JavaScript 中读回它。请参阅下图:

precision mediump float;
varying vec2 pix_pos; // the 2D coord of the texture
uniform sampler2D texture; // this is the input array
    uniform sum_step(uniform* sampler2D){
       // this should perform a reduction step
       // for example, if texture = [1,2,3,4,5,6,7,8]
       // then, in the next step, it would be:
       // [3,7,11,15]
       // and so on, until we get the sum in O(log(n))
    };
void main(void) {
    if (texture.length > 1) // if not fully processed, computes a step
        texture = sum_step(texture); // don't work, texture is readonly!
};

最佳答案

GPU 写入像素。 这些像素是保存的数据

例如this article展示了如何读取 9 个像素的数据,将每个像素乘以一个常数,将它们除以一个数字,然后使用如下所示的着色器写入一个像素

precision mediump float;

// our texture
uniform sampler2D u_image;
uniform vec2 u_textureSize;
uniform float u_kernel[9];

// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;

void main() {
   vec2 onePixel = vec2(1.0, 1.0) / u_textureSize;
   vec4 colorSum =
     texture2D(u_image, v_texCoord + onePixel * vec2(-1, -1)) * u_kernel[0] +
     texture2D(u_image, v_texCoord + onePixel * vec2( 0, -1)) * u_kernel[1] +
     texture2D(u_image, v_texCoord + onePixel * vec2( 1, -1)) * u_kernel[2] +
     texture2D(u_image, v_texCoord + onePixel * vec2(-1,  0)) * u_kernel[3] +
     texture2D(u_image, v_texCoord + onePixel * vec2( 0,  0)) * u_kernel[4] +
     texture2D(u_image, v_texCoord + onePixel * vec2( 1,  0)) * u_kernel[5] +
     texture2D(u_image, v_texCoord + onePixel * vec2(-1,  1)) * u_kernel[6] +
     texture2D(u_image, v_texCoord + onePixel * vec2( 0,  1)) * u_kernel[7] +
     texture2D(u_image, v_texCoord + onePixel * vec2( 1,  1)) * u_kernel[8] ;
   float kernelWeight =
     u_kernel[0] +
     u_kernel[1] +
     u_kernel[2] +
     u_kernel[3] +
     u_kernel[4] +
     u_kernel[5] +
     u_kernel[6] +
     u_kernel[7] +
     u_kernel[8] ;

   if (kernelWeight <= 0.0) {
     kernelWeight = 1.0;
   }

   // Divide the sum by the weight but just use rgb
   // we'll set alpha to 1.0
   gl_FragColor = vec4((colorSum / kernelWeight).rgb, 1.0);
}

要读回数据,请调用gl.readPixels

写入像素时,您可以将它们写入 Canvas (默认情况下),也可以制作纹理,将其附加到帧缓冲区并写入(通过绘制)和读取(通过调用 gl.readPixels)帧缓冲区的纹理。

上面链接的示例仅使用 RGBA/UNSIGNED_BYTE 纹理,每个 channel 8 位,4 个 channel 。如果用户的硬件通过启用 OES_texture_float 扩展支持,您还可以使用 RGBA/FLOAT 纹理。

唯一的复杂之处是,在 WebGL (1.0) 中,您无法使用 gl.readPixels 读取 float 。仅允许字节。但是,一旦您将数据放入 FLOAT 纹理中,您就可以将该纹理绘制到 RGBA/UNSIGNED_BYTE 纹理中,并将 float 据拆分为 4 个字节,然后将其读回以字节形式输出(使用 gl.readPixels)并在 JavaScript 中将其组装回 float

PS:是的,我知道链接到代码不好,但问题本身已经得到解答。 (您通过绘制像素来保存数据,并通过调用gl.readPixels读取数据)该链接仅作为示例。

关于javascript - 如何在 WebGL 上的着色器内保存变量,以及如何从 JavaScript 程序读取其值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21348487/

相关文章:

javascript - 在 Opentelemetry 中为 JavaScript 应用程序添加服务名称

javascript - javascript可以选择未显示在DOM上的对象吗?

php - 如何在保存提示期间不向浏览器发送所有文件数据?

android - 采用 OpenGL ES 2.0 的 Google map 设备

javascript - this 和 DOM 事件处理程序

javascript - 在开发者控制台的“网络”选项卡上访问或获取文件

使用 http 和其他替代技术下载 JavaFX 文件?

objective-c - iPad [opengl-es] 的画图应用程序线条不正确

ios - 我的应用程序的恢复时间很长

javascript - 切换按钮仅在一个方向起作用