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

标签 android opengl-es libgdx alpha

更新1

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

enter image description here

左侧为原始图像,比手机 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();

右边是TextureRegion先绘制在FrameBuffer上,然后绘制在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 对困惑的纹理做了什么,所以它无法与着色器一起使用。我需要先在像素图上绘制它,这样我就可以混合两个透明的帧缓冲区。一直以来我都以为问题出在着色器上,我花了三天时间才找到问题所在,所以如果有人能帮助我,我将非常感激! :)

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

更新2

看起来我应该做一些事情,在 FrameBuffer 上绘制时设置一种 GL 混合,并在绘制 FrameBuffer 时设置第二种混合,但我还无法获得正确的组合...

老问题

enter image description here

左图是在 Photoshop 中制作的,具有 alpha 透明度,但我放置了黑色背景,以便看得更清楚。右图是 Android 屏幕的屏幕截图。这是我的代码,我首先在像素图上绘制纹理,然后在屏幕上绘制该像素图,纹理质量非常糟糕,并且如您所见,Alpha channel 非常扭曲。

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();

最佳答案

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

让我们通过查看单个像素如何从纹理转换到 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 channel )
  • 因此混合结果将是:[r:0.211, g:0.422, b:0.0] (无 Alpha channel )

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

如果您不喜欢这种行为,那么您可以使用 Batch#disableBlending() 完全禁用混合。 。如果您只想混合一次,那么您可以使用不带 alpha channel 的 FBO(例如 RGB888 而不是 RGBA8888 )。或者,如果您想自定义行为,则可以使用不同的混合函数 Batch#setBlendFunction .

顺便说一句,当我打字时,我记得我以前这样做过。这实际上是相同的问题和答案:https://stackoverflow.com/a/31146449/2512687

关于android - 在 FrameBuffer 上绘制的 LibGDX 纹理比原始纹理更暗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35993069/

相关文章:

java - NoClassDefFoundError、proGuard 和补间引擎库

android - 包装的 android-app 在恢复 "no current context"时崩溃

c++ - 有什么方法可以将 EGL 绘制到/dev/fb1 而不是/dev/fb0 而无需在 Raspberry Pi 上复制数据?

android - Libgdx 渲染纹理与 Sprite

java - 如何使用自定义对象创建 libgdx 数组的副本?

Android:提高手机屏幕的响应速度?

java - 在 AsyncTask 中使用回调函数时出现 NullpointerException

android - 仅针对广告平台的位置权限 : Is it worth it?

java - 执行顺序困惑

java - 延迟行动