Model.readyPromise not Fulfilled

Hi,

When loading a model Cesium.Model.fromGltf, the model readyPromise is never fulfilled.

Based on examples I found around, it seems that it only works when the primitive is added to the scene.

What I would like to achieve is to prevent the rendering to break when the model can not be loaded for any given reason (404, invalid format, etc…)

I expect the model promise to be triggered when the model is fully loaded before I can add it to the scene. I could prevent it to reach rendering if the promise reach the “otherwise” method.

I modified this example from Matthew Amato to highlight the problem:

The Original states:

var model = scene.primitives.add(Cesium.Model.fromGltf({…

``

Mine does:

var model = Cesium.Model.fromGltf({

``

The whole thing to be ran in Sandcastle:

var viewer = new Cesium.Viewer(‘cesiumContainer’);

var scene = viewer.scene;

var height = 5000.0;

var heading = 0.0;

var pitch = Cesium.Math.toRadians(10.0);

var roll = Cesium.Math.toRadians(-20.0);

var origin = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);

var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(origin, heading, pitch, roll);

var model = Cesium.Model.fromGltf({

url : ‘…/…/SampleData/models/CesiumAir/Cesium_Air.gltf’,

modelMatrix : modelMatrix,

minimumPixelSize : 128

});

model.readyPromise.then(function(model) {

scene.primitives.add(model);

// Play and loop all animations at half-speed

model.activeAnimations.addAll({

   speedup : 0.5,

   loop : Cesium.ModelAnimationLoop.REPEAT

});

var camera = viewer.camera;

// Zoom to model

var controller = scene.screenSpaceCameraController;

var r = 2.0 * Math.max(model.boundingSphere.radius, camera.frustum.near);

controller.minimumZoomDistance = r * 0.5;

var center = Cesium.Matrix4.multiplyByPoint(model.modelMatrix, model.boundingSphere.center, new Cesium.Cartesian3());

var heading = Cesium.Math.toRadians(230.0);

var pitch = Cesium.Math.toRadians(-20.0);

camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, r * 2.0));

}).otherwise(function(error){

window.alert(error);

});

``

Cheers,

Xavier.

Also notice how changing the model URL to something wrong (looking for a 404):

var model = scene.primitives.add(Cesium.Model.fromGltf({

url : ‘…/…/SampleData/models/CesiumAir/foo_bar.gltf’,

modelMatrix : modelMatrix,

minimumPixelSize : 128

}));

``

… will not reject the promise into the “otherwise” method.

The reason the ready promise is never resolved (or rejected) is because a model is loaded across multiple frames. By adding it to the scene first, it will be updated every frame. Otherwise it will not be updated and never finish loading.

I’m not sure I understand your explanation.

But I do expect the Model promise to just resolve when model is loaded, no matter how many frames it takes. If I add it to the scene, it is already to late to prevent a corrupted model to hit the rendering process. And that leads to Cesium “crashing”, which is breaking the user experience.

I would be glad if anybody could explain how to handle and mitigate this kind of situation. It is not possible to fully rely on perfectly formed and fully loaded models: files can be corrupted, network could drop, etc… My application must be resilient to that.

Cheers,

Xavier

Xavier,

I totally agree with your original assertion. I would actually consider this a bug in Cesium. The good news is that it has already been addressed as part of the 3D Tiles work and will be part of 1.17: See here for the change that brought it into master: https://github.com/AnalyticalGraphicsInc/cesium/pull/3276

For example, in 1.16, the below code generated a RunTimeError in the render loop, which as you mentioned “crashes” Cesium. But in 1.17, the otherwise code path is called and rendering continues as if the Model simply isn’t there.

var viewer = new Cesium.Viewer(‘cesiumContainer’);

var badModel = Cesium.Model.fromGltf({

url: ‘invalid.invalid’

});

viewer.scene.primitives.add(badModel);

badModel.readyPromise.then(function(){

alert(‘success’);

}).otherwise(function(e){

alert(e);

});

Brilliant! Thanks.