如何正确使用 LIBGDX FrameBuffer
Posted
技术标签:
【中文标题】如何正确使用 LIBGDX FrameBuffer【英文标题】:How to use LIBGDX FrameBuffer correctly 【发布时间】:2020-06-11 13:11:45 【问题描述】:这是我的第一个问题。我试图查看源代码(link) 搜索了***并阅读了一些一般解释。但是对于如何正确设置(或理解)它,我没有任何智慧。
我不懂投影矩阵或大部分 GL 术语。 我不知道当您应该更新相机时设置相机 (camera.setToOrtho()) 会发生什么 或何时设置批次的投影矩阵。到目前为止,我对它的唯一使用仅限于下面所示的 draw() 方法中使用的代码。
我有一个基于图块的分层游戏。我想使用 FrameBuffer 将水层绘制到 TextureRegion。所以我以后可以尝试用着色器来操作它。我认为这就是这样做的方法。
(我没有使用任何“Scene2d”或“Tiled”类)
Example of what the layer looks like
我如何绘制图层:
public void draw(OrthographicCamera camera)
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA,GL20.GL_ONE_MINUS_SRC_ALPHA); // [1]
BATCH.setProjectionMatrix(camera.combined);
BATCH.begin();
for (int i = 0; i < NUM_LAYERS; i++)
if (RENDER[i])
if (SORT[i]) Collections.sort(LAYERS.get(i));
for (DrwDat dat: LAYERS.get(i)) // [2]
dat.draw(BATCH);
BATCH.end();
1。不知道这是做什么的,但我似乎不需要它。 [2]。 DrwDat 只是一个保存可绘制对象的类。在这种情况下,这些是图块。
好的。因此,在绘制循环中,我放置了一个在绘制水层时要调用的方法。目前 我想绘制应该在屏幕上显示的每个图块,而不是将它们绘制到缓冲区。然后:将缓冲区绘制到屏幕上。
问题:我可以在下面的“renderFBO()”方法中添加什么使其工作?为什么?基本上在不使用 FrameBuffer 的情况下让屏幕准确显示它会显示的内容
(当前的代码纯粹是绝望,因为我试图使用 youtube 教程作为模板而不理解它。)
private void renderFBO(OrthographicCamera camera, int layer)
BATCH.end();
frameBuffer.begin();
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
BATCH.begin();
camera.setToOrtho(false);
camera.position.set(FocusPoint.position.x,FocusPoint.position.y,0); // [3]
camera.update();
BATCH.setProjectionMatrix(camera.combined);
for (DrwDat dat: LAYERS.get(layer))
dat.draw(BATCH);
frameBuffer.end(); // [4]
BATCH.end();
camera.setToOrtho(false);
//BATCH.setProjectionMatrix(camera.combined);
BATCH.begin();
BATCH.draw(bufferTexture.getTexture(),0,0,Settings.SCREEN_W,Settings.SCREEN_H);
BATCH.end();
camera.position.set(FocusPoint.position.x,FocusPoint.position.y,0);
camera.update();
BATCH.setProjectionMatrix(camera.combined);
BATCH.begin();
[3]。 FocusPoint 只是相机跟随的一个点(例如:鼠标点击位置)
[4]。出于某种原因,将 framebuffer.end() 设置在 batch.end() 下面不会渲染任何内容。
这是我初始化 FrameBuffer 的方法:
private FrameBuffer frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888,Settings.SCREEN_W,Settings.SCREEN_H,false);
private TextureRegion bufferTexture = new TextureRegion(frameBuffer.getColorBufferTexture());
如果这太笼统了,我很抱歉。但任何帮助表示赞赏。我能读到的任何提示也会 很有帮助。
【问题讨论】:
【参考方案1】:关于您的第 1 点:您不需要该行,因为 SpriteBatch 自己管理混合并将覆盖您在调用 batch.begin()
之前设置的任何混合状态。
关于你的第 4 点:像这样把它们弄乱,你根本就没有画到 FBO。可能是您的 FBO 设置或绘制方式有问题,因此无法正常工作,但像往常一样直接在屏幕上绘制会使它看起来可以正常工作。
就像在您的示例中一样,这将假设它正在中断在batch.begin()
和batch.end()
之间完成的现有绘图。所以它会在你的 begin()
和 end()
调用之间被调用,如下所示:
public void draw(OrthographicCamera camera)
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
BATCH.setProjectionMatrix(camera.combined);
BATCH.begin();
renderFbo();
BATCH.end();
无需使用相机来绘制帧缓冲区内容以覆盖整个屏幕。您可以使用单位投影矩阵以及 OpenGL 将默认投影定义为 2 个单位宽和高,以 (0, 0) 为中心的知识。
您无需结束和开始批处理。在切换渲染表面之前刷新它会更简单一些。
private final Matrix4 originalMatrixTemp = Matrix4();
private static final Matrix4 IDENTITY = Matrix4();
public void renderFbo()
// Finish drawing anything queued before we switch the frame buffer.
batch.flush();
// Store the current Batch state for things we're going to temporarily change.
originalMatrixTemp.set(BATCH.getProjectionMatrix());
ShaderProgram originalShader = BATCH.getShaderProgram();
int originalBlendSrcFunc = BATCH.getBlendSrcFunc();
int originalBlendDstFunc = BATCH.getBlendDstFunc();
// No need to set up camera projection again.
// It was already set before calling this method.
// This ensures alpha is preserved in case you have overlapping translucent sprites.
BATCH.setBlendFunctionSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE);
// Draw to FBO
frameBuffer.begin();
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
for (DrwDat dat: LAYERS.get(layer))
dat.draw(BATCH);
BATCH.flush();
frameBuffer.end();
/* When you have a custom shader for rendering FBO contents, here's where
you would prepare it.
BATCH.setShader(waterFboShader);
waterFboShader.setUniformf("u_someUniformAttribute", someUniformAttribute);
etc.
*/
// Ensure we're drawing the frame buffer texture without modifying its color.
BATCH.setColor(Color.WHITE);
// Dimensions to the corners of the screen when using an identity matrix for
// projection. Negative height to flip vertically. (OpenGL image space and world
// space have opposite Y directions for some reason.)
BATCH.setProjectionMatrix(IDENTITY);
BATCH.draw(frameBuffer.getColorBufferTexture(), -1, 1, 2, -2);
BATCH.flush();
// Restore state from before this method was called.
BATCH.setShader(originalShader);
BATCH.setProjectionMatrix(originalMatrixTemp);
BATCH.setBlendFunction(originalBlendSrcFunc, originalBlendDstFunc);
在存储原始矩阵时,您必须将其值复制到您自己的临时实例中,因为 SpriteBatch 会将其自己的最终实例传递给您,当您应用单位矩阵时,其值即将被覆盖。
【讨论】:
评论不用于扩展讨论;这个对话是moved to chat。 我用一个更简单的程序尝试了你的例子。它奏效了。所以我关于在 Libgdx 中正确使用帧缓冲区的问题已经得到解答。即使它对我的项目不起作用。还有一些我做错了。以上是关于如何正确使用 LIBGDX FrameBuffer的主要内容,如果未能解决你的问题,请参考以下文章
Libgdx/Java ShadowMap 和 Framebuffer 使用相机更新