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

时间:2016-03-14 16:35:10

标签: 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();

右边部分首先在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做什么来纹理它的混乱,所以它不能用着色器。我需要首先在pixmap上绘制它,所以我可以混合两个透明的FrameBuffers。一直以来我都认为问题出在着色器上,我失去了3天发现问题所在,所以如果有人能帮助我,我将非常感激! :)

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

更新2

在绘制FrameBuffer时设置一种GL混合,并在绘制FrameBuffer时设置第二种混合看起来我应该做些什么,但我还是不能得到正确的组合... < / p>

旧问题

enter image description here

左图是在Photoshop中制作的,具有Alpha透明度,但我放置了黑色背景,因此可以更好地看到它。右图是从android屏幕拍摄的屏幕。这是我的代码,我首先在pixmap上绘制纹理,然后我在屏幕上绘制像素图,纹理质量非常差,并且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();

1 个答案:

答案 0 :(得分: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