GLTF Model has extra texture from a Blender export with Armature Modifier

Does anybody know why a Blender glTF export with a character armature modifier, results in a “phantom” texture being used.

I was playing around with a texture editor, so I was regularly dispose of all the geometries, materials and textures in the scene. Then I noticed that the texture count was going up and up?

I was trying to figure out a way to dispose of this “phantom” texture but I couldn’t find it anywhere. I was traversing the whole scene, looking in the gltfloader cache files and even disposing the renderer. Still couldnt get rid of it.

I found out that if you apply the armature_modifier in blender before the export the “phantom” texture goes away. But I lose the animations. (Note: they are there, they just don’t deform the mesh)

Any help would be much appreciated

Below is a screenshot of simple scene with a glb model with no texture.

( The original courtesy of [quaternius])(https://quaternius.com/)

Skinned mesh animation is done on the gpu I think and animation bones are written to a data texture.

Might this be the ghost texture?

Thanks @manthrax. That sounds like a very plausible explanation.

If it is, do you have any ideas on how to dispose of it?

I think it’s an internal cache with no exposed interface. It may be used to cache bones for multiple skinned models for instance… so it may stick around in case new skinned models come in.

Are you seeing many of them pile up? That could be a legit bug if true…

From my testing.
→ add skinned mesh to scene
→ dispose of all geoms, mats and textures.
→ clear scene.

→ upload new gltf via file.
→ repeat

The renderer.info shows an additional texture for each skinned mesh I added. Non-skinned meshes with textures were successfully removed.
I suppose it could be a bookkeeping bug. Or something I’m doing wrong with disposing of the scene.


  scene.traverse((child) => {

    if (child.geometry) {
      child.geometry.dispose();
    }

    if (child.material) {
      if (Array.isArray(child.material)) {
        for (let i = 0; i < child.material.length; i++) {
          const mat = child.material[i];

          for (const key in mat) {
            if (mat[key]?.isTexture) {
              mat[key].dispose();
            }
          }

          mat.dispose();
        }
      } else {
        if (child.material.map) {
          child.material.map.dispose();

          for (const key in child.material) {
            if (child.material[key]?.isTexture) {
              child.material[key].dispose();
            }
          }
        }
        child.material.dispose();
      }
    }
  });

  for (let i = scene.children.length - 1; i >= 0; i--) {
    const child = scene.children[i];
    if (!child.type.includes('Light')) {
      scene.remove(child);
    }
  }

Also here is a jsfiddle

Are you sharing an AnimationMixer between characters? Might be hanging off the mixer…

Might be skinnedMesh.skeleton.dispose()?

1 Like

Yes thanks @donmccurdy - It was this!

Also just and extra thanks for all your great work. Love gltf.report and your articles online. Plus all help you post. really appreciate it.

1 Like