From 8bb8f5cdab059e22c8e364224e67c29e9495b01f Mon Sep 17 00:00:00 2001 From: Marco Fugaro Date: Fri, 30 Jul 2021 17:06:05 +0200 Subject: [PATCH 1/2] GLTFExporter: add support for draco compression --- examples/jsm/exporters/DRACOExporter.js | 63 +++++++++++--- examples/jsm/exporters/GLTFExporter.js | 107 ++++++++++++++++++++---- examples/misc_exporter_draco.html | 2 +- examples/misc_exporter_gltf.html | 40 +++++---- 4 files changed, 167 insertions(+), 45 deletions(-) diff --git a/examples/jsm/exporters/DRACOExporter.js b/examples/jsm/exporters/DRACOExporter.js index 6800d86ef0ccc8..b0b17c755c5646 100644 --- a/examples/jsm/exporters/DRACOExporter.js +++ b/examples/jsm/exporters/DRACOExporter.js @@ -44,7 +44,7 @@ class DRACOExporter { const encoder = new dracoEncoder.Encoder(); let builder; let dracoObject; - + const attributeIDs = {}; if ( geometry.isBufferGeometry !== true ) { @@ -58,7 +58,13 @@ class DRACOExporter { dracoObject = new dracoEncoder.Mesh(); const vertices = geometry.getAttribute( 'position' ); - builder.AddFloatAttributeToMesh( dracoObject, dracoEncoder.POSITION, vertices.count, vertices.itemSize, vertices.array ); + attributeIDs[ 'POSITION' ] = builder.AddFloatAttributeToMesh( + dracoObject, + dracoEncoder.POSITION, + vertices.count, + vertices.itemSize, + vertices.array + ); const faces = geometry.getIndex(); @@ -86,7 +92,13 @@ class DRACOExporter { if ( normals !== undefined ) { - builder.AddFloatAttributeToMesh( dracoObject, dracoEncoder.NORMAL, normals.count, normals.itemSize, normals.array ); + attributeIDs[ 'NORMAL' ] = builder.AddFloatAttributeToMesh( + dracoObject, + dracoEncoder.NORMAL, + normals.count, + normals.itemSize, + normals.array + ); } @@ -98,7 +110,13 @@ class DRACOExporter { if ( uvs !== undefined ) { - builder.AddFloatAttributeToMesh( dracoObject, dracoEncoder.TEX_COORD, uvs.count, uvs.itemSize, uvs.array ); + attributeIDs[ 'TEXCOORD_0' ] = builder.AddFloatAttributeToMesh( + dracoObject, + dracoEncoder.TEX_COORD, + uvs.count, + uvs.itemSize, + uvs.array + ); } @@ -110,7 +128,13 @@ class DRACOExporter { if ( colors !== undefined ) { - builder.AddFloatAttributeToMesh( dracoObject, dracoEncoder.COLOR, colors.count, colors.itemSize, colors.array ); + attributeIDs[ 'COLOR_0' ] = builder.AddFloatAttributeToMesh( + dracoObject, + dracoEncoder.COLOR, + colors.count, + colors.itemSize, + colors.array + ); } @@ -122,7 +146,13 @@ class DRACOExporter { dracoObject = new dracoEncoder.PointCloud(); const vertices = geometry.getAttribute( 'position' ); - builder.AddFloatAttribute( dracoObject, dracoEncoder.POSITION, vertices.count, vertices.itemSize, vertices.array ); + builder.AddFloatAttribute( + dracoObject, + dracoEncoder.POSITION, + vertices.count, + vertices.itemSize, + vertices.array + ); if ( options.exportColor === true ) { @@ -130,7 +160,13 @@ class DRACOExporter { if ( colors !== undefined ) { - builder.AddFloatAttribute( dracoObject, dracoEncoder.COLOR, colors.count, colors.itemSize, colors.array ); + builder.AddFloatAttribute( + dracoObject, + dracoEncoder.COLOR, + colors.count, + colors.itemSize, + colors.array + ); } @@ -138,15 +174,15 @@ class DRACOExporter { } else { - throw new Error( 'DRACOExporter: Unsupported object type.' ); + throw new Error( 'DRACOExporter: Unsupported object type: ' + object.type ); } - //Compress using draco encoder + // Compress using draco encoder const encodedData = new dracoEncoder.DracoInt8Array(); - //Sets the desired encoding and decoding speed for the given options from 0 (slowest speed, but the best compression) to 10 (fastest, but the worst compression). + // Sets the desired encoding and decoding speed for the given options from 0 (slowest speed, but the best compression) to 10 (fastest, but the worst compression). const encodeSpeed = ( options.encodeSpeed !== undefined ) ? options.encodeSpeed : 5; const decodeSpeed = ( options.decodeSpeed !== undefined ) ? options.decodeSpeed : 5; @@ -197,7 +233,7 @@ class DRACOExporter { } - //Copy encoded data to buffer. + // Copy encoded data to buffer. const outputData = new Int8Array( new ArrayBuffer( length ) ); for ( let i = 0; i < length; i ++ ) { @@ -210,7 +246,10 @@ class DRACOExporter { dracoEncoder.destroy( encoder ); dracoEncoder.destroy( builder ); - return outputData; + return { + buffer: outputData, + attributeIDs, + }; } diff --git a/examples/jsm/exporters/GLTFExporter.js b/examples/jsm/exporters/GLTFExporter.js index 7d792b54de8871..73f556c3882f28 100644 --- a/examples/jsm/exporters/GLTFExporter.js +++ b/examples/jsm/exporters/GLTFExporter.js @@ -26,6 +26,8 @@ class GLTFExporter { constructor() { + this.dracoExporter = null; + this.pluginCallbacks = []; this.register( function ( writer ) { @@ -84,6 +86,13 @@ class GLTFExporter { } + setDRACOExporter( dracoExporter ) { + + this.dracoExporter = dracoExporter; + return this; + + } + /** * Parse scenes and generate GLTF output * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes @@ -101,6 +110,13 @@ class GLTFExporter { } + + if ( options && options.draco ) { + + writer.dracoExporter = this.dracoExporter; + + } + writer.setPlugins( plugins ); writer.write( input, onDone, options ); @@ -386,6 +402,7 @@ class GLTFWriter { this.options = Object.assign( {}, { // default options binary: false, + draco: false, trs: false, onlyVisible: true, truncateDrawRange: true, @@ -903,30 +920,43 @@ class GLTFWriter { if ( count === 0 ) return null; const minMax = getMinMax( attribute, start, count ); - let bufferViewTarget; - - // If geometry isn't provided, don't infer the target usage of the bufferView. For - // animation samplers, target must not be set. - if ( geometry !== undefined ) { - - bufferViewTarget = attribute === geometry.index ? WEBGL_CONSTANTS.ELEMENT_ARRAY_BUFFER : WEBGL_CONSTANTS.ARRAY_BUFFER; - - } - - const bufferView = this.processBufferView( attribute, componentType, start, count, bufferViewTarget ); const accessorDef = { - - bufferView: bufferView.id, - byteOffset: bufferView.byteOffset, componentType: componentType, count: count, max: minMax.max, min: minMax.min, - type: types[ attribute.itemSize ] - + type: types[ attribute.itemSize ], }; + if ( ! this.options.draco ) { + + let bufferViewTarget; + + // If geometry isn't provided, don't infer the target usage of the bufferView. For + // animation samplers, target must not be set. + if ( geometry !== undefined ) { + + bufferViewTarget = + attribute === geometry.index + ? WEBGL_CONSTANTS.ELEMENT_ARRAY_BUFFER + : WEBGL_CONSTANTS.ARRAY_BUFFER; + + } + + const bufferView = this.processBufferView( + attribute, + componentType, + start, + count, + bufferViewTarget + ); + + accessorDef.bufferView = bufferView.id; + accessorDef.byteOffset = bufferView.byteOffset; + + } + if ( attribute.normalized === true ) accessorDef.normalized = true; if ( ! json.accessors ) json.accessors = []; @@ -1590,6 +1620,51 @@ class GLTFWriter { meshDef.primitives = primitives; + + if ( this.options.draco ) { + + const dracoOutput = this.dracoExporter.parse( mesh ); + + // Add buffer + this.processBuffer( dracoOutput.buffer ); + + // Add single bufferView + const bufferView = { + buffer: 0, + byteOffset: this.byteOffset, + byteLength: dracoOutput.buffer.length, + }; + this.byteOffset += bufferView.byteLength; + + if ( ! json.bufferViews ) json.bufferViews = []; + + json.bufferViews.push( bufferView ); + + primitives.forEach( ( primitive ) => { + + // Add draco extension to the primitive + if ( ! primitive.extensions ) primitive.extensions = {}; + primitive.extensions[ 'KHR_draco_mesh_compression' ] = { + bufferView: json.bufferViews.length - 1, + attributes: dracoOutput.attributeIDs, + }; + + } ); + + // add draco to extensionsRequired + if ( ! json.extensionsRequired ) json.extensionsRequired = []; + if ( ! json.extensionsRequired.includes( 'KHR_draco_mesh_compression' ) ) { + + json.extensionsRequired.push( 'KHR_draco_mesh_compression' ); + + } + + // add draco to extensionsUsed + this.extensionsUsed[ 'KHR_draco_mesh_compression' ] = true; + + } + + if ( ! json.meshes ) json.meshes = []; this._invokeAll( function ( ext ) { diff --git a/examples/misc_exporter_draco.html b/examples/misc_exporter_draco.html index 682c9dfcccea40..c417b86803e2a5 100644 --- a/examples/misc_exporter_draco.html +++ b/examples/misc_exporter_draco.html @@ -120,7 +120,7 @@ function exportFile() { const result = exporter.parse( mesh ); - saveArrayBuffer( result, 'file.drc' ); + saveArrayBuffer( result.buffer, 'file.drc' ); } diff --git a/examples/misc_exporter_gltf.html b/examples/misc_exporter_gltf.html index 8f6fae7b45403d..4006966b5acb01 100644 --- a/examples/misc_exporter_gltf.html +++ b/examples/misc_exporter_gltf.html @@ -20,25 +20,33 @@
+ + +