From 83e7723b1c55122352e9e455952391c3353fbf7e Mon Sep 17 00:00:00 2001 From: Sean Lilley Date: Tue, 21 Mar 2017 14:37:52 -0400 Subject: [PATCH] Transparency and other updates --- README.md | 2 +- bin/obj2gltf.js | 4 ++-- lib/convert.js | 6 +++++- lib/image.js | 46 +++++++++++++++++++++++++----------------- lib/obj.js | 2 +- lib/writeUris.js | 3 +-- specs/lib/gltfSpec.js | 36 ++++++++++++++++++--------------- specs/lib/imageSpec.js | 4 ++-- 8 files changed, 60 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 44a0251..a1b625a 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Using obj2gltf as a command-line tool: |`--cesium`|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`| |`--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`| -|`--checkTextureAlpha`|Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. By default textures with an alpha channel are considered to be transparent.|No, default `false`| +|`--hasTransparency`|Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. By default textures with an alpha channel are considered to be transparent.|No, default `false`| ## Build Instructions diff --git a/bin/obj2gltf.js b/bin/obj2gltf.js index 5d975e2..0b7bd66 100644 --- a/bin/obj2gltf.js +++ b/bin/obj2gltf.js @@ -80,7 +80,7 @@ var argv = yargs type: 'boolean', default: false }, - 'checkTextureAlpha': { + 'hasTransparency': { describe: 'Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. By default textures with an alpha channel are considered to be transparent.', type: 'boolean', default: false @@ -111,7 +111,7 @@ var options = { ao : argv.ao, optimizeForCesium : argv.cesium, bypassPipeline : argv.bypassPipeline, - checkTextureAlpha : argv.checkTextureAlpha + hasTransparency : argv.hasTransparency }; console.time('Total'); diff --git a/lib/convert.js b/lib/convert.js index 23f48e0..aef3037 100644 --- a/lib/convert.js +++ b/lib/convert.js @@ -32,7 +32,7 @@ module.exports = convert; * @param {Boolean} [options.ao=false] Apply ambient occlusion to the converted model. * @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.checkTextureAlpha=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. + * @param {Boolean} [options.hasTransparency=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. */ function convert(objPath, gltfPath, options) { @@ -61,6 +61,10 @@ function convert(objPath, gltfPath, options) { var extension = path.extname(gltfPath); if (extension === '.glb') { binary = true; + if (bypassPipeline) { + console.log('--bypassPipeline does not convert to binary glTF, saving as .gltf'); + extension = '.gltf'; + } } gltfPath = path.join(path.dirname(gltfPath), modelName + extension); diff --git a/lib/image.js b/lib/image.js index 1ad93ba..568c663 100644 --- a/lib/image.js +++ b/lib/image.js @@ -1,11 +1,11 @@ 'use strict'; var Cesium = require('cesium'); -var fs = require('fs-extra'); +var fsExtra = require('fs-extra'); 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 defaultValue = Cesium.defaultValue; var WebGLConstants = Cesium.WebGLConstants; @@ -17,16 +17,16 @@ module.exports = loadImage; * * @param {String} imagePath Path to the image file. * @param {Object} [options] An object with the following properties: - * @param {Boolean} [options.checkTextureAlpha=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. + * @param {Boolean} [options.hasTransparency=false] 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) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - var checkTextureAlpha = defaultValue(options.checkTextureAlpha, false); + var hasTransparency = defaultValue(options.hasTransparency, false); - return fsReadFile(imagePath) + return fsExtraReadFile(imagePath) .then(function(data) { var extension = path.extname(imagePath); @@ -44,10 +44,13 @@ function loadImage(imagePath, options) { info.format = getFormat(channels); if (channels === 4) { - if (checkTextureAlpha) { - info.transparent = isTransparent(data); - } else { - info.transparent = true; + info.transparent = true; + if (hasTransparency) { + return isTransparent(data) + .then(function(transparent) { + info.transparent = transparent; + return info; + }); } } } @@ -61,15 +64,22 @@ function loadImage(imagePath, options) { } function isTransparent(data) { - var decoded = PNG.sync.read(data); - var pixels = decoded.data; - var pixelsLength = decoded.width * decoded.height; - for (var i = 0; i < pixelsLength; ++i) { - if (pixels[i * 4 + 3] < 255) { - return true; - } - } - return false; + return new Promise(function(resolve, reject) { + new PNG().parse(data, function(error, data) { + if (error) { + reject(error); + } + 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) { diff --git a/lib/obj.js b/lib/obj.js index e9b2159..af6be9d 100644 --- a/lib/obj.js +++ b/lib/obj.js @@ -52,7 +52,7 @@ var facePattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/( * * @param {String} objPath Path to the obj file. * @param {Object} [options] An object with the following properties: - * @param {Boolean} [options.checkTextureAlpha=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. + * @param {Boolean} [options.hasTransparency=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. * @returns {Promise} A promise resolving to the obj data. * @exception {RuntimeError} The file does not have any geometry information in it. * diff --git a/lib/writeUris.js b/lib/writeUris.js index 286ed72..f49c759 100644 --- a/lib/writeUris.js +++ b/lib/writeUris.js @@ -52,10 +52,9 @@ function writeUris(gltf, gltfPath, separateBuffers, separateTextures) { writeEmbeddedTextures(gltf); } - deleteExtras(gltf); - return Promise.all(promises) .then(function() { + deleteExtras(gltf); return gltf; }); } diff --git a/specs/lib/gltfSpec.js b/specs/lib/gltfSpec.js index 260a116..297918e 100644 --- a/specs/lib/gltfSpec.js +++ b/specs/lib/gltfSpec.js @@ -57,30 +57,34 @@ describe('gltf', function() { ]).then(done); }); - it('simple gltf', function() { + it('simple gltf', function(done) { var objData = clone(boxObjData, true); var gltf = createGltf(objData); - writeUris(gltf, boxGltfUrl, false, false); - expect(gltf).toEqual(boxGltf); + expect(writeUris(gltf, boxGltfUrl, false, false) + .then(function() { + expect(gltf).toEqual(boxGltf); + }), done).toResolve(); }); - it('multiple nodes, meshes, and primitives', function() { + it('multiple nodes, meshes, and primitives', function(done) { var objData = clone(groupObjData, true); var gltf = createGltf(objData); - writeUris(gltf, groupGltfUrl, false, false); - 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); + expect(writeUris(gltf, groupGltfUrl, false, false) + .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); - } - } + // 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() { diff --git a/specs/lib/imageSpec.js b/specs/lib/imageSpec.js index c046463..9fe5277 100644 --- a/specs/lib/imageSpec.js +++ b/specs/lib/imageSpec.js @@ -82,9 +82,9 @@ describe('image', function() { }), done).toResolve(); }); - it('loads image with fully opaque alpha channel with checkTextureAlpha flag', function(done) { + it('loads image with fully opaque alpha channel with hasTransparency flag', function(done) { var options = { - checkTextureAlpha : true + hasTransparency : true }; expect(loadImage(opaqueAlphaImage, options) .then(function(info) {