GLTFLoader does not display all materials of model

Hi

How do I display all the materials of a GLTF file?
I’m trying to add this model to my website, everything works fine, but I don’t get the water drops.

This is my code:

    function init() {
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xfdcc81);

  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  camera.position.z = 20;
  camera.position.y = 0;

  hlight = new THREE.AmbientLight(0x404040, 5);
  scene.add(hlight);

  directionalLight = new THREE.DirectionalLight(0xc4c4c4, 1);
  directionalLight.position.set(0, 1, 0);
  directionalLight.castShadow = true;
  scene.add(directionalLight);

  light = new THREE.PointLight(0xc4c4c4, 1);
  light.position.set(0, 300, 500);
  scene.add(light);

  light2 = new THREE.PointLight(0xc4c4c4, 1);
  light2.position.set(500, 100, 0);
  scene.add(light2);

  light3 = new THREE.PointLight(0xc4c4c4, 1);
  light3.position.set(0, 100, -500);
  scene.add(light3);

  light4 = new THREE.PointLight(0xc4c4c4, 1);
  light4.position.set(-500, 300, 500);
  scene.add(light4);

  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.outputEncoding = THREE.sRGBEncoding;
  renderer.toneMapping = THREE.ReinhardToneMapping;
  renderer.toneMappingExposure = 2;
  renderer.gammaFactor = 2.2;
  renderer.gammaOutput = true;

  controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.target.set(0, 5, 0);
  document.body.appendChild(renderer.domElement);

  const loader = new THREE.GLTFLoader();
  loader.load("can/scene.gltf", (gltf) => {
    model = gltf.scene.children[0];
    scene.add(model);

    gltf.parser.getDependencies( 'material' ).then( ( materials ) => {
      console.log( materials );
    });
    animate();
  });
}

function animate() {
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

window.addEventListener("resize", onWindowResize, false);

init();

Your code looks fine – the model is just missing information. When troubleshooting a model you should start with a viewer, to eliminate possible sources of error (i.e. if the glTF file appears wrong in a “good” glTF viewer, the problem is in the model not your code).

Testing:

The droplets are missing in all of them. So this is a bug in Sketchfab’s export, or Sketchfab supports a feature that it cannot export to glTF. Probably a bit of both.

Investigating further in Blender, if you select everything you’ll see the wireframe of the droplets there, but select them and then look at their material and the alpha property is 0. This will make them invisible. You can find the same information in three.js with:

droplets = model.getObjectByName('Can|Drip1|Dupli|22_Conden003_0');
droplets.material.opacity // 0

// Fix:
droplets.material.opacity = 0.25;

It won’t look as good as the Sketchfab render, because we don’t yet support the (unfinished) glTF extension for physically-based transparency, KHR_materials_transmission. You might be able to get a bit closer by switching the material to MeshPhysicalMaterial and setting .transparency instead of .opacity, but I’m not sure how well that will work.

3 Likes

If you switched the material to THREE.MeshPhysicalMaterial i think you’d get something like the screenshot below. Note that the droplets refract the environment, not the can itself, so they look more silver than actually transparent. This screenshot is created in Blender but I’d expect something similar in three.js:

Blender supports screen space refraction, as well, which is what you actually want here. However, I don’t think three.js can do that yet, or not with any default materials. The result with that enabled in Blender is better:

1 Like

Thanks for the help donmccurdy.

But when I use THREE.MeshPhysicalMaterial I don’t get that reflection effect you did.

I did it like this:

droplets.material = new THREE.MeshPhysicalMaterial({clearcoat: 1, transparent: true, reflectivity: 1});

You’ll need to pass the right settings from the previous material. I think you want something like:

droplets.material = new MeshPhysicalMaterial({
  roughness: droplets.material.roughness,
  metalness: droplets.material.metalness,
  map: droplets.material.map,
  transparency: 1
});

You will also need to either set a .envMap on the material, or a .environment on the scene. Physical transparency requires an environment map.

1 Like