jcmesserschmidt
You are passing the region a THREE Texture, but it expects a Spine ThreeJsTexture.
I see at least three ways to get your result.
The first is to use the Spine asset manager to load the texture, transforming your createRuntimeAttachment like this:
async function createRuntimeAttachment(
skeletonMesh,
attachmentName,
imgUrl,
) {
const spineThreeJsTexture = await assetManager.loadTextureAsync(imgUrl);
const image = spineThreeJsTexture.texture.image;
const region = new spine.TextureAtlasRegion(new spine.TextureAtlasPage(imgUrl), imgUrl);
region.u = region.v = 0;
region.u2 = region.v2 = 1;
region.page.width = region.width = region.originalWidth = image.width;
region.page.height = region.height = region.originalHeight = image.height;
const atlas = new spine.TextureAtlas("");
atlas.pages.push(region.page);
atlas.regions.push(region);
region.page.setTexture(spineThreeJsTexture);
const attachment = new spine.RegionAttachment(attachmentName, attachmentName);
attachment.width = image.width;
attachment.height = image.height;
attachment.region = region;
attachment.updateRegion();
return attachment;
}
If you want to use the ThreeJS texture loader, you can keep your createRuntimeAttachment with some small modifications:
const textureLoader = new THREE.TextureLoader();
return new Promise((resolve, reject) => {
textureLoader.load(
imgUrl,
(texture) => {
const image = texture.image;
const region = new spine.TextureAtlasRegion(new spine.TextureAtlasPage(imgUrl), imgUrl);
region.u = region.v = 0;
region.u2 = region.v2 = 1;
region.page.width = region.width = region.originalWidth = image.width;
region.page.height = region.height = region.originalHeight = image.height;
const atlas = new spine.TextureAtlas("");
atlas.pages.push(region.page);
atlas.regions.push(region);
region.page.setTexture(new spine.ThreeJsTexture(texture.image, false));
const attachment = new spine.RegionAttachment(attachmentName, attachmentName);
attachment.width = texture.image.width;
attachment.height = texture.image.height;
attachment.region = region;
attachment.updateRegion();
resolve(attachment);
},
undefined,
(error) => {
console.error(`Failed to load texture ${imagePath}:`, error);
reject(error);
}
);
});
Pay attention because spine.ThreeJsTexture creates a new ThreeJS Texture, so you probably want to create a variation that does not create the texture but keeps the rest.
A third, quicker but hacky solution is to add a texture property to the ThreeJS Texture that references itself:
texture.texture = texture
This is the main reason your code does not work, because the renderer expects the actual texture in that property. See it here. However, since the texture you are passing to the region lacks some methods (like setFilters), the runtime may invoke them and throw an error.
So my advice is to use method 1 or method 2.