Javascript 使用帧缓冲区对象的图像上的webgl多片段着色器提供黑色输出

Javascript 使用帧缓冲区对象的图像上的webgl多片段着色器提供黑色输出,javascript,webgl,textures,framebuffer,Javascript,Webgl,Textures,Framebuffer,首先,我是WebGL的新手。我尝试在要渲染的单个图像上应用多个片段着色器(这里是两个着色器)。我在不同的文章和其他堆栈溢出问题中读到,我们应该为此使用帧缓冲区(乒乓方法),但在任何地方都找不到任何示例代码片段。我的理解是,首先我创建了两个程序,每个程序都有一个不同的片段着色器。然后使用帧缓冲区对象,我可以在原始图像上使用我的第一个程序(第一个着色器),并将其输出到fbo纹理。然后将此输出纹理用作第二个程序中的输入,以便保留两个着色器。该输出最终在画布上呈现。 我试着做同样的事情,但我的画布是完全

首先,我是WebGL的新手。我尝试在要渲染的单个图像上应用多个片段着色器(这里是两个着色器)。我在不同的文章和其他堆栈溢出问题中读到,我们应该为此使用帧缓冲区(乒乓方法),但在任何地方都找不到任何示例代码片段。我的理解是,首先我创建了两个程序,每个程序都有一个不同的片段着色器。然后使用帧缓冲区对象,我可以在原始图像上使用我的第一个程序(第一个着色器),并将其输出到fbo纹理。然后将此输出纹理用作第二个程序中的输入,以便保留两个着色器。该输出最终在画布上呈现。 我试着做同样的事情,但我的画布是完全黑色的。我没有得到任何错误的控制台一切似乎很好,但不是结果。 好几个小时了,我都被它迷住了。谁能帮我查一下吗? 下面是我写的代码

const canvas = document.querySelector("canvas")
const gl = canvas.getContext("webgl");
//create two programs using a createprogram function written in my code.
const programA = createProgram(gl, vertexShader, fragmentShaderA); // program using #shader1
const programB = createProgram(gl, vertexShader, fragmentShaderB);
const texFbPair = createTextureAndFramebuffer(gl); //function defined below
setAttributes(programA);
setAttributes(programB);

function setAttributes(program) {
    const positionLocation = gl.getAttribLocation(program, 'position');
    const positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        -1, -1, -1, 1, 1, -1,
        1, 1, 1, -1, -1, 1,
    ]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
    const texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
    const texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        0.0, 1.0,
        0.0, 0.0,
        1.0, 1.0,
        1.0, 0.0,
        1.0, 1.0,
        0.0, 0.0]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(texCoordLocation);
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
}

const texture = gl.createTexture();
texture.image = new Image();
texture.image.onload = function () {
    handleLoadedTexture(gl, texture);
};
texture.image.crossOrigin = '';
texture.image.src = 'skogafoss_waterfall_iceland.jpg';
function handleLoadedTexture(gl, texture, callback) {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
}

gl.useProgram(programA);
gl.bindFramebuffer(gl.FRAMEBUFFER, texFbPair.fb);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.clearColor(0, 0, 1, 1);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.drawArrays(gl.TRIANGLES, 0, 6);

gl.useProgram(programB);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, texFbPair.tex);
gl.clearColor(0, 0, 0, 1);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.drawArrays(gl.TRIANGLES, 0, 6)

function createTextureAndFramebuffer(gl) {
    const tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    const fb = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
    return { tex: tex, fb: fb };
}

从代码中看,您似乎对属性的工作方式有错误的理解。属性是WebGL1中的全局状态,因此

setAttributes(programA);
setAttributes(programB);
不行。对
setAttributes
的第二次调用只会将全局属性更改为第二次调用的设置

看到和

下一个问题是代码不等待图像加载,所以它创建了一个图像,设置了一个回调,当它完成加载时,它会绘制两个东西。然后,图像完成加载并复制到纹理,但之后不会绘制

代码也从不在
createTextureAndFramebuffer

为此,您需要调用
gl.texImage2D

下面是一些工作代码

const vertexShader=`
属性向量4位置;
属性向量2 a_texCoord;
可变矢量2 v_texCoord;
void main(){
gl_位置=位置;
v_texCoord=a_texCoord;
}
`;
常数fragmentShaderA=`
高精度浮点;
可变矢量2 v_texCoord;
均匀采样2d-tex;
void main(){
gl_FragColor=纹理2d(tex,v_texCoord);
}
`;
常数fragmentShaderB=`
高精度浮点;
可变矢量2 v_texCoord;
均匀采样2d-tex;
void main(){
gl_FragColor=纹理2d(tex,v_texCoord);
}
`;
const canvas=document.querySelector(“canvas”)
const gl=canvas.getContext(“webgl”);
//使用我的代码中编写的createprogram函数创建两个程序。
const programA=createProgram(gl、vertexShader、fragmentShaderA);//使用#着色器1编程
const programB=createProgram(gl、vertexShader、fragmentShaderB);
const texFbPair=createTextureAndFramebuffer(gl)//函数定义如下
函数集合属性(程序){
const positionLocation=gl.getAttriblLocation(程序“位置”);
const positionBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY\u BUFFER,positionBuffer);
gl.bufferData(gl.ARRAY\u BUFFER,新Float32Array([
-1, -1, -1, 1, 1, -1,
1, 1, 1, -1, -1, 1,
])、总图、静态图);
gl.EnableVertexAttributeArray(位置位置);
gl.VertexAttribute指针(位置位置,2,gl.FLOAT,false,0,0);
const texCoordLocation=gl.getAttribLocation(程序,“a_texCoord”);
const texCoordBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,texCoordBuffer);
gl.bufferData(gl.ARRAY\u BUFFER,新Float32Array([
0.0, 1.0,
0.0, 0.0,
1.0, 1.0,
1.0, 0.0,
1.0, 1.0,
0.0,0.0]),总图静态图);
gl.EnableVertexAttributeArray(texCoordLocation);
gl.VertexAttributePointer(texCoordLocation,2,gl.FLOAT,false,0,0);
}
常量纹理=gl.createTexture();
texture.image=新图像();
texture.image.onload=函数(){
手工织物(gl,纹理);
};
texture.image.crossOrigin='';
texture.image.src=https://i.imgur.com/ZKMnXce.png';
函数handleLoadedTexture(gl、纹理、回调){
gl.bindTexture(gl.TEXTURE_2D,纹理);
gl.texParameteri(gl.TEXTURE_2D、gl.TEXTURE_WRAP_S、gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE\u 2D、gl.TEXTURE\u WRAP\u T、gl.CLAMP\u至边缘);
gl.texParameteri(gl.TEXTURE\u 2D,gl.TEXTURE\u MAG\u过滤器,gl.NEAREST);
gl.texParameteri(gl.TEXTURE\u 2D,gl.TEXTURE\u MIN\u过滤器,gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_字节,TEXTURE.image);
setAttributes(programA);
gl.useProgram(programA);
gl.bindFramebuffer(gl.FRAMEBUFFER,texFbPair.fb);
gl.bindTexture(gl.TEXTURE_2D,纹理);
gl.clearColor(0,0,1,1);
总图视口(0,0,总图画布宽度,总图画布高度);
gl.绘图阵列(gl.三角形,0,6);
设置属性(程序B);
gl.useProgram(程序B);
gl.bindFramebuffer(gl.FRAMEBUFFER,null);
gl.bindTexture(gl.TEXTURE_2D,texFbPair.tex);
gl.clearColor(0,0,0,1);
总图视口(0,0,总图画布宽度,总图画布高度);
gl.DrawArray(gl.TRIANGLES,0,6)}
函数createTextureAndFramebuffer(gl){
常量tex=gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D,tex);
gl.texImage2D(
gl.U 2D,
0,//mip级别
gl.RGBA,//内部格式
gl.canvas.width,//宽度
gl.canvas.height,//高度
0,//边框
gl.RGBA,//格式
gl.UNSIGNED_字节,//类型
null);//数据
gl.texParameteri(gl.TEXTURE\u 2D,gl.TEXTURE\u MIN\u过滤器,gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D、gl.TEXTURE_WRAP_S、gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE\u 2D、gl.TEXTURE\u WRAP\u T、gl.CLAMP\u至边缘);
const fb=gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER,fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,tex,0);
返回{tex:tex,fb:fb};
}
函数createProgram(总账、vs、fs){
返回twgl.createProgram(总帐,[vs,fs]);
}

从代码中可以看出,您对属性的工作方式有错误的理解。属性是WebGL1中的全局状态,因此

setAttributes(programA);
setAttributes(programB);
不行。第二次调用
setAttributes