Troubleshooting Loading JSON Model

Attempting to load JSON model that has been exported from Blender. Getting the error

three.min.js:684 Uncaught TypeError: Cannot read property 'length' of undefined
    at ce.parse (three.min.js:684)
    at dunno.html:2039

in the console. Have attempted the solution found at https://stackoverflow.com/questions/27992147/three-js-include-mesh-data-in-code/27996338#27996338 but I am still receiving this error. Code below.

var loader = new THREE.JSONLoader();
var model = loader.parse(iss);
mesh = new THREE.Mesh(model.geometry, model.materials[ 0 ]);
scene.add(mesh);

Does it upload correctly here: https://blackthread.io/gltf-converter ?

If not it’s probably a problem with the model. Try exporting as glTF instead in that case.

Ended up being a problem with the model. Have a version of the modeled that uploaded and I have exported as a glTF but now am getting the error

Uncaught TypeError: Cannot read property 'extractUrlBase' of undefined
    at GLTFLoader.load (GLTFLoader.js:27)
    at dunno.html:2080

Attempting to load glTF as such

var loaderGLTF = new THREE.GLTFLoader();  
loaderGLTF.load(
    'Resources/Earth3/iss.gltf',
    function(gltf) {
        scene.add(gltf);
    }
);

Attempted to upload as an FBX as well (with FBX loader) and got the same error.

Uncaught TypeError: Cannot read property ‘extractUrlBase’ of undefined

That sounds like you’re using newer versions of GLTFLoader or FBXLoader with older versions of three.js. Updating three.js or using older loaders should work.

1 Like

Updated three.js and all loaders, getting the error

THREE.Object3D.add: object not an instance of THREE.Object3D. Object
add @ three.js:8163

from

var loaderGLTF = new THREE.GLTFLoader();  
loaderGLTF.load(
    "Resources/Earth3/iss.gltf",
    function(object) {
        scene.add(object);
    }
);

Got the fbx loader to work, but whenever I attempt to create a mesh from the imported geometry the model disappears with no error. FBX code posted below.

var loader = new THREE.FBXLoader();
loader.load( 'Resources/Earth3/iss3.fbx', function ( geometry ) {
    var basicMaterial = THREE.MeshBasicMaterial({
            color: 0xff0000
        })
    var issMesh = THREE.Mesh(geometry, basicMaterial);
    console.log(issMesh.position);
    scene.add(issMesh);
} );

GLTFLoader gives a differently structured result, see GLTFLoader docs. Try:

var loaderGLTF = new THREE.GLTFLoader();  
loaderGLTF.load(
    "Resources/Earth3/iss.gltf",
    function(gltf) {
        scene.add(gltf.scene);
    }
);

You can also test glTF models here: http://gltf-viewer.donmccurdy.com/

This worked thanks. Attempting to animate the gltf’s position from within the animate function. Attempted this by creating a global variable and setting it equal to the model from within the loader callback. Still does not appear the position is accessible from the outside of the loader function. Any tips?

var issModel;
var loaderGLTF = new THREE.GLTFLoader();  
loaderGLTF.load(
    "Resources/Earth3/iss.gltf",
    function(gltf) {
        issModel = gltf;
        console.log(gltf.scene.position);
        scene.add(gltf.scene);
    }
)
console.log(issModel.scene.position);

The error

dunno.html:141 Uncaught TypeError: Cannot read property 'scene' of undefined
    at dunno.html:141

is thrown. The position is also properly printed to the console due to the call from within the loader callback.

The model is loaded asynchronously. This means that what you have is:

var issModel; // currently undefined

// load model asynchronously, may not be ready for some time
loaderGLTF.load( ...


// called immediately and throws an error, since the model has not loaded yet
console.log(issModel.scene.position);

I understand. The model has not loaded due to the async behavior, therefore is not available. What is the best method to deal with such an issue? I have tried to include a parameter in the animate function which passes the gltf, to it such as

var issModel;
var loaderGLTF = new THREE.GLTFLoader();  
loaderGLTF.load(
    "Resources/Earth3/iss.gltf",
    function(gltf) {
        console.log(gltf.scene.position);
        scene.add(gltf.scene);
        animate(gltf);
    }
)

Then in the animate function

function animate(gltf) {
console.log(gltf.scene.position);
} 

Which actually did work for one iteration, then an error was thrown and the entire scene froze, therefore I know this can’t be right. Ultimately I am trying to update the position of an imported object with coordinates from an AJAX request that is triggered every 5 seconds. I have this working perfectly using a sphere. Am trying to replace the sphere with the imported model.

The model has not loaded due to the async behavior, therefore is not available. What is the best method to deal with such an issue?

The only way to deal with this issue is to structure your code in such a way that the model is not used until it has loaded. It seems confusing at first but you get used to it!

You seem to be on the right track with your animate function, what error message are you getting?

Okay great. What I have attempted is

var issModel;
var loaderGLTF = new THREE.GLTFLoader();  
loaderGLTF.load(
    "Resources/Earth3/iss.gltf",
    function(gltf) {
        gltf.scene.scale.x = 0.1;
        gltf.scene.scale.y = 0.1;
        gltf.scene.scale.z = 0.1;
        console.log(gltf.scene.position);
        scene.add(gltf.scene);
        animate(gltf);
    }
)

with my animate function

function animate(gltf) {
    clouds.rotation.x += 0.0001;
    clouds.rotation.y += 0.0001;
    clouds.rotation.z += 0.0001; 
    
    issPosition = latLongToVector3(lat, long, 200, 10);
    posSphere.position.x = issPosition.x;
    posSphere.position.y = issPosition.y;
    posSphere.position.z = issPosition.z;
    
    gltf.scene.position.x = issPosition.x;
    gltf.scene.position.y = issPosition.y;
    gltf.scene.position.z = issPosition.z;
    
    controls.update();
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
            }       

Reciveing the error

Uncaught TypeError: Cannot read property 'scene' of undefined
    at animate (dunno.html:2140)
    at dunno.html:2148

and

Uncaught TypeError: Cannot read property 'position' of undefined
    at animate (dunno.html:2140)   

Although the model is put in the correct position for the very first frame, the model is completely frozen/unresponsive to trackball controls. I can post entire source if that would help troubleshooting.

Yes, please do that.

Here it is. Trying to show the ISS orbiting the earth.

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - OBJLoader + MTLLoader</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;
			}
		</style>
	</head>

	<body>

		<script src="Resources/three.js"></script>
        <script src="Resources/TDSLoader.js"></script>
        <script src="Resources/FBXLoader.js"></script>
        <script src="Resources/GLTFLoader.js"></script>
        <script src="Resources/inflate.min.js"></script>
        <script src="Resources/TrackballControls.js"></script>
<script>
var lat, long, issPosition;
//*********************PRELIM FUNCTIONS BEGIN**********************************
//AJAX request for current position of the ISS
function GetValue() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
    var requestResponse = xhr.responseText;
    var issInfo = JSON.parse(requestResponse);
    var Lat = issInfo.iss_position.latitude;
    var Long = issInfo.iss_position.longitude;
    callback(Lat, Long); //callback function with lat and long info
                }
            };
            xhr.open("GET", "http://api.open-notify.org/iss-now.json", true);
            xhr.send();
        }
    
    function callback(Lat, Long) {
        lat = Lat; //set global variables equal to lat and long so animate function has access
        long = Long;
    }
    
    GetValue(); //function call to get iss location
    setInterval(GetValue, 5000); //interval for iss location, updates every 5 seconds
    
//convert long & lat to 3D coordinate
function latLongToVector3(lat, lon, radius, heigth) {
    var phi = (lat)*Math.PI/180;
    var theta = (lon-180)*Math.PI/180;
 
    var x = -(radius+heigth) * Math.cos(phi) * Math.cos(theta);
    var y = (radius+heigth) * Math.sin(phi);
    var z = (radius+heigth) * Math.cos(phi) * Math.sin(theta);
 
        return new THREE.Vector3(x,y,z);
    }     
//******************PRELIM FUNCTIONS END********************************************

//******************THREE JS ENVIRONMENT BEGIN**************************************   
var width = window.innerWidth;
var height = window.innerHeight;
            
var scene = new THREE.Scene();
            
var camera = new THREE.PerspectiveCamera(75, width/height, 0.01, 1000);
camera.position.z = 400;
    
var controls = new THREE.TrackballControls( camera );

				controls.rotateSpeed = 1.0;
				controls.zoomSpeed = 1.2;
				controls.panSpeed = 0.8;

				controls.noZoom = false;
				controls.noPan = false;

				controls.staticMoving = true;
				controls.dynamicDampingFactor = 0.3;

				controls.keys = [ 65, 83, 68 ];
            
var renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
            
var direcLight = new THREE.DirectionalLight(0xffffff, 0.3);
direcLight.position.set(-3,3,1.5);
direcLight.castShadow = true;
scene.add(direcLight);
            
var ambientLight = new THREE.AmbientLight(0xc9c9c9, 1.5);
scene.add(ambientLight);
            
var geometry1 = new THREE.SphereGeometry(200,32,32);
var geometry2 = new THREE.SphereGeometry(202.5,32,32);
var geometry3 = new THREE.SphereGeometry(3, 32, 32);
var material1 = new THREE.MeshBasicMaterial ({
    color: 0xff0000
});
var material2 = new THREE.MeshPhongMaterial({
    map: new THREE.TextureLoader().load('Resources/Earth3/earthmapoftwo.jpg'),
    bumpMap: new THREE.TextureLoader().load('Resources/Earth3/Bump2.jpg'),
    bumpScale: 1,
    specularMap: new THREE.TextureLoader().load('Resources/Earth3/oceanmaskbytwo.png'),
    specular: new THREE.Color('grey'),
    shininess: 40
});
var material3 = new THREE.MeshPhongMaterial({
    alphaMap: new THREE.TextureLoader().load('Resources/Earth3/Clouds.png'),
    transparent: true,
});

var issModel;
var loaderGLTF = new THREE.GLTFLoader();  
loaderGLTF.load(
    "Resources/Earth3/iss.gltf",
    function(gltf) {
        gltf.scene.scale.x = 0.1;
        gltf.scene.scale.y = 0.1;
        gltf.scene.scale.z = 0.1;
        console.log(gltf.scene.position);
        scene.add(gltf.scene);
        animate(gltf);
    }
)
            
var sphere = new THREE.Mesh(geometry1, material2); 
var clouds = new THREE.Mesh(geometry2, material3);
var posSphere = new THREE.Mesh(geometry3, material1);

sphere.receiveShadow = true;
clouds.receiveShadow = true;
posSphere.receiveShadow = true;
scene.add(sphere);
scene.add(clouds);
scene.add(posSphere);
            
function animate(gltf) {
    clouds.rotation.x += 0.0001;
    clouds.rotation.y += 0.0001;
    clouds.rotation.z += 0.0001; 
    
    issPosition = latLongToVector3(lat, long, 200, 10);
    posSphere.position.x = issPosition.x; //sphere's location is updated with the issPosition & works 
    posSphere.position.y = issPosition.y;
    posSphere.position.z = issPosition.z;
    
    gltf.scene.position.x = issPosition.x; //Part I am struggling with here, how to access the gltf's position from within this function. Essentially I want to replace the sphere with the gltf
    gltf.scene.position.y = issPosition.y;
    gltf.scene.position.z = issPosition.z;
    
    controls.update();
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
            }          
animate();
//**************************THREE JS ENVIRONMENT END*************************************  
</script>

</body>
</html>
animate();
//**************************THREE JS ENVIRONMENT END*************************************  
</script>

</body>
</html>

You’re calling the animation function twice, you’ll need to remove the call at the end of your script.

1 Like

Ah, yes thats right. Thanks. Ended up making the position of the imported model global, updated the position of the model in the animate function, then called the animate function within the callback of the model. Thank you for the help.

Hi donmccurdy!

I’m having the same error:
“Uncaught TypeError: Cannot read property ‘extractUrlBase’ of undefined at GLTFLoader.load”

I recently downloaded the GLTFLoader.js and three.js from the the three.js site with its examples but I still get this error.
I posted my issue in a new post, could you please look at it!!
[Uncaught TypeError: Cannot read property 'extractUrlBase' of undefined at GLTFLoader.load]

Thanks!

I commented on your thread earlier — it’s not possible to reproduce the problem from what you have posted so far, and your screenshot shows an older version of three.js (r85) which does not match the latest GLTFLoader. I suggest updating three.js to r92.

Notice, in the console logs: THREE.WebGLRenderer r85.