我正在尝试在 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/