Blender Exported .glb model not loading with texture

Hi,
I have exported simple .glb model from blender (2.83) with texture.
Tested the exported model on below viewer its coming perfect.
https://gltf-viewer.donmccurdy.com/
https://sandbox.babylonjs.com/

but when i load this model in my scene, material and texture both not loading, even if i load texture separate UV not coming fine.

I am not sure where i am making wrong, i am attaching a .glb file please check.
cube.glb (29.5 KB)
Here is my code:

three.js ar - hit test
	<div id="info">
		<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> ar - hit test<br/>(Chrome Android 81+)
	</div>

	<Button id="drill" onclick="modelcall()">  drill model </Button>
	<input type="hidden" id = "dob" value="laptop"> </input>

	<script>
		function modelcall()
		{
			document.getElementById("dob").value = "drill";	
			init();		  
		}
	</script>

	<script type="module">

		import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118.3/build/three.module.js';
		import { ARButton } from './jsm/webxr/ARButton.js';
		import { OBJLoader } from 'https://cdn.jsdelivr.net/npm/three@0.118.3/examples/jsm/loaders/OBJLoader.js';
		import { MTLLoader } from 'https://cdn.jsdelivr.net/npm/three@0.118.3/examples/jsm/loaders/MTLLoader.js';
		//import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.118.3/examples/jsm/loaders/GLTFLoader.js';
		import {FBXLoader} from 'https://cdn.jsdelivr.net/npm/three@0.112.1/examples/jsm/loaders/FBXLoader.js';
		import {GLTFLoader} from 'https://cdn.jsdelivr.net/npm/three@0.112.1/examples/jsm/loaders/GLTFLoader.js';			
		
		//import {DRACOLoader} from './jsm/loaders/DRACOLoader.js';

		var container;
		var camera, scene, renderer;
		var controller;

		var reticle;

		var hitTestSource = null;
		var hitTestSourceRequested = false;

		var mtlLoader;
		var mtlLoader2;
		var monkeymesh;

		var texture;

		var numberofModels = 0;
		var addedmodels= [0];

		var model ="";

		init();
		animate();		

		function init() {

			container = document.createElement( 'div' );
			document.body.appendChild( container );

			scene = new THREE.Scene();

			camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 20 );
			camera.position.z = 10;

			var light = new THREE.DirectionalLight( 0xefffff);
			light.position.set( 0, 200, 100 );
			scene.add( light );

			var ambientlight = new THREE.AmbientLight(0xefab9d , 0.5);
			scene.add(ambientlight);

			//

			renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
			renderer.setPixelRatio( window.devicePixelRatio );
			renderer.setSize( window.innerWidth, window.innerHeight );
			renderer.xr.enabled = true;
			container.appendChild( renderer.domElement );
			
			document.body.appendChild( ARButton.createButton( renderer, { requiredFeatures: [ 'hit-test' ] } ) );

			//load box geometry
			var boxgeometry = new THREE.BoxBufferGeometry( 0.25, 0.25, 0.25 ).translate( 0, 0.1, 0 );

			//load texture here
			var texture = new THREE.TextureLoader().load( './models/intellogo.png' );
			
			var modelgetname = document.getElementById("dob").value;				
			
			//load materil for OBJ import
			mtlLoader = new MTLLoader();						
			
			
			///////////////GLTF-GLB LOADER//////////////////////////////////////////
			var loader = new GLTFLoader();
			var meshgltf;

			loader.load('./models/cube.glb', handle_load)

			function handle_load(gltf)
			{
				meshgltf = gltf.scene.children[0];
				meshgltf.material = new THREE.MeshStandardMaterial({

				color: 0xffffff,

				roughness: 1,
				metalness: 0.0,

			}); 
				//meshgltf.material.metalness = 0.0;
				//meshgltf.material.roughness = 1.0;
				//meshgltf.material.map = texture;
				scene.add(meshgltf);
				meshgltf.position.set(0, 1, 5);
				meshgltf.rotation.set(0,10,0);
				console.log(meshgltf.name);
			}
			

			function onSelect() {					
				
				if ( reticle.visible ) {

					/*
					var material = new THREE.MeshPhongMaterial( { color: 0xffffff * Math.random() } );
					var mesh = new THREE.Mesh( boxgeometry, material );
					mesh.position.setFromMatrixPosition( reticle.matrix );
					//mesh.scale.y = Math.random() * 2 + 1;
					mesh.scale.set( 0.1, 0.1, 0.1 );
					scene.add( mesh );
					*/

					////////////////////////////////////////////////////////////////////////////////////////////////
					mtlLoader.setPath( "./models/" );
					mtlLoader.load( 'laptop'+'.mtl', function ( materials ) {
					
					materials.preload();
					
					var objLoader = new OBJLoader();
					objLoader.setMaterials( materials, );
					objLoader.setPath( "./models/" );
					objLoader.load( 'laptop.obj', function ( object ) {
					
					monkeymesh = object;
					monkeymesh.position.setFromMatrixPosition( reticle.matrix );
					monkeymesh.position.set(0, -4, -4);
					monkeymesh.scale.set( 2, 2, 2 );
					monkeymesh.rotation.set(0, 75, 0);
					
					var textureloader = new THREE.TextureLoader();
					texture = textureloader.load('./models/Noise.jpg');
					
					object.traverse(function (child) {
					
						if ( child.isMesh ) 
						{
							
							child.material = new THREE.MeshPhongMaterial
							({
								//color:     0x996633,
								//specular:  0x050505,
								//shininess: my_shine_value,
								map:       texture1,
								//side:      THREE.DoubleSide

							});

							numberofModels++;

							
						}
					});

					if(addedmodels.length >= 1)
					{
						scene.remove(monkeymesh.name);
						numberofModels = 1;
					}

					scene.add( monkeymesh );
					addedmodels.push(monkeymesh);

					} );

				} );

				}

			}

			controller = renderer.xr.getController( 0 );
			controller.addEventListener( 'select', onSelect );
			scene.add( controller );

			reticle = new THREE.Mesh(
				new THREE.RingBufferGeometry( 0.15, 0.2, 32 ).rotateX( - Math.PI / 2 ),
				new THREE.MeshBasicMaterial()
			);
			reticle.matrixAutoUpdate = false;
			reticle.visible = false;
			scene.add( reticle );

			//

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

		}


		function onWindowResize() {

			camera.aspect = window.innerWidth / window.innerHeight;
			camera.updateProjectionMatrix();

			renderer.setSize( window.innerWidth, window.innerHeight );

		}

		//

		function animate() {
			renderer.setAnimationLoop( render );

		}

		function render( timestamp, frame ) {

			if ( frame ) {

				var referenceSpace = renderer.xr.getReferenceSpace();
				var session = renderer.xr.getSession();

				if ( hitTestSourceRequested === false ) {

					session.requestReferenceSpace( 'viewer' ).then( function ( referenceSpace ) {

						session.requestHitTestSource( { space: referenceSpace } ).then( function ( source ) {

							hitTestSource = source;

						} );

					} );

					session.addEventListener( 'end', function () {

						hitTestSourceRequested = false;
						hitTestSource = null;

					} );

					hitTestSourceRequested = true;

				}

				if ( hitTestSource ) {

					var hitTestResults = frame.getHitTestResults( hitTestSource );

					if ( hitTestResults.length ) {

						var hit = hitTestResults[ 0 ];

						reticle.visible = true;
						reticle.matrix.fromArray( hit.getPose( referenceSpace ).transform.matrix );

					} else {

						reticle.visible = false;

					}

				}

			}

			renderer.render( scene, camera );

		}


	</script>
</body>

So your problem is that your glb file loaded fine, and was added to the scene successfully, but you have trouble assigning a texture to its material ?

Then it would be useful to know where your texture variable came from. Did you wait for the texture to load before to assign it to the material map property ?

If the model appeared correctly in these viewers, you shouldn’t need to swap out the materials and textures this way. Be sure to put an environment map or at least some direct lighting on the model, and not just ambient lighting. The model is 100% metallic, and that sort of material requires other lighting — otherwise it will appear black.

i am loading my texture from my local drive:

var texture = new THREE.TextureLoader().load( './models/texture.png' );`

glb loading fine in the viewer why its not loading it in the scene?`

initially i tried without loading a texture and material it ws coming as pink color so i applied material and texture after that.

Your scene needs better lighting. I think all the rest (swapping the texture, swapping the material) are just introducing new problems on top of that.

can you please try with that model from your end?
or suggest the good lighting on this?

The model you shared looks like this in my viewer, with no changes to the glb:

Any light except ambient and directional lights will work here. These light types do not affect fully metallic materials. Try THREE.PointLight. Or perhaps change the material to have .metalness = 0.

i tried this, but still not working.
Can you please load this model in your system an try?

I did, and it works fine. Please share enough details that we know what you’re trying if it isn’t working for you.

index.html (7.7 KB)

i have attached my code, can you please check and tell what is the issue in this for not loading a textures and animations?

Your handle_load function is trying to do too much. Just set material.metalness=0, there is no need to swap materials or load the texture again.

				function handle_load(gltf)
				{
					meshgltf = gltf.scene.children[0];
					meshgltf.material.metalness = 0;
					meshgltf.position.set(0, 1, 5);
					meshgltf.rotation.set(0, 10, 0);
					scene.add(meshgltf);
					console.log(meshgltf.name);
				}

The model you shared earlier did not have any animations, but if it did you would need to play them following examples like this one:

i have changed my handle_load function as you mentioned but i am getting this error.

This error is coming when i remove the material properties inside the handle_load function

if its possible can you please share the code which you did?

Your code is mixing parts of three.js from two different versions. Be sure to use the same version for all files:

import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118.3/build/three.module.js';
import { OBJLoader } from 'https://cdn.jsdelivr.net/npm/three@0.118.3/examples/jsm/loaders/OBJLoader.js';
import { MTLLoader } from 'https://cdn.jsdelivr.net/npm/three@0.118.3/examples/jsm/loaders/MTLLoader.js';
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.118.3/examples/jsm/loaders/GLTFLoader.js';

Thanks, its working now.
Let me try to add animations here, as you mentioned above.


any solution for this ?

Hi Don,
We are successfully loading .glb shoe model created from blender, however we are not getting the leather shine. We tried, since the last 2-3 days, changing the lighting parameters in main.js however it had no effect. We are sharing the main.js file below as well as a link to the model. Could you kindly advise?

[quote=“donmccurdy, post:3, topic:17397, full:true”]
If the model appeared correctly in these viewers, you shouldn’t need to swap out the materials and textures this way. Be sure to put an environment map or at least some direct lighting on the model, and not just ambient lighting. The model is 100% metallic, and that sort of material requires other lighting — otherwise it will appear black.

RedHeels.glb (4.9 MB)


const _settings = {
  threshold: 0.9, // detection sensitivity, between 0 and 1. best: 0.8
  NNVersion: 30, // best: 30

  // CONVERSES SHOES:
  // 3D models:
  shoeRightPath: 'assets/Ballerina.glb',
  isModelLightMapped: true,
  occluderPath: 'assets/Occluder.glb',

  // pose settings:
  scale: 0.95,
  translation: [0, -0.02, 0], // Z -> verical, Y+ -> front way


  // debug flags:
  debugCube: false, // Add a cube
  debugDisplayLandmarks: true
};

const _three = {
  loadingManager: null
}

const _states = {
  notLoaded: -1,
  loading: 0,
  running: 1,
  busy: 2
};
let _state = _states.notLoaded;
let _isSelfieCam = false;


function setFullScreen(cv){
  cv.width = window.innerWidth;
  cv.height = window.innerHeight;
}


// entry point:
function main(){
  _state = _states.loading;

  const handTrackerCanvas = document.getElementById('handTrackerCanvas');
  const VTOCanvas = document.getElementById('ARCanvas');

  setFullScreen(handTrackerCanvas);
  setFullScreen(VTOCanvas);

  HandTrackerThreeHelper.init({
    poseLandmarksLabels: [
      'ankleBack', 'ankleOut', 'ankleIn', 'ankleFront',
      'heelBackOut', 'heelBackIn',
      'pinkyToeBaseTop', 'middleToeBaseTop', 'bigToeBaseTop'
    ],
    enableFlipObject: true,//true,
    cameraZoom: 1,
    freeZRot: false,
    threshold: _settings.threshold,
    scanSettings: {
      multiDetectionSearchSlotsRate: 0.5,
      multiDetectionMaxOverlap: 0.3,
      multiDetectionOverlapScaleXY: [0.5, 1],
      multiDetectionEqualizeSearchSlotScale: true, 
      multiDetectionForceSearchOnOtherSide: true,
      multiDetectionForceChirality: 1,
      disableIsRightHandNNEval: true,
      overlapFactors: [1.0, 1.0, 1.0],
      translationScalingFactors: [0.3, 0.3, 1],
      nScaleLevels: 2, // in the higher scale level, the size of the detection window is the smallest video dimension
      scale0Factor: 0.5
    },
    VTOCanvas: VTOCanvas,
    handTrackerCanvas: handTrackerCanvas,
    debugDisplayLandmarks: false,
    NNsPaths: ['../../neuralNets/NN_FOOT_' + _settings.NNVersion.toString() + '.json'],
    maxHandsDetected: 2,
    stabilizationSettings: {
      //qualityFactorRange: [0.4, 0.7],
      NNSwitchMask: {
        isRightHand: false,
        isFlipped: false
      }
    },
    landmarksStabilizerSpec: { 
      minCutOff: 0.001,
      beta: 5 // lower => more stabilized
    }
  }).then(function(three){
    handTrackerCanvas.style.zIndex = 3; // fix a weird bug on iOS15 / safari
    start(three);
  }).catch(function(err){
    console.log('INFO in main.js: an error happens ', err);
  });
} 


function start(three){
  three.loadingManager.onLoad = function(){
    console.log('INFO in main.js: Everything is loaded');
    _state = _states.running;
  }

  // set tonemapping:
  three.renderer.toneMapping = THREE.ACESFilmicToneMapping;
  three.renderer.outputEncoding = THREE.sRGBEncoding;

  // set lighting:
  if (!_settings.isModelLightMapped){
    const pointLight = new THREE.PointLight(0xffffff, 2);
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
    three.scene.add(pointLight, ambientLight);
  }

  // add a debug cube:
  if (_settings.debugCube){
    const s = 1;
    const cubeGeom = new THREE.BoxGeometry(s,s,s);
    const cubeMesh = new THREE.Mesh(cubeGeom,new THREE.MeshNormalMaterial());
    HandTrackerThreeHelper.add_threeObject(cubeMesh);
  }

  function transform(threeObject){
    threeObject.scale.multiplyScalar(_settings.scale);
    threeObject.position.add(new THREE.Vector3().fromArray(_settings.translation));
  }

  // load the shoes 3D model:
  new THREE.GLTFLoader().load(_settings.shoeRightPath, function(gltf){
    const shoe = gltf.scene;
    transform(shoe);
    HandTrackerThreeHelper.add_threeObject(shoe);
  });

  new THREE.GLTFLoader(three.loadingManager).load(_settings.occluderPath, function(gltf){
    const occluder = gltf.scene.children[0];
    transform(occluder);
    HandTrackerThreeHelper.add_threeOccluder(occluder);
  });
}



function flip_camera(){
  if (_state !== _states.running){
    return;
  }
  _state = _states.busy;
  WEBARROCKSHAND.update_videoSettings({
    facingMode: (_isSelfieCam) ? 'environment' : 'user'
  }).then(function(){
    _isSelfieCam = !_isSelfieCam;
    _state = _states.running;
    // mirror canvas using CSS in selfie cam mode:
    document.getElementById('canvases').style.transform = (_isSelfieCam) ? 'rotateY(180deg)' : '';
    console.log('INFO in main.js: Camera flipped successfully');
  }).catch(function(err){
    console.log('ERROR in main.js: Cannot flip camera -', err);
  });
}


window.addEventListener('load', main);

I only see point and ambient lights in your code – that is not enough for PBR materials. I would recommend starting out with an environment map, or THREE.RoomEnvironment.

1 Like