How to apply offsets for texture atlas in InstancedMesh?

Hi. I’m trying to create minecraft bootleg, which, unsurprisingly takes has thousands of blocks to render, so using InstancedMesh is very effective. I already know I have to use a texture atlas and apply the texture and simply offset it, but all my attempts on this didn’t work. Could anybody write an examplary code for me to work off from? I believe from an example handling 2 textures I would be able to move on. Unfortunatelly I only end up with errors rn. Thanks for any reply!

I got bad news for you. InstancedMesh will not work, it doesn’t let you carry arbitrary attributes. However, you can write your work version of InstancedMesh, using InstancedBufferGeometry and Mesh. Not that hard to be honest. //incorrect

After that, you need to have a per-instance attribute that encodes a UV region of the atlas that should be used for the block. I typically encode those as vec4 with the structure vec4(u0, v0, us, vs) where u0,v0 are offsets into the atlas, and us,vs are scale factors for the patch (like 0.1 for 1/10 of the entire atlas length). Deriving atlas UV from there is pretty trivial, you get your standard UV and do this:

vec2 patch_uv = (uv - vec2(u0,v0) ) * vec2(us,vs);

I’ve been doing something similar for my particle engine, and it’s been working great for me.


just for completeness, I should say that it is theoretically possible to use InstancedMesh by coopting the per-instance color attribute which is vec3, and encoding your patch UV in there, and then doing voodoo in the shader to decode that. But I would strongly advice against that - as if you’re making a Bootcraft or a Mineleg, you’ll probably end up needing more attributes per block than just the atlas, such as lighting info. As well as packing things this way just being super hacky.

2 Likes

You can add any InstancedBufferAttribute to the geometry (for example, BoxGeometry, or SphereGeometry, any buffer geometry actually), that you pass into InstancedMesh constructor, and it’ll work.
For reference: javascript - How can I colour points differently in three.js using dat.gui depending on their distance from the origin? - Stack Overflow
colorIdx is an InstancedBufferAttribute, added to SphereGeometry, that’s used in InstancedMesh.

3 Likes

Oh wow, didn’t know that. Thanks for the pointer.

Note that you’ll probably have to make sure that the new attribute that you add has the right number of instances allocated for it.

Hi, thanks for your answer. I know what I’m about to ask should be a brand new topic, but seeing you have some knowledge around this topic, have you got any code directly for texture atlas? I attempted to do the thing but it ended up swapping the texture only randomly

Not the exact thing you’re looking for, but something close: How to use spritesheet in this special case? - #2 by prisoner849

Maybe better to show what you’ve tried in an editable live code example, so it would be easier to provide help (not specifically from me, but from users, who would like to help).

As much as I would like to do that, I use assets like perlinjs, pointerlockcontrols etc and due to my smartness I have edited the code even further, opting for directly swapping textures and now Im left with a code with inner workings completely different to what I intended + it still produces the same issue so yeah, me happy now. Do you think the code is worth sharing, still?

Only you know what and how works in your code, and how the final result has to look like :slight_smile:
A minimal live code example would be enough. And reference pics of what you have and what you would like to have.
So far, all my help is random shots to choose the right things for you.

I’m still very happy for that anyways.
I decided to upload the entire code to my website as I was unable to get it running anywhere - if anybody wants to witness the mess - https://itzarty.xyz/ext/mc/, complete js code at https://itzarty.xyz/ext/mc/script.js. I tried implementing texture swapping per block but that didnt work out, as only the top layer should be dirt, the rest should be cobblestone. Im still looking forward to texture atlas because later, I believe it would be way easier to implement new masses of blocks. I know Im providing the code poorly but I have written just too much to treat the thing by blocks of code.

I’ve got “500 Internal Server Error” for both links provided :frowning:

Sorry, I had everything cached, it should work now just fine

Does it have to look something like this?

Exactly, if this would be achieved with texture atlas, yes, that would be exactly what Im looking for, but Im looking forward to alternatives as well.

Yes, this is achieved with a texture atlas.
изображение
I encoded it to base64, the purpose is not to use external textures in the jsfiddle. Basically, it’s your textures (cobblestone and dirt), merged into one (atlas).

This is a very rough example, not the ultimate solution: Edit fiddle - JSFiddle - Code Playground

1 Like

Allow me to say one thing; You are a legend! I know I effectively just made you do what I was supposed to, but my skills with C++ or whatever languge that is are very poor. Thanks you much!

You’re welcome :beers:
I hope the example helps :slight_smile:

Alrighty! Very useful stuff, actually finally managed to generate a lagless world, but I have to ask this: where & how exactly are these atlas offsets defined etc. as I have been only unsuccessfully able to expand the atlas (some textures went over each other & similar stuff). Thing works great, but I really wasnt able to expand it. Tl;dr: Just need to know where and how the UVs are set specifically and how to extend the atlas (Aaaaand yeah, I know this starts to be annoying but is it possible to adjust some faces specifically? And also, the textures seem kinda stretched or something like that, is it just me doing something wrong? - I really do appreciate the help, but it’s too complicated for me, I just wanna do the exciting parts like caves etc)