【问题标题】:LibGDX Texture drawn on FrameBuffer is darker then original Texture在 FrameBuffer 上绘制的 LibGDX 纹理比原始纹理更暗
【发布时间】:2016-06-29 19:37:40
【问题描述】:

更新 1

您可以看到在 FrameBuffer 上绘制的 LibGDX 纹理,与直接在 SpriteBatcher 上绘制的纹理相比,SpriteBatcher 上的纹理比原始纹理更暗。

左边是原图,比手机 1080x1920 屏幕小 50%。

中间部分直接从SpriteBatch上的TextureRegion绘制,并水平镜像,以便更好地与左右图像进行比较。它有点失真,但我启用了线性过滤,正如您在代码中看到的那样:

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 对与它混淆的纹理做了什么,所以它不能与着色器一起使用。而且我需要先在像素图上绘制它,这样我才能混合两个透明的帧缓冲区。一直以来我都认为问题出在着色器上,我花了 3 天时间才找到问题所在,所以如果有人可以帮助我,我将不胜感激! :)

注意:我尝试在 FrameBuffer 上绘图时启用混合,首先使用 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);但没有任何区别。

更新 2

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

老问题

左图是在 Photoshop 中制作的,具有 alpha 透明度,但我设置了黑色背景,以便更好地查看。右图是安卓屏幕的屏幕截图。这是我的代码,我先在像素图上绘制纹理,然后在屏幕上绘制像素图,纹理质量很差,alpha 通道非常失真,如您所见。

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(pixmapregion, 0, 0, screenWidth, screenHeight);
batcher.end();

【问题讨论】:

  • 图片在哪里?
  • 对不起,我忘记添加链接了...
  • 您的图像是 RGBA8888 格式吗?试试 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);和 spritebatch.enableBlending(); spritebatch.setBlendFunction(gl.BLEND_SRC_ALPHA,gl.BLEND_ONE_MINUS_SRC_ALPHA);
  • 是的,在 Photoshop 中,我将网络图像保存为 24 位并检查了透明度,据我所知,这应该是 RGBA8888。我也尝试启用混合并设置混合功能,但没有成功,同样的事情再次发生......:/

标签: android opengl-es libgdx alpha


【解决方案1】:

这是正常的以及混合的工作原理。您正在将具有透明度的纹理渲染到具有透明度的帧缓冲区上,然后您将其渲染到屏幕上(后缓冲区)。这会导致应用两次混合。

让我们通过观察单个像素如何从纹理转换到 fbo 再到屏幕来了解实际发生的情况。首先看看渲染到 FBO 时会发生什么:

  • 假设纹理中的像素是[r:0.5, g:1.0, b:0.0, a:0.75],这将是我们的源像素。
  • 当您将其渲染到帧缓冲区时,目标像素最初是 [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, a:(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 而不是 RGBA8888)。或者,如果您想自定义行为,则可以使用 Batch#setBlendFunction 使用不同的混合功能。

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

【讨论】:

  • 对不起,双重工作,我没有看到这个问题,我在谷歌上搜索但没有找到。我在 fbo 上绘图时尝试了所有可能的混合组合,我发现 setBlendFunction(GL20.GL_ONE_MINUS_DST_ALPHA, GL20.GL_ONE) 和 setBlendFunction(GL20.GL_BLEND_SRC_ALPHA, GL20.GL_ONE) 做得最好。现在的问题是,当我使用 ShaderProgram 绘制 FrameBuffer 时,它的行为非常奇怪,在 FBO 上绘制纹理时以及在屏幕上绘制 FBO 时,每种可能的混合组合都会出现。我无法获得与使用着色器绘制纹理时相同的结果。
  • 如果您还有其他问题,请考虑打开另一个问题。
  • 好吧,当我只向 fbo 绘制一个 PNG 时,混合效果很好,但是当我向 fbo 绘制多个 PNG 时,混合效果非常糟糕,透明区域相互重叠,并且颜色会失真。 ..我尝试了所有可能的组合,将它们与屏幕不同部分的触摸事件混合,但没有运气。 LibGDX 中是否有替代 FrameBuffer 的方法?
  • 如果我想在 fbo 上绘制几个透明纹理(如旧问题中的图像上的那个)并且它们经常相互重叠,我该怎么办。我将它们绘制在透明背景上,然后将它们绘制在之前同时绘制的另一个之上。我应该在那里使用什么混合组合?
  • 如前所述,如果您只想混合一次,则可以使用没有 Alpha 通道的 FBO(例如 RGB888 而不是 RGBA8888)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-04
  • 2014-09-05
  • 2014-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-09
相关资源
最近更新 更多