On my model I can replace a specific texture in Sandbox via Inspector / Load Texture From File with a variant, and all looks fine. But when I try the same in code, the texture renders wrong.
What is different between the Inspector / Load Texture from File, and simply writing:
mesh.material.albedoTexture = new Texture( "texture.png" );
Thanks for the suggestion, actually tried that one already too. No change, apparently the engine handles the texture.isReady state for us.
Funny thing is I have two similar variant textures, one predominantly light and one dark. The lightness and darkness are apparent in the result, which tells me the specific texture is driving the material in some way, just not the intended way.
Here’s the result from the dark version swapped in at runtime:
And here’s the light version:
I know it looks like the textures themselves must be wrong, but both swap fine in the Sandbox Inspector.
Hmm, it looks like the inspector changes the texture by calling updateURL() on the existing texture (rather than creating a new one). So I guess calling it like below would work like the inspector, by preserving the existing texture’s settings (disclaimer I’ve never actually used/noticed that function before thou).
According to pbrMaterial.d.ts (Im using Typescript), albedoTexture is an instance of BaseTexture, not of Texture. Meanwhile updateURL() is a method on Texture, which extends BaseTexture, and so not available on the PBRMaterial.albedoTexture
But trying it anyway, because who knows…
…
HEY, whadayaknow! Success! Apparently SceneLoader has performed some kind of setup in the initialization of the embedded texture, which I dont/cant know to replicate on my own new Texture(). But at least now I dont need to.
Also, it smells like a minor bug that I should have to do a runtime type check of the albedoTexture to confirm it’s a Texture not a BaseTexture, in order to access a critical method. Maybe Texture.updateURL() should be promoted into the BaseTexture class?
Either way, thank you! New trick learned, if not fully understood. Live texture swap now behaves as intended.
Yes that’s the method I know.
Besides, you can also make clones of textures (not instances) and assign and update them on your materials (whatever material)… and then, to be honest I don’t see the ‘academic part’ issue missing in this aspect in BJS. For me, it all works fine.
@bghgary Except that these are instantiated via SceneLoader.LoadAssetContainer() so I’ve no control over the instantiation of the given Texture.
So to summarize:
SceneLoader instantiates a PBRMaterial with a Texture in albedoTexture (BaseTexture),
requiring runtime explicit type checking to avoid making an otherwise dangerous assumption in calling albedoTexture.updateURL() when I need to do a texture swap.
I mean if runtime type inspection is considered a best practice, okay, it just feels a little wonky to me.