Can't get material from a gltf loaded scene in threejs

Viewed 52

I'd like to modify the material in a gltf loaded model to set its opacity/transparency.

I can't seem to get any meshes. I have created this fiddle that says 'no mesh found'. I have found quite a few examples of getting material and they all seem to do it this way (making sure it's mesh then getting the material).

<style>
  canvas {
    display: block;
    width: 98%;
    height: 98%;
  }

</style>

<canvas id="canvasid"></canvas>

<script src="https://cdn.jsdelivr.net/npm/three@0.143/examples/js/controls/OrbitControls.js"></script>-->

<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
  {
          "imports": {
            "three": "https://cdn.jsdelivr.net/npm/three@0.143/build/three.module.js"
          }
        }
    </script>

<script type="module">
  import * as THREE from 'three';
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.143/examples/jsm/loaders/GLTFLoader.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.143/examples/jsm/controls/OrbitControls.js';

var scene = new THREE.Scene();
scene.background = new THREE.Color(0x6699cc);
const lights = [];
lights[0] = new THREE.PointLight(0xffffff, 1, 0);
lights[1] = new THREE.PointLight(0xffffff, 1, 0);
lights[2] = new THREE.PointLight(0xffffff, 1, 0);
lights[0].position.set(0, 100, 0);
lights[1].position.set(100, 100, 100);
lights[2].position.set(- 100, - 100, - 100);
scene.add(lights[0]);
scene.add(lights[1]);
scene.add(lights[2]);

const loader = new GLTFLoader();

loader.load("https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf", function (gltf) {
    const mesh = gltf.scene.children[0];
    scene.add(mesh);

    //my main question is about this code - looks like everyone can test if isMesh, then can get the material.  I have tried multiple models and can never find any mesh.  If I just assumme a material that doesn't work either
    gltf.scene.traverse((o) => {
        if (o.isMesh) {
            console.log("found mesh");
            console.log(o && o.material);
        } else {
            console.log("no mesh found");
        }
    });
}, undefined, function (error) {
    console.error(error);
});

var canvas = document.getElementById("canvasid");
var renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    antialias: true
});
renderer.setSize(canvas.parentElement.clientWidth, canvas.parentElement.clientHeight);
var camera = new THREE.PerspectiveCamera(1, canvas.parentElement.clientWidth / canvas.parentElement.clientHeight, 1, 1000);
camera.position.z = 100;

const controls = new OrbitControls(camera, renderer.domElement);
controls.update();
controls.autoRotate = true;
controls.enableDamping = true;
var animate = function () {
    requestAnimationFrame(animate);
    controls.update();

    renderer.render(scene, camera);
};

window.addEventListener('resize', function () {
    renderer.setSize(canvas.parentElement.clientWidth, canvas.parentElement.clientHeight);

    camera.aspect = canvas.parentElement.clientWidth / canvas.parentElement.clientHeight;
    camera.updateProjectionMatrix();
}, false);

animate();

How can I access the mesh/material?

1 Answers

The traverse does not work since you add the first child of gltf.scene to scene. That means you change the object hierarchy and thus break the traversal.

To fix this, simply move the below two lines of code after the call of Object3D.traverse().

const mesh = gltf.scene.children[0];
scene.add(mesh);

Also, consider to just do this since a glTF asset does not necessarily only have a single child mesh:

scene.add(gltf.scene);

Updated fiddle: https://jsfiddle.net/ftcnby9e/

Related