LibGDX iOS 上的 FrameBuffer 怪癖
LibGDX FrameBuffer quirk on iOS
我为文字游戏创建了动态纹理,并将其保存在 FrameBuffer 中。然后,我使用由该 FrameBuffer 支持的 TextureRegions 绘制到屏幕上。此代码在 Android 上运行良好,但我在 iOS.
上遇到问题
您可以在下方看到左下角绘制了 FrameBuffer 内容的屏幕截图 - 一切正常。
但是,如果我 return 到 iOS 主屏幕,我会处理 FrameBuffer,然后根据需要重新创建并重绘所有内容到 FrameBuffer。然后 FrameBuffer 的内容看起来是屏幕的部分翻转镜像。
我尝试在每一帧上处理并重新创建 FrameBuffer 以查看会发生什么。同样,除非我 return 到 iOS 主屏幕,否则这非常有效,之后 FrameBuffer 的内容不正确。
然后我尝试减小 FrameBuffer 的大小并跨多个 FrameBuffer 绘图。如果我这样做它再次工作正常,除非我 return 到 iOS 主屏幕。但是,在这种情况下,只有创建的第一个 FrameBuffer 损坏,所有后续缓冲区都很好。
然后我尝试总是首先创建一个 1x1px FrameBuffer,我从不在其中绘制任何东西,这解决了我的问题....但为什么呢!?从 iOS 主屏幕 returning 后创建的第一个 FrameBuffer 似乎没有按预期工作,但之后的每个 FrameBuffer 都很好。看起来它总是试图在我创建的第一个 FrameBuffer 上绘制屏幕。
以下FrameBuffer的创建和绘制代码:
private static FrameBuffer getFrameBuffer(boolean newRequired) {
if (newRequired || frameBuffers.size == 0) {
FrameBuffer frameBuffer;
try {
frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, getFrameBufferSize(), getFrameBufferSize(), false);
} catch (Exception e) {
frameBuffer = new FrameBuffer(Format.RGBA4444, getFrameBufferSize(), getFrameBufferSize(), false);
}
frameBuffer.begin();
Gdx.gl20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
frameBuffer.end();
frameBuffers.add(frameBuffer);
// Set up the camera correctly for the frame buffer
OrthographicCamera camera = new OrthographicCamera(frameBuffer.getWidth(), frameBuffer.getHeight());
camera.position.set(frameBuffer.getWidth() * 0.5f, frameBuffer.getHeight() * 0.5f, 0);
camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
}
return frameBuffers.get(frameBuffers.size - 1);
}
private static TextureRegion getTextureUsingGpu(String letter, Bubble.BubbleType bubbleType) {
if (!enabled)
return null;
TextureRegion tx = getBlockImage(letter, bubbleType);
int width = (int) (tx.getRegionWidth() * LayoutManager.getShortEdge() / 1080 * LayoutManager.getScaling());
int height = (int) (tx.getRegionHeight() * LayoutManager.getShortEdge() / 1080 * LayoutManager.getScaling());
if (nextTextureX + width + PADDING > getFrameBufferSize()) {
nextTextureX = PADDING;
nextTextureY = nextRowY + PADDING;
if (nextTextureY + height + PADDING > getFrameBufferSize()) {
getFrameBuffer(true);
nextRowY = PADDING;
nextTextureY = PADDING;
}
}
FrameBuffer fb = getFrameBuffer(false);
fb.begin();
spriteBatch.begin();
tx.flip(false, !tx.isFlipY());
spriteBatch.disableBlending();
spriteBatch.draw(tx, nextTextureX, nextTextureY, width, height);
spriteBatch.enableBlending();
// Drawing Code Removed
spriteBatch.end();
fb.end();
TextureRegion textureRegion = new TextureRegion(fb.getColorBufferTexture(), nextTextureX, nextTextureY, width, height);
textureRegion.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
cacheTexture(letter, textureRegion);
nextTextureX += width;
nextRowY = Math.max(nextRowY, nextTextureY + height);
return textureRegion;
}
如果您从 resize
或 resume
方法调用 getFrameBuffer
或 getTextureUsingGpu
,那就是问题所在。在 iOS 上,resize
和 resume
不一定在 OpenGL 准备好恢复之前被调用,所以在那里做任何与 OpenGL 直接相关的事情都是不安全的,比如创建 ShaderPrograms,加载纹理,或创建帧缓冲区。我在我的游戏中通过使用 resume
设置一个成员布尔值来修复此问题,并使用它将新帧缓冲区的创建推迟到 render
方法。
我为文字游戏创建了动态纹理,并将其保存在 FrameBuffer 中。然后,我使用由该 FrameBuffer 支持的 TextureRegions 绘制到屏幕上。此代码在 Android 上运行良好,但我在 iOS.
上遇到问题您可以在下方看到左下角绘制了 FrameBuffer 内容的屏幕截图 - 一切正常。
但是,如果我 return 到 iOS 主屏幕,我会处理 FrameBuffer,然后根据需要重新创建并重绘所有内容到 FrameBuffer。然后 FrameBuffer 的内容看起来是屏幕的部分翻转镜像。
我尝试在每一帧上处理并重新创建 FrameBuffer 以查看会发生什么。同样,除非我 return 到 iOS 主屏幕,否则这非常有效,之后 FrameBuffer 的内容不正确。
然后我尝试减小 FrameBuffer 的大小并跨多个 FrameBuffer 绘图。如果我这样做它再次工作正常,除非我 return 到 iOS 主屏幕。但是,在这种情况下,只有创建的第一个 FrameBuffer 损坏,所有后续缓冲区都很好。
然后我尝试总是首先创建一个 1x1px FrameBuffer,我从不在其中绘制任何东西,这解决了我的问题....但为什么呢!?从 iOS 主屏幕 returning 后创建的第一个 FrameBuffer 似乎没有按预期工作,但之后的每个 FrameBuffer 都很好。看起来它总是试图在我创建的第一个 FrameBuffer 上绘制屏幕。
以下FrameBuffer的创建和绘制代码:
private static FrameBuffer getFrameBuffer(boolean newRequired) {
if (newRequired || frameBuffers.size == 0) {
FrameBuffer frameBuffer;
try {
frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, getFrameBufferSize(), getFrameBufferSize(), false);
} catch (Exception e) {
frameBuffer = new FrameBuffer(Format.RGBA4444, getFrameBufferSize(), getFrameBufferSize(), false);
}
frameBuffer.begin();
Gdx.gl20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
frameBuffer.end();
frameBuffers.add(frameBuffer);
// Set up the camera correctly for the frame buffer
OrthographicCamera camera = new OrthographicCamera(frameBuffer.getWidth(), frameBuffer.getHeight());
camera.position.set(frameBuffer.getWidth() * 0.5f, frameBuffer.getHeight() * 0.5f, 0);
camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
}
return frameBuffers.get(frameBuffers.size - 1);
}
private static TextureRegion getTextureUsingGpu(String letter, Bubble.BubbleType bubbleType) {
if (!enabled)
return null;
TextureRegion tx = getBlockImage(letter, bubbleType);
int width = (int) (tx.getRegionWidth() * LayoutManager.getShortEdge() / 1080 * LayoutManager.getScaling());
int height = (int) (tx.getRegionHeight() * LayoutManager.getShortEdge() / 1080 * LayoutManager.getScaling());
if (nextTextureX + width + PADDING > getFrameBufferSize()) {
nextTextureX = PADDING;
nextTextureY = nextRowY + PADDING;
if (nextTextureY + height + PADDING > getFrameBufferSize()) {
getFrameBuffer(true);
nextRowY = PADDING;
nextTextureY = PADDING;
}
}
FrameBuffer fb = getFrameBuffer(false);
fb.begin();
spriteBatch.begin();
tx.flip(false, !tx.isFlipY());
spriteBatch.disableBlending();
spriteBatch.draw(tx, nextTextureX, nextTextureY, width, height);
spriteBatch.enableBlending();
// Drawing Code Removed
spriteBatch.end();
fb.end();
TextureRegion textureRegion = new TextureRegion(fb.getColorBufferTexture(), nextTextureX, nextTextureY, width, height);
textureRegion.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
cacheTexture(letter, textureRegion);
nextTextureX += width;
nextRowY = Math.max(nextRowY, nextTextureY + height);
return textureRegion;
}
如果您从 resize
或 resume
方法调用 getFrameBuffer
或 getTextureUsingGpu
,那就是问题所在。在 iOS 上,resize
和 resume
不一定在 OpenGL 准备好恢复之前被调用,所以在那里做任何与 OpenGL 直接相关的事情都是不安全的,比如创建 ShaderPrograms,加载纹理,或创建帧缓冲区。我在我的游戏中通过使用 resume
设置一个成员布尔值来修复此问题,并使用它将新帧缓冲区的创建推迟到 render
方法。