1
votes

UPDATE 1

As you can see LibGDX Texture drawn on FrameBuffer, then on SpriteBatcher is darker then original Texture in comparison with Texture drawn directly on SpriteBatcher.

enter image description here

Left part is original image, which is 50% smaller of phone 1080x1920 screen.

Middle part is drawn directly from TextureRegion on SpriteBatch, and is mirrored horizontally for better comparison with left and right images. It is little distorted, but I enabled Linear filtering as you can see in code:

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

Right part is TextureRegion drawn on FrameBuffer first, then drawn on SpriteBatch, like in following code:

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

Like you can see, it is little darker than image drawn directly from texture. And when I draw it with shader, the results are real mess in comparison with texture drawn with shader.

So the real question is what FrameBuffer do to texture that mess with it, so it is unusable with shader. And I need to draw it on pixmap first, so I can blend two transparent FrameBuffers. All this time I thought problem is with shader, and I lost 3 days finding what the problem is, so if someone could help me I would be very grateful! :)

Note: I tried to enable blending when drawing on FrameBuffer, to clear it first with Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); but nothing made difference.

UPDATE 2

It looks like there is something I should do with setting one kind of GL blending when drawing on FrameBuffer, and setting osecond kind of blending when drawing FrameBuffer, but I can't get the right combination yet...

OLD QUESTION

enter image description here

Left image is made in Photoshop, with alpha transparency, but I put black background so it can be seen better. Right image is screen shoot from android screen. This is my code, i first draw texture on pixmap, then i draw that pixmap on screen, and texture quality is very bad, and alpha channel is very distorted as you can see.

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
where are the images?Hllink
Sorry, I forgot to add link for it...Spartacus
is your image on RGBA8888 format? try Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); and spritebatch.enableBlending(); spritebatch.setBlendFunction(gl.BLEND_SRC_ALPHA,gl.BLEND_ONE_MINUS_SRC_ALPHA);Hllink
Yes, in Photoshop I saved image for web as 24bit with transparency checked, that should be RGBA8888 as I understood. I also tried to enable blending and set that blend function, but no success, same thing happens again... :/Spartacus

1 Answers

2
votes

This is normal and how blending works. You are rendering a texture with transparency onto a framebuffer with transparency, which in turn you render onto the screen (backbuffer). This causes the blending to be applied twice.

Let look at what is actually happening by looking how a single pixel is transformed from the texture to the fbo to the screen. First by looking at what happens when rendering to the FBO:

  • Let's say that pixel in the texture is [r:0.5, g:1.0, b:0.0, a:0.75], this is will be our source pixel.
  • When you render that to the framebuffer then the destination pixel is initially [r:0.0, g:0.0, b:0.0, a:0.0], which is your glClearColor.
  • The blend function by default is for the source SRC_ALPHA and for the destination ONE_MINUS_SRC_ALPHA.
  • When rendering to the FBO this will result in: [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] which results in [r:0.375, g:0.75, b:0.0, a:0.5625]

Now let's see what happens when rendering the FBO to the screen:

  • The source pixel is: [r:0.375, g:0.75, b:0.0, a:0.5625]
  • The destination pixel (glClearColor of the screen) is [r:0, g:0, b:0] (no alpha channel)
  • So the blended result will be: [r:0.211, g:0.422, b:0.0] (no alpha channel)

Note how the result gets darker and darker. This is because it gets blended with the original color, which in your case is black. If you'd use e.g. white then it would actually get brighter and brighter.

If you don't like this behavior then you can disable blending altogether using Batch#disableBlending(). If you only want to blend once then you can use a FBO without alpha channel (e.g. RGB888 instead of RGBA8888). Or, if you want to customize the behavior then you can use a different blend function using Batch#setBlendFunction.

BTW, while I was typing this, I remembered I did that before. Here's practically the same question and answer: https://stackoverflow.com/a/31146449/2512687