I don't undertand TextureAtlas

OK. I searched the forum for some more examples of using TextureAtlas, and I came across this topic, which has a nice example of how to load several textures into a TextureAtlas, and then use TextureAtlasTile.transformTextureCoords to assign a particular texture to a geometry. So, I’ve been playing around with this quite a bit.

I extended that example to create a wall of 400 tiles, each with one of 1,024 random textures, each 32 by 32 pixels, and then update the texture of a random tile 500 times per second. If the wind is blowing in the right direction, I get about 1500 FPS running this.

private TextureAtlas atlas;
private Texture[] texture = new Texture[1024];
private Material material;
private Random random = new Random();
private Geometry[][] tiles = new Geometry[20][20];
private float time;

@Override
public void simpleInitApp() {
    atlas = new TextureAtlas(1024, 1024);
    
    String[] files = {
        "Textures/red.png",
        "Textures/green.png",
        "Textures/blue.png",
        "Textures/yellow.png"
    };
    
    for (int i = 0; i < 1024; i++) {
        texture[i] = assetManager.loadTexture(files[i % 4]);
        
        atlas.addTexture(texture[i], "ColorMap");
    }
    
    material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    material.setTexture("ColorMap", atlas.getAtlasTexture("ColorMap"));
    
    for (int x = 0; x < 20; x++) {
        for (int y = 0; y < 20; y++) {
            addTile(x, y);
        }
    }
}

@Override
public void simpleUpdate(float tpf) {
    time += tpf;
    
    if (time > 0.002f) {
        time -= 0.002f;
        
        int x = random.nextInt(20);
        int y = random.nextInt(20);

        tiles[x][y].removeFromParent();

        addTile(x, y);
    }
}

private void addTile(int x, int y) {
    Quad quad = new Quad(1, 1);
    
    tiles[x][y] = new Geometry("Tile", quad);
    tiles[x][y].setLocalTranslation(x - 10, y - 10, -10);
    tiles[x][y].setMaterial(material);
    
    FloatBuffer buf = quad.getFloatBuffer(Type.TexCoord);
    atlas.getAtlasTile(texture[random.nextInt(1024)]).transformTextureCoords(buf, 0, buf);
    
    rootNode.attachChild(tiles[x][y]);
}

I’m actually only using four images, but, I’m loading them 256 times each. I don’t think this will affect the results.

I then did the same thing without using TextureAtlas, and typically get about 800 FPS running this:

private Texture[] texture = new Texture[1024];
private Random random = new Random();
private Geometry[][] tiles = new Geometry[20][20];
private float time;

@Override
public void simpleInitApp() {
    String[] files = {
        "Textures/red.png",
        "Textures/green.png",
        "Textures/blue.png",
        "Textures/yellow.png"
    };
    
    for (int i = 0; i < 1024; i++) {
        texture[i] = assetManager.loadTexture(files[i % 4]);
    }
    
    for (int x = 0; x < 20; x++) {
        for (int y = 0; y < 20; y++) {
            addTile(x, y);
        }
    }
}

@Override
public void simpleUpdate(float tpf) {
    time += tpf;
    
    if (time > 0.002f) {
        time -= 0.002f;
        
        int x = random.nextInt(20);
        int y = random.nextInt(20);

        tiles[x][y].removeFromParent();

        addTile(x, y);
    }
}

private void addTile(int x, int y) {
    Quad quad = new Quad(1, 1);
    
    tiles[x][y] = new Geometry("Tile", quad);
    tiles[x][y].setLocalTranslation(x - 10, y - 10, -10);
    
    Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    material.setTexture("ColorMap", texture[random.nextInt(1024)]);
    tiles[x][y].setMaterial(material);
    
    rootNode.attachChild(tiles[x][y]);
}

Results vary greatly from one run to the next, however. In both cases, FPS will start well over 1000 for several seconds, but is more likely to stabilize well below 1000 when not using TextureAtlas. However, sometimes I run the version without TextureAtlas, and FPS will stabilize at over 1000 FPS, and then, when I run the version with TextureAtlas, FPS will stabilize well below 1000, meaning that, occasionally, the version without TextureAtlas actually runs faster.

On my PC, updating tiles 500 times per second causes the version with TextureAtlas to (tend to) greatly out-perform the version without TextureAtlas. Updating the tiles much more or less than 500 times per second, and the difference in FPS is less pronounced. In these cases, the version with TextureAtlas does still tend to do better than the version without though. For example, with TextureAtlas, I’ll get about 850 FPS, and without TextureAtlas, about 775 FPS.

If the scene isn’t updated, then TextureAtlas doesn’t make any difference to FPS. So, when used like this, TextureAtlas only seems to make a difference when the scene is getting updated a lot.

1,024 textures seems quite a lot. However, using just four textures instead, TextureAtlas doesn’t make any difference. I also tried using four textures, but each one being 2048 by 2048 pixels, but, TextureAtlas still didn’t make any difference.

Hope all this matches up with what is expected when using TextureAtlas, and that I haven’t gone off in completely the wrong direction with it. I’m just trying to understand how to use it, and in what situations it can make a difference.