Change texture preserving buffer and uv data

Hello,
I’m trying to change dynamically the texture of an .gltf model on button click.
The texture i’m using has different colors, but the wrapping is the same as the previous image.

But if I generate a new Texture, the _buffer becomes null and the wrapping is not correct.
I tried storing the buffer info and reassign it, but it gives me the same result as before.

document.getElementById('btn3').addEventListener('click', function() {
       scene.meshes[1].material.albedoColor = new BABYLON.Color3(1, 1, 1);
      
      var texture = new BABYLON.Texture("old_wooden_bookshelf/textures/Bookshelf_M_baseColor-light.jpg", scene);
       texture._buffer = buffer; // var buffer assigned, contains the buffer array info
       scene.meshes[1].material.albedoTexture = texture;
   })

if i load the image from babylon debugger it replace it correctly.
What i would like to achieve is exactly that, which seems simple.
Just change the path to the image texture, preserving all the wrapping infos.

If anyone could help me, it would be really appreciated.
Thank you

I don’t think you can change the image of a texture after it is created. it is possible, see post below.

What you should do instead is something like:

var uscale = scene.meshes[1].material.albedoTexture.uScale;
var vscale = scene.meshes[1].material.albedoTexture.vScale;
...
scene.meshes[1].material.albedoTexture = new BABYLON.Texture("old_wooden_bookshelf/textures/Bookshelf_M_baseColor-light.jpg", scene);
scene.meshes[1].material.albedoTexture.uScale = uscale;
scene.meshes[1].material.albedoTexture.vScale = vscale;
...

Thank you very much for the answer.
Unfortunately the uScale and the vScale are the same (1, 1) even after i create the new Texture();
So reassigning it, doesn’t change the wrapping.
starting texture:


after upload on click:
uploading with debugger (correct result)

I thought there was a way of managing this texture change, since in the debugger it’s achieved through load texture from file (without a model reloading).

You’re right, there is a method to update the texture afterward!

public updateURL(url: string, buffer: Nullable<string | ArrayBuffer | ArrayBufferView | HTMLImageElement | Blob> = null, onLoad?: () => void): void {

Here’s what the “Load texture from file” button in the inspector is doing:

const texture = this.props.texture;
Tools.ReadFile(file, (data) => {
    var blob = new Blob([data], { type: "octet/stream" });

    var reader = new FileReader();
    reader.readAsDataURL(blob); 
    reader.onloadend = () => {
        let base64data = reader.result as string;     

        if (texture.isCube) {
            let extension: string | undefined = undefined;
            if (file.name.toLowerCase().indexOf(".dds") > 0) {
                extension = ".dds";
            } else if (file.name.toLowerCase().indexOf(".env") > 0) {
                extension = ".env";
            }

            (texture as CubeTexture).updateURL(base64data, extension, () => this.foreceRefresh());
        } else {
            (texture as Texture).updateURL(base64data, null, () => this.foreceRefresh());
        }
    };

}, undefined, true);
2 Likes

Awesome!
I haven’t thought about using this method, but it’s exactly what i needed.
Since the image is not uploaded and i already have the path to it, what solved the problem is simply using that method, without the need to pass the buffer info:

document.getElementById('btn3').addEventListener('click', function() {
    scene.meshes[1].material.albedoTexture.updateURL('old_wooden_bookshelf/textures/Bookshelf_M_baseColor-light.jpg');
   })

Thank you again!

TS prevents this from working, the only way to do this is to cast the mesh.material to any and then do the updateURL and assign the material back to the mesh. If you don’t cast to any, albedoTexture doesn’t contain the updateURL property and if you cast it to Material, it doesn’t have the albedoTexture property.

How can it be solved without casting to any?

Upd:
I did it like this:
const mat = mesh.material as PBRMaterial;
(mat.albedoTexture as BABYLON.Texture).updateURL(root + i + “.png”);
mesh.material = mat;

1 Like