Schoolboy errors seek Three Master fix!

Hi
All I’m getting is a blank white browser screen with the following attempt to import a gltf model. Can anyone help me please?
I’ve read and re-read the Three.js documentation here: https://threejs.org/docs/index.html#manual/en/introduction/Loading-3D-models
I’ve exported my gltf file from Blender using the [new] recommended exporter GLTF2.0
I’m running on a local server. I get the following console errors: Uncaught TypeError: Cannot read property ‘prototype’ of undefined
at GLTFLoader.js:1015
at GLTFLoader.js:3377

(index):22 Uncaught TypeError: THREE.GLTFLoader is not a constructor
at (index):22

Here is my html index code:

<!DOCTYPE html>
<html>
	<head>
		<meta charset=utf-8>
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
			canvas { width: 100%; height: 100% }
		</style>


		<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.js"></script>
		<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/GLTFLoader.js"></script>
	</head>
	<body>


		
		<script>
			
			// import 3d model
			var loader = new THREE.GLTFLoader();

loader.load( 'model/sofa.glb', function ( gltf ) {

	scene.add( gltf.scene );

}, undefined, function ( error ) {

	console.error( error );

} );

		</script>
	</body>
</html>

Many thanks!

RiverTim

Is there a specific reason why you’re loading r71 of the three.js library? Have you tried it with something more recent?

1 Like

Yeah, it’s no good approach to use the latest GLTFLoader with such an old version of three.js. Try it with these two URLs:

<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/loaders/GLTFLoader.js"></script>
1 Like

Thank you both for your answers. I finally got to load the model by following the code in this example: https://threejs.org/examples/?q=gltf#webgl_loader_gltf
However, now I have loaded my own animation model into three.js it shows – and I can rotate it with the mouse – but the actual model animation does not play. Have you any ideas please? My code:

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - glTF loader</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<style>
			body {
				font-family: Monospace;
				background-color: #000;
				color: #fff;
				margin: 0px;
				overflow: hidden;
			}
			#info {
				color: #fff;
				position: absolute;
				top: 10px;
				width: 100%;
				text-align: center;
				z-index: 100;
				display:block;
			}
			#info a {
				color: #75ddc1;
				font-weight: bold;
			}


		</style>
	</head>

	<body>
		
		<!-- all required to run -->
		<script src="https://threejs.org/build/three.js"></script>
		<script src="https://threejs.org/examples/js/loaders/GLTFLoader.js"></script>
		<script src="js/controls/OrbitControls.js"></script>
		<script src="js/WebGL.js"></script>
		<script src="js/libs/stats.min.js"></script>

		<script>

			//if ( WEBGL.isWebGLAvailable() === false ) {

				// document.body.appendChild( WEBGL.getWebGLErrorMessage() );

			// }

			var container, stats, controls;
			var camera, scene, renderer, light;

			init();
			animate();

			function init() {

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

				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );
				camera.position.set( - 1.8, 0.9, 2.7 );

				controls = new THREE.OrbitControls( camera );
				controls.target.set( 0, - 0.2, - 0.2 );
				controls.update();

				var urls = [ 'posx.jpg', 'negx.jpg', 'posy.jpg', 'negy.jpg', 'posz.jpg', 'negz.jpg' ];
				var loader = new THREE.CubeTextureLoader().setPath( 'textures/cube/Bridge2/' );
				var background = loader.load( urls );

				scene = new THREE.Scene();
				scene.background = background;  // add the background

				light = new THREE.HemisphereLight( 0xbbbbff, 0x444422 );
				light.position.set( 0, 1, 0 );
				scene.add( light );

				// model
				var loader = new THREE.GLTFLoader().setPath( 'models/sofa/glTF/' );
				loader.load( 'sofaanim.gltf', function ( gltf ) {

					gltf.scene.traverse( function ( child ) {

						if ( child.isMesh ) {

							child.material.envMap = background;

						}

					} );

					scene.add( gltf.scene );

				}, undefined, function ( e ) {

					console.error( e );

				} );

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.gammaOutput = true;
				container.appendChild( renderer.domElement );

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

				// stats box
				// stats = new Stats();
				// container.appendChild( stats.dom );

			}

			function onWindowResize() {

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

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

			}

			//

			function animate() {

				requestAnimationFrame( animate );

				renderer.render( scene, camera );

				// stats.update();

			}

		</script>

	</body>
</html>

PS I have checked my GLTF export here https://gltf-viewer.donmccurdy.com and it is playing the animation, so I guess the error is in my three.js code!

Well, you haven’t added anything to your code that tells your models to animate. Have you tried looking it up in the docs? A quick search gives you a whole article about the Three.js animation system and how to implement it.

1 Like

Thank you. I’ve now read that documentation. I knew something was missing. I see the model loaded – but I still can’t get my animation to play. Is there some simple example I could follow? I think the ones in the three.js examples are beyond my skills at present, and there seems not much info out there for using the new GTLFLoader workflow from Blender. Confused! Many thanks.

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - glTF loader</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<style>
			body {
				font-family: Monospace;
				background-color: #000;
				color: #fff;
				margin: 0px;
				overflow: hidden;
			}
			#info {
				color: #fff;
				position: absolute;
				top: 10px;
				width: 100%;
				text-align: center;
				z-index: 100;
				display:block;
			}
			#info a {
				color: #75ddc1;
				font-weight: bold;
			}


		</style>
	</head>

	<body>
		
		<!-- all required to run -->
		<script src="https://threejs.org/build/three.js"></script>
		<script src="https://threejs.org/examples/js/loaders/GLTFLoader.js"></script>
		<script src="js/controls/OrbitControls.js"></script>
		<script src="js/WebGL.js"></script>
		<script src="js/libs/stats.min.js"></script>

		<script>

			//if ( WEBGL.isWebGLAvailable() === false ) {

				// document.body.appendChild( WEBGL.getWebGLErrorMessage() );

			// }

			var container, stats, controls;
			var camera, scene, renderer, light;

			init();
			animate();

			function init() {

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

				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );
				camera.position.set( - 1.8, 0.9, 2.7 );

				controls = new THREE.OrbitControls( camera );
				controls.target.set( 0, - 0.2, - 0.2 );
				controls.update();

				var urls = [ 'posx.jpg', 'negx.jpg', 'posy.jpg', 'negy.jpg', 'posz.jpg', 'negz.jpg' ];
				var loader = new THREE.CubeTextureLoader().setPath( 'textures/cube/Bridge2/' );
				var background = loader.load( urls );

				scene = new THREE.Scene();
				scene.background = background;  // add the background

				light = new THREE.HemisphereLight( 0xbbbbff, 0x444422 );
				light.position.set( 0, 1, 0 );
				scene.add( light );

				// model
				var loader = new THREE.GLTFLoader().setPath( 'models/sofa/glTF/' );
				loader.load( 'sofaanim.gltf', function ( gltf ) {

					gltf.scene.traverse( function ( child ) {

						if ( child.isMesh ) {

							child.material.envMap = background;

						}

					} );

					scene.add( gltf.scene );



				}, undefined, function ( e ) {

					console.error( e );

				} );

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.gammaOutput = true;
				container.appendChild( renderer.domElement );

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

				// stats box
				// stats = new Stats();
				// container.appendChild( stats.dom );

			}

			function onWindowResize() {

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

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

			}


			//

			function animate() {

				requestAnimationFrame( animate );

				renderer.render( scene, camera );

				// stats.update();

			} 

			var mesh;

			// Create an AnimationMixer, and get the list of AnimationClip instances
			var mixer = new THREE.AnimationMixer( mesh );
			var clips = mesh.animations;

			// Update the mixer on each frame
			function update () {
				mixer.update( deltaSeconds );
			}

			// Play all animations
			clips.forEach( function ( clip ) {
				mixer.clipAction( clip ).play();
			} );


		</script>

	</body>
</html>

You normally use the following code in your onLoad() callback to play a single animation:

loader.load( 'sofaanim.gltf', function ( gltf ) {

    const model = gltf.scene;
    const animations = gltf.animations;

    mixer = new THREE.AnimationMixer( model );
   
    // play the first animation

    const action = mixer.clipAction( animations[ 0 ] );
    action.play();

    scene.add( model );

} );

And your animation loop should look like this:

function animate() {

    requestAnimationFrame( animate );

    const delta = clock.getDelta();

    if ( mixer ) mixer.update( delta );

    renderer.render( scene, camera );
   
}

Thanks. But I’m now getting only a black screen with this code. Have I misunderstood your code?

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - glTF loader</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<style>
			body {
				font-family: Monospace;
				background-color: #000;
				color: #fff;
				margin: 0px;
				overflow: hidden;
			}
			#info {
				color: #fff;
				position: absolute;
				top: 10px;
				width: 100%;
				text-align: center;
				z-index: 100;
				display:block;
			}
			#info a {
				color: #75ddc1;
				font-weight: bold;
			}


		</style>
	</head>

	<body>
		
		<!-- all required to run -->
		<script src="https://threejs.org/build/three.js"></script>
		<script src="https://threejs.org/examples/js/loaders/GLTFLoader.js"></script>
		<script src="js/controls/OrbitControls.js"></script>
		<script src="js/WebGL.js"></script>
		<script src="js/libs/stats.min.js"></script>

		<script>

			//if ( WEBGL.isWebGLAvailable() === false ) {

				// document.body.appendChild( WEBGL.getWebGLErrorMessage() );

			// }

			var container, stats, controls;
			var camera, scene, renderer, light;

			init();
			animate();

			function init() {

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

				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );
				camera.position.set( - 1.8, 0.9, 2.7 );

				controls = new THREE.OrbitControls( camera );
				controls.target.set( 0, - 0.2, - 0.2 );
				controls.update();

				var urls = [ 'posx.jpg', 'negx.jpg', 'posy.jpg', 'negy.jpg', 'posz.jpg', 'negz.jpg' ];
				var loader = new THREE.CubeTextureLoader().setPath( 'textures/cube/Bridge2/' );
				var background = loader.load( urls );

				scene = new THREE.Scene();
				scene.background = background;  // add the background

				light = new THREE.HemisphereLight( 0xbbbbff, 0x444422 );
				light.position.set( 0, 1, 0 );
				scene.add( light );

				// model
				loader.load( 'models/sofa/gltf/sofaanim.gltf', function ( gltf ) {

				    const model = gltf.scene;
				    const animations = gltf.animations;

				    mixer = new THREE.AnimationMixer( model );
				   
				    // play the first animation

				    const action = mixer.clipAction( animations[ 0 ] );
				    action.play();

				    scene.add( model );

				} );



				}, undefined, function ( e ) {

					console.error( e );

				} );

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.gammaOutput = true;
				container.appendChild( renderer.domElement );

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

				// stats box
				// stats = new Stats();
				// container.appendChild( stats.dom );

			}

			function onWindowResize() {

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

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

			}


			//

			function animate() {

			    requestAnimationFrame( animate );

			    const delta = clock.getDelta();

			    if ( mixer ) mixer.update( delta );

			    renderer.render( scene, camera );
			   
			} );





		</script>

	</body>
</html>

Thanks!

You have a lot of syntax errors in your code. Make sure to have look at the browser console when testing your stuff.

Try it with this live demo: https://jsfiddle.net/f2Lommf5/16828/

Thanks for that example! Much clearer to see it there. :slight_smile: I now have narrowed it down to gltf file. If I swap mine out for the solider.glb, it all works fine. Should I be exporting as .glb instead? Any settings I have to check from Blender?
Thanks.

I personally use always glb in production since you can load the model with a single network request.

Just export the model as glb.

@Mugen87 Thanks for all your help and advice – very helpful!
Tim