How to reuse the same Texture in different Sprites and change the UV individually

I’m working with huge PNG’s that are used as Sprites. Then I change the UV system to show the parts I need. The problem is that I get a huge impact in memory after adding multiple sprites of this kind. I don’t know how to reuse the same texture and change the UV of each sprite.

Is there a technique or hack to solve this issue?

How are you settling the UVs currently? On the Texture itself? Also how are you loading the Textures and associating them with Sprites? A few code samples may get you a more specific answer.

In the meantime, one suggestion is if you happen to be using TextureLoader multiple times for the same image, don’t do that, but instead use Texture.clone which is a shallow copy sharing the image data (but with its oen separate UVs).

Keep in mind that this will still trigger a texture GPU upload for each cloned instance. This is a known issue and discussed here:

The only way of solving this right now is to use same instance of THREE.Texture for all models and modify the uv-coordinates instead (and not Texture.offset or Texture.repeat).

1 Like

By using Texture.transformUv or how? I don’t see any UV property at level of Sprite or SpriteMaterial.

Oh wow, I didn’t know that! Thanks for the tip, that’s a big deal!

So I guess now the question is how to set the UVs of either Sprite or SpriteMaterial. I don’t see an obvious way in the docs, but if you look at the Sprite.js source it has a BufferGeometry on the inside so maybe you can change the UVs there?

The idea is to edit BufferGeometry.attributes.uv. An instead of using THREE.Sprite, use a mesh with a plane geometry that always faces the camera. You can achieve this like so:

mesh.quaternion.copy(camera.quaternion);
1 Like

I see that THREE.Sprite also have sprite.geometry.attributes.uv why I need to use a Plane instead?

And also, any docs where I can understand how to use the uv parameters?

All sprites share the same geometry object which is located in the module scope of Sprite.js. The engine assumes that users do not touch this object. Hence, you will be on the safe side by using plane geometries.

You mean on geometry level? There are no actual uv parameters but just texture coordinates defined as instances of BufferAttribute. So you have to learn how BufferGeometry works in order to get familiar with creating custom texture coordinates.

2 Likes

Using of points is an option too: Split Image into Particle Tiles

1 Like

Sorry that this long-standing issue is not fixed, yet. It’s actually a problem deep inside WebGLRenderer. There is already a PR but it’s unfortunately complex to review.

1 Like

I’m not sure. Let say I have a big image with 8x8 tiles. How can I show the cell/frame I want of that image? Any example that you can refer to?

@Enzo Take a look ati this post: How to have different colors/textures on bottom and top side of a Plane?
See lines 62 - 82 in its codepen’s JS section.
The same material (changed with .onBeforeCompile()) with a texture was used for all planes.

2 Likes

That is a good example thank you :slight_smile:

Hello again. I finally had a working version using the MeshBasicMaterial approach. It worked fine because the huge texture was loaded only once and there wasn’t impact on memory.

The problem is that when I change the opacity or the RGB this is applied to all the object. Is there a new better solution to solve this?