LibGDX 如何防止 tilemap 中的纹理渗色

How to prevent texture bleeding in a tilemap in LibGDX

我知道有很多关于这个主题的问题(和答案),但它们都有不同的解决方案,其中 none 似乎适用于我的情况。

我正在用 libGDX, in which I tried to add a simple tilemap. I created the tilemap using Tiled 开发一个小型测试项目,它似乎工作得很好,除了纹理渗色,有时会导致瓷砖之间出现黑线(背景色)。


目前我尝试过的:

我阅读了几个 SO 问题、教程和论坛帖子,并尝试了几乎所有的解决方案,但我似乎无法正常工作。大多数答案都说我需要在图块之间进行填充,但这似乎并不能解决问题。我还尝试使用不同的参数加载 tilemap(例如,在加载它们时使用 Nearest 过滤器)或舍入相机的位置以防止舍入问题,但这甚至使情况变得更糟。


我目前的设置:

您可以在 GitHub 上找到整个项目。该分支称为 'tile_map_scaling'

目前我正在使用由这张图块图片组成的图块集:

每个图块之间有两个 space 像素,用作填充和边距。

我的 Tiled tileset 设置如下所示:

我使用两个像素的边距和间距,以(尝试)防止此处出现渗色。

大多数情况下渲染得很好,但有时在图块之间仍然有这些线,就像这张图片中的那样(有时它们似乎只出现在地图的一部分上):

我目前正在不带任何参数将瓦片地图加载到资产管理器中:

public void load() {
    AssetManager manager = new AssetManager();
    manager.setLoader(TiledMap.class, new TmxMapLoader(new InternalFileHandleResolver()));
    manager.setErrorListener(this);
    manager.load("map/map.tmx", TiledMap.class, new AssetLoaderParameters());
}

... 并像这样使用它:

public class GameScreen {

    public static final float WORLD_TO_SCREEN = 4.0f;
    public static final float SCENE_WIDTH = 1280f;
    public static final float SCENE_HEIGHT = 720f;

    //...

    private Viewport viewport;
    private OrthographicCamera camera;
    
    private TiledMap map;
    private OrthogonalTiledMapRenderer renderer;
    
    public GameScreen() {
        camera = new OrthographicCamera();
        viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);

        map = assetManager.get("map/map.tmx");
        renderer = new OrthogonalTiledMapRenderer(map);
    }

    @Override
    public void render(float delta) {
        //clear the screen (with a black screen)
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    
        moveCamera(delta);
        renderer.setView(camera);
        renderer.render();
        //... draw the player, some debug graphics, a hud, ...
        moveCameraToPlayer();
    }

    private void moveCamera(float delta) {
        if (Gdx.input.isKeyPressed(Keys.LEFT)) {
            camera.position.x -= CAMERA_SPEED * delta;
        }
        else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
            camera.position.x += CAMERA_SPEED * delta;
        }
        
        // ...

        //update the camera to re-calculate the matrices
        camera.update();
    }


    private void moveCameraToPlayer() {
        Vector2 dwarfPosition = dwarf.getPosition();
        
        //movement in positive X and Y direction
        float deltaX = camera.position.x - dwarfPosition.x;
        float deltaY = camera.position.y - dwarfPosition.y;
        float movementXPos = deltaX - MOVEMENT_RANGE_X;
        float movementYPos = deltaY - MOVEMENT_RANGE_Y;
        
        //movement in negative X and Y direction
        deltaX = dwarfPosition.x - camera.position.x;
        deltaY = dwarfPosition.y - camera.position.y;
        float movementXNeg = deltaX - MOVEMENT_RANGE_X;
        float movementYNeg = deltaY - MOVEMENT_RANGE_Y;
            
        camera.position.x -= Math.max(movementXPos, 0);
        camera.position.y -= Math.max(movementYPos, 0);
        
        camera.position.x += Math.max(movementXNeg, 0);
        camera.position.y += Math.max(movementYNeg, 0);
        
        camera.update();
    }
    
    // ... some other methods ...
}

问题:

我在 tilemap 上使用填充,也尝试了不同的加载参数和四舍五入相机位置,但我的 tilemap 中仍然存在纹理渗色问题。
我错过了什么?或者我做错了什么?

任何帮助都将非常有用。

您需要在图块表中填充图块的边缘。 看起来您已尝试这样做,但填充是透明的,它需要具有填充像素的颜色。

因此,如果您有这样的图像(其中每个字母是一个像素,图块大小是一个):

AB
CB

然后填充它应该看起来像这样

 A  B 
AAABBB
 A  B
 C  C
CCCCCC
 C  C

被填充的像素必须用相同颜色的像素填充。

(我会尝试为您的 git-repo 创建一个包含修复的拉取请求。)

作为 bornander 回答的一点补充,我创建了一些 python 脚本,它们完成所有工作以生成一个 tileset 纹理,它具有正确的边缘填充(bornander 在他的回答中解释)来自纹理,还没有填充。

以防万一有人可以使用它,可以在 GitHub 上找到它: https://github.com/tfassbender/libGdxImageTools

还有一个可以挤出瓷砖的npm包。它是为 Phaser JS 游戏库构建的,但您仍然可以使用它。 https://github.com/sporadic-labs/tile-extruder