How does a frameBuffer interact with multiple camera's and viewports

Viewed 43

My goal is to draw all my visuals to a framebuffer which has a size that matches 1 by 1 with my pixel art assets. And then output the framebuffer texture to the current screen size. (A common solution for scaling pixel art).

The problem I am having while trying to achieve this is 2-fold

  1. The frameBuffer texture is drawn too small. I expect the texture to match the whole window.

texture too small

  1. resizing the screen further distorts the proportions and position. I expect the frameBuffer texture to keep filling the screen after resizing it.

resizing

This is my trimmed down code.

public class BattleScreen extends GameScreen {
    public static final int VISIBLE_WIDTH = 21;
    public static final int VISIBLE_HEIGHT = 21;
    private static OrthographicCamera mapCamera = null;
    private SpriteBatch spriteBatch;
    private OrthographicCamera hudCamera;
    private Hud hud;
    private EntityStage entityStage;
    private FrameBuffer fbo;

    private void initializeVariables(UnitOwner enemy, MapManager mapMgr) {
        mapCamera = new OrthographicCamera();
        mapCamera.setToOrtho(false, VISIBLE_WIDTH, VISIBLE_HEIGHT);
        fbo = new FrameBuffer(Pixmap.Format.RGBA8888, 672, 672, false);
        spriteBatch = new SpriteBatch(900);
        entityStage = new EntityStage();
        hudCamera = new OrthographicCamera();
        hudCamera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    }

    @Override
    public void show() {
        resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        mapCamera.position.set(currentMap.getMapWidth() * 0.5f, currentMap.getMapHeight() * 0.5f, 0f);
        mapRenderer = new OrthogonalTiledMapRenderer(mapMgr.getCurrentTiledMap(), Map.UNIT_SCALE, spriteBatch);
        mapRenderer.setView(mapCamera);

        final FitViewport vp = new FitViewport(VISIBLE_WIDTH, VISIBLE_HEIGHT, mapCamera);
        currentMap.getTiledMapStage().setViewport(vp);
        entityStage.setViewport(vp);
    }

    private void update(final float delta) {
                    mapCamera.position.x = Utility.clamp(mapCamera.position.x, currentMap.getTilemapWidthInTiles() - (mapCamera.viewportWidth * 0.5f), 0 + (mapCamera.viewportWidth * 0.5f));
        mapCamera.position.y = Utility.clamp(mapCamera.position.y, currentMap.getTilemapHeightInTiles() - (mapCamera.viewportHeight * 0.5f), 0 + (mapCamera.viewportHeight * 0.5f));
        mapCamera.update();
        hudCamera.update();
    }

    private void renderElements(final float delta) {
        Gdx.gl.glClearColor(0, 0, 0, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        fbo.begin();
        Gdx.gl.glClearColor(0, 0, 0, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        renderMap();
        renderUnits();
        renderHUD(delta);
        fbo.end();
        spriteBatch.begin();
        Texture texture = fbo.getColorBufferTexture();
        TextureRegion textureRegion = new TextureRegion(texture);
        textureRegion.flip(false, true);
        spriteBatch.draw(textureRegion, 0, 0, fbo.getWidth(), fbo.getHeight());
        spriteBatch.end();
    }

    private void renderMap() {
        spriteBatch.setProjectionMatrix(mapCamera.combined);
        mapRenderer.setView(mapCamera);
        currentMap.getTiledMapStage().getViewport().apply();
        mapRenderer.render();
    }

    private void renderUnits() {
        spriteBatch.begin();
        entityStage.getViewport().apply();
        for (Entity unit : units) {
            final Color temp = spriteBatch.getColor();
            spriteBatch.setColor(new Color(temp.r, temp.g, temp.b, unit.getEntityactor().getColor().a));
            spriteBatch.draw(getFrame(), getEntityactor().getX(), unit.getEntityactor().getY(), 1.0f, 1.0f);
            spriteBatch.setColor(temp);
        }
    }

    private void renderHUD(final float delta) {
        spriteBatch.setProjectionMatrix(hud.getStage().getCamera().combined);
        hud.getStage().getViewport().apply();
        hud.render(delta);
    }

    @Override
    public void resize(final int width, final int height) {
        currentMap.getTiledMapStage().getViewport().update(width, height, false);
        entityStage.getViewport().update(width, height, false);

        hud.resize(width, height);
        pauseMenu.resize(width, height);
    }
}

What I tried is changing the width and height on this line in the render method

spriteBatch.draw(textureRegion, 0, 0, 1000, 1000);

And then it does fill up the whole screen nicely

enter image description here

Which is weird because the screen is 672 x 672 in size.

1 Answers

Fixed problem 1 with the following adaptation

mapCamera.setToOrtho(false, fbo.getWidth(), fbo.getHeight()); //adapt camera to fbo
mapCamera.update();
spriteBatch.setProjectionMatrix(mapCamera.combined);
spriteBatch.draw(textureRegion, 0, 0, fbo.getWidth(), fbo.getHeight());
spriteBatch.end();
mapCamera.setToOrtho(false, VISIBLE_WIDTH, VISIBLE_HEIGHT); //reset camera
mapCamera.update();

The spriteBatch is being reused for the map, the entities and the ui for efficiency. So I had to configure it to project the buffer texture on the screen

Related