简体   繁体   English

WebGL:从纹理中读取并将 output 写入第二个纹理

[英]WebGL: read from a texture and write the output to a second texture

I am using WebGL2.我正在使用 WebGL2。 I have two programs.我有两个程序。 Program 1 renders my favorite triangle, in my favorite color, into a texture, for safe keeping.程序 1 以我最喜欢的颜色将我最喜欢的三角形渲染为纹理,以便安全保存。

Program 2 reads the output of program 1 (the first texture) and then renders the contents of that texture.程序 2 读取程序 1(第一个纹理)的 output,然后渲染该纹理的内容。

This works fine when program 2 renders to the canvas, but I would like program 2 to render to a second texture.当程序 2 渲染到 canvas 时,这工作正常,但我希望程序 2 渲染到第二个纹理。 So after the first program's draw call I unbind the first fbo, create another fbo backed by a second texture, and then draw.因此,在第一个程序的绘制调用之后,我解除了第一个 fbo 的绑定,创建了另一个由第二个纹理支持的 fbo,然后进行绘制。

....

gl.bindFramebuffer(gl.FRAMEBUFFER,null)

gl.useProgram(program2)

....

const fbo2 = gl.createFramebuffer()
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)

const intermediateTexture = createEmptyTexture(gl,gl.canvas.width,gl.canvas.height,mipLevel)
gl.framebufferTexture2D(
    gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, intermediateTexture, mipLevel)

gl.viewport(0,0,gl.canvas.width,gl.canvas.height)
gl.drawArrays(gl.TRIANGLES, 0, 6)

This produces the following error: :GL_INVALID_OPERATION: glDrawArrays: Source and destination textures of the draw are the same.这会产生以下错误: :GL_INVALID_OPERATION: glDrawArrays: Source and destination textures of the draw are the same.

My interpretation of this error is that program 2 is reading from, and writing to, the same texture.我对这个错误的解释是程序 2 正在读取和写入相同的纹理。 I think the problem is that I haven't told program 2 which texture to read from.我认为问题在于我没有告诉程序 2 读取哪个纹理。 But I don't know how to tell program 2 to read from the texture in fb1, after that frame buffer has been unbound.但我不知道如何告诉程序 2 从 fb1 中的纹理中读取,在该帧缓冲区已解除绑定之后。

How do I get program 2 to read from the first texture and draw to the second texture?如何让程序 2 从第一个纹理读取并绘制到第二个纹理?

Thank you so much for your help非常感谢你的帮助

full code:完整代码:

 const vs1 = `#version 300 es in vec4 a_position; void main() { gl_Position = a_position; } ` const fs1 = `#version 300 es precision highp float; out vec4 outColor; void main() { outColor = vec4(1, 0.5, .2, 1); } ` const vs2 = `#version 300 es in vec3 a_texCoord; out vec2 v_texCoord; void main() { v_texCoord = a_texCoord.xy; gl_Position = vec4(a_texCoord, 1.0); }` const fs2 = `#version 300 es precision highp float; uniform sampler2D tex; in vec2 v_texCoord; out vec4 color; void main() { color = texture(tex,v_texCoord); } ` function createShader(gl, type, source) { let shader = gl.createShader(type) gl.shaderSource(shader, source) gl.compileShader(shader) return shader } function createProgram(gl, vertexShader, fragmentShader) { let program = gl.createProgram() gl.attachShader(program, vertexShader) gl.attachShader(program, fragmentShader) gl.linkProgram(program) return program } function createEmptyTexture(gl, targetTextureWidth, targetTextureHeight, mipLevel) { let texture = gl.createTexture() gl.bindTexture(gl.TEXTURE_2D, texture) gl.texImage2D(gl.TEXTURE_2D, mipLevel, gl.RGB, targetTextureWidth, targetTextureHeight, 0, gl.RGB, gl.UNSIGNED_BYTE, null) 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_MIN_FILTER, gl.LINEAR) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) return texture } function main() { const vertexShader1 = createShader(gl, gl.VERTEX_SHADER, vs1), fragmentShader1 = createShader(gl, gl.FRAGMENT_SHADER, fs1), vertexShader2 = createShader(gl, gl.VERTEX_SHADER, vs2), fragmentShader2 = createShader(gl, gl.FRAGMENT_SHADER, fs2), program1 = createProgram(gl, vertexShader1, fragmentShader1), program2 = createProgram(gl, vertexShader2, fragmentShader2), positionAttributeLocation = gl.getAttribLocation(program1, "a_position"), texturePositionAttributeLocation = gl.getAttribLocation(program2, "a_texCoord"), positionBuffer = gl.createBuffer() gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer) gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, .5, 0, 0, 1, .5]), gl.STATIC_DRAW) const vao1 = gl.createVertexArray() gl.bindVertexArray(vao1) gl.enableVertexAttribArray(positionAttributeLocation) gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0) const mipLevel = 0 // program1 draws to fbo1 backed by intermediateTexture at color attachment 0 gl.useProgram(program1) gl.bindVertexArray(vao1) const fbo1 = gl.createFramebuffer() gl.bindFramebuffer(gl.FRAMEBUFFER, fbo1) const intermediateTexture = createEmptyTexture(gl, gl.canvas.width, gl.canvas.height, mipLevel) gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, intermediateTexture, mipLevel) gl.viewport(0, 0, gl.canvas.width, gl.canvas.height) gl.drawArrays(gl.TRIANGLES, 0, 3) gl.bindFramebuffer(gl.FRAMEBUFFER, null) // Is this the problem? // program2 is supposed to draw to fbo2 backed by new texture at color attachment 0 gl.useProgram(program2) const vao2 = gl.createVertexArray() gl.bindVertexArray(vao2) gl.enableVertexAttribArray(texturePositionAttributeLocation) gl.vertexAttribPointer(texturePositionAttributeLocation, 2, gl.FLOAT, false, 0, 0) gl.bindVertexArray(vao2) const quad = [-1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1] gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(quad), gl.STATIC_DRAW) gl.viewport(0, 0, gl.canvas.width, gl.canvas.height) const fbo2 = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2); const targetTexture = createEmptyTexture(gl, gl.canvas.width, gl.canvas.height, mipLevel) gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, targetTexture, mipLevel) gl.drawArrays(gl.TRIANGLES, 0, 6) // error: glDrawArrays: Source and destination textures of the draw are the same } main();

Your function createEmptyTexture binds the texture it creates to the (implicitly) activated texture unit 0, and leaves it bound.您的function createEmptyTexture将它创建的纹理绑定到(隐式)激活的纹理单元 0,并将其绑定。 So if you want to read from the texture of the first framebuffer you'll need to bind that before rendering with program 2. That being said, usually you'd setup all the vertex-, index- and framebuffers with their respective textures and programs upfront during initialization, your render loop then emits bind, draw and attribute pointer calls.因此,如果您想从第一个帧缓冲区的纹理中读取,您需要在使用程序 2 渲染之前绑定它。话虽如此,通常您会使用它们各自的纹理和程序设置所有顶点缓冲区、索引缓冲区和帧缓冲区在初始化期间,您的渲染循环会发出绑定、绘制和属性指针调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM