[SOLVED] TextureAtlas to Voxel Engine

Hello monkeys :monkey_face: !

I’m designing a TextureAtlas to a Voxel Engine, to have a better memory usage and such. But I have a question about how to design it, follow-me:

I have a big picture texture which I got on those Minecraft forum, just for testing, so it’s a Textured Tiled png file, where I have 16x16 textures of 128 pixels on ABGR8 format.

What I understand that I have to do is to load this image into a single Texture (which I named “atlas”) and get the needed sub textures from it, so If I need the texture placed on (3, 4) of atlas, I just return a sub texture originated from this bigger texture.

So, my question is, since the main atlas Texture is backed by an Image which is backed by a ByteBuffer, how I supposed to get a reference from this main ByteBuffer (the “atlas” one) which contains only the relevant sub texture without copying (allocating more memory) it to a new ByteBuffer??

I don’t know If I was clear enough but since the main goal of TextureAtlas is to have a single copy of a bigger tiled texture on memory, when I have to create small ByteBuffer (sub textures) from this atlas, i’m duplicating my needed memory, no?

Here is my piece of code, where I generate a new Texture based on main bigger tiled Texture. On bellow code, I duplicated the needed memory because i’m hosting a bigger texture (atlas) and sub textures:

private Texture getTexture(int x, int y) {
    //The texture loaded on atlas contains less then 2GB, so get the first ByteBuffer;
    List<ByteBuffer> list = atlas.getImage().getData(0);

    //those a constants, but they are here just to illustrate.
    int IMAGE_TILE_SIZE = 16;
    int IMAGE_PIXELS = 128;
    int IMAGE_CHANNELS = 4;
    int IMAGE_BYTES = IMAGE_PIXELS * IMAGE_CHANNELS;
    int IMAGE_SIZE = IMAGE_PIXELS * IMAGE_PIXELS * IMAGE_CHANNELS;
    int IMAGE_ROW_SIZE = IMAGE_BYTES * IMAGE_TILE_SIZE;

    int beginIndex = (x * IMAGE_PIXELS * IMAGE_ROW_SIZE) + (y * IMAGE_BYTES);

    //This may be switched to a global temp buffer, to avoip allocating new arrays every time.    
    byte[] b = new byte[IMAGE_SIZE];

    for (int i = 0; i < IMAGE_PIXELS; i++) {
        buffer.position(beginIndex + (i * IMAGE_ROW_SIZE));
        buffer.get(b, i * IMAGE_BYTES, IMAGE_BYTES);
    }

    //To create a new Image, I must have to send to constructor a new direct allocated ByteBuffer 
    Image img = new Image(Image.Format.ABGR8, IMAGE_PIXELS, IMAGE_PIXELS, ByteBuffer.allocateDirect(IMAGE_SIZE).put(b));
    return new Texture2D(img);
}

That’s not how texture atlases work. You are working from a few misunderstandings, actually.

Texture atlases aren’t about ‘reducing memory’… the same memory is used either way. It’s about reducing texture state changes and improving batching. Better to have one shared material than 20 separate materials + state switches… and better still if it lets you batch more geometry into larger meshes.

A texture atlas is a big texture that you index into with texture coordinates. If you have a 16x16 atlas then the 0,0 tile is texture coordinates 0,0 → 1/16, 1/16 (roughly).

1 Like

@pspeed, after thinking a lot about it, I think I understood. I will created a big texture, say with 10x10 tiles, where all those textures shares the same material properties, like shinning and no-alpha for example. So I create a single material, with this bigger texture, and set the textCoord of vertex (I have all my voxels joined in a single mesh per chunk) to match the desired coordinates.

If I need texture (3,3) I just do a similar function, like previous, but considering the texture bounds as 0,1 and tile bounds as 0,1/10…

Is that way you meant?

Exactly. Also notice you don’t have an actual bunch of boxes in your mesh, only the visible surfaces. So if you have two boxes next to each other you don’t have an actual surface between them.

1 Like

I don’t work with box, I just pre-compute the visible faces of chunk and then compute a single mesh, which I call Chunk.

Actually the problem that i’m seeing with this TextureAtlas approach is how to tile tiled textures…If a have a mesh where it’s vertices is:

v2(0,1)             v3(4,1)
    +----+----+----+
    |              |
    +----+----+----+
v0(0,0)             v1(4,0)

So if I want to set texture (1,1) from atlas (using my previous example), I have to get the texture 1/10,1/10 => (0.10,0.10).

v0 => [0.10, 0.10]
v1 => [0.20, 0.10]
v2 => [0.10, 0.20]
v3 => [0.20, 0.20]

But this will lead in a stretched texture on X axis. If I wasn’t using TextureAtlas, I would just scale texture on X axis by 4. How I can avoid this stretch on X axis, given this example?

I hope I don’t have to write my own shader… :sweat_smile:

Don’t use texture atlases. Or write your own shader.

I’ll understand this as “There is no way to use TextureAtlas and avoid stretching without creating custom shader to handle it”, :sweat:

But thanks guys! I’ll dive deep into shader now…

You could also not do greedy mesh generation.

Everything has tradeoffs.

Note: Mythruna does not use a texture atlas at all for regular blocks. Though I reserve the right to do it later… it’s just as likely that I’ll use a texture array instead.

By texture array, you mean OpenGL Array Texture or a simple array with textures and scale or fract coordText?

I think for Voxel Engine don’t use faces join algorithms, like greedy mesh, isn’t an option, since it reduces a lot the number of drawCalls.

No, it reduces the size of the mesh.

Note: Mythruna doesn’t do greedy mesh generation either.

And by texture arrays I meant openGL texture arrays.

1 Like

I’ll dive into shader, because I think I’ll need it to do another things, like Occlusion and some lightning, so It’s time to master it.

I would like just to note something about Shaders on JME3:

Man, this ShaderNode design is really amazing! Not just because SDK have a visual editor, but the logic is really fantastic!! I was afraid in working with shader, because I did it already on C++ and it’s a pain to compile, change and maintain, but this!!, this is really amazing.

Congratz guys!

thanks :wink: