Merge pull request #49 from AnalyticalGraphicsInc/major-cleanup
Refactor and Tests
|
@ -0,0 +1,12 @@
|
||||||
|
# http://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
|
@ -2,9 +2,6 @@
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
|
||||||
# TypeScript definitions
|
|
||||||
typings
|
|
||||||
|
|
||||||
# WebStorm user-specific
|
# WebStorm user-specific
|
||||||
.idea/workspace.xml
|
.idea/workspace.xml
|
||||||
.idea/tasks.xml
|
.idea/tasks.xml
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaScriptLibraryMappings">
|
|
||||||
<file url="PROJECT" libraries="{typings}" />
|
|
||||||
<includedPredefinedLibrary name="Node.js Core" />
|
|
||||||
<excludedPredefinedLibrary name="HTML" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<component name="libraryTable">
|
|
||||||
<library name="typings" type="javaScript">
|
|
||||||
<properties>
|
|
||||||
<sourceFilesUrls>
|
|
||||||
<item url="file://$PROJECT_DIR$/typings" />
|
|
||||||
</sourceFilesUrls>
|
|
||||||
</properties>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="file://$PROJECT_DIR$/typings" />
|
|
||||||
</CLASSES>
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
|
@ -2,7 +2,7 @@
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/OBJ2GLTF.iml" filepath="$PROJECT_DIR$/.idea/OBJ2GLTF.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/obj2gltf.iml" filepath="$PROJECT_DIR$/.idea/obj2gltf.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -7,6 +7,5 @@
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="typings" level="project" />
|
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
|
@ -4,10 +4,9 @@
|
||||||
/output
|
/output
|
||||||
/specs
|
/specs
|
||||||
/test
|
/test
|
||||||
/typings
|
/output
|
||||||
.jshintrc
|
.jshintrc
|
||||||
.npmignore
|
.npmignore
|
||||||
.travis.yml
|
.travis.yml
|
||||||
gulpfile.js
|
gulpfile.js
|
||||||
typings.json
|
|
||||||
*.tgz
|
*.tgz
|
||||||
|
|
|
@ -5,7 +5,8 @@ node_js:
|
||||||
script:
|
script:
|
||||||
- npm run jsHint -- --failTaskOnError
|
- npm run jsHint -- --failTaskOnError
|
||||||
- npm run test -- --failTaskOnError --suppressPassed
|
- npm run test -- --failTaskOnError --suppressPassed
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
## We only need to run coveralls for one node version (doesn't matter which one).
|
## We only need to run coveralls for one node version (doesn't matter which one).
|
||||||
## We also ignore publishing failures, since restarting an existing travis build would otherwise break.
|
## We also ignore publishing failures, since restarting an existing travis build would otherwise break.
|
||||||
- if node --version | grep -q ^v6 ; npm run coveralls ; fi
|
- if node --version | grep -q ^v6 ; npm run coverage && npm run coveralls; fi
|
||||||
|
|
188
LICENSE.md
|
@ -11,79 +11,29 @@ Third-Party Code
|
||||||
|
|
||||||
obj2gltf includes the following third-party code.
|
obj2gltf includes the following third-party code.
|
||||||
|
|
||||||
### async
|
|
||||||
|
|
||||||
https://www.npmjs.com/package/async
|
|
||||||
|
|
||||||
> Copyright (c) 2010-2016 Caolan McMahon
|
|
||||||
>
|
|
||||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
>
|
|
||||||
> The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
>
|
|
||||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
### bluebird
|
### bluebird
|
||||||
|
|
||||||
https://www.npmjs.com/package/bluebird
|
|
||||||
|
|
||||||
> The MIT License (MIT)
|
> The MIT License (MIT)
|
||||||
>
|
>
|
||||||
> Copyright (c) 2013-2015 Petka Antonov
|
> Copyright (c) 2013-2015 Petka Antonov
|
||||||
>
|
>
|
||||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
> of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
> in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
> copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
> furnished to do so, subject to the following conditions:
|
||||||
>
|
>
|
||||||
> The above copyright notice and this permission notice shall be included in
|
> The above copyright notice and this permission notice shall be included in
|
||||||
all copies or substantial portions of the Software.
|
> all copies or substantial portions of the Software.
|
||||||
>
|
>
|
||||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
> THE SOFTWARE.
|
||||||
|
|
||||||
### byline
|
|
||||||
|
|
||||||
https://www.npmjs.com/package/byline
|
|
||||||
|
|
||||||
> node-byline (C) 2011-2015 John Hewson
|
|
||||||
>
|
|
||||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to
|
|
||||||
deal in the Software without restriction, including without limitation the
|
|
||||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
>
|
|
||||||
> The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
>
|
|
||||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
IN THE SOFTWARE.
|
|
||||||
|
|
||||||
### Cesium
|
### Cesium
|
||||||
|
|
||||||
|
@ -99,6 +49,35 @@ http://cesiumjs.org/
|
||||||
|
|
||||||
See https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md
|
See https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md
|
||||||
|
|
||||||
|
### event-stream
|
||||||
|
|
||||||
|
https://www.npmjs.com/package/event-stream
|
||||||
|
|
||||||
|
> The MIT License (MIT)
|
||||||
|
>
|
||||||
|
> Copyright (c) 2011 Dominic Tarr
|
||||||
|
>
|
||||||
|
> Permission is hereby granted, free of charge,
|
||||||
|
> to any person obtaining a copy of this software and
|
||||||
|
> associated documentation files (the "Software"), to
|
||||||
|
> deal in the Software without restriction, including
|
||||||
|
> without limitation the rights to use, copy, modify,
|
||||||
|
> merge, publish, distribute, sublicense, and/or sell
|
||||||
|
> copies of the Software, and to permit persons to whom
|
||||||
|
> the Software is furnished to do so,
|
||||||
|
> subject to the following conditions:
|
||||||
|
>
|
||||||
|
> The above copyright notice and this permission notice
|
||||||
|
> shall be included in all copies or substantial portions of the Software.
|
||||||
|
>
|
||||||
|
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
> OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
> ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
### fs-extra
|
### fs-extra
|
||||||
|
|
||||||
https://www.npmjs.com/package/fs-extra
|
https://www.npmjs.com/package/fs-extra
|
||||||
|
@ -108,16 +87,16 @@ https://www.npmjs.com/package/fs-extra
|
||||||
> Copyright (c) 2011-2016 JP Richardson
|
> Copyright (c) 2011-2016 JP Richardson
|
||||||
>
|
>
|
||||||
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
|
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
|
||||||
(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
|
> (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
|
||||||
> merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
> merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||||
> furnished to do so, subject to the following conditions:
|
> furnished to do so, subject to the following conditions:
|
||||||
>
|
>
|
||||||
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
>
|
||||||
> THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
> THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
> WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||||
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
> OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
> ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
### gltf-pipeline
|
### gltf-pipeline
|
||||||
|
|
||||||
|
@ -131,6 +110,55 @@ https://www.npmjs.com/package/gltf-pipeline
|
||||||
>
|
>
|
||||||
> Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
> Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
### mime
|
||||||
|
|
||||||
|
https://www.npmjs.com/package/mime
|
||||||
|
|
||||||
|
> Copyright (c) 2010 Benjamin Thomas, Robert Kieffer
|
||||||
|
>
|
||||||
|
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
> of this software and associated documentation files (the "Software"), to deal
|
||||||
|
> in the Software without restriction, including without limitation the rights
|
||||||
|
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
> copies of the Software, and to permit persons to whom the Software is
|
||||||
|
> furnished to do so, subject to the following conditions:
|
||||||
|
>
|
||||||
|
> The above copyright notice and this permission notice shall be included in
|
||||||
|
> all copies or substantial portions of the Software.
|
||||||
|
>
|
||||||
|
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
> THE SOFTWARE.
|
||||||
|
|
||||||
|
### pngjs
|
||||||
|
|
||||||
|
https://www.npmjs.com/package/pngjs
|
||||||
|
|
||||||
|
> pngjs2 original work Copyright (c) 2015 Luke Page & Original Contributors
|
||||||
|
> pngjs derived work Copyright (c) 2012 Kuba Niegowski
|
||||||
|
>
|
||||||
|
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
> of this software and associated documentation files (the "Software"), to deal
|
||||||
|
> in the Software without restriction, including without limitation the rights
|
||||||
|
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
> copies of the Software, and to permit persons to whom the Software is
|
||||||
|
> furnished to do so, subject to the following conditions:
|
||||||
|
>
|
||||||
|
> The above copyright notice and this permission notice shall be included in
|
||||||
|
> all copies or substantial portions of the Software.
|
||||||
|
>
|
||||||
|
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
> THE SOFTWARE.
|
||||||
|
|
||||||
### yargs
|
### yargs
|
||||||
|
|
||||||
https://www.npmjs.com/package/yargs
|
https://www.npmjs.com/package/yargs
|
||||||
|
@ -138,24 +166,24 @@ https://www.npmjs.com/package/yargs
|
||||||
The command-line tool uses yargs.
|
The command-line tool uses yargs.
|
||||||
|
|
||||||
> Copyright 2010 James Halliday (mail@substack.net)
|
> Copyright 2010 James Halliday (mail@substack.net)
|
||||||
Modified work Copyright 2014 Contributors (ben@npmjs.com)
|
> Modified work Copyright 2014 Contributors (ben@npmjs.com)
|
||||||
>
|
>
|
||||||
> This project is free software released under the MIT/X11 license:
|
> This project is free software released under the MIT/X11 license:
|
||||||
>
|
>
|
||||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
> of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
> in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
> copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
> furnished to do so, subject to the following conditions:
|
||||||
>
|
>
|
||||||
> The above copyright notice and this permission notice shall be included in
|
> The above copyright notice and this permission notice shall be included in
|
||||||
all copies or substantial portions of the Software.
|
> all copies or substantial portions of the Software.
|
||||||
>
|
>
|
||||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
> THE SOFTWARE.
|
||||||
|
|
32
README.md
|
@ -11,39 +11,41 @@ npm install --save obj2gltf
|
||||||
Using obj2gltf as a library:
|
Using obj2gltf as a library:
|
||||||
```javascript
|
```javascript
|
||||||
var obj2gltf = require('obj2gltf');
|
var obj2gltf = require('obj2gltf');
|
||||||
var convert = obj2gltf.convert;
|
|
||||||
var options = {
|
var options = {
|
||||||
embedImage : false // Don't embed image in the converted glTF
|
separateTextures : true // Don't embed textures in the converted glTF
|
||||||
}
|
}
|
||||||
convert('model.obj', 'model.gltf', options)
|
obj2gltf('model.obj', 'model.gltf', options)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
console.log('Converted model');
|
console.log('Converted model');
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
Using obj2gltf as a command-line tool:
|
Using obj2gltf as a command-line tool:
|
||||||
|
|
||||||
`node bin/obj2gltf.js model.obj`
|
`node bin/obj2gltf.js -i model.obj`
|
||||||
|
|
||||||
`node bin/obj2gltf.js model.obj model.gltf`
|
|
||||||
|
|
||||||
`node bin/obj2gltf.js -i model.obj -o model.gltf`
|
`node bin/obj2gltf.js -i model.obj -o model.gltf`
|
||||||
|
|
||||||
`node bin/obj2gltf.js -i model.obj -o model.gltf -s`
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
###Command line flags:
|
###Command line flags:
|
||||||
|
|
||||||
|Flag|Description|Required|
|
|Flag|Description|Required|
|
||||||
|----|-----------|--------|
|
|----|-----------|--------|
|
||||||
|`-i`|Path to the input OBJ file.| :white_check_mark: Yes|
|
|`-h`, `--help`|Display help.|No|
|
||||||
|`-o`|Directory or filename for the exported glTF file.|No|
|
|`-i`, `--input`|Path to the obj file.| :white_check_mark: Yes|
|
||||||
|`-b`|Output binary glTF.|No, default `false`|
|
|`-o`, `--output`|Path of the converted glTF file.|No|
|
||||||
|`-s`|Writes out separate geometry/animation data files, shader files, and textures instead of embedding them in the glTF file.|No, default `false`|
|
|`-b`, `--binary`|Save as binary glTF.|No, default `false`|
|
||||||
|`-t`|Write out separate textures only.|No, default `false`|
|
|`-s`, `--separate`|Writes out separate geometry data files, shader files, and textures instead of embedding them in the glTF file.|No, default `false`|
|
||||||
|
|`-t`, `--separateTextures`|Write out separate textures only.|No, default `false`|
|
||||||
|
|`-c`, `--compress`|Quantize positions, compress texture coordinates, and oct-encode normals.|No, default `false`|
|
||||||
|
|`-z`, `--optimize`|Use the optimization stages in the glTF pipeline.|No, default `false`|
|
||||||
|
|`-n`, `--generateNormals`|Generate normals if they are missing.|No, default `false`|
|
||||||
|
|`--optimizeForCesium`|Optimize the glTF for Cesium by using the sun as a default light source.|No, default `false`|
|
||||||
|`--ao`|Apply ambient occlusion to the converted model.|No, default `false`|
|
|`--ao`|Apply ambient occlusion to the converted model.|No, default `false`|
|
||||||
|`-h`|Display help|No|
|
|`--kmc|Output glTF with the KHR_materials_common extension.|No, default `false`|
|
||||||
|
|`--bypassPipeline`|Bypass the gltf-pipeline for debugging purposes. This option overrides many of the options above and will save the glTF with the KHR_materials_common extension.|No, default `false`|
|
||||||
|
|`--checkTransparency`|Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. By default textures are considered to be opaque.|No, default `false`|
|
||||||
|
|`--secure`|Prevent the converter from reading image or mtl files outside of the input obj directory.|No, default `false`|
|
||||||
|
|
||||||
## Build Instructions
|
## Build Instructions
|
||||||
|
|
||||||
|
|
160
bin/obj2gltf.js
|
@ -1,53 +1,133 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
"use strict";
|
'use strict';
|
||||||
var argv = require('yargs').argv;
|
|
||||||
var Cesium = require('cesium');
|
var Cesium = require('cesium');
|
||||||
var defined = Cesium.defined;
|
var path = require('path');
|
||||||
var defaultValue = Cesium.defaultValue;
|
var yargs = require('yargs');
|
||||||
var convert = require('../lib/convert');
|
var convert = require('../lib/convert');
|
||||||
|
|
||||||
if (process.argv.length < 3 || defined(argv.h) || defined(argv.help)) {
|
var defined = Cesium.defined;
|
||||||
console.log('Usage: ./bin/obj2gltf.js [INPUT] [OPTIONS]');
|
|
||||||
console.log(' -i, --input Path to obj file');
|
var defaults = convert.defaults;
|
||||||
console.log(' -o, --output Directory or filename for the exported glTF file');
|
|
||||||
console.log(' -b, --binary Output binary glTF');
|
var args = process.argv;
|
||||||
console.log(' -s --separate Writes out separate geometry/animation data files, shader files, and textures instead of embedding them in the glTF file.');
|
|
||||||
console.log(' -t --separateImage Write out separate textures only.');
|
var argv = yargs
|
||||||
console.log(' -c --compress Quantize positions, compress texture coordinates, and oct-encode normals.');
|
.usage('Usage: node $0 -i inputPath -o outputPath')
|
||||||
console.log(' -h, --help Display this help');
|
.example('node $0 -i ./specs/data/box/box.obj -o box.gltf')
|
||||||
console.log(' --ao Apply ambient occlusion to the converted model');
|
.help('h')
|
||||||
console.log(' --cesium Optimize the glTF for Cesium by using the sun as a default light source.');
|
.alias('h', 'help')
|
||||||
process.exit(0);
|
.options({
|
||||||
|
input : {
|
||||||
|
alias: 'i',
|
||||||
|
describe: 'Path to the obj file.',
|
||||||
|
type: 'string',
|
||||||
|
normalize: true,
|
||||||
|
demandOption: true
|
||||||
|
},
|
||||||
|
output : {
|
||||||
|
alias: 'o',
|
||||||
|
describe: 'Path of the converted glTF file.',
|
||||||
|
type: 'string',
|
||||||
|
normalize: true
|
||||||
|
},
|
||||||
|
binary : {
|
||||||
|
alias: 'b',
|
||||||
|
describe: 'Save as binary glTF.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.binary
|
||||||
|
},
|
||||||
|
separate : {
|
||||||
|
alias: 's',
|
||||||
|
describe: 'Write separate geometry data files, shader files, and textures instead of embedding them in the glTF.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.separate
|
||||||
|
},
|
||||||
|
separateTextures : {
|
||||||
|
alias: 't',
|
||||||
|
describe: 'Write out separate textures only.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.separateTextures
|
||||||
|
},
|
||||||
|
compress : {
|
||||||
|
alias: 'c',
|
||||||
|
describe: 'Quantize positions, compress texture coordinates, and oct-encode normals.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.compress
|
||||||
|
},
|
||||||
|
optimize : {
|
||||||
|
alias: 'z',
|
||||||
|
describe: 'Optimize the glTF for size and runtime performance.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.optimize
|
||||||
|
},
|
||||||
|
optimizeForCesium : {
|
||||||
|
describe: 'Optimize the glTF for Cesium by using the sun as a default light source.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.optimizeForCesium
|
||||||
|
},
|
||||||
|
generateNormals : {
|
||||||
|
alias: 'n',
|
||||||
|
describe: 'Generate normals if they are missing.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.generateNormals
|
||||||
|
},
|
||||||
|
ao : {
|
||||||
|
describe: 'Apply ambient occlusion to the converted model.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.ao
|
||||||
|
},
|
||||||
|
kmc : {
|
||||||
|
describe: 'Output glTF with the KHR_materials_common extension.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.kmc
|
||||||
|
},
|
||||||
|
bypassPipeline : {
|
||||||
|
describe: 'Bypass the gltf-pipeline for debugging purposes. This option overrides many of the options above and will save the glTF with the KHR_materials_common extension.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.bypassPipeline
|
||||||
|
},
|
||||||
|
checkTransparency : {
|
||||||
|
describe: 'Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. By default textures are considered to be opaque.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.checkTransparency
|
||||||
|
},
|
||||||
|
secure : {
|
||||||
|
describe: 'Prevent the converter from reading image or mtl files outside of the input obj directory.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: defaults.secure
|
||||||
|
}
|
||||||
|
}).parse(args);
|
||||||
|
|
||||||
|
var objPath = argv.i;
|
||||||
|
var gltfPath = argv.o;
|
||||||
|
|
||||||
|
if (!defined(gltfPath)) {
|
||||||
|
var extension = argv.b ? '.glb' : '.gltf';
|
||||||
|
var modelName = path.basename(objPath, path.extname(objPath));
|
||||||
|
gltfPath = path.join(path.dirname(objPath), modelName + extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
var objFile = defaultValue(argv._[0], defaultValue(argv.i, argv.input));
|
var options = {
|
||||||
var outputPath = defaultValue(argv._[1], defaultValue(argv.o, argv.output));
|
binary : argv.binary,
|
||||||
var binary = defaultValue(defaultValue(argv.b, argv.binary), false);
|
separate : argv.separate,
|
||||||
var separate = defaultValue(defaultValue(argv.s, argv.separate), false);
|
separateTextures : argv.separateTextures,
|
||||||
var separateImage = defaultValue(defaultValue(argv.t, argv.separateImage), false);
|
compress : argv.compress,
|
||||||
var compress = defaultValue(defaultValue(argv.c, argv.compress), false);
|
optimize : argv.optimize,
|
||||||
var ao = defaultValue(argv.ao, false);
|
optimizeForCesium : argv.optimizeForCesium,
|
||||||
var optimizeForCesium = defaultValue(argv.cesium, false);
|
generateNormals : argv.generateNormals,
|
||||||
|
ao : argv.ao,
|
||||||
if (!defined(objFile)) {
|
kmc : argv.kmc,
|
||||||
throw new Error('-i or --input argument is required. See --help for details.');
|
bypassPipeline : argv.bypassPipeline,
|
||||||
}
|
checkTransparency : argv.checkTransparency,
|
||||||
|
secure : argv.secure
|
||||||
|
};
|
||||||
|
|
||||||
console.time('Total');
|
console.time('Total');
|
||||||
|
|
||||||
var options = {
|
convert(objPath, gltfPath, options)
|
||||||
binary : binary,
|
|
||||||
embed : !separate,
|
|
||||||
embedImage : !separateImage,
|
|
||||||
compress : compress,
|
|
||||||
ao : ao,
|
|
||||||
optimizeForCesium : optimizeForCesium
|
|
||||||
};
|
|
||||||
|
|
||||||
convert(objFile, outputPath, options)
|
|
||||||
.then(function() {
|
.then(function() {
|
||||||
console.timeEnd('Total');
|
console.timeEnd('Total');
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(error) {
|
||||||
console.log(err);
|
console.log(error.message);
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ var fsExtra = require('fs-extra');
|
||||||
var gulp = require('gulp');
|
var gulp = require('gulp');
|
||||||
var gulpJshint = require('gulp-jshint');
|
var gulpJshint = require('gulp-jshint');
|
||||||
var Jasmine = require('jasmine');
|
var Jasmine = require('jasmine');
|
||||||
var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
var JasmineSpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||||
var open = require('open');
|
var open = require('open');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var yargs = require('yargs');
|
var yargs = require('yargs');
|
||||||
|
@ -21,7 +21,7 @@ var nodeBinaries = path.join(__dirname, 'node_modules', '.bin');
|
||||||
process.env.PATH += environmentSeparator + nodeBinaries;
|
process.env.PATH += environmentSeparator + nodeBinaries;
|
||||||
|
|
||||||
var jsHintFiles = ['**/*.js', '!node_modules/**', '!coverage/**', '!doc/**'];
|
var jsHintFiles = ['**/*.js', '!node_modules/**', '!coverage/**', '!doc/**'];
|
||||||
var specFiles = ['**/*.js', '!node_modules/**', '!coverage/**'];
|
var specFiles = ['**/*.js', '!node_modules/**', '!coverage/**', '!doc/**', '!bin/**'];
|
||||||
|
|
||||||
gulp.task('jsHint', function () {
|
gulp.task('jsHint', function () {
|
||||||
var stream = gulp.src(jsHintFiles)
|
var stream = gulp.src(jsHintFiles)
|
||||||
|
@ -42,7 +42,7 @@ gulp.task('jsHint-watch', function () {
|
||||||
gulp.task('test', function (done) {
|
gulp.task('test', function (done) {
|
||||||
var jasmine = new Jasmine();
|
var jasmine = new Jasmine();
|
||||||
jasmine.loadConfigFile('specs/jasmine.json');
|
jasmine.loadConfigFile('specs/jasmine.json');
|
||||||
jasmine.addReporter(new SpecReporter({
|
jasmine.addReporter(new JasmineSpecReporter({
|
||||||
displaySuccessfulSpec: !defined(argv.suppressPassed) || !argv.suppressPassed
|
displaySuccessfulSpec: !defined(argv.suppressPassed) || !argv.suppressPassed
|
||||||
}));
|
}));
|
||||||
jasmine.execute();
|
jasmine.execute();
|
||||||
|
@ -71,7 +71,7 @@ gulp.task('coverage', function () {
|
||||||
' cover' +
|
' cover' +
|
||||||
' --include-all-sources' +
|
' --include-all-sources' +
|
||||||
' --dir coverage' +
|
' --dir coverage' +
|
||||||
' -x "specs/** coverage/** index.js gulpfile.js"' +
|
' -x "specs/**" -x "coverage/**" -x "doc/**" -x "bin/**" -x "index.js" -x "gulpfile.js"' +
|
||||||
' node_modules/jasmine/bin/jasmine.js' +
|
' node_modules/jasmine/bin/jasmine.js' +
|
||||||
' JASMINE_CONFIG_PATH=specs/jasmine.json', {
|
' JASMINE_CONFIG_PATH=specs/jasmine.json', {
|
||||||
stdio: [process.stdin, process.stdout, process.stderr]
|
stdio: [process.stdin, process.stdout, process.stderr]
|
||||||
|
|
4
index.js
|
@ -1,3 +1 @@
|
||||||
module.exports = {
|
module.exports = require('./lib/convert');
|
||||||
convert : require('./lib/convert')
|
|
||||||
};
|
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
'use strict';
|
||||||
|
var Cesium = require('cesium');
|
||||||
|
|
||||||
|
var ComponentDatatype = Cesium.ComponentDatatype;
|
||||||
|
|
||||||
|
module.exports = ArrayStorage;
|
||||||
|
|
||||||
|
var initialLength = 1024; // 2^10
|
||||||
|
var doublingThreshold = 33554432; // 2^25 (~134 MB for a Float32Array)
|
||||||
|
var fixedExpansionLength = 33554432; // 2^25 (~134 MB for a Float32Array)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides expandable typed array storage for geometry data. This is preferable to JS arrays which are
|
||||||
|
* stored with double precision. The resizing mechanism is similar to std::vector.
|
||||||
|
*
|
||||||
|
* @param {ComponentDatatype} componentDatatype The data type.
|
||||||
|
* @constructor
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function ArrayStorage(componentDatatype) {
|
||||||
|
this.componentDatatype = componentDatatype;
|
||||||
|
this.typedArray = ComponentDatatype.createTypedArray(componentDatatype, 0);
|
||||||
|
this.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resize(storage, length) {
|
||||||
|
var typedArray = ComponentDatatype.createTypedArray(storage.componentDatatype, length);
|
||||||
|
typedArray.set(storage.typedArray);
|
||||||
|
storage.typedArray = typedArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayStorage.prototype.push = function(value) {
|
||||||
|
var length = this.length;
|
||||||
|
var typedArrayLength = this.typedArray.length;
|
||||||
|
|
||||||
|
if (length === 0) {
|
||||||
|
resize(this, initialLength);
|
||||||
|
} else if (length === typedArrayLength) {
|
||||||
|
if (length < doublingThreshold) {
|
||||||
|
resize(this, typedArrayLength * 2);
|
||||||
|
} else {
|
||||||
|
resize(this, typedArrayLength + fixedExpansionLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.typedArray[this.length++] = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrayStorage.prototype.get = function(index) {
|
||||||
|
return this.typedArray[index];
|
||||||
|
};
|
||||||
|
|
||||||
|
var sizeOfUint16 = 2;
|
||||||
|
var sizeOfUint32 = 4;
|
||||||
|
var sizeOfFloat = 4;
|
||||||
|
|
||||||
|
ArrayStorage.prototype.toUint16Buffer = function() {
|
||||||
|
var length = this.length;
|
||||||
|
var typedArray = this.typedArray;
|
||||||
|
var paddedLength = length + ((length % 2 === 0) ? 0 : 1); // Round to next multiple of 2
|
||||||
|
var buffer = Buffer.alloc(paddedLength * sizeOfUint16);
|
||||||
|
for (var i = 0; i < length; ++i) {
|
||||||
|
buffer.writeUInt16LE(typedArray[i], i * sizeOfUint16);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrayStorage.prototype.toUint32Buffer = function() {
|
||||||
|
var length = this.length;
|
||||||
|
var typedArray = this.typedArray;
|
||||||
|
var buffer = Buffer.alloc(length * sizeOfUint32);
|
||||||
|
for (var i = 0; i < length; ++i) {
|
||||||
|
buffer.writeUInt32LE(typedArray[i], i * sizeOfUint32);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrayStorage.prototype.toFloatBuffer = function() {
|
||||||
|
var length = this.length;
|
||||||
|
var typedArray = this.typedArray;
|
||||||
|
var buffer = Buffer.alloc(length * sizeOfFloat);
|
||||||
|
for (var i = 0; i < length; ++i) {
|
||||||
|
buffer.writeFloatLE(typedArray[i], i * sizeOfFloat);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrayStorage.prototype.getMinMax = function(components) {
|
||||||
|
var length = this.length;
|
||||||
|
var typedArray = this.typedArray;
|
||||||
|
var count = length / components;
|
||||||
|
var min = new Array(components).fill(Number.POSITIVE_INFINITY);
|
||||||
|
var max = new Array(components).fill(Number.NEGATIVE_INFINITY);
|
||||||
|
for (var i = 0; i < count; ++i) {
|
||||||
|
for (var j = 0; j < components; ++j) {
|
||||||
|
var index = i * components + j;
|
||||||
|
var value = typedArray[index];
|
||||||
|
min[j] = Math.min(min[j], value);
|
||||||
|
max[j] = Math.max(max[j], value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
min : min,
|
||||||
|
max : max
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,19 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = Material;
|
||||||
|
|
||||||
|
function Material() {
|
||||||
|
this.ambientColor = [0.0, 0.0, 0.0, 1.0]; // Ka
|
||||||
|
this.emissionColor = [0.0, 0.0, 0.0, 1.0]; // Ke
|
||||||
|
this.diffuseColor = [0.5, 0.5, 0.5, 1.0]; // Kd
|
||||||
|
this.specularColor = [0.0, 0.0, 0.0, 1.0]; // Ks
|
||||||
|
this.specularShininess = 0.0; // Ns
|
||||||
|
this.alpha = 1.0; // d / Tr
|
||||||
|
this.ambientTexture = undefined; // map_Ka
|
||||||
|
this.emissionTexture = undefined; // map_Ke
|
||||||
|
this.diffuseTexture = undefined; // map_Kd
|
||||||
|
this.specularTexture = undefined; // map_Ks
|
||||||
|
this.specularShininessMap = undefined; // map_Ns
|
||||||
|
this.normalMap = undefined; // map_Bump
|
||||||
|
this.alphaMap = undefined; // map_d
|
||||||
|
}
|
245
lib/convert.js
|
@ -1,60 +1,221 @@
|
||||||
"use strict";
|
'use strict';
|
||||||
var path = require('path');
|
|
||||||
var GltfPipeline = require('gltf-pipeline').Pipeline;
|
|
||||||
var parseObj = require('./obj');
|
|
||||||
var createGltf = require('./gltf');
|
|
||||||
var Cesium = require('cesium');
|
var Cesium = require('cesium');
|
||||||
var defined = Cesium.defined;
|
var fsExtra = require('fs-extra');
|
||||||
|
var GltfPipeline = require('gltf-pipeline').Pipeline;
|
||||||
|
var path = require('path');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
var createGltf = require('./gltf');
|
||||||
|
var loadObj = require('./obj');
|
||||||
|
var writeUris = require('./writeUris');
|
||||||
|
|
||||||
|
var fsExtraOutputJson = Promise.promisify(fsExtra.outputJson);
|
||||||
|
|
||||||
var defaultValue = Cesium.defaultValue;
|
var defaultValue = Cesium.defaultValue;
|
||||||
|
var defined = Cesium.defined;
|
||||||
|
var DeveloperError = Cesium.DeveloperError;
|
||||||
|
|
||||||
module.exports = convert;
|
module.exports = convert;
|
||||||
|
|
||||||
function convert(objFile, outputPath, options) {
|
/**
|
||||||
|
* Converts an obj file to a glTF file.
|
||||||
|
*
|
||||||
|
* @param {String} objPath Path to the obj file.
|
||||||
|
* @param {String} gltfPath Path of the converted glTF file.
|
||||||
|
* @param {Object} [options] An object with the following properties:
|
||||||
|
* @param {Boolean} [options.binary=false] Save as binary glTF.
|
||||||
|
* @param {Boolean} [options.separate=false] Writes out separate geometry data files, shader files, and textures instead of embedding them in the glTF.
|
||||||
|
* @param {Boolean} [options.separateTextures=false] Write out separate textures only.
|
||||||
|
* @param {Boolean} [options.compress=false] Quantize positions, compress texture coordinates, and oct-encode normals.
|
||||||
|
* @param {Boolean} [options.optimize=false] Optimize the glTF for size and runtime performance.
|
||||||
|
* @param {Boolean} [options.optimizeForCesium=false] Optimize the glTF for Cesium by using the sun as a default light source.
|
||||||
|
* @param {Boolean} [options.generateNormals=false] Generate normals if they are missing.
|
||||||
|
* @param {Boolean} [options.ao=false] Apply ambient occlusion to the converted model.
|
||||||
|
* @param {Boolean} [options.kmc=false] Output glTF with the KHR_materials_common extension.
|
||||||
|
* @param {Boolean} [options.textureCompressionOptions] Options sent to the compressTextures stage of gltf-pipeline.
|
||||||
|
* @param {Boolean} [options.bypassPipeline=false] Bypass the gltf-pipeline for debugging purposes. This option overrides many of the options above and will save the glTF with the KHR_materials_common extension.
|
||||||
|
* @param {Boolean} [options.checkTransparency=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel.
|
||||||
|
* @param {Boolean} [options.secure=false] Prevent the converter from reading image or mtl files outside of the input obj directory.
|
||||||
|
* @param {Logger} [options.logger] A callback function for handling logged messages. Defaults to console.log.
|
||||||
|
*/
|
||||||
|
function convert(objPath, gltfPath, options) {
|
||||||
|
var defaults = convert.defaults;
|
||||||
|
|
||||||
options = defaultValue(options, {});
|
options = defaultValue(options, {});
|
||||||
var binary = defaultValue(options.binary, false);
|
var binary = defaultValue(options.binary, defaults.binary);
|
||||||
var embed = defaultValue(options.embed, true);
|
var separate = defaultValue(options.separate, defaults.separate);
|
||||||
var embedImage = defaultValue(options.embedImage, true);
|
var separateTextures = defaultValue(options.separateTextures, defaults.separateTextures) || separate;
|
||||||
var compress = defaultValue(options.compress, false);
|
var compress = defaultValue(options.compress, defaults.compress);
|
||||||
var ao = defaultValue(options.ao, false);
|
var optimize = defaultValue(options.optimize, defaults.optimize);
|
||||||
var optimizeForCesium = defaultValue(options.optimizeForCesium, false);
|
var optimizeForCesium = defaultValue(options.optimizeForCesium, defaults.optimizeForCesium);
|
||||||
|
var generateNormals = defaultValue(options.generateNormals, defaults.generateNormals);
|
||||||
|
var ao = defaultValue(options.ao, defaults.ao);
|
||||||
|
var kmc = defaultValue(options.kmc, defaults.kmc);
|
||||||
|
var textureCompressionOptions = options.textureCompressionOptions;
|
||||||
|
var bypassPipeline = defaultValue(options.bypassPipeline, defaults.bypassPipeline);
|
||||||
|
var checkTransparency = defaultValue(options.checkTransparency, defaults.checkTransparency);
|
||||||
|
var secure = defaultValue(options.secure, defaults.secure);
|
||||||
|
var logger = defaultValue(options.logger, defaults.logger);
|
||||||
|
|
||||||
if (!defined(objFile)) {
|
options.separate = separate;
|
||||||
throw new Error('objFile is required');
|
options.separateTextures = separateTextures;
|
||||||
|
options.checkTransparency = checkTransparency;
|
||||||
|
options.secure = secure;
|
||||||
|
options.logger = logger;
|
||||||
|
|
||||||
|
|
||||||
|
if (!defined(objPath)) {
|
||||||
|
throw new DeveloperError('objPath is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defined(outputPath)) {
|
if (!defined(gltfPath)) {
|
||||||
outputPath = path.dirname(objFile);
|
throw new DeveloperError('gltfPath is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
var inputPath = path.dirname(objFile);
|
var extension = path.extname(gltfPath).toLowerCase();
|
||||||
var modelName = path.basename(objFile, '.obj');
|
var basePath = path.dirname(gltfPath);
|
||||||
|
var modelName = path.basename(gltfPath, path.extname(gltfPath));
|
||||||
var extension = path.extname(outputPath);
|
if (extension === '.glb') {
|
||||||
if (extension !== '') {
|
binary = true;
|
||||||
modelName = path.basename(outputPath, extension);
|
|
||||||
outputPath = path.dirname(outputPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension = binary ? '.glb' : '.gltf';
|
if (binary && bypassPipeline) {
|
||||||
var gltfFile = path.join(outputPath, modelName + extension);
|
throw new DeveloperError('--bypassPipeline does not convert to binary glTF');
|
||||||
|
}
|
||||||
|
|
||||||
return parseObj(objFile, inputPath)
|
gltfPath = path.join(path.dirname(gltfPath), modelName + extension);
|
||||||
.then(function(data) {
|
|
||||||
return createGltf(data, inputPath, modelName);
|
var aoOptions = ao ? {} : undefined;
|
||||||
|
var kmcOptions = kmc ? {} : undefined;
|
||||||
|
|
||||||
|
var pipelineOptions = {
|
||||||
|
createDirectory : false,
|
||||||
|
basePath : basePath,
|
||||||
|
binary : binary,
|
||||||
|
embed : !separate,
|
||||||
|
embedImage : !separateTextures,
|
||||||
|
quantize : compress,
|
||||||
|
compressTextureCoordinates : compress,
|
||||||
|
encodeNormals : compress,
|
||||||
|
preserve : !optimize,
|
||||||
|
optimizeForCesium : optimizeForCesium,
|
||||||
|
smoothNormals : generateNormals,
|
||||||
|
aoOptions : aoOptions,
|
||||||
|
kmcOptions : kmcOptions,
|
||||||
|
textureCompressionOptions : textureCompressionOptions
|
||||||
|
};
|
||||||
|
|
||||||
|
return loadObj(objPath, options)
|
||||||
|
.then(function(objData) {
|
||||||
|
return createGltf(objData);
|
||||||
})
|
})
|
||||||
.then(function(gltf) {
|
.then(function(gltf) {
|
||||||
var aoOptions = ao ? {enable : true} : undefined;
|
return writeUris(gltf, gltfPath, options);
|
||||||
var options = {
|
})
|
||||||
binary: binary,
|
.then(function(gltf) {
|
||||||
embed: embed,
|
if (bypassPipeline) {
|
||||||
embedImage: embedImage,
|
return convert._outputJson(gltfPath, gltf);
|
||||||
encodeNormals: compress,
|
} else {
|
||||||
quantize: compress,
|
return GltfPipeline.processJSONToDisk(gltf, gltfPath, pipelineOptions);
|
||||||
aoOptions: aoOptions,
|
}
|
||||||
optimizeForCesium : optimizeForCesium,
|
|
||||||
createDirectory: false,
|
|
||||||
basePath: inputPath
|
|
||||||
};
|
|
||||||
return GltfPipeline.processJSONToDisk(gltf, gltfFile, options);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default values that will be used when calling convert(options) unless specified in the options object.
|
||||||
|
*/
|
||||||
|
convert.defaults = {
|
||||||
|
/**
|
||||||
|
* Gets or sets whether the model will be saved as binary glTF.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
binary: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether to write out separate geometry/animation data files,
|
||||||
|
* shader files, and textures instead of embedding them in the glTF.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
separate: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether to write out separate textures only.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
separateTextures: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether to compress attribute data. This includes quantizing positions, compressing texture coordinates, and oct-encoding normals.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
compress: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether the model is optimized for size and runtime performance.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
optimize: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether the model is optimized for Cesium by using the sun as a default light source.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
optimizeForCesium: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether normals will be generated for the model if they are missing.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
generateNormals: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether the model will have ambient occlusion applied.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
ao: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether the model will be saved with the KHR_materials_common extension.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
kmc: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether the converter will bypass the gltf-pipeline for debugging purposes.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
bypassPipeline: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether the converter will do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
checkTransparency: false,
|
||||||
|
/**
|
||||||
|
* Gets or sets whether the source model can reference paths outside of its directory.
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
secure: false,
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
logger: function(message) {
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposed for testing
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
convert._outputJson = fsExtraOutputJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback function that logs messages.
|
||||||
|
* @callback Logger
|
||||||
|
*
|
||||||
|
* @param {String} message The message to log.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
558
lib/gltf.js
|
@ -1,148 +1,38 @@
|
||||||
"use strict";
|
'use strict';
|
||||||
var Cesium = require('cesium');
|
var Cesium = require('cesium');
|
||||||
var Promise = require('bluebird');
|
|
||||||
var fs = require('fs-extra');
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var Material = require('./Material');
|
||||||
|
|
||||||
var defined = Cesium.defined;
|
var defined = Cesium.defined;
|
||||||
var defaultValue = Cesium.defaultValue;
|
var defaultValue = Cesium.defaultValue;
|
||||||
var WebGLConstants = Cesium.WebGLConstants;
|
var WebGLConstants = Cesium.WebGLConstants;
|
||||||
|
|
||||||
var fsWriteFile = Promise.promisify(fs.writeFile);
|
|
||||||
|
|
||||||
module.exports = createGltf;
|
module.exports = createGltf;
|
||||||
|
|
||||||
function createGltf(data, inputPath, modelName) {
|
/**
|
||||||
var vertexCount = data.vertexCount;
|
* Create a glTF from obj data.
|
||||||
var vertexArray = data.vertexArray;
|
*
|
||||||
var positionMin = data.positionMin;
|
* @param {Object} objData Output of obj.js, containing an array of nodes containing geometry information, materials, and images.
|
||||||
var positionMax = data.positionMax;
|
* @returns {Object} A glTF asset with the KHR_materials_common extension.
|
||||||
var hasUVs = data.hasUVs;
|
*
|
||||||
var hasNormals = data.hasNormals;
|
* @private
|
||||||
var materialGroups = data.materialGroups;
|
*/
|
||||||
var materials = data.materials;
|
function createGltf(objData) {
|
||||||
var images = data.images;
|
var nodes = objData.nodes;
|
||||||
|
var materials = objData.materials;
|
||||||
var i, j, name;
|
var images = objData.images;
|
||||||
|
var sceneId = 'scene';
|
||||||
var sizeOfFloat32 = 4;
|
var samplerId = 'sampler';
|
||||||
var sizeOfUint32 = 4;
|
var bufferId = 'buffer';
|
||||||
var sizeOfUint16 = 2;
|
var vertexBufferViewId = 'bufferView_vertex';
|
||||||
|
var indexBufferViewId = 'bufferView_index';
|
||||||
var indexComponentType;
|
|
||||||
var indexComponentSize;
|
|
||||||
|
|
||||||
// Reserve the 65535 index for primitive restart
|
|
||||||
if (vertexCount < 65535) {
|
|
||||||
indexComponentType = WebGLConstants.UNSIGNED_SHORT;
|
|
||||||
indexComponentSize = sizeOfUint16;
|
|
||||||
} else {
|
|
||||||
indexComponentType = WebGLConstants.UNSIGNED_INT;
|
|
||||||
indexComponentSize = sizeOfUint32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create primitives
|
|
||||||
var primitives = [];
|
|
||||||
var indexArrayLength = 0;
|
|
||||||
var indexArray;
|
|
||||||
var indexCount;
|
|
||||||
for (name in materialGroups) {
|
|
||||||
if (materialGroups.hasOwnProperty(name)) {
|
|
||||||
indexArray = materialGroups[name];
|
|
||||||
indexCount = indexArray.length;
|
|
||||||
primitives.push({
|
|
||||||
indexArray : indexArray,
|
|
||||||
indexOffset : indexArrayLength,
|
|
||||||
indexCount : indexCount,
|
|
||||||
material : name
|
|
||||||
});
|
|
||||||
indexArrayLength += indexCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create buffer to store vertex and index data
|
|
||||||
var indexArrayByteLength = indexArrayLength * indexComponentSize;
|
|
||||||
var vertexArrayLength = vertexArray.length; // In floats
|
|
||||||
var vertexArrayByteLength = vertexArrayLength * sizeOfFloat32;
|
|
||||||
var bufferByteLength = vertexArrayByteLength + indexArrayByteLength;
|
|
||||||
var buffer = new Buffer(bufferByteLength);
|
|
||||||
|
|
||||||
// Write vertex data
|
|
||||||
var byteOffset = 0;
|
|
||||||
for (i = 0; i < vertexArrayLength; ++i) {
|
|
||||||
buffer.writeFloatLE(vertexArray[i], byteOffset);
|
|
||||||
byteOffset += sizeOfFloat32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write index data
|
|
||||||
var primitivesLength = primitives.length;
|
|
||||||
for (i = 0; i < primitivesLength; ++i) {
|
|
||||||
indexArray = primitives[i].indexArray;
|
|
||||||
indexCount = indexArray.length;
|
|
||||||
for (j = 0; j < indexCount; ++j) {
|
|
||||||
if (indexComponentSize === sizeOfUint16) {
|
|
||||||
buffer.writeUInt16LE(indexArray[j], byteOffset);
|
|
||||||
} else {
|
|
||||||
buffer.writeUInt32LE(indexArray[j], byteOffset);
|
|
||||||
}
|
|
||||||
byteOffset += indexComponentSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var positionByteOffset = 0;
|
|
||||||
var normalByteOffset = 0;
|
|
||||||
var uvByteOffset = 0;
|
|
||||||
var vertexByteStride = 0;
|
|
||||||
|
|
||||||
if (hasNormals && hasUVs) {
|
|
||||||
normalByteOffset = sizeOfFloat32 * 3;
|
|
||||||
uvByteOffset = sizeOfFloat32 * 6;
|
|
||||||
vertexByteStride = sizeOfFloat32 * 8;
|
|
||||||
} else if (hasNormals && !hasUVs) {
|
|
||||||
normalByteOffset = sizeOfFloat32 * 3;
|
|
||||||
vertexByteStride = sizeOfFloat32 * 6;
|
|
||||||
} else if (!hasNormals && hasUVs) {
|
|
||||||
uvByteOffset = sizeOfFloat32 * 3;
|
|
||||||
vertexByteStride = sizeOfFloat32 * 5;
|
|
||||||
} else if (!hasNormals && !hasUVs) {
|
|
||||||
vertexByteStride = sizeOfFloat32 * 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
var bufferId = modelName + '_buffer';
|
|
||||||
var bufferViewVertexId = 'bufferView_vertex';
|
|
||||||
var bufferViewIndexId = 'bufferView_index';
|
|
||||||
var accessorPositionId = 'accessor_position';
|
|
||||||
var accessorUVId = 'accessor_uv';
|
|
||||||
var accessorNormalId = 'accessor_normal';
|
|
||||||
var meshId = 'mesh_' + modelName;
|
|
||||||
var sceneId = 'scene_' + modelName;
|
|
||||||
var nodeId = 'node_' + modelName;
|
|
||||||
var samplerId = 'sampler_0';
|
|
||||||
|
|
||||||
function getAccessorIndexId(i) {
|
|
||||||
return 'accessor_index_' + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMaterialId(material) {
|
|
||||||
return 'material_' + material;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTextureId(image) {
|
|
||||||
if (!defined(image)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return 'texture_' + path.basename(image).substr(0, image.lastIndexOf('.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getImageId(image) {
|
|
||||||
return path.basename(image, path.extname(image));
|
|
||||||
}
|
|
||||||
|
|
||||||
var gltf = {
|
var gltf = {
|
||||||
accessors : {},
|
accessors : {},
|
||||||
asset : {},
|
asset : {},
|
||||||
buffers : {},
|
buffers : {},
|
||||||
bufferViews : {},
|
bufferViews : {},
|
||||||
|
extensionsUsed : ['KHR_materials_common'],
|
||||||
images : {},
|
images : {},
|
||||||
materials : {},
|
materials : {},
|
||||||
meshes : {},
|
meshes : {},
|
||||||
|
@ -154,174 +44,105 @@ function createGltf(data, inputPath, modelName) {
|
||||||
};
|
};
|
||||||
|
|
||||||
gltf.asset = {
|
gltf.asset = {
|
||||||
"generator": "OBJ2GLTF",
|
generator : 'obj2gltf',
|
||||||
"premultipliedAlpha": true,
|
profile : {
|
||||||
"profile": {
|
api : 'WebGL',
|
||||||
"api": "WebGL",
|
version : '1.0'
|
||||||
"version": "1.0"
|
|
||||||
},
|
},
|
||||||
"version": 1
|
version: '1.0'
|
||||||
};
|
};
|
||||||
|
|
||||||
gltf.scenes[sceneId] = {
|
gltf.scenes[sceneId] = {
|
||||||
nodes : [nodeId]
|
nodes : []
|
||||||
};
|
};
|
||||||
|
|
||||||
gltf.nodes[nodeId] = {
|
function getImageId(imagePath) {
|
||||||
children : [],
|
return path.basename(imagePath, path.extname(imagePath));
|
||||||
matrix : [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
}
|
||||||
meshes : [meshId],
|
|
||||||
name : modelName
|
|
||||||
};
|
|
||||||
|
|
||||||
gltf.samplers[samplerId] = {}; // Use default values
|
function getTextureId(imagePath) {
|
||||||
|
if (!defined(imagePath) || !defined(images[imagePath])) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return 'texture_' + getImageId(imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
var bufferSeparate = false;
|
function createMaterial(material, hasNormals) {
|
||||||
var bufferUri;
|
var ambient = defaultValue(defaultValue(getTextureId(material.ambientTexture), material.ambientColor));
|
||||||
if (buffer.length > 201326580) {
|
var diffuse = defaultValue(defaultValue(getTextureId(material.diffuseTexture), material.diffuseColor));
|
||||||
// toString fails for buffers larger than ~192MB. Instead save the buffer to a .bin file.
|
var emission = defaultValue(defaultValue(getTextureId(material.emissionTexture), material.emissionColor));
|
||||||
// Source: https://github.com/nodejs/node/issues/4266
|
var specular = defaultValue(defaultValue(getTextureId(material.specularTexture), material.specularColor));
|
||||||
bufferSeparate = true;
|
var alpha = defaultValue(defaultValue(material.alpha), 1.0);
|
||||||
bufferUri = modelName + '.bin';
|
var shininess = defaultValue(material.specularShininess, 0.0);
|
||||||
|
var hasSpecular = (shininess > 0.0) && (specular[0] > 0.0 || specular[1] > 0.0 || specular[2] > 0.0);
|
||||||
|
|
||||||
|
var transparent;
|
||||||
|
var transparency = 1.0;
|
||||||
|
if (typeof diffuse === 'string') {
|
||||||
|
transparency = alpha;
|
||||||
|
transparent = images[material.diffuseTexture].transparent || (transparency < 1.0);
|
||||||
} else {
|
} else {
|
||||||
bufferUri = 'data:application/octet-stream;base64,' + buffer.toString('base64');
|
diffuse[3] = alpha;
|
||||||
|
transparent = diffuse[3] < 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gltf.buffers[bufferId] = {
|
var doubleSided = transparent;
|
||||||
byteLength : bufferByteLength,
|
|
||||||
type : 'arraybuffer',
|
|
||||||
uri : bufferUri
|
|
||||||
};
|
|
||||||
|
|
||||||
gltf.bufferViews[bufferViewVertexId] = {
|
if (!hasNormals) {
|
||||||
buffer : bufferId,
|
// Constant technique only factors in ambient and emission sources - set emission to diffuse
|
||||||
byteLength : vertexArrayByteLength,
|
emission = diffuse;
|
||||||
byteOffset : 0,
|
diffuse = [0, 0, 0, 1];
|
||||||
target : WebGLConstants.ARRAY_BUFFER
|
}
|
||||||
};
|
|
||||||
gltf.bufferViews[bufferViewIndexId] = {
|
|
||||||
buffer : bufferId,
|
|
||||||
byteLength : indexArrayByteLength,
|
|
||||||
byteOffset : vertexArrayByteLength,
|
|
||||||
target : WebGLConstants.ELEMENT_ARRAY_BUFFER
|
|
||||||
};
|
|
||||||
|
|
||||||
for (i = 0; i < primitivesLength; ++i) {
|
var technique = hasNormals ? (hasSpecular ? 'PHONG' : 'LAMBERT') : 'CONSTANT';
|
||||||
var primitive = primitives[i];
|
return {
|
||||||
gltf.accessors[getAccessorIndexId(i)] = {
|
extensions : {
|
||||||
bufferView : bufferViewIndexId,
|
KHR_materials_common : {
|
||||||
byteOffset : primitive.indexOffset * indexComponentSize,
|
technique : technique,
|
||||||
byteStride : 0,
|
transparent : transparent,
|
||||||
componentType : indexComponentType,
|
doubleSided : doubleSided,
|
||||||
count : primitive.indexCount,
|
values : {
|
||||||
type : 'SCALAR'
|
ambient : ambient,
|
||||||
|
diffuse : diffuse,
|
||||||
|
emission : emission,
|
||||||
|
specular : specular,
|
||||||
|
shininess : shininess,
|
||||||
|
transparency : transparency,
|
||||||
|
transparent : transparent,
|
||||||
|
doubleSided : doubleSided
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
gltf.accessors[accessorPositionId] = {
|
if (Object.keys(images).length > 0) {
|
||||||
bufferView : bufferViewVertexId,
|
gltf.samplers[samplerId] = {
|
||||||
byteOffset : positionByteOffset,
|
magFilter : WebGLConstants.LINEAR,
|
||||||
byteStride : vertexByteStride,
|
minFilter : WebGLConstants.LINEAR,
|
||||||
componentType : WebGLConstants.FLOAT,
|
wrapS : WebGLConstants.REPEAT,
|
||||||
count : vertexCount,
|
wrapT : WebGLConstants.REPEAT
|
||||||
min : positionMin,
|
|
||||||
max : positionMax,
|
|
||||||
type : 'VEC3'
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hasNormals) {
|
|
||||||
gltf.accessors[accessorNormalId] = {
|
|
||||||
bufferView : bufferViewVertexId,
|
|
||||||
byteOffset : normalByteOffset,
|
|
||||||
byteStride : vertexByteStride,
|
|
||||||
componentType : WebGLConstants.FLOAT,
|
|
||||||
count : vertexCount,
|
|
||||||
type : 'VEC3'
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasUVs) {
|
for (var imagePath in images) {
|
||||||
gltf.accessors[accessorUVId] = {
|
if (images.hasOwnProperty(imagePath)) {
|
||||||
bufferView : bufferViewVertexId,
|
var image = images[imagePath];
|
||||||
byteOffset : uvByteOffset,
|
var imageId = getImageId(imagePath);
|
||||||
byteStride : vertexByteStride,
|
var textureId = getTextureId(imagePath);
|
||||||
componentType : WebGLConstants.FLOAT,
|
|
||||||
count : vertexCount,
|
|
||||||
type : 'VEC2'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var gltfPrimitives = [];
|
|
||||||
gltf.meshes[meshId] = {
|
|
||||||
name : modelName,
|
|
||||||
primitives : gltfPrimitives
|
|
||||||
};
|
|
||||||
|
|
||||||
var gltfAttributes = {};
|
|
||||||
gltfAttributes.POSITION = accessorPositionId;
|
|
||||||
if (hasNormals) {
|
|
||||||
gltfAttributes.NORMAL = accessorNormalId;
|
|
||||||
}
|
|
||||||
if (hasUVs) {
|
|
||||||
gltfAttributes.TEXCOORD_0 = accessorUVId;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < primitivesLength; ++i) {
|
|
||||||
gltfPrimitives.push({
|
|
||||||
attributes : gltfAttributes,
|
|
||||||
indices : getAccessorIndexId(i),
|
|
||||||
material : getMaterialId(primitives[i].material),
|
|
||||||
mode : WebGLConstants.TRIANGLES
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (name in materials) {
|
|
||||||
if (materials.hasOwnProperty(name)) {
|
|
||||||
var material = materials[name];
|
|
||||||
var materialId = getMaterialId(name);
|
|
||||||
var values = {
|
|
||||||
ambient : defaultValue(defaultValue(getTextureId(material.ambientColorMap), material.ambientColor), [0, 0, 0, 1]),
|
|
||||||
diffuse : defaultValue(defaultValue(getTextureId(material.diffuseColorMap), material.diffuseColor), [0, 0, 0, 1]),
|
|
||||||
emission : defaultValue(defaultValue(getTextureId(material.emissionColorMap), material.emissionColor), [0, 0, 0, 1]),
|
|
||||||
specular : defaultValue(defaultValue(getTextureId(material.specularColorMap), material.specularColor), [0, 0, 0, 1]),
|
|
||||||
shininess : defaultValue(material.specularShininess, 0.0)
|
|
||||||
};
|
|
||||||
|
|
||||||
gltf.materials[materialId] = {
|
|
||||||
name: name,
|
|
||||||
values: values
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (name in images) {
|
|
||||||
if (images.hasOwnProperty(name)) {
|
|
||||||
var image = images[name];
|
|
||||||
var imageId = getImageId(name);
|
|
||||||
var textureId = getTextureId(name);
|
|
||||||
var format;
|
|
||||||
var channels = image.channels;
|
|
||||||
switch (channels) {
|
|
||||||
case 1:
|
|
||||||
format = WebGLConstants.ALPHA;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
format = WebGLConstants.LUMINANCE_ALPHA;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
format = WebGLConstants.RGB;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
format = WebGLConstants.RGBA;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
gltf.images[imageId] = {
|
gltf.images[imageId] = {
|
||||||
uri : image.uri
|
name : imageId,
|
||||||
|
extras : {
|
||||||
|
_obj2gltf : {
|
||||||
|
source : image.source,
|
||||||
|
extension : image.extension
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
gltf.textures[textureId] = {
|
gltf.textures[textureId] = {
|
||||||
format : format,
|
format : image.format,
|
||||||
internalFormat : format,
|
internalFormat : image.format,
|
||||||
sampler : samplerId,
|
sampler : samplerId,
|
||||||
source : imageId,
|
source : imageId,
|
||||||
target : WebGLConstants.TEXTURE_2D,
|
target : WebGLConstants.TEXTURE_2D,
|
||||||
|
@ -330,9 +151,190 @@ function createGltf(data, inputPath, modelName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferSeparate) {
|
var vertexBuffers = [];
|
||||||
var bufferPath = path.join(inputPath, modelName + '.bin');
|
var vertexBufferByteOffset = 0;
|
||||||
return fsWriteFile(bufferPath, buffer);
|
var indexBuffers = [];
|
||||||
|
var indexBufferByteOffset = 0;
|
||||||
|
var accessorCount = 0;
|
||||||
|
|
||||||
|
function addVertexAttribute(array, components) {
|
||||||
|
var count = array.length / components;
|
||||||
|
var buffer = array.toFloatBuffer();
|
||||||
|
var minMax = array.getMinMax(components);
|
||||||
|
|
||||||
|
var type = (components === 3 ? 'VEC3' : 'VEC2');
|
||||||
|
var accessor = {
|
||||||
|
bufferView : vertexBufferViewId,
|
||||||
|
byteOffset : vertexBufferByteOffset,
|
||||||
|
byteStride : 0,
|
||||||
|
componentType : WebGLConstants.FLOAT,
|
||||||
|
count : count,
|
||||||
|
min : minMax.min,
|
||||||
|
max : minMax.max,
|
||||||
|
type : type
|
||||||
|
};
|
||||||
|
|
||||||
|
vertexBufferByteOffset += buffer.length;
|
||||||
|
vertexBuffers.push(buffer);
|
||||||
|
var accessorId = 'accessor_' + accessorCount++;
|
||||||
|
gltf.accessors[accessorId] = accessor;
|
||||||
|
return accessorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addIndexArray(array, uint32Indices) {
|
||||||
|
var buffer = uint32Indices ? array.toUint32Buffer() : array.toUint16Buffer();
|
||||||
|
var componentType = uint32Indices ? WebGLConstants.UNSIGNED_INT : WebGLConstants.UNSIGNED_SHORT;
|
||||||
|
var length = array.length;
|
||||||
|
var minMax = array.getMinMax(1);
|
||||||
|
var accessor = {
|
||||||
|
bufferView : indexBufferViewId,
|
||||||
|
byteOffset : indexBufferByteOffset,
|
||||||
|
byteStride : 0,
|
||||||
|
componentType : componentType,
|
||||||
|
count : length,
|
||||||
|
min : minMax.min,
|
||||||
|
max : minMax.max,
|
||||||
|
type : 'SCALAR'
|
||||||
|
};
|
||||||
|
|
||||||
|
indexBufferByteOffset += buffer.length;
|
||||||
|
indexBuffers.push(buffer);
|
||||||
|
|
||||||
|
var accessorId = 'accessor_' + accessorCount++;
|
||||||
|
gltf.accessors[accessorId] = accessor;
|
||||||
|
return accessorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function requiresUint32Indices(nodes) {
|
||||||
|
var nodesLength = nodes.length;
|
||||||
|
for (var i = 0; i < nodesLength; ++i) {
|
||||||
|
var meshes = nodes[i].meshes;
|
||||||
|
var meshesLength = meshes.length;
|
||||||
|
for (var j = 0; j < meshesLength; ++j) {
|
||||||
|
// Reserve the 65535 index for primitive restart
|
||||||
|
var vertexCount = meshes[j].positions.length / 3;
|
||||||
|
if (vertexCount > 65534) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var uint32Indices = requiresUint32Indices(nodes);
|
||||||
|
var gltfSceneNodes = gltf.scenes[sceneId].nodes;
|
||||||
|
var nodesLength = nodes.length;
|
||||||
|
for (var i = 0; i < nodesLength; ++i) {
|
||||||
|
// Add node
|
||||||
|
var node = nodes[i];
|
||||||
|
var nodeId = node.name;
|
||||||
|
gltfSceneNodes.push(nodeId);
|
||||||
|
var gltfNodeMeshes = [];
|
||||||
|
gltf.nodes[nodeId] = {
|
||||||
|
name : nodeId,
|
||||||
|
meshes : gltfNodeMeshes
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add meshes to node
|
||||||
|
var meshes = node.meshes;
|
||||||
|
var meshesLength = meshes.length;
|
||||||
|
for (var j = 0; j < meshesLength; ++j) {
|
||||||
|
var mesh = meshes[j];
|
||||||
|
var meshId = mesh.name;
|
||||||
|
gltfNodeMeshes.push(meshId);
|
||||||
|
|
||||||
|
var hasPositions = mesh.positions.length > 0;
|
||||||
|
var hasNormals = mesh.normals.length > 0;
|
||||||
|
var hasUVs = mesh.uvs.length > 0;
|
||||||
|
|
||||||
|
var attributes = {};
|
||||||
|
if (hasPositions) {
|
||||||
|
attributes.POSITION = addVertexAttribute(mesh.positions, 3);
|
||||||
|
}
|
||||||
|
if (hasNormals) {
|
||||||
|
attributes.NORMAL = addVertexAttribute(mesh.normals, 3);
|
||||||
|
}
|
||||||
|
if (hasUVs) {
|
||||||
|
attributes.TEXCOORD_0 = addVertexAttribute(mesh.uvs, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unload resources
|
||||||
|
mesh.positions = undefined;
|
||||||
|
mesh.normals = undefined;
|
||||||
|
mesh.uvs = undefined;
|
||||||
|
|
||||||
|
var gltfMeshPrimitives = [];
|
||||||
|
gltf.meshes[meshId] = {
|
||||||
|
name : meshId,
|
||||||
|
primitives : gltfMeshPrimitives
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add primitives to mesh
|
||||||
|
var primitives = mesh.primitives;
|
||||||
|
var primitivesLength = primitives.length;
|
||||||
|
for (var k = 0; k < primitivesLength; ++k) {
|
||||||
|
var primitive = primitives[k];
|
||||||
|
var indexAccessorId = addIndexArray(primitive.indices, uint32Indices);
|
||||||
|
primitive.indices = undefined; // Unload resources
|
||||||
|
var materialId = primitive.material;
|
||||||
|
|
||||||
|
if (!defined(materialId)) {
|
||||||
|
// Create a default material if the primitive does not specify one
|
||||||
|
materialId = 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
var material = materials[materialId];
|
||||||
|
material = defined(material) ? material : new Material();
|
||||||
|
var gltfMaterial = gltf.materials[materialId];
|
||||||
|
if (defined(gltfMaterial)) {
|
||||||
|
// Check if this material has already been added but with incompatible shading
|
||||||
|
var normalShading = (gltfMaterial.extensions.KHR_materials_common.technique !== 'CONSTANT');
|
||||||
|
if (hasNormals !== normalShading) {
|
||||||
|
materialId += (hasNormals ? '_shaded' : '_constant');
|
||||||
|
gltfMaterial = gltf.materials[materialId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined(gltfMaterial)) {
|
||||||
|
gltf.materials[materialId] = createMaterial(material, hasNormals);
|
||||||
|
}
|
||||||
|
|
||||||
|
gltfMeshPrimitives.push({
|
||||||
|
attributes : attributes,
|
||||||
|
indices : indexAccessorId,
|
||||||
|
material : materialId,
|
||||||
|
mode : WebGLConstants.TRIANGLES
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffers = [];
|
||||||
|
buffers = buffers.concat(vertexBuffers, indexBuffers);
|
||||||
|
var buffer = Buffer.concat(buffers);
|
||||||
|
|
||||||
|
gltf.buffers[bufferId] = {
|
||||||
|
byteLength : buffer.byteLength,
|
||||||
|
extras : {
|
||||||
|
_obj2gltf : {
|
||||||
|
source : buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
gltf.bufferViews[vertexBufferViewId] = {
|
||||||
|
buffer : bufferId,
|
||||||
|
byteLength : vertexBufferByteOffset,
|
||||||
|
byteOffset : 0,
|
||||||
|
target : WebGLConstants.ARRAY_BUFFER
|
||||||
|
};
|
||||||
|
|
||||||
|
gltf.bufferViews[indexBufferViewId] = {
|
||||||
|
buffer : bufferId,
|
||||||
|
byteLength : indexBufferByteOffset,
|
||||||
|
byteOffset : vertexBufferByteOffset,
|
||||||
|
target : WebGLConstants.ELEMENT_ARRAY_BUFFER
|
||||||
|
};
|
||||||
|
|
||||||
return gltf;
|
return gltf;
|
||||||
}
|
}
|
||||||
|
|
128
lib/image.js
|
@ -1,12 +1,85 @@
|
||||||
"use strict";
|
'use strict';
|
||||||
var Promise = require('bluebird');
|
var Cesium = require('cesium');
|
||||||
var fs = require('fs-extra');
|
var fsExtra = require('fs-extra');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var PNG = require('pngjs').PNG;
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
var fsReadFile = Promise.promisify(fs.readFile);
|
var fsExtraReadFile = Promise.promisify(fsExtra.readFile);
|
||||||
|
|
||||||
|
var defined = Cesium.defined;
|
||||||
|
var WebGLConstants = Cesium.WebGLConstants;
|
||||||
|
|
||||||
module.exports = loadImage;
|
module.exports = loadImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an image file and get information about it.
|
||||||
|
*
|
||||||
|
* @param {String} imagePath Path to the image file.
|
||||||
|
* @param {Object} options An object with the following properties:
|
||||||
|
* @param {Boolean} options.checkTransparency Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel.
|
||||||
|
* @returns {Promise} A promise resolving to the image information, or undefined if the file doesn't exist.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function loadImage(imagePath, options) {
|
||||||
|
return fsExtraReadFile(imagePath)
|
||||||
|
.then(function(data) {
|
||||||
|
var extension = path.extname(imagePath).toLowerCase();
|
||||||
|
|
||||||
|
var info = {
|
||||||
|
transparent : false,
|
||||||
|
format : getFormat(3),
|
||||||
|
source : data,
|
||||||
|
extension : extension
|
||||||
|
};
|
||||||
|
|
||||||
|
if (extension === '.png') {
|
||||||
|
return getPngInfo(data, info, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPngInfo(data, info, options) {
|
||||||
|
// Color type is encoded in the 25th bit of the png
|
||||||
|
var colorType = data[25];
|
||||||
|
var channels = getChannels(colorType);
|
||||||
|
info.format = getFormat(channels);
|
||||||
|
|
||||||
|
if (channels === 4) {
|
||||||
|
if (options.checkTransparency) {
|
||||||
|
return isTransparent(data)
|
||||||
|
.then(function(transparent) {
|
||||||
|
info.transparent = transparent;
|
||||||
|
return info;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTransparent(data) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
new PNG().parse(data, function(error, data) {
|
||||||
|
if (defined(error)) {
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var pixels = data.data;
|
||||||
|
var pixelsLength = data.width * data.height;
|
||||||
|
for (var i = 0; i < pixelsLength; ++i) {
|
||||||
|
if (pixels[i * 4 + 3] < 255) {
|
||||||
|
resolve(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getChannels(colorType) {
|
function getChannels(colorType) {
|
||||||
switch (colorType) {
|
switch (colorType) {
|
||||||
case 0: // greyscale
|
case 0: // greyscale
|
||||||
|
@ -22,42 +95,15 @@ function getChannels(colorType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUriType(extension) {
|
function getFormat(channels) {
|
||||||
switch (extension) {
|
switch (channels) {
|
||||||
case 'png':
|
case 1:
|
||||||
return 'data:image/png';
|
return WebGLConstants.ALPHA;
|
||||||
case 'jpg':
|
case 2:
|
||||||
return 'data:image/jpeg';
|
return WebGLConstants.LUMINANCE_ALPHA;
|
||||||
case 'jpeg':
|
case 3:
|
||||||
return 'data:image/jpeg';
|
return WebGLConstants.RGB;
|
||||||
case 'gif':
|
case 4:
|
||||||
return 'data:image/gif';
|
return WebGLConstants.RGBA;
|
||||||
default:
|
|
||||||
return 'data:image/' + extension;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadImage(imagePath) {
|
|
||||||
return fsReadFile(imagePath)
|
|
||||||
.then(function(data) {
|
|
||||||
var extension = path.extname(imagePath).slice(1);
|
|
||||||
var uriType = getUriType(extension);
|
|
||||||
var uri = uriType + ';base64,' + data.toString('base64');
|
|
||||||
|
|
||||||
var info = {
|
|
||||||
transparent: false,
|
|
||||||
channels: 3,
|
|
||||||
data: data,
|
|
||||||
uri: uri
|
|
||||||
};
|
|
||||||
|
|
||||||
if (path.extname(imagePath) === 'png') {
|
|
||||||
// Color type is encoded in the 25th bit of the png
|
|
||||||
var colorType = data[25];
|
|
||||||
var channels = getChannels(colorType);
|
|
||||||
info.channels = channels;
|
|
||||||
info.transparent = (channels === 4);
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
87
lib/mtl.js
|
@ -1,53 +1,30 @@
|
||||||
"use strict";
|
'use strict';
|
||||||
var Promise = require('bluebird');
|
var path = require('path');
|
||||||
var fs = require('fs-extra');
|
var Material = require('./Material');
|
||||||
var defined = require('cesium').defined;
|
var readLines = require('./readLines');
|
||||||
|
|
||||||
var fsReadFile = Promise.promisify(fs.readFile);
|
module.exports = loadMtl;
|
||||||
|
|
||||||
module.exports = {
|
/**
|
||||||
getDefault : getDefault,
|
* Parse an mtl file.
|
||||||
parse : parse
|
*
|
||||||
};
|
* @param {String} mtlPath Path to the mtl file.
|
||||||
|
* @returns {Promise} A promise resolving to the materials.
|
||||||
function createMaterial() {
|
*
|
||||||
return {
|
* @private
|
||||||
ambientColor : undefined, // Ka
|
*/
|
||||||
emissionColor : undefined, // Ke
|
function loadMtl(mtlPath) {
|
||||||
diffuseColor : undefined, // Kd
|
|
||||||
specularColor : undefined, // Ks
|
|
||||||
specularShininess : undefined, // Ns
|
|
||||||
alpha : undefined, // d / Tr
|
|
||||||
ambientColorMap : undefined, // map_Ka
|
|
||||||
emissionColorMap : undefined, // map_Ke
|
|
||||||
diffuseColorMap : undefined, // map_Kd
|
|
||||||
specularColorMap : undefined, // map_Ks
|
|
||||||
specularShininessMap : undefined, // map_Ns
|
|
||||||
normalMap : undefined, // map_Bump
|
|
||||||
alphaMap : undefined // map_d
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDefault() {
|
|
||||||
var material = createMaterial();
|
|
||||||
material.diffuseColor = [0.5, 0.5, 0.5, 1.0];
|
|
||||||
return material;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parse(mtlPath) {
|
|
||||||
return fsReadFile(mtlPath, 'utf8')
|
|
||||||
.then(function (contents) {
|
|
||||||
var materials = {};
|
|
||||||
var material;
|
var material;
|
||||||
var values;
|
var values;
|
||||||
var value;
|
var value;
|
||||||
var lines = contents.split('\n');
|
var mtlDirectory = path.dirname(mtlPath);
|
||||||
var length = lines.length;
|
var materials = {};
|
||||||
for (var i = 0; i < length; ++i) {
|
|
||||||
var line = lines[i].trim();
|
function parseLine(line) {
|
||||||
|
line = line.trim();
|
||||||
if (/^newmtl /i.test(line)) {
|
if (/^newmtl /i.test(line)) {
|
||||||
var name = line.substring(7).trim();
|
var name = line.substring(7).trim();
|
||||||
material = createMaterial();
|
material = new Material();
|
||||||
materials[name] = material;
|
materials[name] = material;
|
||||||
} else if (/^Ka /i.test(line)) {
|
} else if (/^Ka /i.test(line)) {
|
||||||
values = line.substring(3).trim().split(' ');
|
values = line.substring(3).trim().split(' ');
|
||||||
|
@ -91,28 +68,24 @@ function parse(mtlPath) {
|
||||||
value = line.substring(3).trim();
|
value = line.substring(3).trim();
|
||||||
material.alpha = parseFloat(value);
|
material.alpha = parseFloat(value);
|
||||||
} else if (/^map_Ka /i.test(line)) {
|
} else if (/^map_Ka /i.test(line)) {
|
||||||
material.ambientColorMap = line.substring(7).trim();
|
material.ambientTexture = path.resolve(mtlDirectory, line.substring(7).trim());
|
||||||
} else if (/^map_Ke /i.test(line)) {
|
} else if (/^map_Ke /i.test(line)) {
|
||||||
material.emissionColorMap = line.substring(7).trim();
|
material.emissionTexture = path.resolve(mtlDirectory, line.substring(7).trim());
|
||||||
} else if (/^map_Kd /i.test(line)) {
|
} else if (/^map_Kd /i.test(line)) {
|
||||||
material.diffuseColorMap = line.substring(7).trim();
|
material.diffuseTexture = path.resolve(mtlDirectory, line.substring(7).trim());
|
||||||
} else if (/^map_Ks /i.test(line)) {
|
} else if (/^map_Ks /i.test(line)) {
|
||||||
material.specularColorMap = line.substring(7).trim();
|
material.specularTexture = path.resolve(mtlDirectory, line.substring(7).trim());
|
||||||
} else if (/^map_Ns /i.test(line)) {
|
} else if (/^map_Ns /i.test(line)) {
|
||||||
material.specularShininessMap = line.substring(7).trim();
|
material.specularShininessMap = path.resolve(mtlDirectory, line.substring(7).trim());
|
||||||
} else if (/^map_Bump /i.test(line)) {
|
} else if (/^map_Bump /i.test(line)) {
|
||||||
material.normalMap = line.substring(9).trim();
|
material.normalMap = path.resolve(mtlDirectory, line.substring(9).trim());
|
||||||
} else if (/^map_d /i.test(line)) {
|
} else if (/^map_d /i.test(line)) {
|
||||||
material.alphaMap = line.substring(6).trim();
|
material.alphaMap = path.resolve(mtlDirectory, line.substring(6).trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (defined(material.alpha)) {
|
|
||||||
material.diffuseColor[3] = material.alpha;
|
return readLines(mtlPath, parseLine)
|
||||||
}
|
.then(function() {
|
||||||
return materials;
|
return materials;
|
||||||
})
|
|
||||||
.catch(function() {
|
|
||||||
console.log('Could not read material file at ' + mtlPath + '. Using default material instead.');
|
|
||||||
return {};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
555
lib/obj.js
|
@ -1,125 +1,170 @@
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
var Cesium = require('cesium');
|
var Cesium = require('cesium');
|
||||||
var Promise = require('bluebird');
|
|
||||||
var byline = require('byline');
|
|
||||||
var fs = require('fs-extra');
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
|
var ArrayStorage = require('./ArrayStorage');
|
||||||
var loadImage = require('./image');
|
var loadImage = require('./image');
|
||||||
var Material = require('./mtl');
|
var loadMtl = require('./mtl');
|
||||||
|
var readLines = require('./readLines');
|
||||||
|
|
||||||
var Cartesian3 = Cesium.Cartesian3;
|
var ComponentDatatype = Cesium.ComponentDatatype;
|
||||||
|
var defaultValue = Cesium.defaultValue;
|
||||||
var defined = Cesium.defined;
|
var defined = Cesium.defined;
|
||||||
|
var RuntimeError = Cesium.RuntimeError;
|
||||||
|
|
||||||
module.exports = parseObj;
|
module.exports = loadObj;
|
||||||
|
|
||||||
// OBJ regex patterns are from ThreeJS (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js)
|
// Object name (o) -> node
|
||||||
|
// Group name (g) -> mesh
|
||||||
|
// Material name (usemtl) -> primitive
|
||||||
|
|
||||||
function parseObj(objFile, inputPath) {
|
function Node() {
|
||||||
return getObjInfo(objFile, inputPath)
|
this.name = undefined;
|
||||||
.then(function(result) {
|
this.meshes = [];
|
||||||
var info = result.info;
|
|
||||||
var materials = result.materials;
|
|
||||||
var images = result.images;
|
|
||||||
return processObj(objFile, info, materials, images);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function processObj(objFile, info, materials, images) {
|
function Mesh() {
|
||||||
return new Promise(function(resolve) {
|
this.name = undefined;
|
||||||
// A vertex is specified by indexes into each of the attribute arrays,
|
this.primitives = [];
|
||||||
// but these indexes may be different. This maps the separate indexes to a single index.
|
this.positions = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||||
|
this.normals = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||||
|
this.uvs = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Primitive() {
|
||||||
|
this.material = undefined;
|
||||||
|
this.indices = new ArrayStorage(ComponentDatatype.UNSIGNED_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OBJ regex patterns are modified from ThreeJS (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js)
|
||||||
|
var vertexPattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // v float float float
|
||||||
|
var normalPattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vn float float float
|
||||||
|
var uvPattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vt float float
|
||||||
|
var facePattern1 = /f( +-?\d+)\/?( +-?\d+)\/?( +-?\d+)\/?( +-?\d+)?\/?/; // f vertex vertex vertex ...
|
||||||
|
var facePattern2 = /f( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)?/; // f vertex/uv vertex/uv vertex/uv ...
|
||||||
|
var facePattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/; // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
|
||||||
|
var facePattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/; // f vertex//normal vertex//normal vertex//normal ...
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an obj file.
|
||||||
|
*
|
||||||
|
* @param {String} objPath Path to the obj file.
|
||||||
|
* @param {Object} options An object with the following properties:
|
||||||
|
* @param {Boolean} options.checkTransparency Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel.
|
||||||
|
* @param {Boolean} options.secure Prevent the converter from reading image or mtl files outside of the input obj directory.
|
||||||
|
* @param {Boolean} options.logger A callback function for handling logged messages. Defaults to console.log.
|
||||||
|
* @returns {Promise} A promise resolving to the obj data.
|
||||||
|
* @exception {RuntimeError} The file does not have any geometry information in it.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function loadObj(objPath, options) {
|
||||||
|
// Global store of vertex attributes listed in the obj file
|
||||||
|
var positions = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||||
|
var normals = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||||
|
var uvs = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||||
|
|
||||||
|
// The current node, mesh, and primitive
|
||||||
|
var node;
|
||||||
|
var mesh;
|
||||||
|
var primitive;
|
||||||
|
|
||||||
|
// All nodes seen in the obj
|
||||||
|
var nodes = [];
|
||||||
|
|
||||||
|
// Used to build the indices. The vertex cache is unique to each mesh.
|
||||||
var vertexCache = {};
|
var vertexCache = {};
|
||||||
|
var vertexCacheLimit = 1000000;
|
||||||
|
var vertexCacheCount = 0;
|
||||||
var vertexCount = 0;
|
var vertexCount = 0;
|
||||||
|
|
||||||
var vertexArray = [];
|
// All mtl paths seen in the obj
|
||||||
|
var mtlPaths = [];
|
||||||
|
|
||||||
var positions = [];
|
function getName(name) {
|
||||||
var normals = [];
|
return (name === '' ? undefined : name);
|
||||||
var uvs = [];
|
|
||||||
|
|
||||||
var positionMin = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE];
|
|
||||||
var positionMax = [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE];
|
|
||||||
|
|
||||||
var hasNormals = info.hasNormals;
|
|
||||||
var hasUVs = info.hasUVs;
|
|
||||||
|
|
||||||
var materialGroups = {}; // Map material to index array
|
|
||||||
var currentIndexArray;
|
|
||||||
|
|
||||||
// Switch to the material-specific index array, or create it if it doesn't exist
|
|
||||||
function useMaterial(material) {
|
|
||||||
if (!defined(materials[material])) {
|
|
||||||
useDefaultMaterial();
|
|
||||||
} else {
|
|
||||||
currentIndexArray = materialGroups[material];
|
|
||||||
if (!defined(currentIndexArray)) {
|
|
||||||
currentIndexArray = [];
|
|
||||||
materialGroups[material] = currentIndexArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function useDefaultMaterial() {
|
function addNode(name) {
|
||||||
var defaultMaterial = 'czmDefaultMat';
|
node = new Node();
|
||||||
if (!defined(materials[defaultMaterial])) {
|
node.name = getName(name);
|
||||||
materials[defaultMaterial] = Material.getDefault();
|
nodes.push(node);
|
||||||
}
|
addMesh();
|
||||||
useMaterial(defaultMaterial);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var materialsLength = Object.keys(materials).length;
|
function addMesh(name) {
|
||||||
if (materialsLength === 0) {
|
mesh = new Mesh();
|
||||||
useDefaultMaterial();
|
mesh.name = getName(name);
|
||||||
|
node.meshes.push(mesh);
|
||||||
|
addPrimitive();
|
||||||
|
|
||||||
|
// Clear the vertex cache for each new mesh
|
||||||
|
vertexCache = {};
|
||||||
|
vertexCacheCount = 0;
|
||||||
|
vertexCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOffset(a, data, components) {
|
function addPrimitive() {
|
||||||
|
primitive = new Primitive();
|
||||||
|
mesh.primitives.push(primitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useMaterial(name) {
|
||||||
|
// Look to see if this material has already been used by a primitive in the mesh
|
||||||
|
var material = getName(name);
|
||||||
|
var primitives = mesh.primitives;
|
||||||
|
var primitivesLength = primitives.length;
|
||||||
|
for (var i = 0; i < primitivesLength; ++i) {
|
||||||
|
if (primitives[i].material === material) {
|
||||||
|
primitive = primitives[i];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add a new primitive with this material
|
||||||
|
addPrimitive();
|
||||||
|
primitive.material = getName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOffset(a, attributeData, components) {
|
||||||
var i = parseInt(a);
|
var i = parseInt(a);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
// Negative vertex indexes reference the vertices immediately above it
|
// Negative vertex indexes reference the vertices immediately above it
|
||||||
return (data.length / components + i) * components;
|
return (attributeData.length / components + i) * components;
|
||||||
}
|
}
|
||||||
return (i - 1) * components;
|
return (i - 1) * components;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createVertex(p, u, n) {
|
function createVertex(p, u, n) {
|
||||||
// Positions
|
// Positions
|
||||||
|
if (defined(p)) {
|
||||||
var pi = getOffset(p, positions, 3);
|
var pi = getOffset(p, positions, 3);
|
||||||
var px = positions[pi + 0];
|
var px = positions.get(pi + 0);
|
||||||
var py = positions[pi + 1];
|
var py = positions.get(pi + 1);
|
||||||
var pz = positions[pi + 2];
|
var pz = positions.get(pi + 2);
|
||||||
|
mesh.positions.push(px);
|
||||||
positionMin[0] = Math.min(px, positionMin[0]);
|
mesh.positions.push(py);
|
||||||
positionMin[1] = Math.min(py, positionMin[1]);
|
mesh.positions.push(pz);
|
||||||
positionMin[2] = Math.min(pz, positionMin[2]);
|
}
|
||||||
positionMax[0] = Math.max(px, positionMax[0]);
|
|
||||||
positionMax[1] = Math.max(py, positionMax[1]);
|
|
||||||
positionMax[2] = Math.max(pz, positionMax[2]);
|
|
||||||
vertexArray.push(px, py, pz);
|
|
||||||
|
|
||||||
// Normals
|
// Normals
|
||||||
if (hasNormals) {
|
if (defined(n)) {
|
||||||
var ni = getOffset(n, normals, 3);
|
var ni = getOffset(n, normals, 3);
|
||||||
var nx = normals[ni + 0];
|
var nx = normals.get(ni + 0);
|
||||||
var ny = normals[ni + 1];
|
var ny = normals.get(ni + 1);
|
||||||
var nz = normals[ni + 2];
|
var nz = normals.get(ni + 2);
|
||||||
vertexArray.push(nx, ny, nz);
|
mesh.normals.push(nx);
|
||||||
|
mesh.normals.push(ny);
|
||||||
|
mesh.normals.push(nz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UVs
|
// UVs
|
||||||
if (hasUVs) {
|
|
||||||
if (defined(u)) {
|
if (defined(u)) {
|
||||||
var ui = getOffset(u, uvs, 2);
|
var ui = getOffset(u, uvs, 2);
|
||||||
var ux = uvs[ui + 0];
|
var ux = uvs.get(ui + 0);
|
||||||
var uy = uvs[ui + 1];
|
var uy = uvs.get(ui + 1);
|
||||||
// Flip y so 0.0 is the bottom of the image
|
mesh.uvs.push(ux);
|
||||||
uy = 1.0 - uy;
|
mesh.uvs.push(uy);
|
||||||
vertexArray.push(ux, uy);
|
|
||||||
} else {
|
|
||||||
// Some objects in the model may not have uvs, fill with 0's for consistency
|
|
||||||
vertexArray.push(0.0, 0.0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,8 +174,15 @@ function processObj(objFile, info, materials, images) {
|
||||||
index = vertexCount++;
|
index = vertexCount++;
|
||||||
vertexCache[v] = index;
|
vertexCache[v] = index;
|
||||||
createVertex(p, u, n);
|
createVertex(p, u, n);
|
||||||
}
|
|
||||||
|
|
||||||
|
// Prevent the vertex cache from growing too large. As a result of clearing the cache there
|
||||||
|
// may be some duplicate vertices.
|
||||||
|
vertexCacheCount++;
|
||||||
|
if (vertexCacheCount > vertexCacheLimit) {
|
||||||
|
vertexCacheCount = 0;
|
||||||
|
vertexCache = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,63 +191,48 @@ function processObj(objFile, info, materials, images) {
|
||||||
var index2 = addVertex(v2, p2, u2, n2);
|
var index2 = addVertex(v2, p2, u2, n2);
|
||||||
var index3 = addVertex(v3, p3, u3, n3);
|
var index3 = addVertex(v3, p3, u3, n3);
|
||||||
|
|
||||||
currentIndexArray.push(index1);
|
primitive.indices.push(index1);
|
||||||
currentIndexArray.push(index2);
|
primitive.indices.push(index2);
|
||||||
currentIndexArray.push(index3);
|
primitive.indices.push(index3);
|
||||||
|
|
||||||
// Triangulate if the face is a quad
|
// Triangulate if the face is a quad
|
||||||
if (defined(v4)) {
|
if (defined(v4)) {
|
||||||
var index4 = addVertex(v4, p4, u4, n4);
|
var index4 = addVertex(v4, p4, u4, n4);
|
||||||
currentIndexArray.push(index1);
|
primitive.indices.push(index1);
|
||||||
currentIndexArray.push(index3);
|
primitive.indices.push(index3);
|
||||||
currentIndexArray.push(index4);
|
primitive.indices.push(index4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// v float float float
|
function parseLine(line) {
|
||||||
var vertexPattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
|
|
||||||
|
|
||||||
// vn float float float
|
|
||||||
var normalPattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
|
|
||||||
|
|
||||||
// vt float float
|
|
||||||
var uvPattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
|
|
||||||
|
|
||||||
// f vertex vertex vertex ...
|
|
||||||
var facePattern1 = /f( +-?\d+)\/?( +-?\d+)\/?( +-?\d+)\/?( +-?\d+)?\/?/;
|
|
||||||
|
|
||||||
// f vertex/uv vertex/uv vertex/uv ...
|
|
||||||
var facePattern2 = /f( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)( +(-?\d+)\/(-?\d+)\/?)?/;
|
|
||||||
|
|
||||||
// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
|
|
||||||
var facePattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/;
|
|
||||||
|
|
||||||
// f vertex//normal vertex//normal vertex//normal ...
|
|
||||||
var facePattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/;
|
|
||||||
|
|
||||||
var stream = byline(fs.createReadStream(objFile, {encoding: 'utf8'}));
|
|
||||||
stream.on('data', function (line) {
|
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
var result;
|
var result;
|
||||||
|
|
||||||
if ((line.length === 0) || (line.charAt(0) === '#')) {
|
if ((line.length === 0) || (line.charAt(0) === '#')) {
|
||||||
// Don't process empty lines or comments
|
// Don't process empty lines or comments
|
||||||
|
} else if (/^o\s/i.test(line)) {
|
||||||
|
var objectName = line.substring(2).trim();
|
||||||
|
addNode(objectName);
|
||||||
|
} else if (/^g\s/i.test(line)) {
|
||||||
|
var groupName = line.substring(2).trim();
|
||||||
|
addMesh(groupName);
|
||||||
|
} else if (/^usemtl\s/i.test(line)) {
|
||||||
|
var materialName = line.substring(7).trim();
|
||||||
|
useMaterial(materialName);
|
||||||
|
} else if (/^mtllib/i.test(line)) {
|
||||||
|
var paths = line.substring(7).trim().split(' ');
|
||||||
|
mtlPaths = mtlPaths.concat(paths);
|
||||||
} else if ((result = vertexPattern.exec(line)) !== null) {
|
} else if ((result = vertexPattern.exec(line)) !== null) {
|
||||||
positions.push(
|
positions.push(parseFloat(result[1]));
|
||||||
parseFloat(result[1]),
|
positions.push(parseFloat(result[2]));
|
||||||
parseFloat(result[2]),
|
positions.push(parseFloat(result[3]));
|
||||||
parseFloat(result[3])
|
|
||||||
);
|
|
||||||
} else if ((result = normalPattern.exec(line) ) !== null) {
|
} else if ((result = normalPattern.exec(line) ) !== null) {
|
||||||
var nx = parseFloat(result[1]);
|
normals.push(parseFloat(result[1]));
|
||||||
var ny = parseFloat(result[2]);
|
normals.push(parseFloat(result[2]));
|
||||||
var nz = parseFloat(result[3]);
|
normals.push(parseFloat(result[3]));
|
||||||
var normal = Cartesian3.normalize(new Cartesian3(nx, ny, nz), new Cartesian3());
|
|
||||||
normals.push(normal.x, normal.y, normal.z);
|
|
||||||
} else if ((result = uvPattern.exec(line)) !== null) {
|
} else if ((result = uvPattern.exec(line)) !== null) {
|
||||||
uvs.push(
|
uvs.push(parseFloat(result[1]));
|
||||||
parseFloat(result[1]),
|
uvs.push(1.0 - parseFloat(result[2])); // Flip y so 0.0 is the bottom of the image
|
||||||
parseFloat(result[2])
|
|
||||||
);
|
|
||||||
} else if ((result = facePattern1.exec(line)) !== null) {
|
} else if ((result = facePattern1.exec(line)) !== null) {
|
||||||
addFace(
|
addFace(
|
||||||
result[1], result[1], undefined, undefined,
|
result[1], result[1], undefined, undefined,
|
||||||
|
@ -224,142 +261,188 @@ function processObj(objFile, info, materials, images) {
|
||||||
result[7], result[8], undefined, result[9],
|
result[7], result[8], undefined, result[9],
|
||||||
result[10], result[11], undefined, result[12]
|
result[10], result[11], undefined, result[12]
|
||||||
);
|
);
|
||||||
} else if (/^usemtl /.test(line)) {
|
|
||||||
var materialName = line.substring(7).trim();
|
|
||||||
useMaterial(materialName);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
stream.on('end', function () {
|
// Create a default node in case there are no o/g/usemtl lines in the obj
|
||||||
resolve({
|
addNode();
|
||||||
vertexCount: vertexCount,
|
|
||||||
vertexArray: vertexArray,
|
// Parse the obj file
|
||||||
positionMin: positionMin,
|
return readLines(objPath, parseLine)
|
||||||
positionMax: positionMax,
|
.then(function() {
|
||||||
hasUVs: hasUVs,
|
// Unload resources
|
||||||
hasNormals: hasNormals,
|
positions = undefined;
|
||||||
materialGroups: materialGroups,
|
normals = undefined;
|
||||||
|
uvs = undefined;
|
||||||
|
|
||||||
|
// Load materials and images
|
||||||
|
return finishLoading(nodes, mtlPaths, objPath, options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishLoading(nodes, mtlPaths, objPath, options) {
|
||||||
|
nodes = cleanNodes(nodes);
|
||||||
|
if (nodes.length === 0) {
|
||||||
|
return Promise.reject(new RuntimeError(objPath + ' does not have any geometry data'));
|
||||||
|
}
|
||||||
|
return loadMaterials(mtlPaths, objPath, options)
|
||||||
|
.then(function(materials) {
|
||||||
|
var imagePaths = getImagePaths(materials);
|
||||||
|
return loadImages(imagePaths, objPath, options)
|
||||||
|
.then(function(images) {
|
||||||
|
return {
|
||||||
|
nodes : nodes,
|
||||||
materials : materials,
|
materials : materials,
|
||||||
images : images
|
images : images
|
||||||
});
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getImages(inputPath, materials) {
|
function outsideDirectory(filePath, objPath) {
|
||||||
// Collect all the image files from the materials
|
return (path.relative(path.dirname(objPath), filePath).indexOf('..') === 0);
|
||||||
var images = [];
|
}
|
||||||
|
|
||||||
|
function loadMaterials(mtlPaths, objPath, options) {
|
||||||
|
var secure = options.secure;
|
||||||
|
var logger = options.logger;
|
||||||
|
var objDirectory = path.dirname(objPath);
|
||||||
|
var materials = {};
|
||||||
|
return Promise.map(mtlPaths, function(mtlPath) {
|
||||||
|
mtlPath = path.resolve(objDirectory, mtlPath);
|
||||||
|
if (secure && outsideDirectory(mtlPath, objPath)) {
|
||||||
|
logger('Could not read mtl file at ' + mtlPath + ' because it is outside of the obj directory and the secure flag is true. Using default material instead.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return loadMtl(mtlPath)
|
||||||
|
.then(function(materialsInMtl) {
|
||||||
|
materials = Object.assign(materials, materialsInMtl);
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
logger('Could not read mtl file at ' + mtlPath + '. Using default material instead.');
|
||||||
|
});
|
||||||
|
}, {concurrency : 10})
|
||||||
|
.thenReturn(materials);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadImages(imagePaths, objPath, options) {
|
||||||
|
var secure = options.secure;
|
||||||
|
var logger = options.logger;
|
||||||
|
var images = {};
|
||||||
|
return Promise.map(imagePaths, function(imagePath) {
|
||||||
|
if (secure && outsideDirectory(imagePath, objPath)) {
|
||||||
|
logger('Could not read image file at ' + imagePath + ' because it is outside of the obj directory and the secure flag is true. Material will ignore this image.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return loadImage(imagePath, options)
|
||||||
|
.then(function(image) {
|
||||||
|
images[imagePath] = image;
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
logger('Could not read image file at ' + imagePath + '. Material will ignore this image.');
|
||||||
|
});
|
||||||
|
}, {concurrency : 10})
|
||||||
|
.thenReturn(images);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImagePaths(materials) {
|
||||||
|
var imagePaths = {};
|
||||||
for (var name in materials) {
|
for (var name in materials) {
|
||||||
if (materials.hasOwnProperty(name)) {
|
if (materials.hasOwnProperty(name)) {
|
||||||
var material = materials[name];
|
var material = materials[name];
|
||||||
if (defined(material.ambientColorMap) && (images.indexOf(material.ambientColorMap) === -1)) {
|
if (defined(material.ambientTexture)) {
|
||||||
images.push(material.ambientColorMap);
|
imagePaths[material.ambientTexture] = true;
|
||||||
}
|
}
|
||||||
if (defined(material.diffuseColorMap) && (images.indexOf(material.diffuseColorMap) === -1)) {
|
if (defined(material.diffuseTexture)) {
|
||||||
images.push(material.diffuseColorMap);
|
imagePaths[material.diffuseTexture] = true;
|
||||||
}
|
}
|
||||||
if (defined(material.emissionColorMap) && (images.indexOf(material.emissionColorMap) === -1)) {
|
if (defined(material.emissionTexture)) {
|
||||||
images.push(material.emissionColorMap);
|
imagePaths[material.emissionTexture] = true;
|
||||||
}
|
}
|
||||||
if (defined(material.specularColorMap) && (images.indexOf(material.specularColorMap) === -1)) {
|
if (defined(material.specularTexture)) {
|
||||||
images.push(material.specularColorMap);
|
imagePaths[material.specularTexture] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Object.keys(imagePaths);
|
||||||
|
}
|
||||||
|
|
||||||
// Load the image files
|
function removeEmptyMeshes(meshes) {
|
||||||
var promises = [];
|
return meshes.filter(function(mesh) {
|
||||||
var imagesInfo = {};
|
// Remove empty primitives
|
||||||
var imagesLength = images.length;
|
mesh.primitives = mesh.primitives.filter(function(primitive) {
|
||||||
for (var i = 0; i < imagesLength; i++) {
|
return primitive.indices.length > 0;
|
||||||
var imagePath = images[i];
|
});
|
||||||
if (!path.isAbsolute(imagePath)) {
|
// Valid meshes must have at least one primitive and contain positions
|
||||||
imagePath = path.join(inputPath, imagePath);
|
return (mesh.primitives.length > 0) && (mesh.positions.length > 0);
|
||||||
}
|
|
||||||
promises.push(loadImage(imagePath));
|
|
||||||
}
|
|
||||||
return Promise.all(promises)
|
|
||||||
.then(function(imageInfoArray) {
|
|
||||||
var imageInfoArrayLength = imageInfoArray.length;
|
|
||||||
for (var j = 0; j < imageInfoArrayLength; j++) {
|
|
||||||
var image = images[j];
|
|
||||||
var imageInfo = imageInfoArray[j];
|
|
||||||
imagesInfo[image] = imageInfo;
|
|
||||||
}
|
|
||||||
return imagesInfo;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMaterials(mtlPath, hasMaterialGroups) {
|
function meshesHaveNames(meshes) {
|
||||||
if (hasMaterialGroups && defined(mtlPath)) {
|
var meshesLength = meshes.length;
|
||||||
return Material.parse(mtlPath);
|
for (var i = 0; i < meshesLength; ++i) {
|
||||||
|
if (defined(meshes[i].name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
function removeEmptyNodes(nodes) {
|
||||||
|
var final = [];
|
||||||
|
var nodesLength = nodes.length;
|
||||||
|
for (var i = 0; i < nodesLength; ++i) {
|
||||||
|
var node = nodes[i];
|
||||||
|
var meshes = removeEmptyMeshes(node.meshes);
|
||||||
|
if (meshes.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
node.meshes = meshes;
|
||||||
|
if (!defined(node.name) && meshesHaveNames(meshes)) {
|
||||||
|
// If the obj has groups (g) but not object groups (o) then convert meshes to nodes
|
||||||
|
var meshesLength = meshes.length;
|
||||||
|
for (var j = 0; j < meshesLength; ++j) {
|
||||||
|
var mesh = meshes[j];
|
||||||
|
var convertedNode = new Node();
|
||||||
|
convertedNode.name = mesh.name;
|
||||||
|
convertedNode.meshes = [mesh];
|
||||||
|
final.push(convertedNode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return final;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getObjInfo(objFile, inputPath) {
|
function setDefaultNames(items, defaultName, usedNames) {
|
||||||
var mtlPath;
|
var itemsLength = items.length;
|
||||||
var materials;
|
for (var i = 0; i < itemsLength; ++i) {
|
||||||
var info;
|
var item = items[i];
|
||||||
var hasMaterialGroups = false;
|
var name = defaultValue(item.name, defaultName);
|
||||||
var hasPositions = false;
|
var occurrences = usedNames[name];
|
||||||
var hasNormals = false;
|
if (defined(occurrences)) {
|
||||||
var hasUVs = false;
|
usedNames[name]++;
|
||||||
return new Promise(function(resolve, reject) {
|
name = name + '_' + occurrences;
|
||||||
var stream = byline(fs.createReadStream(objFile, {encoding: 'utf8'}));
|
} else {
|
||||||
stream.on('data', function (line) {
|
usedNames[name] = 1;
|
||||||
if (!defined(mtlPath)) {
|
}
|
||||||
var mtllibMatches = line.match(/^mtllib.*/gm);
|
item.name = name;
|
||||||
if (mtllibMatches !== null) {
|
|
||||||
var mtlFile = mtllibMatches[0].substring(7).trim();
|
|
||||||
mtlPath = mtlFile;
|
|
||||||
if (!path.isAbsolute(mtlPath)) {
|
|
||||||
mtlPath = path.join(inputPath, mtlFile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!hasMaterialGroups) {
|
|
||||||
hasMaterialGroups = /^usemtl/gm.test(line);
|
|
||||||
}
|
|
||||||
if (!hasPositions) {
|
|
||||||
hasPositions = /^v\s/gm.test(line);
|
|
||||||
}
|
|
||||||
if (!hasNormals) {
|
|
||||||
hasNormals = /^vn/gm.test(line);
|
|
||||||
}
|
|
||||||
if (!hasUVs) {
|
|
||||||
hasUVs = /^vt/gm.test(line);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
stream.on('error', function(err) {
|
function setDefaults(nodes) {
|
||||||
reject(err);
|
var usedNames = {};
|
||||||
});
|
setDefaultNames(nodes, 'Node', usedNames);
|
||||||
|
var nodesLength = nodes.length;
|
||||||
|
for (var i = 0; i < nodesLength; ++i) {
|
||||||
|
var node = nodes[i];
|
||||||
|
setDefaultNames(node.meshes, node.name + '-Mesh', usedNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stream.on('end', function () {
|
function cleanNodes(nodes) {
|
||||||
if (!hasPositions) {
|
nodes = removeEmptyNodes(nodes);
|
||||||
reject(new Error('Could not process OBJ file, no positions.'));
|
setDefaults(nodes);
|
||||||
}
|
return nodes;
|
||||||
info = {
|
|
||||||
hasNormals: hasNormals,
|
|
||||||
hasUVs: hasUVs
|
|
||||||
};
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
return getMaterials(mtlPath, hasMaterialGroups);
|
|
||||||
})
|
|
||||||
.then(function(returnedMaterials) {
|
|
||||||
materials = returnedMaterials;
|
|
||||||
return getImages(inputPath, materials);
|
|
||||||
})
|
|
||||||
.then(function(images) {
|
|
||||||
return {
|
|
||||||
info : info,
|
|
||||||
materials : materials,
|
|
||||||
images : images
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
'use strict';
|
||||||
|
var eventStream = require('event-stream');
|
||||||
|
var fsExtra = require('fs-extra');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
|
module.exports = readLines;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a file line-by-line.
|
||||||
|
*
|
||||||
|
* @param {String} path Path to the file.
|
||||||
|
* @param {Function} callback Function to call when reading each line.
|
||||||
|
* @returns {Promise} A promise when the reader is finished.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function readLines(path, callback) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
fsExtra.createReadStream(path)
|
||||||
|
.on('error', reject)
|
||||||
|
.on('end', resolve)
|
||||||
|
.pipe(eventStream.split())
|
||||||
|
.pipe(eventStream.mapSync(function (line) {
|
||||||
|
callback(line);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
'use strict';
|
||||||
|
var Cesium = require('cesium');
|
||||||
|
var fsExtra = require('fs-extra');
|
||||||
|
var mime = require('mime');
|
||||||
|
var path = require('path');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
|
var fsExtraOutputFile = Promise.promisify(fsExtra.outputFile);
|
||||||
|
|
||||||
|
var RuntimeError = Cesium.RuntimeError;
|
||||||
|
|
||||||
|
module.exports = writeUris;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write glTF resources as embedded data uris or external files.
|
||||||
|
*
|
||||||
|
* @param {Object} gltf The glTF asset.
|
||||||
|
* @param {String} gltfPath Path where the glTF will be saved.
|
||||||
|
* @param {Object} options An object with the following properties:
|
||||||
|
* @param {Boolean} options.separate Writes out separate buffers.
|
||||||
|
* @param {Boolean} options.separateTextures Write out separate textures only.
|
||||||
|
* @returns {Promise} A promise that resolves to the glTF asset.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function writeUris(gltf, gltfPath, options) {
|
||||||
|
var separate = options.separate;
|
||||||
|
var separateTextures = options.separateTextures;
|
||||||
|
|
||||||
|
var promises = [];
|
||||||
|
|
||||||
|
var buffer = gltf.buffers[Object.keys(gltf.buffers)[0]];
|
||||||
|
var bufferByteLength = buffer.extras._obj2gltf.source.length;
|
||||||
|
|
||||||
|
var texturesByteLength = 0;
|
||||||
|
var images = gltf.images;
|
||||||
|
for (var id in images) {
|
||||||
|
if (images.hasOwnProperty(id)) {
|
||||||
|
texturesByteLength += images[id].extras._obj2gltf.source.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffers larger than ~192MB cannot be base64 encoded due to a NodeJS limitation. Source: https://github.com/nodejs/node/issues/4266
|
||||||
|
var exceedsMaximum = (texturesByteLength + bufferByteLength > 201326580);
|
||||||
|
|
||||||
|
if (exceedsMaximum && !separate) {
|
||||||
|
return Promise.reject(new RuntimeError('Buffers and textures are too large to encode in the glTF, saving as separate resources.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (separate) {
|
||||||
|
promises.push(writeSeparateBuffer(gltf, gltfPath));
|
||||||
|
} else {
|
||||||
|
writeEmbeddedBuffer(gltf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (separateTextures) {
|
||||||
|
promises.push(writeSeparateTextures(gltf, gltfPath));
|
||||||
|
} else {
|
||||||
|
writeEmbeddedTextures(gltf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises)
|
||||||
|
.then(function() {
|
||||||
|
deleteExtras(gltf);
|
||||||
|
return gltf;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteExtras(gltf) {
|
||||||
|
var buffer = gltf.buffers[Object.keys(gltf.buffers)[0]];
|
||||||
|
delete buffer.extras;
|
||||||
|
|
||||||
|
var images = gltf.images;
|
||||||
|
for (var id in images) {
|
||||||
|
if (images.hasOwnProperty(id)) {
|
||||||
|
var image = images[id];
|
||||||
|
delete image.extras;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeSeparateBuffer(gltf, gltfPath) {
|
||||||
|
var buffer = gltf.buffers[Object.keys(gltf.buffers)[0]];
|
||||||
|
var source = buffer.extras._obj2gltf.source;
|
||||||
|
var bufferName = path.basename(gltfPath, path.extname(gltfPath));
|
||||||
|
var bufferUri = bufferName + '.bin';
|
||||||
|
buffer.uri = bufferUri;
|
||||||
|
var bufferPath = path.join(path.dirname(gltfPath), bufferUri);
|
||||||
|
return writeUris._outputFile(bufferPath, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeSeparateTextures(gltf, gltfPath) {
|
||||||
|
var images = gltf.images;
|
||||||
|
return Promise.map(Object.keys(images), function(id) {
|
||||||
|
var image = images[id];
|
||||||
|
var extras = image.extras._obj2gltf;
|
||||||
|
var imageUri = image.name + extras.extension;
|
||||||
|
image.uri = imageUri;
|
||||||
|
var imagePath = path.join(path.dirname(gltfPath), imageUri);
|
||||||
|
return writeUris._outputFile(imagePath, extras.source);
|
||||||
|
}, {concurrency : 10});
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeEmbeddedBuffer(gltf) {
|
||||||
|
var buffer = gltf.buffers[Object.keys(gltf.buffers)[0]];
|
||||||
|
var source = buffer.extras._obj2gltf.source;
|
||||||
|
buffer.uri = 'data:application/octet-stream;base64,' + source.toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeEmbeddedTextures(gltf) {
|
||||||
|
var images = gltf.images;
|
||||||
|
for (var id in images) {
|
||||||
|
if (images.hasOwnProperty(id)) {
|
||||||
|
var image = images[id];
|
||||||
|
var extras = image.extras._obj2gltf;
|
||||||
|
image.uri = 'data:' + mime.lookup(extras.extension) + ';base64,' + extras.source.toString('base64');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposed for testing.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
writeUris._outputFile = fsExtraOutputFile;
|
32
package.json
|
@ -6,50 +6,48 @@
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
{
|
||||||
"name": "Analytical Graphics, Inc., and Contributors",
|
"name": "Analytical Graphics, Inc., and Contributors",
|
||||||
"url": "https://github.com/AnalyticalGraphicsInc/OBJ2GLTF/graphs/contributors"
|
"url": "https://github.com/AnalyticalGraphicsInc/obj2gltf/graphs/contributors"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"obj",
|
"obj",
|
||||||
"gltf"
|
"gltf"
|
||||||
],
|
],
|
||||||
"homepage": "https://github.com/AnalyticalGraphicsInc/OBJ2GLTF",
|
"homepage": "https://github.com/AnalyticalGraphicsInc/obj2gltf",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@github.com:AnalyticalGraphicsInc/OBJ2GLTF.git"
|
"url": "git@github.com:AnalyticalGraphicsInc/obj2gltf.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/AnalyticalGraphicsInc/OBJ2GLTF/issues"
|
"url": "https://github.com/AnalyticalGraphicsInc/obj2gltf/issues"
|
||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0.0"
|
"node": ">=4.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^2.1.4",
|
|
||||||
"bluebird": "^3.4.7",
|
"bluebird": "^3.4.7",
|
||||||
"byline": "^5.0.0",
|
"cesium": "^1.31.0",
|
||||||
"cesium": "^1.29.0",
|
"event-stream": "^3.3.4",
|
||||||
"fs-extra": "^1.0.0",
|
"fs-extra": "^2.0.0",
|
||||||
"gltf-pipeline": "^0.1.0-alpha9",
|
"gltf-pipeline": "^0.1.0-alpha11",
|
||||||
"yargs": "^6.6.0"
|
"mime": "^1.3.4",
|
||||||
|
"pngjs": "^3.0.1",
|
||||||
|
"yargs": "^7.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"coveralls": "^2.11.15",
|
"coveralls": "^2.12.0",
|
||||||
"gulp": "^3.9.1",
|
"gulp": "^3.9.1",
|
||||||
"gulp-jshint": "^2.0.4",
|
"gulp-jshint": "^2.0.4",
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"jasmine": "^2.5.2",
|
"jasmine": "^2.5.3",
|
||||||
"jasmine-spec-reporter": "^3.0.0",
|
"jasmine-spec-reporter": "^3.2.0",
|
||||||
"jsdoc": "^3.4.3",
|
|
||||||
"jshint": "^2.9.4",
|
"jshint": "^2.9.4",
|
||||||
"jshint-stylish": "^2.2.1",
|
"jshint-stylish": "^2.2.1",
|
||||||
"open": "^0.0.5",
|
"open": "^0.0.5",
|
||||||
"requirejs": "^2.3.2",
|
"requirejs": "^2.3.3"
|
||||||
"typings": "^2.1.0"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepublish": "typings install",
|
|
||||||
"jsdoc": "jsdoc ./lib -R ./README.md -d doc",
|
"jsdoc": "jsdoc ./lib -R ./README.md -d doc",
|
||||||
"jsHint": "gulp jsHint",
|
"jsHint": "gulp jsHint",
|
||||||
"jsHint-watch": "gulp jsHint-watch",
|
"jsHint-watch": "gulp jsHint-watch",
|
||||||
|
|
Before Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,20 @@
|
||||||
|
# Blender MTL File: 'None'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.200000 0.200000 0.200000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.100000 0.100000 0.100000
|
||||||
|
Ni 1.000000
|
||||||
|
d 0.900000
|
||||||
|
Tr 0.900000
|
||||||
|
map_Ka ambient.gif
|
||||||
|
map_Ke emission.jpg
|
||||||
|
map_Kd diffuse.png
|
||||||
|
map_Ks specular.jpeg
|
||||||
|
map_Ns shininess.png
|
||||||
|
map_Bump bump.png
|
||||||
|
map_d alpha.png
|
||||||
|
illum 2
|
|
@ -1,7 +1,7 @@
|
||||||
# Blender v2.77 (sub 0) OBJ File: 'BoxTextured.blend'
|
# Blender v2.78 (sub 0) OBJ File: ''
|
||||||
# www.blender.org
|
# www.blender.org
|
||||||
mtllib BoxTextured.mtl
|
mtllib box-complex-material.mtl
|
||||||
o Cube_Cube.001
|
o Cube
|
||||||
v -1.000000 -1.000000 1.000000
|
v -1.000000 -1.000000 1.000000
|
||||||
v -1.000000 1.000000 1.000000
|
v -1.000000 1.000000 1.000000
|
||||||
v -1.000000 -1.000000 -1.000000
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
@ -26,9 +26,9 @@ vt 0.0000 0.0000
|
||||||
vt 1.0000 0.0000
|
vt 1.0000 0.0000
|
||||||
vt 1.0000 1.0000
|
vt 1.0000 1.0000
|
||||||
vt 0.0000 1.0000
|
vt 0.0000 1.0000
|
||||||
vt 0.0000 0.0000
|
|
||||||
vt 1.0000 0.0000
|
vt 1.0000 0.0000
|
||||||
vt 1.0000 1.0000
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
vt 0.0000 1.0000
|
vt 0.0000 1.0000
|
||||||
vn -1.0000 0.0000 0.0000
|
vn -1.0000 0.0000 0.0000
|
||||||
vn 0.0000 0.0000 -1.0000
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
@ -36,11 +36,11 @@ vn 1.0000 0.0000 0.0000
|
||||||
vn 0.0000 0.0000 1.0000
|
vn 0.0000 0.0000 1.0000
|
||||||
vn 0.0000 -1.0000 0.0000
|
vn 0.0000 -1.0000 0.0000
|
||||||
vn 0.0000 1.0000 0.0000
|
vn 0.0000 1.0000 0.0000
|
||||||
usemtl Textured
|
usemtl Material
|
||||||
s off
|
s off
|
||||||
f 2/1/1 4/2/1 3/3/1 1/4/1
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
f 4/5/2 8/6/2 7/7/2 3/8/2
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
f 8/9/3 6/10/3 5/11/3 7/12/3
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
f 6/13/4 2/14/4 1/15/4 5/16/4
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
f 1/17/5 3/18/5 7/7/5 5/16/5
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
f 6/13/6 8/6/6 4/19/6 2/20/6
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 5.5 KiB |
|
@ -0,0 +1,13 @@
|
||||||
|
# Blender MTL File: 'box.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl MaterialTextured
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd ../box-textured/cesium.png
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box-multiple-materials.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-external-resources.mtl
|
||||||
|
mtllib ../box/box.mtl
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
usemtl MaterialTextured
|
||||||
|
f 3/1/1 7/2/1 5/3/1 1/4/1
|
||||||
|
f 1/9/3 2/10/3 4/11/3 3/12/3
|
||||||
|
f 3/1/5 4/6/5 8/17/5 7/18/5
|
||||||
|
usemtl Material
|
||||||
|
f 8/5/2 4/6/2 2/7/2 6/8/2
|
||||||
|
f 7/13/4 8/14/4 6/15/4 5/16/4
|
||||||
|
f 5/19/6 6/20/6 2/7/6 1/4/6
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Blender MTL File: 'box-objects.blend'
|
||||||
|
# Material Count: 3
|
||||||
|
|
||||||
|
newmtl Blue
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.000000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Green
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.640000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Red
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.000000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,132 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box-objects.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-groups.mtl
|
||||||
|
g CubeBlue
|
||||||
|
v -1.000000 -1.000000 -4.000000
|
||||||
|
v -1.000000 1.000000 -4.000000
|
||||||
|
v -1.000000 -1.000000 -6.000000
|
||||||
|
v -1.000000 1.000000 -6.000000
|
||||||
|
v 1.000000 -1.000000 -4.000000
|
||||||
|
v 1.000000 1.000000 -4.000000
|
||||||
|
v 1.000000 -1.000000 -6.000000
|
||||||
|
v 1.000000 1.000000 -6.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Blue
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
||||||
|
g CubeGreen
|
||||||
|
v 4.000000 -1.000000 1.000000
|
||||||
|
v 4.000000 1.000000 1.000000
|
||||||
|
v 4.000000 -1.000000 -1.000000
|
||||||
|
v 4.000000 1.000000 -1.000000
|
||||||
|
v 6.000000 -1.000000 1.000000
|
||||||
|
v 6.000000 1.000000 1.000000
|
||||||
|
v 6.000000 -1.000000 -1.000000
|
||||||
|
v 6.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Green
|
||||||
|
s off
|
||||||
|
f 9/21/7 10/22/7 12/23/7 11/24/7
|
||||||
|
f 11/25/8 12/26/8 16/27/8 15/28/8
|
||||||
|
f 15/29/9 16/30/9 14/31/9 13/32/9
|
||||||
|
f 13/33/10 14/34/10 10/35/10 9/36/10
|
||||||
|
f 11/25/11 15/37/11 13/38/11 9/36/11
|
||||||
|
f 16/39/12 12/26/12 10/35/12 14/40/12
|
||||||
|
g CubeRed
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Red
|
||||||
|
s off
|
||||||
|
f 17/41/13 18/42/13 20/43/13 19/44/13
|
||||||
|
f 19/45/14 20/46/14 24/47/14 23/48/14
|
||||||
|
f 23/49/15 24/50/15 22/51/15 21/52/15
|
||||||
|
f 21/53/16 22/54/16 18/55/16 17/56/16
|
||||||
|
f 19/45/17 23/57/17 21/58/17 17/56/17
|
||||||
|
f 24/59/18 20/46/18 18/55/18 22/60/18
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: ''
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
|
@ -1,13 +1,13 @@
|
||||||
# Blender MTL File: 'BoxTextured.blend'
|
# Blender MTL File: 'box.blend'
|
||||||
# Material Count: 1
|
# Material Count: 1
|
||||||
|
|
||||||
newmtl Textured
|
newmtl Material
|
||||||
Ns 96.078431
|
Ns 96.078431
|
||||||
Ka 1.000000 1.000000 1.000000
|
Ka 0.000000 0.000000 0.000000
|
||||||
Kd 0.640000 0.640000 0.640000
|
Kd 0.640000 0.640000 0.640000
|
||||||
Ks 0.500000 0.500000 0.500000
|
Ks 0.500000 0.500000 0.500000
|
||||||
Ke 0.000000 0.000000 0.000000
|
Ke 0.000000 0.000000 0.000000
|
||||||
Ni 1.000000
|
Ni 1.000000
|
||||||
d 1.000000
|
d 1.000000
|
||||||
illum 2
|
illum 2
|
||||||
map_Kd CesiumLogoFlat.png
|
map_Kd cesium.png
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-missing-texture.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'box-multiple-materials.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Blue
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.000000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'box-multiple-materials.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Green
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.640000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'box-multiple-materials.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Red
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.000000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box-multiple-materials.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-mtllib-red.mtl
|
||||||
|
mtllib box-mtllib-green.mtl box-mtllib-blue.mtl
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
usemtl Red
|
||||||
|
f 3/1/1 7/2/1 5/3/1 1/4/1
|
||||||
|
usemtl Green
|
||||||
|
f 1/9/3 2/10/3 4/11/3 3/12/3
|
||||||
|
usemtl Blue
|
||||||
|
f 3/1/5 4/6/5 8/17/5 7/18/5
|
||||||
|
usemtl Red
|
||||||
|
f 8/5/2 4/6/2 2/7/2 6/8/2
|
||||||
|
usemtl Green
|
||||||
|
f 7/13/4 8/14/4 6/15/4 5/16/4
|
||||||
|
usemtl Blue
|
||||||
|
f 5/19/6 6/20/6 2/7/6 1/4/6
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Blender MTL File: 'box-multiple-materials.blend'
|
||||||
|
# Material Count: 3
|
||||||
|
|
||||||
|
newmtl Blue
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.000000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Green
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.640000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Red
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.000000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box-multiple-materials.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-multiple-materials.mtl
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
usemtl Red
|
||||||
|
f 3/1/1 7/2/1 5/3/1 1/4/1
|
||||||
|
usemtl Green
|
||||||
|
f 1/9/3 2/10/3 4/11/3 3/12/3
|
||||||
|
usemtl Blue
|
||||||
|
f 3/1/5 4/6/5 8/17/5 7/18/5
|
||||||
|
usemtl Red
|
||||||
|
f 8/5/2 4/6/2 2/7/2 6/8/2
|
||||||
|
usemtl Green
|
||||||
|
f 7/13/4 8/14/4 6/15/4 5/16/4
|
||||||
|
usemtl Blue
|
||||||
|
f 5/19/6 6/20/6 2/7/6 1/4/6
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'box.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-negative-indices.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f -8 -7 -5 -6
|
||||||
|
f -6 -5 -1 -2
|
||||||
|
f -2 -1 -3 -4
|
||||||
|
f -4 -3 -7 -8
|
||||||
|
f -6 -2 -4 -8
|
||||||
|
f -1 -5 -7 -3
|
|
@ -0,0 +1,125 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box-objects.blend'
|
||||||
|
# www.blender.org
|
||||||
|
v -1.000000 -1.000000 -4.000000
|
||||||
|
v -1.000000 1.000000 -4.000000
|
||||||
|
v -1.000000 -1.000000 -6.000000
|
||||||
|
v -1.000000 1.000000 -6.000000
|
||||||
|
v 1.000000 -1.000000 -4.000000
|
||||||
|
v 1.000000 1.000000 -4.000000
|
||||||
|
v 1.000000 -1.000000 -6.000000
|
||||||
|
v 1.000000 1.000000 -6.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
||||||
|
v 4.000000 -1.000000 1.000000
|
||||||
|
v 4.000000 1.000000 1.000000
|
||||||
|
v 4.000000 -1.000000 -1.000000
|
||||||
|
v 4.000000 1.000000 -1.000000
|
||||||
|
v 6.000000 -1.000000 1.000000
|
||||||
|
v 6.000000 1.000000 1.000000
|
||||||
|
v 6.000000 -1.000000 -1.000000
|
||||||
|
v 6.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
s off
|
||||||
|
f 9/21/7 10/22/7 12/23/7 11/24/7
|
||||||
|
f 11/25/8 12/26/8 16/27/8 15/28/8
|
||||||
|
f 15/29/9 16/30/9 14/31/9 13/32/9
|
||||||
|
f 13/33/10 14/34/10 10/35/10 9/36/10
|
||||||
|
f 11/25/11 15/37/11 13/38/11 9/36/11
|
||||||
|
f 16/39/12 12/26/12 10/35/12 14/40/12
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
s off
|
||||||
|
f 17/41/13 18/42/13 20/43/13 19/44/13
|
||||||
|
f 19/45/14 20/46/14 24/47/14 23/48/14
|
||||||
|
f 23/49/15 24/50/15 22/51/15 21/52/15
|
||||||
|
f 21/53/16 22/54/16 18/55/16 17/56/16
|
||||||
|
f 19/45/17 23/57/17 21/58/17 17/56/17
|
||||||
|
f 24/59/18 20/46/18 18/55/18 22/60/18
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'box.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-normals.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1//1 2//1 4//1 3//1
|
||||||
|
f 3//2 4//2 8//2 7//2
|
||||||
|
f 7//3 8//3 6//3 5//3
|
||||||
|
f 5//4 6//4 2//4 1//4
|
||||||
|
f 3//5 7//5 5//5 1//5
|
||||||
|
f 8//6 4//6 2//6 6//6
|
|
@ -0,0 +1,492 @@
|
||||||
|
{
|
||||||
|
"accessors": {
|
||||||
|
"accessor_0": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-6
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
-4
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
"accessor_1": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 288,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
"accessor_2": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 576,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
"accessor_3": {
|
||||||
|
"bufferView": "bufferView_index",
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5123,
|
||||||
|
"count": 18,
|
||||||
|
"min": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
"accessor_4": {
|
||||||
|
"bufferView": "bufferView_index",
|
||||||
|
"byteOffset": 36,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5123,
|
||||||
|
"count": 18,
|
||||||
|
"min": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
"accessor_5": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 768,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
4,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
6,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
"accessor_6": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 1056,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
"accessor_7": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 1344,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
"accessor_8": {
|
||||||
|
"bufferView": "bufferView_index",
|
||||||
|
"byteOffset": 72,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5123,
|
||||||
|
"count": 18,
|
||||||
|
"min": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
"accessor_9": {
|
||||||
|
"bufferView": "bufferView_index",
|
||||||
|
"byteOffset": 108,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5123,
|
||||||
|
"count": 18,
|
||||||
|
"min": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
"accessor_10": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 1536,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
"accessor_11": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 1824,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
"accessor_12": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 2112,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
"accessor_13": {
|
||||||
|
"bufferView": "bufferView_index",
|
||||||
|
"byteOffset": 144,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5123,
|
||||||
|
"count": 18,
|
||||||
|
"min": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
"accessor_14": {
|
||||||
|
"bufferView": "bufferView_index",
|
||||||
|
"byteOffset": 180,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5123,
|
||||||
|
"count": 18,
|
||||||
|
"min": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"asset": {
|
||||||
|
"generator": "obj2gltf",
|
||||||
|
"profile": {
|
||||||
|
"api": "WebGL",
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"buffers": {
|
||||||
|
"buffer": {
|
||||||
|
"byteLength": 2520,
|
||||||
|
"uri": "data:application/octet-stream;base64,AACAvwAAgL8AAIDAAACAvwAAgD8AAIDAAACAvwAAgD8AAMDAAACAvwAAgL8AAMDAAACAvwAAgL8AAMDAAACAvwAAgD8AAMDAAACAPwAAgD8AAMDAAACAPwAAgL8AAMDAAACAPwAAgL8AAMDAAACAPwAAgD8AAMDAAACAPwAAgD8AAIDAAACAPwAAgL8AAIDAAACAPwAAgL8AAIDAAACAPwAAgD8AAIDAAACAvwAAgD8AAIDAAACAvwAAgL8AAIDAAACAvwAAgL8AAMDAAACAPwAAgL8AAMDAAACAPwAAgL8AAIDAAACAvwAAgL8AAIDAAACAPwAAgD8AAMDAAACAvwAAgD8AAMDAAACAvwAAgD8AAIDAAACAPwAAgD8AAIDAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAQAAAgL8AAIA/AACAQAAAgD8AAIA/AACAQAAAgD8AAIC/AACAQAAAgL8AAIC/AACAQAAAgL8AAIC/AACAQAAAgD8AAIC/AADAQAAAgD8AAIC/AADAQAAAgL8AAIC/AADAQAAAgL8AAIC/AADAQAAAgD8AAIC/AADAQAAAgD8AAIA/AADAQAAAgL8AAIA/AADAQAAAgL8AAIA/AADAQAAAgD8AAIA/AACAQAAAgD8AAIA/AACAQAAAgL8AAIA/AACAQAAAgL8AAIC/AADAQAAAgL8AAIC/AADAQAAAgL8AAIA/AACAQAAAgL8AAIA/AADAQAAAgD8AAIC/AACAQAAAgD8AAIC/AACAQAAAgD8AAIA/AADAQAAAgD8AAIA/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAPwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIA/AACAPwAAgD8AAIA/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAABAAIAAAACAAMABAAFAAYABAAGAAcACAAJAAoACAAKAAsADAANAA4ADAAOAA8AEAARABIAEAASABMAFAAVABYAFAAWABcAAAABAAIAAAACAAMABAAFAAYABAAGAAcACAAJAAoACAAKAAsADAANAA4ADAAOAA8AEAARABIAEAASABMAFAAVABYAFAAWABcAAAABAAIAAAACAAMABAAFAAYABAAGAAcACAAJAAoACAAKAAsADAANAA4ADAAOAA8AEAARABIAEAASABMAFAAVABYAFAAWABcA"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bufferViews": {
|
||||||
|
"bufferView_vertex": {
|
||||||
|
"buffer": "buffer",
|
||||||
|
"byteLength": 2304,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"target": 34962
|
||||||
|
},
|
||||||
|
"bufferView_index": {
|
||||||
|
"buffer": "buffer",
|
||||||
|
"byteLength": 216,
|
||||||
|
"byteOffset": 2304,
|
||||||
|
"target": 34963
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensionsUsed": [
|
||||||
|
"KHR_materials_common"
|
||||||
|
],
|
||||||
|
"images": {},
|
||||||
|
"materials": {
|
||||||
|
"Blue": {
|
||||||
|
"extensions": {
|
||||||
|
"KHR_materials_common": {
|
||||||
|
"technique": "PHONG",
|
||||||
|
"transparent": false,
|
||||||
|
"doubleSided": false,
|
||||||
|
"values": {
|
||||||
|
"ambient": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"diffuse": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0.64,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"emission": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"specular": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"shininess": 96.078431,
|
||||||
|
"transparency": 1,
|
||||||
|
"transparent": false,
|
||||||
|
"doubleSided": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Green": {
|
||||||
|
"extensions": {
|
||||||
|
"KHR_materials_common": {
|
||||||
|
"technique": "PHONG",
|
||||||
|
"transparent": false,
|
||||||
|
"doubleSided": false,
|
||||||
|
"values": {
|
||||||
|
"ambient": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"diffuse": [
|
||||||
|
0,
|
||||||
|
0.64,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"emission": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"specular": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"shininess": 96.078431,
|
||||||
|
"transparency": 1,
|
||||||
|
"transparent": false,
|
||||||
|
"doubleSided": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Red": {
|
||||||
|
"extensions": {
|
||||||
|
"KHR_materials_common": {
|
||||||
|
"technique": "PHONG",
|
||||||
|
"transparent": false,
|
||||||
|
"doubleSided": false,
|
||||||
|
"values": {
|
||||||
|
"ambient": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"diffuse": [
|
||||||
|
0.64,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"emission": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"specular": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"shininess": 96.078431,
|
||||||
|
"transparency": 1,
|
||||||
|
"transparent": false,
|
||||||
|
"doubleSided": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"meshes": {
|
||||||
|
"CubeBlue_CubeBlue_Blue": {
|
||||||
|
"name": "CubeBlue_CubeBlue_Blue",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"POSITION": "accessor_0",
|
||||||
|
"NORMAL": "accessor_1",
|
||||||
|
"TEXCOORD_0": "accessor_2"
|
||||||
|
},
|
||||||
|
"indices": "accessor_3",
|
||||||
|
"material": "Blue",
|
||||||
|
"mode": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"POSITION": "accessor_0",
|
||||||
|
"NORMAL": "accessor_1",
|
||||||
|
"TEXCOORD_0": "accessor_2"
|
||||||
|
},
|
||||||
|
"indices": "accessor_4",
|
||||||
|
"material": "Green",
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"CubeGreen_CubeGreen_Green": {
|
||||||
|
"name": "CubeGreen_CubeGreen_Green",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"POSITION": "accessor_5",
|
||||||
|
"NORMAL": "accessor_6",
|
||||||
|
"TEXCOORD_0": "accessor_7"
|
||||||
|
},
|
||||||
|
"indices": "accessor_8",
|
||||||
|
"material": "Green",
|
||||||
|
"mode": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"POSITION": "accessor_5",
|
||||||
|
"NORMAL": "accessor_6",
|
||||||
|
"TEXCOORD_0": "accessor_7"
|
||||||
|
},
|
||||||
|
"indices": "accessor_9",
|
||||||
|
"material": "Red",
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"CubeRed_CubeRed_Red": {
|
||||||
|
"name": "CubeRed_CubeRed_Red",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"POSITION": "accessor_10",
|
||||||
|
"NORMAL": "accessor_11",
|
||||||
|
"TEXCOORD_0": "accessor_12"
|
||||||
|
},
|
||||||
|
"indices": "accessor_13",
|
||||||
|
"material": "Red",
|
||||||
|
"mode": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"POSITION": "accessor_10",
|
||||||
|
"NORMAL": "accessor_11",
|
||||||
|
"TEXCOORD_0": "accessor_12"
|
||||||
|
},
|
||||||
|
"indices": "accessor_14",
|
||||||
|
"material": "Blue",
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nodes": {
|
||||||
|
"Cube": {
|
||||||
|
"name": "Cube",
|
||||||
|
"meshes": [
|
||||||
|
"CubeBlue_CubeBlue_Blue",
|
||||||
|
"CubeGreen_CubeGreen_Green",
|
||||||
|
"CubeRed_CubeRed_Red"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"samplers": {},
|
||||||
|
"scene": "scene",
|
||||||
|
"scenes": {
|
||||||
|
"scene": {
|
||||||
|
"nodes": [
|
||||||
|
"Cube"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"textures": {}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Blender MTL File: 'box-objects.blend'
|
||||||
|
# Material Count: 3
|
||||||
|
|
||||||
|
newmtl Blue
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.000000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Green
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.640000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Red
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.000000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,133 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box-objects.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-objects-groups-materials.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 -4.000000
|
||||||
|
v -1.000000 1.000000 -4.000000
|
||||||
|
v -1.000000 -1.000000 -6.000000
|
||||||
|
v -1.000000 1.000000 -6.000000
|
||||||
|
v 1.000000 -1.000000 -4.000000
|
||||||
|
v 1.000000 1.000000 -4.000000
|
||||||
|
v 1.000000 -1.000000 -6.000000
|
||||||
|
v 1.000000 1.000000 -6.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
g CubeBlue_CubeBlue_Blue
|
||||||
|
usemtl Blue
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
usemtl Green
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
||||||
|
v 4.000000 -1.000000 1.000000
|
||||||
|
v 4.000000 1.000000 1.000000
|
||||||
|
v 4.000000 -1.000000 -1.000000
|
||||||
|
v 4.000000 1.000000 -1.000000
|
||||||
|
v 6.000000 -1.000000 1.000000
|
||||||
|
v 6.000000 1.000000 1.000000
|
||||||
|
v 6.000000 -1.000000 -1.000000
|
||||||
|
v 6.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
g CubeGreen_CubeGreen_Green
|
||||||
|
usemtl Green
|
||||||
|
f 9/21/7 10/22/7 12/23/7 11/24/7
|
||||||
|
f 11/25/8 12/26/8 16/27/8 15/28/8
|
||||||
|
f 15/29/9 16/30/9 14/31/9 13/32/9
|
||||||
|
usemtl Red
|
||||||
|
f 13/33/10 14/34/10 10/35/10 9/36/10
|
||||||
|
f 11/25/11 15/37/11 13/38/11 9/36/11
|
||||||
|
f 16/39/12 12/26/12 10/35/12 14/40/12
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
g CubeRed_CubeRed_Red
|
||||||
|
usemtl Red
|
||||||
|
f 17/41/13 18/42/13 20/43/13 19/44/13
|
||||||
|
f 19/45/14 20/46/14 24/47/14 23/48/14
|
||||||
|
f 23/49/15 24/50/15 22/51/15 21/52/15
|
||||||
|
usemtl Blue
|
||||||
|
f 21/53/16 22/54/16 18/55/16 17/56/16
|
||||||
|
f 19/45/17 23/57/17 21/58/17 17/56/17
|
||||||
|
f 24/59/18 20/46/18 18/55/18 22/60/18
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Blender MTL File: 'box-objects.blend'
|
||||||
|
# Material Count: 3
|
||||||
|
|
||||||
|
newmtl Blue
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.000000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Green
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.640000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Red
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.000000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,135 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box-objects.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-objects-groups.mtl
|
||||||
|
o CubeBlue
|
||||||
|
v -1.000000 -1.000000 -4.000000
|
||||||
|
v -1.000000 1.000000 -4.000000
|
||||||
|
v -1.000000 -1.000000 -6.000000
|
||||||
|
v -1.000000 1.000000 -6.000000
|
||||||
|
v 1.000000 -1.000000 -4.000000
|
||||||
|
v 1.000000 1.000000 -4.000000
|
||||||
|
v 1.000000 -1.000000 -6.000000
|
||||||
|
v 1.000000 1.000000 -6.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
g CubeBlue_CubeBlue_Blue
|
||||||
|
usemtl Blue
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
||||||
|
o CubeGreen
|
||||||
|
v 4.000000 -1.000000 1.000000
|
||||||
|
v 4.000000 1.000000 1.000000
|
||||||
|
v 4.000000 -1.000000 -1.000000
|
||||||
|
v 4.000000 1.000000 -1.000000
|
||||||
|
v 6.000000 -1.000000 1.000000
|
||||||
|
v 6.000000 1.000000 1.000000
|
||||||
|
v 6.000000 -1.000000 -1.000000
|
||||||
|
v 6.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
g CubeGreen_CubeGreen_Green
|
||||||
|
usemtl Green
|
||||||
|
s off
|
||||||
|
f 9/21/7 10/22/7 12/23/7 11/24/7
|
||||||
|
f 11/25/8 12/26/8 16/27/8 15/28/8
|
||||||
|
f 15/29/9 16/30/9 14/31/9 13/32/9
|
||||||
|
f 13/33/10 14/34/10 10/35/10 9/36/10
|
||||||
|
f 11/25/11 15/37/11 13/38/11 9/36/11
|
||||||
|
f 16/39/12 12/26/12 10/35/12 14/40/12
|
||||||
|
o CubeRed
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
g CubeRed_CubeRed_Red
|
||||||
|
usemtl Red
|
||||||
|
s off
|
||||||
|
f 17/41/13 18/42/13 20/43/13 19/44/13
|
||||||
|
f 19/45/14 20/46/14 24/47/14 23/48/14
|
||||||
|
f 23/49/15 24/50/15 22/51/15 21/52/15
|
||||||
|
f 21/53/16 22/54/16 18/55/16 17/56/16
|
||||||
|
f 19/45/17 23/57/17 21/58/17 17/56/17
|
||||||
|
f 24/59/18 20/46/18 18/55/18 22/60/18
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Blender MTL File: 'box-objects.blend'
|
||||||
|
# Material Count: 3
|
||||||
|
|
||||||
|
newmtl Blue
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.000000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Green
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.640000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Red
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.000000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,132 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box-objects.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-objects.mtl
|
||||||
|
o CubeBlue
|
||||||
|
v -1.000000 -1.000000 -4.000000
|
||||||
|
v -1.000000 1.000000 -4.000000
|
||||||
|
v -1.000000 -1.000000 -6.000000
|
||||||
|
v -1.000000 1.000000 -6.000000
|
||||||
|
v 1.000000 -1.000000 -4.000000
|
||||||
|
v 1.000000 1.000000 -4.000000
|
||||||
|
v 1.000000 -1.000000 -6.000000
|
||||||
|
v 1.000000 1.000000 -6.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Blue
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
||||||
|
o CubeGreen
|
||||||
|
v 4.000000 -1.000000 1.000000
|
||||||
|
v 4.000000 1.000000 1.000000
|
||||||
|
v 4.000000 -1.000000 -1.000000
|
||||||
|
v 4.000000 1.000000 -1.000000
|
||||||
|
v 6.000000 -1.000000 1.000000
|
||||||
|
v 6.000000 1.000000 1.000000
|
||||||
|
v 6.000000 -1.000000 -1.000000
|
||||||
|
v 6.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Green
|
||||||
|
s off
|
||||||
|
f 9/21/7 10/22/7 12/23/7 11/24/7
|
||||||
|
f 11/25/8 12/26/8 16/27/8 15/28/8
|
||||||
|
f 15/29/9 16/30/9 14/31/9 13/32/9
|
||||||
|
f 13/33/10 14/34/10 10/35/10 9/36/10
|
||||||
|
f 11/25/11 15/37/11 13/38/11 9/36/11
|
||||||
|
f 16/39/12 12/26/12 10/35/12 14/40/12
|
||||||
|
o CubeRed
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Red
|
||||||
|
s off
|
||||||
|
f 17/41/13 18/42/13 20/43/13 19/44/13
|
||||||
|
f 19/45/14 20/46/14 24/47/14 23/48/14
|
||||||
|
f 23/49/15 24/50/15 22/51/15 21/52/15
|
||||||
|
f 21/53/16 22/54/16 18/55/16 17/56/16
|
||||||
|
f 19/45/17 23/57/17 21/58/17 17/56/17
|
||||||
|
f 24/59/18 20/46/18 18/55/18 22/60/18
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'box.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-positions-only.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1 2 4 3
|
||||||
|
f 3 4 8 7
|
||||||
|
f 7 8 6 5
|
||||||
|
f 5 6 2 1
|
||||||
|
f 3 7 5 1
|
||||||
|
f 8 4 2 6
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib materials/box-textured.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Blender MTL File: 'box.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd images/cesium.png
|
After Width: | Height: | Size: 7.5 KiB |
|
@ -0,0 +1,13 @@
|
||||||
|
# Blender MTL File: 'box.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd cesium.png
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-textured.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
After Width: | Height: | Size: 7.5 KiB |
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'box.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-triangles.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'None'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: ''
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-uncleaned.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
g Cube
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
o Cube
|
||||||
|
g Cube
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
||||||
|
g Cube
|
||||||
|
usemtl Material
|
||||||
|
o Cube
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Blender MTL File: 'box-objects.blend'
|
||||||
|
# Material Count: 3
|
||||||
|
|
||||||
|
newmtl Blue
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.000000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Green
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.000000 0.640000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Red
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.000000 0.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,129 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box-objects.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-usemtl.mtl
|
||||||
|
v -1.000000 -1.000000 -4.000000
|
||||||
|
v -1.000000 1.000000 -4.000000
|
||||||
|
v -1.000000 -1.000000 -6.000000
|
||||||
|
v -1.000000 1.000000 -6.000000
|
||||||
|
v 1.000000 -1.000000 -4.000000
|
||||||
|
v 1.000000 1.000000 -4.000000
|
||||||
|
v 1.000000 -1.000000 -6.000000
|
||||||
|
v 1.000000 1.000000 -6.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Blue
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
||||||
|
v 4.000000 -1.000000 1.000000
|
||||||
|
v 4.000000 1.000000 1.000000
|
||||||
|
v 4.000000 -1.000000 -1.000000
|
||||||
|
v 4.000000 1.000000 -1.000000
|
||||||
|
v 6.000000 -1.000000 1.000000
|
||||||
|
v 6.000000 1.000000 1.000000
|
||||||
|
v 6.000000 -1.000000 -1.000000
|
||||||
|
v 6.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Green
|
||||||
|
s off
|
||||||
|
f 9/21/7 10/22/7 12/23/7 11/24/7
|
||||||
|
f 11/25/8 12/26/8 16/27/8 15/28/8
|
||||||
|
f 15/29/9 16/30/9 14/31/9 13/32/9
|
||||||
|
f 13/33/10 14/34/10 10/35/10 9/36/10
|
||||||
|
f 11/25/11 15/37/11 13/38/11 9/36/11
|
||||||
|
f 16/39/12 12/26/12 10/35/12 14/40/12
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Red
|
||||||
|
s off
|
||||||
|
f 17/41/13 18/42/13 20/43/13 19/44/13
|
||||||
|
f 19/45/14 20/46/14 24/47/14 23/48/14
|
||||||
|
f 23/49/15 24/50/15 22/51/15 21/52/15
|
||||||
|
f 21/53/16 22/54/16 18/55/16 17/56/16
|
||||||
|
f 19/45/17 23/57/17 21/58/17 17/56/17
|
||||||
|
f 24/59/18 20/46/18 18/55/18 22/60/18
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'box.blend'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,40 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: 'box.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box-uvs.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1/1 2/2 4/3 3/4
|
||||||
|
f 3/5 4/6 8/7 7/8
|
||||||
|
f 7/9 8/10 6/11 5/12
|
||||||
|
f 5/13 6/14 2/15 1/16
|
||||||
|
f 3/5 7/17 5/18 1/16
|
||||||
|
f 8/19 4/6 2/15 6/20
|
|
@ -0,0 +1,178 @@
|
||||||
|
{
|
||||||
|
"accessors": {
|
||||||
|
"accessor_0": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
"accessor_1": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 288,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
"accessor_2": {
|
||||||
|
"bufferView": "bufferView_vertex",
|
||||||
|
"byteOffset": 576,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"min": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
"accessor_3": {
|
||||||
|
"bufferView": "bufferView_index",
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteStride": 0,
|
||||||
|
"componentType": 5123,
|
||||||
|
"count": 36,
|
||||||
|
"min": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"max": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"asset": {
|
||||||
|
"generator": "obj2gltf",
|
||||||
|
"profile": {
|
||||||
|
"api": "WebGL",
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"buffers": {
|
||||||
|
"buffer": {
|
||||||
|
"byteLength": 840,
|
||||||
|
"uri": "data:application/octet-stream;base64,AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAPwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIA/AACAPwAAgD8AAIA/AACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAABAAIAAAACAAMABAAFAAYABAAGAAcACAAJAAoACAAKAAsADAANAA4ADAAOAA8AEAARABIAEAASABMAFAAVABYAFAAWABcA"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bufferViews": {
|
||||||
|
"bufferView_vertex": {
|
||||||
|
"buffer": "buffer",
|
||||||
|
"byteLength": 768,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"target": 34962
|
||||||
|
},
|
||||||
|
"bufferView_index": {
|
||||||
|
"buffer": "buffer",
|
||||||
|
"byteLength": 72,
|
||||||
|
"byteOffset": 768,
|
||||||
|
"target": 34963
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensionsUsed": [
|
||||||
|
"KHR_materials_common"
|
||||||
|
],
|
||||||
|
"images": {},
|
||||||
|
"materials": {
|
||||||
|
"Material": {
|
||||||
|
"extensions": {
|
||||||
|
"KHR_materials_common": {
|
||||||
|
"technique": "PHONG",
|
||||||
|
"transparent": false,
|
||||||
|
"doubleSided": false,
|
||||||
|
"values": {
|
||||||
|
"ambient": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"diffuse": [
|
||||||
|
0.64,
|
||||||
|
0.64,
|
||||||
|
0.64,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"emission": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"specular": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"shininess": 96.078431,
|
||||||
|
"transparency": 1,
|
||||||
|
"transparent": false,
|
||||||
|
"doubleSided": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"meshes": {
|
||||||
|
"Cube-Mesh": {
|
||||||
|
"name": "Cube-Mesh",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"POSITION": "accessor_0",
|
||||||
|
"NORMAL": "accessor_1",
|
||||||
|
"TEXCOORD_0": "accessor_2"
|
||||||
|
},
|
||||||
|
"indices": "accessor_3",
|
||||||
|
"material": "Material",
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nodes": {
|
||||||
|
"Cube": {
|
||||||
|
"name": "Cube",
|
||||||
|
"meshes": [
|
||||||
|
"Cube-Mesh"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"samplers": {},
|
||||||
|
"scene": "scene",
|
||||||
|
"scenes": {
|
||||||
|
"scene": {
|
||||||
|
"nodes": [
|
||||||
|
"Cube"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"textures": {}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Blender MTL File: 'None'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Blender v2.78 (sub 0) OBJ File: ''
|
||||||
|
# www.blender.org
|
||||||
|
mtllib box.mtl
|
||||||
|
o Cube
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vt 1.0000 0.0000
|
||||||
|
vt 1.0000 1.0000
|
||||||
|
vt 0.0000 0.0000
|
||||||
|
vt 0.0000 1.0000
|
||||||
|
vn -1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn 0.0000 0.0000 1.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl Material
|
||||||
|
s off
|
||||||
|
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||||
|
f 3/5/2 4/6/2 8/7/2 7/8/2
|
||||||
|
f 7/9/3 8/10/3 6/11/3 5/12/3
|
||||||
|
f 5/13/4 6/14/4 2/15/4 1/16/4
|
||||||
|
f 3/5/5 7/17/5 5/18/5 1/16/5
|
||||||
|
f 8/19/6 4/6/6 2/15/6 6/20/6
|
|
@ -1,23 +1,137 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
var Promise = require('bluebird');
|
|
||||||
|
|
||||||
var GltfPipeline = require('gltf-pipeline').Pipeline;
|
var GltfPipeline = require('gltf-pipeline').Pipeline;
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var convert = require('../../lib/convert');
|
var convert = require('../../lib/convert');
|
||||||
|
var writeUris = require('../../lib/writeUris');
|
||||||
|
|
||||||
var objFile = './specs/data/BoxTextured/BoxTextured.obj';
|
var objPath = 'specs/data/box-textured/box-textured.obj';
|
||||||
var gltfFile = './specs/data/BoxTextured/BoxTextured.gltf';
|
var gltfPath = 'specs/data/box-textured/box-textured.gltf';
|
||||||
|
var glbPath = 'specs/data/box-textured/box-textured.glb';
|
||||||
|
var objPathNonExistent = 'specs/data/non-existent.obj';
|
||||||
|
var objExternalResourcesPath = 'specs/data/box-external-resources/box-external-resources.obj';
|
||||||
|
|
||||||
describe('convert', function() {
|
describe('convert', function() {
|
||||||
it('converts an obj to gltf', function(done) {
|
it('converts an obj to gltf', function(done) {
|
||||||
var spy = spyOn(GltfPipeline, 'processJSONToDisk').and.callFake(function(gltf, outputPath, options, callback) {
|
var spy = spyOn(GltfPipeline, 'processJSONToDisk');
|
||||||
return;
|
expect(convert(objPath, gltfPath)
|
||||||
});
|
|
||||||
expect(convert(objFile, gltfFile, {})
|
|
||||||
.then(function() {
|
.then(function() {
|
||||||
var args = spy.calls.first().args;
|
var args = spy.calls.first().args;
|
||||||
expect(args[0]).toBeDefined();
|
var gltf = args[0];
|
||||||
expect(path.normalize(args[1])).toEqual(path.normalize(gltfFile));
|
var outputPath = args[1];
|
||||||
|
expect(path.normalize(outputPath)).toEqual(path.normalize(gltfPath));
|
||||||
|
expect(gltf).toBeDefined();
|
||||||
|
expect(gltf.images.cesium).toBeDefined();
|
||||||
}), done).toResolve();
|
}), done).toResolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses default gltf-pipeline options', function(done) {
|
||||||
|
var spy = spyOn(GltfPipeline, 'processJSONToDisk');
|
||||||
|
expect(convert(objPath, gltfPath)
|
||||||
|
.then(function() {
|
||||||
|
var args = spy.calls.first().args;
|
||||||
|
var options = args[2];
|
||||||
|
expect(options).toEqual({
|
||||||
|
createDirectory : false,
|
||||||
|
basePath : path.dirname(objPath),
|
||||||
|
binary : false,
|
||||||
|
embed : true,
|
||||||
|
embedImage : true,
|
||||||
|
encodeNormals : false,
|
||||||
|
quantize : false,
|
||||||
|
compressTextureCoordinates : false,
|
||||||
|
aoOptions : undefined,
|
||||||
|
kmcOptions : undefined,
|
||||||
|
smoothNormals : false,
|
||||||
|
optimizeForCesium : false,
|
||||||
|
textureCompressionOptions : undefined,
|
||||||
|
preserve : true
|
||||||
|
});
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets options', function(done) {
|
||||||
|
var spy = spyOn(GltfPipeline, 'processJSONToDisk');
|
||||||
|
spyOn(writeUris, '_outputFile');
|
||||||
|
var textureCompressionOptions = {
|
||||||
|
format : 'dxt1',
|
||||||
|
quality : 10
|
||||||
|
};
|
||||||
|
var options = {
|
||||||
|
binary : true,
|
||||||
|
separate : true,
|
||||||
|
separateTextures : true,
|
||||||
|
compress : true,
|
||||||
|
optimize : true,
|
||||||
|
optimizeForCesium : true,
|
||||||
|
generateNormals : true,
|
||||||
|
ao : true,
|
||||||
|
kmc : true,
|
||||||
|
textureCompressionOptions : textureCompressionOptions,
|
||||||
|
checkTransparency : true,
|
||||||
|
secure : true,
|
||||||
|
logger : convert.defaults.logger
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(convert(objPath, gltfPath, options)
|
||||||
|
.then(function() {
|
||||||
|
var args = spy.calls.first().args;
|
||||||
|
var options = args[2];
|
||||||
|
expect(options).toEqual({
|
||||||
|
createDirectory : false,
|
||||||
|
basePath : path.dirname(objPath),
|
||||||
|
binary : true,
|
||||||
|
embed : false,
|
||||||
|
embedImage : false,
|
||||||
|
encodeNormals : true,
|
||||||
|
quantize : true,
|
||||||
|
compressTextureCoordinates : true,
|
||||||
|
aoOptions : {},
|
||||||
|
kmcOptions : {},
|
||||||
|
smoothNormals : true,
|
||||||
|
optimizeForCesium : true,
|
||||||
|
textureCompressionOptions : textureCompressionOptions,
|
||||||
|
preserve : false
|
||||||
|
});
|
||||||
|
expect(writeUris._outputFile.calls.count()).toBe(2); // Saves out .png and .bin
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saves as binary if gltfPath has a .glb extension', function(done) {
|
||||||
|
var spy = spyOn(GltfPipeline, 'processJSONToDisk');
|
||||||
|
expect(convert(objPath, glbPath)
|
||||||
|
.then(function() {
|
||||||
|
var args = spy.calls.first().args;
|
||||||
|
var options = args[2];
|
||||||
|
expect(options.binary).toBe(true);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('bypassPipeline flag bypasses gltf-pipeline', function(done) {
|
||||||
|
spyOn(convert, '_outputJson');
|
||||||
|
spyOn(GltfPipeline, 'processJSONToDisk');
|
||||||
|
var options = {
|
||||||
|
bypassPipeline : true
|
||||||
|
};
|
||||||
|
expect(convert(objPath, gltfPath, options)
|
||||||
|
.then(function() {
|
||||||
|
expect(convert._outputJson).toHaveBeenCalled();
|
||||||
|
expect(GltfPipeline.processJSONToDisk).not.toHaveBeenCalled();
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects if obj path does not exist', function(done) {
|
||||||
|
expect(convert(objPathNonExistent, gltfPath), done).toRejectWith(Error);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws if objPath is undefined', function() {
|
||||||
|
expect(function() {
|
||||||
|
convert(undefined, gltfPath);
|
||||||
|
}).toThrowDeveloperError();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects if gltfPath is undefined', function() {
|
||||||
|
expect(function() {
|
||||||
|
convert(objPath, undefined);
|
||||||
|
}).toThrowDeveloperError();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,362 @@
|
||||||
|
'use strict';
|
||||||
|
var Cesium = require('cesium');
|
||||||
|
var fsExtra = require('fs-extra');
|
||||||
|
var path = require('path');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
var convert = require('../../lib/convert');
|
||||||
|
var createGltf = require('../../lib/gltf');
|
||||||
|
var loadImage = require('../../lib/image');
|
||||||
|
var loadObj = require('../../lib/obj');
|
||||||
|
var Material = require('../../lib/Material');
|
||||||
|
var writeUris = require('../../lib/writeUris');
|
||||||
|
|
||||||
|
var clone = Cesium.clone;
|
||||||
|
var WebGLConstants = Cesium.WebGLConstants;
|
||||||
|
|
||||||
|
var fsExtraReadJson = Promise.promisify(fsExtra.readJson);
|
||||||
|
|
||||||
|
var boxObjUrl = 'specs/data/box/box.obj';
|
||||||
|
var groupObjUrl = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.obj';
|
||||||
|
var boxGltfUrl = 'specs/data/box/box.gltf';
|
||||||
|
var groupGltfUrl = 'specs/data/box-objects-groups-materials/box-objects-groups-materials.gltf';
|
||||||
|
var diffuseTextureUrl = 'specs/data/box-textured/cesium.png';
|
||||||
|
var transparentDiffuseTextureUrl = 'specs/data/box-complex-material/diffuse.png';
|
||||||
|
|
||||||
|
var defaultOptions = convert.defaults;
|
||||||
|
var checkTransparencyOptions = clone(defaultOptions);
|
||||||
|
checkTransparencyOptions.checkTransparency = true;
|
||||||
|
|
||||||
|
describe('gltf', function() {
|
||||||
|
var boxObjData;
|
||||||
|
var duplicateBoxObjData;
|
||||||
|
var groupObjData;
|
||||||
|
var boxGltf;
|
||||||
|
var groupGltf;
|
||||||
|
var diffuseTexture;
|
||||||
|
var transparentDiffuseTexture;
|
||||||
|
|
||||||
|
beforeEach(function(done) {
|
||||||
|
return Promise.all([
|
||||||
|
loadObj(boxObjUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
boxObjData = data;
|
||||||
|
}),
|
||||||
|
loadObj(boxObjUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
duplicateBoxObjData = data;
|
||||||
|
}),
|
||||||
|
loadObj(groupObjUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
groupObjData = data;
|
||||||
|
}),
|
||||||
|
fsExtraReadJson(boxGltfUrl)
|
||||||
|
.then(function(gltf) {
|
||||||
|
boxGltf = gltf;
|
||||||
|
}),
|
||||||
|
fsExtraReadJson(groupGltfUrl)
|
||||||
|
.then(function(gltf) {
|
||||||
|
groupGltf = gltf;
|
||||||
|
}),
|
||||||
|
loadImage(diffuseTextureUrl, defaultOptions)
|
||||||
|
.then(function(image) {
|
||||||
|
diffuseTexture = image;
|
||||||
|
}),
|
||||||
|
loadImage(transparentDiffuseTextureUrl, checkTransparencyOptions)
|
||||||
|
.then(function(image) {
|
||||||
|
transparentDiffuseTexture = image;
|
||||||
|
})
|
||||||
|
]).then(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('simple gltf', function(done) {
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
expect(writeUris(gltf, boxGltfUrl, defaultOptions)
|
||||||
|
.then(function() {
|
||||||
|
expect(gltf).toEqual(boxGltf);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('multiple nodes, meshes, and primitives', function(done) {
|
||||||
|
var gltf = createGltf(groupObjData);
|
||||||
|
|
||||||
|
expect(writeUris(gltf, groupGltfUrl, defaultOptions)
|
||||||
|
.then(function() {
|
||||||
|
expect(gltf).toEqual(groupGltf);
|
||||||
|
expect(Object.keys(gltf.materials).length).toBe(3);
|
||||||
|
expect(Object.keys(gltf.nodes).length).toBe(1);
|
||||||
|
expect(Object.keys(gltf.meshes).length).toBe(3);
|
||||||
|
|
||||||
|
// Check for two primitives in each mesh
|
||||||
|
for (var id in gltf.meshes) {
|
||||||
|
if (gltf.meshes.hasOwnProperty(id)) {
|
||||||
|
var mesh = gltf.meshes[id];
|
||||||
|
expect(mesh.primitives.length).toBe(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets default material values', function() {
|
||||||
|
boxObjData.materials.Material = new Material();
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var material = gltf.materials.Material;
|
||||||
|
var kmc = material.extensions.KHR_materials_common;
|
||||||
|
var values = kmc.values;
|
||||||
|
|
||||||
|
expect(kmc.technique).toBe('LAMBERT');
|
||||||
|
expect(values.ambient).toEqual([0.0, 0.0, 0.0, 1]);
|
||||||
|
expect(values.diffuse).toEqual([0.5, 0.5, 0.5, 1]);
|
||||||
|
expect(values.emission).toEqual([0.0, 0.0, 0.0, 1]);
|
||||||
|
expect(values.specular).toEqual([0.0, 0.0, 0.0, 1]);
|
||||||
|
expect(values.shininess).toEqual(0.0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets material for diffuse texture', function() {
|
||||||
|
var material = new Material();
|
||||||
|
material.diffuseTexture = diffuseTextureUrl;
|
||||||
|
boxObjData.materials.Material = material;
|
||||||
|
boxObjData.images[diffuseTextureUrl] = diffuseTexture;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
var texture = gltf.textures.texture_cesium;
|
||||||
|
var image = gltf.images.cesium;
|
||||||
|
|
||||||
|
expect(kmc.technique).toBe('LAMBERT');
|
||||||
|
expect(kmc.values.diffuse).toEqual('texture_cesium');
|
||||||
|
expect(kmc.values.transparency).toBe(1.0);
|
||||||
|
expect(kmc.values.transparent).toBe(false);
|
||||||
|
expect(kmc.values.doubleSided).toBe(false);
|
||||||
|
|
||||||
|
expect(texture).toEqual({
|
||||||
|
format : WebGLConstants.RGB,
|
||||||
|
internalFormat : WebGLConstants.RGB,
|
||||||
|
sampler : 'sampler',
|
||||||
|
source : 'cesium',
|
||||||
|
target : WebGLConstants.TEXTURE_2D,
|
||||||
|
type : WebGLConstants.UNSIGNED_BYTE
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(image).toBeDefined();
|
||||||
|
expect(image.name).toBe('cesium');
|
||||||
|
expect(image.extras._obj2gltf.source).toBeDefined();
|
||||||
|
expect(image.extras._obj2gltf.extension).toBe('.png');
|
||||||
|
|
||||||
|
expect(gltf.samplers.sampler).toEqual({
|
||||||
|
magFilter : WebGLConstants.LINEAR,
|
||||||
|
minFilter : WebGLConstants.LINEAR,
|
||||||
|
wrapS : WebGLConstants.REPEAT,
|
||||||
|
wrapT : WebGLConstants.REPEAT
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets material for alpha less than 1', function() {
|
||||||
|
var material = new Material();
|
||||||
|
material.alpha = 0.4;
|
||||||
|
boxObjData.materials.Material = material;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
|
||||||
|
expect(kmc.values.diffuse).toEqual([0.5, 0.5, 0.5, 0.4]);
|
||||||
|
expect(kmc.values.transparency).toBe(1.0);
|
||||||
|
expect(kmc.values.transparent).toBe(true);
|
||||||
|
expect(kmc.values.doubleSided).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets material for diffuse texture and alpha less than 1', function() {
|
||||||
|
var material = new Material();
|
||||||
|
material.diffuseTexture = diffuseTextureUrl;
|
||||||
|
material.alpha = 0.4;
|
||||||
|
boxObjData.materials.Material = material;
|
||||||
|
|
||||||
|
boxObjData.images[diffuseTextureUrl] = diffuseTexture;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
|
||||||
|
expect(kmc.values.diffuse).toEqual('texture_cesium');
|
||||||
|
expect(kmc.values.transparency).toBe(0.4);
|
||||||
|
expect(kmc.values.transparent).toBe(true);
|
||||||
|
expect(kmc.values.doubleSided).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets material for transparent diffuse texture', function() {
|
||||||
|
var material = new Material();
|
||||||
|
material.diffuseTexture = transparentDiffuseTextureUrl;
|
||||||
|
boxObjData.materials.Material = material;
|
||||||
|
|
||||||
|
boxObjData.images[transparentDiffuseTextureUrl] = transparentDiffuseTexture;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
|
||||||
|
expect(kmc.values.diffuse).toBe('texture_diffuse');
|
||||||
|
expect(kmc.values.transparency).toBe(1.0);
|
||||||
|
expect(kmc.values.transparent).toBe(true);
|
||||||
|
expect(kmc.values.doubleSided).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets material for specular', function() {
|
||||||
|
var material = new Material();
|
||||||
|
material.specularColor = [0.1, 0.1, 0.2, 1];
|
||||||
|
material.specularShininess = 0.1;
|
||||||
|
boxObjData.materials.Material = material;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
|
||||||
|
expect(kmc.technique).toBe('PHONG');
|
||||||
|
expect(kmc.values.specular).toEqual([0.1, 0.1, 0.2, 1]);
|
||||||
|
expect(kmc.values.shininess).toEqual(0.1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets constant material when there are no normals', function() {
|
||||||
|
boxObjData.nodes[0].meshes[0].normals.length = 0;
|
||||||
|
|
||||||
|
var material = new Material();
|
||||||
|
material.diffuseTexture = diffuseTextureUrl;
|
||||||
|
boxObjData.materials.Material = material;
|
||||||
|
|
||||||
|
boxObjData.images[diffuseTextureUrl] = diffuseTexture;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
|
||||||
|
expect(kmc.technique).toBe('CONSTANT');
|
||||||
|
expect(kmc.values.emission).toEqual('texture_cesium');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets default material when texture is missing', function() {
|
||||||
|
var material = new Material();
|
||||||
|
material.diffuseTexture = diffuseTextureUrl;
|
||||||
|
boxObjData.materials.Material = material;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
|
||||||
|
expect(kmc.values.diffuse).toEqual([0.5, 0.5, 0.5, 1.0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses default material (1)', function() {
|
||||||
|
boxObjData.nodes[0].meshes[0].primitives[0].material = undefined;
|
||||||
|
|
||||||
|
// Creates a material called "default"
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
expect(gltf.materials.default).toBeDefined();
|
||||||
|
var kmc = gltf.materials.default.extensions.KHR_materials_common;
|
||||||
|
expect(kmc.values.diffuse).toEqual([0.5, 0.5, 0.5, 1.0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses default material (2)', function() {
|
||||||
|
boxObjData.materials = {};
|
||||||
|
|
||||||
|
// Uses the original name of the material
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
|
||||||
|
expect(kmc.values.diffuse).toEqual([0.5, 0.5, 0.5, 1.0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles material used with and without normals (1)', function() {
|
||||||
|
// Two meshes - one with normals, and one without
|
||||||
|
boxObjData.nodes.push(duplicateBoxObjData.nodes[0]);
|
||||||
|
boxObjData.nodes[1].meshes[0].normals.length = 0;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc1 = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
var kmc2 = gltf.materials.Material_constant.extensions.KHR_materials_common;
|
||||||
|
|
||||||
|
expect(kmc1.technique).toBe('PHONG');
|
||||||
|
expect(kmc2.technique).toBe('CONSTANT');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles material used with and without normals (2)', function() {
|
||||||
|
// Now test in a different order
|
||||||
|
boxObjData.nodes.push(duplicateBoxObjData.nodes[0]);
|
||||||
|
boxObjData.nodes[0].meshes[0].normals.length = 0;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var kmc1 = gltf.materials.Material.extensions.KHR_materials_common;
|
||||||
|
var kmc2 = gltf.materials.Material_shaded.extensions.KHR_materials_common;
|
||||||
|
|
||||||
|
expect(kmc1.technique).toBe('CONSTANT');
|
||||||
|
expect(kmc2.technique).toBe('PHONG');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs without normals', function() {
|
||||||
|
boxObjData.nodes[0].meshes[0].normals.length = 0;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var attributes = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0].attributes;
|
||||||
|
expect(attributes.POSITION).toBeDefined();
|
||||||
|
expect(attributes.NORMAL).toBeUndefined();
|
||||||
|
expect(attributes.TEXCOORD_0).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs without uvs', function() {
|
||||||
|
boxObjData.nodes[0].meshes[0].uvs.length = 0;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var attributes = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0].attributes;
|
||||||
|
expect(attributes.POSITION).toBeDefined();
|
||||||
|
expect(attributes.NORMAL).toBeDefined();
|
||||||
|
expect(attributes.TEXCOORD_0).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs without uvs and normals', function() {
|
||||||
|
boxObjData.nodes[0].meshes[0].normals.length = 0;
|
||||||
|
boxObjData.nodes[0].meshes[0].uvs.length = 0;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var attributes = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0].attributes;
|
||||||
|
expect(attributes.POSITION).toBeDefined();
|
||||||
|
expect(attributes.NORMAL).toBeUndefined();
|
||||||
|
expect(attributes.TEXCOORD_0).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
function expandObjData(objData, duplicatesLength) {
|
||||||
|
var mesh = objData.nodes[0].meshes[0];
|
||||||
|
var indices = mesh.primitives[0].indices;
|
||||||
|
var positions = mesh.positions;
|
||||||
|
var normals = mesh.normals;
|
||||||
|
var uvs = mesh.uvs;
|
||||||
|
|
||||||
|
var indicesLength = indices.length;
|
||||||
|
var vertexCount = positions.length / 3;
|
||||||
|
|
||||||
|
for (var i = 1; i < duplicatesLength; ++i) {
|
||||||
|
for (var j = 0; j < vertexCount; ++j) {
|
||||||
|
positions.push(0.0);
|
||||||
|
positions.push(0.0);
|
||||||
|
positions.push(0.0);
|
||||||
|
normals.push(0.0);
|
||||||
|
normals.push(0.0);
|
||||||
|
normals.push(0.0);
|
||||||
|
uvs.push(0.0);
|
||||||
|
uvs.push(0.0);
|
||||||
|
}
|
||||||
|
for (var k = 0; k < indicesLength; ++k) {
|
||||||
|
indices.push(indices.get(k) + vertexCount * i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it('detects need to use uint32 indices', function() {
|
||||||
|
expandObjData(boxObjData, 2731); // Right above 65536 limit
|
||||||
|
var mesh = boxObjData.nodes[0].meshes[0];
|
||||||
|
var indicesLength = mesh.primitives[0].indices.length;
|
||||||
|
var vertexCount = mesh.positions.length / 3;
|
||||||
|
|
||||||
|
var gltf = createGltf(boxObjData);
|
||||||
|
var primitive = gltf.meshes[Object.keys(gltf.meshes)[0]].primitives[0];
|
||||||
|
var indicesAccessor = gltf.accessors[primitive.indices];
|
||||||
|
expect(indicesAccessor.count).toBe(indicesLength);
|
||||||
|
expect(indicesAccessor.max[0]).toBe(vertexCount - 1);
|
||||||
|
expect(indicesAccessor.componentType).toBe(WebGLConstants.UNSIGNED_INT);
|
||||||
|
|
||||||
|
var positionAccessor = gltf.accessors[primitive.attributes.POSITION];
|
||||||
|
expect(positionAccessor.count).toBe(vertexCount);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,85 @@
|
||||||
|
'use strict';
|
||||||
|
var Cesium = require('cesium');
|
||||||
|
var convert = require('../../lib/convert');
|
||||||
|
var loadImage = require('../../lib/image');
|
||||||
|
|
||||||
|
var clone = Cesium.clone;
|
||||||
|
var WebGLConstants = Cesium.WebGLConstants;
|
||||||
|
|
||||||
|
var pngImage = 'specs/data/box-complex-material/shininess.png';
|
||||||
|
var jpgImage = 'specs/data/box-complex-material/emission.jpg';
|
||||||
|
var jpegImage = 'specs/data/box-complex-material/specular.jpeg';
|
||||||
|
var gifImage = 'specs/data/box-complex-material/ambient.gif';
|
||||||
|
var grayscaleImage = 'specs/data/box-complex-material/alpha.png';
|
||||||
|
var transparentImage = 'specs/data/box-complex-material/diffuse.png';
|
||||||
|
|
||||||
|
var defaultOptions = convert.defaults;
|
||||||
|
|
||||||
|
describe('image', function() {
|
||||||
|
it('loads png image', function(done) {
|
||||||
|
expect(loadImage(pngImage, defaultOptions)
|
||||||
|
.then(function(info) {
|
||||||
|
expect(info.transparent).toBe(false);
|
||||||
|
expect(info.format).toBe(WebGLConstants.RGB);
|
||||||
|
expect(info.source).toBeDefined();
|
||||||
|
expect(info.extension).toBe('.png');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads jpg image', function(done) {
|
||||||
|
expect(loadImage(jpgImage, defaultOptions)
|
||||||
|
.then(function(info) {
|
||||||
|
expect(info.transparent).toBe(false);
|
||||||
|
expect(info.format).toBe(WebGLConstants.RGB);
|
||||||
|
expect(info.source).toBeDefined();
|
||||||
|
expect(info.extension).toBe('.jpg');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads jpeg image', function(done) {
|
||||||
|
expect(loadImage(jpegImage, defaultOptions)
|
||||||
|
.then(function(info) {
|
||||||
|
expect(info.transparent).toBe(false);
|
||||||
|
expect(info.format).toBe(WebGLConstants.RGB);
|
||||||
|
expect(info.source).toBeDefined();
|
||||||
|
expect(info.extension).toBe('.jpeg');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads gif image', function(done) {
|
||||||
|
expect(loadImage(gifImage, defaultOptions)
|
||||||
|
.then(function(info) {
|
||||||
|
expect(info.transparent).toBe(false);
|
||||||
|
expect(info.format).toBe(WebGLConstants.RGB);
|
||||||
|
expect(info.source).toBeDefined();
|
||||||
|
expect(info.extension).toBe('.gif');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads grayscale image', function(done) {
|
||||||
|
expect(loadImage(grayscaleImage, defaultOptions)
|
||||||
|
.then(function(info) {
|
||||||
|
expect(info.transparent).toBe(false);
|
||||||
|
expect(info.format).toBe(WebGLConstants.ALPHA);
|
||||||
|
expect(info.source).toBeDefined();
|
||||||
|
expect(info.extension).toBe('.png');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads image with alpha channel', function(done) {
|
||||||
|
expect(loadImage(transparentImage, defaultOptions)
|
||||||
|
.then(function(info) {
|
||||||
|
expect(info.transparent).toBe(false);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads image with checkTransparency flag', function(done) {
|
||||||
|
var options = clone(defaultOptions);
|
||||||
|
options.checkTransparency = true;
|
||||||
|
|
||||||
|
expect(loadImage(transparentImage, options)
|
||||||
|
.then(function(info) {
|
||||||
|
expect(info.transparent).toBe(true);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,43 @@
|
||||||
|
'use strict';
|
||||||
|
var path = require('path');
|
||||||
|
var loadMtl = require('../../lib/mtl');
|
||||||
|
|
||||||
|
var complexMaterialUrl = 'specs/data/box-complex-material/box-complex-material.mtl';
|
||||||
|
var multipleMaterialsUrl = 'specs/data/box-multiple-materials/box-multiple-materials.mtl';
|
||||||
|
|
||||||
|
function getImagePath(objPath, relativePath) {
|
||||||
|
return path.resolve(path.dirname(objPath), relativePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mtl', function() {
|
||||||
|
it('loads complex material', function(done) {
|
||||||
|
expect(loadMtl(complexMaterialUrl)
|
||||||
|
.then(function(materials) {
|
||||||
|
var material = materials.Material;
|
||||||
|
expect(material).toBeDefined();
|
||||||
|
expect(material.ambientColor).toEqual([0.2, 0.2, 0.2, 1.0]);
|
||||||
|
expect(material.emissionColor).toEqual([0.1, 0.1, 0.1, 1.0]);
|
||||||
|
expect(material.diffuseColor).toEqual([0.64, 0.64, 0.64, 1.0]);
|
||||||
|
expect(material.specularColor).toEqual([0.5, 0.5, 0.5, 1.0]);
|
||||||
|
expect(material.specularShininess).toEqual(96.078431);
|
||||||
|
expect(material.alpha).toEqual(0.9);
|
||||||
|
expect(material.ambientTexture).toEqual(getImagePath(complexMaterialUrl, 'ambient.gif'));
|
||||||
|
expect(material.emissionTexture).toEqual(getImagePath(complexMaterialUrl, 'emission.jpg'));
|
||||||
|
expect(material.diffuseTexture).toEqual(getImagePath(complexMaterialUrl, 'diffuse.png'));
|
||||||
|
expect(material.specularTexture).toEqual(getImagePath(complexMaterialUrl, 'specular.jpeg'));
|
||||||
|
expect(material.specularShininessMap).toEqual(getImagePath(complexMaterialUrl, 'shininess.png'));
|
||||||
|
expect(material.normalMap).toEqual(getImagePath(complexMaterialUrl, 'bump.png'));
|
||||||
|
expect(material.alphaMap).toEqual(getImagePath(complexMaterialUrl, 'alpha.png'));
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads mtl with multiple materials', function(done) {
|
||||||
|
expect(loadMtl(multipleMaterialsUrl)
|
||||||
|
.then(function(materials) {
|
||||||
|
expect(Object.keys(materials).length).toBe(3);
|
||||||
|
expect(materials.Red.diffuseColor).toEqual([0.64, 0.0, 0.0, 1.0]);
|
||||||
|
expect(materials.Green.diffuseColor).toEqual([0.0, 0.64, 0.0, 1.0]);
|
||||||
|
expect(materials.Blue.diffuseColor).toEqual([0.0, 0.0, 0.64, 1.0]);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,351 @@
|
||||||
|
'use strict';
|
||||||
|
var Cesium = require('cesium');
|
||||||
|
var path = require('path');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
var convert = require('../../lib/convert');
|
||||||
|
var loadObj = require('../../lib/obj');
|
||||||
|
|
||||||
|
var clone = Cesium.clone;
|
||||||
|
var RuntimeError = Cesium.RuntimeError;
|
||||||
|
|
||||||
|
var objUrl = 'specs/data/box/box.obj';
|
||||||
|
var objNormalsUrl = 'specs/data/box-normals/box-normals.obj';
|
||||||
|
var objUvsUrl = 'specs/data/box-uvs/box-uvs.obj';
|
||||||
|
var objPositionsOnlyUrl = 'specs/data/box-positions-only/box-positions-only.obj';
|
||||||
|
var objNegativeIndicesUrl = 'specs/data/box-negative-indices/box-negative-indices.obj';
|
||||||
|
var objTrianglesUrl = 'specs/data/box-triangles/box-triangles.obj';
|
||||||
|
var objObjectsUrl = 'specs/data/box-objects/box-objects.obj';
|
||||||
|
var objGroupsUrl = 'specs/data/box-groups/box-groups.obj';
|
||||||
|
var objObjectsGroupsUrl = 'specs/data/box-objects-groups/box-objects-groups.obj';
|
||||||
|
var objUsemtlUrl = 'specs/data/box-usemtl/box-usemtl.obj';
|
||||||
|
var objNoMaterialsUrl = 'specs/data/box-no-materials/box-no-materials.obj';
|
||||||
|
var objMultipleMaterialsUrl = 'specs/data/box-multiple-materials/box-multiple-materials.obj';
|
||||||
|
var objUncleanedUrl = 'specs/data/box-uncleaned/box-uncleaned.obj';
|
||||||
|
var objMtllibUrl = 'specs/data/box-mtllib/box-mtllib.obj';
|
||||||
|
var objMissingMtllibUrl = 'specs/data/box-missing-mtllib/box-missing-mtllib.obj';
|
||||||
|
var objExternalResourcesUrl = 'specs/data/box-external-resources/box-external-resources.obj';
|
||||||
|
var objTexturedUrl = 'specs/data/box-textured/box-textured.obj';
|
||||||
|
var objMissingTextureUrl = 'specs/data/box-missing-texture/box-missing-texture.obj';
|
||||||
|
var objSubdirectoriesUrl = 'specs/data/box-subdirectories/box-textured.obj';
|
||||||
|
var objComplexMaterialUrl = 'specs/data/box-complex-material/box-complex-material.obj';
|
||||||
|
var objInvalidContentsUrl = 'specs/data/box/box.mtl';
|
||||||
|
var objInvalidUrl = 'invalid.obj';
|
||||||
|
|
||||||
|
function getMeshes(data) {
|
||||||
|
var meshes = [];
|
||||||
|
var nodes = data.nodes;
|
||||||
|
var nodesLength = nodes.length;
|
||||||
|
for (var i = 0; i < nodesLength; ++i) {
|
||||||
|
meshes = meshes.concat(nodes[i].meshes);
|
||||||
|
}
|
||||||
|
return meshes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPrimitives(data) {
|
||||||
|
var primitives = [];
|
||||||
|
var nodes = data.nodes;
|
||||||
|
var nodesLength = nodes.length;
|
||||||
|
for (var i = 0; i < nodesLength; ++i) {
|
||||||
|
var meshes = nodes[i].meshes;
|
||||||
|
var meshesLength = meshes.length;
|
||||||
|
for (var j = 0; j < meshesLength; ++j) {
|
||||||
|
primitives = primitives.concat(meshes[j].primitives);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return primitives;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImagePath(objPath, relativePath) {
|
||||||
|
return path.resolve(path.dirname(objPath), relativePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultOptions = convert.defaults;
|
||||||
|
|
||||||
|
describe('obj', function() {
|
||||||
|
it('loads obj with positions, normals, and uvs', function(done) {
|
||||||
|
expect(loadObj(objUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var images = data.images;
|
||||||
|
var materials = data.materials;
|
||||||
|
var nodes = data.nodes;
|
||||||
|
var meshes = getMeshes(data);
|
||||||
|
var primitives = getPrimitives(data);
|
||||||
|
|
||||||
|
expect(Object.keys(images).length).toBe(0);
|
||||||
|
expect(materials.Material).toBeDefined();
|
||||||
|
expect(nodes.length).toBe(1);
|
||||||
|
expect(meshes.length).toBe(1);
|
||||||
|
expect(primitives.length).toBe(1);
|
||||||
|
|
||||||
|
var node = nodes[0];
|
||||||
|
var mesh = meshes[0];
|
||||||
|
var primitive = primitives[0];
|
||||||
|
|
||||||
|
expect(node.name).toBe('Cube');
|
||||||
|
expect(mesh.name).toBe('Cube-Mesh');
|
||||||
|
expect(mesh.positions.length / 3).toBe(24);
|
||||||
|
expect(mesh.normals.length / 3).toBe(24);
|
||||||
|
expect(mesh.uvs.length / 2).toBe(24);
|
||||||
|
expect(primitive.indices.length).toBe(36);
|
||||||
|
expect(primitive.material).toBe('Material');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with normals', function(done) {
|
||||||
|
expect(loadObj(objNormalsUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var mesh = getMeshes(data)[0];
|
||||||
|
expect(mesh.positions.length / 3).toBe(24);
|
||||||
|
expect(mesh.normals.length / 3).toBe(24);
|
||||||
|
expect(mesh.uvs.length / 2).toBe(0);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with uvs', function(done) {
|
||||||
|
expect(loadObj(objUvsUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var mesh = getMeshes(data)[0];
|
||||||
|
expect(mesh.positions.length / 3).toBe(20);
|
||||||
|
expect(mesh.normals.length / 3).toBe(0);
|
||||||
|
expect(mesh.uvs.length / 2).toBe(20);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with negative indices', function(done) {
|
||||||
|
expect(Promise.all([
|
||||||
|
loadObj(objPositionsOnlyUrl, defaultOptions),
|
||||||
|
loadObj(objNegativeIndicesUrl, defaultOptions)
|
||||||
|
])
|
||||||
|
.then(function(results) {
|
||||||
|
var positionsReference = getMeshes(results[0])[0].positions.toFloatBuffer();
|
||||||
|
var positions = getMeshes(results[1])[0].positions.toFloatBuffer();
|
||||||
|
expect(positions).toEqual(positionsReference);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with triangle faces', function(done) {
|
||||||
|
expect(loadObj(objTrianglesUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var mesh = getMeshes(data)[0];
|
||||||
|
var primitive = getPrimitives(data)[0];
|
||||||
|
expect(mesh.positions.length / 3).toBe(24);
|
||||||
|
expect(primitive.indices.length).toBe(36);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with objects', function(done) {
|
||||||
|
expect(loadObj(objObjectsUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var nodes = data.nodes;
|
||||||
|
expect(nodes.length).toBe(3);
|
||||||
|
expect(nodes[0].name).toBe('CubeBlue');
|
||||||
|
expect(nodes[1].name).toBe('CubeGreen');
|
||||||
|
expect(nodes[2].name).toBe('CubeRed');
|
||||||
|
|
||||||
|
var primitives = getPrimitives(data);
|
||||||
|
expect(primitives.length).toBe(3);
|
||||||
|
expect(primitives[0].material).toBe('Blue');
|
||||||
|
expect(primitives[1].material).toBe('Green');
|
||||||
|
expect(primitives[2].material).toBe('Red');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with groups', function(done) {
|
||||||
|
expect(loadObj(objGroupsUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var nodes = data.nodes;
|
||||||
|
expect(nodes.length).toBe(3);
|
||||||
|
expect(nodes[0].name).toBe('CubeBlue');
|
||||||
|
expect(nodes[1].name).toBe('CubeGreen');
|
||||||
|
expect(nodes[2].name).toBe('CubeRed');
|
||||||
|
|
||||||
|
var primitives = getPrimitives(data);
|
||||||
|
expect(primitives.length).toBe(3);
|
||||||
|
expect(primitives[0].material).toBe('Blue');
|
||||||
|
expect(primitives[1].material).toBe('Green');
|
||||||
|
expect(primitives[2].material).toBe('Red');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with objects and groups', function(done) {
|
||||||
|
expect(loadObj(objObjectsGroupsUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var nodes = data.nodes;
|
||||||
|
expect(nodes.length).toBe(3);
|
||||||
|
expect(nodes[0].name).toBe('CubeBlue');
|
||||||
|
expect(nodes[1].name).toBe('CubeGreen');
|
||||||
|
expect(nodes[2].name).toBe('CubeRed');
|
||||||
|
|
||||||
|
var meshes = getMeshes(data);
|
||||||
|
expect(meshes.length).toBe(3);
|
||||||
|
expect(meshes[0].name).toBe('CubeBlue_CubeBlue_Blue');
|
||||||
|
expect(meshes[1].name).toBe('CubeGreen_CubeGreen_Green');
|
||||||
|
expect(meshes[2].name).toBe('CubeRed_CubeRed_Red');
|
||||||
|
|
||||||
|
var primitives = getPrimitives(data);
|
||||||
|
expect(primitives.length).toBe(3);
|
||||||
|
expect(primitives[0].material).toBe('Blue');
|
||||||
|
expect(primitives[1].material).toBe('Green');
|
||||||
|
expect(primitives[2].material).toBe('Red');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with usemtl only', function(done) {
|
||||||
|
expect(loadObj(objUsemtlUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var nodes = data.nodes;
|
||||||
|
expect(nodes.length).toBe(1);
|
||||||
|
expect(nodes[0].name).toBe('Node'); // default name
|
||||||
|
|
||||||
|
var meshes = getMeshes(data);
|
||||||
|
expect(meshes.length).toBe(1);
|
||||||
|
expect(meshes[0].name).toBe('Node-Mesh');
|
||||||
|
|
||||||
|
var primitives = getPrimitives(data);
|
||||||
|
expect(primitives.length).toBe(3);
|
||||||
|
expect(primitives[0].material).toBe('Blue');
|
||||||
|
expect(primitives[1].material).toBe('Green');
|
||||||
|
expect(primitives[2].material).toBe('Red');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with no materials', function(done) {
|
||||||
|
expect(loadObj(objNoMaterialsUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var nodes = data.nodes;
|
||||||
|
expect(nodes.length).toBe(1);
|
||||||
|
expect(nodes[0].name).toBe('Node'); // default name
|
||||||
|
|
||||||
|
var primitives = getPrimitives(data);
|
||||||
|
expect(primitives.length).toBe(1);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with multiple materials', function(done) {
|
||||||
|
// The usemtl markers are interleaved, but should condense to just three primitives
|
||||||
|
expect(loadObj(objMultipleMaterialsUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var nodes = data.nodes;
|
||||||
|
expect(nodes.length).toBe(1);
|
||||||
|
|
||||||
|
var primitives = getPrimitives(data);
|
||||||
|
expect(primitives.length).toBe(3);
|
||||||
|
|
||||||
|
expect(primitives[0].indices.length).toBe(12);
|
||||||
|
expect(primitives[1].indices.length).toBe(12);
|
||||||
|
expect(primitives[2].indices.length).toBe(12);
|
||||||
|
expect(primitives[0].material).toBe('Red');
|
||||||
|
expect(primitives[1].material).toBe('Green');
|
||||||
|
expect(primitives[2].material).toBe('Blue');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj uncleaned', function(done) {
|
||||||
|
// Obj with extraneous o, g, and usemtl lines
|
||||||
|
// Also tests handling of o and g lines with the same names
|
||||||
|
expect(loadObj(objUncleanedUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var nodes = data.nodes;
|
||||||
|
var meshes = getMeshes(data);
|
||||||
|
var primitives = getPrimitives(data);
|
||||||
|
|
||||||
|
expect(nodes.length).toBe(1);
|
||||||
|
expect(meshes.length).toBe(1);
|
||||||
|
expect(primitives.length).toBe(1);
|
||||||
|
|
||||||
|
expect(nodes[0].name).toBe('Cube');
|
||||||
|
expect(meshes[0].name).toBe('Cube_1');
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with multiple mtllibs', function(done) {
|
||||||
|
expect(loadObj(objMtllibUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var materials = data.materials;
|
||||||
|
expect(Object.keys(materials).length).toBe(3);
|
||||||
|
expect(materials.Red.diffuseColor).toEqual([0.64, 0.0, 0.0, 1.0]);
|
||||||
|
expect(materials.Green.diffuseColor).toEqual([0.0, 0.64, 0.0, 1.0]);
|
||||||
|
expect(materials.Blue.diffuseColor).toEqual([0.0, 0.0, 0.64, 1.0]);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with missing mtllib', function(done) {
|
||||||
|
spyOn(console, 'log');
|
||||||
|
expect(loadObj(objMissingMtllibUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
expect(data.materials).toEqual({});
|
||||||
|
expect(console.log.calls.argsFor(0)[0].indexOf('Could not read mtl file') >= 0).toBe(true);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads resources outside of the obj directory', function(done) {
|
||||||
|
expect(loadObj(objExternalResourcesUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var imagePath = getImagePath(objTexturedUrl, 'cesium.png');
|
||||||
|
expect(data.images[imagePath]).toBeDefined();
|
||||||
|
expect(data.materials.MaterialTextured.diffuseTexture).toEqual(imagePath);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not load resources outside of the obj directory when secure is true', function(done) {
|
||||||
|
spyOn(console, 'log');
|
||||||
|
|
||||||
|
var options = clone(defaultOptions);
|
||||||
|
options.secure = true;
|
||||||
|
|
||||||
|
expect(loadObj(objExternalResourcesUrl, options)
|
||||||
|
.then(function(data) {
|
||||||
|
var imagePath = getImagePath(objMissingTextureUrl, 'cesium.png');
|
||||||
|
expect(data.images[imagePath]).toBeUndefined();
|
||||||
|
expect(data.materials.MaterialTextured).toBeDefined();
|
||||||
|
expect(data.materials.Material).toBeUndefined(); // Not in directory, so not included
|
||||||
|
expect(console.log.calls.argsFor(0)[0].indexOf('Could not read mtl file') >= 0).toBe(true);
|
||||||
|
expect(console.log.calls.argsFor(1)[0].indexOf('Could not read image file') >= 0).toBe(true);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with texture', function(done) {
|
||||||
|
expect(loadObj(objTexturedUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var imagePath = getImagePath(objTexturedUrl, 'cesium.png');
|
||||||
|
expect(data.images[imagePath]).toBeDefined();
|
||||||
|
expect(data.materials.Material.diffuseTexture).toEqual(imagePath);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with missing texture', function(done) {
|
||||||
|
spyOn(console, 'log');
|
||||||
|
expect(loadObj(objMissingTextureUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var imagePath = getImagePath(objMissingTextureUrl, 'cesium.png');
|
||||||
|
expect(data.images[imagePath]).toBeUndefined();
|
||||||
|
expect(data.materials.Material.diffuseTexture).toEqual(imagePath);
|
||||||
|
expect(console.log.calls.argsFor(0)[0].indexOf('Could not read image file') >= 0).toBe(true);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with subdirectories', function(done) {
|
||||||
|
expect(loadObj(objSubdirectoriesUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var imagePath = getImagePath(objSubdirectoriesUrl, path.join('materials', 'images', 'cesium.png'));
|
||||||
|
expect(data.images[imagePath]).toBeDefined();
|
||||||
|
expect(data.materials.Material.diffuseTexture).toEqual(imagePath);
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads obj with complex material', function(done) {
|
||||||
|
expect(loadObj(objComplexMaterialUrl, defaultOptions)
|
||||||
|
.then(function(data) {
|
||||||
|
var images = data.images;
|
||||||
|
expect(Object.keys(images).length).toBe(4); // Only ambient, diffuse, emission, and specular maps are supported by the converter
|
||||||
|
}), done).toResolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not process file with invalid contents', function(done) {
|
||||||
|
expect(loadObj(objInvalidContentsUrl, defaultOptions), done).toRejectWith(RuntimeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throw when reading invalid file', function(done) {
|
||||||
|
expect(loadObj(objInvalidUrl, defaultOptions), done).toRejectWith(Error);
|
||||||
|
});
|
||||||
|
});
|
16
typings.json
|
@ -1,16 +0,0 @@
|
||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"async": "registry:npm/async#2.0.1+20160815105832",
|
|
||||||
"bluebird": "registry:npm/bluebird#3.4.1+20160909132857",
|
|
||||||
"gulp": "registry:npm/gulp#4.0.0-alpha.2+20160817105618",
|
|
||||||
"requirejs": "registry:npm/requirejs#2.2.0+20160319062357",
|
|
||||||
"yargs": "registry:npm/yargs#5.0.0+20160907000723"
|
|
||||||
},
|
|
||||||
"globalDependencies": {
|
|
||||||
"byline": "registry:dt/byline#4.2.1+20161006132146",
|
|
||||||
"fs-extra": "registry:dt/fs-extra#0.0.0+20161004190449",
|
|
||||||
"istanbul": "registry:dt/istanbul#0.4.0+20160316155526",
|
|
||||||
"jasmine": "registry:dt/jasmine#2.5.0+20161003201800",
|
|
||||||
"open": "registry:dt/open#0.0.3+20160316155526"
|
|
||||||
}
|
|
||||||
}
|
|