Skip to content

Commit

Permalink
Improve glTF LOD handling
Browse files Browse the repository at this point in the history
  • Loading branch information
bghgary committed Jun 9, 2018
1 parent 721d736 commit b429344
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 85 deletions.
4 changes: 2 additions & 2 deletions inspector/src/tabs/GLTFTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ module INSPECTOR {
defaults.extensions[extension.name] = extensionDefaults;
});

const data = '{ "asset": { "version": "2.0" }, "scenes": [ { } ] }';
return loader.loadAsync(scene, data, "").then(() => {
const data = '{ "asset": { "version": "2.0" } }';
return loader.importMeshAsync([], scene, data, "").then(() => {
scene.dispose();
engine.dispose();

Expand Down
105 changes: 44 additions & 61 deletions loaders/src/glTF/2.0/Extensions/MSFT_lod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,35 @@ module BABYLON.GLTF2.Extensions {
*/
public onMaterialLODsLoadedObservable = new Observable<number>();

private _loadingNodeLOD: Nullable<_ILoaderNode> = null;
private _loadNodeSignals: { [nodeIndex: number]: Deferred<void> } = {};
private _loadNodePromises = new Array<Array<Promise<void>>>();
private _nodeIndexLOD: Nullable<number> = null;
private _nodeSignalLODs = new Array<Deferred<void>>();
private _nodePromiseLODs = new Array<Array<Promise<void>>>();

private _loadingMaterialLOD: Nullable<_ILoaderMaterial> = null;
private _loadMaterialSignals: { [materialIndex: number]: Deferred<void> } = {};
private _loadMaterialPromises = new Array<Array<Promise<void>>>();
private _materialIndexLOD: Nullable<number> = null;
private _materialSignalLODs = new Array<Deferred<void>>();
private _materialPromiseLODs = new Array<Array<Promise<void>>>();

constructor(loader: GLTFLoader) {
super(loader);

this._loader._onReadyObservable.addOnce(() => {
for (let indexLOD = 0; indexLOD < this._loadNodePromises.length; indexLOD++) {
Promise.all(this._loadNodePromises[indexLOD]).then(() => {
this._loader._readyPromise.then(() => {
for (let indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
Promise.all(this._nodePromiseLODs[indexLOD]).then(() => {
this._loader._parent._log(`Loaded node LOD ${indexLOD}`);
this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
if (indexLOD !== this._nodePromiseLODs.length - 1) {
this._nodeSignalLODs[indexLOD].resolve();
}
});
}

for (let indexLOD = 0; indexLOD < this._loadMaterialPromises.length; indexLOD++) {
Promise.all(this._loadMaterialPromises[indexLOD]).then(() => {
for (let indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
Promise.all(this._materialPromiseLODs[indexLOD]).then(() => {
this._loader._parent._log(`Loaded material LOD ${indexLOD}`);
this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
if (indexLOD !== this._materialPromiseLODs.length - 1) {
this._materialSignalLODs[indexLOD].resolve();
}
});
}
});
Expand All @@ -63,10 +69,13 @@ module BABYLON.GLTF2.Extensions {
public dispose() {
super.dispose();

this._loadingNodeLOD = null;
this._loadNodeSignals = {};
this._loadingMaterialLOD = null;
this._loadMaterialSignals = {};
this._nodeIndexLOD = null;
this._nodeSignalLODs.length = 0;
this._nodePromiseLODs.length = 0;

this._materialIndexLOD = null;
this._materialSignalLODs.length = 0;
this._materialPromiseLODs.length = 0;

this.onMaterialLODsLoadedObservable.clear();
this.onNodeLODsLoadedObservable.clear();
Expand All @@ -83,11 +92,8 @@ module BABYLON.GLTF2.Extensions {
const nodeLOD = nodeLODs[indexLOD];

if (indexLOD !== 0) {
this._loadingNodeLOD = nodeLOD;

if (!this._loadNodeSignals[nodeLOD._index]) {
this._loadNodeSignals[nodeLOD._index] = new Deferred<void>();
}
this._nodeIndexLOD = indexLOD;
this._nodeSignalLODs[indexLOD] = this._nodeSignalLODs[indexLOD] || new Deferred();
}

const promise = this._loader._loadNodeAsync(`#/nodes/${nodeLOD._index}`, nodeLOD).then(() => {
Expand All @@ -98,27 +104,18 @@ module BABYLON.GLTF2.Extensions {
delete previousNodeLOD._babylonMesh;
}
}

if (indexLOD !== nodeLODs.length - 1) {
const nodeIndex = nodeLODs[indexLOD + 1]._index;

if (this._loadNodeSignals[nodeIndex]) {
this._loadNodeSignals[nodeIndex].resolve();
delete this._loadNodeSignals[nodeIndex];
}
}
});

if (indexLOD === 0) {
firstPromise = promise;
}
else {
this._loader._completePromises.push(promise);
this._loadingNodeLOD = null;
this._nodeIndexLOD = null;
}

this._loadNodePromises[indexLOD] = this._loadNodePromises[indexLOD] || [];
this._loadNodePromises[indexLOD].push(promise);
this._nodePromiseLODs[indexLOD] = this._nodePromiseLODs[indexLOD] || [];
this._nodePromiseLODs[indexLOD].push(promise);
}

this._loader._parent._logClose();
Expand All @@ -128,7 +125,7 @@ module BABYLON.GLTF2.Extensions {

protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>> {
// Don't load material LODs if already loading a node LOD.
if (this._loadingNodeLOD) {
if (this._nodeIndexLOD) {
return null;
}

Expand All @@ -142,11 +139,7 @@ module BABYLON.GLTF2.Extensions {
const materialLOD = materialLODs[indexLOD];

if (indexLOD !== 0) {
this._loadingMaterialLOD = materialLOD;

if (!this._loadMaterialSignals[materialLOD._index]) {
this._loadMaterialSignals[materialLOD._index] = new Deferred<void>();
}
this._materialIndexLOD = indexLOD;
}

const promise = this._loader._loadMaterialAsync(`#/materials/${materialLOD._index}`, materialLOD, mesh, babylonMesh, babylonDrawMode, indexLOD === 0 ? assign : () => {}).then(() => {
Expand All @@ -160,26 +153,18 @@ module BABYLON.GLTF2.Extensions {
delete previousBabylonDataLOD[babylonDrawMode];
}
}

if (indexLOD !== materialLODs.length - 1) {
const materialIndex = materialLODs[indexLOD + 1]._index;
if (this._loadMaterialSignals[materialIndex]) {
this._loadMaterialSignals[materialIndex].resolve();
delete this._loadMaterialSignals[materialIndex];
}
}
});

if (indexLOD === 0) {
firstPromise = promise;
}
else {
this._loader._completePromises.push(promise);
this._loadingMaterialLOD = null;
this._materialIndexLOD = null;
}

this._loadMaterialPromises[indexLOD] = this._loadMaterialPromises[indexLOD] || [];
this._loadMaterialPromises[indexLOD].push(promise);
this._materialPromiseLODs[indexLOD] = this._materialPromiseLODs[indexLOD] || [];
this._materialPromiseLODs[indexLOD].push(promise);
}

this._loader._parent._logClose();
Expand All @@ -188,22 +173,20 @@ module BABYLON.GLTF2.Extensions {
}

protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>> {
if (this._loadingMaterialLOD || this._loadingNodeLOD) {
if (this._loader._parent.loggingEnabled) {
this._loader._parent._log(`deferred`);
}
}

// Defer the loading of uris if loading a material or node LOD.
if (this._loadingMaterialLOD) {
const index = this._loadingMaterialLOD._index;
return this._loadMaterialSignals[index].promise.then(() => {
if (this._materialIndexLOD !== null) {
this._loader._parent._log(`deferred`);
const previousIndexLOD = this._materialIndexLOD - 1;
this._materialSignalLODs[previousIndexLOD] = this._materialSignalLODs[previousIndexLOD] || new Deferred<void>();
return this._materialSignalLODs[previousIndexLOD].promise.then(() => {
return this._loader._loadUriAsync(context, uri);
});
}
else if (this._loadingNodeLOD) {
const index = this._loadingNodeLOD._index;
return this._loadNodeSignals[index].promise.then(() => {
else if (this._nodeIndexLOD !== null) {
this._loader._parent._log(`deferred`);
const previousIndexLOD = this._nodeIndexLOD - 1;
this._nodeSignalLODs[previousIndexLOD] = this._nodeSignalLODs[previousIndexLOD] || new Deferred<void>();
return this._nodeSignalLODs[this._nodeIndexLOD - 1].promise.then(() => {
return this._loader._loadUriAsync(context, uri);
});
}
Expand Down
34 changes: 13 additions & 21 deletions loaders/src/glTF/2.0/babylon.glTFLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ module BABYLON.GLTF2 {
public _parent: GLTFFileLoader;
public _gltf: _ILoaderGLTF;
public _babylonScene: Scene;
public _readyPromise: Promise<void>;
public _completePromises = new Array<Promise<void>>();
public _onReadyObservable = new Observable<IGLTFLoader>();

private _disposed = false;
private _state: Nullable<GLTFLoaderState> = null;
Expand Down Expand Up @@ -79,8 +79,8 @@ module BABYLON.GLTF2 {

delete this._gltf;
delete this._babylonScene;
delete this._readyPromise;
this._completePromises.length = 0;
this._onReadyObservable.clear();

for (const name in this._extensions) {
this._extensions[name].dispose();
Expand All @@ -101,22 +101,22 @@ module BABYLON.GLTF2 {
this._progressCallback = onProgress;
this._loadData(data);

let nodes: Nullable<Array<_ILoaderNode>> = null;
let nodes: Nullable<Array<number>> = null;

if (meshesNames) {
const nodeMap: { [name: string]: _ILoaderNode } = {};
const nodeMap: { [name: string]: number } = {};
if (this._gltf.nodes) {
for (const node of this._gltf.nodes) {
if (node.name) {
nodeMap[node.name] = node;
nodeMap[node.name] = node._index;
}
}
}

const names = (meshesNames instanceof Array) ? meshesNames : [meshesNames];
nodes = names.map(name => {
const node = nodeMap[name];
if (!node) {
if (node === undefined) {
throw new Error(`Failed to find node '${name}'`);
}

Expand Down Expand Up @@ -145,18 +145,21 @@ module BABYLON.GLTF2 {
});
}

private _loadAsync(nodes: Nullable<Array<_ILoaderNode>>): Promise<void> {
private _loadAsync(nodes: Nullable<Array<number>>): Promise<void> {
return Promise.resolve().then(() => {
this._state = GLTFLoaderState.LOADING;
this._parent._log(`Loading`);

const readyDeferred = new Deferred<void>();
this._readyPromise = readyDeferred.promise;

this._loadExtensions();
this._checkExtensions();

const promises = new Array<Promise<void>>();

if (nodes) {
promises.push(this._loadNodesAsync(nodes));
promises.push(this._loadSceneAsync("#/nodes", { nodes: nodes, _index: -1 }));
}
else {
const scene = GLTFLoader._GetProperty(`#/scene`, this._gltf.scenes, this._gltf.scene || 0);
Expand All @@ -175,7 +178,8 @@ module BABYLON.GLTF2 {
this._state = GLTFLoaderState.READY;
this._parent._log(`Ready`);

this._onReadyObservable.notifyObservers(this);
readyDeferred.resolve();

this._startAnimations();
});

Expand Down Expand Up @@ -313,18 +317,6 @@ module BABYLON.GLTF2 {
return rootNode;
}

private _loadNodesAsync(nodes: _ILoaderNode[]): Promise<void> {
const promises = new Array<Promise<void>>();

for (let node of nodes) {
promises.push(this._loadNodeAsync(`#/nodes/${node._index}`, node));
}

promises.push(this._loadAnimationsAsync());

return Promise.all(promises).then(() => {});
}

public _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void> {
const promise = GLTFLoaderExtension._LoadSceneAsync(this, context, scene);
if (promise) {
Expand Down
3 changes: 2 additions & 1 deletion sandbox/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,9 @@ if (BABYLON.Engine.isSupported()) {

window.addEventListener("keydown", function (event) {
// Press R to reload
if (event.keyCode === 82 && event.target.nodeName !== "INPUT") {
if (event.keyCode === 82 && event.target.nodeName !== "INPUT" && currentScene) {
debugLayerLastActiveTab = currentScene.debugLayer.getActiveTab();

if (assetUrl) {
loadFromAssetUrl();
}
Expand Down

0 comments on commit b429344

Please sign in to comment.