For code as mentioned in the post you referenced , i did resort to waiting for the texture to load before assigning it to the material to prevent that dissapearing issue
my material update function handles just routing the call to 3 types of materials in my scene , not very fancy , just some conditionals :
function updateMaterial(materialData) {
let mat = collectionMaterials[materialData.name];
if (!mat) {
createUpdateMaterialPending(materialData);
return;
}
if (mat instanceof NodeMaterial) {
let wrapper = collectionMaterialsWappers[mat.name];
if (wrapper) {
if (wrapper instanceof NodeMaterial1) {
updateMaterialNode1(materialData);
}
if (wrapper instanceof NodeMaterial2) {
updateMaterialNode2(materialData);
}
}
} else {
updateMaterialPBR(materialData);
}
}
this is my PBR update function :
function updateMaterialPBR(materialData) {
let mat = collectionMaterials[materialData.name];
//props
for (let prop in materialData.props) {
mat[prop] = materialData.props[prop];
}
//colors
for (let prop in materialData.colors) {
let colorKey = materialData.colors[prop];
console.log(colorKey)
let colorAsset = colorCache[colorKey];
if (!colorAsset) {
let colorHex = getColor(colorKey);
if (colorHex.length > 7) {
colorAsset = colorCache[colorKey] = Color4.FromHexString(colorHex).toLinearSpace();
} else {
colorAsset = colorCache[colorKey] = Color3.FromHexString(colorHex).toLinearSpace();
}
}
mat[prop] = colorAsset;
}
//textures
for (let prop in materialData.textures) {
let textureData = materialData.textures[prop];
let textureURL = textureData.url;
if (!textureURL) {
textureURL = getTexture(textureData.key);
}
//the cache key is using the url now instead of key , since te same texture is listed under several keys for some assets
//and if I dont use the url , then it will create redundant textures in memory
let textureAsset = textureCache[textureURL];
if (!textureAsset) {
textureAsset = textureCache[textureURL] = new BabylonTextureAsset(textureURL);
textureAsset.texture = new Texture(window.location_url + textureURL + "?cache_uid=" + buildNumber.value);
for (let textureProperty in textureData.textureProperties) {
textureAsset.texture[textureProperty] = textureData.textureProperties[textureProperty];
}
textureAsset.texture.onLoadObservable.addOnce((eventData) => {
var texCacheKey = textureURL;
var mk = materialData.name;
var ck = prop;
collectionMaterials[mk][ck] = eventData;
textureCache[texCacheKey].loadSuccess();
});
textureAsset.load();
} else {
if (textureAsset.texture.isReadyOrNotBlocking()) {
mat[prop] = textureAsset.texture;
} else {
//more than one material might want to use this same texture , and the first call to use it would cause a creation and load,
//since subsequent calls will find it exists they then also need a callback for applying it once loaded
textureAsset.texture.onLoadObservable.addOnce((eventData) => {
var mk = materialData.name; // mk is material key
var ck = prop; // ck is channel key
collectionMaterials[mk][ck] = eventData;
});
}
}
}
}
there is a bit happening in there but really:
it gets a reference to the material and set properties ,
Some updates are primitive values , so they are just handled in a loop at first
materialData.props
Some updates are color values , so they are handled specifically
materialData.colors
Some updates are texture values , so they are handled specifically
materialData.textures
take note a texture can also have properties , these are primitive values again and just handled with a loop again within the block of code handling texture updates ( things like texture level or UV index etc)
textureData.textureProperties
There is some extra complexity in my texture handling because my update system could have more than one material calling for an update that will share a texture , so I need to track this but anyway , hopefully you can see what is happening in the code , the part from the thread you mentioned :
inside the observable ,
textureAsset.texture.onLoadObservable.addOnce...
I assign the texture to the channel on the material :
collectionMaterials[mk][ck] = eventData;
when disposing :
for (let prop in textureCache) {
let texAsset = textureCache[prop];
if (texAsset.texture) {
texAsset.texture.dispose(false, true);
}
texAsset.texture = null;
texAsset = null;
}
textureCache = null;