Changing texture url prop does not change the image used in texture
Created a playground example with a toggle button that switches between two URL-s:
https://brianzinn.github.io/react-babylonjs/playground?snippetId=CTqBHrbd
But the image used by the texture is not updating.
This possibly happens because setting the url prop of a Texture does nothing. Instead one needs to call updateURL().
When I update the playground example with a code that calls updateURL() inside an effect, it works:
function MyMaterial({url}: {url: string}) {
const ref = useRef<StandardMaterial>(null);
useEffect(() => {
if (ref.current) {
ref.current.diffuseTexture.updateURL(url);
}
}, [url]);
return (
<standardMaterial ref={ref} name="mat">
<texture url={url} />
</standardMaterial>
)
}
PS. I tried copying the whole code from playground to here as well, but for some reason the copy functionality doesn't quite work there.
it's kind of a known issue. it likely is a bug on the one hand. this will work:
<standardMaterial ...>
<texture key={url} url={url} />
</standardMaterial>
The "bug" is that the updateUrl isn't mapped properly - it's not a known property, since it's a function and those aren't usually mapped. I think only observables are by default.
The "feature" might be to detect constructor properties that aren't properties of an object that are updated after instantiation to create a new instance. That might be confusing for some people, especially when we have in some instances like what you have another way to update the url.
I did at one point a bunch of investigation on the mesh shapes like 'box', 'sphere', 'ground', etc. That if the construction/builder props were updated that it would update the underlying mesh. It started to get a bit involved and I was wondering where to make the distinction between a lighter Renderer vs. a full framework with knowledge of all the components. I can detect which properties are constructor only through the code generation, but haven't made any decisions to use it yet.
I wanted to add as well - what a declarative solution would look like. So, the updateUrl would be supplied when the texture is created, but then altered as a prop? There would need to be some convention for props that would not call the underlying function as well. Not sure what that would look like...
As a user I really would just expect to be able to write <texture url={dynamicUrl} />. Having to write <texture updateUrl={dynamicUrl} /> would be really confusing. Though I might be misunderstanding what you're saying.
One thought I have is that mutating a prop that is BabylonJS constructor parameter and doesn't have a setter could just trigger recreation of the whole BabylonJS object.
I agree with everything you said. url isn't a property that seems to do anything, but I would expect that as well:
https://github.com/BabylonJS/Babylon.js/blob/master/packages/dev/core/src/Materials/Textures/texture.ts#L211
whereas the function actually does something: https://github.com/BabylonJS/Babylon.js/blob/master/packages/dev/core/src/Materials/Textures/texture.ts#L575
I am trying to balance between writing custom code for every object in Babylon.js with escape hatches. Here, for example, I would even think the real change belongs upstream...
edit: so, despite this "constructor" arg having a matching url property, even if I coded it to create a new Texture you would actually not do so here, since an instance property of the same name exists! 😄 i think url should have a get() that calls updateUrl() in the main library when it changes, but it would need a backed prop.
I really appreciate you creating these issues. It's useful to reconsider some design decisions, especially ones that make the library harder to use than it needs to be. Hopefully I have some time in ~10 days to address a couple of them.
Hey so I'm currently looking at the example on https://brianzinn.github.io/react-babylonjs/examples/textures/image-textures and the <texture> tag here doesn't have an url in it, but the current version requires an url attribute to be given. What should I put in the url attribute here?
I hope you could help me on this!
hi @trietng - that's because it's using fromInstance, which means that instead of asking react-babylonjs to instantiate a Texture class for you that you will instead be supplying your own instance. That example was done to load the textures with a loading screen, so there's no glitch pre-load on the meshes.
There are only a small number of custom properties that deviate from the babylon.js API - that is one of them: https://brianzinn.github.io/react-babylonjs/examples/basic/from-instance
Behind the scenes the "typings" are such that you either need fromInstance or the required constructor args. So, that's why current (and going pretty far back) require an url attribute. You can just put a path or link link the "rootUrl" here - I don't think I have a <texture ..> example anymore:
https://brianzinn.github.io/react-babylonjs/examples/textures/pbr-configuration
if that doesn't solve it for you, please open a separate issue. thx.