写在前面

Three中的加载脚本很多,但是核心思想是差不多的,就是文件用文件解析器加载,图片用图片解析器加载,然后json转换为对象,但是由于gltf格式可以自己编辑所以有的源码参考意义不大,glb及拓展材质都没用上就还没有翻译,以后可能会补上。

源码位置

  • 该源码位置在three.js源码examples\js\loaders文件夹下

源码翻译

/*** @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* @author Don McCurdy / https://www.donmccurdy.com*/
/** 本文档为Three.js翻译文档,如有任何疑问请联系:* dreameng1997@163.com*/
THREE.GLTFLoader = (function () {/*** @description GLTF的加载文件* @date 2019-04-16* @param {*} manager 加载管理器*/function GLTFLoader(manager) {//新建一个加载管理器this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager;//设置点云加载器为空,接收draco文件的this.dracoLoader = null;}GLTFLoader.prototype = {constructor: GLTFLoader,crossOrigin: 'anonymous',/*** @description gltf加载方法* @date 2019-04-17* @param {*} url url的地址* @param {*} onLoad  加载方法* @param {*} onProgress    加载过程中调用的方法* @param {*} onError 加载失败调用的方法*/load: function (url, onLoad, onProgress, onError) {//获得this  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);}// Tells the LoadingManager to track an extra item, which resolves after// the model is fully loaded. This means the count of items loaded will// be incorrect, but ensures manager.onLoad() does not fire early.//加载管理器开始监听urlscope.manager.itemStart(url);//加载失败的方法var _onError = function (e) {if (onError) {onError(e);} else {console.error(e);}scope.manager.itemError(url);scope.manager.itemEnd(url);};//新建一个文件加载器var loader = new THREE.FileLoader(scope.manager);//设置路径loader.setPath(this.path);//设置响应类型,响应类型在FileLoader有写loader.setResponseType('arraybuffer');//开始加载资源,有两个参数,一个是url一个是加载成功的数据方法loader.load(url, function (data) {try {//尝试去加载资源scope.parse(data, resourcePath, function (gltf) {//返回的gltf是可以直接导入到场景的gltfonLoad(gltf);//结束管理器的监听scope.manager.itemEnd(url);}, _onError);} catch (e) {_onError(e);}}, onProgress, _onError);},/*** @description 应该是设置gltf的类型* @date 2019-04-17* @param {*} value* @returns */setCrossOrigin: function (value) {this.crossOrigin = value;return this;},/*** @description 设置路径* @date 2019-04-17* @param {*} value* @returns */setPath: function (value) {this.path = value;return this;},/*** @description 设置资源路径,这个和上一个的区别是上一个可以是一个相对路径,这个是绝对路径* @date 2019-04-17* @param {*} value* @returns */setResourcePath: function (value) {this.resourcePath = value;return this;},/*** @description 设置DRACO文件的加载器* @date 2019-04-17* @param {*} dracoLoader* @returns */setDRACOLoader: function (dracoLoader) {this.dracoLoader = dracoLoader;return this;},/*** @description 加载成功的分析方法* @date 2019-04-17* @param {*} data 加载出来的数据,对于模型来说,一般为arrayBuffer类型的* @param {*} path 加载路径* @param {*} onLoad   加载成功方法* @param {*} onError 加载失败方法* @returns */parse: function (data, path, onLoad, onError) {//新建内容变量和拓展变量数组var content;var extensions = {};//判断data类型如果是string类型的直接赋值if (typeof data === 'string') {content = data;} else {//如果不是string类型,首先取出前四个判断是不是:"{"var magic = THREE.LoaderUtils.decodeText(new Uint8Array(data, 0, 4));//如果前四个是gltf,应该是glb格式的二进制文件,获得具体的数据if (magic === BINARY_EXTENSION_HEADER_MAGIC) {try {extensions[EXTENSIONS.KHR_BINARY_GLTF] = new GLTFBinaryExtension(data);} catch (error) {if (onError) onError(error);return;}content = extensions[EXTENSIONS.KHR_BINARY_GLTF].content;} else {//如果是正常的gltf就转换类型content = THREE.LoaderUtils.decodeText(new Uint8Array(data));}}//转换为json格式var json = JSON.parse(content);//各个gltf不一样,以下的格式加载就不属于模型的范畴了,加载的东西也是千奇百怪,不具体翻译了,可以对照THREE的gltf对照的看if (json.asset === undefined || json.asset.version[0] < 2) {if (onError) onError(new Error('THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported. Use LegacyGLTFLoader instead.'));return;}if (json.extensionsUsed) {for (var i = 0; i < json.extensionsUsed.length; ++i) {var extensionName = json.extensionsUsed[i];var extensionsRequired = json.extensionsRequired || [];switch (extensionName) {case EXTENSIONS.KHR_LIGHTS_PUNCTUAL:extensions[extensionName] = new GLTFLightsExtension(json);break;case EXTENSIONS.KHR_MATERIALS_UNLIT:extensions[extensionName] = new GLTFMaterialsUnlitExtension(json);break;case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:extensions[extensionName] = new GLTFMaterialsPbrSpecularGlossinessExtension(json);break;case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:extensions[extensionName] = new GLTFDracoMeshCompressionExtension(json, this.dracoLoader);break;case EXTENSIONS.MSFT_TEXTURE_DDS:extensions[EXTENSIONS.MSFT_TEXTURE_DDS] = new GLTFTextureDDSExtension();break;case EXTENSIONS.KHR_TEXTURE_TRANSFORM:extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM] = new GLTFTextureTransformExtension(json);break;default:if (extensionsRequired.indexOf(extensionName) >= 0) {console.warn('THREE.GLTFLoader: Unknown extension "' + extensionName + '".');}}}}var parser = new GLTFParser(json, extensions, {path: path || this.resourcePath || '',crossOrigin: this.crossOrigin,manager: this.manager});parser.parse(function (scene, scenes, cameras, animations, json) {var glTF = {scene: scene,scenes: scenes,cameras: cameras,animations: animations,asset: json.asset,parser: parser,userData: {}};addUnknownExtensionsToUserData(extensions, glTF, json);onLoad(glTF);}, onError);}};/* GLTFREGISTRY *//*** @description 创建一个在缓存中的注册函数* @date 2019-04-17* @returns */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 = {};}};}/*********************************//********** EXTENSIONS ***********//*********************************/var EXTENSIONS = {KHR_BINARY_GLTF: 'KHR_binary_glTF',KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',MSFT_TEXTURE_DDS: 'MSFT_texture_dds'};/*** DDS Texture Extension** Specification:* https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds**//*** @description dds图片的拓展* @date 2019-04-17*/function GLTFTextureDDSExtension() {if (!THREE.DDSLoader) {throw new Error('THREE.GLTFLoader: Attempting to load .dds texture without importing THREE.DDSLoader');}this.name = EXTENSIONS.MSFT_TEXTURE_DDS;this.ddsLoader = new THREE.DDSLoader();}/*** Lights Extension** Specification: PENDING*//*** @description 灯光的拓展,及获取* @date 2019-04-17* @param {*} json*/function GLTFLightsExtension(json) {this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL;var extension = (json.extensions && json.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL]) || {};this.lightDefs = extension.lights || [];}/*** @description 加载灯光* @date 2019-04-17* @param {*} lightIndex 灯光的下标*/GLTFLightsExtension.prototype.loadLight = function (lightIndex) {var lightDef = this.lightDefs[lightIndex];var lightNode;var color = new THREE.Color(0xffffff);if (lightDef.color !== undefined) color.fromArray(lightDef.color);var range = lightDef.range !== undefined ? lightDef.range : 0;switch (lightDef.type) {case 'directional':lightNode = new THREE.DirectionalLight(color);lightNode.target.position.set(0, 0, -1);lightNode.add(lightNode.target);break;case 'point':lightNode = new THREE.PointLight(color);lightNode.distance = range;break;case 'spot':lightNode = new THREE.SpotLight(color);lightNode.distance = range;// Handle spotlight properties.lightDef.spot = lightDef.spot || {};lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0;lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0;lightNode.angle = lightDef.spot.outerConeAngle;lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle;lightNode.target.position.set(0, 0, -1);lightNode.add(lightNode.target);break;default:throw new Error('THREE.GLTFLoader: Unexpected light type, "' + lightDef.type + '".');}// Some lights (e.g. spot) default to a position other than the origin. Reset the position// here, because node-level parsing will only override position if explicitly specified.lightNode.position.set(0, 0, 0);lightNode.decay = 2;if (lightDef.intensity !== undefined) lightNode.intensity = lightDef.intensity;lightNode.name = lightDef.name || ('light_' + lightIndex);return Promise.resolve(lightNode);};/*** Unlit Materials Extension (pending)** PR: https://github.com/KhronosGroup/glTF/pull/1163*/function GLTFMaterialsUnlitExtension(json) {this.name = EXTENSIONS.KHR_MATERIALS_UNLIT;}GLTFMaterialsUnlitExtension.prototype.getMaterialType = function (material) {return THREE.MeshBasicMaterial;};GLTFMaterialsUnlitExtension.prototype.extendParams = function (materialParams, material, parser) {var pending = [];materialParams.color = new THREE.Color(1.0, 1.0, 1.0);materialParams.opacity = 1.0;var metallicRoughness = material.pbrMetallicRoughness;if (metallicRoughness) {if (Array.isArray(metallicRoughness.baseColorFactor)) {var array = metallicRoughness.baseColorFactor;materialParams.color.fromArray(array);materialParams.opacity = array[3];}if (metallicRoughness.baseColorTexture !== undefined) {pending.push(parser.assignTexture(materialParams, 'map', metallicRoughness.baseColorTexture));}}return Promise.all(pending);};/* BINARY EXTENSION */var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';var BINARY_EXTENSION_HEADER_LENGTH = 12;var BINARY_EXTENSION_CHUNK_TYPES = {JSON: 0x4E4F534A,BIN: 0x004E4942};/*** @description 加载二进制gltf格式的文件* @date 2019-04-17* @param {*} data 获得到数据*/function GLTFBinaryExtension(data) {//设置名字为gltf二进制文件this.name = EXTENSIONS.KHR_BINARY_GLTF;//创建内容this.content = null;//this.body = null;//获得首视图,获得前12个字符组成的类型视图。var headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH);//获得头标识,不同的gltf会有不同的处理这里以three的为例this.header = {magic: THREE.LoaderUtils.decodeText(new Uint8Array(data.slice(0, 4))),version: headerView.getUint32(4, true),length: headerView.getUint32(8, true)};if (this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC) {throw new Error('THREE.GLTFLoader: Unsupported glTF-Binary header.');} else if (this.header.version < 2.0) {throw new Error('THREE.GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.');}//这块每个gltf都不太一样,不具体翻译了var chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH);var chunkIndex = 0;//取数据while (chunkIndex < chunkView.byteLength) {var chunkLength = chunkView.getUint32(chunkIndex, true);chunkIndex += 4;var chunkType = chunkView.getUint32(chunkIndex, true);chunkIndex += 4;if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) {var contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength);this.content = THREE.LoaderUtils.decodeText(contentArray);} else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) {var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;this.body = data.slice(byteOffset, byteOffset + chunkLength);}// Clients must ignore chunks with unknown types.chunkIndex += chunkLength;}if (this.content === null) {throw new Error('THREE.GLTFLoader: JSON content not found.');}}/*** DRACO Mesh Compression Extension** Specification: https://github.com/KhronosGroup/glTF/pull/874*/function GLTFDracoMeshCompressionExtension(json, dracoLoader) {if (!dracoLoader) {throw new Error('THREE.GLTFLoader: No DRACOLoader instance provided.');}this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION;this.json = json;this.dracoLoader = dracoLoader;THREE.DRACOLoader.getDecoderModule();}GLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function (primitive, parser) {var json = this.json;var dracoLoader = this.dracoLoader;var bufferViewIndex = primitive.extensions[this.name].bufferView;var gltfAttributeMap = primitive.extensions[this.name].attributes;var threeAttributeMap = {};var attributeNormalizedMap = {};var attributeTypeMap = {};for (var attributeName in gltfAttributeMap) {if (!(attributeName in ATTRIBUTES)) continue;threeAttributeMap[ATTRIBUTES[attributeName]] = gltfAttributeMap[attributeName];}for (attributeName in primitive.attributes) {if (ATTRIBUTES[attributeName] !== undefined && gltfAttributeMap[attributeName] !== undefined) {var accessorDef = json.accessors[primitive.attributes[attributeName]];var componentType = WEBGL_COMPONENT_TYPES[accessorDef.componentType];attributeTypeMap[ATTRIBUTES[attributeName]] = componentType;attributeNormalizedMap[ATTRIBUTES[attributeName]] = accessorDef.normalized === true;}}return parser.getDependency('bufferView', bufferViewIndex).then(function (bufferView) {return new Promise(function (resolve) {dracoLoader.decodeDracoFile(bufferView, function (geometry) {for (var attributeName in geometry.attributes) {var attribute = geometry.attributes[attributeName];var normalized = attributeNormalizedMap[attributeName];if (normalized !== undefined) attribute.normalized = normalized;}resolve(geometry);}, threeAttributeMap, attributeTypeMap);});});};/*** Texture Transform Extension** Specification:*/function GLTFTextureTransformExtension(json) {this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM;}GLTFTextureTransformExtension.prototype.extendTexture = function (texture, transform) {texture = texture.clone();if (transform.offset !== undefined) {texture.offset.fromArray(transform.offset);}if (transform.rotation !== undefined) {texture.rotation = transform.rotation;}if (transform.scale !== undefined) {texture.repeat.fromArray(transform.scale);}if (transform.texCoord !== undefined) {console.warn('THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.');}texture.needsUpdate = true;return texture;};/*** Specular-Glossiness Extension* * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness*//*** @description 拓展材质的shader啥的* @date 2019-04-17* @returns */function GLTFMaterialsPbrSpecularGlossinessExtension() {return {name: EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS,specularGlossinessParams: ['color','map','lightMap','lightMapIntensity','aoMap','aoMapIntensity','emissive','emissiveIntensity','emissiveMap','bumpMap','bumpScale','normalMap','displacementMap','displacementScale','displacementBias','specularMap','specular','glossinessMap','glossiness','alphaMap','envMap','envMapIntensity','refractionRatio',],getMaterialType: function () {return THREE.ShaderMaterial;},extendParams: function (params, material, parser) {var pbrSpecularGlossiness = material.extensions[this.name];var shader = THREE.ShaderLib['standard'];var uniforms = THREE.UniformsUtils.clone(shader.uniforms);var specularMapParsFragmentChunk = ['#ifdef USE_SPECULARMAP',' uniform sampler2D specularMap;','#endif'].join('\n');var glossinessMapParsFragmentChunk = ['#ifdef USE_GLOSSINESSMAP','    uniform sampler2D glossinessMap;','#endif'].join('\n');var specularMapFragmentChunk = ['vec3 specularFactor = specular;','#ifdef USE_SPECULARMAP',' vec4 texelSpecular = texture2D( specularMap, vUv );','   texelSpecular = sRGBToLinear( texelSpecular );','    // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture','    specularFactor *= texelSpecular.rgb;','#endif'].join('\n');var glossinessMapFragmentChunk = ['float glossinessFactor = glossiness;','#ifdef USE_GLOSSINESSMAP','   vec4 texelGlossiness = texture2D( glossinessMap, vUv );','   // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture','  glossinessFactor *= texelGlossiness.a;','#endif'].join('\n');var lightPhysicalFragmentChunk = ['PhysicalMaterial material;','material.diffuseColor = diffuseColor.rgb;','material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );','material.specularColor = specularFactor.rgb;',].join('\n');var fragmentShader = shader.fragmentShader.replace('uniform float roughness;', 'uniform vec3 specular;').replace('uniform float metalness;', 'uniform float glossiness;').replace('#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk).replace('#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk).replace('#include <roughnessmap_fragment>', specularMapFragmentChunk).replace('#include <metalnessmap_fragment>', glossinessMapFragmentChunk).replace('#include <lights_physical_fragment>', lightPhysicalFragmentChunk);delete uniforms.roughness;delete uniforms.metalness;delete uniforms.roughnessMap;delete uniforms.metalnessMap;uniforms.specular = {value: new THREE.Color().setHex(0x111111)};uniforms.glossiness = {value: 0.5};uniforms.specularMap = {value: null};uniforms.glossinessMap = {value: null};params.vertexShader = shader.vertexShader;params.fragmentShader = fragmentShader;params.uniforms = uniforms;params.defines = {'STANDARD': ''};params.color = new THREE.Color(1.0, 1.0, 1.0);params.opacity = 1.0;var pending = [];if (Array.isArray(pbrSpecularGlossiness.diffuseFactor)) {var array = pbrSpecularGlossiness.diffuseFactor;params.color.fromArray(array);params.opacity = array[3];}if (pbrSpecularGlossiness.diffuseTexture !== undefined) {pending.push(parser.assignTexture(params, 'map', pbrSpecularGlossiness.diffuseTexture));}params.emissive = new THREE.Color(0.0, 0.0, 0.0);params.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0;params.specular = new THREE.Color(1.0, 1.0, 1.0);if (Array.isArray(pbrSpecularGlossiness.specularFactor)) {params.specular.fromArray(pbrSpecularGlossiness.specularFactor);}if (pbrSpecularGlossiness.specularGlossinessTexture !== undefined) {var specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;pending.push(parser.assignTexture(params, 'glossinessMap', specGlossMapDef));pending.push(parser.assignTexture(params, 'specularMap', specGlossMapDef));}return Promise.all(pending);},createMaterial: function (params) {// setup material properties based on MeshStandardMaterial for Specular-Glossinessvar material = new THREE.ShaderMaterial({defines: params.defines,vertexShader: params.vertexShader,fragmentShader: params.fragmentShader,uniforms: params.uniforms,fog: true,lights: true,opacity: params.opacity,transparent: params.transparent});material.isGLTFSpecularGlossinessMaterial = true;material.color = params.color;material.map = params.map === undefined ? null : params.map;material.lightMap = null;material.lightMapIntensity = 1.0;material.aoMap = params.aoMap === undefined ? null : params.aoMap;material.aoMapIntensity = 1.0;material.emissive = params.emissive;material.emissiveIntensity = 1.0;material.emissiveMap = params.emissiveMap === undefined ? null : params.emissiveMap;material.bumpMap = params.bumpMap === undefined ? null : params.bumpMap;material.bumpScale = 1;material.normalMap = params.normalMap === undefined ? null : params.normalMap;if (params.normalScale) material.normalScale = params.normalScale;material.displacementMap = null;material.displacementScale = 1;material.displacementBias = 0;material.specularMap = params.specularMap === undefined ? null : params.specularMap;material.specular = params.specular;material.glossinessMap = params.glossinessMap === undefined ? null : params.glossinessMap;material.glossiness = params.glossiness;material.alphaMap = null;material.envMap = params.envMap === undefined ? null : params.envMap;material.envMapIntensity = 1.0;material.refractionRatio = 0.98;material.extensions.derivatives = true;return material;},/*** Clones a GLTFSpecularGlossinessMaterial instance. The ShaderMaterial.copy() method can* copy only properties it knows about or inherits, and misses many properties that would* normally be defined by MeshStandardMaterial.** This method allows GLTFSpecularGlossinessMaterials to be cloned in the process of* loading a glTF model, but cloning later (e.g. by the user) would require these changes* AND also updating `.onBeforeRender` on the parent mesh.** @param  {THREE.ShaderMaterial} source* @return {THREE.ShaderMaterial}*/cloneMaterial: function (source) {var target = source.clone();target.isGLTFSpecularGlossinessMaterial = true;var params = this.specularGlossinessParams;for (var i = 0, il = params.length; i < il; i++) {target[params[i]] = source[params[i]];}return target;},// Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer.refreshUniforms: function (renderer, scene, camera, geometry, material, group) {if (material.isGLTFSpecularGlossinessMaterial !== true) {return;}var uniforms = material.uniforms;var defines = material.defines;uniforms.opacity.value = material.opacity;uniforms.diffuse.value.copy(material.color);uniforms.emissive.value.copy(material.emissive).multiplyScalar(material.emissiveIntensity);uniforms.map.value = material.map;uniforms.specularMap.value = material.specularMap;uniforms.alphaMap.value = material.alphaMap;uniforms.lightMap.value = material.lightMap;uniforms.lightMapIntensity.value = material.lightMapIntensity;uniforms.aoMap.value = material.aoMap;uniforms.aoMapIntensity.value = material.aoMapIntensity;// uv repeat and offset setting priorities// 1. color map// 2. specular map// 3. normal map// 4. bump map// 5. alpha map// 6. emissive mapvar uvScaleMap;if (material.map) {uvScaleMap = material.map;} else if (material.specularMap) {uvScaleMap = material.specularMap;} else if (material.displacementMap) {uvScaleMap = material.displacementMap;} else if (material.normalMap) {uvScaleMap = material.normalMap;} else if (material.bumpMap) {uvScaleMap = material.bumpMap;} else if (material.glossinessMap) {uvScaleMap = material.glossinessMap;} else if (material.alphaMap) {uvScaleMap = material.alphaMap;} else if (material.emissiveMap) {uvScaleMap = material.emissiveMap;}if (uvScaleMap !== undefined) {// backwards compatibilityif (uvScaleMap.isWebGLRenderTarget) {uvScaleMap = uvScaleMap.texture;}if (uvScaleMap.matrixAutoUpdate === true) {uvScaleMap.updateMatrix();}uniforms.uvTransform.value.copy(uvScaleMap.matrix);}if (material.envMap) {uniforms.envMap.value = material.envMap;uniforms.envMapIntensity.value = material.envMapIntensity;// don't flip CubeTexture envMaps, flip everything else://  WebGLRenderTargetCube will be flipped for backwards compatibility//  WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture// this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the futureuniforms.flipEnvMap.value = material.envMap.isCubeTexture ? -1 : 1;uniforms.reflectivity.value = material.reflectivity;uniforms.refractionRatio.value = material.refractionRatio;uniforms.maxMipLevel.value = renderer.properties.get(material.envMap).__maxMipLevel;}uniforms.specular.value.copy(material.specular);uniforms.glossiness.value = material.glossiness;uniforms.glossinessMap.value = material.glossinessMap;uniforms.emissiveMap.value = material.emissiveMap;uniforms.bumpMap.value = material.bumpMap;uniforms.normalMap.value = material.normalMap;uniforms.displacementMap.value = material.displacementMap;uniforms.displacementScale.value = material.displacementScale;uniforms.displacementBias.value = material.displacementBias;if (uniforms.glossinessMap.value !== null && defines.USE_GLOSSINESSMAP === undefined) {defines.USE_GLOSSINESSMAP = '';// set USE_ROUGHNESSMAP to enable vUvdefines.USE_ROUGHNESSMAP = '';}if (uniforms.glossinessMap.value === null && defines.USE_GLOSSINESSMAP !== undefined) {delete defines.USE_GLOSSINESSMAP;delete defines.USE_ROUGHNESSMAP;}}};}/*********************************//********** INTERPOLATION ********//*********************************/// Spline Interpolation// Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolationfunction GLTFCubicSplineInterpolant(parameterPositions, sampleValues, sampleSize, resultBuffer) {THREE.Interpolant.call(this, parameterPositions, sampleValues, sampleSize, resultBuffer);}GLTFCubicSplineInterpolant.prototype = Object.create(THREE.Interpolant.prototype);GLTFCubicSplineInterpolant.prototype.constructor = GLTFCubicSplineInterpolant;GLTFCubicSplineInterpolant.prototype.copySampleValue_ = function (index) {// Copies a sample value to the result buffer. See description of glTF// CUBICSPLINE values layout in interpolate_() function below.var result = this.resultBuffer,values = this.sampleValues,valueSize = this.valueSize,offset = index * valueSize * 3 + valueSize;for (var i = 0; i !== valueSize; i++) {result[i] = values[offset + i];}return result;};GLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;GLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;GLTFCubicSplineInterpolant.prototype.interpolate_ = function (i1, t0, t, t1) {var result = this.resultBuffer;var values = this.sampleValues;var stride = this.valueSize;var stride2 = stride * 2;var stride3 = stride * 3;var td = t1 - t0;var p = (t - t0) / td;var pp = p * p;var ppp = pp * p;var offset1 = i1 * stride3;var offset0 = offset1 - stride3;var s2 = -2 * ppp + 3 * pp;var s3 = ppp - pp;var s0 = 1 - s2;var s1 = s3 - pp + p;// Layout of keyframe output values for CUBICSPLINE animations://   [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]for (var i = 0; i !== stride; i++) {var p0 = values[offset0 + i + stride]; // splineVertex_kvar m0 = values[offset0 + i + stride2] * td; // outTangent_k * (t_k+1 - t_k)var p1 = values[offset1 + i + stride]; // splineVertex_k+1var m1 = values[offset1 + i] * td; // inTangent_k+1 * (t_k+1 - t_k)result[i] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1;}return result;};/*********************************//********** 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,POINTS: 0,LINES: 1,LINE_LOOP: 2,LINE_STRIP: 3,TRIANGLES: 4,TRIANGLE_STRIP: 5,TRIANGLE_FAN: 6,UNSIGNED_BYTE: 5121,UNSIGNED_SHORT: 5123};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_SIDES = {1028: THREE.BackSide, // Culling front1029: 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 ATTRIBUTES = {POSITION: 'position',NORMAL: 'normal',TANGENT: 'tangent',TEXCOORD_0: 'uv',TEXCOORD_1: 'uv2',COLOR_0: 'color',WEIGHTS_0: 'skinWeight',JOINTS_0: 'skinIndex',};var PATH_PROPERTIES = {scale: 'scale',translation: 'position',rotation: 'quaternion',weights: 'morphTargetInfluences'};var INTERPOLATION = {CUBICSPLINE: THREE.InterpolateSmooth, // We use custom interpolation GLTFCubicSplineInterpolation for CUBICSPLINE.// KeyframeTrack.optimize() can't handle glTF Cubic Spline output values layout,// using THREE.InterpolateSmooth for KeyframeTrack instantiation to prevent optimization.// See KeyframeTrack.optimize() for the detail.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'};var ALPHA_MODES = {OPAQUE: 'OPAQUE',MASK: 'MASK',BLEND: 'BLEND'};var MIME_TYPE_FORMATS = {'image/png': THREE.RGBAFormat,'image/jpeg': THREE.RGBFormat};/* UTILITY FUNCTIONS */function resolveURL(url, path) {// Invalid URLif (typeof url !== 'string' || url === '') return '';// Absolute URL http://,https://,//if (/^(https?:)?\/\//i.test(url)) return url;// Data URIif (/^data:.*,.*$/i.test(url)) return url;// Blob URLif (/^blob:.*$/i.test(url)) return url;// Relative URLreturn path + url;}var defaultMaterial;/*** Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material*/function createDefaultMaterial() {defaultMaterial = defaultMaterial || new THREE.MeshStandardMaterial({color: 0xFFFFFF,emissive: 0x000000,metalness: 1,roughness: 1,transparent: false,depthTest: true,side: THREE.FrontSide});return defaultMaterial;}function addUnknownExtensionsToUserData(knownExtensions, object, objectDef) {// Add unknown glTF extensions to an object's userData.for (var name in objectDef.extensions) {if (knownExtensions[name] === undefined) {object.userData.gltfExtensions = object.userData.gltfExtensions || {};object.userData.gltfExtensions[name] = objectDef.extensions[name];}}}/*** @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry} object* @param {GLTF.definition} gltfDef*/function assignExtrasToUserData(object, gltfDef) {if (gltfDef.extras !== undefined) {if (typeof gltfDef.extras === 'object') {object.userData = gltfDef.extras;} else {console.warn('THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras);}}}/*** Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets** @param {THREE.BufferGeometry} geometry* @param {Array<GLTF.Target>} targets* @param {GLTFParser} parser* @return {Promise<THREE.BufferGeometry>}*/function addMorphTargets(geometry, targets, parser) {var hasMorphPosition = false;var hasMorphNormal = false;for (var i = 0, il = targets.length; i < il; i++) {var target = targets[i];if (target.POSITION !== undefined) hasMorphPosition = true;if (target.NORMAL !== undefined) hasMorphNormal = true;if (hasMorphPosition && hasMorphNormal) break;}if (!hasMorphPosition && !hasMorphNormal) return Promise.resolve(geometry);var pendingPositionAccessors = [];var pendingNormalAccessors = [];for (var i = 0, il = targets.length; i < il; i++) {var target = targets[i];if (hasMorphPosition) {// TODO: Error-prone use of a callback inside a loop.var accessor = target.POSITION !== undefined ?parser.getDependency('accessor', target.POSITION).then(function (accessor) {// Cloning not to pollute original accessor belowreturn cloneBufferAttribute(accessor);}) :geometry.attributes.position;pendingPositionAccessors.push(accessor);}if (hasMorphNormal) {// TODO: Error-prone use of a callback inside a loop.var accessor = target.NORMAL !== undefined ?parser.getDependency('accessor', target.NORMAL).then(function (accessor) {return cloneBufferAttribute(accessor);}) :geometry.attributes.normal;pendingNormalAccessors.push(accessor);}}return Promise.all([Promise.all(pendingPositionAccessors),Promise.all(pendingNormalAccessors)]).then(function (accessors) {var morphPositions = accessors[0];var morphNormals = accessors[1];for (var i = 0, il = targets.length; i < il; i++) {var target = targets[i];var attributeName = 'morphTarget' + i;if (hasMorphPosition) {// Three.js morph position is absolute value. The formula is//   basePosition//     + weight0 * ( morphPosition0 - basePosition )//     + weight1 * ( morphPosition1 - basePosition )//     ...// while the glTF one is relative//   basePosition//     + weight0 * glTFmorphPosition0//     + weight1 * glTFmorphPosition1//     ...// then we need to convert from relative to absolute here.if (target.POSITION !== undefined) {var positionAttribute = morphPositions[i];positionAttribute.name = attributeName;var position = geometry.attributes.position;for (var j = 0, jl = positionAttribute.count; j < jl; j++) {positionAttribute.setXYZ(j,positionAttribute.getX(j) + position.getX(j),positionAttribute.getY(j) + position.getY(j),positionAttribute.getZ(j) + position.getZ(j));}}}if (hasMorphNormal) {// see target.POSITION's commentif (target.NORMAL !== undefined) {var normalAttribute = morphNormals[i];normalAttribute.name = attributeName;var normal = geometry.attributes.normal;for (var j = 0, jl = normalAttribute.count; j < jl; j++) {normalAttribute.setXYZ(j,normalAttribute.getX(j) + normal.getX(j),normalAttribute.getY(j) + normal.getY(j),normalAttribute.getZ(j) + normal.getZ(j));}}}}if (hasMorphPosition) geometry.morphAttributes.position = morphPositions;if (hasMorphNormal) geometry.morphAttributes.normal = morphNormals;return geometry;});}/*** @param {THREE.Mesh} mesh* @param {GLTF.Mesh} meshDef*/function updateMorphTargets(mesh, meshDef) {mesh.updateMorphTargets();if (meshDef.weights !== undefined) {for (var i = 0, il = meshDef.weights.length; i < il; i++) {mesh.morphTargetInfluences[i] = meshDef.weights[i];}}// .extras has user-defined data, so check that .extras.targetNames is an array.if (meshDef.extras && Array.isArray(meshDef.extras.targetNames)) {var targetNames = meshDef.extras.targetNames;if (mesh.morphTargetInfluences.length === targetNames.length) {mesh.morphTargetDictionary = {};for (var i = 0, il = targetNames.length; i < il; i++) {mesh.morphTargetDictionary[targetNames[i]] = i;}} else {console.warn('THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.');}}}function isObjectEqual(a, b) {if (Object.keys(a).length !== Object.keys(b).length) return false;for (var key in a) {if (a[key] !== b[key]) return false;}return true;}function createPrimitiveKey(primitiveDef) {var dracoExtension = primitiveDef.extensions && primitiveDef.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION];var geometryKey;if (dracoExtension) {geometryKey = 'draco:' + dracoExtension.bufferView +':' + dracoExtension.indices +':' + createAttributesKey(dracoExtension.attributes);} else {geometryKey = primitiveDef.indices + ':' + createAttributesKey(primitiveDef.attributes) + ':' + primitiveDef.mode;}return geometryKey;}function createAttributesKey(attributes) {var attributesKey = '';var keys = Object.keys(attributes).sort();for (var i = 0, il = keys.length; i < il; i++) {attributesKey += keys[i] + ':' + attributes[keys[i]] + ';';}return attributesKey;}function cloneBufferAttribute(attribute) {if (attribute.isInterleavedBufferAttribute) {var count = attribute.count;var itemSize = attribute.itemSize;var array = attribute.array.slice(0, count * itemSize);for (var i = 0, j = 0; i < count; ++i) {array[j++] = attribute.getX(i);if (itemSize >= 2) array[j++] = attribute.getY(i);if (itemSize >= 3) array[j++] = attribute.getZ(i);if (itemSize >= 4) array[j++] = attribute.getW(i);}return new THREE.BufferAttribute(array, itemSize, attribute.normalized);}return attribute.clone();}/* GLTF PARSER */function GLTFParser(json, extensions, options) {this.json = json || {};this.extensions = extensions || {};this.options = options || {};// loader object cachethis.cache = new GLTFRegistry();// BufferGeometry cachingthis.primitiveCache = {};this.textureLoader = new THREE.TextureLoader(this.options.manager);this.textureLoader.setCrossOrigin(this.options.crossOrigin);this.fileLoader = new THREE.FileLoader(this.options.manager);this.fileLoader.setResponseType('arraybuffer');}GLTFParser.prototype.parse = function (onLoad, onError) {var json = this.json;// Clear the loader cachethis.cache.removeAll();// Mark the special nodes/meshes in json for efficient parsethis.markDefs();// Fire the callback on completethis.getMultiDependencies(['scene','animation','camera']).then(function (dependencies) {var scenes = dependencies.scenes || [];var scene = scenes[json.scene || 0];var animations = dependencies.animations || [];var cameras = dependencies.cameras || [];onLoad(scene, scenes, cameras, animations, json);}).catch(onError);};/*** Marks the special nodes/meshes in json for efficient parse.*/GLTFParser.prototype.markDefs = function () {var nodeDefs = this.json.nodes || [];var skinDefs = this.json.skins || [];var meshDefs = this.json.meshes || [];var meshReferences = {};var meshUses = {};// Nothing in the node definition indicates whether it is a Bone or an// Object3D. Use the skins' joint references to mark bones.for (var skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex++) {var joints = skinDefs[skinIndex].joints;for (var i = 0, il = joints.length; i < il; i++) {nodeDefs[joints[i]].isBone = true;}}// Meshes can (and should) be reused by multiple nodes in a glTF asset. To// avoid having more than one THREE.Mesh with the same name, count// references and rename instances below.//// Example: CesiumMilkTruck sample model reuses "Wheel" meshes.for (var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++) {var nodeDef = nodeDefs[nodeIndex];if (nodeDef.mesh !== undefined) {if (meshReferences[nodeDef.mesh] === undefined) {meshReferences[nodeDef.mesh] = meshUses[nodeDef.mesh] = 0;}meshReferences[nodeDef.mesh]++;// Nothing in the mesh definition indicates whether it is// a SkinnedMesh or Mesh. Use the node's mesh reference// to mark SkinnedMesh if node has skin.if (nodeDef.skin !== undefined) {meshDefs[nodeDef.mesh].isSkinnedMesh = true;}}}this.json.meshReferences = meshReferences;this.json.meshUses = meshUses;};/*** Requests the specified dependency asynchronously, with caching.* @param {string} type* @param {number} index* @return {Promise<THREE.Object3D|THREE.Material|THREE.Texture|THREE.AnimationClip|ArrayBuffer|Object>}*/GLTFParser.prototype.getDependency = function (type, index) {var cacheKey = type + ':' + index;var dependency = this.cache.get(cacheKey);if (!dependency) {switch (type) {case 'scene':dependency = this.loadScene(index);break;case 'node':dependency = this.loadNode(index);break;case 'mesh':dependency = this.loadMesh(index);break;case 'accessor':dependency = this.loadAccessor(index);break;case 'bufferView':dependency = this.loadBufferView(index);break;case 'buffer':dependency = this.loadBuffer(index);break;case 'material':dependency = this.loadMaterial(index);break;case 'texture':dependency = this.loadTexture(index);break;case 'skin':dependency = this.loadSkin(index);break;case 'animation':dependency = this.loadAnimation(index);break;case 'camera':dependency = this.loadCamera(index);break;case 'light':dependency = this.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].loadLight(index);break;default:throw new Error('Unknown type: ' + type);}this.cache.add(cacheKey, dependency);}return dependency;};/*** Requests all dependencies of the specified type asynchronously, with caching.* @param {string} type* @return {Promise<Array<Object>>}*/GLTFParser.prototype.getDependencies = function (type) {var dependencies = this.cache.get(type);if (!dependencies) {var parser = this;var defs = this.json[type + (type === 'mesh' ? 'es' : 's')] || [];dependencies = Promise.all(defs.map(function (def, index) {return parser.getDependency(type, index);}));this.cache.add(type, dependencies);}return dependencies;};/*** Requests all multiple dependencies of the specified types asynchronously, with caching.* @param {Array<string>} types* @return {Promise<Object<Array<Object>>>}*/GLTFParser.prototype.getMultiDependencies = function (types) {var results = {};var pending = [];for (var i = 0, il = types.length; i < il; i++) {var type = types[i];var value = this.getDependencies(type);// TODO: Error-prone use of a callback inside a loop.value = value.then(function (key, value) {results[key] = value;}.bind(this, type + (type === 'mesh' ? 'es' : 's')));pending.push(value);}return Promise.all(pending).then(function () {return results;});};/*** Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views* @param {number} bufferIndex* @return {Promise<ArrayBuffer>}*/GLTFParser.prototype.loadBuffer = function (bufferIndex) {var bufferDef = this.json.buffers[bufferIndex];var loader = this.fileLoader;if (bufferDef.type && bufferDef.type !== 'arraybuffer') {throw new Error('THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.');}// If present, GLB container is required to be the first buffer.if (bufferDef.uri === undefined && bufferIndex === 0) {return Promise.resolve(this.extensions[EXTENSIONS.KHR_BINARY_GLTF].body);}var options = this.options;return new Promise(function (resolve, reject) {loader.load(resolveURL(bufferDef.uri, options.path), resolve, undefined, function () {reject(new Error('THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".'));});});};/*** Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views* @param {number} bufferViewIndex* @return {Promise<ArrayBuffer>}*/GLTFParser.prototype.loadBufferView = function (bufferViewIndex) {var bufferViewDef = this.json.bufferViews[bufferViewIndex];return this.getDependency('buffer', bufferViewDef.buffer).then(function (buffer) {var byteLength = bufferViewDef.byteLength || 0;var byteOffset = bufferViewDef.byteOffset || 0;return buffer.slice(byteOffset, byteOffset + byteLength);});};/*** Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors* @param {number} accessorIndex* @return {Promise<THREE.BufferAttribute|THREE.InterleavedBufferAttribute>}*/GLTFParser.prototype.loadAccessor = function (accessorIndex) {var parser = this;var json = this.json;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 Promise.resolve(null);}var pendingBufferViews = [];if (accessorDef.bufferView !== undefined) {pendingBufferViews.push(this.getDependency('bufferView', accessorDef.bufferView));} else {pendingBufferViews.push(null);}if (accessorDef.sparse !== undefined) {pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.indices.bufferView));pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.values.bufferView));}return Promise.all(pendingBufferViews).then(function (bufferViews) {var bufferView = bufferViews[0];var itemSize = WEBGL_TYPE_SIZES[accessorDef.type];var TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType];// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.var elementBytes = TypedArray.BYTES_PER_ELEMENT;var itemBytes = elementBytes * itemSize;var byteOffset = accessorDef.byteOffset || 0;var byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[accessorDef.bufferView].byteStride : undefined;var normalized = accessorDef.normalized === true;var array, bufferAttribute;// The buffer is not interleaved if the stride is the item size in bytes.if (byteStride && byteStride !== itemBytes) {var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType;var ib = parser.cache.get(ibCacheKey);if (!ib) {// Use the full buffer if it's interleaved.array = new TypedArray(bufferView);// Integer parameters to IB/IBA are in array elements, not bytes.ib = new THREE.InterleavedBuffer(array, byteStride / elementBytes);parser.cache.add(ibCacheKey, ib);}bufferAttribute = new THREE.InterleavedBufferAttribute(ib, itemSize, byteOffset / elementBytes, normalized);} else {if (bufferView === null) {array = new TypedArray(accessorDef.count * itemSize);} else {array = new TypedArray(bufferView, byteOffset, accessorDef.count * itemSize);}bufferAttribute = new THREE.BufferAttribute(array, itemSize, normalized);}// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessorsif (accessorDef.sparse !== undefined) {var itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR;var TypedArrayIndices = WEBGL_COMPONENT_TYPES[accessorDef.sparse.indices.componentType];var byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0;var byteOffsetValues = accessorDef.sparse.values.byteOffset || 0;var sparseIndices = new TypedArrayIndices(bufferViews[1], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices);var sparseValues = new TypedArray(bufferViews[2], byteOffsetValues, accessorDef.sparse.count * itemSize);if (bufferView !== null) {// Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.bufferAttribute.setArray(bufferAttribute.array.slice());}for (var i = 0, il = sparseIndices.length; i < il; i++) {var index = sparseIndices[i];bufferAttribute.setX(index, sparseValues[i * itemSize]);if (itemSize >= 2) bufferAttribute.setY(index, sparseValues[i * itemSize + 1]);if (itemSize >= 3) bufferAttribute.setZ(index, sparseValues[i * itemSize + 2]);if (itemSize >= 4) bufferAttribute.setW(index, sparseValues[i * itemSize + 3]);if (itemSize >= 5) throw new Error('THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.');}}return bufferAttribute;});};/*** Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures* @param {number} textureIndex* @return {Promise<THREE.Texture>}*/GLTFParser.prototype.loadTexture = function (textureIndex) {var parser = this;var json = this.json;var options = this.options;var textureLoader = this.textureLoader;var URL = window.URL || window.webkitURL;var textureDef = json.textures[textureIndex];var textureExtensions = textureDef.extensions || {};var source;if (textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS]) {source = json.images[textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS].source];} else {source = json.images[textureDef.source];}var sourceURI = source.uri;var isObjectURL = false;if (source.bufferView !== undefined) {// Load binary image data from bufferView, if provided.sourceURI = parser.getDependency('bufferView', source.bufferView).then(function (bufferView) {isObjectURL = true;var blob = new Blob([bufferView], {type: source.mimeType});sourceURI = URL.createObjectURL(blob);return sourceURI;});}return Promise.resolve(sourceURI).then(function (sourceURI) {// Load Texture resource.var loader = THREE.Loader.Handlers.get(sourceURI);if (!loader) {loader = textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS] ?parser.extensions[EXTENSIONS.MSFT_TEXTURE_DDS].ddsLoader :textureLoader;}return new Promise(function (resolve, reject) {loader.load(resolveURL(sourceURI, options.path), resolve, undefined, reject);});}).then(function (texture) {// Clean up resources and configure Texture.if (isObjectURL === true) {URL.revokeObjectURL(sourceURI);}texture.flipY = false;if (textureDef.name !== undefined) texture.name = textureDef.name;// Ignore unknown mime types, like DDS files.if (source.mimeType in MIME_TYPE_FORMATS) {texture.format = MIME_TYPE_FORMATS[source.mimeType];}var samplers = json.samplers || {};var sampler = samplers[textureDef.sampler] || {};texture.magFilter = WEBGL_FILTERS[sampler.magFilter] || THREE.LinearFilter;texture.minFilter = WEBGL_FILTERS[sampler.minFilter] || THREE.LinearMipMapLinearFilter;texture.wrapS = WEBGL_WRAPPINGS[sampler.wrapS] || THREE.RepeatWrapping;texture.wrapT = WEBGL_WRAPPINGS[sampler.wrapT] || THREE.RepeatWrapping;return texture;});};/*** Asynchronously assigns a texture to the given material parameters.* @param {Object} materialParams* @param {string} mapName* @param {Object} mapDef* @return {Promise}*/GLTFParser.prototype.assignTexture = function (materialParams, mapName, mapDef) {var parser = this;return this.getDependency('texture', mapDef.index).then(function (texture) {switch (mapName) {case 'aoMap':case 'emissiveMap':case 'metalnessMap':case 'normalMap':case 'roughnessMap':texture.format = THREE.RGBFormat;break;}if (parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM]) {var transform = mapDef.extensions !== undefined ? mapDef.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM] : undefined;if (transform) {texture = parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM].extendTexture(texture, transform);}}materialParams[mapName] = texture;});};/*** Assigns final material to a Mesh, Line, or Points instance. The instance* already has a material (generated from the glTF material options alone)* but reuse of the same glTF material may require multiple threejs materials* to accomodate different primitive types, defines, etc. New materials will* be created if necessary, and reused from a cache.* @param  {THREE.Object3D} mesh Mesh, Line, or Points instance.*/GLTFParser.prototype.assignFinalMaterial = function (mesh) {var geometry = mesh.geometry;var material = mesh.material;var extensions = this.extensions;var useVertexTangents = geometry.attributes.tangent !== undefined;var useVertexColors = geometry.attributes.color !== undefined;var useFlatShading = geometry.attributes.normal === undefined;var useSkinning = mesh.isSkinnedMesh === true;var useMorphTargets = Object.keys(geometry.morphAttributes).length > 0;var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined;if (mesh.isPoints) {var cacheKey = 'PointsMaterial:' + material.uuid;var pointsMaterial = this.cache.get(cacheKey);if (!pointsMaterial) {pointsMaterial = new THREE.PointsMaterial();THREE.Material.prototype.copy.call(pointsMaterial, material);pointsMaterial.color.copy(material.color);pointsMaterial.map = material.map;pointsMaterial.lights = false; // PointsMaterial doesn't support lights yetthis.cache.add(cacheKey, pointsMaterial);}material = pointsMaterial;} else if (mesh.isLine) {var cacheKey = 'LineBasicMaterial:' + material.uuid;var lineMaterial = this.cache.get(cacheKey);if (!lineMaterial) {lineMaterial = new THREE.LineBasicMaterial();THREE.Material.prototype.copy.call(lineMaterial, material);lineMaterial.color.copy(material.color);lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yetthis.cache.add(cacheKey, lineMaterial);}material = lineMaterial;}// Clone the material if it will be modifiedif (useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets) {var cacheKey = 'ClonedMaterial:' + material.uuid + ':';if (material.isGLTFSpecularGlossinessMaterial) cacheKey += 'specular-glossiness:';if (useSkinning) cacheKey += 'skinning:';if (useVertexTangents) cacheKey += 'vertex-tangents:';if (useVertexColors) cacheKey += 'vertex-colors:';if (useFlatShading) cacheKey += 'flat-shading:';if (useMorphTargets) cacheKey += 'morph-targets:';if (useMorphNormals) cacheKey += 'morph-normals:';var cachedMaterial = this.cache.get(cacheKey);if (!cachedMaterial) {cachedMaterial = material.isGLTFSpecularGlossinessMaterial ?extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].cloneMaterial(material) :material.clone();if (useSkinning) cachedMaterial.skinning = true;if (useVertexTangents) cachedMaterial.vertexTangents = true;if (useVertexColors) cachedMaterial.vertexColors = THREE.VertexColors;if (useFlatShading) cachedMaterial.flatShading = true;if (useMorphTargets) cachedMaterial.morphTargets = true;if (useMorphNormals) cachedMaterial.morphNormals = true;this.cache.add(cacheKey, cachedMaterial);}material = cachedMaterial;}// workarounds for mesh and geometryif (material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined) {console.log('THREE.GLTFLoader: Duplicating UVs to support aoMap.');geometry.addAttribute('uv2', new THREE.BufferAttribute(geometry.attributes.uv.array, 2));}if (material.isGLTFSpecularGlossinessMaterial) {// for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime updatemesh.onBeforeRender = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].refreshUniforms;}mesh.material = material;};/*** Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials* @param {number} materialIndex* @return {Promise<THREE.Material>}*/GLTFParser.prototype.loadMaterial = function (materialIndex) {var parser = this;var json = this.json;var extensions = this.extensions;var materialDef = json.materials[materialIndex];var materialType;var materialParams = {};var materialExtensions = materialDef.extensions || {};var pending = [];if (materialExtensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS]) {var sgExtension = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS];materialType = sgExtension.getMaterialType(materialDef);pending.push(sgExtension.extendParams(materialParams, materialDef, parser));} else if (materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]) {var kmuExtension = extensions[EXTENSIONS.KHR_MATERIALS_UNLIT];materialType = kmuExtension.getMaterialType(materialDef);pending.push(kmuExtension.extendParams(materialParams, materialDef, parser));} else {// Specification:// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-materialmaterialType = THREE.MeshStandardMaterial;var metallicRoughness = materialDef.pbrMetallicRoughness || {};materialParams.color = new THREE.Color(1.0, 1.0, 1.0);materialParams.opacity = 1.0;if (Array.isArray(metallicRoughness.baseColorFactor)) {var array = metallicRoughness.baseColorFactor;materialParams.color.fromArray(array);materialParams.opacity = array[3];}if (metallicRoughness.baseColorTexture !== undefined) {pending.push(parser.assignTexture(materialParams, 'map', metallicRoughness.baseColorTexture));}materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;if (metallicRoughness.metallicRoughnessTexture !== undefined) {pending.push(parser.assignTexture(materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture));pending.push(parser.assignTexture(materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture));}}if (materialDef.doubleSided === true) {materialParams.side = THREE.DoubleSide;}var alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE;if (alphaMode === ALPHA_MODES.BLEND) {materialParams.transparent = true;} else {materialParams.transparent = false;if (alphaMode === ALPHA_MODES.MASK) {materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5;}}if (materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {pending.push(parser.assignTexture(materialParams, 'normalMap', materialDef.normalTexture));materialParams.normalScale = new THREE.Vector2(1, 1);if (materialDef.normalTexture.scale !== undefined) {materialParams.normalScale.set(materialDef.normalTexture.scale, materialDef.normalTexture.scale);}}if (materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {pending.push(parser.assignTexture(materialParams, 'aoMap', materialDef.occlusionTexture));if (materialDef.occlusionTexture.strength !== undefined) {materialParams.aoMapIntensity = materialDef.occlusionTexture.strength;}}if (materialDef.emissiveFactor !== undefined && materialType !== THREE.MeshBasicMaterial) {materialParams.emissive = new THREE.Color().fromArray(materialDef.emissiveFactor);}if (materialDef.emissiveTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {pending.push(parser.assignTexture(materialParams, 'emissiveMap', materialDef.emissiveTexture));}return Promise.all(pending).then(function () {var material;if (materialType === THREE.ShaderMaterial) {material = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].createMaterial(materialParams);} else {material = new materialType(materialParams);}if (materialDef.name !== undefined) material.name = materialDef.name;// baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.if (material.map) material.map.encoding = THREE.sRGBEncoding;if (material.emissiveMap) material.emissiveMap.encoding = THREE.sRGBEncoding;if (material.specularMap) material.specularMap.encoding = THREE.sRGBEncoding;assignExtrasToUserData(material, materialDef);if (materialDef.extensions) addUnknownExtensionsToUserData(extensions, material, materialDef);return material;});};/*** @param {THREE.BufferGeometry} geometry* @param {GLTF.Primitive} primitiveDef* @param {GLTFParser} parser* @return {Promise<THREE.BufferGeometry>}*/function addPrimitiveAttributes(geometry, primitiveDef, parser) {var attributes = primitiveDef.attributes;var pending = [];function assignAttributeAccessor(accessorIndex, attributeName) {return parser.getDependency('accessor', accessorIndex).then(function (accessor) {geometry.addAttribute(attributeName, accessor);});}for (var gltfAttributeName in attributes) {var threeAttributeName = ATTRIBUTES[gltfAttributeName];if (!threeAttributeName) continue;// Skip attributes already provided by e.g. Draco extension.if (threeAttributeName in geometry.attributes) continue;pending.push(assignAttributeAccessor(attributes[gltfAttributeName], threeAttributeName));}if (primitiveDef.indices !== undefined && !geometry.index) {var accessor = parser.getDependency('accessor', primitiveDef.indices).then(function (accessor) {geometry.setIndex(accessor);});pending.push(accessor);}assignExtrasToUserData(geometry, primitiveDef);return Promise.all(pending).then(function () {return primitiveDef.targets !== undefined ?addMorphTargets(geometry, primitiveDef.targets, parser) :geometry;});}/*** Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry** Creates BufferGeometries from primitives.** @param {Array<GLTF.Primitive>} primitives* @return {Promise<Array<THREE.BufferGeometry>>}*/GLTFParser.prototype.loadGeometries = function (primitives) {var parser = this;var extensions = this.extensions;var cache = this.primitiveCache;function createDracoPrimitive(primitive) {return extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION].decodePrimitive(primitive, parser).then(function (geometry) {return addPrimitiveAttributes(geometry, primitive, parser);});}var pending = [];for (var i = 0, il = primitives.length; i < il; i++) {var primitive = primitives[i];var cacheKey = createPrimitiveKey(primitive);// See if we've already created this geometryvar cached = cache[cacheKey];if (cached) {// Use the cached geometry if it existspending.push(cached.promise);} else {var geometryPromise;if (primitive.extensions && primitive.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]) {// Use DRACO geometry if availablegeometryPromise = createDracoPrimitive(primitive);} else {// Otherwise create a new geometrygeometryPromise = addPrimitiveAttributes(new THREE.BufferGeometry(), primitive, parser);}// Cache this geometrycache[cacheKey] = {primitive: primitive,promise: geometryPromise};pending.push(geometryPromise);}}return Promise.all(pending);};/*** Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes* @param {number} meshIndex* @return {Promise<THREE.Group|THREE.Mesh|THREE.SkinnedMesh>}*/GLTFParser.prototype.loadMesh = function (meshIndex) {var parser = this;var json = this.json;var extensions = this.extensions;var meshDef = json.meshes[meshIndex];var primitives = meshDef.primitives;var pending = [];for (var i = 0, il = primitives.length; i < il; i++) {var material = primitives[i].material === undefined ?createDefaultMaterial() :this.getDependency('material', primitives[i].material);pending.push(material);}return Promise.all(pending).then(function (originalMaterials) {return parser.loadGeometries(primitives).then(function (geometries) {var meshes = [];for (var i = 0, il = geometries.length; i < il; i++) {var geometry = geometries[i];var primitive = primitives[i];// 1. create Meshvar mesh;var material = originalMaterials[i];if (primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||primitive.mode === undefined) {// .isSkinnedMesh isn't in glTF spec. See .markDefs()mesh = meshDef.isSkinnedMesh === true ?new THREE.SkinnedMesh(geometry, material) :new THREE.Mesh(geometry, material);if (mesh.isSkinnedMesh === true) mesh.normalizeSkinWeights(); // #15319if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP) {mesh.drawMode = THREE.TriangleStripDrawMode;} else if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN) {mesh.drawMode = THREE.TriangleFanDrawMode;}} else if (primitive.mode === WEBGL_CONSTANTS.LINES) {mesh = new THREE.LineSegments(geometry, material);} else if (primitive.mode === WEBGL_CONSTANTS.LINE_STRIP) {mesh = new THREE.Line(geometry, material);} else if (primitive.mode === WEBGL_CONSTANTS.LINE_LOOP) {mesh = new THREE.LineLoop(geometry, material);} else if (primitive.mode === WEBGL_CONSTANTS.POINTS) {mesh = new THREE.Points(geometry, material);} else {throw new Error('THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode);}if (Object.keys(mesh.geometry.morphAttributes).length > 0) {updateMorphTargets(mesh, meshDef);}mesh.name = meshDef.name || ('mesh_' + meshIndex);if (geometries.length > 1) mesh.name += '_' + i;assignExtrasToUserData(mesh, meshDef);parser.assignFinalMaterial(mesh);meshes.push(mesh);}if (meshes.length === 1) {return meshes[0];}var group = new THREE.Group();for (var i = 0, il = meshes.length; i < il; i++) {group.add(meshes[i]);}return group;});});};/*** Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras* @param {number} cameraIndex* @return {Promise<THREE.Camera>}*/GLTFParser.prototype.loadCamera = function (cameraIndex) {var camera;var cameraDef = this.json.cameras[cameraIndex];var params = cameraDef[cameraDef.type];if (!params) {console.warn('THREE.GLTFLoader: Missing camera parameters.');return;}if (cameraDef.type === 'perspective') {camera = new THREE.PerspectiveCamera(THREE.Math.radToDeg(params.yfov), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6);} else if (cameraDef.type === 'orthographic') {camera = new THREE.OrthographicCamera(params.xmag / -2, params.xmag / 2, params.ymag / 2, params.ymag / -2, params.znear, params.zfar);}if (cameraDef.name !== undefined) camera.name = cameraDef.name;assignExtrasToUserData(camera, cameraDef);return Promise.resolve(camera);};/*** Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins* @param {number} skinIndex* @return {Promise<Object>}*/GLTFParser.prototype.loadSkin = function (skinIndex) {var skinDef = this.json.skins[skinIndex];var skinEntry = {joints: skinDef.joints};if (skinDef.inverseBindMatrices === undefined) {return Promise.resolve(skinEntry);}return this.getDependency('accessor', skinDef.inverseBindMatrices).then(function (accessor) {skinEntry.inverseBindMatrices = accessor;return skinEntry;});};/*** Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations* @param {number} animationIndex* @return {Promise<THREE.AnimationClip>}*/GLTFParser.prototype.loadAnimation = function (animationIndex) {var json = this.json;var animationDef = json.animations[animationIndex];var pendingNodes = [];var pendingInputAccessors = [];var pendingOutputAccessors = [];var pendingSamplers = [];var pendingTargets = [];for (var i = 0, il = animationDef.channels.length; i < il; i++) {var channel = animationDef.channels[i];var sampler = animationDef.samplers[channel.sampler];var target = channel.target;var name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated.var input = animationDef.parameters !== undefined ? animationDef.parameters[sampler.input] : sampler.input;var output = animationDef.parameters !== undefined ? animationDef.parameters[sampler.output] : sampler.output;pendingNodes.push(this.getDependency('node', name));pendingInputAccessors.push(this.getDependency('accessor', input));pendingOutputAccessors.push(this.getDependency('accessor', output));pendingSamplers.push(sampler);pendingTargets.push(target);}return Promise.all([Promise.all(pendingNodes),Promise.all(pendingInputAccessors),Promise.all(pendingOutputAccessors),Promise.all(pendingSamplers),Promise.all(pendingTargets)]).then(function (dependencies) {var nodes = dependencies[0];var inputAccessors = dependencies[1];var outputAccessors = dependencies[2];var samplers = dependencies[3];var targets = dependencies[4];var tracks = [];for (var i = 0, il = nodes.length; i < il; i++) {var node = nodes[i];var inputAccessor = inputAccessors[i];var outputAccessor = outputAccessors[i];var sampler = samplers[i];var target = targets[i];if (node === undefined) continue;node.updateMatrix();node.matrixAutoUpdate = true;var TypedKeyframeTrack;switch (PATH_PROPERTIES[target.path]) {case PATH_PROPERTIES.weights:TypedKeyframeTrack = THREE.NumberKeyframeTrack;break;case PATH_PROPERTIES.rotation:TypedKeyframeTrack = THREE.QuaternionKeyframeTrack;break;case PATH_PROPERTIES.position:case PATH_PROPERTIES.scale:default:TypedKeyframeTrack = THREE.VectorKeyframeTrack;break;}var targetName = node.name ? node.name : node.uuid;var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[sampler.interpolation] : THREE.InterpolateLinear;var targetNames = [];if (PATH_PROPERTIES[target.path] === PATH_PROPERTIES.weights) {// node can be THREE.Group here but// PATH_PROPERTIES.weights(morphTargetInfluences) should be// the property of a mesh object under group.node.traverse(function (object) {if (object.isMesh === true && object.morphTargetInfluences) {targetNames.push(object.name ? object.name : object.uuid);}});} else {targetNames.push(targetName);}// 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.for (var j = 0, jl = targetNames.length; j < jl; j++) {var track = new TypedKeyframeTrack(targetNames[j] + '.' + PATH_PROPERTIES[target.path],THREE.AnimationUtils.arraySlice(inputAccessor.array, 0),THREE.AnimationUtils.arraySlice(outputAccessor.array, 0),interpolation);// Here is the trick to enable custom interpolation.// Overrides .createInterpolant in a factory method which creates custom interpolation.if (sampler.interpolation === 'CUBICSPLINE') {track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline(result) {// A CUBICSPLINE keyframe in glTF has three output values for each input value,// representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()// must be divided by three to get the interpolant's sampleSize argument.return new GLTFCubicSplineInterpolant(this.times, this.values, this.getValueSize() / 3, result);};// Workaround, provide an alternate way to know if the interpolant type is cubis spline to track.// track.getInterpolation() doesn't return valid value for custom interpolant.track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;}tracks.push(track);}}var name = animationDef.name !== undefined ? animationDef.name : 'animation_' + animationIndex;return new THREE.AnimationClip(name, undefined, tracks);});};/*** Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy* @param {number} nodeIndex* @return {Promise<THREE.Object3D>}*/GLTFParser.prototype.loadNode = function (nodeIndex) {var json = this.json;var extensions = this.extensions;var parser = this;var meshReferences = json.meshReferences;var meshUses = json.meshUses;var nodeDef = json.nodes[nodeIndex];return (function () {// .isBone isn't in glTF spec. See .markDefsif (nodeDef.isBone === true) {return Promise.resolve(new THREE.Bone());} else if (nodeDef.mesh !== undefined) {return parser.getDependency('mesh', nodeDef.mesh).then(function (mesh) {var node;if (meshReferences[nodeDef.mesh] > 1) {var instanceNum = meshUses[nodeDef.mesh]++;node = mesh.clone();node.name += '_instance_' + instanceNum;// onBeforeRender copy for Specular-Glossinessnode.onBeforeRender = mesh.onBeforeRender;for (var i = 0, il = node.children.length; i < il; i++) {node.children[i].name += '_instance_' + instanceNum;node.children[i].onBeforeRender = mesh.children[i].onBeforeRender;}} else {node = mesh;}// if weights are provided on the node, override weights on the mesh.if (nodeDef.weights !== undefined) {node.traverse(function (o) {if (!o.isMesh) return;for (var i = 0, il = nodeDef.weights.length; i < il; i++) {o.morphTargetInfluences[i] = nodeDef.weights[i];}});}return node;});} else if (nodeDef.camera !== undefined) {return parser.getDependency('camera', nodeDef.camera);} else if (nodeDef.extensions &&nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL] &&nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light !== undefined) {return parser.getDependency('light', nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light);} else {return Promise.resolve(new THREE.Object3D());}}()).then(function (node) {if (nodeDef.name !== undefined) {node.name = THREE.PropertyBinding.sanitizeNodeName(nodeDef.name);}assignExtrasToUserData(node, nodeDef);if (nodeDef.extensions) addUnknownExtensionsToUserData(extensions, node, nodeDef);if (nodeDef.matrix !== undefined) {var matrix = new THREE.Matrix4();matrix.fromArray(nodeDef.matrix);node.applyMatrix(matrix);} else {if (nodeDef.translation !== undefined) {node.position.fromArray(nodeDef.translation);}if (nodeDef.rotation !== undefined) {node.quaternion.fromArray(nodeDef.rotation);}if (nodeDef.scale !== undefined) {node.scale.fromArray(nodeDef.scale);}}return node;});};/*** Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes* @param {number} sceneIndex* @return {Promise<THREE.Scene>}*/GLTFParser.prototype.loadScene = function () {// scene node hierachy builderfunction buildNodeHierachy(nodeId, parentObject, json, parser) {var nodeDef = json.nodes[nodeId];return parser.getDependency('node', nodeId).then(function (node) {if (nodeDef.skin === undefined) return node;// build skeleton here as wellvar skinEntry;return parser.getDependency('skin', nodeDef.skin).then(function (skin) {skinEntry = skin;var pendingJoints = [];for (var i = 0, il = skinEntry.joints.length; i < il; i++) {pendingJoints.push(parser.getDependency('node', skinEntry.joints[i]));}return Promise.all(pendingJoints);}).then(function (jointNodes) {var meshes = node.isGroup === true ? node.children : [node];for (var i = 0, il = meshes.length; i < il; i++) {var mesh = meshes[i];var bones = [];var boneInverses = [];for (var j = 0, jl = jointNodes.length; j < jl; j++) {var jointNode = jointNodes[j];if (jointNode) {bones.push(jointNode);var mat = new THREE.Matrix4();if (skinEntry.inverseBindMatrices !== undefined) {mat.fromArray(skinEntry.inverseBindMatrices.array, j * 16);}boneInverses.push(mat);} else {console.warn('THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[j]);}}mesh.bind(new THREE.Skeleton(bones, boneInverses), mesh.matrixWorld);}return node;});}).then(function (node) {// build node hierachyparentObject.add(node);var pending = [];if (nodeDef.children) {var children = nodeDef.children;for (var i = 0, il = children.length; i < il; i++) {var child = children[i];pending.push(buildNodeHierachy(child, node, json, parser));}}return Promise.all(pending);});}return function loadScene(sceneIndex) {var json = this.json;var extensions = this.extensions;var sceneDef = this.json.scenes[sceneIndex];var parser = this;var scene = new THREE.Scene();if (sceneDef.name !== undefined) scene.name = sceneDef.name;assignExtrasToUserData(scene, sceneDef);if (sceneDef.extensions) addUnknownExtensionsToUserData(extensions, scene, sceneDef);var nodeIds = sceneDef.nodes || [];var pending = [];for (var i = 0, il = nodeIds.length; i < il; i++) {pending.push(buildNodeHierachy(nodeIds[i], scene, json, parser));}return Promise.all(pending).then(function () {return scene;});};}();return GLTFLoader;})();

three.js源码翻译及案例(五)-GLTFLoader.js相关推荐

  1. three.js 源码注释(九十五)extras/core/Gyroscope.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  2. three.js 源码注释(一)./Three.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  3. vue.js源码学习分享(五)

    //配置项var config = {/*** Option merge strategies (used in core/util/options)//选项合并策略*/optionMergeStra ...

  4. underscore.js源码研究(5)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  5. Evil.js源码解读

    https://github.com/duo001/evil.js 火爆全网的 Evil.js 源码解读 火爆全网的 Evil.js 源码解读 什么?黑心996公司要让你提桶跑路了? 想在离开前给你们 ...

  6. vue源码解析(3)—— Vue.js 源码构建

    Vue.js 源码构建 Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下. 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.json ...

  7. SingleSpa及qiankun入门、源码分析及案例

    文章目录 SingleSpa及qiankun入门.源码分析及案例 一.简介 1.微服务 2.什么是微前端 3.微前端的优点 4.微前端的缺点 5.如何落地微前端 6.示例 7.总结 二.SingleS ...

  8. php tire树,Immutable.js源码之List 类型的详细解析(附示例)

    本篇文章给大家带来的内容是关于Immutable.js源码之List 类型的详细解析(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 一.存储图解 我以下面这段代码为例子,画 ...

  9. 【Vue.js源码解析 一】-- 响应式原理

    前言 笔记来源:拉勾教育 大前端高薪训练营 阅读建议:建议通过左侧导航栏进行阅读 课程目标 Vue.js 的静态成员和实例成员初始化过程 首次渲染的过程 数据响应式原理 – 最核心的特性之一 准备工作 ...

最新文章

  1. PyTorch中文版官方教程来啦(附下载)
  2. Leetcode 205. 同构字符串 解题思路及C++实现
  3. Gradle善良:获得更多的依赖性见解
  4. 前缀中缀后缀表达式的计算求值
  5. w ndows10即将停止更新,微软开始警告Windows 10 v1909用户即将停止更新服务
  6. Xen Documentation - Hypercall Interfaces
  7. 清空linux当前页面内容,linux文档整理
  8. 大数据分析需掌握哪些方面
  9. 被知乎反杀,是一种什么体验?
  10. pve万兆网卡驱动_WiFi 6扩展有什么选择?Killer AX1650X无线网卡深度测评
  11. Linux设置每分钟、每小时、每天、每周、每月、每年定时执行
  12. 辛弃疾·青玉案·元夕
  13. css3中transition过渡和animation动画的区别
  14. iOS软件源怎么找,怎么下载/签名安装?
  15. 即时消息服务器eChat
  16. memcpy和memset使用时需要区分的注意点
  17. 升级Mountain Lion系统后因为 “来自身份不明开发者” 不能打开某些软件的解决方法
  18. PC端微信下的dat 文件在线解码还原成为图片
  19. swing入门教程(一) swing简介
  20. LWN:如何保护虚拟机不受恶意来源的攻击?

热门文章

  1. 数据采集模块方案 采集网口TCP主动上传模式,支持域名解析和指定IP模式上传
  2. pd.read_csv用法
  3. ntleas加载失败_模块加载失败,请确保二进制存储在指定的路径中,或者调试它以检查该二进制或相关的...
  4. asp.net+sqlserver装修管理系统-计算机毕业设计源码10327
  5. android 之旋转罗盘 风车 开发 Android 随手指旋转图片
  6. 快速认识联邦学习及其难点问题
  7. 2022-2028全球及中国先进和超高强度钢行业研究及十四五规划分析报告
  8. 贪心:排队打水—排序不等式
  9. 【MFC之小知识点】
  10. Windows 窗口停靠测试