How to add texture on mesh on click of button

Hi Everyone,
I have implemented react app where im importing glb model and adding texture on it but difficulty im facing is how to add texture on mesh on click of button.
Please help me with the logic.

Here is source code for reference

import React, { Component } from “react”;
import * as BABYLON from “babylonjs”;
import “babylonjs-loaders”;
import { ShadowOnlyMaterial } from “@babylonjs/materials/shadowOnly”;

var scene;

class Mug extends Component {
constructor(props) {
super(props);
this.state = {
height: window.innerHeight,
width: window.innerWidth,
useWireFrame: false,
shouldAnimate: false,
};
this.updateDimensions = this.updateDimensions.bind(this);
}

componentDidMount = () => {
// start ENGINE
this.engine = new BABYLON.Engine(this.canvas, true);

//Create Scene
scene = new BABYLON.Scene(this.engine);
scene.clearColor = new BABYLON.Color3.Gray;
// E8EBEE

window.addEventListener("resize", this.updateDimensions);

//--Light---
this.addLight();

//--Camera---
this.addCamera();

//--Meshes---
this.addModels();

// Add Events
window.addEventListener("resize", this.onWindowResize, false);

// Render Loop
this.engine.runRenderLoop(() => {
  scene.render();
});

};

updateDimensions() {
this.setState({
height: window.innerHeight,
width: window.innerWidth
});
}

componentWillUnmount() {
window.removeEventListener(“resize”, this.updateDimensions);
};

componentWillUnmount() {
window.removeEventListener(“resize”, this.onWindowResize, false);
}

onWindowResize = event => {
this.engine.resize();
};

/* Add Lights */
addLight = () => {

var light = new BABYLON.HemisphericLight("hemiLight", new BABYLON.Vector3(-1, -1, 0), scene);

};

/* Add Camera */
addCamera = () => {
// create a camera pointing at your model.
scene.createDefaultCameraOrLight(true, true, true);
var camera = scene.getCameraByID(“default camera”);
camera.beta = 1.4;
camera.alpha = 1.2;
camera.attachControl(this.canvas, true)
};

/*** Add Models */
addModels = () => {

// Adding texture to model
var mat = new BABYLON.StandardMaterial("mat", scene);
var texture = new BABYLON.Texture("https://i.imgur.com/vxH5bCg.jpg", scene);
mat.diffuseTexture = texture;

// Importing model from git hub
BABYLON.SceneLoader.ImportMeshAsync("",
  "https://raw.githubusercontent.com/pavankulkarni11/3D_Meshes/main/",
  "mug_glb_itr4.glb", scene).then((frame) => {
    const meshes = frame.meshes;
    meshes[1].material = mat;
  });

};

render() {
return (
<>
<canvas
style={{ width: window.innerWidth, height: window.innerHeight }}
ref={canvas => {
this.canvas = canvas;
}}
/>
Preview
</>
);
}
}
export default Mug;

You can create ActionManager for mesh to set texture on mouse click (pick). Just register ExecuteCodeAction with OnPickTrigger and set callback-function where you create and set texture on mesh material. I would place it into then after ImportMeshAsync.

Example PG:

Docs:

2 Likes

Thanks @Takemura. But im confused in implementation.
I explain scenario of my query.
I have implemented UI using Reactjs where i upload a image from local folder and display it. Then i have a preview button so on click of preview button, the uploaded image should be texture mapped on model.3D model im importing it from git hub. How can i achive this?
Im struggling to find logic of implementation since 3 days, if possible please help me with solution.
Thanks

What exactly is going wrong with your implementation? The logic should be simply: click on button → call a function that creates and assign a texture.

I assume your preview button is HTML button and you know how to get element in javascript.
Then you can add event listener to button:

button.addEventListener("click",function () {
        var img = ... // Get your HTML image element (img.src needs to be set)

        sphere.material.diffuseTexture = new BABYLON.Texture(`texture`, scene, true,
                true, BABYLON.Texture.BILINEAR_SAMPLINGMODE,
                null, null, img, true);
});

You will need to check parameters of texture, because the options matches my texture not yours. What you need is buffer of Texture constructor.

Thanks for response @Takemura .

Im trying this way but not able to achive expected result like “on click of button add texture on mesh”

/*** Add Models */
addModels = () => {
// Importing model from git hub
BABYLON.SceneLoader.ImportMeshAsync(“”,
https://raw.githubusercontent.com/pavankulkarni11/3D_Meshes/main/”,
“mug_glb_itr4.glb”, this.scene).then((frame) => {
const meshes = frame.meshes;
meshes[1].material = this.mat;
});
};

handleClick() {
// Adding texture to model
var mat = new BABYLON.StandardMaterial(“mat”, scene);
var texture = new BABYLON.Texture(“https://i.imgur.com/vxH5bCg.jpg”, scene);
mat.diffuseTexture = texture;
console.log(‘Click happened’);
}

render() {
return (
<>
<canvas
style={{ width: window.innerWidth, height: window.innerHeight }}
ref={canvas => {
this.canvas = canvas;
}}
/>
Preview
</>
);
}

Thanks for response @carolhmj .

Yes i have button with onClick event and calling function which has logic to apply texture on material. But unable to achive it.

Here is the code for reference.

/*** Add Models */
addModels = () => {
// Importing model from git hub
BABYLON.SceneLoader.ImportMeshAsync(“”,
https://raw.githubusercontent.com/pavankulkarni11/3D_Meshes/main/”,
“mug_glb_itr4.glb”, this.scene).then((frame) => {
const meshes = frame.meshes;
meshes[1].material = this.mat;
});
};

handleClick() {
// Adding texture to model
var mat = new BABYLON.StandardMaterial(“mat”, scene);
var texture = new BABYLON.Texture(“https://i.imgur.com/vxH5bCg.jpg”, scene);
mat.diffuseTexture = texture;
console.log(‘Click happened’);
}

render() {
return (
<>
<canvas
style={{ width: window.innerWidth, height: window.innerHeight }}
ref={canvas => {
this.canvas = canvas;
}}
/>
Preview
</>
);
}

Where is your button, it seems that its onclick won’t reach handleClick inside your Mug-class.

It might work to get button element and set button.onclick = handleClick. If not I would create handleClick just like your addModels (not as direct Mug-function) and try to set again.

@Takemura I have button in render method, when i copy paste the code, button element is not visible here.
I have a screen shot for reference.

btn

Do you miss this.scene here? Then you might need this in constructor:

this.handleClick = this.handleClick.bind(this);

Did you try a more simple example?

I created this example and it shows the button:

import { Component } from 'react';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.abc = 'wa';
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    alert(this.abc);
    alert('hello world');
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me!
      </button>
    );
  }
}
1 Like

@Takemura This code is working. Previously i console logged the click event and it was working fine.

But not able to add texture on click of button. Now i have onclick event triggered and have function that import mesh and to function to to add texture. But texture is not successfully applied on mesh.

Here i have attached screenshot for reference.

Here is the output

and thanks for response @Takemura . I really appreaciate your concern.

You do create material and set to mesh on import, but you don’t set new material on mesh inside handleClick(), or do I miss something?

Also did you add bind(this) to handleClick inside constructor?

3 Likes

Thank you so much @Takemura :pray:. Its working now :melting_face: