Glsl 在WebGL中将数据放到不同的纹理上并将其取出

Glsl 在WebGL中将数据放到不同的纹理上并将其取出,glsl,webgl,Glsl,Webgl,我试图从着色器输出多个缓冲区-一般目标是将其用于GPGPU目的。我已经看到了这一点,并通过这一点更接近目标: document.addEventListener("DOMContentLoaded", function() { function main() { const gl = document.querySelector('canvas').getContext('webgl2'); if (!gl) {

我试图从着色器输出多个缓冲区-一般目标是将其用于GPGPU目的。我已经看到了这一点,并通过这一点更接近目标:

document.addEventListener("DOMContentLoaded", function() {
    function main() {
        const gl = document.querySelector('canvas').getContext('webgl2');
        if (!gl) {
            return alert("need WebGL2");
        }
        gl.canvas.width  = 2;
        gl.canvas.height = 2;


        const vs = `
#version 300 es
in vec2 position;

void main(void) {
     gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
}
`;

        const fs = `
#version 300 es
precision mediump float;

  layout(location = 0) out vec4 outColor0;
  layout(location = 1) out vec4 outColor1;
  layout(location = 2) out vec4 outColor2;
  layout(location = 3) out vec4 outColor3;
  layout(location = 4) out vec4 outColor4;
  layout(location = 5) out vec4 outColor5;

  void main() {
    // simplified for question purposes
    outColor0 = vec4(1, 0, 0, 1);
    outColor1 = vec4(0, 1, 0, 1);
    outColor2 = vec4(0, 0, 1, 1);
    outColor3 = vec4(1, 1, 0, 1);
    outColor4 = vec4(1, 0, 1, 1);
    outColor5 = vec4(0, 1, 1, 1);
  } 
  `

        const program = twgl.createProgram(gl, [vs, fs]);

        const textures = [];

        const fb = gl.createFramebuffer();
        gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

        for (let i = 0; i < 6; ++i) {
            const tex = gl.createTexture();
            textures.push(tex);
            gl.bindTexture(gl.TEXTURE_2D, tex);

            const width = 2;
            const height = 2;
            const level = 0;
            
            gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            // attach texture to framebuffer
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, tex, level);
        }

        gl.viewport(0, 0, 2, 2);

        // tell it we want to draw to all 4 attachments

        gl.drawBuffers([
            gl.COLOR_ATTACHMENT0,
            gl.COLOR_ATTACHMENT1, 
            gl.COLOR_ATTACHMENT2,
            gl.COLOR_ATTACHMENT3,
            gl.COLOR_ATTACHMENT4,
            gl.COLOR_ATTACHMENT5,                   
        ]);

        // draw a single point
        gl.useProgram(program);
        {
            const offset = 0;
            const count = 1
            gl.drawArrays(gl.TRIANGLE, 0, 4);
        }

        for (var l = 0; l < 6; l++) { 
            var pixels  = new Uint8Array(gl.canvas.width * gl.canvas.height * 4);
            
            gl.readBuffer(gl.COLOR_ATTACHMENT0 + l);
            gl.readPixels(0, 0, gl.canvas.width, gl.canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

            console.log(pixels.join(' '));
        }
    }
    main();
})
而不是我所希望/期望的:

255 0 0 255 255 0 0 255 255 0 0 255 255 0 0 255
etc.
我早就料到了

outColor0 = vec4(1, 0, 0, 1);
相当于

gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
但显然我错了


那么,我如何才能得到期望的结果——能够在每个缓冲区上设置每个像素?

代码不提供任何顶点数据,即使它要求它绘制4个顶点。此外,它正在传入不存在的
gl.TRIANGLE
。它是
gl.三角形
,末尾是
s
<代码>总图三角形将被未定义,强制为0,与总图点匹配

在JavaScript控制台中

> const gl = document.createElement('canvas').getContext('webgl2');
< undefined
> gl.TRIANGLE 
< undefined
> gl.TRIANGLES
< 4
> gl.POINTS
< 0
你可以这么做

gl.drawArrays(4, offset, count) 
因为
gl.三角形
=4

但是你没有使用
gl.TRIANGLES
你使用了
gl.TRIANGLE
(没有
S
),所以你有效地做到了这一点

gl.drawArrays(undefined, offset, count) 
这被解释为

gl.drawArrays(0, offset, count) 
0=gl.POINTS,这与

gl.drawArrays(gl.POINTS, offset, count) 
然后,代码在同一位置绘制单个1像素点4次,因为您使用计数4调用它

gl.drawArrays(gl.POINTS, 0, 4) 
顶点着色器中的任何内容都不会更改每次迭代,因此每次迭代都将执行完全相同的操作。在本例中,它将在剪辑空间位置0,0,0,1处绘制一个1x1像素点,该点将最终成为2x2像素的左下像素

在任何情况下,您可能希望提供顶点,但作为一个简单的测试,如果我添加

  gl_PointSize = 2.0;
到顶点着色器,并将绘制调用更改为

gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
然后它会产生您期望的结果。它在剪辑空间位置0,0,0,1处绘制单个2x2像素点

函数main(){
const gl=document.querySelector('canvas').getContext('webgl2');
如果(!gl){
返回警报(“需要WebGL2”);
}
gl.canvas.width=2;
gl.canvas.height=2;
常数vs=`
#300版es
在vec2位置;
真空总管(真空){
gl_位置=vec4(0.0,0.0,0.0,1.0);
gl_PointSize=2.0;
}
`;
常数fs=`
#300版es
精密中泵浮子;
布局(位置=0)输出vec4输出颜色0;
布局(位置=1)输出向量4输出颜色1;
布局(位置=2)输出向量4输出颜色2;
布局(位置=3)输出向量4输出颜色3;
布局(位置=4)输出向量4输出颜色4;
布局(位置=5)输出向量4输出颜色5;
void main(){
//为提问而简化
outColor0=vec4(1,0,0,1);
outColor1=vec4(0,1,0,1);
outColor2=vec4(0,0,1,1);
outColor3=vec4(1,1,0,1);
outColor4=vec4(1,0,1,1);
outColor5=vec4(0,1,1,1);
} 
`
const program=twgl.createProgram(gl[vs,fs]);
常量纹理=[];
const fb=gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER,fb);
for(设i=0;i<6;++i){
常量tex=gl.createTexture();
纹理。推送(tex);
gl.bindTexture(gl.TEXTURE_2D,tex);
常数宽度=2;
常数高度=2;
常数级=0;
gl.texImage2D(gl.TEXTURE_2D,level,gl.RGBA,宽度,高度,0,gl.RGBA,gl.UNSIGNED_字节,null);
//将纹理附加到帧缓冲区
gl.framebufferTexture2D(gl.FRAMEBUFFER、gl.COLOR_ATTACHMENT0+i、gl.TEXTURE_2D、tex、level);
}
总图视口(0,0,2,2);
//告诉它我们要绘制所有4个附件
德国劳埃德船级社([
gl.COLOR_附件0,
gl.COLOR_附件1,
gl.COLOR_附件2,
gl.COLOR_附件3,
gl.COLOR_附件4,
gl.COLOR_附件5,
]);
//画一个点
gl.useProgram(程序){
常数偏移=0;
常数计数=1
总图绘制阵列(总图点,0,1);
}
对于(var l=0;l<6;l++){
var像素=新的Uint8Array(gl.canvas.width*gl.canvas.height*4);
gl.readBuffer(gl.COLOR_附件0+l);
gl.readPixels(0,0,gl.canvas.width,gl.canvas.height,gl.RGBA,gl.UNSIGNED_字节,像素);
console.log(像素连接(“”));
}
}
main()


我可能会在某个时候提出一些澄清性的问题,但首先,我会仔细研究,直到完全理解答案。我希望有一种方法能够以某种方式总结这些以GPGPU为重点的问题和答案,并反馈给社区。还是除了我,他们太明显了?还是太利基了?你觉得怎么样?如果我的回答不容易理解,我很抱歉。更新了答案。我不确定您对WebGL的理解程度,但可能会有所帮助
  gl_PointSize = 2.0;
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point