javascripthtmlmodel-viewer

Can I change a model-viewer texture using an uploaded file? (client side)


The challenge

The goal is to allow users to upload their textures to preview on the model-viewer model.

What I tried so far

  1. I made it work but instead of <input type="file"> using <input type="text">.
  2. I can make an uploaded image display as a <img> element.

Example

https://jsfiddle.net/pynrdk25/11/

document.getElementById("urlA").addEventListener("change", function() {
  const file = this.files[0];

  if (file) {
    const reader = new FileReader();
    document.getElementById("modelA").model.materials[0].pbrMetallicRoughness.baseColorTexture.texture.source.setURI(this.value);
    reader.readAsDataURL(file);
  }
})
body {
  background-color: rgba(255,255,255,0.85)
}
h1 {
  margin: 0;
  font-size:  16pt;
  font-family: Arial, Helvetica, sans-serif;
  color: #4a5a8a
  
}
model-viewer {
  width: 512px;
  height: 512px;
  border: 2px solid black;
  background-color: #484E61
}
input[type="file"] {
  margin: 15px auto
}
<script src="https://unpkg.com/@google/model-viewer@1.12.0/dist/model-viewer-umd.js"></script>
<h1>Upload an image to preview it in the model</h1>
<input type="file" id="urlA">
<model-viewer
id="modelA"
camera-controls
src="https://modelviewer.dev/shared-assets/models/Astronaut.glb"
shadow-intensity="0"
environment-image="neutral"
exposure="0.5"
></model-viewer>


Solution

  • I don't know much about model-viewer or what texture you're trying to change, but I can provide details on why your code is not obtaining the content of the file properly.

    You need to subscribe to the load event on FileReader and access the result property to obtain the generated data URI.

    document.getElementById("urlA").addEventListener("change", function() {
      const file = this.files[0];
      const viewer = document.getElementById("modelA");
    
      if (!file) return;
    
      const reader = new FileReader();
      reader.addEventListener('load', async function() {
        const texture = await viewer.createTexture(reader.result);
        viewer.model.materials[0].normalTexture.setTexture(texture);
      });
      reader.readAsDataURL(file);
    })
    body {
      background-color: rgba(255,255,255,0.85)
    }
    h1 {
      margin: 0;
      font-size:  16pt;
      font-family: Arial, Helvetica, sans-serif;
      color: #4a5a8a
      
    }
    model-viewer {
      width: 512px;
      height: 512px;
      border: 2px solid black;
      background-color: #484E61
    }
    input[type="file"] {
      margin: 15px auto
    }
    <script src="https://unpkg.com/@google/model-viewer@1.12.0/dist/model-viewer-umd.js"></script>
    <h1>Upload an image to preview it in the model</h1>
    <input type="file" id="urlA">
    <model-viewer
    id="modelA"
    camera-controls
    src="https://modelviewer.dev/shared-assets/models/Astronaut.glb"
    shadow-intensity="0"
    environment-image="neutral"
    exposure="0.5"
    ></model-viewer>