├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── basic-sample.html ├── search-sample.html ├── third_party └── three.js │ ├── LICENSE │ ├── METADATA │ ├── README.md │ └── js │ ├── LegacyGLTFLoader.js │ ├── MTLLoader.js │ ├── OBJLoader.js │ └── three.min.js └── tiltbrush-sample.html /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | This project is not accepting pull requests at the moment. 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Poly API - Web Sample 2 | 3 | Copyright (c) 2017 Google Inc. All rights reserved. 4 | 5 | This is a sample project showing how to invoke the 6 | [Poly API](https://developers.google.com/poly) from 7 | a web app. 8 | 9 | ## How to run 10 | 11 | First, generate an API Key for the Poly API following the instructions in [the 12 | developer documentation](https://developers.google.com/poly/develop). 13 | 14 | Then, enter your API key in each of the HTML files in this sample, replacing 15 | the value of the `API_KEY` variable: 16 | 17 | const API_KEY = "*** INSERT YOUR API KEY HERE ***"; 18 | 19 | When replacing, do not leave the asterisks, replace the entire string by 20 | your API Key. 21 | 22 | Place the sample files at the root directory of your web server. 23 | If you have Python installed, you can use the `SimpleHTTPServer` module 24 | to serve a local directory for testing: 25 | 26 | cd /path/to/sample 27 | python -m SimpleHTTPServer 8000 28 | 29 | These are the available samples: 30 | 31 | * **basic-sample.html**. Shows how to load and display a single asset 32 | with known ID. 33 | 34 | * **search-sample.html**. Shows how to search for assets and display them. 35 | 36 | * **tiltbrush-sample.html**. Shows how to load and display a Tilt Brush sketch. 37 | 38 | ## License 39 | 40 | For license information, refer to the `LICENSE` file. 41 | 42 | -------------------------------------------------------------------------------- /basic-sample.html: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 49 | 50 | 51 | 52 |
53 | 54 |
55 | Title
56 | by Author 57 |
58 | 59 | 60 | 61 | 62 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /search-sample.html: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 81 | 82 | 83 | 84 | 88 | 89 | 90 |
91 | Title
92 | by Author 93 |
94 | 95 | 96 | 97 | 98 | 277 | 278 | 279 | -------------------------------------------------------------------------------- /third_party/three.js/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright © 2010-2017 three.js authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /third_party/three.js/METADATA: -------------------------------------------------------------------------------- 1 | name: "three.js" 2 | description: 3 | "Lightweight 3D library for WebGL." 4 | 5 | third_party { 6 | url { 7 | type: HOMEPAGE 8 | value: "https://github.com/mrdoob/three.js" 9 | } 10 | url { 11 | type: GIT 12 | value: "https://github.com/mrdoob/three.js" 13 | } 14 | version: "62a32a2db8a78b1b8e752c909a68302e83f42202" 15 | last_upgrade_date { year: 2017 month: 11 day: 15 } 16 | license_type: NOTICE 17 | local_modifications: 18 | "Removed all unneeded files, kept minimal subset of needed files in" 19 | "js/ subdirectory." 20 | } 21 | -------------------------------------------------------------------------------- /third_party/three.js/README.md: -------------------------------------------------------------------------------- 1 | three.js 2 | ======== 3 | 4 | [![Gitter][gitter-badge]][gitter-badge-url] 5 | [![Latest NPM release][npm-badge]][npm-badge-url] 6 | [![License][license-badge]][license-badge-url] 7 | [![Dependencies][dependencies-badge]][dependencies-badge-url] 8 | [![Dev Dependencies][devDependencies-badge]][devDependencies-badge-url] 9 | 10 | #### JavaScript 3D library #### 11 | 12 | The aim of the project is to create an easy to use, lightweight, 3D library. The library provides <canvas>, <svg>, CSS3D and WebGL renderers. 13 | 14 | [Examples](http://threejs.org/examples/) — 15 | [Documentation](http://threejs.org/docs/) — 16 | [Wiki](https://github.com/mrdoob/three.js/wiki) — 17 | [Migrating](https://github.com/mrdoob/three.js/wiki/Migration-Guide) — 18 | [Help](http://stackoverflow.com/questions/tagged/three.js) 19 | 20 | ### Usage ### 21 | 22 | Download the [minified library](http://threejs.org/build/three.min.js) and include it in your HTML, or install and import it as a [module](http://threejs.org/docs/#manual/introduction/Import-via-modules), 23 | Alternatively see [how to build the library yourself](https://github.com/mrdoob/three.js/wiki/Build-instructions). 24 | 25 | ```html 26 | 27 | ``` 28 | 29 | This code creates a scene, a camera, and a geometric cube, and it adds the cube to the scene. It then creates a `WebGL` renderer for the scene and camera, and it adds that viewport to the document.body element. Finally, it animates the cube within the scene for the camera. 30 | 31 | ```javascript 32 | var camera, scene, renderer; 33 | var geometry, material, mesh; 34 | 35 | init(); 36 | animate(); 37 | 38 | function init() { 39 | 40 | camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 ); 41 | camera.position.z = 1; 42 | 43 | scene = new THREE.Scene(); 44 | 45 | geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 ); 46 | material = new THREE.MeshNormalMaterial(); 47 | 48 | mesh = new THREE.Mesh( geometry, material ); 49 | scene.add( mesh ); 50 | 51 | renderer = new THREE.WebGLRenderer( { antialias: true } ); 52 | renderer.setSize( window.innerWidth, window.innerHeight ); 53 | document.body.appendChild( renderer.domElement ); 54 | 55 | } 56 | 57 | function animate() { 58 | 59 | requestAnimationFrame( animate ); 60 | 61 | mesh.rotation.x += 0.01; 62 | mesh.rotation.y += 0.02; 63 | 64 | renderer.render( scene, camera ); 65 | 66 | } 67 | ``` 68 | 69 | If everything went well you should see [this](https://jsfiddle.net/f2Lommf5/). 70 | 71 | ### Change log ### 72 | 73 | [releases](https://github.com/mrdoob/three.js/releases) 74 | 75 | 76 | [gitter-badge]: https://badges.gitter.im/mrdoob/three.js.svg 77 | [gitter-badge-url]: https://gitter.im/mrdoob/three.js 78 | [npm-badge]: https://img.shields.io/npm/v/three.svg 79 | [npm-badge-url]: https://www.npmjs.com/package/three 80 | [license-badge]: https://img.shields.io/npm/l/three.svg 81 | [license-badge-url]: ./LICENSE 82 | [dependencies-badge]: https://img.shields.io/david/mrdoob/three.js.svg 83 | [dependencies-badge-url]: https://david-dm.org/mrdoob/three.js 84 | [devDependencies-badge]: https://img.shields.io/david/dev/mrdoob/three.js.svg 85 | [devDependencies-badge-url]: https://david-dm.org/mrdoob/three.js#info=devDependencies 86 | -------------------------------------------------------------------------------- /third_party/three.js/js/LegacyGLTFLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Rich Tibbett / https://github.com/richtr 3 | * @author mrdoob / http://mrdoob.com/ 4 | * @author Tony Parisi / http://www.tonyparisi.com/ 5 | * @author Takahiro / https://github.com/takahirox 6 | */ 7 | 8 | THREE.LegacyGLTFLoader = ( function () { 9 | 10 | function LegacyGLTFLoader( manager ) { 11 | 12 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 13 | 14 | } 15 | 16 | LegacyGLTFLoader.prototype = { 17 | 18 | constructor: LegacyGLTFLoader, 19 | 20 | crossOrigin: 'Anonymous', 21 | 22 | load: function ( url, onLoad, onProgress, onError ) { 23 | 24 | var scope = this; 25 | 26 | var path = this.path && ( typeof this.path === "string" ) ? this.path : THREE.Loader.prototype.extractUrlBase( url ); 27 | 28 | var loader = new THREE.FileLoader( scope.manager ); 29 | 30 | loader.setResponseType( 'arraybuffer' ); 31 | 32 | loader.load( url, function ( data ) { 33 | 34 | scope.parse( data, onLoad, path ); 35 | 36 | }, onProgress, onError ); 37 | 38 | }, 39 | 40 | setCrossOrigin: function ( value ) { 41 | 42 | this.crossOrigin = value; 43 | 44 | }, 45 | 46 | setPath: function ( value ) { 47 | 48 | this.path = value; 49 | 50 | }, 51 | 52 | parse: function ( data, callback, path ) { 53 | 54 | var content; 55 | var extensions = {}; 56 | 57 | var magic = convertUint8ArrayToString( new Uint8Array( data, 0, 4 ) ); 58 | 59 | if ( magic === BINARY_EXTENSION_HEADER_DEFAULTS.magic ) { 60 | 61 | extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data ); 62 | content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content; 63 | 64 | } else { 65 | 66 | content = convertUint8ArrayToString( new Uint8Array( data ) ); 67 | 68 | } 69 | 70 | var json = JSON.parse( content ); 71 | 72 | if ( json.extensionsUsed && json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_COMMON ) >= 0 ) { 73 | 74 | extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] = new GLTFMaterialsCommonExtension( json ); 75 | 76 | } 77 | 78 | console.time( 'LegacyGLTFLoader' ); 79 | 80 | var parser = new GLTFParser( json, extensions, { 81 | 82 | path: path || this.path, 83 | crossOrigin: this.crossOrigin 84 | 85 | } ); 86 | 87 | parser.parse( function ( scene, scenes, cameras, animations ) { 88 | 89 | console.timeEnd( 'LegacyGLTFLoader' ); 90 | 91 | var glTF = { 92 | "scene": scene, 93 | "scenes": scenes, 94 | "cameras": cameras, 95 | "animations": animations 96 | }; 97 | 98 | callback( glTF ); 99 | 100 | } ); 101 | 102 | } 103 | 104 | }; 105 | 106 | /* GLTFREGISTRY */ 107 | 108 | function GLTFRegistry() { 109 | 110 | var objects = {}; 111 | 112 | return { 113 | 114 | get: function ( key ) { 115 | 116 | return objects[ key ]; 117 | 118 | }, 119 | 120 | add: function ( key, object ) { 121 | 122 | objects[ key ] = object; 123 | 124 | }, 125 | 126 | remove: function ( key ) { 127 | 128 | delete objects[ key ]; 129 | 130 | }, 131 | 132 | removeAll: function () { 133 | 134 | objects = {}; 135 | 136 | }, 137 | 138 | update: function ( scene, camera ) { 139 | 140 | for ( var name in objects ) { 141 | 142 | var object = objects[ name ]; 143 | 144 | if ( object.update ) { 145 | 146 | object.update( scene, camera ); 147 | 148 | } 149 | 150 | } 151 | 152 | } 153 | 154 | }; 155 | 156 | } 157 | 158 | /* GLTFSHADERS */ 159 | 160 | LegacyGLTFLoader.Shaders = { 161 | 162 | update: function () { 163 | 164 | console.warn( 'THREE.LegacyGLTFLoader.Shaders has been deprecated, and now updates automatically.' ); 165 | 166 | } 167 | 168 | }; 169 | 170 | /* GLTFSHADER */ 171 | 172 | function GLTFShader( targetNode, allNodes ) { 173 | 174 | var boundUniforms = {}; 175 | 176 | // bind each uniform to its source node 177 | 178 | var uniforms = targetNode.material.uniforms; 179 | 180 | for ( var uniformId in uniforms ) { 181 | 182 | var uniform = uniforms[ uniformId ]; 183 | 184 | if ( uniform.semantic ) { 185 | 186 | var sourceNodeRef = uniform.node; 187 | 188 | var sourceNode = targetNode; 189 | 190 | if ( sourceNodeRef ) { 191 | 192 | sourceNode = allNodes[ sourceNodeRef ]; 193 | 194 | } 195 | 196 | boundUniforms[ uniformId ] = { 197 | semantic: uniform.semantic, 198 | sourceNode: sourceNode, 199 | targetNode: targetNode, 200 | uniform: uniform 201 | }; 202 | 203 | } 204 | 205 | } 206 | 207 | this.boundUniforms = boundUniforms; 208 | this._m4 = new THREE.Matrix4(); 209 | 210 | } 211 | 212 | // Update - update all the uniform values 213 | GLTFShader.prototype.update = function ( scene, camera ) { 214 | 215 | var boundUniforms = this.boundUniforms; 216 | 217 | for ( var name in boundUniforms ) { 218 | 219 | var boundUniform = boundUniforms[ name ]; 220 | 221 | switch ( boundUniform.semantic ) { 222 | 223 | case "MODELVIEW": 224 | 225 | var m4 = boundUniform.uniform.value; 226 | m4.multiplyMatrices( camera.matrixWorldInverse, boundUniform.sourceNode.matrixWorld ); 227 | break; 228 | 229 | case "MODELVIEWINVERSETRANSPOSE": 230 | 231 | var m3 = boundUniform.uniform.value; 232 | this._m4.multiplyMatrices( camera.matrixWorldInverse, boundUniform.sourceNode.matrixWorld ); 233 | m3.getNormalMatrix( this._m4 ); 234 | break; 235 | 236 | case "PROJECTION": 237 | 238 | var m4 = boundUniform.uniform.value; 239 | m4.copy( camera.projectionMatrix ); 240 | break; 241 | 242 | case "JOINTMATRIX": 243 | 244 | var m4v = boundUniform.uniform.value; 245 | 246 | for ( var mi = 0; mi < m4v.length; mi ++ ) { 247 | 248 | // So it goes like this: 249 | // SkinnedMesh world matrix is already baked into MODELVIEW; 250 | // transform joints to local space, 251 | // then transform using joint's inverse 252 | m4v[ mi ] 253 | .getInverse( boundUniform.sourceNode.matrixWorld ) 254 | .multiply( boundUniform.targetNode.skeleton.bones[ mi ].matrixWorld ) 255 | .multiply( boundUniform.targetNode.skeleton.boneInverses[ mi ] ) 256 | .multiply( boundUniform.targetNode.bindMatrix ); 257 | 258 | } 259 | 260 | break; 261 | 262 | default : 263 | 264 | console.warn( "Unhandled shader semantic: " + boundUniform.semantic ); 265 | break; 266 | 267 | } 268 | 269 | } 270 | 271 | }; 272 | 273 | 274 | /* ANIMATION */ 275 | 276 | LegacyGLTFLoader.Animations = { 277 | 278 | update: function () { 279 | 280 | console.warn( 'THREE.LegacyGLTFLoader.Animation has been deprecated. Use THREE.AnimationMixer instead.' ); 281 | 282 | } 283 | 284 | }; 285 | 286 | /*********************************/ 287 | /********** EXTENSIONS ***********/ 288 | /*********************************/ 289 | 290 | var EXTENSIONS = { 291 | KHR_BINARY_GLTF: 'KHR_binary_glTF', 292 | KHR_MATERIALS_COMMON: 'KHR_materials_common' 293 | }; 294 | 295 | /* MATERIALS COMMON EXTENSION */ 296 | 297 | function GLTFMaterialsCommonExtension( json ) { 298 | 299 | this.name = EXTENSIONS.KHR_MATERIALS_COMMON; 300 | 301 | this.lights = {}; 302 | 303 | var extension = ( json.extensions && json.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) || {}; 304 | var lights = extension.lights || {}; 305 | 306 | for ( var lightId in lights ) { 307 | 308 | var light = lights[ lightId ]; 309 | var lightNode; 310 | 311 | var lightParams = light[ light.type ]; 312 | var color = new THREE.Color().fromArray( lightParams.color ); 313 | 314 | switch ( light.type ) { 315 | 316 | case "directional": 317 | lightNode = new THREE.DirectionalLight( color ); 318 | lightNode.position.set( 0, 0, 1 ); 319 | break; 320 | 321 | case "point": 322 | lightNode = new THREE.PointLight( color ); 323 | break; 324 | 325 | case "spot": 326 | lightNode = new THREE.SpotLight( color ); 327 | lightNode.position.set( 0, 0, 1 ); 328 | break; 329 | 330 | case "ambient": 331 | lightNode = new THREE.AmbientLight( color ); 332 | break; 333 | 334 | } 335 | 336 | if ( lightNode ) { 337 | 338 | this.lights[ lightId ] = lightNode; 339 | 340 | } 341 | 342 | } 343 | 344 | } 345 | 346 | /* BINARY EXTENSION */ 347 | 348 | var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF'; 349 | 350 | var BINARY_EXTENSION_HEADER_DEFAULTS = { magic: 'glTF', version: 1, contentFormat: 0 }; 351 | 352 | var BINARY_EXTENSION_HEADER_LENGTH = 20; 353 | 354 | function GLTFBinaryExtension( data ) { 355 | 356 | this.name = EXTENSIONS.KHR_BINARY_GLTF; 357 | 358 | var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH ); 359 | 360 | var header = { 361 | magic: convertUint8ArrayToString( new Uint8Array( data.slice( 0, 4 ) ) ), 362 | version: headerView.getUint32( 4, true ), 363 | length: headerView.getUint32( 8, true ), 364 | contentLength: headerView.getUint32( 12, true ), 365 | contentFormat: headerView.getUint32( 16, true ) 366 | }; 367 | 368 | for ( var key in BINARY_EXTENSION_HEADER_DEFAULTS ) { 369 | 370 | var value = BINARY_EXTENSION_HEADER_DEFAULTS[ key ]; 371 | 372 | if ( header[ key ] !== value ) { 373 | 374 | throw new Error( 'Unsupported glTF-Binary header: Expected "%s" to be "%s".', key, value ); 375 | 376 | } 377 | 378 | } 379 | 380 | var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH, header.contentLength ); 381 | 382 | this.header = header; 383 | this.content = convertUint8ArrayToString( contentArray ); 384 | this.body = data.slice( BINARY_EXTENSION_HEADER_LENGTH + header.contentLength, header.length ); 385 | 386 | } 387 | 388 | GLTFBinaryExtension.prototype.loadShader = function ( shader, bufferViews ) { 389 | 390 | var bufferView = bufferViews[ shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].bufferView ]; 391 | var array = new Uint8Array( bufferView ); 392 | 393 | return convertUint8ArrayToString( array ); 394 | 395 | }; 396 | 397 | GLTFBinaryExtension.prototype.loadTextureSourceUri = function ( source, bufferViews ) { 398 | 399 | var metadata = source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ]; 400 | var bufferView = bufferViews[ metadata.bufferView ]; 401 | var stringData = convertUint8ArrayToString( new Uint8Array( bufferView ) ); 402 | 403 | return 'data:' + metadata.mimeType + ';base64,' + btoa( stringData ); 404 | 405 | }; 406 | 407 | /*********************************/ 408 | /********** INTERNALS ************/ 409 | /*********************************/ 410 | 411 | /* CONSTANTS */ 412 | 413 | var WEBGL_CONSTANTS = { 414 | FLOAT: 5126, 415 | //FLOAT_MAT2: 35674, 416 | FLOAT_MAT3: 35675, 417 | FLOAT_MAT4: 35676, 418 | FLOAT_VEC2: 35664, 419 | FLOAT_VEC3: 35665, 420 | FLOAT_VEC4: 35666, 421 | LINEAR: 9729, 422 | REPEAT: 10497, 423 | SAMPLER_2D: 35678, 424 | TRIANGLES: 4, 425 | LINES: 1, 426 | UNSIGNED_BYTE: 5121, 427 | UNSIGNED_SHORT: 5123, 428 | 429 | VERTEX_SHADER: 35633, 430 | FRAGMENT_SHADER: 35632 431 | }; 432 | 433 | var WEBGL_TYPE = { 434 | 5126: Number, 435 | //35674: THREE.Matrix2, 436 | 35675: THREE.Matrix3, 437 | 35676: THREE.Matrix4, 438 | 35664: THREE.Vector2, 439 | 35665: THREE.Vector3, 440 | 35666: THREE.Vector4, 441 | 35678: THREE.Texture 442 | }; 443 | 444 | var WEBGL_COMPONENT_TYPES = { 445 | 5120: Int8Array, 446 | 5121: Uint8Array, 447 | 5122: Int16Array, 448 | 5123: Uint16Array, 449 | 5125: Uint32Array, 450 | 5126: Float32Array 451 | }; 452 | 453 | var WEBGL_FILTERS = { 454 | 9728: THREE.NearestFilter, 455 | 9729: THREE.LinearFilter, 456 | 9984: THREE.NearestMipMapNearestFilter, 457 | 9985: THREE.LinearMipMapNearestFilter, 458 | 9986: THREE.NearestMipMapLinearFilter, 459 | 9987: THREE.LinearMipMapLinearFilter 460 | }; 461 | 462 | var WEBGL_WRAPPINGS = { 463 | 33071: THREE.ClampToEdgeWrapping, 464 | 33648: THREE.MirroredRepeatWrapping, 465 | 10497: THREE.RepeatWrapping 466 | }; 467 | 468 | var WEBGL_TEXTURE_FORMATS = { 469 | 6406: THREE.AlphaFormat, 470 | 6407: THREE.RGBFormat, 471 | 6408: THREE.RGBAFormat, 472 | 6409: THREE.LuminanceFormat, 473 | 6410: THREE.LuminanceAlphaFormat 474 | }; 475 | 476 | var WEBGL_TEXTURE_DATATYPES = { 477 | 5121: THREE.UnsignedByteType, 478 | 32819: THREE.UnsignedShort4444Type, 479 | 32820: THREE.UnsignedShort5551Type, 480 | 33635: THREE.UnsignedShort565Type 481 | }; 482 | 483 | var WEBGL_SIDES = { 484 | 1028: THREE.BackSide, // Culling front 485 | 1029: THREE.FrontSide // Culling back 486 | //1032: THREE.NoSide // Culling front and back, what to do? 487 | }; 488 | 489 | var WEBGL_DEPTH_FUNCS = { 490 | 512: THREE.NeverDepth, 491 | 513: THREE.LessDepth, 492 | 514: THREE.EqualDepth, 493 | 515: THREE.LessEqualDepth, 494 | 516: THREE.GreaterEqualDepth, 495 | 517: THREE.NotEqualDepth, 496 | 518: THREE.GreaterEqualDepth, 497 | 519: THREE.AlwaysDepth 498 | }; 499 | 500 | var WEBGL_BLEND_EQUATIONS = { 501 | 32774: THREE.AddEquation, 502 | 32778: THREE.SubtractEquation, 503 | 32779: THREE.ReverseSubtractEquation 504 | }; 505 | 506 | var WEBGL_BLEND_FUNCS = { 507 | 0: THREE.ZeroFactor, 508 | 1: THREE.OneFactor, 509 | 768: THREE.SrcColorFactor, 510 | 769: THREE.OneMinusSrcColorFactor, 511 | 770: THREE.SrcAlphaFactor, 512 | 771: THREE.OneMinusSrcAlphaFactor, 513 | 772: THREE.DstAlphaFactor, 514 | 773: THREE.OneMinusDstAlphaFactor, 515 | 774: THREE.DstColorFactor, 516 | 775: THREE.OneMinusDstColorFactor, 517 | 776: THREE.SrcAlphaSaturateFactor 518 | // The followings are not supported by Three.js yet 519 | //32769: CONSTANT_COLOR, 520 | //32770: ONE_MINUS_CONSTANT_COLOR, 521 | //32771: CONSTANT_ALPHA, 522 | //32772: ONE_MINUS_CONSTANT_COLOR 523 | }; 524 | 525 | var WEBGL_TYPE_SIZES = { 526 | 'SCALAR': 1, 527 | 'VEC2': 2, 528 | 'VEC3': 3, 529 | 'VEC4': 4, 530 | 'MAT2': 4, 531 | 'MAT3': 9, 532 | 'MAT4': 16 533 | }; 534 | 535 | var PATH_PROPERTIES = { 536 | scale: 'scale', 537 | translation: 'position', 538 | rotation: 'quaternion' 539 | }; 540 | 541 | var INTERPOLATION = { 542 | LINEAR: THREE.InterpolateLinear, 543 | STEP: THREE.InterpolateDiscrete 544 | }; 545 | 546 | var STATES_ENABLES = { 547 | 2884: 'CULL_FACE', 548 | 2929: 'DEPTH_TEST', 549 | 3042: 'BLEND', 550 | 3089: 'SCISSOR_TEST', 551 | 32823: 'POLYGON_OFFSET_FILL', 552 | 32926: 'SAMPLE_ALPHA_TO_COVERAGE' 553 | }; 554 | 555 | /* UTILITY FUNCTIONS */ 556 | 557 | function _each( object, callback, thisObj ) { 558 | 559 | if ( !object ) { 560 | return Promise.resolve(); 561 | } 562 | 563 | var results; 564 | var fns = []; 565 | 566 | if ( Object.prototype.toString.call( object ) === '[object Array]' ) { 567 | 568 | results = []; 569 | 570 | var length = object.length; 571 | 572 | for ( var idx = 0; idx < length; idx ++ ) { 573 | 574 | var value = callback.call( thisObj || this, object[ idx ], idx ); 575 | 576 | if ( value ) { 577 | 578 | fns.push( value ); 579 | 580 | if ( value instanceof Promise ) { 581 | 582 | value.then( function( key, value ) { 583 | 584 | results[ key ] = value; 585 | 586 | }.bind( this, idx )); 587 | 588 | } else { 589 | 590 | results[ idx ] = value; 591 | 592 | } 593 | 594 | } 595 | 596 | } 597 | 598 | } else { 599 | 600 | results = {}; 601 | 602 | for ( var key in object ) { 603 | 604 | if ( object.hasOwnProperty( key ) ) { 605 | 606 | var value = callback.call( thisObj || this, object[ key ], key ); 607 | 608 | if ( value ) { 609 | 610 | fns.push( value ); 611 | 612 | if ( value instanceof Promise ) { 613 | 614 | value.then( function( key, value ) { 615 | 616 | results[ key ] = value; 617 | 618 | }.bind( this, key )); 619 | 620 | } else { 621 | 622 | results[ key ] = value; 623 | 624 | } 625 | 626 | } 627 | 628 | } 629 | 630 | } 631 | 632 | } 633 | 634 | return Promise.all( fns ).then( function() { 635 | 636 | return results; 637 | 638 | }); 639 | 640 | } 641 | 642 | function resolveURL( url, path ) { 643 | 644 | // Invalid URL 645 | if ( typeof url !== 'string' || url === '' ) 646 | return ''; 647 | 648 | // Absolute URL http://,https://,// 649 | if ( /^(https?:)?\/\//i.test( url ) ) { 650 | 651 | return url; 652 | 653 | } 654 | 655 | // Data URI 656 | if ( /^data:.*,.*$/i.test( url ) ) { 657 | 658 | return url; 659 | 660 | } 661 | 662 | // Relative URL 663 | return ( path || '' ) + url; 664 | 665 | } 666 | 667 | function convertUint8ArrayToString( array ) { 668 | 669 | if ( window.TextDecoder !== undefined ) { 670 | 671 | return new TextDecoder().decode( array ); 672 | 673 | } 674 | 675 | // Avoid the String.fromCharCode.apply(null, array) shortcut, which 676 | // throws a "maximum call stack size exceeded" error for large arrays. 677 | 678 | var s = ''; 679 | 680 | for ( var i = 0, il = array.length; i < il; i ++ ) { 681 | 682 | s += String.fromCharCode( array[ i ] ); 683 | 684 | } 685 | 686 | return s; 687 | 688 | } 689 | 690 | // Three.js seems too dependent on attribute names so globally 691 | // replace those in the shader code 692 | function replaceTHREEShaderAttributes( shaderText, technique ) { 693 | 694 | // Expected technique attributes 695 | var attributes = {}; 696 | 697 | for ( var attributeId in technique.attributes ) { 698 | 699 | var pname = technique.attributes[ attributeId ]; 700 | 701 | var param = technique.parameters[ pname ]; 702 | var atype = param.type; 703 | var semantic = param.semantic; 704 | 705 | attributes[ attributeId ] = { 706 | type: atype, 707 | semantic: semantic 708 | }; 709 | 710 | } 711 | 712 | // Figure out which attributes to change in technique 713 | 714 | var shaderParams = technique.parameters; 715 | var shaderAttributes = technique.attributes; 716 | var params = {}; 717 | 718 | for ( var attributeId in attributes ) { 719 | 720 | var pname = shaderAttributes[ attributeId ]; 721 | var shaderParam = shaderParams[ pname ]; 722 | var semantic = shaderParam.semantic; 723 | if ( semantic ) { 724 | 725 | params[ attributeId ] = shaderParam; 726 | 727 | } 728 | 729 | } 730 | 731 | for ( var pname in params ) { 732 | 733 | var param = params[ pname ]; 734 | var semantic = param.semantic; 735 | 736 | var regEx = new RegExp( "\\b" + pname + "\\b", "g" ); 737 | 738 | switch ( semantic ) { 739 | 740 | case "POSITION": 741 | 742 | shaderText = shaderText.replace( regEx, 'position' ); 743 | break; 744 | 745 | case "NORMAL": 746 | 747 | shaderText = shaderText.replace( regEx, 'normal' ); 748 | break; 749 | 750 | case 'TEXCOORD_0': 751 | case 'TEXCOORD0': 752 | case 'TEXCOORD': 753 | 754 | shaderText = shaderText.replace( regEx, 'uv' ); 755 | break; 756 | 757 | case 'TEXCOORD_1': 758 | 759 | shaderText = shaderText.replace( regEx, 'uv2' ); 760 | break; 761 | 762 | case 'COLOR_0': 763 | case 'COLOR0': 764 | case 'COLOR': 765 | 766 | shaderText = shaderText.replace( regEx, 'color' ); 767 | break; 768 | 769 | case "WEIGHT": 770 | 771 | shaderText = shaderText.replace( regEx, 'skinWeight' ); 772 | break; 773 | 774 | case "JOINT": 775 | 776 | shaderText = shaderText.replace( regEx, 'skinIndex' ); 777 | break; 778 | 779 | } 780 | 781 | } 782 | 783 | return shaderText; 784 | 785 | } 786 | 787 | function createDefaultMaterial() { 788 | 789 | return new THREE.MeshPhongMaterial( { 790 | color: 0x00000, 791 | emissive: 0x888888, 792 | specular: 0x000000, 793 | shininess: 0, 794 | transparent: false, 795 | depthTest: true, 796 | side: THREE.FrontSide 797 | } ); 798 | 799 | } 800 | 801 | // Deferred constructor for RawShaderMaterial types 802 | function DeferredShaderMaterial( params ) { 803 | 804 | this.isDeferredShaderMaterial = true; 805 | 806 | this.params = params; 807 | 808 | } 809 | 810 | DeferredShaderMaterial.prototype.create = function () { 811 | 812 | var uniforms = THREE.UniformsUtils.clone( this.params.uniforms ); 813 | 814 | for ( var uniformId in this.params.uniforms ) { 815 | 816 | var originalUniform = this.params.uniforms[ uniformId ]; 817 | 818 | if ( originalUniform.value instanceof THREE.Texture ) { 819 | 820 | uniforms[ uniformId ].value = originalUniform.value; 821 | uniforms[ uniformId ].value.needsUpdate = true; 822 | 823 | } 824 | 825 | uniforms[ uniformId ].semantic = originalUniform.semantic; 826 | uniforms[ uniformId ].node = originalUniform.node; 827 | 828 | } 829 | 830 | this.params.uniforms = uniforms; 831 | 832 | return new THREE.RawShaderMaterial( this.params ); 833 | 834 | }; 835 | 836 | /* GLTF PARSER */ 837 | 838 | function GLTFParser( json, extensions, options ) { 839 | 840 | this.json = json || {}; 841 | this.extensions = extensions || {}; 842 | this.options = options || {}; 843 | 844 | // loader object cache 845 | this.cache = new GLTFRegistry(); 846 | 847 | } 848 | 849 | GLTFParser.prototype._withDependencies = function ( dependencies ) { 850 | 851 | var _dependencies = {}; 852 | 853 | for ( var i = 0; i < dependencies.length; i ++ ) { 854 | 855 | var dependency = dependencies[ i ]; 856 | var fnName = "load" + dependency.charAt( 0 ).toUpperCase() + dependency.slice( 1 ); 857 | 858 | var cached = this.cache.get( dependency ); 859 | 860 | if ( cached !== undefined ) { 861 | 862 | _dependencies[ dependency ] = cached; 863 | 864 | } else if ( this[ fnName ] ) { 865 | 866 | var fn = this[ fnName ](); 867 | this.cache.add( dependency, fn ); 868 | 869 | _dependencies[ dependency ] = fn; 870 | 871 | } 872 | 873 | } 874 | 875 | return _each( _dependencies, function ( dependency ) { 876 | 877 | return dependency; 878 | 879 | } ); 880 | 881 | }; 882 | 883 | GLTFParser.prototype.parse = function ( callback ) { 884 | 885 | var json = this.json; 886 | 887 | // Clear the loader cache 888 | this.cache.removeAll(); 889 | 890 | // Fire the callback on complete 891 | this._withDependencies( [ 892 | 893 | "scenes", 894 | "cameras", 895 | "animations" 896 | 897 | ] ).then( function ( dependencies ) { 898 | 899 | var scenes = []; 900 | 901 | for ( var name in dependencies.scenes ) { 902 | 903 | scenes.push( dependencies.scenes[ name ] ); 904 | 905 | } 906 | 907 | var scene = json.scene !== undefined ? dependencies.scenes[ json.scene ] : scenes[ 0 ]; 908 | 909 | var cameras = []; 910 | 911 | for ( var name in dependencies.cameras ) { 912 | 913 | var camera = dependencies.cameras[ name ]; 914 | cameras.push( camera ); 915 | 916 | } 917 | 918 | var animations = []; 919 | 920 | for ( var name in dependencies.animations ) { 921 | 922 | animations.push( dependencies.animations[ name ] ); 923 | 924 | } 925 | 926 | callback( scene, scenes, cameras, animations ); 927 | 928 | } ); 929 | 930 | }; 931 | 932 | GLTFParser.prototype.loadShaders = function () { 933 | 934 | var json = this.json; 935 | var extensions = this.extensions; 936 | var options = this.options; 937 | 938 | return this._withDependencies( [ 939 | 940 | "bufferViews" 941 | 942 | ] ).then( function ( dependencies ) { 943 | 944 | return _each( json.shaders, function ( shader ) { 945 | 946 | if ( shader.extensions && shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) { 947 | 948 | return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadShader( shader, dependencies.bufferViews ); 949 | 950 | } 951 | 952 | return new Promise( function ( resolve ) { 953 | 954 | var loader = new THREE.FileLoader(); 955 | loader.setResponseType( 'text' ); 956 | loader.load( resolveURL( shader.uri, options.path ), function ( shaderText ) { 957 | 958 | resolve( shaderText ); 959 | 960 | } ); 961 | 962 | } ); 963 | 964 | } ); 965 | 966 | } ); 967 | 968 | }; 969 | 970 | GLTFParser.prototype.loadBuffers = function () { 971 | 972 | var json = this.json; 973 | var extensions = this.extensions; 974 | var options = this.options; 975 | 976 | return _each( json.buffers, function ( buffer, name ) { 977 | 978 | if ( name === BINARY_EXTENSION_BUFFER_NAME ) { 979 | 980 | return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body; 981 | 982 | } 983 | 984 | if ( buffer.type === 'arraybuffer' || buffer.type === undefined ) { 985 | 986 | return new Promise( function ( resolve ) { 987 | 988 | var loader = new THREE.FileLoader(); 989 | loader.setResponseType( 'arraybuffer' ); 990 | loader.load( resolveURL( buffer.uri, options.path ), function ( buffer ) { 991 | 992 | resolve( buffer ); 993 | 994 | } ); 995 | 996 | } ); 997 | 998 | } else { 999 | 1000 | console.warn( 'THREE.LegacyGLTFLoader: ' + buffer.type + ' buffer type is not supported' ); 1001 | 1002 | } 1003 | 1004 | } ); 1005 | 1006 | }; 1007 | 1008 | GLTFParser.prototype.loadBufferViews = function () { 1009 | 1010 | var json = this.json; 1011 | 1012 | return this._withDependencies( [ 1013 | 1014 | "buffers" 1015 | 1016 | ] ).then( function ( dependencies ) { 1017 | 1018 | return _each( json.bufferViews, function ( bufferView ) { 1019 | 1020 | var arraybuffer = dependencies.buffers[ bufferView.buffer ]; 1021 | 1022 | var byteLength = bufferView.byteLength !== undefined ? bufferView.byteLength : 0; 1023 | 1024 | return arraybuffer.slice( bufferView.byteOffset, bufferView.byteOffset + byteLength ); 1025 | 1026 | } ); 1027 | 1028 | } ); 1029 | 1030 | }; 1031 | 1032 | GLTFParser.prototype.loadAccessors = function () { 1033 | 1034 | var json = this.json; 1035 | 1036 | return this._withDependencies( [ 1037 | 1038 | "bufferViews" 1039 | 1040 | ] ).then( function ( dependencies ) { 1041 | 1042 | return _each( json.accessors, function ( accessor ) { 1043 | 1044 | var arraybuffer = dependencies.bufferViews[ accessor.bufferView ]; 1045 | var itemSize = WEBGL_TYPE_SIZES[ accessor.type ]; 1046 | var TypedArray = WEBGL_COMPONENT_TYPES[ accessor.componentType ]; 1047 | 1048 | // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12. 1049 | var elementBytes = TypedArray.BYTES_PER_ELEMENT; 1050 | var itemBytes = elementBytes * itemSize; 1051 | 1052 | // The buffer is not interleaved if the stride is the item size in bytes. 1053 | if ( accessor.byteStride && accessor.byteStride !== itemBytes ) { 1054 | 1055 | // Use the full buffer if it's interleaved. 1056 | var array = new TypedArray( arraybuffer ); 1057 | 1058 | // Integer parameters to IB/IBA are in array elements, not bytes. 1059 | var ib = new THREE.InterleavedBuffer( array, accessor.byteStride / elementBytes ); 1060 | 1061 | return new THREE.InterleavedBufferAttribute( ib, itemSize, accessor.byteOffset / elementBytes ); 1062 | 1063 | } else { 1064 | 1065 | array = new TypedArray( arraybuffer, accessor.byteOffset, accessor.count * itemSize ); 1066 | 1067 | return new THREE.BufferAttribute( array, itemSize ); 1068 | 1069 | } 1070 | 1071 | } ); 1072 | 1073 | } ); 1074 | 1075 | }; 1076 | 1077 | GLTFParser.prototype.loadTextures = function () { 1078 | 1079 | var json = this.json; 1080 | var extensions = this.extensions; 1081 | var options = this.options; 1082 | 1083 | return this._withDependencies( [ 1084 | 1085 | "bufferViews" 1086 | 1087 | ] ).then( function ( dependencies ) { 1088 | 1089 | return _each( json.textures, function ( texture ) { 1090 | 1091 | if ( texture.source ) { 1092 | 1093 | return new Promise( function ( resolve ) { 1094 | 1095 | var source = json.images[ texture.source ]; 1096 | var sourceUri = source.uri; 1097 | 1098 | if ( source.extensions && source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) { 1099 | 1100 | sourceUri = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadTextureSourceUri( source, dependencies.bufferViews ); 1101 | 1102 | } 1103 | 1104 | var textureLoader = THREE.Loader.Handlers.get( sourceUri ); 1105 | 1106 | if ( textureLoader === null ) { 1107 | 1108 | textureLoader = new THREE.TextureLoader(); 1109 | 1110 | } 1111 | 1112 | textureLoader.setCrossOrigin( options.crossOrigin ); 1113 | 1114 | textureLoader.load( resolveURL( sourceUri, options.path ), function ( _texture ) { 1115 | 1116 | _texture.flipY = false; 1117 | 1118 | if ( texture.name !== undefined ) _texture.name = texture.name; 1119 | 1120 | _texture.format = texture.format !== undefined ? WEBGL_TEXTURE_FORMATS[ texture.format ] : THREE.RGBAFormat; 1121 | 1122 | if ( texture.internalFormat !== undefined && _texture.format !== WEBGL_TEXTURE_FORMATS[ texture.internalFormat ] ) { 1123 | 1124 | console.warn( 'THREE.LegacyGLTFLoader: Three.js doesn\'t support texture internalFormat which is different from texture format. ' + 1125 | 'internalFormat will be forced to be the same value as format.' ); 1126 | 1127 | } 1128 | 1129 | _texture.type = texture.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ texture.type ] : THREE.UnsignedByteType; 1130 | 1131 | if ( texture.sampler ) { 1132 | 1133 | var sampler = json.samplers[ texture.sampler ]; 1134 | 1135 | _texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter; 1136 | _texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.NearestMipMapLinearFilter; 1137 | _texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping; 1138 | _texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping; 1139 | 1140 | } 1141 | 1142 | resolve( _texture ); 1143 | 1144 | }, undefined, function () { 1145 | 1146 | resolve(); 1147 | 1148 | } ); 1149 | 1150 | } ); 1151 | 1152 | } 1153 | 1154 | } ); 1155 | 1156 | } ); 1157 | 1158 | }; 1159 | 1160 | GLTFParser.prototype.loadMaterials = function () { 1161 | 1162 | var json = this.json; 1163 | 1164 | return this._withDependencies( [ 1165 | 1166 | "shaders", 1167 | "textures" 1168 | 1169 | ] ).then( function ( dependencies ) { 1170 | 1171 | return _each( json.materials, function ( material ) { 1172 | 1173 | var materialType; 1174 | var materialValues = {}; 1175 | var materialParams = {}; 1176 | 1177 | var khr_material; 1178 | 1179 | if ( material.extensions && material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) { 1180 | 1181 | khr_material = material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ]; 1182 | 1183 | } 1184 | 1185 | if ( khr_material ) { 1186 | 1187 | // don't copy over unused values to avoid material warning spam 1188 | var keys = [ 'ambient', 'emission', 'transparent', 'transparency', 'doubleSided' ]; 1189 | 1190 | switch ( khr_material.technique ) { 1191 | 1192 | case 'BLINN' : 1193 | case 'PHONG' : 1194 | materialType = THREE.MeshPhongMaterial; 1195 | keys.push( 'diffuse', 'specular', 'shininess' ); 1196 | break; 1197 | 1198 | case 'LAMBERT' : 1199 | materialType = THREE.MeshLambertMaterial; 1200 | keys.push( 'diffuse' ); 1201 | break; 1202 | 1203 | case 'CONSTANT' : 1204 | default : 1205 | materialType = THREE.MeshBasicMaterial; 1206 | break; 1207 | 1208 | } 1209 | 1210 | keys.forEach( function( v ) { 1211 | 1212 | if ( khr_material.values[ v ] !== undefined ) materialValues[ v ] = khr_material.values[ v ]; 1213 | 1214 | } ); 1215 | 1216 | if ( khr_material.doubleSided || materialValues.doubleSided ) { 1217 | 1218 | materialParams.side = THREE.DoubleSide; 1219 | 1220 | } 1221 | 1222 | if ( khr_material.transparent || materialValues.transparent ) { 1223 | 1224 | materialParams.transparent = true; 1225 | materialParams.opacity = ( materialValues.transparency !== undefined ) ? materialValues.transparency : 1; 1226 | 1227 | } 1228 | 1229 | } else if ( material.technique === undefined ) { 1230 | 1231 | materialType = THREE.MeshPhongMaterial; 1232 | 1233 | Object.assign( materialValues, material.values ); 1234 | 1235 | } else { 1236 | 1237 | materialType = DeferredShaderMaterial; 1238 | 1239 | var technique = json.techniques[ material.technique ]; 1240 | 1241 | materialParams.uniforms = {}; 1242 | 1243 | var program = json.programs[ technique.program ]; 1244 | 1245 | if ( program ) { 1246 | 1247 | materialParams.fragmentShader = dependencies.shaders[ program.fragmentShader ]; 1248 | 1249 | if ( ! materialParams.fragmentShader ) { 1250 | 1251 | console.warn( "ERROR: Missing fragment shader definition:", program.fragmentShader ); 1252 | materialType = THREE.MeshPhongMaterial; 1253 | 1254 | } 1255 | 1256 | var vertexShader = dependencies.shaders[ program.vertexShader ]; 1257 | 1258 | if ( ! vertexShader ) { 1259 | 1260 | console.warn( "ERROR: Missing vertex shader definition:", program.vertexShader ); 1261 | materialType = THREE.MeshPhongMaterial; 1262 | 1263 | } 1264 | 1265 | // IMPORTANT: FIX VERTEX SHADER ATTRIBUTE DEFINITIONS 1266 | materialParams.vertexShader = replaceTHREEShaderAttributes( vertexShader, technique ); 1267 | 1268 | var uniforms = technique.uniforms; 1269 | 1270 | for ( var uniformId in uniforms ) { 1271 | 1272 | var pname = uniforms[ uniformId ]; 1273 | var shaderParam = technique.parameters[ pname ]; 1274 | 1275 | var ptype = shaderParam.type; 1276 | 1277 | if ( WEBGL_TYPE[ ptype ] ) { 1278 | 1279 | var pcount = shaderParam.count; 1280 | var value; 1281 | 1282 | if ( material.values !== undefined ) value = material.values[ pname ]; 1283 | 1284 | var uvalue = new WEBGL_TYPE[ ptype ](); 1285 | var usemantic = shaderParam.semantic; 1286 | var unode = shaderParam.node; 1287 | 1288 | switch ( ptype ) { 1289 | 1290 | case WEBGL_CONSTANTS.FLOAT: 1291 | 1292 | uvalue = shaderParam.value; 1293 | 1294 | if ( pname == "transparency" ) { 1295 | 1296 | materialParams.transparent = true; 1297 | 1298 | } 1299 | 1300 | if ( value !== undefined ) { 1301 | 1302 | uvalue = value; 1303 | 1304 | } 1305 | 1306 | break; 1307 | 1308 | case WEBGL_CONSTANTS.FLOAT_VEC2: 1309 | case WEBGL_CONSTANTS.FLOAT_VEC3: 1310 | case WEBGL_CONSTANTS.FLOAT_VEC4: 1311 | case WEBGL_CONSTANTS.FLOAT_MAT3: 1312 | 1313 | if ( shaderParam && shaderParam.value ) { 1314 | 1315 | uvalue.fromArray( shaderParam.value ); 1316 | 1317 | } 1318 | 1319 | if ( value ) { 1320 | 1321 | uvalue.fromArray( value ); 1322 | 1323 | } 1324 | 1325 | break; 1326 | 1327 | case WEBGL_CONSTANTS.FLOAT_MAT2: 1328 | 1329 | // what to do? 1330 | console.warn( "FLOAT_MAT2 is not a supported uniform type" ); 1331 | break; 1332 | 1333 | case WEBGL_CONSTANTS.FLOAT_MAT4: 1334 | 1335 | if ( pcount ) { 1336 | 1337 | uvalue = new Array( pcount ); 1338 | 1339 | for ( var mi = 0; mi < pcount; mi ++ ) { 1340 | 1341 | uvalue[ mi ] = new WEBGL_TYPE[ ptype ](); 1342 | 1343 | } 1344 | 1345 | if ( shaderParam && shaderParam.value ) { 1346 | 1347 | var m4v = shaderParam.value; 1348 | uvalue.fromArray( m4v ); 1349 | 1350 | } 1351 | 1352 | if ( value ) { 1353 | 1354 | uvalue.fromArray( value ); 1355 | 1356 | } 1357 | 1358 | } else { 1359 | 1360 | if ( shaderParam && shaderParam.value ) { 1361 | 1362 | var m4 = shaderParam.value; 1363 | uvalue.fromArray( m4 ); 1364 | 1365 | } 1366 | 1367 | if ( value ) { 1368 | 1369 | uvalue.fromArray( value ); 1370 | 1371 | } 1372 | 1373 | } 1374 | 1375 | break; 1376 | 1377 | case WEBGL_CONSTANTS.SAMPLER_2D: 1378 | 1379 | if ( value !== undefined ) { 1380 | 1381 | uvalue = dependencies.textures[ value ]; 1382 | 1383 | } else if ( shaderParam.value !== undefined ) { 1384 | 1385 | uvalue = dependencies.textures[ shaderParam.value ]; 1386 | 1387 | } else { 1388 | 1389 | uvalue = null; 1390 | 1391 | } 1392 | 1393 | break; 1394 | 1395 | } 1396 | 1397 | materialParams.uniforms[ uniformId ] = { 1398 | value: uvalue, 1399 | semantic: usemantic, 1400 | node: unode 1401 | }; 1402 | 1403 | } else { 1404 | 1405 | throw new Error( "Unknown shader uniform param type: " + ptype ); 1406 | 1407 | } 1408 | 1409 | } 1410 | 1411 | var states = technique.states || {}; 1412 | var enables = states.enable || []; 1413 | var functions = states.functions || {}; 1414 | 1415 | var enableCullFace = false; 1416 | var enableDepthTest = false; 1417 | var enableBlend = false; 1418 | 1419 | for ( var i = 0, il = enables.length; i < il; i ++ ) { 1420 | 1421 | var enable = enables[ i ]; 1422 | 1423 | switch ( STATES_ENABLES[ enable ] ) { 1424 | 1425 | case 'CULL_FACE': 1426 | 1427 | enableCullFace = true; 1428 | 1429 | break; 1430 | 1431 | case 'DEPTH_TEST': 1432 | 1433 | enableDepthTest = true; 1434 | 1435 | break; 1436 | 1437 | case 'BLEND': 1438 | 1439 | enableBlend = true; 1440 | 1441 | break; 1442 | 1443 | // TODO: implement 1444 | case 'SCISSOR_TEST': 1445 | case 'POLYGON_OFFSET_FILL': 1446 | case 'SAMPLE_ALPHA_TO_COVERAGE': 1447 | 1448 | break; 1449 | 1450 | default: 1451 | 1452 | throw new Error( "Unknown technique.states.enable: " + enable ); 1453 | 1454 | } 1455 | 1456 | } 1457 | 1458 | if ( enableCullFace ) { 1459 | 1460 | materialParams.side = functions.cullFace !== undefined ? WEBGL_SIDES[ functions.cullFace ] : THREE.FrontSide; 1461 | 1462 | } else { 1463 | 1464 | materialParams.side = THREE.DoubleSide; 1465 | 1466 | } 1467 | 1468 | materialParams.depthTest = enableDepthTest; 1469 | materialParams.depthFunc = functions.depthFunc !== undefined ? WEBGL_DEPTH_FUNCS[ functions.depthFunc ] : THREE.LessDepth; 1470 | materialParams.depthWrite = functions.depthMask !== undefined ? functions.depthMask[ 0 ] : true; 1471 | 1472 | materialParams.blending = enableBlend ? THREE.CustomBlending : THREE.NoBlending; 1473 | materialParams.transparent = enableBlend; 1474 | 1475 | var blendEquationSeparate = functions.blendEquationSeparate; 1476 | 1477 | if ( blendEquationSeparate !== undefined ) { 1478 | 1479 | materialParams.blendEquation = WEBGL_BLEND_EQUATIONS[ blendEquationSeparate[ 0 ] ]; 1480 | materialParams.blendEquationAlpha = WEBGL_BLEND_EQUATIONS[ blendEquationSeparate[ 1 ] ]; 1481 | 1482 | } else { 1483 | 1484 | materialParams.blendEquation = THREE.AddEquation; 1485 | materialParams.blendEquationAlpha = THREE.AddEquation; 1486 | 1487 | } 1488 | 1489 | var blendFuncSeparate = functions.blendFuncSeparate; 1490 | 1491 | if ( blendFuncSeparate !== undefined ) { 1492 | 1493 | materialParams.blendSrc = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 0 ] ]; 1494 | materialParams.blendDst = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 1 ] ]; 1495 | materialParams.blendSrcAlpha = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 2 ] ]; 1496 | materialParams.blendDstAlpha = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 3 ] ]; 1497 | 1498 | } else { 1499 | 1500 | materialParams.blendSrc = THREE.OneFactor; 1501 | materialParams.blendDst = THREE.ZeroFactor; 1502 | materialParams.blendSrcAlpha = THREE.OneFactor; 1503 | materialParams.blendDstAlpha = THREE.ZeroFactor; 1504 | 1505 | } 1506 | 1507 | } 1508 | 1509 | } 1510 | 1511 | if ( Array.isArray( materialValues.diffuse ) ) { 1512 | 1513 | materialParams.color = new THREE.Color().fromArray( materialValues.diffuse ); 1514 | 1515 | } else if ( typeof( materialValues.diffuse ) === 'string' ) { 1516 | 1517 | materialParams.map = dependencies.textures[ materialValues.diffuse ]; 1518 | 1519 | } 1520 | 1521 | delete materialParams.diffuse; 1522 | 1523 | if ( typeof( materialValues.reflective ) === 'string' ) { 1524 | 1525 | materialParams.envMap = dependencies.textures[ materialValues.reflective ]; 1526 | 1527 | } 1528 | 1529 | if ( typeof( materialValues.bump ) === 'string' ) { 1530 | 1531 | materialParams.bumpMap = dependencies.textures[ materialValues.bump ]; 1532 | 1533 | } 1534 | 1535 | if ( Array.isArray( materialValues.emission ) ) { 1536 | 1537 | if ( materialType === THREE.MeshBasicMaterial ) { 1538 | 1539 | materialParams.color = new THREE.Color().fromArray( materialValues.emission ); 1540 | 1541 | } else { 1542 | 1543 | materialParams.emissive = new THREE.Color().fromArray( materialValues.emission ); 1544 | 1545 | } 1546 | 1547 | } else if ( typeof( materialValues.emission ) === 'string' ) { 1548 | 1549 | if ( materialType === THREE.MeshBasicMaterial ) { 1550 | 1551 | materialParams.map = dependencies.textures[ materialValues.emission ]; 1552 | 1553 | } else { 1554 | 1555 | materialParams.emissiveMap = dependencies.textures[ materialValues.emission ]; 1556 | 1557 | } 1558 | 1559 | } 1560 | 1561 | if ( Array.isArray( materialValues.specular ) ) { 1562 | 1563 | materialParams.specular = new THREE.Color().fromArray( materialValues.specular ); 1564 | 1565 | } else if ( typeof( materialValues.specular ) === 'string' ) { 1566 | 1567 | materialParams.specularMap = dependencies.textures[ materialValues.specular ]; 1568 | 1569 | } 1570 | 1571 | if ( materialValues.shininess !== undefined ) { 1572 | 1573 | materialParams.shininess = materialValues.shininess; 1574 | 1575 | } 1576 | 1577 | var _material = new materialType( materialParams ); 1578 | if ( material.name !== undefined ) _material.name = material.name; 1579 | 1580 | return _material; 1581 | 1582 | } ); 1583 | 1584 | } ); 1585 | 1586 | }; 1587 | 1588 | GLTFParser.prototype.loadMeshes = function () { 1589 | 1590 | var json = this.json; 1591 | 1592 | return this._withDependencies( [ 1593 | 1594 | "accessors", 1595 | "materials" 1596 | 1597 | ] ).then( function ( dependencies ) { 1598 | 1599 | return _each( json.meshes, function ( mesh ) { 1600 | 1601 | var group = new THREE.Group(); 1602 | if ( mesh.name !== undefined ) group.name = mesh.name; 1603 | 1604 | if ( mesh.extras ) group.userData = mesh.extras; 1605 | 1606 | var primitives = mesh.primitives || []; 1607 | 1608 | for ( var name in primitives ) { 1609 | 1610 | var primitive = primitives[ name ]; 1611 | 1612 | if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) { 1613 | 1614 | var geometry = new THREE.BufferGeometry(); 1615 | 1616 | var attributes = primitive.attributes; 1617 | 1618 | for ( var attributeId in attributes ) { 1619 | 1620 | var attributeEntry = attributes[ attributeId ]; 1621 | 1622 | if ( ! attributeEntry ) return; 1623 | 1624 | var bufferAttribute = dependencies.accessors[ attributeEntry ]; 1625 | 1626 | switch ( attributeId ) { 1627 | 1628 | case 'POSITION': 1629 | geometry.addAttribute( 'position', bufferAttribute ); 1630 | break; 1631 | 1632 | case 'NORMAL': 1633 | geometry.addAttribute( 'normal', bufferAttribute ); 1634 | break; 1635 | 1636 | case 'TEXCOORD_0': 1637 | case 'TEXCOORD0': 1638 | case 'TEXCOORD': 1639 | geometry.addAttribute( 'uv', bufferAttribute ); 1640 | break; 1641 | 1642 | case 'TEXCOORD_1': 1643 | geometry.addAttribute( 'uv2', bufferAttribute ); 1644 | break; 1645 | 1646 | case 'COLOR_0': 1647 | case 'COLOR0': 1648 | case 'COLOR': 1649 | geometry.addAttribute( 'color', bufferAttribute ); 1650 | break; 1651 | 1652 | case 'WEIGHT': 1653 | geometry.addAttribute( 'skinWeight', bufferAttribute ); 1654 | break; 1655 | 1656 | case 'JOINT': 1657 | geometry.addAttribute( 'skinIndex', bufferAttribute ); 1658 | break; 1659 | 1660 | } 1661 | 1662 | } 1663 | 1664 | if ( primitive.indices ) { 1665 | 1666 | geometry.setIndex( dependencies.accessors[ primitive.indices ] ); 1667 | 1668 | } 1669 | 1670 | var material = dependencies.materials !== undefined ? dependencies.materials[ primitive.material ] : createDefaultMaterial(); 1671 | 1672 | var meshNode = new THREE.Mesh( geometry, material ); 1673 | meshNode.castShadow = true; 1674 | meshNode.name = ( name === "0" ? group.name : group.name + name ); 1675 | 1676 | if ( primitive.extras ) meshNode.userData = primitive.extras; 1677 | 1678 | group.add( meshNode ); 1679 | 1680 | } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) { 1681 | 1682 | var geometry = new THREE.BufferGeometry(); 1683 | 1684 | var attributes = primitive.attributes; 1685 | 1686 | for ( var attributeId in attributes ) { 1687 | 1688 | var attributeEntry = attributes[ attributeId ]; 1689 | 1690 | if ( ! attributeEntry ) return; 1691 | 1692 | var bufferAttribute = dependencies.accessors[ attributeEntry ]; 1693 | 1694 | switch ( attributeId ) { 1695 | 1696 | case 'POSITION': 1697 | geometry.addAttribute( 'position', bufferAttribute ); 1698 | break; 1699 | 1700 | case 'COLOR_0': 1701 | case 'COLOR0': 1702 | case 'COLOR': 1703 | geometry.addAttribute( 'color', bufferAttribute ); 1704 | break; 1705 | 1706 | } 1707 | 1708 | } 1709 | 1710 | var material = dependencies.materials[ primitive.material ]; 1711 | 1712 | var meshNode; 1713 | 1714 | if ( primitive.indices ) { 1715 | 1716 | geometry.setIndex( dependencies.accessors[ primitive.indices ] ); 1717 | 1718 | meshNode = new THREE.LineSegments( geometry, material ); 1719 | 1720 | } else { 1721 | 1722 | meshNode = new THREE.Line( geometry, material ); 1723 | 1724 | } 1725 | 1726 | meshNode.name = ( name === "0" ? group.name : group.name + name ); 1727 | 1728 | if ( primitive.extras ) meshNode.userData = primitive.extras; 1729 | 1730 | group.add( meshNode ); 1731 | 1732 | } else { 1733 | 1734 | console.warn( "Only triangular and line primitives are supported" ); 1735 | 1736 | } 1737 | 1738 | } 1739 | 1740 | return group; 1741 | 1742 | } ); 1743 | 1744 | } ); 1745 | 1746 | }; 1747 | 1748 | GLTFParser.prototype.loadCameras = function () { 1749 | 1750 | var json = this.json; 1751 | 1752 | return _each( json.cameras, function ( camera ) { 1753 | 1754 | if ( camera.type == "perspective" && camera.perspective ) { 1755 | 1756 | var yfov = camera.perspective.yfov; 1757 | var aspectRatio = camera.perspective.aspectRatio !== undefined ? camera.perspective.aspectRatio : 1; 1758 | 1759 | // According to COLLADA spec... 1760 | // aspectRatio = xfov / yfov 1761 | var xfov = yfov * aspectRatio; 1762 | 1763 | var _camera = new THREE.PerspectiveCamera( THREE.Math.radToDeg( xfov ), aspectRatio, camera.perspective.znear || 1, camera.perspective.zfar || 2e6 ); 1764 | if ( camera.name !== undefined ) _camera.name = camera.name; 1765 | 1766 | if ( camera.extras ) _camera.userData = camera.extras; 1767 | 1768 | return _camera; 1769 | 1770 | } else if ( camera.type == "orthographic" && camera.orthographic ) { 1771 | 1772 | var _camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, camera.orthographic.znear, camera.orthographic.zfar ); 1773 | if ( camera.name !== undefined ) _camera.name = camera.name; 1774 | 1775 | if ( camera.extras ) _camera.userData = camera.extras; 1776 | 1777 | return _camera; 1778 | 1779 | } 1780 | 1781 | } ); 1782 | 1783 | }; 1784 | 1785 | GLTFParser.prototype.loadSkins = function () { 1786 | 1787 | var json = this.json; 1788 | 1789 | return this._withDependencies( [ 1790 | 1791 | "accessors" 1792 | 1793 | ] ).then( function ( dependencies ) { 1794 | 1795 | return _each( json.skins, function ( skin ) { 1796 | 1797 | var bindShapeMatrix = new THREE.Matrix4(); 1798 | 1799 | if ( skin.bindShapeMatrix !== undefined ) bindShapeMatrix.fromArray( skin.bindShapeMatrix ); 1800 | 1801 | var _skin = { 1802 | bindShapeMatrix: bindShapeMatrix, 1803 | jointNames: skin.jointNames, 1804 | inverseBindMatrices: dependencies.accessors[ skin.inverseBindMatrices ] 1805 | }; 1806 | 1807 | return _skin; 1808 | 1809 | } ); 1810 | 1811 | } ); 1812 | 1813 | }; 1814 | 1815 | GLTFParser.prototype.loadAnimations = function () { 1816 | 1817 | var json = this.json; 1818 | 1819 | return this._withDependencies( [ 1820 | 1821 | "accessors", 1822 | "nodes" 1823 | 1824 | ] ).then( function ( dependencies ) { 1825 | 1826 | return _each( json.animations, function ( animation, animationId ) { 1827 | 1828 | var tracks = []; 1829 | 1830 | for ( var channelId in animation.channels ) { 1831 | 1832 | var channel = animation.channels[ channelId ]; 1833 | var sampler = animation.samplers[ channel.sampler ]; 1834 | 1835 | if ( sampler ) { 1836 | 1837 | var target = channel.target; 1838 | var name = target.id; 1839 | var input = animation.parameters !== undefined ? animation.parameters[ sampler.input ] : sampler.input; 1840 | var output = animation.parameters !== undefined ? animation.parameters[ sampler.output ] : sampler.output; 1841 | 1842 | var inputAccessor = dependencies.accessors[ input ]; 1843 | var outputAccessor = dependencies.accessors[ output ]; 1844 | 1845 | var node = dependencies.nodes[ name ]; 1846 | 1847 | if ( node ) { 1848 | 1849 | node.updateMatrix(); 1850 | node.matrixAutoUpdate = true; 1851 | 1852 | var TypedKeyframeTrack = PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.rotation 1853 | ? THREE.QuaternionKeyframeTrack 1854 | : THREE.VectorKeyframeTrack; 1855 | 1856 | var targetName = node.name ? node.name : node.uuid; 1857 | var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : THREE.InterpolateLinear; 1858 | 1859 | // KeyframeTrack.optimize() will modify given 'times' and 'values' 1860 | // buffers before creating a truncated copy to keep. Because buffers may 1861 | // be reused by other tracks, make copies here. 1862 | tracks.push( new TypedKeyframeTrack( 1863 | targetName + '.' + PATH_PROPERTIES[ target.path ], 1864 | THREE.AnimationUtils.arraySlice( inputAccessor.array, 0 ), 1865 | THREE.AnimationUtils.arraySlice( outputAccessor.array, 0 ), 1866 | interpolation 1867 | ) ); 1868 | 1869 | } 1870 | 1871 | } 1872 | 1873 | } 1874 | 1875 | var name = animation.name !== undefined ? animation.name : "animation_" + animationId; 1876 | 1877 | return new THREE.AnimationClip( name, undefined, tracks ); 1878 | 1879 | } ); 1880 | 1881 | } ); 1882 | 1883 | }; 1884 | 1885 | GLTFParser.prototype.loadNodes = function () { 1886 | 1887 | var json = this.json; 1888 | var extensions = this.extensions; 1889 | var scope = this; 1890 | 1891 | return _each( json.nodes, function ( node ) { 1892 | 1893 | var matrix = new THREE.Matrix4(); 1894 | 1895 | var _node; 1896 | 1897 | if ( node.jointName ) { 1898 | 1899 | _node = new THREE.Bone(); 1900 | _node.name = node.name !== undefined ? node.name : node.jointName; 1901 | _node.jointName = node.jointName; 1902 | 1903 | } else { 1904 | 1905 | _node = new THREE.Object3D(); 1906 | if ( node.name !== undefined ) _node.name = node.name; 1907 | 1908 | } 1909 | 1910 | if ( node.extras ) _node.userData = node.extras; 1911 | 1912 | if ( node.matrix !== undefined ) { 1913 | 1914 | matrix.fromArray( node.matrix ); 1915 | _node.applyMatrix( matrix ); 1916 | 1917 | } else { 1918 | 1919 | if ( node.translation !== undefined ) { 1920 | 1921 | _node.position.fromArray( node.translation ); 1922 | 1923 | } 1924 | 1925 | if ( node.rotation !== undefined ) { 1926 | 1927 | _node.quaternion.fromArray( node.rotation ); 1928 | 1929 | } 1930 | 1931 | if ( node.scale !== undefined ) { 1932 | 1933 | _node.scale.fromArray( node.scale ); 1934 | 1935 | } 1936 | 1937 | } 1938 | 1939 | return _node; 1940 | 1941 | } ).then( function ( __nodes ) { 1942 | 1943 | return scope._withDependencies( [ 1944 | 1945 | "meshes", 1946 | "skins", 1947 | "cameras" 1948 | 1949 | ] ).then( function ( dependencies ) { 1950 | 1951 | return _each( __nodes, function ( _node, nodeId ) { 1952 | 1953 | var node = json.nodes[ nodeId ]; 1954 | 1955 | if ( node.meshes !== undefined ) { 1956 | 1957 | for ( var meshId in node.meshes ) { 1958 | 1959 | var mesh = node.meshes[ meshId ]; 1960 | var group = dependencies.meshes[ mesh ]; 1961 | 1962 | if ( group === undefined ) { 1963 | 1964 | console.warn( 'LegacyGLTFLoader: Couldn\'t find node "' + mesh + '".' ); 1965 | continue; 1966 | 1967 | } 1968 | 1969 | for ( var childrenId in group.children ) { 1970 | 1971 | var child = group.children[ childrenId ]; 1972 | 1973 | // clone Mesh to add to _node 1974 | 1975 | var originalMaterial = child.material; 1976 | var originalGeometry = child.geometry; 1977 | var originalUserData = child.userData; 1978 | var originalName = child.name; 1979 | 1980 | var material; 1981 | 1982 | if ( originalMaterial.isDeferredShaderMaterial ) { 1983 | 1984 | originalMaterial = material = originalMaterial.create(); 1985 | 1986 | } else { 1987 | 1988 | material = originalMaterial; 1989 | 1990 | } 1991 | 1992 | switch ( child.type ) { 1993 | 1994 | case 'LineSegments': 1995 | child = new THREE.LineSegments( originalGeometry, material ); 1996 | break; 1997 | 1998 | case 'LineLoop': 1999 | child = new THREE.LineLoop( originalGeometry, material ); 2000 | break; 2001 | 2002 | case 'Line': 2003 | child = new THREE.Line( originalGeometry, material ); 2004 | break; 2005 | 2006 | default: 2007 | child = new THREE.Mesh( originalGeometry, material ); 2008 | 2009 | } 2010 | 2011 | child.castShadow = true; 2012 | child.userData = originalUserData; 2013 | child.name = originalName; 2014 | 2015 | var skinEntry; 2016 | 2017 | if ( node.skin ) { 2018 | 2019 | skinEntry = dependencies.skins[ node.skin ]; 2020 | 2021 | } 2022 | 2023 | // Replace Mesh with SkinnedMesh in library 2024 | if ( skinEntry ) { 2025 | 2026 | var getJointNode = function ( jointId ) { 2027 | 2028 | var keys = Object.keys( __nodes ); 2029 | 2030 | for ( var i = 0, il = keys.length; i < il; i ++ ) { 2031 | 2032 | var n = __nodes[ keys[ i ] ]; 2033 | 2034 | if ( n.jointName === jointId ) return n; 2035 | 2036 | } 2037 | 2038 | return null; 2039 | 2040 | }; 2041 | 2042 | var geometry = originalGeometry; 2043 | var material = originalMaterial; 2044 | material.skinning = true; 2045 | 2046 | child = new THREE.SkinnedMesh( geometry, material ); 2047 | child.castShadow = true; 2048 | child.userData = originalUserData; 2049 | child.name = originalName; 2050 | 2051 | var bones = []; 2052 | var boneInverses = []; 2053 | 2054 | for ( var i = 0, l = skinEntry.jointNames.length; i < l; i ++ ) { 2055 | 2056 | var jointId = skinEntry.jointNames[ i ]; 2057 | var jointNode = getJointNode( jointId ); 2058 | 2059 | if ( jointNode ) { 2060 | 2061 | bones.push( jointNode ); 2062 | 2063 | var m = skinEntry.inverseBindMatrices.array; 2064 | var mat = new THREE.Matrix4().fromArray( m, i * 16 ); 2065 | boneInverses.push( mat ); 2066 | 2067 | } else { 2068 | 2069 | console.warn( "WARNING: joint: '" + jointId + "' could not be found" ); 2070 | 2071 | } 2072 | 2073 | } 2074 | 2075 | child.bind( new THREE.Skeleton( bones, boneInverses ), skinEntry.bindShapeMatrix ); 2076 | 2077 | var buildBoneGraph = function ( parentJson, parentObject, property ) { 2078 | 2079 | var children = parentJson[ property ]; 2080 | 2081 | if ( children === undefined ) return; 2082 | 2083 | for ( var i = 0, il = children.length; i < il; i ++ ) { 2084 | 2085 | var nodeId = children[ i ]; 2086 | var bone = __nodes[ nodeId ]; 2087 | var boneJson = json.nodes[ nodeId ]; 2088 | 2089 | if ( bone !== undefined && bone.isBone === true && boneJson !== undefined ) { 2090 | 2091 | parentObject.add( bone ); 2092 | buildBoneGraph( boneJson, bone, 'children' ); 2093 | 2094 | } 2095 | 2096 | } 2097 | 2098 | }; 2099 | 2100 | buildBoneGraph( node, child, 'skeletons' ); 2101 | 2102 | } 2103 | 2104 | _node.add( child ); 2105 | 2106 | } 2107 | 2108 | } 2109 | 2110 | } 2111 | 2112 | if ( node.camera !== undefined ) { 2113 | 2114 | var camera = dependencies.cameras[ node.camera ]; 2115 | 2116 | _node.add( camera ); 2117 | 2118 | } 2119 | 2120 | if ( node.extensions 2121 | && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] 2122 | && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ) { 2123 | 2124 | var extensionLights = extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].lights; 2125 | var light = extensionLights[ node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ]; 2126 | 2127 | _node.add( light ); 2128 | 2129 | } 2130 | 2131 | return _node; 2132 | 2133 | } ); 2134 | 2135 | } ); 2136 | 2137 | } ); 2138 | 2139 | }; 2140 | 2141 | GLTFParser.prototype.loadScenes = function () { 2142 | 2143 | var json = this.json; 2144 | 2145 | // scene node hierachy builder 2146 | 2147 | function buildNodeHierachy( nodeId, parentObject, allNodes ) { 2148 | 2149 | var _node = allNodes[ nodeId ]; 2150 | parentObject.add( _node ); 2151 | 2152 | var node = json.nodes[ nodeId ]; 2153 | 2154 | if ( node.children ) { 2155 | 2156 | var children = node.children; 2157 | 2158 | for ( var i = 0, l = children.length; i < l; i ++ ) { 2159 | 2160 | var child = children[ i ]; 2161 | buildNodeHierachy( child, _node, allNodes ); 2162 | 2163 | } 2164 | 2165 | } 2166 | 2167 | } 2168 | 2169 | return this._withDependencies( [ 2170 | 2171 | "nodes" 2172 | 2173 | ] ).then( function ( dependencies ) { 2174 | 2175 | return _each( json.scenes, function ( scene ) { 2176 | 2177 | var _scene = new THREE.Scene(); 2178 | if ( scene.name !== undefined ) _scene.name = scene.name; 2179 | 2180 | if ( scene.extras ) _scene.userData = scene.extras; 2181 | 2182 | var nodes = scene.nodes || []; 2183 | 2184 | for ( var i = 0, l = nodes.length; i < l; i ++ ) { 2185 | 2186 | var nodeId = nodes[ i ]; 2187 | buildNodeHierachy( nodeId, _scene, dependencies.nodes ); 2188 | 2189 | } 2190 | 2191 | _scene.traverse( function ( child ) { 2192 | 2193 | // Register raw material meshes with LegacyGLTFLoader.Shaders 2194 | if ( child.material && child.material.isRawShaderMaterial ) { 2195 | 2196 | child.gltfShader = new GLTFShader( child, dependencies.nodes ); 2197 | child.onBeforeRender = function(renderer, scene, camera){ 2198 | this.gltfShader.update(scene, camera); 2199 | }; 2200 | 2201 | } 2202 | 2203 | } ); 2204 | 2205 | return _scene; 2206 | 2207 | } ); 2208 | 2209 | } ); 2210 | 2211 | }; 2212 | 2213 | return LegacyGLTFLoader; 2214 | 2215 | } )(); 2216 | -------------------------------------------------------------------------------- /third_party/three.js/js/MTLLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Loads a Wavefront .mtl file specifying materials 3 | * 4 | * @author angelxuanchang 5 | */ 6 | 7 | THREE.MTLLoader = function ( manager ) { 8 | 9 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 10 | 11 | }; 12 | 13 | THREE.MTLLoader.prototype = { 14 | 15 | constructor: THREE.MTLLoader, 16 | 17 | /** 18 | * Loads and parses a MTL asset from a URL. 19 | * 20 | * @param {String} url - URL to the MTL file. 21 | * @param {Function} [onLoad] - Callback invoked with the loaded object. 22 | * @param {Function} [onProgress] - Callback for download progress. 23 | * @param {Function} [onError] - Callback for download errors. 24 | * 25 | * @see setPath setTexturePath 26 | * 27 | * @note In order for relative texture references to resolve correctly 28 | * you must call setPath and/or setTexturePath explicitly prior to load. 29 | */ 30 | load: function ( url, onLoad, onProgress, onError ) { 31 | 32 | var scope = this; 33 | 34 | var loader = new THREE.FileLoader( this.manager ); 35 | loader.setPath( this.path ); 36 | loader.load( url, function ( text ) { 37 | 38 | onLoad( scope.parse( text ) ); 39 | 40 | }, onProgress, onError ); 41 | 42 | }, 43 | 44 | /** 45 | * Set base path for resolving references. 46 | * If set this path will be prepended to each loaded and found reference. 47 | * 48 | * @see setTexturePath 49 | * @param {String} path 50 | * 51 | * @example 52 | * mtlLoader.setPath( 'assets/obj/' ); 53 | * mtlLoader.load( 'my.mtl', ... ); 54 | */ 55 | setPath: function ( path ) { 56 | 57 | this.path = path; 58 | 59 | }, 60 | 61 | /** 62 | * Set base path for resolving texture references. 63 | * If set this path will be prepended found texture reference. 64 | * If not set and setPath is, it will be used as texture base path. 65 | * 66 | * @see setPath 67 | * @param {String} path 68 | * 69 | * @example 70 | * mtlLoader.setPath( 'assets/obj/' ); 71 | * mtlLoader.setTexturePath( 'assets/textures/' ); 72 | * mtlLoader.load( 'my.mtl', ... ); 73 | */ 74 | setTexturePath: function ( path ) { 75 | 76 | this.texturePath = path; 77 | 78 | }, 79 | 80 | setBaseUrl: function ( path ) { 81 | 82 | console.warn( 'THREE.MTLLoader: .setBaseUrl() is deprecated. Use .setTexturePath( path ) for texture path or .setPath( path ) for general base path instead.' ); 83 | 84 | this.setTexturePath( path ); 85 | 86 | }, 87 | 88 | setCrossOrigin: function ( value ) { 89 | 90 | this.crossOrigin = value; 91 | 92 | }, 93 | 94 | setMaterialOptions: function ( value ) { 95 | 96 | this.materialOptions = value; 97 | 98 | }, 99 | 100 | /** 101 | * Parses a MTL file. 102 | * 103 | * @param {String} text - Content of MTL file 104 | * @return {THREE.MTLLoader.MaterialCreator} 105 | * 106 | * @see setPath setTexturePath 107 | * 108 | * @note In order for relative texture references to resolve correctly 109 | * you must call setPath and/or setTexturePath explicitly prior to parse. 110 | */ 111 | parse: function ( text ) { 112 | 113 | var lines = text.split( '\n' ); 114 | var info = {}; 115 | var delimiter_pattern = /\s+/; 116 | var materialsInfo = {}; 117 | 118 | for ( var i = 0; i < lines.length; i ++ ) { 119 | 120 | var line = lines[ i ]; 121 | line = line.trim(); 122 | 123 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 124 | 125 | // Blank line or comment ignore 126 | continue; 127 | 128 | } 129 | 130 | var pos = line.indexOf( ' ' ); 131 | 132 | var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line; 133 | key = key.toLowerCase(); 134 | 135 | var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : ''; 136 | value = value.trim(); 137 | 138 | if ( key === 'newmtl' ) { 139 | 140 | // New material 141 | 142 | info = { name: value }; 143 | materialsInfo[ value ] = info; 144 | 145 | } else if ( info ) { 146 | 147 | if ( key === 'ka' || key === 'kd' || key === 'ks' ) { 148 | 149 | var ss = value.split( delimiter_pattern, 3 ); 150 | info[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ]; 151 | 152 | } else { 153 | 154 | info[ key ] = value; 155 | 156 | } 157 | 158 | } 159 | 160 | } 161 | 162 | var materialCreator = new THREE.MTLLoader.MaterialCreator( this.texturePath || this.path, this.materialOptions ); 163 | materialCreator.setCrossOrigin( this.crossOrigin ); 164 | materialCreator.setManager( this.manager ); 165 | materialCreator.setMaterials( materialsInfo ); 166 | return materialCreator; 167 | 168 | } 169 | 170 | }; 171 | 172 | /** 173 | * Create a new THREE-MTLLoader.MaterialCreator 174 | * @param baseUrl - Url relative to which textures are loaded 175 | * @param options - Set of options on how to construct the materials 176 | * side: Which side to apply the material 177 | * THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide 178 | * wrap: What type of wrapping to apply for textures 179 | * THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping 180 | * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255 181 | * Default: false, assumed to be already normalized 182 | * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's 183 | * Default: false 184 | * @constructor 185 | */ 186 | 187 | THREE.MTLLoader.MaterialCreator = function ( baseUrl, options ) { 188 | 189 | this.baseUrl = baseUrl || ''; 190 | this.options = options; 191 | this.materialsInfo = {}; 192 | this.materials = {}; 193 | this.materialsArray = []; 194 | this.nameLookup = {}; 195 | 196 | this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide; 197 | this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping; 198 | 199 | }; 200 | 201 | THREE.MTLLoader.MaterialCreator.prototype = { 202 | 203 | constructor: THREE.MTLLoader.MaterialCreator, 204 | 205 | crossOrigin: 'Anonymous', 206 | 207 | setCrossOrigin: function ( value ) { 208 | 209 | this.crossOrigin = value; 210 | 211 | }, 212 | 213 | setManager: function ( value ) { 214 | 215 | this.manager = value; 216 | 217 | }, 218 | 219 | setMaterials: function ( materialsInfo ) { 220 | 221 | this.materialsInfo = this.convert( materialsInfo ); 222 | this.materials = {}; 223 | this.materialsArray = []; 224 | this.nameLookup = {}; 225 | 226 | }, 227 | 228 | convert: function ( materialsInfo ) { 229 | 230 | if ( ! this.options ) return materialsInfo; 231 | 232 | var converted = {}; 233 | 234 | for ( var mn in materialsInfo ) { 235 | 236 | // Convert materials info into normalized form based on options 237 | 238 | var mat = materialsInfo[ mn ]; 239 | 240 | var covmat = {}; 241 | 242 | converted[ mn ] = covmat; 243 | 244 | for ( var prop in mat ) { 245 | 246 | var save = true; 247 | var value = mat[ prop ]; 248 | var lprop = prop.toLowerCase(); 249 | 250 | switch ( lprop ) { 251 | 252 | case 'kd': 253 | case 'ka': 254 | case 'ks': 255 | 256 | // Diffuse color (color under white light) using RGB values 257 | 258 | if ( this.options && this.options.normalizeRGB ) { 259 | 260 | value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ]; 261 | 262 | } 263 | 264 | if ( this.options && this.options.ignoreZeroRGBs ) { 265 | 266 | if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 2 ] === 0 ) { 267 | 268 | // ignore 269 | 270 | save = false; 271 | 272 | } 273 | 274 | } 275 | 276 | break; 277 | 278 | default: 279 | 280 | break; 281 | 282 | } 283 | 284 | if ( save ) { 285 | 286 | covmat[ lprop ] = value; 287 | 288 | } 289 | 290 | } 291 | 292 | } 293 | 294 | return converted; 295 | 296 | }, 297 | 298 | preload: function () { 299 | 300 | for ( var mn in this.materialsInfo ) { 301 | 302 | this.create( mn ); 303 | 304 | } 305 | 306 | }, 307 | 308 | getIndex: function ( materialName ) { 309 | 310 | return this.nameLookup[ materialName ]; 311 | 312 | }, 313 | 314 | getAsArray: function () { 315 | 316 | var index = 0; 317 | 318 | for ( var mn in this.materialsInfo ) { 319 | 320 | this.materialsArray[ index ] = this.create( mn ); 321 | this.nameLookup[ mn ] = index; 322 | index ++; 323 | 324 | } 325 | 326 | return this.materialsArray; 327 | 328 | }, 329 | 330 | create: function ( materialName ) { 331 | 332 | if ( this.materials[ materialName ] === undefined ) { 333 | 334 | this.createMaterial_( materialName ); 335 | 336 | } 337 | 338 | return this.materials[ materialName ]; 339 | 340 | }, 341 | 342 | createMaterial_: function ( materialName ) { 343 | 344 | // Create material 345 | 346 | var scope = this; 347 | var mat = this.materialsInfo[ materialName ]; 348 | var params = { 349 | 350 | name: materialName, 351 | side: this.side 352 | 353 | }; 354 | 355 | function resolveURL( baseUrl, url ) { 356 | 357 | if ( typeof url !== 'string' || url === '' ) 358 | return ''; 359 | 360 | // Absolute URL 361 | if ( /^https?:\/\//i.test( url ) ) return url; 362 | 363 | return baseUrl + url; 364 | 365 | } 366 | 367 | function setMapForType( mapType, value ) { 368 | 369 | if ( params[ mapType ] ) return; // Keep the first encountered texture 370 | 371 | var texParams = scope.getTextureParams( value, params ); 372 | var map = scope.loadTexture( resolveURL( scope.baseUrl, texParams.url ) ); 373 | 374 | map.repeat.copy( texParams.scale ); 375 | map.offset.copy( texParams.offset ); 376 | 377 | map.wrapS = scope.wrap; 378 | map.wrapT = scope.wrap; 379 | 380 | params[ mapType ] = map; 381 | 382 | } 383 | 384 | for ( var prop in mat ) { 385 | 386 | var value = mat[ prop ]; 387 | var n; 388 | 389 | if ( value === '' ) continue; 390 | 391 | switch ( prop.toLowerCase() ) { 392 | 393 | // Ns is material specular exponent 394 | 395 | case 'kd': 396 | 397 | // Diffuse color (color under white light) using RGB values 398 | 399 | params.color = new THREE.Color().fromArray( value ); 400 | 401 | break; 402 | 403 | case 'ks': 404 | 405 | // Specular color (color when light is reflected from shiny surface) using RGB values 406 | params.specular = new THREE.Color().fromArray( value ); 407 | 408 | break; 409 | 410 | case 'map_kd': 411 | 412 | // Diffuse texture map 413 | 414 | setMapForType( "map", value ); 415 | 416 | break; 417 | 418 | case 'map_ks': 419 | 420 | // Specular map 421 | 422 | setMapForType( "specularMap", value ); 423 | 424 | break; 425 | 426 | case 'norm': 427 | 428 | setMapForType( "normalMap", value ); 429 | 430 | break; 431 | 432 | case 'map_bump': 433 | case 'bump': 434 | 435 | // Bump texture map 436 | 437 | setMapForType( "bumpMap", value ); 438 | 439 | break; 440 | 441 | case 'ns': 442 | 443 | // The specular exponent (defines the focus of the specular highlight) 444 | // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000. 445 | 446 | params.shininess = parseFloat( value ); 447 | 448 | break; 449 | 450 | case 'd': 451 | n = parseFloat( value ); 452 | 453 | if ( n < 1 ) { 454 | 455 | params.opacity = n; 456 | params.transparent = true; 457 | 458 | } 459 | 460 | break; 461 | 462 | case 'tr': 463 | n = parseFloat( value ); 464 | 465 | if ( n > 0 ) { 466 | 467 | params.opacity = 1 - n; 468 | params.transparent = true; 469 | 470 | } 471 | 472 | break; 473 | 474 | default: 475 | break; 476 | 477 | } 478 | 479 | } 480 | 481 | this.materials[ materialName ] = new THREE.MeshPhongMaterial( params ); 482 | return this.materials[ materialName ]; 483 | 484 | }, 485 | 486 | getTextureParams: function ( value, matParams ) { 487 | 488 | var texParams = { 489 | 490 | scale: new THREE.Vector2( 1, 1 ), 491 | offset: new THREE.Vector2( 0, 0 ) 492 | 493 | }; 494 | 495 | var items = value.split( /\s+/ ); 496 | var pos; 497 | 498 | pos = items.indexOf( '-bm' ); 499 | 500 | if ( pos >= 0 ) { 501 | 502 | matParams.bumpScale = parseFloat( items[ pos + 1 ] ); 503 | items.splice( pos, 2 ); 504 | 505 | } 506 | 507 | pos = items.indexOf( '-s' ); 508 | 509 | if ( pos >= 0 ) { 510 | 511 | texParams.scale.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) ); 512 | items.splice( pos, 4 ); // we expect 3 parameters here! 513 | 514 | } 515 | 516 | pos = items.indexOf( '-o' ); 517 | 518 | if ( pos >= 0 ) { 519 | 520 | texParams.offset.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) ); 521 | items.splice( pos, 4 ); // we expect 3 parameters here! 522 | 523 | } 524 | 525 | texParams.url = items.join( ' ' ).trim(); 526 | return texParams; 527 | 528 | }, 529 | 530 | loadTexture: function ( url, mapping, onLoad, onProgress, onError ) { 531 | 532 | var texture; 533 | var loader = THREE.Loader.Handlers.get( url ); 534 | var manager = ( this.manager !== undefined ) ? this.manager : THREE.DefaultLoadingManager; 535 | 536 | if ( loader === null ) { 537 | 538 | loader = new THREE.TextureLoader( manager ); 539 | 540 | } 541 | 542 | if ( loader.setCrossOrigin ) loader.setCrossOrigin( this.crossOrigin ); 543 | texture = loader.load( url, onLoad, onProgress, onError ); 544 | 545 | if ( mapping !== undefined ) texture.mapping = mapping; 546 | 547 | return texture; 548 | 549 | } 550 | 551 | }; 552 | -------------------------------------------------------------------------------- /third_party/three.js/js/OBJLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.OBJLoader = ( function () { 6 | 7 | // o object_name | g group_name 8 | var object_pattern = /^[og]\s*(.+)?/; 9 | // mtllib file_reference 10 | var material_library_pattern = /^mtllib /; 11 | // usemtl material_name 12 | var material_use_pattern = /^usemtl /; 13 | 14 | function ParserState() { 15 | 16 | var state = { 17 | objects: [], 18 | object: {}, 19 | 20 | vertices: [], 21 | normals: [], 22 | colors: [], 23 | uvs: [], 24 | 25 | materialLibraries: [], 26 | 27 | startObject: function ( name, fromDeclaration ) { 28 | 29 | // If the current object (initial from reset) is not from a g/o declaration in the parsed 30 | // file. We need to use it for the first parsed g/o to keep things in sync. 31 | if ( this.object && this.object.fromDeclaration === false ) { 32 | 33 | this.object.name = name; 34 | this.object.fromDeclaration = ( fromDeclaration !== false ); 35 | return; 36 | 37 | } 38 | 39 | var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined ); 40 | 41 | if ( this.object && typeof this.object._finalize === 'function' ) { 42 | 43 | this.object._finalize( true ); 44 | 45 | } 46 | 47 | this.object = { 48 | name: name || '', 49 | fromDeclaration: ( fromDeclaration !== false ), 50 | 51 | geometry: { 52 | vertices: [], 53 | normals: [], 54 | colors: [], 55 | uvs: [] 56 | }, 57 | materials: [], 58 | smooth: true, 59 | 60 | startMaterial: function ( name, libraries ) { 61 | 62 | var previous = this._finalize( false ); 63 | 64 | // New usemtl declaration overwrites an inherited material, except if faces were declared 65 | // after the material, then it must be preserved for proper MultiMaterial continuation. 66 | if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) { 67 | 68 | this.materials.splice( previous.index, 1 ); 69 | 70 | } 71 | 72 | var material = { 73 | index: this.materials.length, 74 | name: name || '', 75 | mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ), 76 | smooth: ( previous !== undefined ? previous.smooth : this.smooth ), 77 | groupStart: ( previous !== undefined ? previous.groupEnd : 0 ), 78 | groupEnd: - 1, 79 | groupCount: - 1, 80 | inherited: false, 81 | 82 | clone: function ( index ) { 83 | 84 | var cloned = { 85 | index: ( typeof index === 'number' ? index : this.index ), 86 | name: this.name, 87 | mtllib: this.mtllib, 88 | smooth: this.smooth, 89 | groupStart: 0, 90 | groupEnd: - 1, 91 | groupCount: - 1, 92 | inherited: false 93 | }; 94 | cloned.clone = this.clone.bind( cloned ); 95 | return cloned; 96 | 97 | } 98 | }; 99 | 100 | this.materials.push( material ); 101 | 102 | return material; 103 | 104 | }, 105 | 106 | currentMaterial: function () { 107 | 108 | if ( this.materials.length > 0 ) { 109 | 110 | return this.materials[ this.materials.length - 1 ]; 111 | 112 | } 113 | 114 | return undefined; 115 | 116 | }, 117 | 118 | _finalize: function ( end ) { 119 | 120 | var lastMultiMaterial = this.currentMaterial(); 121 | if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) { 122 | 123 | lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3; 124 | lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart; 125 | lastMultiMaterial.inherited = false; 126 | 127 | } 128 | 129 | // Ignore objects tail materials if no face declarations followed them before a new o/g started. 130 | if ( end && this.materials.length > 1 ) { 131 | 132 | for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) { 133 | 134 | if ( this.materials[ mi ].groupCount <= 0 ) { 135 | 136 | this.materials.splice( mi, 1 ); 137 | 138 | } 139 | 140 | } 141 | 142 | } 143 | 144 | // Guarantee at least one empty material, this makes the creation later more straight forward. 145 | if ( end && this.materials.length === 0 ) { 146 | 147 | this.materials.push( { 148 | name: '', 149 | smooth: this.smooth 150 | } ); 151 | 152 | } 153 | 154 | return lastMultiMaterial; 155 | 156 | } 157 | }; 158 | 159 | // Inherit previous objects material. 160 | // Spec tells us that a declared material must be set to all objects until a new material is declared. 161 | // If a usemtl declaration is encountered while this new object is being parsed, it will 162 | // overwrite the inherited material. Exception being that there was already face declarations 163 | // to the inherited material, then it will be preserved for proper MultiMaterial continuation. 164 | 165 | if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) { 166 | 167 | var declared = previousMaterial.clone( 0 ); 168 | declared.inherited = true; 169 | this.object.materials.push( declared ); 170 | 171 | } 172 | 173 | this.objects.push( this.object ); 174 | 175 | }, 176 | 177 | finalize: function () { 178 | 179 | if ( this.object && typeof this.object._finalize === 'function' ) { 180 | 181 | this.object._finalize( true ); 182 | 183 | } 184 | 185 | }, 186 | 187 | parseVertexIndex: function ( value, len ) { 188 | 189 | var index = parseInt( value, 10 ); 190 | return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; 191 | 192 | }, 193 | 194 | parseNormalIndex: function ( value, len ) { 195 | 196 | var index = parseInt( value, 10 ); 197 | return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; 198 | 199 | }, 200 | 201 | parseUVIndex: function ( value, len ) { 202 | 203 | var index = parseInt( value, 10 ); 204 | return ( index >= 0 ? index - 1 : index + len / 2 ) * 2; 205 | 206 | }, 207 | 208 | addVertex: function ( a, b, c ) { 209 | 210 | var src = this.vertices; 211 | var dst = this.object.geometry.vertices; 212 | 213 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 214 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); 215 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); 216 | 217 | }, 218 | 219 | addVertexLine: function ( a ) { 220 | 221 | var src = this.vertices; 222 | var dst = this.object.geometry.vertices; 223 | 224 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 225 | 226 | }, 227 | 228 | addNormal: function ( a, b, c ) { 229 | 230 | var src = this.normals; 231 | var dst = this.object.geometry.normals; 232 | 233 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 234 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); 235 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); 236 | 237 | }, 238 | 239 | addColor: function ( a, b, c ) { 240 | 241 | var src = this.colors; 242 | var dst = this.object.geometry.colors; 243 | 244 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); 245 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); 246 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); 247 | 248 | }, 249 | 250 | addUV: function ( a, b, c ) { 251 | 252 | var src = this.uvs; 253 | var dst = this.object.geometry.uvs; 254 | 255 | dst.push( src[ a + 0 ], src[ a + 1 ] ); 256 | dst.push( src[ b + 0 ], src[ b + 1 ] ); 257 | dst.push( src[ c + 0 ], src[ c + 1 ] ); 258 | 259 | }, 260 | 261 | addUVLine: function ( a ) { 262 | 263 | var src = this.uvs; 264 | var dst = this.object.geometry.uvs; 265 | 266 | dst.push( src[ a + 0 ], src[ a + 1 ] ); 267 | 268 | }, 269 | 270 | addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) { 271 | 272 | var vLen = this.vertices.length; 273 | 274 | var ia = this.parseVertexIndex( a, vLen ); 275 | var ib = this.parseVertexIndex( b, vLen ); 276 | var ic = this.parseVertexIndex( c, vLen ); 277 | 278 | this.addVertex( ia, ib, ic ); 279 | 280 | if ( ua !== undefined ) { 281 | 282 | var uvLen = this.uvs.length; 283 | 284 | ia = this.parseUVIndex( ua, uvLen ); 285 | ib = this.parseUVIndex( ub, uvLen ); 286 | ic = this.parseUVIndex( uc, uvLen ); 287 | 288 | this.addUV( ia, ib, ic ); 289 | 290 | } 291 | 292 | if ( na !== undefined ) { 293 | 294 | // Normals are many times the same. If so, skip function call and parseInt. 295 | var nLen = this.normals.length; 296 | ia = this.parseNormalIndex( na, nLen ); 297 | 298 | ib = na === nb ? ia : this.parseNormalIndex( nb, nLen ); 299 | ic = na === nc ? ia : this.parseNormalIndex( nc, nLen ); 300 | 301 | this.addNormal( ia, ib, ic ); 302 | 303 | } 304 | 305 | if ( this.colors.length > 0 ) { 306 | 307 | this.addColor( ia, ib, ic ); 308 | 309 | } 310 | 311 | }, 312 | 313 | addLineGeometry: function ( vertices, uvs ) { 314 | 315 | this.object.geometry.type = 'Line'; 316 | 317 | var vLen = this.vertices.length; 318 | var uvLen = this.uvs.length; 319 | 320 | for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) { 321 | 322 | this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) ); 323 | 324 | } 325 | 326 | for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) { 327 | 328 | this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) ); 329 | 330 | } 331 | 332 | } 333 | 334 | }; 335 | 336 | state.startObject( '', false ); 337 | 338 | return state; 339 | 340 | } 341 | 342 | // 343 | 344 | function OBJLoader( manager ) { 345 | 346 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; 347 | 348 | this.materials = null; 349 | 350 | } 351 | 352 | OBJLoader.prototype = { 353 | 354 | constructor: OBJLoader, 355 | 356 | load: function ( url, onLoad, onProgress, onError ) { 357 | 358 | var scope = this; 359 | 360 | var loader = new THREE.FileLoader( scope.manager ); 361 | loader.setPath( this.path ); 362 | loader.load( url, function ( text ) { 363 | 364 | onLoad( scope.parse( text ) ); 365 | 366 | }, onProgress, onError ); 367 | 368 | }, 369 | 370 | setPath: function ( value ) { 371 | 372 | this.path = value; 373 | 374 | }, 375 | 376 | setMaterials: function ( materials ) { 377 | 378 | this.materials = materials; 379 | 380 | return this; 381 | 382 | }, 383 | 384 | parse: function ( text ) { 385 | 386 | console.time( 'OBJLoader' ); 387 | 388 | var state = new ParserState(); 389 | 390 | if ( text.indexOf( '\r\n' ) !== - 1 ) { 391 | 392 | // This is faster than String.split with regex that splits on both 393 | text = text.replace( /\r\n/g, '\n' ); 394 | 395 | } 396 | 397 | if ( text.indexOf( '\\\n' ) !== - 1 ) { 398 | 399 | // join lines separated by a line continuation character (\) 400 | text = text.replace( /\\\n/g, '' ); 401 | 402 | } 403 | 404 | var lines = text.split( '\n' ); 405 | var line = '', lineFirstChar = ''; 406 | var lineLength = 0; 407 | var result = []; 408 | 409 | // Faster to just trim left side of the line. Use if available. 410 | var trimLeft = ( typeof ''.trimLeft === 'function' ); 411 | 412 | for ( var i = 0, l = lines.length; i < l; i ++ ) { 413 | 414 | line = lines[ i ]; 415 | 416 | line = trimLeft ? line.trimLeft() : line.trim(); 417 | 418 | lineLength = line.length; 419 | 420 | if ( lineLength === 0 ) continue; 421 | 422 | lineFirstChar = line.charAt( 0 ); 423 | 424 | // @todo invoke passed in handler if any 425 | if ( lineFirstChar === '#' ) continue; 426 | 427 | if ( lineFirstChar === 'v' ) { 428 | 429 | var data = line.split( /\s+/ ); 430 | 431 | switch ( data[ 0 ] ) { 432 | 433 | case 'v': 434 | state.vertices.push( 435 | parseFloat( data[ 1 ] ), 436 | parseFloat( data[ 2 ] ), 437 | parseFloat( data[ 3 ] ) 438 | ); 439 | if ( data.length === 8 ) { 440 | 441 | state.colors.push( 442 | parseFloat( data[ 4 ] ), 443 | parseFloat( data[ 5 ] ), 444 | parseFloat( data[ 6 ] ) 445 | 446 | ); 447 | 448 | } 449 | break; 450 | case 'vn': 451 | state.normals.push( 452 | parseFloat( data[ 1 ] ), 453 | parseFloat( data[ 2 ] ), 454 | parseFloat( data[ 3 ] ) 455 | ); 456 | break; 457 | case 'vt': 458 | state.uvs.push( 459 | parseFloat( data[ 1 ] ), 460 | parseFloat( data[ 2 ] ) 461 | ); 462 | break; 463 | 464 | } 465 | 466 | } else if ( lineFirstChar === 'f' ) { 467 | 468 | var lineData = line.substr( 1 ).trim(); 469 | var vertexData = lineData.split( /\s+/ ); 470 | var faceVertices = []; 471 | 472 | // Parse the face vertex data into an easy to work with format 473 | 474 | for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) { 475 | 476 | var vertex = vertexData[ j ]; 477 | 478 | if ( vertex.length > 0 ) { 479 | 480 | var vertexParts = vertex.split( '/' ); 481 | faceVertices.push( vertexParts ); 482 | 483 | } 484 | 485 | } 486 | 487 | // Draw an edge between the first vertex and all subsequent vertices to form an n-gon 488 | 489 | var v1 = faceVertices[ 0 ]; 490 | 491 | for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) { 492 | 493 | var v2 = faceVertices[ j ]; 494 | var v3 = faceVertices[ j + 1 ]; 495 | 496 | state.addFace( 497 | v1[ 0 ], v2[ 0 ], v3[ 0 ], 498 | v1[ 1 ], v2[ 1 ], v3[ 1 ], 499 | v1[ 2 ], v2[ 2 ], v3[ 2 ] 500 | ); 501 | 502 | } 503 | 504 | } else if ( lineFirstChar === 'l' ) { 505 | 506 | var lineParts = line.substring( 1 ).trim().split( " " ); 507 | var lineVertices = [], lineUVs = []; 508 | 509 | if ( line.indexOf( "/" ) === - 1 ) { 510 | 511 | lineVertices = lineParts; 512 | 513 | } else { 514 | 515 | for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) { 516 | 517 | var parts = lineParts[ li ].split( "/" ); 518 | 519 | if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] ); 520 | if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] ); 521 | 522 | } 523 | 524 | } 525 | state.addLineGeometry( lineVertices, lineUVs ); 526 | 527 | } else if ( ( result = object_pattern.exec( line ) ) !== null ) { 528 | 529 | // o object_name 530 | // or 531 | // g group_name 532 | 533 | // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869 534 | // var name = result[ 0 ].substr( 1 ).trim(); 535 | var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 ); 536 | 537 | state.startObject( name ); 538 | 539 | } else if ( material_use_pattern.test( line ) ) { 540 | 541 | // material 542 | 543 | state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries ); 544 | 545 | } else if ( material_library_pattern.test( line ) ) { 546 | 547 | // mtl file 548 | 549 | state.materialLibraries.push( line.substring( 7 ).trim() ); 550 | 551 | } else if ( lineFirstChar === 's' ) { 552 | 553 | result = line.split( ' ' ); 554 | 555 | // smooth shading 556 | 557 | // @todo Handle files that have varying smooth values for a set of faces inside one geometry, 558 | // but does not define a usemtl for each face set. 559 | // This should be detected and a dummy material created (later MultiMaterial and geometry groups). 560 | // This requires some care to not create extra material on each smooth value for "normal" obj files. 561 | // where explicit usemtl defines geometry groups. 562 | // Example asset: examples/models/obj/cerberus/Cerberus.obj 563 | 564 | /* 565 | * http://paulbourke.net/dataformats/obj/ 566 | * or 567 | * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf 568 | * 569 | * From chapter "Grouping" Syntax explanation "s group_number": 570 | * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off. 571 | * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form 572 | * surfaces, smoothing groups are either turned on or off; there is no difference between values greater 573 | * than 0." 574 | */ 575 | if ( result.length > 1 ) { 576 | 577 | var value = result[ 1 ].trim().toLowerCase(); 578 | state.object.smooth = ( value !== '0' && value !== 'off' ); 579 | 580 | } else { 581 | 582 | // ZBrush can produce "s" lines #11707 583 | state.object.smooth = true; 584 | 585 | } 586 | var material = state.object.currentMaterial(); 587 | if ( material ) material.smooth = state.object.smooth; 588 | 589 | } else { 590 | 591 | // Handle null terminated files without exception 592 | if ( line === '\0' ) continue; 593 | 594 | throw new Error( 'THREE.OBJLoader: Unexpected line: "' + line + '"' ); 595 | 596 | } 597 | 598 | } 599 | 600 | state.finalize(); 601 | 602 | var container = new THREE.Group(); 603 | container.materialLibraries = [].concat( state.materialLibraries ); 604 | 605 | for ( var i = 0, l = state.objects.length; i < l; i ++ ) { 606 | 607 | var object = state.objects[ i ]; 608 | var geometry = object.geometry; 609 | var materials = object.materials; 610 | var isLine = ( geometry.type === 'Line' ); 611 | 612 | // Skip o/g line declarations that did not follow with any faces 613 | if ( geometry.vertices.length === 0 ) continue; 614 | 615 | var buffergeometry = new THREE.BufferGeometry(); 616 | 617 | buffergeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) ); 618 | 619 | if ( geometry.normals.length > 0 ) { 620 | 621 | buffergeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) ); 622 | 623 | } else { 624 | 625 | buffergeometry.computeVertexNormals(); 626 | 627 | } 628 | 629 | if ( geometry.colors.length > 0 ) { 630 | 631 | buffergeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) ); 632 | 633 | } 634 | 635 | if ( geometry.uvs.length > 0 ) { 636 | 637 | buffergeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) ); 638 | 639 | } 640 | 641 | // Create materials 642 | 643 | var createdMaterials = []; 644 | 645 | for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { 646 | 647 | var sourceMaterial = materials[ mi ]; 648 | var material = undefined; 649 | 650 | if ( this.materials !== null ) { 651 | 652 | material = this.materials.create( sourceMaterial.name ); 653 | 654 | // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material. 655 | if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) { 656 | 657 | var materialLine = new THREE.LineBasicMaterial(); 658 | materialLine.copy( material ); 659 | materialLine.lights = false; // TOFIX 660 | material = materialLine; 661 | 662 | } 663 | 664 | } 665 | 666 | if ( ! material ) { 667 | 668 | material = ( ! isLine ? new THREE.MeshPhongMaterial() : new THREE.LineBasicMaterial() ); 669 | material.name = sourceMaterial.name; 670 | 671 | } 672 | 673 | material.flatShading = sourceMaterial.smooth ? false : true; 674 | 675 | createdMaterials.push( material ); 676 | 677 | } 678 | 679 | // Create mesh 680 | 681 | var mesh; 682 | 683 | if ( createdMaterials.length > 1 ) { 684 | 685 | for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { 686 | 687 | var sourceMaterial = materials[ mi ]; 688 | buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi ); 689 | 690 | } 691 | 692 | mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials ) : new THREE.LineSegments( buffergeometry, createdMaterials ) ); 693 | 694 | } else { 695 | 696 | mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ) : new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ) ); 697 | 698 | } 699 | 700 | mesh.name = object.name; 701 | 702 | container.add( mesh ); 703 | 704 | } 705 | 706 | console.timeEnd( 'OBJLoader' ); 707 | 708 | return container; 709 | 710 | } 711 | 712 | }; 713 | 714 | return OBJLoader; 715 | 716 | } )(); 717 | -------------------------------------------------------------------------------- /tiltbrush-sample.html: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 49 | 50 | 51 | 52 |
53 | 54 |
55 | Title
56 | by Author 57 |
58 | 59 | 60 | 61 | 143 | 144 | 145 | --------------------------------------------------------------------------------