WebGL:从纹理读取并将输出写入第二个纹理
WebGL: read from a texture and write the output to a second texture
我正在使用 WebGL2。我有两个程序。程序 1 将我最喜欢的三角形以我最喜欢的颜色渲染成纹理,以便安全保存。
程序 2 读取程序 1 的输出(第一个纹理),然后渲染该纹理的内容。
这在程序 2 渲染到 canvas 时工作正常,但我希望程序 2 渲染到第二个纹理。
因此,在第一个程序的绘制调用之后,我取消绑定第一个 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)
这会产生以下错误::GL_INVALID_OPERATION : glDrawArrays: Source and destination textures of the draw are the same.
我对此错误的解释是程序 2 正在读取和写入相同的纹理。我认为问题在于我还没有告诉程序 2 要读取哪个纹理。
但是我不知道如何告诉程序 2 在 fb1 中读取纹理,在帧缓冲区被解除绑定之后。
如何让程序 2 从第一个纹理读取并绘制到第二个纹理?
非常感谢您的帮助
完整代码:
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();
您的函数 createEmptyTexture
将它创建的纹理绑定到(隐式)激活的纹理单元 0,并且 离开 它绑定的。因此,如果你想从第一个帧缓冲区的纹理中读取,你需要在使用程序 2 渲染之前绑定它。也就是说,通常你会使用它们各自的纹理和程序设置所有顶点缓冲区、索引缓冲区和帧缓冲区在初始化期间预先,您的渲染循环然后发出绑定、绘制和属性指针调用。
我正在使用 WebGL2。我有两个程序。程序 1 将我最喜欢的三角形以我最喜欢的颜色渲染成纹理,以便安全保存。
程序 2 读取程序 1 的输出(第一个纹理),然后渲染该纹理的内容。
这在程序 2 渲染到 canvas 时工作正常,但我希望程序 2 渲染到第二个纹理。 因此,在第一个程序的绘制调用之后,我取消绑定第一个 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)
这会产生以下错误::GL_INVALID_OPERATION : glDrawArrays: Source and destination textures of the draw are the same.
我对此错误的解释是程序 2 正在读取和写入相同的纹理。我认为问题在于我还没有告诉程序 2 要读取哪个纹理。 但是我不知道如何告诉程序 2 在 fb1 中读取纹理,在帧缓冲区被解除绑定之后。
如何让程序 2 从第一个纹理读取并绘制到第二个纹理?
非常感谢您的帮助
完整代码:
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();
您的函数 createEmptyTexture
将它创建的纹理绑定到(隐式)激活的纹理单元 0,并且 离开 它绑定的。因此,如果你想从第一个帧缓冲区的纹理中读取,你需要在使用程序 2 渲染之前绑定它。也就是说,通常你会使用它们各自的纹理和程序设置所有顶点缓冲区、索引缓冲区和帧缓冲区在初始化期间预先,您的渲染循环然后发出绑定、绘制和属性指针调用。