From 056ff3bf003a42dc397c1813d293df759991c51f Mon Sep 17 00:00:00 2001 From: Don McCurdy Date: Sat, 16 Sep 2017 22:42:40 -0700 Subject: [PATCH 01/15] GLTFLoader: Implement KHR_draco_mesh_compression extension. --- docs/examples/loaders/GLTFLoader.html | 11 ++ examples/js/loaders/GLTFLoader.js | 164 +++++++++++++++------ examples/webgl_loader_gltf_extensions.html | 8 +- 3 files changed, 137 insertions(+), 46 deletions(-) diff --git a/docs/examples/loaders/GLTFLoader.html b/docs/examples/loaders/GLTFLoader.html index 299b12cd1a75f3..05d7ac2b9dd964 100644 --- a/docs/examples/loaders/GLTFLoader.html +++ b/docs/examples/loaders/GLTFLoader.html @@ -35,6 +35,9 @@

Extensions

  • KHR_lights (experimental)
  • +
  • + KHR_draco_mesh_compression (experimental) +
  • Example

    @@ -43,6 +46,9 @@

    Example

    // Instantiate a loader var loader = new THREE.GLTFLoader(); + // Optional: Provide a DRACOLoader instance to decode compressed mesh data + loader.setDRACOLoader( new THREE.DRACOLoader( undefined, {type: 'js'} ) ); + // Load a glTF resource loader.load( // resource URL @@ -124,6 +130,11 @@

    [method:null setCrossOrigin]( [page:String value] )

    [page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS. +

    [method:null setDRACOLoader]( [page:DRACOLoader dracoLoader] )

    +
    + [page:DRACOLoader dracoLoader] — Instance of THREE.DRACOLoader, to be used for decoding assets compressed with the KHR_draco_mesh_compression extension. +
    +

    [method:null parse]( [page:ArrayBuffer data], [page:String path], [page:Function onLoad], [page:Function onError] )

    [page:ArrayBuffer data] — glTF asset to parse, as an ArrayBuffer or JSON string.
    diff --git a/examples/js/loaders/GLTFLoader.js b/examples/js/loaders/GLTFLoader.js index bbb07a4e856fb2..9e2fcbcb967b71 100644 --- a/examples/js/loaders/GLTFLoader.js +++ b/examples/js/loaders/GLTFLoader.js @@ -11,6 +11,7 @@ THREE.GLTFLoader = ( function () { function GLTFLoader( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.dracoLoader = null; } @@ -68,6 +69,12 @@ THREE.GLTFLoader = ( function () { }, + setDRACOLoader: function ( dracoLoader ) { + + this.dracoLoader = dracoLoader; + + }, + parse: function ( data, path, onLoad, onError ) { var content; @@ -127,6 +134,12 @@ THREE.GLTFLoader = ( function () { } + if ( json.extensionsUsed.indexOf( EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ) >= 0 ) { + + extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] = new GLTFDracoMeshCompressionExtension( this.dracoLoader ); + + } + } console.time( 'GLTFLoader' ); @@ -201,6 +214,7 @@ THREE.GLTFLoader = ( function () { var EXTENSIONS = { KHR_BINARY_GLTF: 'KHR_binary_glTF', + KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression', KHR_LIGHTS: 'KHR_lights', KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness' }; @@ -357,6 +371,46 @@ THREE.GLTFLoader = ( function () { } + /** + * DRACO Mesh Compression Extension + * + * Specification: https://github.com/KhronosGroup/glTF/pull/874 + * + * TODO: + * - Support additional (uncompressed) attributes in addition to 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. + */ + function GLTFDracoMeshCompressionExtension ( dracoLoader ) { + + if ( ! dracoLoader ) { + + throw new Error( 'THREE.GLTFLoader: No DRACOLoader instance provided.' ); + + } + + this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION; + this.dracoLoader = dracoLoader; + + } + + GLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function ( primitive, parser ) { + + var dracoLoader = this.dracoLoader; + var bufferViewIndex = primitive.extensions[ this.name ].bufferView; + + return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) { + + return new Promise( function ( resolve ) { + + dracoLoader.decodeDracoFile( bufferView, resolve ); + + } ); + + } ); + + }; + /** * Specular-Glossiness Extension * @@ -1480,6 +1534,15 @@ THREE.GLTFLoader = ( function () { var accessorDef = this.json.accessors[ accessorIndex ]; + if ( accessorDef.bufferView === undefined && accessorDef.sparse === undefined ) { + + // Ignore empty accessors, which may be used to declare runtime + // information about attributes coming from another source (e.g. Draco + // compression extension). + return null; + + } + var pendingBufferViews = []; if ( accessorDef.bufferView !== undefined ) { @@ -1880,6 +1943,8 @@ THREE.GLTFLoader = ( function () { */ GLTFParser.prototype.loadGeometries = function ( primitives ) { + var parser = this; + var extensions = this.extensions; var cache = this.primitiveCache; return this.getDependencies( 'accessor' ).then( function ( accessors ) { @@ -1893,88 +1958,97 @@ THREE.GLTFLoader = ( function () { // See if we've already created this geometry var cached = getCachedGeometry( cache, primitive ); + var geometry; + if ( cached ) { // Use the cached geometry if it exists geometries.push( cached ); - } else { + continue; + + } else if ( primitive.extensions && primitive.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) { + + // Use DRACO geometry if available + geometry = extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ].decodePrimitive( primitive, parser ); + + } else { // Otherwise create a new geometry - var geometry = new THREE.BufferGeometry(); + geometry = new THREE.BufferGeometry(); - var attributes = primitive.attributes; + } - for ( var attributeId in attributes ) { + var attributes = primitive.attributes; - var attributeEntry = attributes[ attributeId ]; + for ( var attributeId in attributes ) { - var bufferAttribute = accessors[ attributeEntry ]; + var attributeEntry = attributes[ attributeId ]; - switch ( attributeId ) { + var bufferAttribute = accessors[ attributeEntry ]; - case 'POSITION': + switch ( attributeId ) { - geometry.addAttribute( 'position', bufferAttribute ); - break; + case 'POSITION': - case 'NORMAL': + geometry.addAttribute( 'position', bufferAttribute ); + break; - geometry.addAttribute( 'normal', bufferAttribute ); - break; + case 'NORMAL': - case 'TEXCOORD_0': - case 'TEXCOORD0': - case 'TEXCOORD': + geometry.addAttribute( 'normal', bufferAttribute ); + break; - geometry.addAttribute( 'uv', bufferAttribute ); - break; + case 'TEXCOORD_0': + case 'TEXCOORD0': + case 'TEXCOORD': - case 'TEXCOORD_1': + geometry.addAttribute( 'uv', bufferAttribute ); + break; - geometry.addAttribute( 'uv2', bufferAttribute ); - break; + case 'TEXCOORD_1': - case 'COLOR_0': - case 'COLOR0': - case 'COLOR': + geometry.addAttribute( 'uv2', bufferAttribute ); + break; - geometry.addAttribute( 'color', bufferAttribute ); - break; + case 'COLOR_0': + case 'COLOR0': + case 'COLOR': - case 'WEIGHTS_0': - case 'WEIGHT': // WEIGHT semantic deprecated. + geometry.addAttribute( 'color', bufferAttribute ); + break; - geometry.addAttribute( 'skinWeight', bufferAttribute ); - break; + case 'WEIGHTS_0': + case 'WEIGHT': // WEIGHT semantic deprecated. - case 'JOINTS_0': - case 'JOINT': // JOINT semantic deprecated. + geometry.addAttribute( 'skinWeight', bufferAttribute ); + break; - geometry.addAttribute( 'skinIndex', bufferAttribute ); - break; + case 'JOINTS_0': + case 'JOINT': // JOINT semantic deprecated. - } + geometry.addAttribute( 'skinIndex', bufferAttribute ); + break; } - if ( primitive.indices !== undefined ) { + } - geometry.setIndex( accessors[ primitive.indices ] ); + if ( primitive.indices !== undefined ) { - } + geometry.setIndex( accessors[ primitive.indices ] ); - // Cache this geometry - cache.push( { + } - primitive: primitive, - geometry: geometry + // Cache this geometry + cache.push( { - } ); + primitive: primitive, + geometry: geometry - geometries.push( geometry ); + } ); - } + geometries.push( geometry ); } diff --git a/examples/webgl_loader_gltf_extensions.html b/examples/webgl_loader_gltf_extensions.html index 259a1bdcf86280..d30803a419e4b7 100644 --- a/examples/webgl_loader_gltf_extensions.html +++ b/examples/webgl_loader_gltf_extensions.html @@ -90,11 +90,13 @@ +
    +