Last active
March 12, 2025 06:10
THREE.GLTFLoader with Draco support in Node.js.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* THREE.GLTFLoader with Draco support in Node.js. | |
*/ | |
const fs = require('fs'); | |
// All packages in 'three/examples/js' currently require access to the THREE | |
// variable in global scope. Work on supporting ES modules is in progress. | |
const THREE = global.THREE = require('three'); | |
// GLTFLoader is more efficient with access to a TextDecoder instance, which is | |
// in the global namespace in the browser. | |
global.TextDecoder = require('util').TextDecoder; | |
// GLTFLoader will add itself to the THREE namespace. Work on supporting ES | |
// modules is in progress. | |
require('three/examples/js/loaders/GLTFLoader.js'); | |
// Custom-built version of DRACOLoader, for Node.js. | |
const NodeDRACOLoader = require('./NodeDRACOLoader.js'); | |
// GLTFLoader prefetches the decoder module, when Draco is needed, to speed up | |
// parsing later. This isn't necessary for our custom decoder, so set the | |
// method to a no-op. | |
THREE.DRACOLoader.getDecoderModule = () => {}; | |
// Create a loader, and configure it with the custom Draco decoder. | |
const loader = new THREE.GLTFLoader(); | |
loader.setDRACOLoader( new NodeDRACOLoader() ); | |
// Read model from disk and parse it. If the model required external resources, | |
// we would need to import the 'node-xmlhttprequest' package and patch it into | |
// the global namespace. Unfortunately GLTFLoader cannot parse embedded textures | |
// in a Node.js context, due to reliance on browser APIs (URL.createObjectURL). | |
const content = fs.readFileSync( 'model.glb' ); | |
loader.parse( trimBuffer( content ), '', ( gltf ) => { | |
console.log( gltf ); | |
}, ( e ) => { | |
console.error( e ); | |
} ); | |
/** | |
* The Node.js filesystem API ('fs') returns a Buffer instance, which may be a | |
* view into a larger buffer. Because GLTFLoader parsing expects a raw | |
* ArrayBuffer, we make a trimmed copy of the original here. | |
* | |
* @param {Buffer} buffer | |
* @return {ArrayBuffer} | |
*/ | |
function trimBuffer ( buffer ) { | |
const { byteOffset, byteLength } = buffer; | |
return buffer.buffer.slice( byteOffset, byteOffset + byteLength ); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/node_modules/three/examples/js/loaders/DRACOLoader.js b/NodeDRACOLoader.js | |
index 57767d7..cc46f2c 100644 | |
--- a/node_modules/three/examples/js/loaders/DRACOLoader.js | |
+++ b/NodeDRACOLoader.js | |
@@ -14,10 +14,12 @@ | |
// | |
'use strict'; | |
+const decoder = require('draco3dgltf').createDecoderModule(); | |
+ | |
/** | |
* @param {THREE.LoadingManager} manager | |
*/ | |
-THREE.DRACOLoader = function(manager) { | |
+module.exports = THREE.DRACOLoader = function(manager) { | |
this.timeLoaded = 0; | |
this.manager = manager || THREE.DefaultLoadingManager; | |
this.materials = null; | |
@@ -100,12 +102,8 @@ THREE.DRACOLoader.prototype = { | |
*/ | |
decodeDracoFile: function(rawBuffer, callback, attributeUniqueIdMap, | |
attributeTypeMap) { | |
- var scope = this; | |
- THREE.DRACOLoader.getDecoderModule() | |
- .then( function ( module ) { | |
- scope.decodeDracoFileInternal( rawBuffer, module.decoder, callback, | |
- attributeUniqueIdMap, attributeTypeMap); | |
- }); | |
+ this.decodeDracoFileInternal( rawBuffer, decoder, callback, | |
+ attributeUniqueIdMap, attributeTypeMap); | |
}, | |
decodeDracoFileInternal: function(rawBuffer, dracoDecoder, callback, | |
@@ -238,7 +236,7 @@ THREE.DRACOLoader.prototype = { | |
} | |
var dracoGeometry; | |
var decodingStatus; | |
- var start_time = performance.now(); | |
+ // var start_time = performance.now(); | |
if (geometryType === dracoDecoder.TRIANGULAR_MESH) { | |
dracoGeometry = new dracoDecoder.Mesh(); | |
decodingStatus = decoder.DecodeBufferToMesh(buffer, dracoGeometry); | |
@@ -256,7 +254,7 @@ THREE.DRACOLoader.prototype = { | |
throw new Error(errorMsg); | |
} | |
- var decode_end = performance.now(); | |
+ // var decode_end = performance.now(); | |
dracoDecoder.destroy(buffer); | |
/* | |
* Example on how to retrieve mesh and attributes. | |
@@ -381,21 +379,18 @@ THREE.DRACOLoader.prototype = { | |
dracoDecoder.destroy(decoder); | |
dracoDecoder.destroy(dracoGeometry); | |
- this.decode_time = decode_end - start_time; | |
- this.import_time = performance.now() - decode_end; | |
+ // this.decode_time = decode_end - start_time; | |
+ // this.import_time = performance.now() - decode_end; | |
- if (this.verbosity > 0) { | |
- console.log('Decode time: ' + this.decode_time); | |
- console.log('Import time: ' + this.import_time); | |
- } | |
+ // if (this.verbosity > 0) { | |
+ // console.log('Decode time: ' + this.decode_time); | |
+ // console.log('Import time: ' + this.import_time); | |
+ // } | |
return geometry; | |
}, | |
isVersionSupported: function(version, callback) { | |
- THREE.DRACOLoader.getDecoderModule() | |
- .then( function ( module ) { | |
- callback( module.decoder.isVersionSupported( version ) ); | |
- }); | |
+ callback( decoder.isVersionSupported( version ) ); | |
}, | |
getAttributeOptions: function(attributeName) { | |
@@ -404,118 +399,3 @@ THREE.DRACOLoader.prototype = { | |
return this.attributeOptions[attributeName]; | |
} | |
}; | |
- | |
-THREE.DRACOLoader.decoderPath = './'; | |
-THREE.DRACOLoader.decoderConfig = {}; | |
-THREE.DRACOLoader.decoderModulePromise = null; | |
- | |
-/** | |
- * Sets the base path for decoder source files. | |
- * @param {string} path | |
- */ | |
-THREE.DRACOLoader.setDecoderPath = function ( path ) { | |
- THREE.DRACOLoader.decoderPath = path; | |
-}; | |
- | |
-/** | |
- * Sets decoder configuration and releases singleton decoder module. Module | |
- * will be recreated with the next decoding call. | |
- * @param {Object} config | |
- */ | |
-THREE.DRACOLoader.setDecoderConfig = function ( config ) { | |
- var wasmBinary = THREE.DRACOLoader.decoderConfig.wasmBinary; | |
- THREE.DRACOLoader.decoderConfig = config || {}; | |
- THREE.DRACOLoader.releaseDecoderModule(); | |
- | |
- // Reuse WASM binary. | |
- if ( wasmBinary ) THREE.DRACOLoader.decoderConfig.wasmBinary = wasmBinary; | |
-}; | |
- | |
-/** | |
- * Releases the singleton DracoDecoderModule instance. Module will be recreated | |
- * with the next decoding call. | |
- */ | |
-THREE.DRACOLoader.releaseDecoderModule = function () { | |
- THREE.DRACOLoader.decoderModulePromise = null; | |
-}; | |
- | |
-/** | |
- * Gets WebAssembly or asm.js singleton instance of DracoDecoderModule | |
- * after testing for browser support. Returns Promise that resolves when | |
- * module is available. | |
- * @return {Promise<{decoder: DracoDecoderModule}>} | |
- */ | |
-THREE.DRACOLoader.getDecoderModule = function () { | |
- var scope = this; | |
- var path = THREE.DRACOLoader.decoderPath; | |
- var config = THREE.DRACOLoader.decoderConfig; | |
- var promise = THREE.DRACOLoader.decoderModulePromise; | |
- | |
- if ( promise ) return promise; | |
- | |
- // Load source files. | |
- if ( typeof DracoDecoderModule !== 'undefined' ) { | |
- // Loaded externally. | |
- promise = Promise.resolve(); | |
- } else if ( typeof WebAssembly !== 'object' || config.type === 'js' ) { | |
- // Load with asm.js. | |
- promise = THREE.DRACOLoader._loadScript( path + 'draco_decoder.js' ); | |
- } else { | |
- // Load with WebAssembly. | |
- config.wasmBinaryFile = path + 'draco_decoder.wasm'; | |
- promise = THREE.DRACOLoader._loadScript( path + 'draco_wasm_wrapper.js' ) | |
- .then( function () { | |
- return THREE.DRACOLoader._loadArrayBuffer( config.wasmBinaryFile ); | |
- } ) | |
- .then( function ( wasmBinary ) { | |
- config.wasmBinary = wasmBinary; | |
- } ); | |
- } | |
- | |
- // Wait for source files, then create and return a decoder. | |
- promise = promise.then( function () { | |
- return new Promise( function ( resolve ) { | |
- config.onModuleLoaded = function ( decoder ) { | |
- scope.timeLoaded = performance.now(); | |
- // Module is Promise-like. Wrap before resolving to avoid loop. | |
- resolve( { decoder: decoder } ); | |
- }; | |
- DracoDecoderModule( config ); | |
- } ); | |
- } ); | |
- | |
- THREE.DRACOLoader.decoderModulePromise = promise; | |
- return promise; | |
-}; | |
- | |
-/** | |
- * @param {string} src | |
- * @return {Promise} | |
- */ | |
-THREE.DRACOLoader._loadScript = function ( src ) { | |
- var prevScript = document.getElementById( 'decoder_script' ); | |
- if ( prevScript !== null ) { | |
- prevScript.parentNode.removeChild( prevScript ); | |
- } | |
- var head = document.getElementsByTagName( 'head' )[ 0 ]; | |
- var script = document.createElement( 'script' ); | |
- script.id = 'decoder_script'; | |
- script.type = 'text/javascript'; | |
- script.src = src; | |
- return new Promise( function ( resolve ) { | |
- script.onload = resolve; | |
- head.appendChild( script ); | |
- }); | |
-}; | |
- | |
-/** | |
- * @param {string} src | |
- * @return {Promise} | |
- */ | |
-THREE.DRACOLoader._loadArrayBuffer = function ( src ) { | |
- var loader = new THREE.FileLoader(); | |
- loader.setResponseType( 'arraybuffer' ); | |
- return new Promise( function( resolve, reject ) { | |
- loader.load( src, resolve, undefined, reject ); | |
- }); | |
-}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2016 The Draco Authors. | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
// | |
'use strict'; | |
const decoder = require('draco3dgltf').createDecoderModule(); | |
/** | |
* @param {THREE.LoadingManager} manager | |
*/ | |
module.exports = THREE.DRACOLoader = function(manager) { | |
this.timeLoaded = 0; | |
this.manager = manager || THREE.DefaultLoadingManager; | |
this.materials = null; | |
this.verbosity = 0; | |
this.attributeOptions = {}; | |
this.drawMode = THREE.TrianglesDrawMode; | |
// Native Draco attribute type to Three.JS attribute type. | |
this.nativeAttributeMap = { | |
'position' : 'POSITION', | |
'normal' : 'NORMAL', | |
'color' : 'COLOR', | |
'uv' : 'TEX_COORD' | |
}; | |
}; | |
THREE.DRACOLoader.prototype = { | |
constructor: THREE.DRACOLoader, | |
load: function(url, onLoad, onProgress, onError) { | |
var scope = this; | |
var loader = new THREE.FileLoader(scope.manager); | |
loader.setPath(this.path); | |
loader.setResponseType('arraybuffer'); | |
loader.load(url, function(blob) { | |
scope.decodeDracoFile(blob, onLoad); | |
}, onProgress, onError); | |
}, | |
setPath: function(value) { | |
this.path = value; | |
return this; | |
}, | |
setVerbosity: function(level) { | |
this.verbosity = level; | |
return this; | |
}, | |
/** | |
* Sets desired mode for generated geometry indices. | |
* Can be either: | |
* THREE.TrianglesDrawMode | |
* THREE.TriangleStripDrawMode | |
*/ | |
setDrawMode: function(drawMode) { | |
this.drawMode = drawMode; | |
return this; | |
}, | |
/** | |
* Skips dequantization for a specific attribute. | |
* |attributeName| is the THREE.js name of the given attribute type. | |
* The only currently supported |attributeName| is 'position', more may be | |
* added in future. | |
*/ | |
setSkipDequantization: function(attributeName, skip) { | |
var skipDequantization = true; | |
if (typeof skip !== 'undefined') | |
skipDequantization = skip; | |
this.getAttributeOptions(attributeName).skipDequantization = | |
skipDequantization; | |
return this; | |
}, | |
/** | |
* Decompresses a Draco buffer. Names of attributes (for ID and type maps) | |
* must be one of the supported three.js types, including: position, color, | |
* normal, uv, uv2, skinIndex, skinWeight. | |
* | |
* @param {ArrayBuffer} rawBuffer | |
* @param {Function} callback | |
* @param {Object|undefined} attributeUniqueIdMap Provides a pre-defined ID | |
* for each attribute in the geometry to be decoded. If given, | |
* `attributeTypeMap` is required and `nativeAttributeMap` will be | |
* ignored. | |
* @param {Object|undefined} attributeTypeMap Provides a predefined data | |
* type (as a typed array constructor) for each attribute in the | |
* geometry to be decoded. | |
*/ | |
decodeDracoFile: function(rawBuffer, callback, attributeUniqueIdMap, | |
attributeTypeMap) { | |
this.decodeDracoFileInternal( rawBuffer, decoder, callback, | |
attributeUniqueIdMap, attributeTypeMap); | |
}, | |
decodeDracoFileInternal: function(rawBuffer, dracoDecoder, callback, | |
attributeUniqueIdMap, attributeTypeMap) { | |
/* | |
* Here is how to use Draco Javascript decoder and get the geometry. | |
*/ | |
var buffer = new dracoDecoder.DecoderBuffer(); | |
buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength); | |
var decoder = new dracoDecoder.Decoder(); | |
/* | |
* Determine what type is this file: mesh or point cloud. | |
*/ | |
var geometryType = decoder.GetEncodedGeometryType(buffer); | |
if (geometryType == dracoDecoder.TRIANGULAR_MESH) { | |
if (this.verbosity > 0) { | |
console.log('Loaded a mesh.'); | |
} | |
} else if (geometryType == dracoDecoder.POINT_CLOUD) { | |
if (this.verbosity > 0) { | |
console.log('Loaded a point cloud.'); | |
} | |
} else { | |
var errorMsg = 'THREE.DRACOLoader: Unknown geometry type.'; | |
console.error(errorMsg); | |
throw new Error(errorMsg); | |
} | |
callback(this.convertDracoGeometryTo3JS(dracoDecoder, decoder, | |
geometryType, buffer, attributeUniqueIdMap, attributeTypeMap)); | |
}, | |
addAttributeToGeometry: function(dracoDecoder, decoder, dracoGeometry, | |
attributeName, attributeType, attribute, | |
geometry, geometryBuffer) { | |
if (attribute.ptr === 0) { | |
var errorMsg = 'THREE.DRACOLoader: No attribute ' + attributeName; | |
console.error(errorMsg); | |
throw new Error(errorMsg); | |
} | |
var numComponents = attribute.num_components(); | |
var numPoints = dracoGeometry.num_points(); | |
var numValues = numPoints * numComponents; | |
var attributeData; | |
var TypedBufferAttribute; | |
switch ( attributeType ) { | |
case Float32Array: | |
attributeData = new dracoDecoder.DracoFloat32Array(); | |
decoder.GetAttributeFloatForAllPoints( | |
dracoGeometry, attribute, attributeData); | |
geometryBuffer[ attributeName ] = new Float32Array( numValues ); | |
TypedBufferAttribute = THREE.Float32BufferAttribute; | |
break; | |
case Int8Array: | |
attributeData = new dracoDecoder.DracoInt8Array(); | |
decoder.GetAttributeInt8ForAllPoints( | |
dracoGeometry, attribute, attributeData ); | |
geometryBuffer[ attributeName ] = new Int8Array( numValues ); | |
TypedBufferAttribute = THREE.Int8BufferAttribute; | |
break; | |
case Int16Array: | |
attributeData = new dracoDecoder.DracoInt16Array(); | |
decoder.GetAttributeInt16ForAllPoints( | |
dracoGeometry, attribute, attributeData); | |
geometryBuffer[ attributeName ] = new Int16Array( numValues ); | |
TypedBufferAttribute = THREE.Int16BufferAttribute; | |
break; | |
case Int32Array: | |
attributeData = new dracoDecoder.DracoInt32Array(); | |
decoder.GetAttributeInt32ForAllPoints( | |
dracoGeometry, attribute, attributeData); | |
geometryBuffer[ attributeName ] = new Int32Array( numValues ); | |
TypedBufferAttribute = THREE.Int32BufferAttribute; | |
break; | |
case Uint8Array: | |
attributeData = new dracoDecoder.DracoUInt8Array(); | |
decoder.GetAttributeUInt8ForAllPoints( | |
dracoGeometry, attribute, attributeData); | |
geometryBuffer[ attributeName ] = new Uint8Array( numValues ); | |
TypedBufferAttribute = THREE.Uint8BufferAttribute; | |
break; | |
case Uint16Array: | |
attributeData = new dracoDecoder.DracoUInt16Array(); | |
decoder.GetAttributeUInt16ForAllPoints( | |
dracoGeometry, attribute, attributeData); | |
geometryBuffer[ attributeName ] = new Uint16Array( numValues ); | |
TypedBufferAttribute = THREE.Uint16BufferAttribute; | |
break; | |
case Uint32Array: | |
attributeData = new dracoDecoder.DracoUInt32Array(); | |
decoder.GetAttributeUInt32ForAllPoints( | |
dracoGeometry, attribute, attributeData); | |
geometryBuffer[ attributeName ] = new Uint32Array( numValues ); | |
TypedBufferAttribute = THREE.Uint32BufferAttribute; | |
break; | |
default: | |
var errorMsg = 'THREE.DRACOLoader: Unexpected attribute type.'; | |
console.error( errorMsg ); | |
throw new Error( errorMsg ); | |
} | |
// Copy data from decoder. | |
for (var i = 0; i < numValues; i++) { | |
geometryBuffer[attributeName][i] = attributeData.GetValue(i); | |
} | |
// Add attribute to THREEJS geometry for rendering. | |
geometry.addAttribute(attributeName, | |
new TypedBufferAttribute(geometryBuffer[attributeName], | |
numComponents)); | |
dracoDecoder.destroy(attributeData); | |
}, | |
convertDracoGeometryTo3JS: function(dracoDecoder, decoder, geometryType, | |
buffer, attributeUniqueIdMap, | |
attributeTypeMap) { | |
// TODO: Should not assume native Draco attribute IDs apply. | |
if (this.getAttributeOptions('position').skipDequantization === true) { | |
decoder.SkipAttributeTransform(dracoDecoder.POSITION); | |
} | |
var dracoGeometry; | |
var decodingStatus; | |
// var start_time = performance.now(); | |
if (geometryType === dracoDecoder.TRIANGULAR_MESH) { | |
dracoGeometry = new dracoDecoder.Mesh(); | |
decodingStatus = decoder.DecodeBufferToMesh(buffer, dracoGeometry); | |
} else { | |
dracoGeometry = new dracoDecoder.PointCloud(); | |
decodingStatus = | |
decoder.DecodeBufferToPointCloud(buffer, dracoGeometry); | |
} | |
if (!decodingStatus.ok() || dracoGeometry.ptr == 0) { | |
var errorMsg = 'THREE.DRACOLoader: Decoding failed: '; | |
errorMsg += decodingStatus.error_msg(); | |
console.error(errorMsg); | |
dracoDecoder.destroy(decoder); | |
dracoDecoder.destroy(dracoGeometry); | |
throw new Error(errorMsg); | |
} | |
// var decode_end = performance.now(); | |
dracoDecoder.destroy(buffer); | |
/* | |
* Example on how to retrieve mesh and attributes. | |
*/ | |
var numFaces; | |
if (geometryType == dracoDecoder.TRIANGULAR_MESH) { | |
numFaces = dracoGeometry.num_faces(); | |
if (this.verbosity > 0) { | |
console.log('Number of faces loaded: ' + numFaces.toString()); | |
} | |
} else { | |
numFaces = 0; | |
} | |
var numPoints = dracoGeometry.num_points(); | |
var numAttributes = dracoGeometry.num_attributes(); | |
if (this.verbosity > 0) { | |
console.log('Number of points loaded: ' + numPoints.toString()); | |
console.log('Number of attributes loaded: ' + | |
numAttributes.toString()); | |
} | |
// Verify if there is position attribute. | |
// TODO: Should not assume native Draco attribute IDs apply. | |
var posAttId = decoder.GetAttributeId(dracoGeometry, | |
dracoDecoder.POSITION); | |
if (posAttId == -1) { | |
var errorMsg = 'THREE.DRACOLoader: No position attribute found.'; | |
console.error(errorMsg); | |
dracoDecoder.destroy(decoder); | |
dracoDecoder.destroy(dracoGeometry); | |
throw new Error(errorMsg); | |
} | |
var posAttribute = decoder.GetAttribute(dracoGeometry, posAttId); | |
// Structure for converting to THREEJS geometry later. | |
var geometryBuffer = {}; | |
// Import data to Three JS geometry. | |
var geometry = new THREE.BufferGeometry(); | |
// Do not use both the native attribute map and a provided (e.g. glTF) map. | |
if ( attributeUniqueIdMap ) { | |
// Add attributes of user specified unique id. E.g. GLTF models. | |
for (var attributeName in attributeUniqueIdMap) { | |
var attributeType = attributeTypeMap[attributeName]; | |
var attributeId = attributeUniqueIdMap[attributeName]; | |
var attribute = decoder.GetAttributeByUniqueId(dracoGeometry, | |
attributeId); | |
this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry, | |
attributeName, attributeType, attribute, geometry, geometryBuffer); | |
} | |
} else { | |
// Add native Draco attribute type to geometry. | |
for (var attributeName in this.nativeAttributeMap) { | |
var attId = decoder.GetAttributeId(dracoGeometry, | |
dracoDecoder[this.nativeAttributeMap[attributeName]]); | |
if (attId !== -1) { | |
if (this.verbosity > 0) { | |
console.log('Loaded ' + attributeName + ' attribute.'); | |
} | |
var attribute = decoder.GetAttribute(dracoGeometry, attId); | |
this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry, | |
attributeName, Float32Array, attribute, geometry, geometryBuffer); | |
} | |
} | |
} | |
// For mesh, we need to generate the faces. | |
if (geometryType == dracoDecoder.TRIANGULAR_MESH) { | |
if (this.drawMode === THREE.TriangleStripDrawMode) { | |
var stripsArray = new dracoDecoder.DracoInt32Array(); | |
var numStrips = decoder.GetTriangleStripsFromMesh( | |
dracoGeometry, stripsArray); | |
geometryBuffer.indices = new Uint32Array(stripsArray.size()); | |
for (var i = 0; i < stripsArray.size(); ++i) { | |
geometryBuffer.indices[i] = stripsArray.GetValue(i); | |
} | |
dracoDecoder.destroy(stripsArray); | |
} else { | |
var numIndices = numFaces * 3; | |
geometryBuffer.indices = new Uint32Array(numIndices); | |
var ia = new dracoDecoder.DracoInt32Array(); | |
for (var i = 0; i < numFaces; ++i) { | |
decoder.GetFaceFromMesh(dracoGeometry, i, ia); | |
var index = i * 3; | |
geometryBuffer.indices[index] = ia.GetValue(0); | |
geometryBuffer.indices[index + 1] = ia.GetValue(1); | |
geometryBuffer.indices[index + 2] = ia.GetValue(2); | |
} | |
dracoDecoder.destroy(ia); | |
} | |
} | |
geometry.drawMode = this.drawMode; | |
if (geometryType == dracoDecoder.TRIANGULAR_MESH) { | |
geometry.setIndex(new(geometryBuffer.indices.length > 65535 ? | |
THREE.Uint32BufferAttribute : THREE.Uint16BufferAttribute) | |
(geometryBuffer.indices, 1)); | |
} | |
// TODO: Should not assume native Draco attribute IDs apply. | |
// TODO: Can other attribute types be quantized? | |
var posTransform = new dracoDecoder.AttributeQuantizationTransform(); | |
if (posTransform.InitFromAttribute(posAttribute)) { | |
// Quantized attribute. Store the quantization parameters into the | |
// THREE.js attribute. | |
geometry.attributes['position'].isQuantized = true; | |
geometry.attributes['position'].maxRange = posTransform.range(); | |
geometry.attributes['position'].numQuantizationBits = | |
posTransform.quantization_bits(); | |
geometry.attributes['position'].minValues = new Float32Array(3); | |
for (var i = 0; i < 3; ++i) { | |
geometry.attributes['position'].minValues[i] = | |
posTransform.min_value(i); | |
} | |
} | |
dracoDecoder.destroy(posTransform); | |
dracoDecoder.destroy(decoder); | |
dracoDecoder.destroy(dracoGeometry); | |
// this.decode_time = decode_end - start_time; | |
// this.import_time = performance.now() - decode_end; | |
// if (this.verbosity > 0) { | |
// console.log('Decode time: ' + this.decode_time); | |
// console.log('Import time: ' + this.import_time); | |
// } | |
return geometry; | |
}, | |
isVersionSupported: function(version, callback) { | |
callback( decoder.isVersionSupported( version ) ); | |
}, | |
getAttributeOptions: function(attributeName) { | |
if (typeof this.attributeOptions[attributeName] === 'undefined') | |
this.attributeOptions[attributeName] = {}; | |
return this.attributeOptions[attributeName]; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If anyone is curious what 3js revision a DRACOLoader.js file
57767d7
is from, try running this command:git log --all -m --find-object 57767d7
. From its output it seems like this file version was introduced in mrdoob/three.js#15084 (October 19, 2018)