GLES:显示奇怪图像的 FrameBuffer 对象
GLES: FrameBuffer object showing weird images
我目前正在尝试使用 Android Studio 让 FBO 在我的游戏中工作。
我已经设法设置了一个 FBO 并为其绘制了一个填充的白色矩形 (64x64px)。
但是当我尝试将 FBO 的颜色缓冲区渲染到屏幕上时,
出现随机噪声和奇怪的图像。
FBO 制作的怪异图像快照
我既不知道为什么我的纯色矩形没有显示也不知道为什么
有一张 Whatsapp 聊天的头像,这不是故意的。
这是我初始化 FrameBuffer 对象的方式:
private void initFrameBuffer() {
int[] temp = new int[1];
//Create a texture object and bind it. This will be the color buffer.
glGenTextures(1, temp, 0);
colorTexture = temp[0];
glBindTexture(GL_TEXTURE_2D, colorTexture);
//Set parameters. We're probably using non-power-of-two (NPOT) dimensions,
//so some values may not be available for use!
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//Create a texture storage:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
//Create framebuffer object and bind it.
glGenBuffers(1, temp, 0);
frameBufferID = temp[0];
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
//Create a depth buffer and bind it.
glGenRenderbuffers(1, temp, 0);
depthBuffer = temp[0];
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
//Allocate storage for the depth buffer.
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
//Attach the depth buffer and the texture (color buffer) to the framebuffer object.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, colorTexture, 0);
//Check if GL ES is happy with all this ... :)
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("Framebuffer not complete! StatusID: " + status);
}
//Switch back to the default framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
整个风景我是怎么画的:
@Override
public void draw() {
GLES20.glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject.getID());
Graphics.setColor(new Color(255, 255, 255));
Graphics.fillRect(0, 0, 64, 64);
GLES20.glBindFramebuffer(GL_FRAMEBUFFER, 0);
Graphics.drawFrameBuffer(frameBufferObject, 0, 0, frameBufferObject.getWidth(), frameBufferObject.getHeight());
}
最后但同样重要的是,这是我如何使用简单的着色器程序将 FBO 的颜色缓冲区绘制到屏幕上:
public static void drawFrameBuffer(FrameBufferObject frameBufferObject, int x, int y, int w, int h) {
ImageMesh mesh = new ImageMesh(generateMesh(x, y, w, h));
imageShader.start();
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameBufferObject.getColorTexture());
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
//Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray(imageShader.positionHandle);
//Prepare triangle coordinate data
GLES20.glVertexAttribPointer(imageShader.positionHandle, 3, GLES20.GL_FLOAT, false, 0, mesh.baseMesh.vertexBuffer);
//Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray(imageShader.texCoordLocation);
//Prepare the textureCoordinates
GLES20.glVertexAttribPointer(imageShader.texCoordLocation, 2, GLES20.GL_FLOAT, false, 0, mesh.uvBuffer);
//Apply the projection and view transformation
GLES20.glUniformMatrix4fv(imageShader.mtrxHandle, 1, false, Renderer.getUMVPMatrix(), 0);
//Set the sampler texture unit to 0
GLES20.glUniform1i(imageShader.samplerLoc, 0);
//Draw the triangles
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mesh.baseMesh.indices.length, GLES20.GL_UNSIGNED_SHORT, mesh.baseMesh.drawListBuffer);
//Disable vertex arrays
GLES20.glDisableVertexAttribArray(imageShader.positionHandle);
GLES20.glDisableVertexAttribArray(imageShader.texCoordLocation);
//Unbind the texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
imageShader.stop();
}
我用的AndroidAPI-Level是22。
此外,我创建的 FBO 完全适合屏幕尺寸,
这是 720x1280px.
这个问题浪费了我一整天的时间,
我不知道是什么导致了这个问题!
非常感谢您提供的任何帮助! <3
几个小时后,我终于成功了!
错误的主要原因是,我没有正确设置我的 FBO,
这导致了这个故障图像。
所以我在 Youtube 上观看了 ThinMatrix 教程的 OpenGL 教程,他让我摆脱了这种糟糕的局面。 :)
这是我更新的 FrameBuffer 对象代码:
public class FrameBufferObject {
private int width;
private int height;
private int frameBufferID;
private int texture;
private int depthTexture;
private int depthBuffer;
private Matrices.MatrixKit previousMatrixKit;
public FrameBufferObject(int width, int height) {
this.width = width;
this.height = height;
initFrameBuffer();
}
private void initFrameBuffer() {
frameBufferID = createFrameBuffer();
texture = createTextureAttachment();
depthTexture = createDepthTextureAttachment(width, height);
depthBuffer = createDepthBufferAttachment();
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
Logger.error("Framebuffer not Complete! STATUS: " + status + "\nWidth: " + width + "\nHeight: " + height);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
private int createFrameBuffer() {
int[] ids = new int[1];
glGenFramebuffers(1, ids, 0);
int frameBufferID = ids[0];
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
int[] buffers = new int[] {GL_COLOR_ATTACHMENT0};
GLES30.glDrawBuffers(1, buffers, 0);
return frameBufferID;
}
private int createTextureAttachment() {
int[] ids = new int[1];
glGenTextures(1, ids, 0);
int colorTexture = ids[0];
glBindTexture(GL_TEXTURE_2D, colorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
return colorTexture;
}
private int createDepthTextureAttachment(int width, int height) {
int[] ids = new int[1];
glGenTextures(1, ids, 0);
int depthTextureID = ids[0];
glBindTexture(GL_TEXTURE_2D, depthTextureID);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTextureID, 0);
return depthTextureID;
}
private int createDepthBufferAttachment() {
int[] ids = new int[1];
glGenBuffers(1, ids, 0);
int depthBuffer = ids[0];
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
return depthBuffer;
}
public int getColorTexture() {
return this.texture;
}
public void bindFrameBuffer() {
glBindTexture(GL_TEXTURE_2D, 0); //just make sure the texture isn't bound
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
glViewport(0, 0, width, height);
previousMatrixKit = Renderer.getMatrices();
Renderer.setMatrixKit(Matrices.createMatrixKit(width, height));
}
public void unbindFrameBuffer() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, previousMatrixKit.width, previousMatrixKit.height);
Renderer.setMatrixKit(previousMatrixKit);
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
public int getID() {
return this.frameBufferID;
}
}
我目前正在尝试使用 Android Studio 让 FBO 在我的游戏中工作。
我已经设法设置了一个 FBO 并为其绘制了一个填充的白色矩形 (64x64px)。
但是当我尝试将 FBO 的颜色缓冲区渲染到屏幕上时, 出现随机噪声和奇怪的图像。
FBO 制作的怪异图像快照
我既不知道为什么我的纯色矩形没有显示也不知道为什么
有一张 Whatsapp 聊天的头像,这不是故意的。
这是我初始化 FrameBuffer 对象的方式:
private void initFrameBuffer() {
int[] temp = new int[1];
//Create a texture object and bind it. This will be the color buffer.
glGenTextures(1, temp, 0);
colorTexture = temp[0];
glBindTexture(GL_TEXTURE_2D, colorTexture);
//Set parameters. We're probably using non-power-of-two (NPOT) dimensions,
//so some values may not be available for use!
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//Create a texture storage:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
//Create framebuffer object and bind it.
glGenBuffers(1, temp, 0);
frameBufferID = temp[0];
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
//Create a depth buffer and bind it.
glGenRenderbuffers(1, temp, 0);
depthBuffer = temp[0];
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
//Allocate storage for the depth buffer.
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
//Attach the depth buffer and the texture (color buffer) to the framebuffer object.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, colorTexture, 0);
//Check if GL ES is happy with all this ... :)
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("Framebuffer not complete! StatusID: " + status);
}
//Switch back to the default framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
整个风景我是怎么画的:
@Override
public void draw() {
GLES20.glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject.getID());
Graphics.setColor(new Color(255, 255, 255));
Graphics.fillRect(0, 0, 64, 64);
GLES20.glBindFramebuffer(GL_FRAMEBUFFER, 0);
Graphics.drawFrameBuffer(frameBufferObject, 0, 0, frameBufferObject.getWidth(), frameBufferObject.getHeight());
}
最后但同样重要的是,这是我如何使用简单的着色器程序将 FBO 的颜色缓冲区绘制到屏幕上:
public static void drawFrameBuffer(FrameBufferObject frameBufferObject, int x, int y, int w, int h) {
ImageMesh mesh = new ImageMesh(generateMesh(x, y, w, h));
imageShader.start();
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameBufferObject.getColorTexture());
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
//Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray(imageShader.positionHandle);
//Prepare triangle coordinate data
GLES20.glVertexAttribPointer(imageShader.positionHandle, 3, GLES20.GL_FLOAT, false, 0, mesh.baseMesh.vertexBuffer);
//Enable generic vertex attribute array
GLES20.glEnableVertexAttribArray(imageShader.texCoordLocation);
//Prepare the textureCoordinates
GLES20.glVertexAttribPointer(imageShader.texCoordLocation, 2, GLES20.GL_FLOAT, false, 0, mesh.uvBuffer);
//Apply the projection and view transformation
GLES20.glUniformMatrix4fv(imageShader.mtrxHandle, 1, false, Renderer.getUMVPMatrix(), 0);
//Set the sampler texture unit to 0
GLES20.glUniform1i(imageShader.samplerLoc, 0);
//Draw the triangles
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mesh.baseMesh.indices.length, GLES20.GL_UNSIGNED_SHORT, mesh.baseMesh.drawListBuffer);
//Disable vertex arrays
GLES20.glDisableVertexAttribArray(imageShader.positionHandle);
GLES20.glDisableVertexAttribArray(imageShader.texCoordLocation);
//Unbind the texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
imageShader.stop();
}
我用的AndroidAPI-Level是22。 此外,我创建的 FBO 完全适合屏幕尺寸, 这是 720x1280px.
这个问题浪费了我一整天的时间, 我不知道是什么导致了这个问题!
非常感谢您提供的任何帮助! <3
几个小时后,我终于成功了!
错误的主要原因是,我没有正确设置我的 FBO, 这导致了这个故障图像。
所以我在 Youtube 上观看了 ThinMatrix 教程的 OpenGL 教程,他让我摆脱了这种糟糕的局面。 :)
这是我更新的 FrameBuffer 对象代码:
public class FrameBufferObject {
private int width;
private int height;
private int frameBufferID;
private int texture;
private int depthTexture;
private int depthBuffer;
private Matrices.MatrixKit previousMatrixKit;
public FrameBufferObject(int width, int height) {
this.width = width;
this.height = height;
initFrameBuffer();
}
private void initFrameBuffer() {
frameBufferID = createFrameBuffer();
texture = createTextureAttachment();
depthTexture = createDepthTextureAttachment(width, height);
depthBuffer = createDepthBufferAttachment();
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
Logger.error("Framebuffer not Complete! STATUS: " + status + "\nWidth: " + width + "\nHeight: " + height);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
private int createFrameBuffer() {
int[] ids = new int[1];
glGenFramebuffers(1, ids, 0);
int frameBufferID = ids[0];
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
int[] buffers = new int[] {GL_COLOR_ATTACHMENT0};
GLES30.glDrawBuffers(1, buffers, 0);
return frameBufferID;
}
private int createTextureAttachment() {
int[] ids = new int[1];
glGenTextures(1, ids, 0);
int colorTexture = ids[0];
glBindTexture(GL_TEXTURE_2D, colorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
return colorTexture;
}
private int createDepthTextureAttachment(int width, int height) {
int[] ids = new int[1];
glGenTextures(1, ids, 0);
int depthTextureID = ids[0];
glBindTexture(GL_TEXTURE_2D, depthTextureID);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTextureID, 0);
return depthTextureID;
}
private int createDepthBufferAttachment() {
int[] ids = new int[1];
glGenBuffers(1, ids, 0);
int depthBuffer = ids[0];
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
return depthBuffer;
}
public int getColorTexture() {
return this.texture;
}
public void bindFrameBuffer() {
glBindTexture(GL_TEXTURE_2D, 0); //just make sure the texture isn't bound
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
glViewport(0, 0, width, height);
previousMatrixKit = Renderer.getMatrices();
Renderer.setMatrixKit(Matrices.createMatrixKit(width, height));
}
public void unbindFrameBuffer() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, previousMatrixKit.width, previousMatrixKit.height);
Renderer.setMatrixKit(previousMatrixKit);
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
public int getID() {
return this.frameBufferID;
}
}