libgdx - blendFunc для рисования линий кисти? (добавка / не добавка смеси)
Я рисую спрайты в кадровом буфере в каждом пикселе для каждого шага в линии между двумя точками, но у меня есть проблема со смешиванием:
Я в настоящее время использую:
(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Затем в моем шейдере я делаю:
if( color.a == 0 )
color.rgb = 0;
Однако, если вы посмотрите на красную и зеленую звезду, вы увидите "аддитивное смешивание", которое происходит, когда альфа находится между интервалами (0,1).
Без аддитивного смешивания этот трехмерный эффект происходит:
Есть ли способ иметь аддитивное смешение одинаковых цветов, но избегать, когда цвета не совпадают?
Это должно выглядеть так:
1 ответ
Вы можете сделать это, используя предварительно умноженную альфу.
Сначала вам нужно правильно настроить текстуру. Нарисуйте его белым по черному так:
Затем скопируйте яркость текстуры в ее альфа-канал. В GIMP вы можете сделать это, щелкнув правой кнопкой мыши на слое, выбрав Add Layer Mask, а затем Grayscale Copy of Layer. Это будет выглядеть примерно так (как показано в Gimp):
Затем вы можете перекрасить его в RGB-канал, если хотите, хотя более универсально оставить его белым и раскрасить его в своем коде.
В вашем коде, когда вы рисуете фигуру, используйте функцию смешивания для предварительно умноженного альфа:
batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
И нарисуйте его, используя шейдер SpriteBatch по умолчанию. После того, как вы нарисовали фигуру, вернитесь к обычному альфа-смешиванию:
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Пример игры:
public class GameMain extends ApplicationAdapter implements InputProcessor{
SpriteBatch batch;
Texture star;
Color color = new Color();
Viewport viewport;
int screenWidth, screenHeight;
FrameBuffer fbo;
boolean shouldClearFBO = false;
boolean fboUpdated = false;
OrthographicCamera fullScreenCamera;
boolean touchDown = false;
Vector2 touchLocation = new Vector2();
int colorIndex = 0;
static final int[] COLORS = {0xff0000ff, 0x00ff00ff, 0x0000ffff, 0xffff00ff, 0xff00ffff, 0x00ffffff, 0xffffffff};
static final float SIZE = 150;
@Override
public void create () {
batch = new SpriteBatch();
star = new Texture("star.png");
viewport = new ExtendViewport(800, 480);
fullScreenCamera = new OrthographicCamera();
Gdx.input.setInputProcessor(this);
}
@Override
public void resize (int width, int height){
viewport.update(width, height, true);
fullScreenCamera.setToOrtho(false, width, height);
fullScreenCamera.position.set(width/2, height/2, 0);
fullScreenCamera.update();
fboUpdated = false;
screenWidth = width;
screenHeight = height;
}
@Override
public void render () {
if (!fboUpdated){
fboUpdated = true;
if (fbo!=null)
fbo.dispose();
fbo = new FrameBuffer(Pixmap.Format.RGBA8888, screenWidth, screenHeight, false);
fbo.begin();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
fbo.end();
}
color.set(COLORS[colorIndex]);
fbo.begin();
if (shouldClearFBO){
shouldClearFBO = false;
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
if (touchDown){
batch.setProjectionMatrix(viewport.getCamera().combined);
batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
batch.begin();
batch.setColor(color);
batch.draw(star, touchLocation.x - SIZE/2, touchLocation.y - SIZE/2, SIZE, SIZE);
batch.end();
}
fbo.end();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setColor(Color.WHITE);
batch.setProjectionMatrix(fullScreenCamera.combined);
batch.setBlendFunction(GL20.GL_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
batch.begin();
batch.draw(fbo.getColorBufferTexture(), 0, screenHeight, screenWidth, -screenHeight);
batch.end();
}
@Override
public boolean keyDown(int keycode) {
switch (keycode){
case Input.Keys.SPACE:
colorIndex = (++colorIndex) % COLORS.length;
return true;
case Input.Keys.X:
shouldClearFBO = true;
return true;
}
return false;
}
@Override
public boolean keyUp(int keycode) {
return false;
}
@Override
public boolean keyTyped(char character) {
return false;
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
viewport.unproject(touchLocation.set(screenX, screenY));
if (pointer==1){
colorIndex = (++colorIndex) % COLORS.length;
return true;
}
if (pointer == 2){
shouldClearFBO = true;
return true;
}
touchDown = true;
return true;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
touchDown = false;
return true;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
viewport.unproject(touchLocation.set(screenX, screenY));
return true;
}
@Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
@Override
public boolean scrolled(int amount) {
return false;
}
}