Search code examples
reactjsthree.js3dreact-three-fiber

Change material of gltf-imported mesh programmatically - react three fiber


I'm currently working at a project with react-three-fiber. I've imported the model with useGLTF from @react-three/drei.

With

const { nodes, materials } = useGLTF('/model.glb');

I access the materials from the glb-file. To access and manipulate the model I used gltfjsx to generate the model.

Now I need to change the material of a mesh programmatically. Because I have no direct access to the JSX of the model I do it with React.cloneElement and modify the props of the mesh.

So I tried something like this:

return React.cloneElement(mesh, {
  material: overwriteMaterial ?
    <meshStandardMaterial attach="material" color={0xa3005c} metalness={1} roughness={0.2} visible={true} /> :
    materials['mat_7']
});

If overwriteMaterial is false it works. It shows the material it should. But if it's true then the mesh disappears.

I also thought of putting the <meshStandardMaterial /> in the children prop of the mesh. Something like so:

return React.cloneElement(mesh, {
  material: overwriteMaterial ? undefined : materials['mat_7'],
  children: overwriteMaterial ? <meshStandardMaterial attach="material" color={0xa3005c} metalness={1} roughness={0.2} visible={true} /> : undefined
});

With this I always get this error and I don't know why it appears:

TypeError: Cannot read properties of undefined (reading 'visible')

Could this approach somehow work or am I doing something completely wrong?

Every help is welcome. Thanks


Solution

  • Alright so I found the answer by myself after some more hours searching for a solution.

    The material property doesn't accept a JSX-tag. So if you create an instance of the class MeshStandardMaterial you can pass it to the property and it works perfectly fine. Now it looks something like this:

    return React.cloneElement(mesh, {
      material: overwriteMaterial
      ? new MeshStandardMaterial({ color: 0x0ff000 })
      : materials['mat_7']
    })
    

    Note: The class MeshStandardMaterial is exported from the three package.