New Sprite uv mechanism

Hi.

Before 91 version of Three.js I was using this hack for same texture atlas for many sprite and set different uv’s

var tex = map.clone();
tex.uuid = map.uuid;
tex.wrapT = tex.wrapS = THREE.RepeatWrapping;
tex.offset.x = res.x1;
tex.offset.y = 1.0 - res.y2;
tex.repeat.set(res.x2 - res.x1, res.y2 - res.y1);

tex.needsUpdate = true;

In 91 versions, WeakMap began to be used and this hack no longer works.
Now, each sprite loads the same texture as many times as many sprites and memory consumption has grown tremendously.
Further in the sprite mechanism added a UV map, but I cannot understand how to use it when I have a texture atlas and different coordinates for different sprites.
If I try set

 var quad_uvs = 
            [res.x1, 1.0 - res.y2,
        res.x2, 1.0 - res.y2,
        res.x2, 1.0 - res.y1,
        res.x1, 1.0 - res.y1];
 var uvs = new Float32Array(quad_uvs);
 meshIcon.geometry.addAttribute('uv', new THREE.BufferAttribute(uvs, 2));

this works but all sprites show the same part of texture.

I looked at the code of the sprite and there the geometry was moved outside of the constructor and the feeling is that the same is used in the end in all the sprites. The same geometry for all Sprites it’s ok for me but the same interleaved buffer contain also uv mapping and when I set values I think all sprites shared also UV’s. Maybe I’m wrong.
For now I’m recreate all geometry for each sprite with different uv and it works.
But I think it’s not a right way.
Please tell me which code now correct for sprites with same texture atlas and different UV’s.

Thanks.

The title of your post is somewhat confusing since the mentioned problem is not restricted to sprites. The introduction of WeakMap in three.js removed a hack that allowed to have multiple texture objects with identical unique IDs. More information about this issue right here:

Using geometries with different texture coordinates is currently the recommended workaround. Although the linked issue is closed, there might be changes in the future that allow a more flexible usage of texture parameters.

So for now I must make own geometry for each sprite and just replay code inside sprite object like this?

        var meshIcon = new THREE.Sprite(material);
        
        var geometry = new THREE.BufferGeometry();

        var float32Array = new Float32Array([
            - 0.5, - 0.5, 0, res.x1, 1.0 - res.y2,
            0.5, - 0.5, 0, res.x2, 1.0 - res.y2,
            0.5, 0.5, 0, res.x2, 1.0 - res.y1,
            - 0.5, 0.5, 0, res.x1, 1.0 - res.y1
        ]);

        var interleavedBuffer = new THREE.InterleavedBuffer(float32Array, 5);

        geometry.setIndex([0, 1, 2, 0, 2, 3]);
        geometry.addAttribute('position', new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0, false));
        geometry.addAttribute('uv', new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3, false));
        meshIcon.geometry = geometry;

Yes, seems to look correct.

1 Like