Spaces:
Running
Running
| /** | |
| * @author Rich Tibbett / https://github.com/richtr | |
| * @author mrdoob / http://mrdoob.com/ | |
| * @author Tony Parisi / http://www.tonyparisi.com/ | |
| * @author Takahiro / https://github.com/takahirox | |
| */ | |
| THREE.LegacyGLTFLoader = ( function () { | |
| function LegacyGLTFLoader( manager ) { | |
| this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; | |
| } | |
| LegacyGLTFLoader.prototype = { | |
| constructor: LegacyGLTFLoader, | |
| crossOrigin: 'anonymous', | |
| load: function ( url, onLoad, onProgress, onError ) { | |
| var scope = this; | |
| var resourcePath; | |
| if ( this.resourcePath !== undefined ) { | |
| resourcePath = this.resourcePath; | |
| } else if ( this.path !== undefined ) { | |
| resourcePath = this.path; | |
| } else { | |
| resourcePath = THREE.LoaderUtils.extractUrlBase( url ); | |
| } | |
| var loader = new THREE.FileLoader( scope.manager ); | |
| loader.setPath( this.path ); | |
| loader.setResponseType( 'arraybuffer' ); | |
| loader.load( url, function ( data ) { | |
| scope.parse( data, resourcePath, onLoad ); | |
| }, onProgress, onError ); | |
| }, | |
| setCrossOrigin: function ( value ) { | |
| this.crossOrigin = value; | |
| return this; | |
| }, | |
| setPath: function ( value ) { | |
| this.path = value; | |
| }, | |
| setResourcePath: function ( value ) { | |
| this.resourcePath = value; | |
| return this; | |
| }, | |
| parse: function ( data, path, callback ) { | |
| var content; | |
| var extensions = {}; | |
| var magic = THREE.LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) ); | |
| if ( magic === BINARY_EXTENSION_HEADER_DEFAULTS.magic ) { | |
| extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data ); | |
| content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content; | |
| } else { | |
| content = THREE.LoaderUtils.decodeText( new Uint8Array( data ) ); | |
| } | |
| var json = JSON.parse( content ); | |
| if ( json.extensionsUsed && json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_COMMON ) >= 0 ) { | |
| extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] = new GLTFMaterialsCommonExtension( json ); | |
| } | |
| var parser = new GLTFParser( json, extensions, { | |
| crossOrigin: this.crossOrigin, | |
| manager: this.manager, | |
| path: path || this.resourcePath || '' | |
| } ); | |
| parser.parse( function ( scene, scenes, cameras, animations ) { | |
| var glTF = { | |
| "scene": scene, | |
| "scenes": scenes, | |
| "cameras": cameras, | |
| "animations": animations | |
| }; | |
| callback( glTF ); | |
| } ); | |
| } | |
| }; | |
| /* GLTFREGISTRY */ | |
| function GLTFRegistry() { | |
| var objects = {}; | |
| return { | |
| get: function ( key ) { | |
| return objects[ key ]; | |
| }, | |
| add: function ( key, object ) { | |
| objects[ key ] = object; | |
| }, | |
| remove: function ( key ) { | |
| delete objects[ key ]; | |
| }, | |
| removeAll: function () { | |
| objects = {}; | |
| }, | |
| update: function ( scene, camera ) { | |
| for ( var name in objects ) { | |
| var object = objects[ name ]; | |
| if ( object.update ) { | |
| object.update( scene, camera ); | |
| } | |
| } | |
| } | |
| }; | |
| } | |
| /* GLTFSHADERS */ | |
| LegacyGLTFLoader.Shaders = { | |
| update: function () { | |
| console.warn( 'THREE.LegacyGLTFLoader.Shaders has been deprecated, and now updates automatically.' ); | |
| } | |
| }; | |
| /* GLTFSHADER */ | |
| function GLTFShader( targetNode, allNodes ) { | |
| var boundUniforms = {}; | |
| // bind each uniform to its source node | |
| var uniforms = targetNode.material.uniforms; | |
| for ( var uniformId in uniforms ) { | |
| var uniform = uniforms[ uniformId ]; | |
| if ( uniform.semantic ) { | |
| var sourceNodeRef = uniform.node; | |
| var sourceNode = targetNode; | |
| if ( sourceNodeRef ) { | |
| sourceNode = allNodes[ sourceNodeRef ]; | |
| } | |
| boundUniforms[ uniformId ] = { | |
| semantic: uniform.semantic, | |
| sourceNode: sourceNode, | |
| targetNode: targetNode, | |
| uniform: uniform | |
| }; | |
| } | |
| } | |
| this.boundUniforms = boundUniforms; | |
| this._m4 = new THREE.Matrix4(); | |
| } | |
| // Update - update all the uniform values | |
| GLTFShader.prototype.update = function ( scene, camera ) { | |
| var boundUniforms = this.boundUniforms; | |
| for ( var name in boundUniforms ) { | |
| var boundUniform = boundUniforms[ name ]; | |
| switch ( boundUniform.semantic ) { | |
| case "MODELVIEW": | |
| var m4 = boundUniform.uniform.value; | |
| m4.multiplyMatrices( camera.matrixWorldInverse, boundUniform.sourceNode.matrixWorld ); | |
| break; | |
| case "MODELVIEWINVERSETRANSPOSE": | |
| var m3 = boundUniform.uniform.value; | |
| this._m4.multiplyMatrices( camera.matrixWorldInverse, boundUniform.sourceNode.matrixWorld ); | |
| m3.getNormalMatrix( this._m4 ); | |
| break; | |
| case "PROJECTION": | |
| var m4 = boundUniform.uniform.value; | |
| m4.copy( camera.projectionMatrix ); | |
| break; | |
| case "JOINTMATRIX": | |
| var m4v = boundUniform.uniform.value; | |
| for ( var mi = 0; mi < m4v.length; mi ++ ) { | |
| // So it goes like this: | |
| // SkinnedMesh world matrix is already baked into MODELVIEW; | |
| // transform joints to local space, | |
| // then transform using joint's inverse | |
| m4v[ mi ] | |
| .getInverse( boundUniform.sourceNode.matrixWorld ) | |
| .multiply( boundUniform.targetNode.skeleton.bones[ mi ].matrixWorld ) | |
| .multiply( boundUniform.targetNode.skeleton.boneInverses[ mi ] ) | |
| .multiply( boundUniform.targetNode.bindMatrix ); | |
| } | |
| break; | |
| default : | |
| console.warn( "Unhandled shader semantic: " + boundUniform.semantic ); | |
| break; | |
| } | |
| } | |
| }; | |
| /* ANIMATION */ | |
| LegacyGLTFLoader.Animations = { | |
| update: function () { | |
| console.warn( 'THREE.LegacyGLTFLoader.Animation has been deprecated. Use THREE.AnimationMixer instead.' ); | |
| } | |
| }; | |
| /*********************************/ | |
| /********** EXTENSIONS ***********/ | |
| /*********************************/ | |
| var EXTENSIONS = { | |
| KHR_BINARY_GLTF: 'KHR_binary_glTF', | |
| KHR_MATERIALS_COMMON: 'KHR_materials_common' | |
| }; | |
| /* MATERIALS COMMON EXTENSION */ | |
| function GLTFMaterialsCommonExtension( json ) { | |
| this.name = EXTENSIONS.KHR_MATERIALS_COMMON; | |
| this.lights = {}; | |
| var extension = ( json.extensions && json.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) || {}; | |
| var lights = extension.lights || {}; | |
| for ( var lightId in lights ) { | |
| var light = lights[ lightId ]; | |
| var lightNode; | |
| var lightParams = light[ light.type ]; | |
| var color = new THREE.Color().fromArray( lightParams.color ); | |
| switch ( light.type ) { | |
| case "directional": | |
| lightNode = new THREE.DirectionalLight( color ); | |
| lightNode.position.set( 0, 0, 1 ); | |
| break; | |
| case "point": | |
| lightNode = new THREE.PointLight( color ); | |
| break; | |
| case "spot": | |
| lightNode = new THREE.SpotLight( color ); | |
| lightNode.position.set( 0, 0, 1 ); | |
| break; | |
| case "ambient": | |
| lightNode = new THREE.AmbientLight( color ); | |
| break; | |
| } | |
| if ( lightNode ) { | |
| this.lights[ lightId ] = lightNode; | |
| } | |
| } | |
| } | |
| /* BINARY EXTENSION */ | |
| var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF'; | |
| var BINARY_EXTENSION_HEADER_DEFAULTS = { magic: 'glTF', version: 1, contentFormat: 0 }; | |
| var BINARY_EXTENSION_HEADER_LENGTH = 20; | |
| function GLTFBinaryExtension( data ) { | |
| this.name = EXTENSIONS.KHR_BINARY_GLTF; | |
| var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH ); | |
| var header = { | |
| magic: THREE.LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ), | |
| version: headerView.getUint32( 4, true ), | |
| length: headerView.getUint32( 8, true ), | |
| contentLength: headerView.getUint32( 12, true ), | |
| contentFormat: headerView.getUint32( 16, true ) | |
| }; | |
| for ( var key in BINARY_EXTENSION_HEADER_DEFAULTS ) { | |
| var value = BINARY_EXTENSION_HEADER_DEFAULTS[ key ]; | |
| if ( header[ key ] !== value ) { | |
| throw new Error( 'Unsupported glTF-Binary header: Expected "%s" to be "%s".', key, value ); | |
| } | |
| } | |
| var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH, header.contentLength ); | |
| this.header = header; | |
| this.content = THREE.LoaderUtils.decodeText( contentArray ); | |
| this.body = data.slice( BINARY_EXTENSION_HEADER_LENGTH + header.contentLength, header.length ); | |
| } | |
| GLTFBinaryExtension.prototype.loadShader = function ( shader, bufferViews ) { | |
| var bufferView = bufferViews[ shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].bufferView ]; | |
| var array = new Uint8Array( bufferView ); | |
| return THREE.LoaderUtils.decodeText( array ); | |
| }; | |
| /*********************************/ | |
| /********** INTERNALS ************/ | |
| /*********************************/ | |
| /* CONSTANTS */ | |
| var WEBGL_CONSTANTS = { | |
| FLOAT: 5126, | |
| //FLOAT_MAT2: 35674, | |
| FLOAT_MAT3: 35675, | |
| FLOAT_MAT4: 35676, | |
| FLOAT_VEC2: 35664, | |
| FLOAT_VEC3: 35665, | |
| FLOAT_VEC4: 35666, | |
| LINEAR: 9729, | |
| REPEAT: 10497, | |
| SAMPLER_2D: 35678, | |
| TRIANGLES: 4, | |
| LINES: 1, | |
| UNSIGNED_BYTE: 5121, | |
| UNSIGNED_SHORT: 5123, | |
| VERTEX_SHADER: 35633, | |
| FRAGMENT_SHADER: 35632 | |
| }; | |
| var WEBGL_TYPE = { | |
| 5126: Number, | |
| //35674: THREE.Matrix2, | |
| 35675: THREE.Matrix3, | |
| 35676: THREE.Matrix4, | |
| 35664: THREE.Vector2, | |
| 35665: THREE.Vector3, | |
| 35666: THREE.Vector4, | |
| 35678: THREE.Texture | |
| }; | |
| var WEBGL_COMPONENT_TYPES = { | |
| 5120: Int8Array, | |
| 5121: Uint8Array, | |
| 5122: Int16Array, | |
| 5123: Uint16Array, | |
| 5125: Uint32Array, | |
| 5126: Float32Array | |
| }; | |
| var WEBGL_FILTERS = { | |
| 9728: THREE.NearestFilter, | |
| 9729: THREE.LinearFilter, | |
| 9984: THREE.NearestMipMapNearestFilter, | |
| 9985: THREE.LinearMipMapNearestFilter, | |
| 9986: THREE.NearestMipMapLinearFilter, | |
| 9987: THREE.LinearMipMapLinearFilter | |
| }; | |
| var WEBGL_WRAPPINGS = { | |
| 33071: THREE.ClampToEdgeWrapping, | |
| 33648: THREE.MirroredRepeatWrapping, | |
| 10497: THREE.RepeatWrapping | |
| }; | |
| var WEBGL_TEXTURE_FORMATS = { | |
| 6406: THREE.AlphaFormat, | |
| 6407: THREE.RGBFormat, | |
| 6408: THREE.RGBAFormat, | |
| 6409: THREE.LuminanceFormat, | |
| 6410: THREE.LuminanceAlphaFormat | |
| }; | |
| var WEBGL_TEXTURE_DATATYPES = { | |
| 5121: THREE.UnsignedByteType, | |
| 32819: THREE.UnsignedShort4444Type, | |
| 32820: THREE.UnsignedShort5551Type, | |
| 33635: THREE.UnsignedShort565Type | |
| }; | |
| var WEBGL_SIDES = { | |
| 1028: THREE.BackSide, // Culling front | |
| 1029: THREE.FrontSide // Culling back | |
| //1032: THREE.NoSide // Culling front and back, what to do? | |
| }; | |
| var WEBGL_DEPTH_FUNCS = { | |
| 512: THREE.NeverDepth, | |
| 513: THREE.LessDepth, | |
| 514: THREE.EqualDepth, | |
| 515: THREE.LessEqualDepth, | |
| 516: THREE.GreaterEqualDepth, | |
| 517: THREE.NotEqualDepth, | |
| 518: THREE.GreaterEqualDepth, | |
| 519: THREE.AlwaysDepth | |
| }; | |
| var WEBGL_BLEND_EQUATIONS = { | |
| 32774: THREE.AddEquation, | |
| 32778: THREE.SubtractEquation, | |
| 32779: THREE.ReverseSubtractEquation | |
| }; | |
| var WEBGL_BLEND_FUNCS = { | |
| 0: THREE.ZeroFactor, | |
| 1: THREE.OneFactor, | |
| 768: THREE.SrcColorFactor, | |
| 769: THREE.OneMinusSrcColorFactor, | |
| 770: THREE.SrcAlphaFactor, | |
| 771: THREE.OneMinusSrcAlphaFactor, | |
| 772: THREE.DstAlphaFactor, | |
| 773: THREE.OneMinusDstAlphaFactor, | |
| 774: THREE.DstColorFactor, | |
| 775: THREE.OneMinusDstColorFactor, | |
| 776: THREE.SrcAlphaSaturateFactor | |
| // The followings are not supported by Three.js yet | |
| //32769: CONSTANT_COLOR, | |
| //32770: ONE_MINUS_CONSTANT_COLOR, | |
| //32771: CONSTANT_ALPHA, | |
| //32772: ONE_MINUS_CONSTANT_COLOR | |
| }; | |
| var WEBGL_TYPE_SIZES = { | |
| 'SCALAR': 1, | |
| 'VEC2': 2, | |
| 'VEC3': 3, | |
| 'VEC4': 4, | |
| 'MAT2': 4, | |
| 'MAT3': 9, | |
| 'MAT4': 16 | |
| }; | |
| var PATH_PROPERTIES = { | |
| scale: 'scale', | |
| translation: 'position', | |
| rotation: 'quaternion' | |
| }; | |
| var INTERPOLATION = { | |
| LINEAR: THREE.InterpolateLinear, | |
| STEP: THREE.InterpolateDiscrete | |
| }; | |
| var STATES_ENABLES = { | |
| 2884: 'CULL_FACE', | |
| 2929: 'DEPTH_TEST', | |
| 3042: 'BLEND', | |
| 3089: 'SCISSOR_TEST', | |
| 32823: 'POLYGON_OFFSET_FILL', | |
| 32926: 'SAMPLE_ALPHA_TO_COVERAGE' | |
| }; | |
| /* UTILITY FUNCTIONS */ | |
| function _each( object, callback, thisObj ) { | |
| if ( ! object ) { | |
| return Promise.resolve(); | |
| } | |
| var results; | |
| var fns = []; | |
| if ( Object.prototype.toString.call( object ) === '[object Array]' ) { | |
| results = []; | |
| var length = object.length; | |
| for ( var idx = 0; idx < length; idx ++ ) { | |
| var value = callback.call( thisObj || this, object[ idx ], idx ); | |
| if ( value ) { | |
| fns.push( value ); | |
| if ( value instanceof Promise ) { | |
| value.then( function ( key, value ) { | |
| results[ key ] = value; | |
| }.bind( this, idx ) ); | |
| } else { | |
| results[ idx ] = value; | |
| } | |
| } | |
| } | |
| } else { | |
| results = {}; | |
| for ( var key in object ) { | |
| if ( object.hasOwnProperty( key ) ) { | |
| var value = callback.call( thisObj || this, object[ key ], key ); | |
| if ( value ) { | |
| fns.push( value ); | |
| if ( value instanceof Promise ) { | |
| value.then( function ( key, value ) { | |
| results[ key ] = value; | |
| }.bind( this, key ) ); | |
| } else { | |
| results[ key ] = value; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return Promise.all( fns ).then( function () { | |
| return results; | |
| } ); | |
| } | |
| function resolveURL( url, path ) { | |
| // Invalid URL | |
| if ( typeof url !== 'string' || url === '' ) | |
| return ''; | |
| // Absolute URL http://,https://,// | |
| if ( /^(https?:)?\/\//i.test( url ) ) { | |
| return url; | |
| } | |
| // Data URI | |
| if ( /^data:.*,.*$/i.test( url ) ) { | |
| return url; | |
| } | |
| // Blob URL | |
| if ( /^blob:.*$/i.test( url ) ) { | |
| return url; | |
| } | |
| // Relative URL | |
| return ( path || '' ) + url; | |
| } | |
| // Three.js seems too dependent on attribute names so globally | |
| // replace those in the shader code | |
| function replaceTHREEShaderAttributes( shaderText, technique ) { | |
| // Expected technique attributes | |
| var attributes = {}; | |
| for ( var attributeId in technique.attributes ) { | |
| var pname = technique.attributes[ attributeId ]; | |
| var param = technique.parameters[ pname ]; | |
| var atype = param.type; | |
| var semantic = param.semantic; | |
| attributes[ attributeId ] = { | |
| type: atype, | |
| semantic: semantic | |
| }; | |
| } | |
| // Figure out which attributes to change in technique | |
| var shaderParams = technique.parameters; | |
| var shaderAttributes = technique.attributes; | |
| var params = {}; | |
| for ( var attributeId in attributes ) { | |
| var pname = shaderAttributes[ attributeId ]; | |
| var shaderParam = shaderParams[ pname ]; | |
| var semantic = shaderParam.semantic; | |
| if ( semantic ) { | |
| params[ attributeId ] = shaderParam; | |
| } | |
| } | |
| for ( var pname in params ) { | |
| var param = params[ pname ]; | |
| var semantic = param.semantic; | |
| var regEx = new RegExp( "\\b" + pname + "\\b", "g" ); | |
| switch ( semantic ) { | |
| case "POSITION": | |
| shaderText = shaderText.replace( regEx, 'position' ); | |
| break; | |
| case "NORMAL": | |
| shaderText = shaderText.replace( regEx, 'normal' ); | |
| break; | |
| case 'TEXCOORD_0': | |
| case 'TEXCOORD0': | |
| case 'TEXCOORD': | |
| shaderText = shaderText.replace( regEx, 'uv' ); | |
| break; | |
| case 'TEXCOORD_1': | |
| shaderText = shaderText.replace( regEx, 'uv2' ); | |
| break; | |
| case 'COLOR_0': | |
| case 'COLOR0': | |
| case 'COLOR': | |
| shaderText = shaderText.replace( regEx, 'color' ); | |
| break; | |
| case "WEIGHT": | |
| shaderText = shaderText.replace( regEx, 'skinWeight' ); | |
| break; | |
| case "JOINT": | |
| shaderText = shaderText.replace( regEx, 'skinIndex' ); | |
| break; | |
| } | |
| } | |
| return shaderText; | |
| } | |
| function createDefaultMaterial() { | |
| return new THREE.MeshPhongMaterial( { | |
| color: 0x00000, | |
| emissive: 0x888888, | |
| specular: 0x000000, | |
| shininess: 0, | |
| transparent: false, | |
| depthTest: true, | |
| side: THREE.FrontSide | |
| } ); | |
| } | |
| // Deferred constructor for RawShaderMaterial types | |
| function DeferredShaderMaterial( params ) { | |
| this.isDeferredShaderMaterial = true; | |
| this.params = params; | |
| } | |
| DeferredShaderMaterial.prototype.create = function () { | |
| var uniforms = THREE.UniformsUtils.clone( this.params.uniforms ); | |
| for ( var uniformId in this.params.uniforms ) { | |
| var originalUniform = this.params.uniforms[ uniformId ]; | |
| if ( originalUniform.value instanceof THREE.Texture ) { | |
| uniforms[ uniformId ].value = originalUniform.value; | |
| uniforms[ uniformId ].value.needsUpdate = true; | |
| } | |
| uniforms[ uniformId ].semantic = originalUniform.semantic; | |
| uniforms[ uniformId ].node = originalUniform.node; | |
| } | |
| this.params.uniforms = uniforms; | |
| return new THREE.RawShaderMaterial( this.params ); | |
| }; | |
| /* GLTF PARSER */ | |
| function GLTFParser( json, extensions, options ) { | |
| this.json = json || {}; | |
| this.extensions = extensions || {}; | |
| this.options = options || {}; | |
| // loader object cache | |
| this.cache = new GLTFRegistry(); | |
| } | |
| GLTFParser.prototype._withDependencies = function ( dependencies ) { | |
| var _dependencies = {}; | |
| for ( var i = 0; i < dependencies.length; i ++ ) { | |
| var dependency = dependencies[ i ]; | |
| var fnName = "load" + dependency.charAt( 0 ).toUpperCase() + dependency.slice( 1 ); | |
| var cached = this.cache.get( dependency ); | |
| if ( cached !== undefined ) { | |
| _dependencies[ dependency ] = cached; | |
| } else if ( this[ fnName ] ) { | |
| var fn = this[ fnName ](); | |
| this.cache.add( dependency, fn ); | |
| _dependencies[ dependency ] = fn; | |
| } | |
| } | |
| return _each( _dependencies, function ( dependency ) { | |
| return dependency; | |
| } ); | |
| }; | |
| GLTFParser.prototype.parse = function ( callback ) { | |
| var json = this.json; | |
| // Clear the loader cache | |
| this.cache.removeAll(); | |
| // Fire the callback on complete | |
| this._withDependencies( [ | |
| "scenes", | |
| "cameras", | |
| "animations" | |
| ] ).then( function ( dependencies ) { | |
| var scenes = []; | |
| for ( var name in dependencies.scenes ) { | |
| scenes.push( dependencies.scenes[ name ] ); | |
| } | |
| var scene = json.scene !== undefined ? dependencies.scenes[ json.scene ] : scenes[ 0 ]; | |
| var cameras = []; | |
| for ( var name in dependencies.cameras ) { | |
| var camera = dependencies.cameras[ name ]; | |
| cameras.push( camera ); | |
| } | |
| var animations = []; | |
| for ( var name in dependencies.animations ) { | |
| animations.push( dependencies.animations[ name ] ); | |
| } | |
| callback( scene, scenes, cameras, animations ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadShaders = function () { | |
| var json = this.json; | |
| var extensions = this.extensions; | |
| var options = this.options; | |
| return this._withDependencies( [ | |
| "bufferViews" | |
| ] ).then( function ( dependencies ) { | |
| return _each( json.shaders, function ( shader ) { | |
| if ( shader.extensions && shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) { | |
| return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadShader( shader, dependencies.bufferViews ); | |
| } | |
| return new Promise( function ( resolve ) { | |
| var loader = new THREE.FileLoader( options.manager ); | |
| loader.setResponseType( 'text' ); | |
| loader.load( resolveURL( shader.uri, options.path ), function ( shaderText ) { | |
| resolve( shaderText ); | |
| } ); | |
| } ); | |
| } ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadBuffers = function () { | |
| var json = this.json; | |
| var extensions = this.extensions; | |
| var options = this.options; | |
| return _each( json.buffers, function ( buffer, name ) { | |
| if ( name === BINARY_EXTENSION_BUFFER_NAME ) { | |
| return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body; | |
| } | |
| if ( buffer.type === 'arraybuffer' || buffer.type === undefined ) { | |
| return new Promise( function ( resolve ) { | |
| var loader = new THREE.FileLoader( options.manager ); | |
| loader.setResponseType( 'arraybuffer' ); | |
| loader.load( resolveURL( buffer.uri, options.path ), function ( buffer ) { | |
| resolve( buffer ); | |
| } ); | |
| } ); | |
| } else { | |
| console.warn( 'THREE.LegacyGLTFLoader: ' + buffer.type + ' buffer type is not supported' ); | |
| } | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadBufferViews = function () { | |
| var json = this.json; | |
| return this._withDependencies( [ | |
| "buffers" | |
| ] ).then( function ( dependencies ) { | |
| return _each( json.bufferViews, function ( bufferView ) { | |
| var arraybuffer = dependencies.buffers[ bufferView.buffer ]; | |
| var byteLength = bufferView.byteLength !== undefined ? bufferView.byteLength : 0; | |
| return arraybuffer.slice( bufferView.byteOffset, bufferView.byteOffset + byteLength ); | |
| } ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadAccessors = function () { | |
| var json = this.json; | |
| return this._withDependencies( [ | |
| "bufferViews" | |
| ] ).then( function ( dependencies ) { | |
| return _each( json.accessors, function ( accessor ) { | |
| var arraybuffer = dependencies.bufferViews[ accessor.bufferView ]; | |
| var itemSize = WEBGL_TYPE_SIZES[ accessor.type ]; | |
| var TypedArray = WEBGL_COMPONENT_TYPES[ accessor.componentType ]; | |
| // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12. | |
| var elementBytes = TypedArray.BYTES_PER_ELEMENT; | |
| var itemBytes = elementBytes * itemSize; | |
| // The buffer is not interleaved if the stride is the item size in bytes. | |
| if ( accessor.byteStride && accessor.byteStride !== itemBytes ) { | |
| // Use the full buffer if it's interleaved. | |
| var array = new TypedArray( arraybuffer ); | |
| // Integer parameters to IB/IBA are in array elements, not bytes. | |
| var ib = new THREE.InterleavedBuffer( array, accessor.byteStride / elementBytes ); | |
| return new THREE.InterleavedBufferAttribute( ib, itemSize, accessor.byteOffset / elementBytes ); | |
| } else { | |
| array = new TypedArray( arraybuffer, accessor.byteOffset, accessor.count * itemSize ); | |
| return new THREE.BufferAttribute( array, itemSize ); | |
| } | |
| } ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadTextures = function () { | |
| var json = this.json; | |
| var extensions = this.extensions; | |
| var options = this.options; | |
| return this._withDependencies( [ | |
| "bufferViews" | |
| ] ).then( function ( dependencies ) { | |
| return _each( json.textures, function ( texture ) { | |
| if ( texture.source ) { | |
| return new Promise( function ( resolve ) { | |
| var source = json.images[ texture.source ]; | |
| var sourceUri = source.uri; | |
| var isObjectURL = false; | |
| if ( source.extensions && source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) { | |
| var metadata = source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ]; | |
| var bufferView = dependencies.bufferViews[ metadata.bufferView ]; | |
| var blob = new Blob( [ bufferView ], { type: metadata.mimeType } ); | |
| sourceUri = URL.createObjectURL( blob ); | |
| isObjectURL = true; | |
| } | |
| var textureLoader = THREE.Loader.Handlers.get( sourceUri ); | |
| if ( textureLoader === null ) { | |
| textureLoader = new THREE.TextureLoader( options.manager ); | |
| } | |
| textureLoader.setCrossOrigin( options.crossOrigin ); | |
| textureLoader.load( resolveURL( sourceUri, options.path ), function ( _texture ) { | |
| if ( isObjectURL ) URL.revokeObjectURL( sourceUri ); | |
| _texture.flipY = false; | |
| if ( texture.name !== undefined ) _texture.name = texture.name; | |
| _texture.format = texture.format !== undefined ? WEBGL_TEXTURE_FORMATS[ texture.format ] : THREE.RGBAFormat; | |
| if ( texture.internalFormat !== undefined && _texture.format !== WEBGL_TEXTURE_FORMATS[ texture.internalFormat ] ) { | |
| console.warn( 'THREE.LegacyGLTFLoader: Three.js doesn\'t support texture internalFormat which is different from texture format. ' + | |
| 'internalFormat will be forced to be the same value as format.' ); | |
| } | |
| _texture.type = texture.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ texture.type ] : THREE.UnsignedByteType; | |
| if ( texture.sampler ) { | |
| var sampler = json.samplers[ texture.sampler ]; | |
| _texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter; | |
| _texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.NearestMipMapLinearFilter; | |
| _texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping; | |
| _texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping; | |
| } | |
| resolve( _texture ); | |
| }, undefined, function () { | |
| if ( isObjectURL ) URL.revokeObjectURL( sourceUri ); | |
| resolve(); | |
| } ); | |
| } ); | |
| } | |
| } ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadMaterials = function () { | |
| var json = this.json; | |
| return this._withDependencies( [ | |
| "shaders", | |
| "textures" | |
| ] ).then( function ( dependencies ) { | |
| return _each( json.materials, function ( material ) { | |
| var materialType; | |
| var materialValues = {}; | |
| var materialParams = {}; | |
| var khr_material; | |
| if ( material.extensions && material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) { | |
| khr_material = material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ]; | |
| } | |
| if ( khr_material ) { | |
| // don't copy over unused values to avoid material warning spam | |
| var keys = [ 'ambient', 'emission', 'transparent', 'transparency', 'doubleSided' ]; | |
| switch ( khr_material.technique ) { | |
| case 'BLINN' : | |
| case 'PHONG' : | |
| materialType = THREE.MeshPhongMaterial; | |
| keys.push( 'diffuse', 'specular', 'shininess' ); | |
| break; | |
| case 'LAMBERT' : | |
| materialType = THREE.MeshLambertMaterial; | |
| keys.push( 'diffuse' ); | |
| break; | |
| case 'CONSTANT' : | |
| default : | |
| materialType = THREE.MeshBasicMaterial; | |
| break; | |
| } | |
| keys.forEach( function ( v ) { | |
| if ( khr_material.values[ v ] !== undefined ) materialValues[ v ] = khr_material.values[ v ]; | |
| } ); | |
| if ( khr_material.doubleSided || materialValues.doubleSided ) { | |
| materialParams.side = THREE.DoubleSide; | |
| } | |
| if ( khr_material.transparent || materialValues.transparent ) { | |
| materialParams.transparent = true; | |
| materialParams.opacity = ( materialValues.transparency !== undefined ) ? materialValues.transparency : 1; | |
| } | |
| } else if ( material.technique === undefined ) { | |
| materialType = THREE.MeshPhongMaterial; | |
| Object.assign( materialValues, material.values ); | |
| } else { | |
| materialType = DeferredShaderMaterial; | |
| var technique = json.techniques[ material.technique ]; | |
| materialParams.uniforms = {}; | |
| var program = json.programs[ technique.program ]; | |
| if ( program ) { | |
| materialParams.fragmentShader = dependencies.shaders[ program.fragmentShader ]; | |
| if ( ! materialParams.fragmentShader ) { | |
| console.warn( "ERROR: Missing fragment shader definition:", program.fragmentShader ); | |
| materialType = THREE.MeshPhongMaterial; | |
| } | |
| var vertexShader = dependencies.shaders[ program.vertexShader ]; | |
| if ( ! vertexShader ) { | |
| console.warn( "ERROR: Missing vertex shader definition:", program.vertexShader ); | |
| materialType = THREE.MeshPhongMaterial; | |
| } | |
| // IMPORTANT: FIX VERTEX SHADER ATTRIBUTE DEFINITIONS | |
| materialParams.vertexShader = replaceTHREEShaderAttributes( vertexShader, technique ); | |
| var uniforms = technique.uniforms; | |
| for ( var uniformId in uniforms ) { | |
| var pname = uniforms[ uniformId ]; | |
| var shaderParam = technique.parameters[ pname ]; | |
| var ptype = shaderParam.type; | |
| if ( WEBGL_TYPE[ ptype ] ) { | |
| var pcount = shaderParam.count; | |
| var value; | |
| if ( material.values !== undefined ) value = material.values[ pname ]; | |
| var uvalue = new WEBGL_TYPE[ ptype ](); | |
| var usemantic = shaderParam.semantic; | |
| var unode = shaderParam.node; | |
| switch ( ptype ) { | |
| case WEBGL_CONSTANTS.FLOAT: | |
| uvalue = shaderParam.value; | |
| if ( pname == "transparency" ) { | |
| materialParams.transparent = true; | |
| } | |
| if ( value !== undefined ) { | |
| uvalue = value; | |
| } | |
| break; | |
| case WEBGL_CONSTANTS.FLOAT_VEC2: | |
| case WEBGL_CONSTANTS.FLOAT_VEC3: | |
| case WEBGL_CONSTANTS.FLOAT_VEC4: | |
| case WEBGL_CONSTANTS.FLOAT_MAT3: | |
| if ( shaderParam && shaderParam.value ) { | |
| uvalue.fromArray( shaderParam.value ); | |
| } | |
| if ( value ) { | |
| uvalue.fromArray( value ); | |
| } | |
| break; | |
| case WEBGL_CONSTANTS.FLOAT_MAT2: | |
| // what to do? | |
| console.warn( "FLOAT_MAT2 is not a supported uniform type" ); | |
| break; | |
| case WEBGL_CONSTANTS.FLOAT_MAT4: | |
| if ( pcount ) { | |
| uvalue = new Array( pcount ); | |
| for ( var mi = 0; mi < pcount; mi ++ ) { | |
| uvalue[ mi ] = new WEBGL_TYPE[ ptype ](); | |
| } | |
| if ( shaderParam && shaderParam.value ) { | |
| var m4v = shaderParam.value; | |
| uvalue.fromArray( m4v ); | |
| } | |
| if ( value ) { | |
| uvalue.fromArray( value ); | |
| } | |
| } else { | |
| if ( shaderParam && shaderParam.value ) { | |
| var m4 = shaderParam.value; | |
| uvalue.fromArray( m4 ); | |
| } | |
| if ( value ) { | |
| uvalue.fromArray( value ); | |
| } | |
| } | |
| break; | |
| case WEBGL_CONSTANTS.SAMPLER_2D: | |
| if ( value !== undefined ) { | |
| uvalue = dependencies.textures[ value ]; | |
| } else if ( shaderParam.value !== undefined ) { | |
| uvalue = dependencies.textures[ shaderParam.value ]; | |
| } else { | |
| uvalue = null; | |
| } | |
| break; | |
| } | |
| materialParams.uniforms[ uniformId ] = { | |
| value: uvalue, | |
| semantic: usemantic, | |
| node: unode | |
| }; | |
| } else { | |
| throw new Error( "Unknown shader uniform param type: " + ptype ); | |
| } | |
| } | |
| var states = technique.states || {}; | |
| var enables = states.enable || []; | |
| var functions = states.functions || {}; | |
| var enableCullFace = false; | |
| var enableDepthTest = false; | |
| var enableBlend = false; | |
| for ( var i = 0, il = enables.length; i < il; i ++ ) { | |
| var enable = enables[ i ]; | |
| switch ( STATES_ENABLES[ enable ] ) { | |
| case 'CULL_FACE': | |
| enableCullFace = true; | |
| break; | |
| case 'DEPTH_TEST': | |
| enableDepthTest = true; | |
| break; | |
| case 'BLEND': | |
| enableBlend = true; | |
| break; | |
| // TODO: implement | |
| case 'SCISSOR_TEST': | |
| case 'POLYGON_OFFSET_FILL': | |
| case 'SAMPLE_ALPHA_TO_COVERAGE': | |
| break; | |
| default: | |
| throw new Error( "Unknown technique.states.enable: " + enable ); | |
| } | |
| } | |
| if ( enableCullFace ) { | |
| materialParams.side = functions.cullFace !== undefined ? WEBGL_SIDES[ functions.cullFace ] : THREE.FrontSide; | |
| } else { | |
| materialParams.side = THREE.DoubleSide; | |
| } | |
| materialParams.depthTest = enableDepthTest; | |
| materialParams.depthFunc = functions.depthFunc !== undefined ? WEBGL_DEPTH_FUNCS[ functions.depthFunc ] : THREE.LessDepth; | |
| materialParams.depthWrite = functions.depthMask !== undefined ? functions.depthMask[ 0 ] : true; | |
| materialParams.blending = enableBlend ? THREE.CustomBlending : THREE.NoBlending; | |
| materialParams.transparent = enableBlend; | |
| var blendEquationSeparate = functions.blendEquationSeparate; | |
| if ( blendEquationSeparate !== undefined ) { | |
| materialParams.blendEquation = WEBGL_BLEND_EQUATIONS[ blendEquationSeparate[ 0 ] ]; | |
| materialParams.blendEquationAlpha = WEBGL_BLEND_EQUATIONS[ blendEquationSeparate[ 1 ] ]; | |
| } else { | |
| materialParams.blendEquation = THREE.AddEquation; | |
| materialParams.blendEquationAlpha = THREE.AddEquation; | |
| } | |
| var blendFuncSeparate = functions.blendFuncSeparate; | |
| if ( blendFuncSeparate !== undefined ) { | |
| materialParams.blendSrc = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 0 ] ]; | |
| materialParams.blendDst = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 1 ] ]; | |
| materialParams.blendSrcAlpha = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 2 ] ]; | |
| materialParams.blendDstAlpha = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 3 ] ]; | |
| } else { | |
| materialParams.blendSrc = THREE.OneFactor; | |
| materialParams.blendDst = THREE.ZeroFactor; | |
| materialParams.blendSrcAlpha = THREE.OneFactor; | |
| materialParams.blendDstAlpha = THREE.ZeroFactor; | |
| } | |
| } | |
| } | |
| if ( Array.isArray( materialValues.diffuse ) ) { | |
| materialParams.color = new THREE.Color().fromArray( materialValues.diffuse ); | |
| } else if ( typeof ( materialValues.diffuse ) === 'string' ) { | |
| materialParams.map = dependencies.textures[ materialValues.diffuse ]; | |
| } | |
| delete materialParams.diffuse; | |
| if ( typeof ( materialValues.reflective ) === 'string' ) { | |
| materialParams.envMap = dependencies.textures[ materialValues.reflective ]; | |
| } | |
| if ( typeof ( materialValues.bump ) === 'string' ) { | |
| materialParams.bumpMap = dependencies.textures[ materialValues.bump ]; | |
| } | |
| if ( Array.isArray( materialValues.emission ) ) { | |
| if ( materialType === THREE.MeshBasicMaterial ) { | |
| materialParams.color = new THREE.Color().fromArray( materialValues.emission ); | |
| } else { | |
| materialParams.emissive = new THREE.Color().fromArray( materialValues.emission ); | |
| } | |
| } else if ( typeof ( materialValues.emission ) === 'string' ) { | |
| if ( materialType === THREE.MeshBasicMaterial ) { | |
| materialParams.map = dependencies.textures[ materialValues.emission ]; | |
| } else { | |
| materialParams.emissiveMap = dependencies.textures[ materialValues.emission ]; | |
| } | |
| } | |
| if ( Array.isArray( materialValues.specular ) ) { | |
| materialParams.specular = new THREE.Color().fromArray( materialValues.specular ); | |
| } else if ( typeof ( materialValues.specular ) === 'string' ) { | |
| materialParams.specularMap = dependencies.textures[ materialValues.specular ]; | |
| } | |
| if ( materialValues.shininess !== undefined ) { | |
| materialParams.shininess = materialValues.shininess; | |
| } | |
| var _material = new materialType( materialParams ); | |
| if ( material.name !== undefined ) _material.name = material.name; | |
| return _material; | |
| } ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadMeshes = function () { | |
| var json = this.json; | |
| return this._withDependencies( [ | |
| "accessors", | |
| "materials" | |
| ] ).then( function ( dependencies ) { | |
| return _each( json.meshes, function ( mesh ) { | |
| var group = new THREE.Group(); | |
| if ( mesh.name !== undefined ) group.name = mesh.name; | |
| if ( mesh.extras ) group.userData = mesh.extras; | |
| var primitives = mesh.primitives || []; | |
| for ( var name in primitives ) { | |
| var primitive = primitives[ name ]; | |
| if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) { | |
| var geometry = new THREE.BufferGeometry(); | |
| var attributes = primitive.attributes; | |
| for ( var attributeId in attributes ) { | |
| var attributeEntry = attributes[ attributeId ]; | |
| if ( ! attributeEntry ) return; | |
| var bufferAttribute = dependencies.accessors[ attributeEntry ]; | |
| switch ( attributeId ) { | |
| case 'POSITION': | |
| geometry.addAttribute( 'position', bufferAttribute ); | |
| break; | |
| case 'NORMAL': | |
| geometry.addAttribute( 'normal', bufferAttribute ); | |
| break; | |
| case 'TEXCOORD_0': | |
| case 'TEXCOORD0': | |
| case 'TEXCOORD': | |
| geometry.addAttribute( 'uv', bufferAttribute ); | |
| break; | |
| case 'TEXCOORD_1': | |
| geometry.addAttribute( 'uv2', bufferAttribute ); | |
| break; | |
| case 'COLOR_0': | |
| case 'COLOR0': | |
| case 'COLOR': | |
| geometry.addAttribute( 'color', bufferAttribute ); | |
| break; | |
| case 'WEIGHT': | |
| geometry.addAttribute( 'skinWeight', bufferAttribute ); | |
| break; | |
| case 'JOINT': | |
| geometry.addAttribute( 'skinIndex', bufferAttribute ); | |
| break; | |
| default: | |
| if ( ! primitive.material ) break; | |
| var material = json.materials[ primitive.material ]; | |
| if ( ! material.technique ) break; | |
| var parameters = json.techniques[ material.technique ].parameters || {}; | |
| for ( var attributeName in parameters ) { | |
| if ( parameters[ attributeName ][ 'semantic' ] === attributeId ) { | |
| geometry.addAttribute( attributeName, bufferAttribute ); | |
| } | |
| } | |
| } | |
| } | |
| if ( primitive.indices ) { | |
| geometry.setIndex( dependencies.accessors[ primitive.indices ] ); | |
| } | |
| var material = dependencies.materials !== undefined ? dependencies.materials[ primitive.material ] : createDefaultMaterial(); | |
| var meshNode = new THREE.Mesh( geometry, material ); | |
| meshNode.castShadow = true; | |
| meshNode.name = ( name === "0" ? group.name : group.name + name ); | |
| if ( primitive.extras ) meshNode.userData = primitive.extras; | |
| group.add( meshNode ); | |
| } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) { | |
| var geometry = new THREE.BufferGeometry(); | |
| var attributes = primitive.attributes; | |
| for ( var attributeId in attributes ) { | |
| var attributeEntry = attributes[ attributeId ]; | |
| if ( ! attributeEntry ) return; | |
| var bufferAttribute = dependencies.accessors[ attributeEntry ]; | |
| switch ( attributeId ) { | |
| case 'POSITION': | |
| geometry.addAttribute( 'position', bufferAttribute ); | |
| break; | |
| case 'COLOR_0': | |
| case 'COLOR0': | |
| case 'COLOR': | |
| geometry.addAttribute( 'color', bufferAttribute ); | |
| break; | |
| } | |
| } | |
| var material = dependencies.materials[ primitive.material ]; | |
| var meshNode; | |
| if ( primitive.indices ) { | |
| geometry.setIndex( dependencies.accessors[ primitive.indices ] ); | |
| meshNode = new THREE.LineSegments( geometry, material ); | |
| } else { | |
| meshNode = new THREE.Line( geometry, material ); | |
| } | |
| meshNode.name = ( name === "0" ? group.name : group.name + name ); | |
| if ( primitive.extras ) meshNode.userData = primitive.extras; | |
| group.add( meshNode ); | |
| } else { | |
| console.warn( "Only triangular and line primitives are supported" ); | |
| } | |
| } | |
| return group; | |
| } ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadCameras = function () { | |
| var json = this.json; | |
| return _each( json.cameras, function ( camera ) { | |
| if ( camera.type == "perspective" && camera.perspective ) { | |
| var yfov = camera.perspective.yfov; | |
| var aspectRatio = camera.perspective.aspectRatio !== undefined ? camera.perspective.aspectRatio : 1; | |
| // According to COLLADA spec... | |
| // aspectRatio = xfov / yfov | |
| var xfov = yfov * aspectRatio; | |
| var _camera = new THREE.PerspectiveCamera( THREE.Math.radToDeg( xfov ), aspectRatio, camera.perspective.znear || 1, camera.perspective.zfar || 2e6 ); | |
| if ( camera.name !== undefined ) _camera.name = camera.name; | |
| if ( camera.extras ) _camera.userData = camera.extras; | |
| return _camera; | |
| } else if ( camera.type == "orthographic" && camera.orthographic ) { | |
| var _camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, camera.orthographic.znear, camera.orthographic.zfar ); | |
| if ( camera.name !== undefined ) _camera.name = camera.name; | |
| if ( camera.extras ) _camera.userData = camera.extras; | |
| return _camera; | |
| } | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadSkins = function () { | |
| var json = this.json; | |
| return this._withDependencies( [ | |
| "accessors" | |
| ] ).then( function ( dependencies ) { | |
| return _each( json.skins, function ( skin ) { | |
| var bindShapeMatrix = new THREE.Matrix4(); | |
| if ( skin.bindShapeMatrix !== undefined ) bindShapeMatrix.fromArray( skin.bindShapeMatrix ); | |
| var _skin = { | |
| bindShapeMatrix: bindShapeMatrix, | |
| jointNames: skin.jointNames, | |
| inverseBindMatrices: dependencies.accessors[ skin.inverseBindMatrices ] | |
| }; | |
| return _skin; | |
| } ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadAnimations = function () { | |
| var json = this.json; | |
| return this._withDependencies( [ | |
| "accessors", | |
| "nodes" | |
| ] ).then( function ( dependencies ) { | |
| return _each( json.animations, function ( animation, animationId ) { | |
| var tracks = []; | |
| for ( var channelId in animation.channels ) { | |
| var channel = animation.channels[ channelId ]; | |
| var sampler = animation.samplers[ channel.sampler ]; | |
| if ( sampler ) { | |
| var target = channel.target; | |
| var name = target.id; | |
| var input = animation.parameters !== undefined ? animation.parameters[ sampler.input ] : sampler.input; | |
| var output = animation.parameters !== undefined ? animation.parameters[ sampler.output ] : sampler.output; | |
| var inputAccessor = dependencies.accessors[ input ]; | |
| var outputAccessor = dependencies.accessors[ output ]; | |
| var node = dependencies.nodes[ name ]; | |
| if ( node ) { | |
| node.updateMatrix(); | |
| node.matrixAutoUpdate = true; | |
| var TypedKeyframeTrack = PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.rotation | |
| ? THREE.QuaternionKeyframeTrack | |
| : THREE.VectorKeyframeTrack; | |
| var targetName = node.name ? node.name : node.uuid; | |
| var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : THREE.InterpolateLinear; | |
| // KeyframeTrack.optimize() will modify given 'times' and 'values' | |
| // buffers before creating a truncated copy to keep. Because buffers may | |
| // be reused by other tracks, make copies here. | |
| tracks.push( new TypedKeyframeTrack( | |
| targetName + '.' + PATH_PROPERTIES[ target.path ], | |
| THREE.AnimationUtils.arraySlice( inputAccessor.array, 0 ), | |
| THREE.AnimationUtils.arraySlice( outputAccessor.array, 0 ), | |
| interpolation | |
| ) ); | |
| } | |
| } | |
| } | |
| var name = animation.name !== undefined ? animation.name : "animation_" + animationId; | |
| return new THREE.AnimationClip( name, undefined, tracks ); | |
| } ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadNodes = function () { | |
| var json = this.json; | |
| var extensions = this.extensions; | |
| var scope = this; | |
| return _each( json.nodes, function ( node ) { | |
| var matrix = new THREE.Matrix4(); | |
| var _node; | |
| if ( node.jointName ) { | |
| _node = new THREE.Bone(); | |
| _node.name = node.name !== undefined ? node.name : node.jointName; | |
| _node.jointName = node.jointName; | |
| } else { | |
| _node = new THREE.Object3D(); | |
| if ( node.name !== undefined ) _node.name = node.name; | |
| } | |
| if ( node.extras ) _node.userData = node.extras; | |
| if ( node.matrix !== undefined ) { | |
| matrix.fromArray( node.matrix ); | |
| _node.applyMatrix( matrix ); | |
| } else { | |
| if ( node.translation !== undefined ) { | |
| _node.position.fromArray( node.translation ); | |
| } | |
| if ( node.rotation !== undefined ) { | |
| _node.quaternion.fromArray( node.rotation ); | |
| } | |
| if ( node.scale !== undefined ) { | |
| _node.scale.fromArray( node.scale ); | |
| } | |
| } | |
| return _node; | |
| } ).then( function ( __nodes ) { | |
| return scope._withDependencies( [ | |
| "meshes", | |
| "skins", | |
| "cameras" | |
| ] ).then( function ( dependencies ) { | |
| return _each( __nodes, function ( _node, nodeId ) { | |
| var node = json.nodes[ nodeId ]; | |
| if ( node.meshes !== undefined ) { | |
| for ( var meshId in node.meshes ) { | |
| var mesh = node.meshes[ meshId ]; | |
| var group = dependencies.meshes[ mesh ]; | |
| if ( group === undefined ) { | |
| console.warn( 'LegacyGLTFLoader: Couldn\'t find node "' + mesh + '".' ); | |
| continue; | |
| } | |
| for ( var childrenId in group.children ) { | |
| var child = group.children[ childrenId ]; | |
| // clone Mesh to add to _node | |
| var originalMaterial = child.material; | |
| var originalGeometry = child.geometry; | |
| var originalUserData = child.userData; | |
| var originalName = child.name; | |
| var material; | |
| if ( originalMaterial.isDeferredShaderMaterial ) { | |
| originalMaterial = material = originalMaterial.create(); | |
| } else { | |
| material = originalMaterial; | |
| } | |
| switch ( child.type ) { | |
| case 'LineSegments': | |
| child = new THREE.LineSegments( originalGeometry, material ); | |
| break; | |
| case 'LineLoop': | |
| child = new THREE.LineLoop( originalGeometry, material ); | |
| break; | |
| case 'Line': | |
| child = new THREE.Line( originalGeometry, material ); | |
| break; | |
| default: | |
| child = new THREE.Mesh( originalGeometry, material ); | |
| } | |
| child.castShadow = true; | |
| child.userData = originalUserData; | |
| child.name = originalName; | |
| var skinEntry; | |
| if ( node.skin ) { | |
| skinEntry = dependencies.skins[ node.skin ]; | |
| } | |
| // Replace Mesh with SkinnedMesh in library | |
| if ( skinEntry ) { | |
| var getJointNode = function ( jointId ) { | |
| var keys = Object.keys( __nodes ); | |
| for ( var i = 0, il = keys.length; i < il; i ++ ) { | |
| var n = __nodes[ keys[ i ] ]; | |
| if ( n.jointName === jointId ) return n; | |
| } | |
| return null; | |
| }; | |
| var geometry = originalGeometry; | |
| var material = originalMaterial; | |
| material.skinning = true; | |
| child = new THREE.SkinnedMesh( geometry, material ); | |
| child.castShadow = true; | |
| child.userData = originalUserData; | |
| child.name = originalName; | |
| var bones = []; | |
| var boneInverses = []; | |
| for ( var i = 0, l = skinEntry.jointNames.length; i < l; i ++ ) { | |
| var jointId = skinEntry.jointNames[ i ]; | |
| var jointNode = getJointNode( jointId ); | |
| if ( jointNode ) { | |
| bones.push( jointNode ); | |
| var m = skinEntry.inverseBindMatrices.array; | |
| var mat = new THREE.Matrix4().fromArray( m, i * 16 ); | |
| boneInverses.push( mat ); | |
| } else { | |
| console.warn( "WARNING: joint: '" + jointId + "' could not be found" ); | |
| } | |
| } | |
| child.bind( new THREE.Skeleton( bones, boneInverses ), skinEntry.bindShapeMatrix ); | |
| var buildBoneGraph = function ( parentJson, parentObject, property ) { | |
| var children = parentJson[ property ]; | |
| if ( children === undefined ) return; | |
| for ( var i = 0, il = children.length; i < il; i ++ ) { | |
| var nodeId = children[ i ]; | |
| var bone = __nodes[ nodeId ]; | |
| var boneJson = json.nodes[ nodeId ]; | |
| if ( bone !== undefined && bone.isBone === true && boneJson !== undefined ) { | |
| parentObject.add( bone ); | |
| buildBoneGraph( boneJson, bone, 'children' ); | |
| } | |
| } | |
| }; | |
| buildBoneGraph( node, child, 'skeletons' ); | |
| } | |
| _node.add( child ); | |
| } | |
| } | |
| } | |
| if ( node.camera !== undefined ) { | |
| var camera = dependencies.cameras[ node.camera ]; | |
| _node.add( camera ); | |
| } | |
| if ( node.extensions | |
| && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] | |
| && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ) { | |
| var extensionLights = extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].lights; | |
| var light = extensionLights[ node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ]; | |
| _node.add( light ); | |
| } | |
| return _node; | |
| } ); | |
| } ); | |
| } ); | |
| }; | |
| GLTFParser.prototype.loadScenes = function () { | |
| var json = this.json; | |
| // scene node hierachy builder | |
| function buildNodeHierachy( nodeId, parentObject, allNodes ) { | |
| var _node = allNodes[ nodeId ]; | |
| parentObject.add( _node ); | |
| var node = json.nodes[ nodeId ]; | |
| if ( node.children ) { | |
| var children = node.children; | |
| for ( var i = 0, l = children.length; i < l; i ++ ) { | |
| var child = children[ i ]; | |
| buildNodeHierachy( child, _node, allNodes ); | |
| } | |
| } | |
| } | |
| return this._withDependencies( [ | |
| "nodes" | |
| ] ).then( function ( dependencies ) { | |
| return _each( json.scenes, function ( scene ) { | |
| var _scene = new THREE.Scene(); | |
| if ( scene.name !== undefined ) _scene.name = scene.name; | |
| if ( scene.extras ) _scene.userData = scene.extras; | |
| var nodes = scene.nodes || []; | |
| for ( var i = 0, l = nodes.length; i < l; i ++ ) { | |
| var nodeId = nodes[ i ]; | |
| buildNodeHierachy( nodeId, _scene, dependencies.nodes ); | |
| } | |
| _scene.traverse( function ( child ) { | |
| // Register raw material meshes with LegacyGLTFLoader.Shaders | |
| if ( child.material && child.material.isRawShaderMaterial ) { | |
| child.gltfShader = new GLTFShader( child, dependencies.nodes ); | |
| child.onBeforeRender = function ( renderer, scene, camera ) { | |
| this.gltfShader.update( scene, camera ); | |
| }; | |
| } | |
| } ); | |
| return _scene; | |
| } ); | |
| } ); | |
| }; | |
| return LegacyGLTFLoader; | |
| } )(); | |