当前位置: 首页 > 知识库问答 >
问题:

在FrameBuffer上绘制的LibGDX纹理比原始纹理更暗

韦原
2023-03-14

更新1

如您所见,在FrameBuffer上绘制的LibGDX纹理,与直接在SpriteBatcher上绘制的纹理相比,在SpriteBatcher上绘制的纹理要比原始纹理暗一些。

左侧为原图,比手机1080x1920屏幕小50%。

texture = new Texture("texture.png");
texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
image = new TextureRegion(texture, 0, 0, 1024, 1024);

batcher.begin();
batcher.draw(image, 0, 0, screenWidth, screenHeight);
batcher.end();

右侧部分是先在FrameBuffer上绘制的TextureRegion,然后在SpriteBatch上绘制,如下代码所示:

texture = new Texture("texture.png");
texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
image = new TextureRegion(texture, 0, 0, 1024, 1024);

pixmap = new FrameBuffer(Pixmap.Format.RGBA8888, screenWidth, screenHeight, false);
pixmapregion = new TextureRegion(pixmap.getColorBufferTexture(), screenWidth, screenHeight);

pixmap.begin();
batcher.begin();
batcher.draw(image, 0, 0, screenWidth, screenHeight);
batcher.end();
pixmap.end();

batcher.begin();
batcher.draw(pixmapregion , 0, 0, screenWidth, screenHeight);
batcher.end();

如你所见,它比直接从纹理绘制的图像暗一点。当我用着色器绘制它时,与用着色器绘制的纹理相比,结果是乱七八糟的。

所以真正的问题是FrameBuffer对纹理做了什么使它混乱,所以它不能与shader一起使用。而且我需要先在pixmap上绘制它,这样我就可以混合两个透明的FrameBuffer了。一直以来,我认为问题是与着色器,我失去了3天找到什么问题是什么,所以如果有人能帮助我,我将非常感激!:)

注意:我尝试在FrameBuffer上绘图时启用混合,首先用gdx.gl.glclear(GL20.gl_color_buffer_bitGL20.gl_depth_buffer_bit)清除它;但没什么不同。

更新2

看起来我应该在绘制FrameBuffer时设置一种GL混合,在绘制FrameBuffer时设置另一种混合,但我还不能得到正确的组合...

texture = new Texture("drop-blue.png");
texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
image = new TextureRegion(texture, 0, 0, 1024, 1024);

pixmap = new FrameBuffer(Pixmap.Format.RGBA8888, screenWidth, screenHeight, false);
pixmapregion = new TextureRegion(pixmap.getColorBufferTexture(), screenWidth, screenHeight);

pixmap.begin();
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batcher.begin();
batcher.draw(image, screenWidth/2 - 512, screenHeight/2 - 512, 1024, 1024);
batcher.end();
pixmap.end();

batcher.begin();
batcher.draw(pixhtml" target="_blank">mapregion, 0, 0, screenWidth, screenHeight);
batcher.end();

共有1个答案

常波鸿
2023-03-14

这是正常的,也是混合工作的方式。您正在将具有透明度的纹理呈现到具有透明度的framebuffer上,然后您将framebuffer呈现到屏幕(backbuffer)上。这导致混合应用两次。

让我们看看实际发生了什么,看看单个像素是如何从纹理到fbo再到屏幕的转换。首先,看看向FBO提供信息时会发生什么:

  • 假设纹理中像素是[r:0.5,g:1.0,b:0.0,a:0.75],这将是我们的源像素。
  • 当您将其呈现到framebuffer时,目标像素最初是[R:0.0,G:0.0,B:0.0,A:0.0],这是您的GLClearColor
  • 默认情况下,混合函数用于源src_alpha和目标one_minus_src_alpha
  • 当呈现给FBO时,这将导致:[R:0.75*0.5,G:0.75*1.0,B:0.75*0.0,A:0.75*0.75]+[R:(1-0.75)*0.0,G:(1-0.75)*0.0,B:(1-0.75)*0.0],这将导致[R:0.375,G:0.75,B:0.0,A:0.5625]

现在让我们看看将FBO渲染到屏幕时会发生什么:

  • 源像素为:[r:0.375,g:0.75,b:0.0,a:0.5625]
  • 目标像素(屏幕的glClearColor)为[R:0,G:0,B:0](无alpha通道)
  • 因此混合结果将为:[R:0.211,G:0.422,B:0.0](无alpha通道)

注意结果是如何变得越来越暗的。这是因为它与原始颜色混合,在您的情况下,原始颜色是黑色。如果你使用白色,那么它实际上会变得越来越亮。

如果您不喜欢这种行为,那么可以使用batch#disableblending()完全禁用混合。如果您只想混合一次,那么您可以使用不带alpha通道的FBO(例如RGB888而不是RGB8888)。或者,如果希望自定义行为,则可以使用batch#setblendfunction使用不同的混合函数。

顺便说一句,当我打这个的时候,我记得我以前也打过。下面是几乎相同的问题和答案:https://stackoverflow.com/a/31146449/2512687

 类似资料:
  • 我试图旋转纹理时,我画他们。我认为这样做比在Paint.NET中旋转图像90度并将它们保存在不同的文件中更有意义。我查看了api文档中spritebatch绘图参数,但我就是不明白。有一堆参数,比如srcX、srcY、originX等等。我也想知道如何做同样的纹理区域。以下是api文档页面的链接:http://libgdx.badlogicgames.com/nightlies/docs/api/

  • 如果我创建一个.png 1024 x 1024的纹理,并在中间画一个124 x 124的圆,它的周围将是空的,它使用的RAM是否与我在124x124空间上画一个124 x 124的圆相同?

  • 我在MyGdxGame中的render方法看起来是这样的,调用舞台绘制自己(连同它的演员),然后我尝试绘制一组纹理以供调试之用。 舞台和它的一个演员一起绘制,但其他的纹理没有被绘制。 我试过的:在舞台相机上设置批处理投影矩阵(在调用之后),确保纹理坐标应该是可见的。

  • 我如何渲染纹理让假设宽度=400,高度=800,在这个比例? 这是我的代码:

  • 再详细一点。我不使用Block2D。瓦片大小由8x8缩放为20x20。使用没有填充的texturepacker(无论如何填充都会出现问题)。我不知道该发布哪段代码,因为我不知道问题可能出在哪里,所以这里只是简单的块类。如果有任何帮助,我将不胜感激,谢谢。

  • 我希望你能帮我找到错误。干杯,Joshflux 编辑:我很确定,它必须做一些事情与窗口的大小。如果我将窗口的高度从800调整为200,那么左角的人看起来是一样的,但是中间的人要小得多。但还是不知道怎么解决...