【发布时间】:2014-10-22 19:07:45
【问题描述】:
我正在尝试使用 SpriteBatch 和 FrameBuffer 渲染三张图像。
这些是我正在做的步骤。
- 清除屏幕、深度和模板缓冲区。
- 绑定帧缓冲区。请参阅 FrameBuffer.bind()。
- 使用我的 SpriteBatch 渲染三个具有不同大小和不同位置的实体四边形。
- 解绑我的 FrameBuffer。请参阅 FrameBuffer.unbind()。
- 绑定我的 FrameBuffers colorTexture。
- 用我的 SpriteBatch 渲染我的 FrameBuffer。
这是我知道的关于这个问题的一些事实
- 纹理显示正确的颜色。他们不是白人。
- 显示了我渲染的第一个纹理,而其他两个没有。如果我更改顺序,仍然会渲染第一个纹理。
- 对于三个纹理,我的意思是三个独立的纹理 ID。
- 我已启用深度测试。
- 没有抛出 OpenGL 错误或 FrameBuffer 错误。
- 当使用我的 SpriteBatch 直接渲染到屏幕时,所有三个四边形都会显示出来。
- 我的 FrameBuffer 大小就是我的屏幕大小。
它应该是这样的
这是我的帧缓冲区的外观。
这是使用我的帧缓冲区并绘制第一个纹理两次的情况。仍然缺少其他两个纹理。定位不是问题。
这是我的 FrameBuffer 的代码:
// Stencil is broken currently broken, in my example. I'm not using any stencil buffers.
public FrameBuffer(int width, int height, boolean hasDepth, boolean hasStencil) {
this.width = width;
this.height = height;
frameBufferID = GL30.glGenFramebuffers();
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID);
if (hasDepth && hasStencil) {
int depthAndStencilBufferID = GL30.glGenRenderbuffers();
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthAndStencilBufferID);
GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, width, height);
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, depthAndStencilBufferID);
}
else if (hasDepth) {
int depthBufferID = GL30.glGenRenderbuffers();
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBufferID);
GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH_COMPONENT32F, width, height);
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER, depthBufferID);
}
else if (hasStencil) {
int stencilBufferID = GL30.glGenRenderbuffers();
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, stencilBufferID);
GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_STENCIL_INDEX16, width, height);
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, stencilBufferID);
}
colorTexture = new Texture(width, height);
colorTexture.bind();
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, colorTexture.getTextureID(), 0);
int result = GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER);
//error handling
RenderUtil.unbindFrameBuffer();
}
private Texture colorTexture;
private int width, height;
private int frameBufferID, depthBufferID, stencilBufferID;
public void begin () {
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID);
GL11.glViewport(0, 0, width, height);
}
public void end () {
GL11.glViewport(0, 0, RenderingEngine.getWidth(), RenderingEngine.getHeight());
RenderUtil.unbindFrameBuffer();
RenderUtil.unbindTextures();
}
public Texture getColorTexture () {
return colorTexture;
}
public int getWidth () {
return width;
}
public int getHeight () {
return height;
}
下面是我创建纹理的方法:
private void loadTexture (ByteBuffer buffer, int textureID, int width, int height) {
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, width, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
}
切换纹理时,我的 SpriteBatch 似乎有问题。以下是切换的工作原理。 我提醒你,使用我的 SpriteBatch 渲染到屏幕可以得到我想要的结果。但是渲染到 FrameBuffer 不起作用。
`
public void flush () {
flushes++;
buffer.flip();
MESH.setVertices(buffer);
if (lastTexture != null) {
lastTexture.bind();
}
MESH.draw();
buffer.clear();
}
/** Begins the SpriteBatch. */
public void begin () {
if (rendering) {
new IllegalStateException("You have to SpriteBatch.end() before calling begin again!").printStackTrace();
}
flushes = 0;
rendering = true;
shader.bind();
shader.setUniformMat4f("projection", camera.getCombined());
shader.setUniformVec4("color", color);
}
/** Ends the SpriteBatch, also flushes it. */
public void end () {
if (!rendering) {
new IllegalStateException("You've to SpriteBatch.begin before ending the spritebatch").printStackTrace();
}
rendering = false;
flush();
RenderUtil.unbindShaders();
RenderUtil.unbindTextures();
}
/** Switches the textures and flushes the old one.
* @param t */
private void switchTextures (Texture t) {
if (lastTexture != null) {
flush();
}
lastTexture = t;
}
` 将创建一个小示例。应该快起来了。
编辑: 问题不是我的 FrameBuffer。是我的 SpriteBatch。
【问题讨论】:
-
快速浏览一下您的代码,我注意到一个错误......当
hasStencil和hasDepth都为真时会发生什么?您尝试将附件绑定到 DEPTH 和 STENCIL,但这在大多数情况下会导致兼容性问题。在这种特殊情况下,您应该添加第三种情况,将打包的深度+模板附件绑定到GL_DEPTH_STENCIL_ATTACHMENT。这里更大的问题是您使用 16 位模板缓冲区,当您也有深度缓冲区时,这几乎永远不会起作用:-\ -
是的,您可以为渲染缓冲区使用深度+模板图像格式。在这种情况下,您使用的是 32 位浮点深度缓冲区,因此您想要的格式是
GL_DEPTH32F_STENCIL8。这实际上是一种特别讨厌的格式,硬件不喜欢 40 位数据,所以实际发生的情况是您浪费了额外的 24 位数据,因此打包的深度+模板被填充为 64 位。老实说,我建议您尝试使用 24 位深度缓冲区,因为这样您就可以使用GL_DEPTH24_STENCIL8而不会浪费任何内存/带宽。 -
不小心删除了我的问题。这里是为 Andon 的回答提供一些背景信息:我只需要创建一个渲染缓冲区吗?
-
@AndonM.Coleman 我更新了代码,depth+stencil 的创建效果如何?
-
最后一件事:你能显示你实际清除缓冲区的代码吗?我期待在函数
begin (...)中看到它,但它不存在。您需要在绑定 FBO 时清除缓冲区,否则您只会清除与窗口关联的颜色/模板/深度缓冲区。
标签: opengl lwjgl framebuffer