You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
this.texture comes from resolveTextureAtlas(...) → game.renderer.cache.get(image, …), which returns a single TextureAtlas shared per source image. So setting .repeat changes the wrap mode image-globally — every consumer of the same image object samples with that wrap.
Surfaced in the PR-2 code review; not a live bug today, but worth pinning before it bites.
How it's silent
The only consumer that sets textureRepeat today is the glTF loader (GLTFScene / GLTFModel), driven by the material's sampler wrapS/wrapT.
glTF decodes its ownHTMLImageElement objects per asset, so the atlas is effectively private to that load.
All primitives of a given material share one sampler → one wrap mode, so meshes sharing the image (e.g. all 6 parts of a Kenney blocky character share texture-a.png) all want the same wrap → mutating the shared atlas is consistent.
Pointing two Meshes (or a Mesh and a Sprite) at the same image object but wanting different wrap modes: last-writer-wins, and the other consumer's wrap silently flips. Niche today, but it's unguarded shared-state mutation — same class as #1489.
Options
A. Carry the wrap on the Mesh and thread it to uploadTexture / cache.getUnit per-draw, instead of mutating the atlas.
B. Hand out a per-(image, repeat)TextureAtlas instance from the cache (so .repeat is never shared across wrap modes).
Address as part of #1410 (the TextureCache/batcher renderer-agnostic refactor). Same root cause as #1489 (per-image atlas sharing); both should be resolved together there.
Summary
Mesh's newtextureRepeatsetting (added with the glTF node-animation work) sets the wrap mode by mutatingthis.texture.repeat:this.texturecomes fromresolveTextureAtlas(...)→game.renderer.cache.get(image, …), which returns a singleTextureAtlasshared per source image. So setting.repeatchanges the wrap mode image-globally — every consumer of the same image object samples with that wrap.Surfaced in the PR-2 code review; not a live bug today, but worth pinning before it bites.
How it's silent
textureRepeattoday is the glTF loader (GLTFScene/GLTFModel), driven by the material's samplerwrapS/wrapT.HTMLImageElementobjects per asset, so the atlas is effectively private to that load.texture-a.png) all want the same wrap → mutating the shared atlas is consistent.(source, repeat)(post-WebGL: createPattern cache-key collision invalidates earlier pattern handles for the same image #1448), so distinct wrap modes still get distinct GL units — but theTextureAtlas.repeatfield the batcher reads at upload time is the shared one.The trigger
Pointing two
Meshes (or aMeshand aSprite) at the same image object but wanting different wrap modes: last-writer-wins, and the other consumer's wrap silently flips. Niche today, but it's unguarded shared-state mutation — same class as #1489.Options
Meshand thread it touploadTexture/cache.getUnitper-draw, instead of mutating the atlas.(image, repeat)TextureAtlasinstance from the cache (so.repeatis never shared across wrap modes).TextureCache+ batcher refactor, which already touches this whole surface.Recommendation
Address as part of #1410 (the
TextureCache/batcher renderer-agnostic refactor). Same root cause as #1489 (per-image atlas sharing); both should be resolved together there.Cross-refs
framewidth/frameheightrefinement no-op)