Skip to content

Commit

Permalink
FIX: Draco decoding in GLTFLoader
Browse files Browse the repository at this point in the history
 - Added a GLTFParser.setDependency() method to be able to store a Promise to a dependency in the GLTFRegistry cache. This allows the Draco decoder extension to asynchronously decode the compressed meshes and attributes, without changing anything in the rest of the GLTF parsing code.
 - Update TODO comments in Draco extension, as additional uncompressed attributes is now supported, and passing primitive.attributes to DRACOLoader is not necessary with the new design (from previous commits).
  • Loading branch information
JeremieA committed Dec 7, 2017
1 parent 5ad8cb6 commit 14e91e8
Showing 1 changed file with 51 additions and 48 deletions.
99 changes: 51 additions & 48 deletions lib/GLTFLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -486,9 +486,7 @@ THREE.GLTFLoader = ( function () {
* Specification: https://github.com/KhronosGroup/glTF/pull/874
*
* TODO:
* - Support additional uncompressed attributes alongside those provided by Draco.
* - Support fallback to uncompressed data if decoder is not unavailable.
* - `primitive.attributes` should be passed to DRACOLoader, but isn't yet supported.
* - Support fallback to uncompressed data if decoder is not available.
*/
function GLTFDracoMeshCompressionExtension ( dracoLoader ) {

Expand All @@ -502,24 +500,22 @@ THREE.GLTFLoader = ( function () {
this.dracoLoader = dracoLoader;
}

GLTFDracoMeshCompressionExtension.prototype.decodeAccessors = function ( parser, accessors ) {
GLTFDracoMeshCompressionExtension.prototype.decodeAccessors = function ( parser ) {

var scope = this;
return _each( parser.json.meshes, function( mesh ) {
return _each( mesh.primitives, function( primitive ) {
if ( primitive.extensions && primitive.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) {
return scope.decodePrimitiveAccessors( primitive, parser, accessors );
} else {
return {};
var meshes = parser.json.meshes;
for ( var i = 0, il = meshes.length; i < il; i ++ ) {
var primitives = meshes[i].primitives;
for ( var j = 0, jl = primitives.length; j < jl; j ++ ) {
var primitiveDef = primitives[j];
if ( primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) {
this.decodePrimitiveAccessors( primitiveDef, parser );
}
} );
} ).then( function () {
return accessors;
} );
}
}

};

GLTFDracoMeshCompressionExtension.prototype.decodePrimitiveAccessors = function ( primitive, parser, accessors ) {
GLTFDracoMeshCompressionExtension.prototype.decodePrimitiveAccessors = function ( primitive, parser ) {

var dracoLoader = this.dracoLoader;
var jsonAccessors = parser.json.accessors;
Expand Down Expand Up @@ -548,35 +544,32 @@ THREE.GLTFLoader = ( function () {
}
}

return parser.getDependency( 'bufferView', compressedBufferViewIndex ).then( function ( bufferView ) {

var decodePromise = parser.getDependency( 'bufferView', compressedBufferViewIndex ).then( function ( bufferView ) {
return new Promise( function ( resolve ) {

dracoLoader.decodeDracoFileData( bufferView, resolve, dracoAttributesToArrayType );
} );
} );

} ).then( function ( geometryBuffer ) {

// indices
{
var array = geometryBuffer.indices;
var accessorId = primitive.indices;
var itemSize = WEBGL_TYPE_SIZES[ jsonAccessors[accessorId].type ];
accessors[accessorId] = new THREE.BufferAttribute( array, itemSize, false );
}
// attributes and morph targets
for (var dracoId in geometryBuffer.attributes) {
var array = geometryBuffer.attributes[dracoId];
var accessorId = dracoAttributesToAccessorId[dracoId];
var itemSize = WEBGL_TYPE_SIZES[ jsonAccessors[accessorId].type ];
var normalized = jsonAccessors[accessorId].normalized === true;
accessors[accessorId] = new THREE.BufferAttribute( array, itemSize, normalized );
}

return accessors;
// indices accessor
parser.setDependency('accessor', primitive.indices, decodePromise.then( function ( geometryBuffer ) {
var array = geometryBuffer.indices;
var accessorId = primitive.indices;
var itemSize = WEBGL_TYPE_SIZES[ jsonAccessors[accessorId].type ];
return new THREE.BufferAttribute( array, itemSize, false );
} ) );

} );
// attributes and morph targets
for (let dracoId in dracoAttributesToAccessorId) {

let accessorId = dracoAttributesToAccessorId[dracoId];
parser.setDependency('accessor', accessorId, decodePromise.then( function ( geometryBuffer ) {
var array = geometryBuffer.attributes[dracoId];
var itemSize = WEBGL_TYPE_SIZES[ jsonAccessors[accessorId].type ];
var normalized = jsonAccessors[accessorId].normalized === true;
return new THREE.BufferAttribute( array, itemSize, normalized );
} ) );

} );
}

};

Expand Down Expand Up @@ -1347,6 +1340,11 @@ THREE.GLTFLoader = ( function () {
// Mark the special nodes/meshes in json for efficient parse
this.markDefs();

// Async decoding of compressed meshes
if ( parser.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] !== undefined) {
parser.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ].decodeAccessors( parser );
}

// Fire the callback on complete
this.getMultiDependencies( [

Expand Down Expand Up @@ -1430,6 +1428,19 @@ THREE.GLTFLoader = ( function () {

};

/**
* Store a dependency value as a Promise in the cache.
* @param {string} type
* @param {number} index
* @param {Promise<Object>} value
*/
GLTFParser.prototype.setDependency = function ( type, index, value ) {

var cacheKey = type + ':' + index;
this.cache.add( cacheKey, value );

};

/**
* Requests the specified dependency asynchronously, with caching.
* @param {string} type
Expand Down Expand Up @@ -1685,14 +1696,6 @@ THREE.GLTFLoader = ( function () {

return bufferAttribute;

} ).then( function ( accessors ) { // TODO: THIS CODE NEEDS TO BE CHANGED DUE TO DEPENDENCIES REFACTORING

if ( parser.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] !== undefined) {
return parser.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ].decodeAccessors( parser, accessors );
} else {
return accessors;
}

} );

};
Expand Down

0 comments on commit 14e91e8

Please sign in to comment.