渲染到纹理时出现黑屏
Posted
技术标签:
【中文标题】渲染到纹理时出现黑屏【英文标题】:Black screen when rendering to a texture 【发布时间】:2021-07-04 19:02:43 【问题描述】:我正在尝试执行以下操作:
-
在第一遍中将场景绘制到我创建的帧缓冲区。
获取附加到创建的帧缓冲区的纹理并将其绘制到平面上,以便它可以显示在屏幕上。
做一些后期处理。
仅使用默认帧缓冲区,场景如下所示:
目前我无法让第 1 部分和第 2 部分工作。我得到的只是黑屏。但是,飞机已正确放置在场景中(通过使用gl.LINE_STRIP
查看线框进行确认)。我不确定这是否是由于我在代码中犯了一个错误,或者对帧缓冲区的工作方式缺乏了解(webgl 对我来说是新的)。
以下是相关代码摘录:
// ======== FRAMEBUFFER PHASE ======== //
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGB,
canvas.clientWidth,
canvas.clientHeight,
0,
gl.RGB,
gl.UNSIGNED_BYTE,
null // don't fill it with pixel data just yet
);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
texture,
0
);
// ======== END FRAMEBUFFER PHASE ======== //
// =========== RENDERBUFFER PHASE ============== //
const renderBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, renderBuffer);
gl.renderbufferStorage(
gl.RENDERBUFFER,
gl.DEPTH_STENCIL,
canvas.clientWidth,
canvas.clientHeight
);
gl.framebufferRenderbuffer(
gl.FRAMEBUFFER,
gl.DEPTH_STENCIL_ATTACHMENT,
gl.RENDERBUFFER,
renderBuffer
);
// =========== END RENDERBUFFER PHASE ============== //
// =========== CHECK FRAMEBUFFER STATUS ============== //
const framebufferState = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (framebufferState !== gl.FRAMEBUFFER_COMPLETE)
throw new Error(
`Framebuffer status is not complete: $framebufferState`
);
// =========== END CHECK FRAMEBUFFER STATUS ============== //
// =========== FIRST PASS RENDERING ============ //
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.clearColor(0.1, 0.1, 0.1, 1.0);
gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
// this sets up the green quad and draws it to the screen
const objectModel = setupObjectModel(
position: [100.0, -10.0, 0.0],
colour: [0.734345265462, 0.89624528765, 0.9868589658, 1.0],
gl,
canvas,
);
objectModel.draw(
shaderProgram: mainShaderProgram,
camera: updatedCamera,
currentTime,
deltaTime,
);
// =========== END FIRST PASS RENDERING ============ //
// =========== SECOND PASS RENDERING ============ //
// back to rendering with the default framebuffer
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.disable(gl.DEPTH_TEST);
gl.useProgram(frameBufferShaderProgram);
// prettier-ignore
const verts = [
// positions // texCoords
-1.0, 1.0, 0.0, 1.0,
-1.0, -1.0, 0.0, 0.0,
1.0, -1.0, 1.0, 0.0,
-1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0
];
// prettier-ignore-end
const screenQuad = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, screenQuad);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
const aPosAttributeLocation = gl.getAttribLocation(
frameBufferShaderProgram,
"aPos"
);
gl.enableVertexAttribArray(aPosAttributeLocation);
gl.vertexAttribPointer(
aPosAttributeLocation,
2,
gl.FLOAT,
false,
Float32Array.BYTES_PER_ELEMENT * 4,
0
);
const aTexCoordsAttributeLocation = gl.getAttribLocation(
frameBufferShaderProgram,
"aTexCoords"
);
gl.enableVertexAttribArray(aTexCoordsAttributeLocation);
gl.vertexAttribPointer(
aTexCoordsAttributeLocation,
2,
gl.FLOAT,
false,
Float32Array.BYTES_PER_ELEMENT * 4,
Float32Array.BYTES_PER_ELEMENT * 2
);
const screenTexture = gl.getUniformLocation(
frameBufferShaderProgram,
"screenTexture"
);
gl.uniform1i(screenTexture, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
这是帧缓冲着色器程序:
// vertex shader
precision mediump float;
attribute vec2 aPos;
attribute vec2 aTexCoords;
varying vec2 TexCoords;
void main()
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
TexCoords = aTexCoords;
// fragment shader
precision mediump float;
uniform sampler2D screenTexture;
varying vec2 TexCoords;
void main()
// the texture coordinates are fine here, it's the screen texture that's the issue
gl_FragColor = texture2D(screenTexture, TexCoords.xy);
【问题讨论】:
【参考方案1】:这是一个常见的错误。 WebGL 1.0 基于 OpenGL ES 2.0。与 mipmap 相同的规则适用于纹理帧缓冲区附件。帧缓冲区纹理的大小必须是 2 的幂。请参阅 Texture Completeness and Non-Power-Of-Two Textures。
创建一个大小等于 2 的幂的帧缓冲区(例如 1024x1024):
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
// [...]
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1024, 1024, 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_MAG_FILTER, gl.LINEAR);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
// [...]
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, 1024, 1024);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderBuffer);
// [...]
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.viewport(0, 0, 1024, 1024);
// [...]
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight,);
// [...]
【讨论】:
谢谢,这行得通!我在调试上花费的时间比我愿意承认的要长。以上是关于渲染到纹理时出现黑屏的主要内容,如果未能解决你的问题,请参考以下文章
快速切换到 UITableViewController 时出现黑屏
OpenGL - 在 NVIDIA 卡上渲染到纹理时出现 FBO 黑屏