我正在尝试将自透明纹理渲染到帧缓冲区,但我没有得到我猜到的东西:先前在帧缓冲区上渲染的所有东西都被忽略了,这个纹理与我清理主画布的颜色混合在一起.
这就是我想要的,但不使用framebuffers:
package test;
import com.badlogic.gdx.*;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
public class GdxTest extends ApplicationAdapter {
SpriteBatch batch;
Texture img;
@Override
public void create () {
batch = new SpriteBatch();
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pixmap.setColor(1, 1, 1, 1);
pixmap.fillRectangle(0, 0, 1, 1);
// Generating a simple 1x1 white texture
img = new Texture(pixmap);
pixmap.dispose();
}
@Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.setColor(1, 1, 1, 1);
batch.draw(img, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.setColor(0, 0, 0, 0.5f);
batch.draw(img, 0, 0, 300, 300);
batch.end();
}
}
Run Code Online (Sandbox Code Playgroud)
它的工作方式与应有的完美:
http://i.stack.imgur.com/wpFNg.png
这就是我使用framebuffer得到的东西(我无法理解为什么第二个渲染纹理不会与前一个纹理混合,因为它没有帧缓冲):
package test;
import com.badlogic.gdx.*;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
import com.badlogic.gdx.graphics.glutils.*;
public class GdxTest extends ApplicationAdapter {
SpriteBatch batch;
Texture img;
FrameBuffer buffer;
TextureRegion region;
@Override
public void create () {
batch = new SpriteBatch();
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pixmap.setColor(1, 1, 1, 1);
pixmap.fillRectangle(0, 0, 1, 1);
// Generating a simple 1x1 white texture
img = new Texture(pixmap);
pixmap.dispose();
// Generating a framebuffer
buffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
region = new TextureRegion(buffer.getColorBufferTexture());
region.flip(false, true);
}
@Override
public void render () {
// Filling with red shows the problem
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
buffer.begin();
batch.begin();
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setColor(1, 1, 1, 1);
batch.draw(img, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.setColor(0, 0, 0, 0.5f);
batch.draw(img, 0, 0, 300, 300);
batch.end();
buffer.end();
batch.begin();
batch.setColor(1, 1, 1, 1);
batch.draw(region, 0, 0);
batch.end();
}
}
Run Code Online (Sandbox Code Playgroud)
并且有一个不可预测的结果:
http://i.stack.imgur.com/UdDKD.png
那么我怎么能让framebuffer版本像第一个版本那样工作呢?;)
简单的答案是在渲染到屏幕时禁用混合.
但我认为如果你想使用FBO,理解为什么会发生这种情况是很好的.那么让我们来看看实际发生的事情.
首先要确保理解纹理的颜色和批次的颜色(顶点颜色)的作用:它们是相乘的.因此,在将批处理颜色设置为0,0,0,0.5和纹理像素(纹素)时,1,1,1,1这将导致值为1*0,1*0,1*0,1*0.5= 0,0,0,0.5.
接下来一定要了解混合的工作原理.默认情况下启用混合,并将使用SRC_ALPHA和ONE_MINUS_SRC_ALPHA功能.这意味着源值(纹素)乘以源alpha并且目标值(屏幕像素)乘以1减去源alpha.因此,如果您的屏幕像素具有该值1,1,1,1并且您的纹理元素具有该值,0,0,0,0.5则屏幕像素将设置为:(0.5*0, 0.5*0, 0.5*0, 0.5*0.5) + ((1-0.5)*1, (1-0.5)*1, (1-0.5)*1, (1-0.5)*1)即(0,0,0,0.25) + (0.5, 0.5, 0.5, 0.5)= (0.5, 0.5, 0.5, 0.75).
那么让我们看看你的第一个代码是如何工作的:
1, 0, 0, 1,换句话说:屏幕的每个像素都包含值1, 0, 0, 1.1,1,1,1屏幕的每个像素现在都包含该值1, 1, 1, 1.0,0,0,0.5每个像素现在都包含该值.0.5, 0.5, 0.5, 0.75已经对这个问题有了感觉?让我们看看你的第二个代码会发生什么:
1, 0, 0, 1:屏幕的每个像素都包含值1, 0, 0, 1.1, 1, 1, 1:FBO的每个像素都包含该值1, 1, 1, 1.1,1,1,1向FBO 渲染一个完整的矩形:FBO的每个像素现在都包含该值1,1,1,1.0,0,0,0.5每个像素现在都包含该值.0.5, 0.5, 0.5, 0.751, 0, 0, 1.0.5, 0.5, 0.5, 0.75乘以0.75并1, 0, 0, 1乘以1-0.75 = 0.25,这将导致0.375, 0.375, 0.375, 0.5625和0.25, 0, 0, 0.25.所以最终的颜色是0.625, 0.375, 0.375, 0,8125确保理解这个过程,否则会引起一些令人沮丧的奇怪问题.如果您发现很难遵循,那么您可以拿笔和纸并手动计算每个步骤的值.