Solved: All sprites use single material offset

Hello,
I’m trying to make particles use single texture map with different offsets (UV coordinates) and I am certain it had worked before. However, no mater how much I try changing offset of one particle changes all of them.
Here’s what I got so far:
https://codepen.io/anon/pen/BedNZR
It uses 4x4 texture map and each particle should get a randomized offset, however, as you can see, all sprites change instead of one.
Would be grateful for any input on the matter.

The problem is that cloning a material does not clone its textures. Hence, modifying offset or repeat affects all sprites.

I’ve changed your code so it produces the intended behavior. However, there are two things to keep in mind.

  • Cloning of textures does only work if the texture has fully loaded. Hence, the scene is now initialized when the onLoad callback of TextureLoader.onLoad() fires.
  • It’s important to set Texture.needsUpdate to true. Otherwise, texture data are not uploaded to the GPU.

https://codepen.io/anon/pen/byryOo

1 Like

Thank you @Mugen87 ! That’s exactly what I was looking for.

I wonder if cloning texture still uses same memory or each clone fills memory with copy of same pixels thus missing the point of using texture-map as memory optimization?
I mean what is more optimal in this case - using a texture map or a bunch of separate textures and assign new one per particle change?

Using multiple texture objects is flexibel but somewhat bad for memory consumption. Each instance of THREE.Texture represents a single WebGLTexture meaning you allocate redundant memory and perform redundant texture uploads to the GPU. This is a current limitation of the library. Also see:

I can see that. Using your solution renderer.info.memory.textures count goes up to 400 so it’s not an optimization at all :confused:
I wonder what will be cheaper - loading 16 separate textures to assign to the cloned materials so that it changes (if it’s not a clone should use same texture?)
Using plane mesh instead of a sprite with a custom shader for UV manipulation? But each geometry is a new redraw so it would hit on performance a bit?

No, since sprites are also drawn individually. You can only draw a group of sprites with a single draw call when using THREE.Points like in the following example or some sort of instanced rendering (which requires custom shader code).

https://threejs.org/examples/webgl_points_sprites

I’m trying a different workaround:
https://codepen.io/driezis/pen/arLbKN

Added an additional variable to each sprite object called myOffset (Vector2) and added an onBeforeRender call for each sprite. That way it uses 1 texture map, 1 geometry. However I have no idea if it impacts performance significantly.

2 Likes

I think this is a valid approach. Can’t think of a better one right now…

1 Like